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