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