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