]> git.ipfire.org Git - thirdparty/bird.git/blob - sysdep/unix/log.c
7cb26360a520e0a587e123526112bbfe059329d1
[thirdparty/bird.git] / sysdep / unix / log.c
1 /*
2 * BIRD Library -- Logging Functions
3 *
4 * (c) 1998--2000 Martin Mares <mj@ucw.cz>
5 *
6 * Can be freely distributed and used under the terms of the GNU GPL.
7 */
8
9 /**
10 * DOC: Logging
11 *
12 * The Logging module offers a simple set of functions for writing
13 * messages to system logs and to the debug output. Message classes
14 * used by this module are described in |birdlib.h| and also in the
15 * user's manual.
16 */
17
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdarg.h>
21 #include <time.h>
22 #include <unistd.h>
23
24 #include "nest/bird.h"
25 #include "nest/cli.h"
26 #include "nest/mrtdump.h"
27 #include "lib/string.h"
28 #include "lib/lists.h"
29 #include "lib/unix.h"
30
31 static FILE *dbgf;
32 static list *current_log_list;
33 static char *current_syslog_name; /* NULL -> syslog closed */
34
35
36 #ifdef USE_PTHREADS
37
38 #include <pthread.h>
39
40 static pthread_mutex_t log_mutex;
41 static inline void log_lock(void) { pthread_mutex_lock(&log_mutex); }
42 static inline void log_unlock(void) { pthread_mutex_unlock(&log_mutex); }
43
44 static pthread_t main_thread;
45 void main_thread_init(void) { main_thread = pthread_self(); }
46 static int main_thread_self(void) { return pthread_equal(pthread_self(), main_thread); }
47
48 #else
49
50 static inline void log_lock(void) { }
51 static inline void log_unlock(void) { }
52 void main_thread_init(void) { }
53 static int main_thread_self(void) { return 1; }
54
55 #endif
56
57
58 #ifdef HAVE_SYSLOG
59 #include <sys/syslog.h>
60
61 static int syslog_priorities[] = {
62 LOG_DEBUG,
63 LOG_DEBUG,
64 LOG_DEBUG,
65 LOG_INFO,
66 LOG_ERR,
67 LOG_WARNING,
68 LOG_ERR,
69 LOG_ERR,
70 LOG_CRIT,
71 LOG_CRIT
72 };
73 #endif
74
75 static char *class_names[] = {
76 "???",
77 "DBG",
78 "TRACE",
79 "INFO",
80 "RMT",
81 "WARN",
82 "ERR",
83 "AUTH",
84 "FATAL",
85 "BUG"
86 };
87
88
89 /**
90 * log_commit - commit a log message
91 * @class: message class information (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
92 *
93 * This function writes a message prepared in the log buffer to the
94 * log file (as specified in the configuration). The log buffer is
95 * reset after that. The log message is a full line, log_commit()
96 * terminates it.
97 *
98 * The message class is an integer, not a first char of a string like
99 * in log(), so it should be written like *L_INFO.
100 */
101 void
102 log_commit(int class, buffer *buf)
103 {
104 struct log_config *l;
105
106 if (buf->pos == buf->end)
107 strcpy(buf->end - 100, " ... <too long>");
108
109 log_lock();
110 WALK_LIST(l, *current_log_list)
111 {
112 if (!(l->mask & (1 << class)))
113 continue;
114 if (l->fh)
115 {
116 if (l->terminal_flag)
117 fputs("bird: ", l->fh);
118 else
119 {
120 byte tbuf[TM_DATETIME_BUFFER_SIZE];
121 tm_format_datetime(tbuf, &config->tf_log, now);
122 fprintf(l->fh, "%s <%s> ", tbuf, class_names[class]);
123 }
124 fputs(buf->start, l->fh);
125 fputc('\n', l->fh);
126 fflush(l->fh);
127 }
128 #ifdef HAVE_SYSLOG
129 else
130 syslog(syslog_priorities[class], "%s", buf->start);
131 #endif
132 }
133 log_unlock();
134
135 /* cli_echo is not thread-safe, so call it just from the main thread */
136 if (main_thread_self())
137 cli_echo(class, buf->start);
138
139 buf->pos = buf->start;
140 }
141
142 int buffer_vprint(buffer *buf, const char *fmt, va_list args);
143
144 static void
145 vlog(int class, const char *msg, va_list args)
146 {
147 buffer buf;
148 LOG_BUFFER_INIT(buf);
149 buffer_vprint(&buf, msg, args);
150 log_commit(class, &buf);
151 }
152
153
154 /**
155 * log - log a message
156 * @msg: printf-like formatting string with message class information
157 * prepended (%L_DEBUG to %L_BUG, see |lib/birdlib.h|)
158 *
159 * This function formats a message according to the format string @msg
160 * and writes it to the corresponding log file (as specified in the
161 * configuration). Please note that the message is automatically
162 * formatted as a full line, no need to include |\n| inside.
163 * It is essentially a sequence of log_reset(), logn() and log_commit().
164 */
165 void
166 log_msg(const char *msg, ...)
167 {
168 int class = 1;
169 va_list args;
170
171 va_start(args, msg);
172 if (*msg >= 1 && *msg <= 8)
173 class = *msg++;
174 vlog(class, msg, args);
175 va_end(args);
176 }
177
178 void
179 log_rl(struct tbf *f, const char *msg, ...)
180 {
181 int last_hit = f->mark;
182 int class = 1;
183 va_list args;
184
185 /* Rate limiting is a bit tricky here as it also logs '...' during the first hit */
186 if (tbf_limit(f) && last_hit)
187 return;
188
189 if (*msg >= 1 && *msg <= 8)
190 class = *msg++;
191
192 va_start(args, msg);
193 vlog(class, (f->mark ? "..." : msg), args);
194 va_end(args);
195 }
196
197 /**
198 * bug - report an internal error
199 * @msg: a printf-like error message
200 *
201 * This function logs an internal error and aborts execution
202 * of the program.
203 */
204 void
205 bug(const char *msg, ...)
206 {
207 va_list args;
208
209 va_start(args, msg);
210 vlog(L_BUG[0], msg, args);
211 abort();
212 }
213
214 /**
215 * bug - report a fatal error
216 * @msg: a printf-like error message
217 *
218 * This function logs a fatal error and aborts execution
219 * of the program.
220 */
221 void
222 die(const char *msg, ...)
223 {
224 va_list args;
225
226 va_start(args, msg);
227 vlog(L_FATAL[0], msg, args);
228 exit(1);
229 }
230
231 /**
232 * debug - write to debug output
233 * @msg: a printf-like message
234 *
235 * This function formats the message @msg and prints it out
236 * to the debugging output. No newline character is appended.
237 */
238 void
239 debug(const char *msg, ...)
240 {
241 va_list args;
242 char buf[1024];
243
244 va_start(args, msg);
245 if (dbgf)
246 {
247 if (bvsnprintf(buf, sizeof(buf), msg, args) < 0)
248 bsprintf(buf + sizeof(buf) - 100, " ... <too long>\n");
249 fputs(buf, dbgf);
250 }
251 va_end(args);
252 }
253
254 static list *
255 default_log_list(int debug, int init, char **syslog_name)
256 {
257 static list init_log_list;
258 init_list(&init_log_list);
259 *syslog_name = NULL;
260
261 #ifdef HAVE_SYSLOG
262 if (!debug)
263 {
264 static struct log_config lc_syslog = { .mask = ~0 };
265 add_tail(&init_log_list, &lc_syslog.n);
266 *syslog_name = bird_name;
267 if (!init)
268 return &init_log_list;
269 }
270 #endif
271
272 static struct log_config lc_stderr = { .mask = ~0, .terminal_flag = 1 };
273 lc_stderr.fh = stderr;
274 add_tail(&init_log_list, &lc_stderr.n);
275 return &init_log_list;
276 }
277
278 void
279 log_switch(int debug, list *l, char *new_syslog_name)
280 {
281 if (!l || EMPTY_LIST(*l))
282 l = default_log_list(debug, !l, &new_syslog_name);
283
284 current_log_list = l;
285
286 #ifdef HAVE_SYSLOG
287 if (current_syslog_name && new_syslog_name &&
288 !strcmp(current_syslog_name, new_syslog_name))
289 return;
290
291 if (current_syslog_name)
292 closelog();
293
294 if (new_syslog_name)
295 openlog(new_syslog_name, LOG_CONS | LOG_NDELAY, LOG_DAEMON);
296
297 current_syslog_name = new_syslog_name;
298 #endif
299 }
300
301
302
303 void
304 log_init_debug(char *f)
305 {
306 if (dbgf && dbgf != stderr)
307 fclose(dbgf);
308 if (!f)
309 dbgf = NULL;
310 else if (!*f)
311 dbgf = stderr;
312 else if (!(dbgf = fopen(f, "a")))
313 log(L_ERR "Error opening debug file `%s': %m", f);
314 if (dbgf)
315 setvbuf(dbgf, NULL, _IONBF, 0);
316 }
317
318 void
319 mrt_dump_message(struct proto *p, u16 type, u16 subtype, byte *buf, u32 len)
320 {
321 /* Prepare header */
322 put_u32(buf+0, now_real);
323 put_u16(buf+4, type);
324 put_u16(buf+6, subtype);
325 put_u32(buf+8, len - MRTDUMP_HDR_LENGTH);
326
327 if (p->cf->global->mrtdump_file != -1)
328 write(p->cf->global->mrtdump_file, buf, len);
329 }