]>
Commit | Line | Data |
---|---|---|
274a4a44 | 1 | /* |
c4c7d0c4 | 2 | * $Id: log.c,v 1.25 2005/02/03 19:22:05 ajs Exp $ |
274a4a44 | 3 | * |
4 | * Logging of zebra | |
718e3744 | 5 | * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro |
6 | * | |
7 | * This file is part of GNU Zebra. | |
8 | * | |
9 | * GNU Zebra is free software; you can redistribute it and/or modify it | |
10 | * under the terms of the GNU General Public License as published by the | |
11 | * Free Software Foundation; either version 2, or (at your option) any | |
12 | * later version. | |
13 | * | |
14 | * GNU Zebra is distributed in the hope that it will be useful, but | |
15 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU General Public License | |
20 | * along with GNU Zebra; see the file COPYING. If not, write to the Free | |
21 | * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
22 | * 02111-1307, USA. | |
23 | */ | |
24 | ||
25 | #include <zebra.h> | |
26 | ||
27 | #include "log.h" | |
28 | #include "memory.h" | |
29 | #include "command.h" | |
7d149b8e | 30 | #ifndef SUNOS_5 |
31 | #include <sys/un.h> | |
32 | #endif | |
718e3744 | 33 | |
c4c7d0c4 | 34 | static int logfile_fd = -1; /* Used in signal handler. */ |
1e221354 | 35 | |
718e3744 | 36 | struct zlog *zlog_default = NULL; |
37 | ||
38 | const char *zlog_proto_names[] = | |
39 | { | |
40 | "NONE", | |
41 | "DEFAULT", | |
42 | "ZEBRA", | |
43 | "RIP", | |
44 | "BGP", | |
45 | "OSPF", | |
46 | "RIPNG", | |
47 | "OSPF6", | |
9e867fe6 | 48 | "ISIS", |
718e3744 | 49 | "MASC", |
50 | NULL, | |
51 | }; | |
52 | ||
53 | const char *zlog_priority[] = | |
54 | { | |
55 | "emergencies", | |
56 | "alerts", | |
57 | "critical", | |
58 | "errors", | |
59 | "warnings", | |
60 | "notifications", | |
61 | "informational", | |
62 | "debugging", | |
63 | NULL, | |
64 | }; | |
65 | ||
66 | ||
67 | \f | |
68 | /* For time string format. */ | |
69 | #define TIME_BUF 27 | |
70 | ||
71 | /* Utility routine for current time printing. */ | |
72 | static void | |
73 | time_print (FILE *fp) | |
74 | { | |
75 | int ret; | |
76 | char buf [TIME_BUF]; | |
77 | time_t clock; | |
78 | struct tm *tm; | |
79 | ||
80 | time (&clock); | |
81 | tm = localtime (&clock); | |
82 | ||
83 | ret = strftime (buf, TIME_BUF, "%Y/%m/%d %H:%M:%S", tm); | |
84 | if (ret == 0) { | |
85 | zlog_warn ("strftime error"); | |
86 | } | |
87 | ||
88 | fprintf (fp, "%s ", buf); | |
89 | } | |
90 | \f | |
91 | /* va_list version of zlog. */ | |
d246bd96 | 92 | static void |
93 | vzlog (struct zlog *zl, int priority, const char *format, va_list args) | |
718e3744 | 94 | { |
95 | /* If zlog is not specified, use default one. */ | |
96 | if (zl == NULL) | |
97 | zl = zlog_default; | |
98 | ||
99 | /* When zlog_default is also NULL, use stderr for logging. */ | |
100 | if (zl == NULL) | |
101 | { | |
102 | time_print (stderr); | |
103 | fprintf (stderr, "%s: ", "unknown"); | |
d246bd96 | 104 | vfprintf (stderr, format, args); |
718e3744 | 105 | fprintf (stderr, "\n"); |
106 | fflush (stderr); | |
107 | ||
108 | /* In this case we return at here. */ | |
109 | return; | |
110 | } | |
111 | ||
718e3744 | 112 | /* Syslog output */ |
274a4a44 | 113 | if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG]) |
d246bd96 | 114 | { |
115 | va_list ac; | |
116 | va_copy(ac, args); | |
117 | vsyslog (priority|zlog_default->facility, format, ac); | |
118 | va_end(ac); | |
119 | } | |
718e3744 | 120 | |
121 | /* File output. */ | |
274a4a44 | 122 | if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp) |
718e3744 | 123 | { |
d246bd96 | 124 | va_list ac; |
718e3744 | 125 | time_print (zl->fp); |
b04c699e | 126 | if (zl->record_priority) |
127 | fprintf (zl->fp, "%s: ", zlog_priority[priority]); | |
718e3744 | 128 | fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]); |
d246bd96 | 129 | va_copy(ac, args); |
130 | vfprintf (zl->fp, format, ac); | |
131 | va_end(ac); | |
718e3744 | 132 | fprintf (zl->fp, "\n"); |
133 | fflush (zl->fp); | |
134 | } | |
135 | ||
136 | /* stdout output. */ | |
274a4a44 | 137 | if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT]) |
718e3744 | 138 | { |
d246bd96 | 139 | va_list ac; |
718e3744 | 140 | time_print (stdout); |
b04c699e | 141 | if (zl->record_priority) |
142 | fprintf (stdout, "%s: ", zlog_priority[priority]); | |
718e3744 | 143 | fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]); |
d246bd96 | 144 | va_copy(ac, args); |
145 | vfprintf (stdout, format, ac); | |
146 | va_end(ac); | |
718e3744 | 147 | fprintf (stdout, "\n"); |
148 | fflush (stdout); | |
149 | } | |
150 | ||
718e3744 | 151 | /* Terminal monitor. */ |
274a4a44 | 152 | if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR]) |
153 | vty_log ((zl->record_priority ? zlog_priority[priority] : NULL), | |
154 | zlog_proto_names[zl->protocol], format, args); | |
718e3744 | 155 | } |
156 | ||
59a06a91 | 157 | static char * |
158 | str_append(char *dst, int len, const char *src) | |
159 | { | |
160 | while ((len-- > 0) && *src) | |
161 | *dst++ = *src++; | |
162 | return dst; | |
163 | } | |
164 | ||
165 | static char * | |
166 | num_append(char *s, int len, u_long x) | |
167 | { | |
168 | char buf[30]; | |
7d149b8e | 169 | char *t; |
59a06a91 | 170 | |
7d149b8e | 171 | if (!x) |
172 | return str_append(s,len,"0"); | |
173 | *(t = &buf[sizeof(buf)-1]) = '\0'; | |
59a06a91 | 174 | while (x && (t > buf)) |
175 | { | |
176 | *--t = '0'+(x % 10); | |
177 | x /= 10; | |
178 | } | |
179 | return str_append(s,len,t); | |
180 | } | |
181 | ||
31364274 | 182 | #if defined(SA_SIGINFO) || defined(HAVE_GLIBC_BACKTRACE) |
7d149b8e | 183 | static char * |
184 | hex_append(char *s, int len, u_long x) | |
185 | { | |
186 | char buf[30]; | |
187 | char *t; | |
188 | ||
189 | if (!x) | |
190 | return str_append(s,len,"0"); | |
191 | *(t = &buf[sizeof(buf)-1]) = '\0'; | |
192 | while (x && (t > buf)) | |
193 | { | |
194 | u_int cc = (x % 16); | |
195 | *--t = ((cc < 10) ? ('0'+cc) : ('a'+cc-10)); | |
196 | x /= 16; | |
197 | } | |
198 | return str_append(s,len,t); | |
199 | } | |
31364274 | 200 | #endif |
7d149b8e | 201 | |
7d149b8e | 202 | /* Needs to be enhanced to support Solaris. */ |
203 | static int | |
204 | syslog_connect(void) | |
205 | { | |
206 | #ifdef SUNOS_5 | |
207 | return -1; | |
208 | #else | |
209 | int fd; | |
210 | char *s; | |
211 | struct sockaddr_un addr; | |
212 | ||
213 | if ((fd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0) | |
214 | return -1; | |
215 | addr.sun_family = AF_UNIX; | |
216 | #ifdef _PATH_LOG | |
217 | #define SYSLOG_SOCKET_PATH _PATH_LOG | |
218 | #else | |
219 | #define SYSLOG_SOCKET_PATH "/dev/log" | |
220 | #endif | |
221 | s = str_append(addr.sun_path,sizeof(addr.sun_path),SYSLOG_SOCKET_PATH); | |
222 | #undef SYSLOG_SOCKET_PATH | |
223 | *s = '\0'; | |
224 | if (connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0) | |
225 | { | |
226 | close(fd); | |
227 | return -1; | |
228 | } | |
229 | return fd; | |
230 | #endif | |
231 | } | |
232 | ||
233 | static void | |
234 | syslog_sigsafe(int priority, const char *msg, size_t msglen) | |
235 | { | |
1e221354 | 236 | static int syslog_fd = -1; |
7d149b8e | 237 | char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50]; |
238 | char *s; | |
239 | ||
240 | if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0)) | |
241 | return; | |
242 | ||
243 | #define LOC s,buf+sizeof(buf)-s | |
244 | s = buf; | |
245 | s = str_append(LOC,"<"); | |
246 | s = num_append(LOC,priority); | |
247 | s = str_append(LOC,">"); | |
248 | /* forget about the timestamp, too difficult in a signal handler */ | |
249 | s = str_append(LOC,zlog_default->ident); | |
250 | if (zlog_default->syslog_options & LOG_PID) | |
251 | { | |
252 | s = str_append(LOC,"["); | |
253 | s = num_append(LOC,getpid()); | |
254 | s = str_append(LOC,"]"); | |
255 | } | |
256 | s = str_append(LOC,": "); | |
257 | s = str_append(LOC,msg); | |
258 | write(syslog_fd,buf,s-buf); | |
259 | #undef LOC | |
260 | } | |
261 | ||
1e221354 | 262 | static int |
263 | open_crashlog(void) | |
264 | { | |
265 | #define CRASHLOG_PREFIX "/var/tmp/quagga." | |
266 | #define CRASHLOG_SUFFIX "crashlog" | |
267 | if (zlog_default && zlog_default->ident) | |
268 | { | |
269 | /* Avoid strlen since it is not async-signal-safe. */ | |
270 | const char *p; | |
271 | size_t ilen; | |
272 | ||
273 | for (p = zlog_default->ident, ilen = 0; *p; p++) | |
274 | ilen++; | |
275 | { | |
276 | char buf[sizeof(CRASHLOG_PREFIX)+ilen+sizeof(CRASHLOG_SUFFIX)+3]; | |
277 | char *s = buf; | |
278 | #define LOC s,buf+sizeof(buf)-s | |
279 | s = str_append(LOC, CRASHLOG_PREFIX); | |
280 | s = str_append(LOC, zlog_default->ident); | |
281 | s = str_append(LOC, "."); | |
282 | s = str_append(LOC, CRASHLOG_SUFFIX); | |
283 | #undef LOC | |
284 | *s = '\0'; | |
285 | return open(buf, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK); | |
286 | } | |
287 | } | |
288 | return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX, O_WRONLY|O_CREAT|O_EXCL, | |
289 | LOGFILE_MASK); | |
290 | #undef CRASHLOG_SUFFIX | |
291 | #undef CRASHLOG_PREFIX | |
292 | } | |
293 | ||
7d149b8e | 294 | /* Note: the goal here is to use only async-signal-safe functions. */ |
59a06a91 | 295 | void |
31364274 | 296 | zlog_signal(int signo, const char *action |
297 | #ifdef SA_SIGINFO | |
298 | , siginfo_t *siginfo, void *program_counter | |
299 | #endif | |
300 | ) | |
59a06a91 | 301 | { |
302 | time_t now; | |
40abf239 | 303 | char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100]; |
59a06a91 | 304 | char *s = buf; |
7d149b8e | 305 | char *msgstart = buf; |
59a06a91 | 306 | #define LOC s,buf+sizeof(buf)-s |
307 | ||
308 | time(&now); | |
309 | if (zlog_default) | |
310 | { | |
311 | s = str_append(LOC,zlog_proto_names[zlog_default->protocol]); | |
312 | *s++ = ':'; | |
313 | *s++ = ' '; | |
7d149b8e | 314 | msgstart = s; |
59a06a91 | 315 | } |
316 | s = str_append(LOC,"Received signal "); | |
317 | s = num_append(LOC,signo); | |
318 | s = str_append(LOC," at "); | |
319 | s = num_append(LOC,now); | |
31364274 | 320 | #ifdef SA_SIGINFO |
40abf239 | 321 | s = str_append(LOC," (si_addr 0x"); |
322 | s = hex_append(LOC,(u_long)(siginfo->si_addr)); | |
323 | if (program_counter) | |
324 | { | |
325 | s = str_append(LOC,", PC 0x"); | |
326 | s = hex_append(LOC,(u_long)program_counter); | |
327 | } | |
328 | s = str_append(LOC,"); "); | |
31364274 | 329 | #else /* SA_SIGINFO */ |
330 | s = str_append(LOC,"; "); | |
331 | #endif /* SA_SIGINFO */ | |
59a06a91 | 332 | s = str_append(LOC,action); |
7d149b8e | 333 | if (s < buf+sizeof(buf)) |
334 | *s++ = '\n'; | |
59a06a91 | 335 | |
274a4a44 | 336 | /* N.B. implicit priority is most severe */ |
1e221354 | 337 | #define PRI LOG_CRIT |
274a4a44 | 338 | |
1e221354 | 339 | #define DUMP(FD) write(FD, buf, s-buf); |
340 | /* If no file logging configured, try to write to fallback log file. */ | |
c4c7d0c4 | 341 | if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) |
342 | DUMP(logfile_fd) | |
59a06a91 | 343 | if (!zlog_default) |
c4c7d0c4 | 344 | DUMP(STDERR_FILENO) |
59a06a91 | 345 | else |
346 | { | |
274a4a44 | 347 | if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) |
c4c7d0c4 | 348 | DUMP(STDOUT_FILENO) |
274a4a44 | 349 | /* Remove trailing '\n' for monitor and syslog */ |
350 | *--s = '\0'; | |
351 | if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) | |
352 | vty_log_fixed(buf,s-buf); | |
353 | if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) | |
354 | syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart); | |
59a06a91 | 355 | } |
356 | #undef DUMP | |
357 | ||
31364274 | 358 | zlog_backtrace_sigsafe(PRI, |
359 | #ifdef SA_SIGINFO | |
360 | program_counter | |
361 | #else | |
362 | NULL | |
363 | #endif | |
364 | ); | |
274a4a44 | 365 | #undef PRI |
063ee52a | 366 | #undef LOC |
367 | } | |
368 | ||
369 | /* Log a backtrace using only async-signal-safe functions. | |
370 | Needs to be enhanced to support syslog logging. */ | |
371 | void | |
239c26fd | 372 | zlog_backtrace_sigsafe(int priority, void *program_counter) |
063ee52a | 373 | { |
59a06a91 | 374 | #ifdef HAVE_GLIBC_BACKTRACE |
239c26fd | 375 | static const char pclabel[] = "Program counter: "; |
063ee52a | 376 | void *array[20]; |
377 | int size; | |
378 | char buf[100]; | |
379 | char *s; | |
380 | #define LOC s,buf+sizeof(buf)-s | |
59a06a91 | 381 | |
063ee52a | 382 | if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || |
383 | ((size_t)size > sizeof(array)/sizeof(array[0]))) | |
384 | return; | |
385 | s = buf; | |
386 | s = str_append(LOC,"Backtrace for "); | |
387 | s = num_append(LOC,size); | |
388 | s = str_append(LOC," stack frames:\n"); | |
59a06a91 | 389 | |
1e221354 | 390 | #define DUMP(FD) { \ |
239c26fd | 391 | if (program_counter) \ |
392 | { \ | |
1e221354 | 393 | write(FD, pclabel, sizeof(pclabel)-1); \ |
394 | backtrace_symbols_fd(&program_counter, 1, FD); \ | |
239c26fd | 395 | } \ |
1e221354 | 396 | write(FD, buf, s-buf); \ |
397 | backtrace_symbols_fd(array, size, FD); \ | |
59a06a91 | 398 | } |
399 | ||
c4c7d0c4 | 400 | if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0)) |
401 | DUMP(logfile_fd) | |
59a06a91 | 402 | if (!zlog_default) |
c4c7d0c4 | 403 | DUMP(STDERR_FILENO) |
59a06a91 | 404 | else |
405 | { | |
274a4a44 | 406 | if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT]) |
c4c7d0c4 | 407 | DUMP(STDOUT_FILENO) |
274a4a44 | 408 | /* Remove trailing '\n' for monitor and syslog */ |
409 | *--s = '\0'; | |
410 | if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) | |
411 | vty_log_fixed(buf,s-buf); | |
412 | if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) | |
413 | syslog_sigsafe(priority|zlog_default->facility,buf,s-buf); | |
414 | { | |
415 | int i; | |
416 | /* Just print the function addresses. */ | |
417 | for (i = 0; i < size; i++) | |
418 | { | |
419 | s = buf; | |
420 | s = str_append(LOC,"[bt "); | |
421 | s = num_append(LOC,i); | |
422 | s = str_append(LOC,"] 0x"); | |
423 | s = hex_append(LOC,(u_long)(array[i])); | |
424 | *s = '\0'; | |
425 | if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR]) | |
426 | vty_log_fixed(buf,s-buf); | |
427 | if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG]) | |
7d149b8e | 428 | syslog_sigsafe(priority|zlog_default->facility,buf,s-buf); |
274a4a44 | 429 | } |
430 | } | |
59a06a91 | 431 | } |
432 | #undef DUMP | |
59a06a91 | 433 | #undef LOC |
063ee52a | 434 | #endif /* HAVE_GLIBC_BACKTRACE */ |
435 | } | |
436 | ||
437 | void | |
438 | zlog_backtrace(int priority) | |
439 | { | |
440 | #ifndef HAVE_GLIBC_BACKTRACE | |
441 | zlog(NULL, priority, "No backtrace available on this platform."); | |
442 | #else | |
443 | void *array[20]; | |
444 | int size, i; | |
445 | char **strings; | |
446 | ||
447 | if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) || | |
448 | ((size_t)size > sizeof(array)/sizeof(array[0]))) | |
449 | { | |
450 | zlog_err("Cannot get backtrace, returned invalid # of frames %d " | |
451 | "(valid range is between 1 and %u)", | |
452 | size, sizeof(array)/sizeof(array[0])); | |
453 | return; | |
454 | } | |
455 | zlog(NULL, priority, "Backtrace for %d stack frames:", size); | |
456 | if (!(strings = backtrace_symbols(array, size))) | |
457 | { | |
458 | zlog_err("Cannot get backtrace symbols (out of memory?)"); | |
459 | for (i = 0; i < size; i++) | |
460 | zlog(NULL, priority, "[bt %d] %p",i,array[i]); | |
461 | } | |
462 | else | |
463 | { | |
464 | for (i = 0; i < size; i++) | |
465 | zlog(NULL, priority, "[bt %d] %s",i,strings[i]); | |
466 | free(strings); | |
467 | } | |
468 | #endif /* HAVE_GLIBC_BACKTRACE */ | |
59a06a91 | 469 | } |
470 | ||
718e3744 | 471 | void |
472 | zlog (struct zlog *zl, int priority, const char *format, ...) | |
473 | { | |
d246bd96 | 474 | va_list args; |
718e3744 | 475 | |
d246bd96 | 476 | va_start(args, format); |
718e3744 | 477 | vzlog (zl, priority, format, args); |
d246bd96 | 478 | va_end (args); |
718e3744 | 479 | } |
480 | ||
d246bd96 | 481 | #define ZLOG_FUNC(FUNCNAME,PRIORITY) \ |
482 | void \ | |
483 | FUNCNAME(const char *format, ...) \ | |
484 | { \ | |
485 | va_list args; \ | |
486 | va_start(args, format); \ | |
487 | vzlog (NULL, PRIORITY, format, args); \ | |
488 | va_end(args); \ | |
718e3744 | 489 | } |
490 | ||
d246bd96 | 491 | ZLOG_FUNC(zlog_err, LOG_ERR) |
718e3744 | 492 | |
d246bd96 | 493 | ZLOG_FUNC(zlog_warn, LOG_WARNING) |
718e3744 | 494 | |
d246bd96 | 495 | ZLOG_FUNC(zlog_info, LOG_INFO) |
718e3744 | 496 | |
d246bd96 | 497 | ZLOG_FUNC(zlog_notice, LOG_NOTICE) |
718e3744 | 498 | |
d246bd96 | 499 | ZLOG_FUNC(zlog_debug, LOG_DEBUG) |
718e3744 | 500 | |
d246bd96 | 501 | #undef ZLOG_FUNC |
718e3744 | 502 | |
d246bd96 | 503 | #define PLOG_FUNC(FUNCNAME,PRIORITY) \ |
504 | void \ | |
505 | FUNCNAME(struct zlog *zl, const char *format, ...) \ | |
506 | { \ | |
507 | va_list args; \ | |
508 | va_start(args, format); \ | |
509 | vzlog (zl, PRIORITY, format, args); \ | |
510 | va_end(args); \ | |
718e3744 | 511 | } |
512 | ||
d246bd96 | 513 | PLOG_FUNC(plog_err, LOG_ERR) |
718e3744 | 514 | |
d246bd96 | 515 | PLOG_FUNC(plog_warn, LOG_WARNING) |
718e3744 | 516 | |
d246bd96 | 517 | PLOG_FUNC(plog_info, LOG_INFO) |
718e3744 | 518 | |
d246bd96 | 519 | PLOG_FUNC(plog_notice, LOG_NOTICE) |
718e3744 | 520 | |
d246bd96 | 521 | PLOG_FUNC(plog_debug, LOG_DEBUG) |
718e3744 | 522 | |
d246bd96 | 523 | #undef PLOG_FUNC |
718e3744 | 524 | |
cee3df1e | 525 | void |
526 | _zlog_assert_failed (const char *assertion, const char *file, | |
527 | unsigned int line, const char *function) | |
528 | { | |
c4c7d0c4 | 529 | /* Force fallback file logging? */ |
530 | if (zlog_default && !zlog_default->fp && | |
531 | ((logfile_fd = open_crashlog()) >= 0) && | |
532 | ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL)) | |
533 | zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR; | |
1e221354 | 534 | zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s", |
535 | assertion,file,line,(function ? function : "?")); | |
536 | zlog_backtrace(LOG_CRIT); | |
cee3df1e | 537 | abort(); |
538 | } | |
539 | ||
718e3744 | 540 | \f |
541 | /* Open log stream */ | |
542 | struct zlog * | |
274a4a44 | 543 | openzlog (const char *progname, zlog_proto_t protocol, |
718e3744 | 544 | int syslog_flags, int syslog_facility) |
545 | { | |
546 | struct zlog *zl; | |
274a4a44 | 547 | u_int i; |
718e3744 | 548 | |
274a4a44 | 549 | zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog)); |
718e3744 | 550 | |
551 | zl->ident = progname; | |
718e3744 | 552 | zl->protocol = protocol; |
553 | zl->facility = syslog_facility; | |
7d149b8e | 554 | zl->syslog_options = syslog_flags; |
718e3744 | 555 | |
274a4a44 | 556 | /* Set default logging levels. */ |
557 | for (i = 0; i < sizeof(zl->maxlvl)/sizeof(zl->maxlvl[0]); i++) | |
558 | zl->maxlvl[i] = ZLOG_DISABLED; | |
559 | zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG; | |
560 | zl->default_lvl = LOG_DEBUG; | |
561 | ||
718e3744 | 562 | openlog (progname, syslog_flags, zl->facility); |
563 | ||
564 | return zl; | |
565 | } | |
566 | ||
567 | void | |
568 | closezlog (struct zlog *zl) | |
569 | { | |
570 | closelog(); | |
571 | fclose (zl->fp); | |
572 | ||
573 | XFREE (MTYPE_ZLOG, zl); | |
574 | } | |
575 | ||
576 | /* Called from command.c. */ | |
577 | void | |
274a4a44 | 578 | zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level) |
718e3744 | 579 | { |
580 | if (zl == NULL) | |
581 | zl = zlog_default; | |
582 | ||
274a4a44 | 583 | zl->maxlvl[dest] = log_level; |
718e3744 | 584 | } |
585 | ||
586 | int | |
274a4a44 | 587 | zlog_set_file (struct zlog *zl, const char *filename, int log_level) |
718e3744 | 588 | { |
589 | FILE *fp; | |
aa593d5e | 590 | mode_t oldumask; |
718e3744 | 591 | |
592 | /* There is opend file. */ | |
593 | zlog_reset_file (zl); | |
594 | ||
595 | /* Set default zl. */ | |
596 | if (zl == NULL) | |
597 | zl = zlog_default; | |
598 | ||
599 | /* Open file. */ | |
aa593d5e | 600 | oldumask = umask (0777 & ~LOGFILE_MASK); |
718e3744 | 601 | fp = fopen (filename, "a"); |
aa593d5e | 602 | umask(oldumask); |
274a4a44 | 603 | if (fp == NULL) |
604 | return 0; | |
718e3744 | 605 | |
606 | /* Set flags. */ | |
607 | zl->filename = strdup (filename); | |
274a4a44 | 608 | zl->maxlvl[ZLOG_DEST_FILE] = log_level; |
718e3744 | 609 | zl->fp = fp; |
c4c7d0c4 | 610 | logfile_fd = fileno(fp); |
718e3744 | 611 | |
612 | return 1; | |
613 | } | |
614 | ||
615 | /* Reset opend file. */ | |
616 | int | |
617 | zlog_reset_file (struct zlog *zl) | |
618 | { | |
619 | if (zl == NULL) | |
620 | zl = zlog_default; | |
621 | ||
718e3744 | 622 | if (zl->fp) |
623 | fclose (zl->fp); | |
624 | zl->fp = NULL; | |
c4c7d0c4 | 625 | logfile_fd = -1; |
274a4a44 | 626 | zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; |
718e3744 | 627 | |
628 | if (zl->filename) | |
629 | free (zl->filename); | |
630 | zl->filename = NULL; | |
631 | ||
632 | return 1; | |
633 | } | |
634 | ||
635 | /* Reopen log file. */ | |
636 | int | |
637 | zlog_rotate (struct zlog *zl) | |
638 | { | |
274a4a44 | 639 | int level; |
718e3744 | 640 | |
641 | if (zl == NULL) | |
642 | zl = zlog_default; | |
643 | ||
644 | if (zl->fp) | |
645 | fclose (zl->fp); | |
646 | zl->fp = NULL; | |
c4c7d0c4 | 647 | logfile_fd = -1; |
274a4a44 | 648 | level = zl->maxlvl[ZLOG_DEST_FILE]; |
649 | zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED; | |
718e3744 | 650 | |
651 | if (zl->filename) | |
652 | { | |
aa593d5e | 653 | mode_t oldumask; |
274a4a44 | 654 | int save_errno; |
aa593d5e | 655 | |
656 | oldumask = umask (0777 & ~LOGFILE_MASK); | |
274a4a44 | 657 | zl->fp = fopen (zl->filename, "a"); |
658 | save_errno = errno; | |
659 | umask(oldumask); | |
660 | if (zl->fp == NULL) | |
aa593d5e | 661 | { |
274a4a44 | 662 | zlog_err("Log rotate failed: cannot open file %s for append: %s", |
663 | zl->filename, safe_strerror(save_errno)); | |
aa593d5e | 664 | return -1; |
665 | } | |
c4c7d0c4 | 666 | logfile_fd = fileno(zl->fp); |
274a4a44 | 667 | zl->maxlvl[ZLOG_DEST_FILE] = level; |
718e3744 | 668 | } |
669 | ||
670 | return 1; | |
671 | } | |
672 | \f | |
718e3744 | 673 | /* Message lookup function. */ |
8c328f11 | 674 | const char * |
718e3744 | 675 | lookup (struct message *mes, int key) |
676 | { | |
677 | struct message *pnt; | |
678 | ||
679 | for (pnt = mes; pnt->key != 0; pnt++) | |
680 | if (pnt->key == key) | |
681 | return pnt->str; | |
682 | ||
683 | return ""; | |
684 | } | |
685 | ||
686 | /* Very old hacky version of message lookup function. Still partly | |
b04c699e | 687 | used in bgpd and ospfd. FIXME Seems that it's not used any more. */ |
8c328f11 | 688 | const char * |
718e3744 | 689 | mes_lookup (struct message *meslist, int max, int index) |
690 | { | |
691 | if (index < 0 || index >= max) | |
692 | { | |
693 | zlog_err ("message index out of bound: %d", max); | |
694 | return NULL; | |
695 | } | |
696 | return meslist[index].str; | |
697 | } | |
ca359769 | 698 | |
699 | /* Wrapper around strerror to handle case where it returns NULL. */ | |
700 | const char * | |
701 | safe_strerror(int errnum) | |
702 | { | |
703 | const char *s = strerror(errnum); | |
704 | return (s != NULL) ? s : "Unknown error"; | |
705 | } |