Line data Source code
1 : /*
2 : * Logging of zebra
3 : * Copyright (C) 1997, 1998, 1999 Kunihiro Ishiguro
4 : *
5 : * This file is part of GNU Zebra.
6 : *
7 : * GNU Zebra is free software; you can redistribute it and/or modify it
8 : * under the terms of the GNU General Public License as published by the
9 : * Free Software Foundation; either version 2, or (at your option) any
10 : * later version.
11 : *
12 : * GNU Zebra is distributed in the hope that it will be useful, but
13 : * WITHOUT ANY WARRANTY; without even the implied warranty of
14 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 : * General Public License for more details.
16 : *
17 : * You should have received a copy of the GNU General Public License
18 : * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 : * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 : * 02111-1307, USA.
21 : */
22 :
23 : #define QUAGGA_DEFINE_DESC_TABLE
24 :
25 : #include <zebra.h>
26 :
27 : #include "log.h"
28 : #include "memory.h"
29 : #include "command.h"
30 : #ifndef SUNOS_5
31 : #include <sys/un.h>
32 : #endif
33 : /* for printstack on solaris */
34 : #ifdef HAVE_UCONTEXT_H
35 : #include <ucontext.h>
36 : #endif
37 :
38 : static int logfile_fd = -1; /* Used in signal handler. */
39 :
40 : struct zlog *zlog_default = NULL;
41 :
42 : const char *zlog_proto_names[] =
43 : {
44 : "NONE",
45 : "DEFAULT",
46 : "ZEBRA",
47 : "RIP",
48 : "BGP",
49 : "OSPF",
50 : "RIPNG",
51 : "BABEL",
52 : "OSPF6",
53 : "ISIS",
54 : "MASC",
55 : NULL,
56 : };
57 :
58 : const char *zlog_priority[] =
59 : {
60 : "emergencies",
61 : "alerts",
62 : "critical",
63 : "errors",
64 : "warnings",
65 : "notifications",
66 : "informational",
67 : "debugging",
68 : NULL,
69 : };
70 :
71 :
72 :
73 : /* For time string format. */
74 :
75 : size_t
76 3894 : quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
77 : {
78 : static struct {
79 : time_t last;
80 : size_t len;
81 : char buf[28];
82 : } cache;
83 : struct timeval clock;
84 :
85 : /* would it be sufficient to use global 'recent_time' here? I fear not... */
86 3894 : gettimeofday(&clock, NULL);
87 :
88 : /* first, we update the cache if the time has changed */
89 3894 : if (cache.last != clock.tv_sec)
90 : {
91 : struct tm *tm;
92 93 : cache.last = clock.tv_sec;
93 93 : tm = localtime(&cache.last);
94 93 : cache.len = strftime(cache.buf, sizeof(cache.buf),
95 : "%Y/%m/%d %H:%M:%S", tm);
96 : }
97 : /* note: it's not worth caching the subsecond part, because
98 : chances are that back-to-back calls are not sufficiently close together
99 : for the clock not to have ticked forward */
100 :
101 3894 : if (buflen > cache.len)
102 : {
103 3894 : memcpy(buf, cache.buf, cache.len);
104 3894 : if ((timestamp_precision > 0) &&
105 0 : (buflen > cache.len+1+timestamp_precision))
106 : {
107 : /* should we worry about locale issues? */
108 : static const int divisor[] = {0, 100000, 10000, 1000, 100, 10, 1};
109 : int prec;
110 0 : char *p = buf+cache.len+1+(prec = timestamp_precision);
111 0 : *p-- = '\0';
112 0 : while (prec > 6)
113 : /* this is unlikely to happen, but protect anyway */
114 : {
115 0 : *p-- = '0';
116 0 : prec--;
117 : }
118 0 : clock.tv_usec /= divisor[prec];
119 : do
120 : {
121 0 : *p-- = '0'+(clock.tv_usec % 10);
122 0 : clock.tv_usec /= 10;
123 : }
124 0 : while (--prec > 0);
125 0 : *p = '.';
126 0 : return cache.len+1+timestamp_precision;
127 : }
128 3894 : buf[cache.len] = '\0';
129 3894 : return cache.len;
130 : }
131 0 : if (buflen > 0)
132 0 : buf[0] = '\0';
133 0 : return 0;
134 : }
135 :
136 : /* Utility routine for current time printing. */
137 : static void
138 3894 : time_print(FILE *fp, struct timestamp_control *ctl)
139 : {
140 3894 : if (!ctl->already_rendered)
141 : {
142 3894 : ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
143 3894 : ctl->already_rendered = 1;
144 : }
145 3894 : fprintf(fp, "%s ", ctl->buf);
146 3894 : }
147 :
148 :
149 : /* va_list version of zlog. */
150 : static void
151 3939 : vzlog (struct zlog *zl, int priority, const char *format, va_list args)
152 : {
153 : struct timestamp_control tsctl;
154 3939 : tsctl.already_rendered = 0;
155 :
156 : /* If zlog is not specified, use default one. */
157 3939 : if (zl == NULL)
158 3939 : zl = zlog_default;
159 :
160 : /* When zlog_default is also NULL, use stderr for logging. */
161 3939 : if (zl == NULL)
162 : {
163 421 : tsctl.precision = 0;
164 421 : time_print(stderr, &tsctl);
165 421 : fprintf (stderr, "%s: ", "unknown");
166 421 : vfprintf (stderr, format, args);
167 421 : fprintf (stderr, "\n");
168 421 : fflush (stderr);
169 :
170 : /* In this case we return at here. */
171 421 : return;
172 : }
173 3518 : tsctl.precision = zl->timestamp_precision;
174 :
175 : /* Syslog output */
176 3518 : if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
177 : {
178 : va_list ac;
179 0 : va_copy(ac, args);
180 0 : vsyslog (priority|zlog_default->facility, format, ac);
181 0 : va_end(ac);
182 : }
183 :
184 : /* File output. */
185 3518 : if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
186 : {
187 : va_list ac;
188 3473 : time_print (zl->fp, &tsctl);
189 3473 : if (zl->record_priority)
190 0 : fprintf (zl->fp, "%s: ", zlog_priority[priority]);
191 3473 : fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
192 3473 : va_copy(ac, args);
193 3473 : vfprintf (zl->fp, format, ac);
194 3473 : va_end(ac);
195 3473 : fprintf (zl->fp, "\n");
196 3473 : fflush (zl->fp);
197 : }
198 :
199 : /* stdout output. */
200 3518 : if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
201 : {
202 : va_list ac;
203 0 : time_print (stdout, &tsctl);
204 0 : if (zl->record_priority)
205 0 : fprintf (stdout, "%s: ", zlog_priority[priority]);
206 0 : fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
207 0 : va_copy(ac, args);
208 0 : vfprintf (stdout, format, ac);
209 0 : va_end(ac);
210 0 : fprintf (stdout, "\n");
211 0 : fflush (stdout);
212 : }
213 :
214 : /* Terminal monitor. */
215 3518 : if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
216 3518 : vty_log ((zl->record_priority ? zlog_priority[priority] : NULL),
217 3518 : zlog_proto_names[zl->protocol], format, &tsctl, args);
218 : }
219 :
220 : static char *
221 0 : str_append(char *dst, int len, const char *src)
222 : {
223 0 : while ((len-- > 0) && *src)
224 0 : *dst++ = *src++;
225 0 : return dst;
226 : }
227 :
228 : static char *
229 0 : num_append(char *s, int len, u_long x)
230 : {
231 : char buf[30];
232 : char *t;
233 :
234 0 : if (!x)
235 0 : return str_append(s,len,"0");
236 0 : *(t = &buf[sizeof(buf)-1]) = '\0';
237 0 : while (x && (t > buf))
238 : {
239 0 : *--t = '0'+(x % 10);
240 0 : x /= 10;
241 : }
242 0 : return str_append(s,len,t);
243 : }
244 :
245 : #if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE)
246 : static char *
247 0 : hex_append(char *s, int len, u_long x)
248 : {
249 : char buf[30];
250 : char *t;
251 :
252 0 : if (!x)
253 0 : return str_append(s,len,"0");
254 0 : *(t = &buf[sizeof(buf)-1]) = '\0';
255 0 : while (x && (t > buf))
256 : {
257 0 : u_int cc = (x % 16);
258 0 : *--t = ((cc < 10) ? ('0'+cc) : ('a'+cc-10));
259 0 : x /= 16;
260 : }
261 0 : return str_append(s,len,t);
262 : }
263 : #endif
264 :
265 : /* Needs to be enhanced to support Solaris. */
266 : static int
267 0 : syslog_connect(void)
268 : {
269 : #ifdef SUNOS_5
270 : return -1;
271 : #else
272 : int fd;
273 : char *s;
274 : struct sockaddr_un addr;
275 :
276 0 : if ((fd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0)
277 0 : return -1;
278 0 : addr.sun_family = AF_UNIX;
279 : #ifdef _PATH_LOG
280 : #define SYSLOG_SOCKET_PATH _PATH_LOG
281 : #else
282 : #define SYSLOG_SOCKET_PATH "/dev/log"
283 : #endif
284 0 : s = str_append(addr.sun_path,sizeof(addr.sun_path),SYSLOG_SOCKET_PATH);
285 : #undef SYSLOG_SOCKET_PATH
286 0 : *s = '\0';
287 0 : if (connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
288 : {
289 0 : close(fd);
290 0 : return -1;
291 : }
292 0 : return fd;
293 : #endif
294 : }
295 :
296 : static void
297 0 : syslog_sigsafe(int priority, const char *msg, size_t msglen)
298 0 : {
299 : static int syslog_fd = -1;
300 0 : char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50];
301 : char *s;
302 :
303 0 : if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0))
304 0 : return;
305 :
306 : #define LOC s,buf+sizeof(buf)-s
307 0 : s = buf;
308 0 : s = str_append(LOC,"<");
309 0 : s = num_append(LOC,priority);
310 0 : s = str_append(LOC,">");
311 : /* forget about the timestamp, too difficult in a signal handler */
312 0 : s = str_append(LOC,zlog_default->ident);
313 0 : if (zlog_default->syslog_options & LOG_PID)
314 : {
315 0 : s = str_append(LOC,"[");
316 0 : s = num_append(LOC,getpid());
317 0 : s = str_append(LOC,"]");
318 : }
319 0 : s = str_append(LOC,": ");
320 0 : s = str_append(LOC,msg);
321 0 : write(syslog_fd,buf,s-buf);
322 : #undef LOC
323 : }
324 :
325 : static int
326 0 : open_crashlog(void)
327 : {
328 : #define CRASHLOG_PREFIX "/var/tmp/quagga."
329 : #define CRASHLOG_SUFFIX "crashlog"
330 0 : if (zlog_default && zlog_default->ident)
331 : {
332 : /* Avoid strlen since it is not async-signal-safe. */
333 : const char *p;
334 : size_t ilen;
335 :
336 0 : for (p = zlog_default->ident, ilen = 0; *p; p++)
337 0 : ilen++;
338 0 : {
339 0 : char buf[sizeof(CRASHLOG_PREFIX)+ilen+sizeof(CRASHLOG_SUFFIX)+3];
340 0 : char *s = buf;
341 : #define LOC s,buf+sizeof(buf)-s
342 0 : s = str_append(LOC, CRASHLOG_PREFIX);
343 0 : s = str_append(LOC, zlog_default->ident);
344 0 : s = str_append(LOC, ".");
345 0 : s = str_append(LOC, CRASHLOG_SUFFIX);
346 : #undef LOC
347 0 : *s = '\0';
348 0 : return open(buf, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK);
349 : }
350 : }
351 0 : return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX, O_WRONLY|O_CREAT|O_EXCL,
352 : LOGFILE_MASK);
353 : #undef CRASHLOG_SUFFIX
354 : #undef CRASHLOG_PREFIX
355 : }
356 :
357 : /* Note: the goal here is to use only async-signal-safe functions. */
358 : void
359 0 : zlog_signal(int signo, const char *action
360 : #ifdef SA_SIGINFO
361 : , siginfo_t *siginfo, void *program_counter
362 : #endif
363 : )
364 : {
365 : time_t now;
366 : char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100];
367 0 : char *s = buf;
368 0 : char *msgstart = buf;
369 : #define LOC s,buf+sizeof(buf)-s
370 :
371 0 : time(&now);
372 0 : if (zlog_default)
373 : {
374 0 : s = str_append(LOC,zlog_proto_names[zlog_default->protocol]);
375 0 : *s++ = ':';
376 0 : *s++ = ' ';
377 0 : msgstart = s;
378 : }
379 0 : s = str_append(LOC,"Received signal ");
380 0 : s = num_append(LOC,signo);
381 0 : s = str_append(LOC," at ");
382 0 : s = num_append(LOC,now);
383 : #ifdef SA_SIGINFO
384 0 : s = str_append(LOC," (si_addr 0x");
385 0 : s = hex_append(LOC,(u_long)(siginfo->si_addr));
386 0 : if (program_counter)
387 : {
388 0 : s = str_append(LOC,", PC 0x");
389 0 : s = hex_append(LOC,(u_long)program_counter);
390 : }
391 0 : s = str_append(LOC,"); ");
392 : #else /* SA_SIGINFO */
393 : s = str_append(LOC,"; ");
394 : #endif /* SA_SIGINFO */
395 0 : s = str_append(LOC,action);
396 0 : if (s < buf+sizeof(buf))
397 0 : *s++ = '\n';
398 :
399 : /* N.B. implicit priority is most severe */
400 : #define PRI LOG_CRIT
401 :
402 : #define DUMP(FD) write(FD, buf, s-buf);
403 : /* If no file logging configured, try to write to fallback log file. */
404 0 : if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
405 0 : DUMP(logfile_fd)
406 0 : if (!zlog_default)
407 0 : DUMP(STDERR_FILENO)
408 : else
409 : {
410 0 : if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
411 0 : DUMP(STDOUT_FILENO)
412 : /* Remove trailing '\n' for monitor and syslog */
413 0 : *--s = '\0';
414 0 : if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
415 0 : vty_log_fixed(buf,s-buf);
416 0 : if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
417 0 : syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart);
418 : }
419 : #undef DUMP
420 :
421 0 : zlog_backtrace_sigsafe(PRI,
422 : #ifdef SA_SIGINFO
423 : program_counter
424 : #else
425 : NULL
426 : #endif
427 : );
428 : #undef PRI
429 : #undef LOC
430 0 : }
431 :
432 : /* Log a backtrace using only async-signal-safe functions.
433 : Needs to be enhanced to support syslog logging. */
434 : void
435 0 : zlog_backtrace_sigsafe(int priority, void *program_counter)
436 : {
437 : #ifdef HAVE_STACK_TRACE
438 : static const char pclabel[] = "Program counter: ";
439 : void *array[64];
440 : int size;
441 : char buf[100];
442 0 : char *s, **bt = NULL;
443 : #define LOC s,buf+sizeof(buf)-s
444 :
445 : #ifdef HAVE_GLIBC_BACKTRACE
446 0 : size = backtrace(array, array_size(array));
447 0 : if (size <= 0 || (size_t)size > array_size(array))
448 0 : return;
449 :
450 : #define DUMP(FD) { \
451 : if (program_counter) \
452 : { \
453 : write(FD, pclabel, sizeof(pclabel)-1); \
454 : backtrace_symbols_fd(&program_counter, 1, FD); \
455 : } \
456 : write(FD, buf, s-buf); \
457 : backtrace_symbols_fd(array, size, FD); \
458 : }
459 : #elif defined(HAVE_PRINTSTACK)
460 : #define DUMP(FD) { \
461 : if (program_counter) \
462 : write((FD), pclabel, sizeof(pclabel)-1); \
463 : write((FD), buf, s-buf); \
464 : printstack((FD)); \
465 : }
466 : #endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
467 :
468 0 : s = buf;
469 0 : s = str_append(LOC,"Backtrace for ");
470 0 : s = num_append(LOC,size);
471 0 : s = str_append(LOC," stack frames:\n");
472 :
473 0 : if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
474 0 : DUMP(logfile_fd)
475 0 : if (!zlog_default)
476 0 : DUMP(STDERR_FILENO)
477 : else
478 : {
479 0 : if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
480 0 : DUMP(STDOUT_FILENO)
481 : /* Remove trailing '\n' for monitor and syslog */
482 0 : *--s = '\0';
483 0 : if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
484 0 : vty_log_fixed(buf,s-buf);
485 0 : if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
486 0 : syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
487 : {
488 : int i;
489 : #ifdef HAVE_GLIBC_BACKTRACE
490 0 : bt = backtrace_symbols(array, size);
491 : #endif
492 : /* Just print the function addresses. */
493 0 : for (i = 0; i < size; i++)
494 : {
495 0 : s = buf;
496 0 : if (bt)
497 0 : s = str_append(LOC, bt[i]);
498 : else {
499 0 : s = str_append(LOC,"[bt ");
500 0 : s = num_append(LOC,i);
501 0 : s = str_append(LOC,"] 0x");
502 0 : s = hex_append(LOC,(u_long)(array[i]));
503 : }
504 0 : *s = '\0';
505 0 : if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
506 0 : vty_log_fixed(buf,s-buf);
507 0 : if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
508 0 : syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
509 : }
510 0 : if (bt)
511 0 : free(bt);
512 : }
513 : }
514 : #undef DUMP
515 : #undef LOC
516 : #endif /* HAVE_STRACK_TRACE */
517 : }
518 :
519 : void
520 0 : zlog_backtrace(int priority)
521 : {
522 : #ifndef HAVE_GLIBC_BACKTRACE
523 : zlog(NULL, priority, "No backtrace available on this platform.");
524 : #else
525 : void *array[20];
526 : int size, i;
527 : char **strings;
528 :
529 0 : size = backtrace(array, array_size(array));
530 0 : if (size <= 0 || (size_t)size > array_size(array))
531 : {
532 0 : zlog_err("Cannot get backtrace, returned invalid # of frames %d "
533 : "(valid range is between 1 and %lu)",
534 : size, (unsigned long)(array_size(array)));
535 0 : return;
536 : }
537 0 : zlog(NULL, priority, "Backtrace for %d stack frames:", size);
538 0 : if (!(strings = backtrace_symbols(array, size)))
539 : {
540 0 : zlog_err("Cannot get backtrace symbols (out of memory?)");
541 0 : for (i = 0; i < size; i++)
542 0 : zlog(NULL, priority, "[bt %d] %p",i,array[i]);
543 : }
544 : else
545 : {
546 0 : for (i = 0; i < size; i++)
547 0 : zlog(NULL, priority, "[bt %d] %s",i,strings[i]);
548 0 : free(strings);
549 : }
550 : #endif /* HAVE_GLIBC_BACKTRACE */
551 : }
552 :
553 : void
554 773 : zlog (struct zlog *zl, int priority, const char *format, ...)
555 : {
556 : va_list args;
557 :
558 773 : va_start(args, format);
559 773 : vzlog (zl, priority, format, args);
560 773 : va_end (args);
561 773 : }
562 :
563 : #define ZLOG_FUNC(FUNCNAME,PRIORITY) \
564 : void \
565 : FUNCNAME(const char *format, ...) \
566 : { \
567 : va_list args; \
568 : va_start(args, format); \
569 : vzlog (NULL, PRIORITY, format, args); \
570 : va_end(args); \
571 : }
572 :
573 5 : ZLOG_FUNC(zlog_err, LOG_ERR)
574 :
575 3 : ZLOG_FUNC(zlog_warn, LOG_WARNING)
576 :
577 190 : ZLOG_FUNC(zlog_info, LOG_INFO)
578 :
579 185 : ZLOG_FUNC(zlog_notice, LOG_NOTICE)
580 :
581 2756 : ZLOG_FUNC(zlog_debug, LOG_DEBUG)
582 :
583 : #undef ZLOG_FUNC
584 :
585 : #define PLOG_FUNC(FUNCNAME,PRIORITY) \
586 : void \
587 : FUNCNAME(struct zlog *zl, const char *format, ...) \
588 : { \
589 : va_list args; \
590 : va_start(args, format); \
591 : vzlog (zl, PRIORITY, format, args); \
592 : va_end(args); \
593 : }
594 :
595 6 : PLOG_FUNC(plog_err, LOG_ERR)
596 :
597 0 : PLOG_FUNC(plog_warn, LOG_WARNING)
598 :
599 0 : PLOG_FUNC(plog_info, LOG_INFO)
600 :
601 0 : PLOG_FUNC(plog_notice, LOG_NOTICE)
602 :
603 21 : PLOG_FUNC(plog_debug, LOG_DEBUG)
604 :
605 : #undef PLOG_FUNC
606 :
607 : void
608 0 : _zlog_assert_failed (const char *assertion, const char *file,
609 : unsigned int line, const char *function)
610 : {
611 : /* Force fallback file logging? */
612 0 : if (zlog_default && !zlog_default->fp &&
613 0 : ((logfile_fd = open_crashlog()) >= 0) &&
614 0 : ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL))
615 0 : zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
616 0 : zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
617 : assertion,file,line,(function ? function : "?"));
618 0 : zlog_backtrace(LOG_CRIT);
619 0 : abort();
620 : }
621 :
622 :
623 : /* Open log stream */
624 : struct zlog *
625 45 : openzlog (const char *progname, zlog_proto_t protocol,
626 : int syslog_flags, int syslog_facility)
627 : {
628 : struct zlog *zl;
629 : u_int i;
630 :
631 45 : zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog));
632 :
633 45 : zl->ident = progname;
634 45 : zl->protocol = protocol;
635 45 : zl->facility = syslog_facility;
636 45 : zl->syslog_options = syslog_flags;
637 :
638 : /* Set default logging levels. */
639 225 : for (i = 0; i < array_size(zl->maxlvl); i++)
640 180 : zl->maxlvl[i] = ZLOG_DISABLED;
641 45 : zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG;
642 45 : zl->default_lvl = LOG_DEBUG;
643 :
644 45 : openlog (progname, syslog_flags, zl->facility);
645 :
646 45 : return zl;
647 : }
648 :
649 : void
650 0 : closezlog (struct zlog *zl)
651 : {
652 0 : closelog();
653 :
654 0 : if (zl->fp != NULL)
655 0 : fclose (zl->fp);
656 :
657 0 : if (zl->filename != NULL)
658 0 : free (zl->filename);
659 :
660 0 : XFREE (MTYPE_ZLOG, zl);
661 0 : }
662 :
663 : /* Called from command.c. */
664 : void
665 0 : zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level)
666 : {
667 0 : if (zl == NULL)
668 0 : zl = zlog_default;
669 :
670 0 : zl->maxlvl[dest] = log_level;
671 0 : }
672 :
673 : int
674 45 : zlog_set_file (struct zlog *zl, const char *filename, int log_level)
675 : {
676 : FILE *fp;
677 : mode_t oldumask;
678 :
679 : /* There is opend file. */
680 45 : zlog_reset_file (zl);
681 :
682 : /* Set default zl. */
683 45 : if (zl == NULL)
684 45 : zl = zlog_default;
685 :
686 : /* Open file. */
687 45 : oldumask = umask (0777 & ~LOGFILE_MASK);
688 45 : fp = fopen (filename, "a");
689 45 : umask(oldumask);
690 45 : if (fp == NULL)
691 0 : return 0;
692 :
693 : /* Set flags. */
694 45 : zl->filename = strdup (filename);
695 45 : zl->maxlvl[ZLOG_DEST_FILE] = log_level;
696 45 : zl->fp = fp;
697 45 : logfile_fd = fileno(fp);
698 :
699 45 : return 1;
700 : }
701 :
702 : /* Reset opend file. */
703 : int
704 45 : zlog_reset_file (struct zlog *zl)
705 : {
706 45 : if (zl == NULL)
707 45 : zl = zlog_default;
708 :
709 45 : if (zl->fp)
710 0 : fclose (zl->fp);
711 45 : zl->fp = NULL;
712 45 : logfile_fd = -1;
713 45 : zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
714 :
715 45 : if (zl->filename)
716 0 : free (zl->filename);
717 45 : zl->filename = NULL;
718 :
719 45 : return 1;
720 : }
721 :
722 : /* Reopen log file. */
723 : int
724 0 : zlog_rotate (struct zlog *zl)
725 : {
726 : int level;
727 :
728 0 : if (zl == NULL)
729 0 : zl = zlog_default;
730 :
731 0 : if (zl->fp)
732 0 : fclose (zl->fp);
733 0 : zl->fp = NULL;
734 0 : logfile_fd = -1;
735 0 : level = zl->maxlvl[ZLOG_DEST_FILE];
736 0 : zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
737 :
738 0 : if (zl->filename)
739 : {
740 : mode_t oldumask;
741 : int save_errno;
742 :
743 0 : oldumask = umask (0777 & ~LOGFILE_MASK);
744 0 : zl->fp = fopen (zl->filename, "a");
745 0 : save_errno = errno;
746 0 : umask(oldumask);
747 0 : if (zl->fp == NULL)
748 : {
749 0 : zlog_err("Log rotate failed: cannot open file %s for append: %s",
750 : zl->filename, safe_strerror(save_errno));
751 0 : return -1;
752 : }
753 0 : logfile_fd = fileno(zl->fp);
754 0 : zl->maxlvl[ZLOG_DEST_FILE] = level;
755 : }
756 :
757 0 : return 1;
758 : }
759 :
760 : /* Message lookup function. */
761 : const char *
762 796 : lookup (const struct message *mes, int key)
763 : {
764 : const struct message *pnt;
765 :
766 1674 : for (pnt = mes; pnt->key != 0; pnt++)
767 1657 : if (pnt->key == key)
768 779 : return pnt->str;
769 :
770 17 : return "";
771 : }
772 :
773 : /* Older/faster version of message lookup function, but requires caller to pass
774 : * in the array size (instead of relying on a 0 key to terminate the search).
775 : *
776 : * The return value is the message string if found, or the 'none' pointer
777 : * provided otherwise.
778 : */
779 : const char *
780 157 : mes_lookup (const struct message *meslist, int max, int index,
781 : const char *none, const char *mesname)
782 : {
783 157 : int pos = index - meslist[0].key;
784 :
785 : /* first check for best case: index is in range and matches the key
786 : * value in that slot.
787 : * NB: key numbering might be offset from 0. E.g. protocol constants
788 : * often start at 1.
789 : */
790 157 : if ((pos >= 0) && (pos < max)
791 134 : && (meslist[pos].key == index))
792 134 : return meslist[pos].str;
793 :
794 : /* fall back to linear search */
795 : {
796 : int i;
797 :
798 130 : for (i = 0; i < max; i++, meslist++)
799 : {
800 129 : if (meslist->key == index)
801 : {
802 22 : const char *str = (meslist->str ? meslist->str : none);
803 :
804 22 : zlog_debug ("message index %d [%s] found in %s at position %d (max is %d)",
805 : index, str, mesname, i, max);
806 22 : return str;
807 : }
808 : }
809 : }
810 1 : zlog_err("message index %d not found in %s (max is %d)", index, mesname, max);
811 1 : assert (none);
812 1 : return none;
813 : }
814 :
815 : /* Wrapper around strerror to handle case where it returns NULL. */
816 : const char *
817 4 : safe_strerror(int errnum)
818 : {
819 4 : const char *s = strerror(errnum);
820 4 : return (s != NULL) ? s : "Unknown error";
821 : }
822 :
823 : #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
824 : static const struct zebra_desc_table command_types[] = {
825 : DESC_ENTRY (ZEBRA_INTERFACE_ADD),
826 : DESC_ENTRY (ZEBRA_INTERFACE_DELETE),
827 : DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_ADD),
828 : DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_DELETE),
829 : DESC_ENTRY (ZEBRA_INTERFACE_UP),
830 : DESC_ENTRY (ZEBRA_INTERFACE_DOWN),
831 : DESC_ENTRY (ZEBRA_IPV4_ROUTE_ADD),
832 : DESC_ENTRY (ZEBRA_IPV4_ROUTE_DELETE),
833 : DESC_ENTRY (ZEBRA_IPV6_ROUTE_ADD),
834 : DESC_ENTRY (ZEBRA_IPV6_ROUTE_DELETE),
835 : DESC_ENTRY (ZEBRA_REDISTRIBUTE_ADD),
836 : DESC_ENTRY (ZEBRA_REDISTRIBUTE_DELETE),
837 : DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_ADD),
838 : DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE),
839 : DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP),
840 : DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_LOOKUP),
841 : DESC_ENTRY (ZEBRA_IPV4_IMPORT_LOOKUP),
842 : DESC_ENTRY (ZEBRA_IPV6_IMPORT_LOOKUP),
843 : DESC_ENTRY (ZEBRA_INTERFACE_RENAME),
844 : DESC_ENTRY (ZEBRA_ROUTER_ID_ADD),
845 : DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
846 : DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
847 : DESC_ENTRY (ZEBRA_HELLO),
848 : };
849 : #undef DESC_ENTRY
850 :
851 : static const struct zebra_desc_table unknown = { 0, "unknown", '?' };
852 :
853 : static const struct zebra_desc_table *
854 628 : zroute_lookup(u_int zroute)
855 : {
856 : u_int i;
857 :
858 628 : if (zroute >= array_size(route_types))
859 : {
860 0 : zlog_err("unknown zebra route type: %u", zroute);
861 0 : return &unknown;
862 : }
863 628 : if (zroute == route_types[zroute].type)
864 628 : return &route_types[zroute];
865 0 : for (i = 0; i < array_size(route_types); i++)
866 : {
867 0 : if (zroute == route_types[i].type)
868 : {
869 0 : zlog_warn("internal error: route type table out of order "
870 : "while searching for %u, please notify developers", zroute);
871 0 : return &route_types[i];
872 : }
873 : }
874 0 : zlog_err("internal error: cannot find route type %u in table!", zroute);
875 0 : return &unknown;
876 : }
877 :
878 : const char *
879 95 : zebra_route_string(u_int zroute)
880 : {
881 95 : return zroute_lookup(zroute)->string;
882 : }
883 :
884 : char
885 533 : zebra_route_char(u_int zroute)
886 : {
887 533 : return zroute_lookup(zroute)->chr;
888 : }
889 :
890 : const char *
891 187 : zserv_command_string (unsigned int command)
892 : {
893 187 : if (command >= array_size(command_types))
894 : {
895 0 : zlog_err ("unknown zserv command type: %u", command);
896 0 : return unknown.string;
897 : }
898 187 : return command_types[command].string;
899 : }
900 :
901 : int
902 15 : proto_name2num(const char *s)
903 : {
904 : unsigned i;
905 :
906 108 : for (i=0; i<array_size(route_types); ++i)
907 108 : if (strcasecmp(s, route_types[i].string) == 0)
908 15 : return route_types[i].type;
909 0 : return -1;
910 : }
911 :
912 : int
913 0 : proto_redistnum(int afi, const char *s)
914 : {
915 0 : if (! s)
916 0 : return -1;
917 :
918 0 : if (afi == AFI_IP)
919 : {
920 0 : if (strncmp (s, "k", 1) == 0)
921 0 : return ZEBRA_ROUTE_KERNEL;
922 0 : else if (strncmp (s, "c", 1) == 0)
923 0 : return ZEBRA_ROUTE_CONNECT;
924 0 : else if (strncmp (s, "s", 1) == 0)
925 0 : return ZEBRA_ROUTE_STATIC;
926 0 : else if (strncmp (s, "r", 1) == 0)
927 0 : return ZEBRA_ROUTE_RIP;
928 0 : else if (strncmp (s, "o", 1) == 0)
929 0 : return ZEBRA_ROUTE_OSPF;
930 0 : else if (strncmp (s, "i", 1) == 0)
931 0 : return ZEBRA_ROUTE_ISIS;
932 0 : else if (strncmp (s, "bg", 2) == 0)
933 0 : return ZEBRA_ROUTE_BGP;
934 0 : else if (strncmp (s, "ba", 2) == 0)
935 0 : return ZEBRA_ROUTE_BABEL;
936 : }
937 0 : if (afi == AFI_IP6)
938 : {
939 0 : if (strncmp (s, "k", 1) == 0)
940 0 : return ZEBRA_ROUTE_KERNEL;
941 0 : else if (strncmp (s, "c", 1) == 0)
942 0 : return ZEBRA_ROUTE_CONNECT;
943 0 : else if (strncmp (s, "s", 1) == 0)
944 0 : return ZEBRA_ROUTE_STATIC;
945 0 : else if (strncmp (s, "r", 1) == 0)
946 0 : return ZEBRA_ROUTE_RIPNG;
947 0 : else if (strncmp (s, "o", 1) == 0)
948 0 : return ZEBRA_ROUTE_OSPF6;
949 0 : else if (strncmp (s, "i", 1) == 0)
950 0 : return ZEBRA_ROUTE_ISIS;
951 0 : else if (strncmp (s, "bg", 2) == 0)
952 0 : return ZEBRA_ROUTE_BGP;
953 0 : else if (strncmp (s, "ba", 2) == 0)
954 0 : return ZEBRA_ROUTE_BABEL;
955 : }
956 0 : return -1;
957 : }
|