blob: 76682227c08a1981a02f3590a3447e55aa8e6676 [file] [log] [blame]
ajs274a4a42004-12-07 15:39:31 +00001/*
Paul Jakmafb66b292006-05-28 08:26:15 +00002 * $Id$
ajs274a4a42004-12-07 15:39:31 +00003 *
4 * Logging of zebra
paul718e3742002-12-13 20:15:29 +00005 * 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"
ajs7d149b82004-11-28 23:00:01 +000030#ifndef SUNOS_5
31#include <sys/un.h>
32#endif
paul718e3742002-12-13 20:15:29 +000033
ajsc4c7d0c2005-02-03 19:22:05 +000034static int logfile_fd = -1; /* Used in signal handler. */
ajs1e221352005-02-03 16:42:40 +000035
paul718e3742002-12-13 20:15:29 +000036struct zlog *zlog_default = NULL;
37
38const char *zlog_proto_names[] =
39{
40 "NONE",
41 "DEFAULT",
42 "ZEBRA",
43 "RIP",
44 "BGP",
45 "OSPF",
46 "RIPNG",
47 "OSPF6",
jardin9e867fe2003-12-23 08:56:18 +000048 "ISIS",
paul718e3742002-12-13 20:15:29 +000049 "MASC",
50 NULL,
51};
52
53const 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
68/* For time string format. */
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +000069
70size_t
71quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
72{
73 static struct {
74 time_t last;
75 size_t len;
76 char buf[28];
77 } cache;
78 struct timeval clock;
79
80 /* would it be sufficient to use global 'recent_time' here? I fear not... */
81 gettimeofday(&clock, NULL);
82
83 /* first, we update the cache if the time has changed */
84 if (cache.last != clock.tv_sec)
85 {
86 struct tm *tm;
87 cache.last = clock.tv_sec;
88 tm = localtime(&cache.last);
89 cache.len = strftime(cache.buf, sizeof(cache.buf),
90 "%Y/%m/%d %H:%M:%S", tm);
91 }
92 /* note: it's not worth caching the subsecond part, because
93 chances are that back-to-back calls are not sufficiently close together
94 for the clock not to have ticked forward */
95
96 if (buflen > cache.len)
97 {
98 memcpy(buf, cache.buf, cache.len);
99 if ((timestamp_precision > 0) &&
100 (buflen > cache.len+1+timestamp_precision))
101 {
102 /* should we worry about locale issues? */
103 long divisor = 100000;
104 char *p = buf+cache.len;
105 *p++ = '.';
106 do
107 {
108 *p++ = '0'+(clock.tv_usec/divisor);
109 clock.tv_usec %= divisor;
110 divisor /= 10;
111 }
112 while (--timestamp_precision > 0);
113 *p = '\0';
114 return p-buf;
115 }
116 buf[cache.len] = '\0';
117 return cache.len;
118 }
119 if (buflen > 0)
120 buf[0] = '\0';
121 return 0;
122}
paul718e3742002-12-13 20:15:29 +0000123
124/* Utility routine for current time printing. */
125static void
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000126time_print(FILE *fp, struct timestamp_control *ctl)
paul718e3742002-12-13 20:15:29 +0000127{
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000128 if (!ctl->already_rendered)
129 {
130 ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
131 ctl->already_rendered = 1;
132 }
133 fprintf(fp, "%s ", ctl->buf);
paul718e3742002-12-13 20:15:29 +0000134}
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000135
paul718e3742002-12-13 20:15:29 +0000136
137/* va_list version of zlog. */
ajsd246bd92004-11-23 17:35:08 +0000138static void
139vzlog (struct zlog *zl, int priority, const char *format, va_list args)
paul718e3742002-12-13 20:15:29 +0000140{
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000141 struct timestamp_control tsctl;
142 tsctl.already_rendered = 0;
143
paul718e3742002-12-13 20:15:29 +0000144 /* If zlog is not specified, use default one. */
145 if (zl == NULL)
146 zl = zlog_default;
147
148 /* When zlog_default is also NULL, use stderr for logging. */
149 if (zl == NULL)
150 {
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000151 tsctl.precision = 0;
152 time_print(stderr, &tsctl);
paul718e3742002-12-13 20:15:29 +0000153 fprintf (stderr, "%s: ", "unknown");
ajsd246bd92004-11-23 17:35:08 +0000154 vfprintf (stderr, format, args);
paul718e3742002-12-13 20:15:29 +0000155 fprintf (stderr, "\n");
156 fflush (stderr);
157
158 /* In this case we return at here. */
159 return;
160 }
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000161 tsctl.precision = zl->timestamp_precision;
paul718e3742002-12-13 20:15:29 +0000162
paul718e3742002-12-13 20:15:29 +0000163 /* Syslog output */
ajs274a4a42004-12-07 15:39:31 +0000164 if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
ajsd246bd92004-11-23 17:35:08 +0000165 {
166 va_list ac;
167 va_copy(ac, args);
168 vsyslog (priority|zlog_default->facility, format, ac);
169 va_end(ac);
170 }
paul718e3742002-12-13 20:15:29 +0000171
172 /* File output. */
ajs274a4a42004-12-07 15:39:31 +0000173 if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
paul718e3742002-12-13 20:15:29 +0000174 {
ajsd246bd92004-11-23 17:35:08 +0000175 va_list ac;
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000176 time_print (zl->fp, &tsctl);
hassob04c6992004-10-04 19:10:31 +0000177 if (zl->record_priority)
178 fprintf (zl->fp, "%s: ", zlog_priority[priority]);
paul718e3742002-12-13 20:15:29 +0000179 fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
ajsd246bd92004-11-23 17:35:08 +0000180 va_copy(ac, args);
181 vfprintf (zl->fp, format, ac);
182 va_end(ac);
paul718e3742002-12-13 20:15:29 +0000183 fprintf (zl->fp, "\n");
184 fflush (zl->fp);
185 }
186
187 /* stdout output. */
ajs274a4a42004-12-07 15:39:31 +0000188 if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
paul718e3742002-12-13 20:15:29 +0000189 {
ajsd246bd92004-11-23 17:35:08 +0000190 va_list ac;
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000191 time_print (stdout, &tsctl);
hassob04c6992004-10-04 19:10:31 +0000192 if (zl->record_priority)
193 fprintf (stdout, "%s: ", zlog_priority[priority]);
paul718e3742002-12-13 20:15:29 +0000194 fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
ajsd246bd92004-11-23 17:35:08 +0000195 va_copy(ac, args);
196 vfprintf (stdout, format, ac);
197 va_end(ac);
paul718e3742002-12-13 20:15:29 +0000198 fprintf (stdout, "\n");
199 fflush (stdout);
200 }
201
paul718e3742002-12-13 20:15:29 +0000202 /* Terminal monitor. */
ajs274a4a42004-12-07 15:39:31 +0000203 if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
204 vty_log ((zl->record_priority ? zlog_priority[priority] : NULL),
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000205 zlog_proto_names[zl->protocol], format, &tsctl, args);
paul718e3742002-12-13 20:15:29 +0000206}
207
ajs59a06a92004-11-23 18:19:14 +0000208static char *
209str_append(char *dst, int len, const char *src)
210{
211 while ((len-- > 0) && *src)
212 *dst++ = *src++;
213 return dst;
214}
215
216static char *
217num_append(char *s, int len, u_long x)
218{
219 char buf[30];
ajs7d149b82004-11-28 23:00:01 +0000220 char *t;
ajs59a06a92004-11-23 18:19:14 +0000221
ajs7d149b82004-11-28 23:00:01 +0000222 if (!x)
223 return str_append(s,len,"0");
224 *(t = &buf[sizeof(buf)-1]) = '\0';
ajs59a06a92004-11-23 18:19:14 +0000225 while (x && (t > buf))
226 {
227 *--t = '0'+(x % 10);
228 x /= 10;
229 }
230 return str_append(s,len,t);
231}
232
Paul Jakmafb66b292006-05-28 08:26:15 +0000233#if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE)
ajs7d149b82004-11-28 23:00:01 +0000234static char *
235hex_append(char *s, int len, u_long x)
236{
237 char buf[30];
238 char *t;
239
240 if (!x)
241 return str_append(s,len,"0");
242 *(t = &buf[sizeof(buf)-1]) = '\0';
243 while (x && (t > buf))
244 {
245 u_int cc = (x % 16);
246 *--t = ((cc < 10) ? ('0'+cc) : ('a'+cc-10));
247 x /= 16;
248 }
249 return str_append(s,len,t);
250}
ajs31364272005-01-18 22:18:59 +0000251#endif
ajs7d149b82004-11-28 23:00:01 +0000252
ajs7d149b82004-11-28 23:00:01 +0000253/* Needs to be enhanced to support Solaris. */
254static int
255syslog_connect(void)
256{
257#ifdef SUNOS_5
258 return -1;
259#else
260 int fd;
261 char *s;
262 struct sockaddr_un addr;
263
264 if ((fd = socket(AF_UNIX,SOCK_DGRAM,0)) < 0)
265 return -1;
266 addr.sun_family = AF_UNIX;
267#ifdef _PATH_LOG
268#define SYSLOG_SOCKET_PATH _PATH_LOG
269#else
270#define SYSLOG_SOCKET_PATH "/dev/log"
271#endif
272 s = str_append(addr.sun_path,sizeof(addr.sun_path),SYSLOG_SOCKET_PATH);
273#undef SYSLOG_SOCKET_PATH
274 *s = '\0';
275 if (connect(fd,(struct sockaddr *)&addr,sizeof(addr)) < 0)
276 {
277 close(fd);
278 return -1;
279 }
280 return fd;
281#endif
282}
283
284static void
285syslog_sigsafe(int priority, const char *msg, size_t msglen)
286{
ajs1e221352005-02-03 16:42:40 +0000287 static int syslog_fd = -1;
ajs7d149b82004-11-28 23:00:01 +0000288 char buf[sizeof("<1234567890>ripngd[1234567890]: ")+msglen+50];
289 char *s;
290
291 if ((syslog_fd < 0) && ((syslog_fd = syslog_connect()) < 0))
292 return;
293
294#define LOC s,buf+sizeof(buf)-s
295 s = buf;
296 s = str_append(LOC,"<");
297 s = num_append(LOC,priority);
298 s = str_append(LOC,">");
299 /* forget about the timestamp, too difficult in a signal handler */
300 s = str_append(LOC,zlog_default->ident);
301 if (zlog_default->syslog_options & LOG_PID)
302 {
303 s = str_append(LOC,"[");
304 s = num_append(LOC,getpid());
305 s = str_append(LOC,"]");
306 }
307 s = str_append(LOC,": ");
308 s = str_append(LOC,msg);
309 write(syslog_fd,buf,s-buf);
310#undef LOC
311}
312
ajs1e221352005-02-03 16:42:40 +0000313static int
314open_crashlog(void)
315{
316#define CRASHLOG_PREFIX "/var/tmp/quagga."
317#define CRASHLOG_SUFFIX "crashlog"
318 if (zlog_default && zlog_default->ident)
319 {
320 /* Avoid strlen since it is not async-signal-safe. */
321 const char *p;
322 size_t ilen;
323
324 for (p = zlog_default->ident, ilen = 0; *p; p++)
325 ilen++;
326 {
327 char buf[sizeof(CRASHLOG_PREFIX)+ilen+sizeof(CRASHLOG_SUFFIX)+3];
328 char *s = buf;
329#define LOC s,buf+sizeof(buf)-s
330 s = str_append(LOC, CRASHLOG_PREFIX);
331 s = str_append(LOC, zlog_default->ident);
332 s = str_append(LOC, ".");
333 s = str_append(LOC, CRASHLOG_SUFFIX);
334#undef LOC
335 *s = '\0';
336 return open(buf, O_WRONLY|O_CREAT|O_EXCL, LOGFILE_MASK);
337 }
338 }
339 return open(CRASHLOG_PREFIX CRASHLOG_SUFFIX, O_WRONLY|O_CREAT|O_EXCL,
340 LOGFILE_MASK);
341#undef CRASHLOG_SUFFIX
342#undef CRASHLOG_PREFIX
343}
344
ajs7d149b82004-11-28 23:00:01 +0000345/* Note: the goal here is to use only async-signal-safe functions. */
ajs59a06a92004-11-23 18:19:14 +0000346void
ajs31364272005-01-18 22:18:59 +0000347zlog_signal(int signo, const char *action
348#ifdef SA_SIGINFO
349 , siginfo_t *siginfo, void *program_counter
350#endif
351 )
ajs59a06a92004-11-23 18:19:14 +0000352{
353 time_t now;
ajs40abf232005-01-12 17:27:27 +0000354 char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100];
ajs59a06a92004-11-23 18:19:14 +0000355 char *s = buf;
ajs7d149b82004-11-28 23:00:01 +0000356 char *msgstart = buf;
ajs59a06a92004-11-23 18:19:14 +0000357#define LOC s,buf+sizeof(buf)-s
358
359 time(&now);
360 if (zlog_default)
361 {
362 s = str_append(LOC,zlog_proto_names[zlog_default->protocol]);
363 *s++ = ':';
364 *s++ = ' ';
ajs7d149b82004-11-28 23:00:01 +0000365 msgstart = s;
ajs59a06a92004-11-23 18:19:14 +0000366 }
367 s = str_append(LOC,"Received signal ");
368 s = num_append(LOC,signo);
369 s = str_append(LOC," at ");
370 s = num_append(LOC,now);
ajs31364272005-01-18 22:18:59 +0000371#ifdef SA_SIGINFO
ajs40abf232005-01-12 17:27:27 +0000372 s = str_append(LOC," (si_addr 0x");
373 s = hex_append(LOC,(u_long)(siginfo->si_addr));
374 if (program_counter)
375 {
376 s = str_append(LOC,", PC 0x");
377 s = hex_append(LOC,(u_long)program_counter);
378 }
379 s = str_append(LOC,"); ");
ajs31364272005-01-18 22:18:59 +0000380#else /* SA_SIGINFO */
381 s = str_append(LOC,"; ");
382#endif /* SA_SIGINFO */
ajs59a06a92004-11-23 18:19:14 +0000383 s = str_append(LOC,action);
ajs7d149b82004-11-28 23:00:01 +0000384 if (s < buf+sizeof(buf))
385 *s++ = '\n';
ajs59a06a92004-11-23 18:19:14 +0000386
ajs274a4a42004-12-07 15:39:31 +0000387 /* N.B. implicit priority is most severe */
ajs1e221352005-02-03 16:42:40 +0000388#define PRI LOG_CRIT
ajs274a4a42004-12-07 15:39:31 +0000389
ajs1e221352005-02-03 16:42:40 +0000390#define DUMP(FD) write(FD, buf, s-buf);
391 /* If no file logging configured, try to write to fallback log file. */
ajsc4c7d0c2005-02-03 19:22:05 +0000392 if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
393 DUMP(logfile_fd)
ajs59a06a92004-11-23 18:19:14 +0000394 if (!zlog_default)
ajsc4c7d0c2005-02-03 19:22:05 +0000395 DUMP(STDERR_FILENO)
ajs59a06a92004-11-23 18:19:14 +0000396 else
397 {
ajs274a4a42004-12-07 15:39:31 +0000398 if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
ajsc4c7d0c2005-02-03 19:22:05 +0000399 DUMP(STDOUT_FILENO)
ajs274a4a42004-12-07 15:39:31 +0000400 /* Remove trailing '\n' for monitor and syslog */
401 *--s = '\0';
402 if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
403 vty_log_fixed(buf,s-buf);
404 if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
405 syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart);
ajs59a06a92004-11-23 18:19:14 +0000406 }
407#undef DUMP
408
ajs31364272005-01-18 22:18:59 +0000409 zlog_backtrace_sigsafe(PRI,
410#ifdef SA_SIGINFO
411 program_counter
412#else
413 NULL
414#endif
415 );
ajs274a4a42004-12-07 15:39:31 +0000416#undef PRI
ajs063ee522004-11-26 18:11:14 +0000417#undef LOC
418}
ajs59a06a92004-11-23 18:19:14 +0000419
ajs063ee522004-11-26 18:11:14 +0000420/* Log a backtrace using only async-signal-safe functions.
421 Needs to be enhanced to support syslog logging. */
422void
ajs239c26f2005-01-17 15:22:28 +0000423zlog_backtrace_sigsafe(int priority, void *program_counter)
ajs063ee522004-11-26 18:11:14 +0000424{
Paul Jakmafb66b292006-05-28 08:26:15 +0000425#ifdef HAVE_STACK_TRACE
ajs239c26f2005-01-17 15:22:28 +0000426 static const char pclabel[] = "Program counter: ";
ajs063ee522004-11-26 18:11:14 +0000427 void *array[20];
428 int size;
429 char buf[100];
430 char *s;
431#define LOC s,buf+sizeof(buf)-s
432
Paul Jakmafb66b292006-05-28 08:26:15 +0000433#ifdef HAVE_GLIBC_BACKTRACE
ajs063ee522004-11-26 18:11:14 +0000434 if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) ||
435 ((size_t)size > sizeof(array)/sizeof(array[0])))
436 return;
ajs59a06a92004-11-23 18:19:14 +0000437
ajs1e221352005-02-03 16:42:40 +0000438#define DUMP(FD) { \
ajs239c26f2005-01-17 15:22:28 +0000439 if (program_counter) \
440 { \
ajs1e221352005-02-03 16:42:40 +0000441 write(FD, pclabel, sizeof(pclabel)-1); \
442 backtrace_symbols_fd(&program_counter, 1, FD); \
ajs239c26f2005-01-17 15:22:28 +0000443 } \
ajs1e221352005-02-03 16:42:40 +0000444 write(FD, buf, s-buf); \
445 backtrace_symbols_fd(array, size, FD); \
ajs59a06a92004-11-23 18:19:14 +0000446}
Paul Jakmafb66b292006-05-28 08:26:15 +0000447#elif defined(HAVE_PRINTSTACK)
448#define DUMP(FD) { \
449 if (program_counter) \
450 write((FD), pclabel, sizeof(pclabel)-1); \
451 write((FD), buf, s-buf); \
452 printstack((FD)); \
453}
454#endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
455
456 s = buf;
457 s = str_append(LOC,"Backtrace for ");
458 s = num_append(LOC,size);
459 s = str_append(LOC," stack frames:\n");
ajs59a06a92004-11-23 18:19:14 +0000460
ajsc4c7d0c2005-02-03 19:22:05 +0000461 if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
462 DUMP(logfile_fd)
ajs59a06a92004-11-23 18:19:14 +0000463 if (!zlog_default)
ajsc4c7d0c2005-02-03 19:22:05 +0000464 DUMP(STDERR_FILENO)
ajs59a06a92004-11-23 18:19:14 +0000465 else
466 {
ajs274a4a42004-12-07 15:39:31 +0000467 if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
ajsc4c7d0c2005-02-03 19:22:05 +0000468 DUMP(STDOUT_FILENO)
ajs274a4a42004-12-07 15:39:31 +0000469 /* Remove trailing '\n' for monitor and syslog */
470 *--s = '\0';
471 if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
472 vty_log_fixed(buf,s-buf);
473 if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
474 syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
475 {
476 int i;
477 /* Just print the function addresses. */
478 for (i = 0; i < size; i++)
479 {
480 s = buf;
481 s = str_append(LOC,"[bt ");
482 s = num_append(LOC,i);
483 s = str_append(LOC,"] 0x");
484 s = hex_append(LOC,(u_long)(array[i]));
485 *s = '\0';
486 if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
487 vty_log_fixed(buf,s-buf);
488 if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
ajs7d149b82004-11-28 23:00:01 +0000489 syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
ajs274a4a42004-12-07 15:39:31 +0000490 }
491 }
ajs59a06a92004-11-23 18:19:14 +0000492 }
493#undef DUMP
ajs59a06a92004-11-23 18:19:14 +0000494#undef LOC
Paul Jakmafb66b292006-05-28 08:26:15 +0000495#endif /* HAVE_STRACK_TRACE */
ajs063ee522004-11-26 18:11:14 +0000496}
497
498void
499zlog_backtrace(int priority)
500{
501#ifndef HAVE_GLIBC_BACKTRACE
502 zlog(NULL, priority, "No backtrace available on this platform.");
503#else
504 void *array[20];
505 int size, i;
506 char **strings;
507
508 if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) ||
509 ((size_t)size > sizeof(array)/sizeof(array[0])))
510 {
511 zlog_err("Cannot get backtrace, returned invalid # of frames %d "
Andrew J. Schorr1ed72e02007-04-28 22:14:10 +0000512 "(valid range is between 1 and %lu)",
513 size, (unsigned long)(sizeof(array)/sizeof(array[0])));
ajs063ee522004-11-26 18:11:14 +0000514 return;
515 }
516 zlog(NULL, priority, "Backtrace for %d stack frames:", size);
517 if (!(strings = backtrace_symbols(array, size)))
518 {
519 zlog_err("Cannot get backtrace symbols (out of memory?)");
520 for (i = 0; i < size; i++)
521 zlog(NULL, priority, "[bt %d] %p",i,array[i]);
522 }
523 else
524 {
525 for (i = 0; i < size; i++)
526 zlog(NULL, priority, "[bt %d] %s",i,strings[i]);
527 free(strings);
528 }
529#endif /* HAVE_GLIBC_BACKTRACE */
ajs59a06a92004-11-23 18:19:14 +0000530}
531
paul718e3742002-12-13 20:15:29 +0000532void
533zlog (struct zlog *zl, int priority, const char *format, ...)
534{
ajsd246bd92004-11-23 17:35:08 +0000535 va_list args;
paul718e3742002-12-13 20:15:29 +0000536
ajsd246bd92004-11-23 17:35:08 +0000537 va_start(args, format);
paul718e3742002-12-13 20:15:29 +0000538 vzlog (zl, priority, format, args);
ajsd246bd92004-11-23 17:35:08 +0000539 va_end (args);
paul718e3742002-12-13 20:15:29 +0000540}
541
ajsd246bd92004-11-23 17:35:08 +0000542#define ZLOG_FUNC(FUNCNAME,PRIORITY) \
543void \
544FUNCNAME(const char *format, ...) \
545{ \
546 va_list args; \
547 va_start(args, format); \
548 vzlog (NULL, PRIORITY, format, args); \
549 va_end(args); \
paul718e3742002-12-13 20:15:29 +0000550}
551
ajsd246bd92004-11-23 17:35:08 +0000552ZLOG_FUNC(zlog_err, LOG_ERR)
paul718e3742002-12-13 20:15:29 +0000553
ajsd246bd92004-11-23 17:35:08 +0000554ZLOG_FUNC(zlog_warn, LOG_WARNING)
paul718e3742002-12-13 20:15:29 +0000555
ajsd246bd92004-11-23 17:35:08 +0000556ZLOG_FUNC(zlog_info, LOG_INFO)
paul718e3742002-12-13 20:15:29 +0000557
ajsd246bd92004-11-23 17:35:08 +0000558ZLOG_FUNC(zlog_notice, LOG_NOTICE)
559
560ZLOG_FUNC(zlog_debug, LOG_DEBUG)
561
562#undef ZLOG_FUNC
563
564#define PLOG_FUNC(FUNCNAME,PRIORITY) \
565void \
566FUNCNAME(struct zlog *zl, const char *format, ...) \
567{ \
568 va_list args; \
569 va_start(args, format); \
570 vzlog (zl, PRIORITY, format, args); \
571 va_end(args); \
paul718e3742002-12-13 20:15:29 +0000572}
573
ajsd246bd92004-11-23 17:35:08 +0000574PLOG_FUNC(plog_err, LOG_ERR)
paul718e3742002-12-13 20:15:29 +0000575
ajsd246bd92004-11-23 17:35:08 +0000576PLOG_FUNC(plog_warn, LOG_WARNING)
paul718e3742002-12-13 20:15:29 +0000577
ajsd246bd92004-11-23 17:35:08 +0000578PLOG_FUNC(plog_info, LOG_INFO)
paul718e3742002-12-13 20:15:29 +0000579
ajsd246bd92004-11-23 17:35:08 +0000580PLOG_FUNC(plog_notice, LOG_NOTICE)
paul718e3742002-12-13 20:15:29 +0000581
ajsd246bd92004-11-23 17:35:08 +0000582PLOG_FUNC(plog_debug, LOG_DEBUG)
paul718e3742002-12-13 20:15:29 +0000583
ajsd246bd92004-11-23 17:35:08 +0000584#undef PLOG_FUNC
paul718e3742002-12-13 20:15:29 +0000585
ajscee3df12004-11-24 17:14:49 +0000586void
587_zlog_assert_failed (const char *assertion, const char *file,
588 unsigned int line, const char *function)
589{
ajsc4c7d0c2005-02-03 19:22:05 +0000590 /* Force fallback file logging? */
591 if (zlog_default && !zlog_default->fp &&
592 ((logfile_fd = open_crashlog()) >= 0) &&
593 ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL))
594 zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
ajs1e221352005-02-03 16:42:40 +0000595 zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
596 assertion,file,line,(function ? function : "?"));
597 zlog_backtrace(LOG_CRIT);
ajscee3df12004-11-24 17:14:49 +0000598 abort();
599}
600
paul718e3742002-12-13 20:15:29 +0000601
602/* Open log stream */
603struct zlog *
ajs274a4a42004-12-07 15:39:31 +0000604openzlog (const char *progname, zlog_proto_t protocol,
paul718e3742002-12-13 20:15:29 +0000605 int syslog_flags, int syslog_facility)
606{
607 struct zlog *zl;
ajs274a4a42004-12-07 15:39:31 +0000608 u_int i;
paul718e3742002-12-13 20:15:29 +0000609
ajs274a4a42004-12-07 15:39:31 +0000610 zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog));
paul718e3742002-12-13 20:15:29 +0000611
612 zl->ident = progname;
paul718e3742002-12-13 20:15:29 +0000613 zl->protocol = protocol;
614 zl->facility = syslog_facility;
ajs7d149b82004-11-28 23:00:01 +0000615 zl->syslog_options = syslog_flags;
paul718e3742002-12-13 20:15:29 +0000616
ajs274a4a42004-12-07 15:39:31 +0000617 /* Set default logging levels. */
618 for (i = 0; i < sizeof(zl->maxlvl)/sizeof(zl->maxlvl[0]); i++)
619 zl->maxlvl[i] = ZLOG_DISABLED;
620 zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG;
621 zl->default_lvl = LOG_DEBUG;
622
paul718e3742002-12-13 20:15:29 +0000623 openlog (progname, syslog_flags, zl->facility);
624
625 return zl;
626}
627
628void
629closezlog (struct zlog *zl)
630{
631 closelog();
632 fclose (zl->fp);
633
634 XFREE (MTYPE_ZLOG, zl);
635}
636
637/* Called from command.c. */
638void
ajs274a4a42004-12-07 15:39:31 +0000639zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level)
paul718e3742002-12-13 20:15:29 +0000640{
641 if (zl == NULL)
642 zl = zlog_default;
643
ajs274a4a42004-12-07 15:39:31 +0000644 zl->maxlvl[dest] = log_level;
paul718e3742002-12-13 20:15:29 +0000645}
646
647int
ajs274a4a42004-12-07 15:39:31 +0000648zlog_set_file (struct zlog *zl, const char *filename, int log_level)
paul718e3742002-12-13 20:15:29 +0000649{
650 FILE *fp;
gdtaa593d52003-12-22 20:15:53 +0000651 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000652
653 /* There is opend file. */
654 zlog_reset_file (zl);
655
656 /* Set default zl. */
657 if (zl == NULL)
658 zl = zlog_default;
659
660 /* Open file. */
gdtaa593d52003-12-22 20:15:53 +0000661 oldumask = umask (0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000662 fp = fopen (filename, "a");
gdtaa593d52003-12-22 20:15:53 +0000663 umask(oldumask);
ajs274a4a42004-12-07 15:39:31 +0000664 if (fp == NULL)
665 return 0;
paul718e3742002-12-13 20:15:29 +0000666
667 /* Set flags. */
668 zl->filename = strdup (filename);
ajs274a4a42004-12-07 15:39:31 +0000669 zl->maxlvl[ZLOG_DEST_FILE] = log_level;
paul718e3742002-12-13 20:15:29 +0000670 zl->fp = fp;
ajsc4c7d0c2005-02-03 19:22:05 +0000671 logfile_fd = fileno(fp);
paul718e3742002-12-13 20:15:29 +0000672
673 return 1;
674}
675
676/* Reset opend file. */
677int
678zlog_reset_file (struct zlog *zl)
679{
680 if (zl == NULL)
681 zl = zlog_default;
682
paul718e3742002-12-13 20:15:29 +0000683 if (zl->fp)
684 fclose (zl->fp);
685 zl->fp = NULL;
ajsc4c7d0c2005-02-03 19:22:05 +0000686 logfile_fd = -1;
ajs274a4a42004-12-07 15:39:31 +0000687 zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
paul718e3742002-12-13 20:15:29 +0000688
689 if (zl->filename)
690 free (zl->filename);
691 zl->filename = NULL;
692
693 return 1;
694}
695
696/* Reopen log file. */
697int
698zlog_rotate (struct zlog *zl)
699{
ajs274a4a42004-12-07 15:39:31 +0000700 int level;
paul718e3742002-12-13 20:15:29 +0000701
702 if (zl == NULL)
703 zl = zlog_default;
704
705 if (zl->fp)
706 fclose (zl->fp);
707 zl->fp = NULL;
ajsc4c7d0c2005-02-03 19:22:05 +0000708 logfile_fd = -1;
ajs274a4a42004-12-07 15:39:31 +0000709 level = zl->maxlvl[ZLOG_DEST_FILE];
710 zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
paul718e3742002-12-13 20:15:29 +0000711
712 if (zl->filename)
713 {
gdtaa593d52003-12-22 20:15:53 +0000714 mode_t oldumask;
ajs274a4a42004-12-07 15:39:31 +0000715 int save_errno;
gdtaa593d52003-12-22 20:15:53 +0000716
717 oldumask = umask (0777 & ~LOGFILE_MASK);
ajs274a4a42004-12-07 15:39:31 +0000718 zl->fp = fopen (zl->filename, "a");
719 save_errno = errno;
720 umask(oldumask);
721 if (zl->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000722 {
ajs274a4a42004-12-07 15:39:31 +0000723 zlog_err("Log rotate failed: cannot open file %s for append: %s",
724 zl->filename, safe_strerror(save_errno));
gdtaa593d52003-12-22 20:15:53 +0000725 return -1;
726 }
ajsc4c7d0c2005-02-03 19:22:05 +0000727 logfile_fd = fileno(zl->fp);
ajs274a4a42004-12-07 15:39:31 +0000728 zl->maxlvl[ZLOG_DEST_FILE] = level;
paul718e3742002-12-13 20:15:29 +0000729 }
730
731 return 1;
732}
733
paul718e3742002-12-13 20:15:29 +0000734/* Message lookup function. */
hasso8c328f12004-10-05 21:01:23 +0000735const char *
paul718e3742002-12-13 20:15:29 +0000736lookup (struct message *mes, int key)
737{
738 struct message *pnt;
739
740 for (pnt = mes; pnt->key != 0; pnt++)
741 if (pnt->key == key)
742 return pnt->str;
743
744 return "";
745}
746
Andrew J. Schorrafb88a62007-03-20 20:48:27 +0000747/* Older/faster version of message lookup function, but requires caller to pass
748 in the array size (instead of relying on a 0 key to terminate the search). */
hasso8c328f12004-10-05 21:01:23 +0000749const char *
paul718e3742002-12-13 20:15:29 +0000750mes_lookup (struct message *meslist, int max, int index)
751{
Andrew J. Schorrafb88a62007-03-20 20:48:27 +0000752 /* first check for best case: index is in range and matches the key
753 value in that slot */
754 if ((index >= 0) && (index < max) && (meslist[index].key == index))
755 return meslist[index].str;
756
757 /* fall back to linear search */
758 {
759 int i;
760
761 for (i = 0; i < max; i++, meslist++)
762 {
763 if (meslist->key == index)
764 {
765 zlog_warn("message index %d [%s] found in position %d (max is %d)",
766 index, meslist->str, i, max);
767 return meslist->str;
768 }
769 }
770 }
771 zlog_err("message index %d not found (max is %d)", index, max);
772 return NULL;
paul718e3742002-12-13 20:15:29 +0000773}
ajsca359762004-11-19 23:40:16 +0000774
775/* Wrapper around strerror to handle case where it returns NULL. */
776const char *
777safe_strerror(int errnum)
778{
779 const char *s = strerror(errnum);
780 return (s != NULL) ? s : "Unknown error";
781}
ajsf52d13c2005-10-01 17:38:06 +0000782
Paul Jakmad6d672a2006-05-15 16:56:51 +0000783struct zebra_desc_table
784{
785 unsigned int type;
ajsf52d13c2005-10-01 17:38:06 +0000786 const char *string;
787 char chr;
ajsf52d13c2005-10-01 17:38:06 +0000788};
789
Paul Jakmad6d672a2006-05-15 16:56:51 +0000790#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) }
791static const struct zebra_desc_table route_types[] = {
792 DESC_ENTRY (ZEBRA_ROUTE_SYSTEM, "system", 'X' ),
793 DESC_ENTRY (ZEBRA_ROUTE_KERNEL, "kernel", 'K' ),
794 DESC_ENTRY (ZEBRA_ROUTE_CONNECT, "connected", 'C' ),
795 DESC_ENTRY (ZEBRA_ROUTE_STATIC, "static", 'S' ),
796 DESC_ENTRY (ZEBRA_ROUTE_RIP, "rip", 'R' ),
797 DESC_ENTRY (ZEBRA_ROUTE_RIPNG, "ripng", 'R' ),
798 DESC_ENTRY (ZEBRA_ROUTE_OSPF, "ospf", 'O' ),
799 DESC_ENTRY (ZEBRA_ROUTE_OSPF6, "ospf6", 'O' ),
800 DESC_ENTRY (ZEBRA_ROUTE_ISIS, "isis", 'I' ),
801 DESC_ENTRY (ZEBRA_ROUTE_BGP, "bgp", 'B' ),
802 DESC_ENTRY (ZEBRA_ROUTE_HSLS, "hsls", 'H' ),
803};
804#undef DESC_ENTRY
805
806#define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
807static const struct zebra_desc_table command_types[] = {
808 DESC_ENTRY (ZEBRA_INTERFACE_ADD),
809 DESC_ENTRY (ZEBRA_INTERFACE_DELETE),
810 DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_ADD),
811 DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_DELETE),
812 DESC_ENTRY (ZEBRA_INTERFACE_UP),
813 DESC_ENTRY (ZEBRA_INTERFACE_DOWN),
814 DESC_ENTRY (ZEBRA_IPV4_ROUTE_ADD),
815 DESC_ENTRY (ZEBRA_IPV4_ROUTE_DELETE),
816 DESC_ENTRY (ZEBRA_IPV6_ROUTE_ADD),
817 DESC_ENTRY (ZEBRA_IPV6_ROUTE_DELETE),
818 DESC_ENTRY (ZEBRA_REDISTRIBUTE_ADD),
819 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DELETE),
820 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_ADD),
821 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE),
822 DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP),
823 DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_LOOKUP),
824 DESC_ENTRY (ZEBRA_IPV4_IMPORT_LOOKUP),
825 DESC_ENTRY (ZEBRA_IPV6_IMPORT_LOOKUP),
826 DESC_ENTRY (ZEBRA_INTERFACE_RENAME),
827 DESC_ENTRY (ZEBRA_ROUTER_ID_ADD),
828 DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
829 DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
830};
831#undef DESC_ENTRY
832
833static const struct zebra_desc_table unknown = { 0, "unknown", '?' };
834
835static const struct zebra_desc_table *
ajsf52d13c2005-10-01 17:38:06 +0000836zroute_lookup(u_int zroute)
837{
ajsf52d13c2005-10-01 17:38:06 +0000838 u_int i;
839
840 if (zroute >= sizeof(route_types)/sizeof(route_types[0]))
841 {
842 zlog_err("unknown zebra route type: %u", zroute);
843 return &unknown;
844 }
Paul Jakmad6d672a2006-05-15 16:56:51 +0000845 if (zroute == route_types[zroute].type)
ajsf52d13c2005-10-01 17:38:06 +0000846 return &route_types[zroute];
847 for (i = 0; i < sizeof(route_types)/sizeof(route_types[0]); i++)
848 {
Paul Jakmad6d672a2006-05-15 16:56:51 +0000849 if (zroute == route_types[i].type)
ajsf52d13c2005-10-01 17:38:06 +0000850 {
851 zlog_warn("internal error: route type table out of order "
852 "while searching for %u, please notify developers", zroute);
853 return &route_types[i];
854 }
855 }
856 zlog_err("internal error: cannot find route type %u in table!", zroute);
857 return &unknown;
858}
859
860const char *
861zebra_route_string(u_int zroute)
862{
863 return zroute_lookup(zroute)->string;
864}
865
866char
867zebra_route_char(u_int zroute)
868{
869 return zroute_lookup(zroute)->chr;
870}
Paul Jakmad6d672a2006-05-15 16:56:51 +0000871
872const char *
873zserv_command_string (unsigned int command)
874{
875 if (command >= sizeof(command_types)/sizeof(command_types[0]))
876 {
877 zlog_err ("unknown zserv command type: %u", command);
878 return unknown.string;
879 }
880 return command_types[command].string;
881}