blob: c123f24f6caf6abcf15159c2bb827c7129336a53 [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. */
69#define TIME_BUF 27
70
71/* Utility routine for current time printing. */
72static void
73time_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
91/* va_list version of zlog. */
ajsd246bd92004-11-23 17:35:08 +000092static void
93vzlog (struct zlog *zl, int priority, const char *format, va_list args)
paul718e3742002-12-13 20:15:29 +000094{
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");
ajsd246bd92004-11-23 17:35:08 +0000104 vfprintf (stderr, format, args);
paul718e3742002-12-13 20:15:29 +0000105 fprintf (stderr, "\n");
106 fflush (stderr);
107
108 /* In this case we return at here. */
109 return;
110 }
111
paul718e3742002-12-13 20:15:29 +0000112 /* Syslog output */
ajs274a4a42004-12-07 15:39:31 +0000113 if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
ajsd246bd92004-11-23 17:35:08 +0000114 {
115 va_list ac;
116 va_copy(ac, args);
117 vsyslog (priority|zlog_default->facility, format, ac);
118 va_end(ac);
119 }
paul718e3742002-12-13 20:15:29 +0000120
121 /* File output. */
ajs274a4a42004-12-07 15:39:31 +0000122 if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
paul718e3742002-12-13 20:15:29 +0000123 {
ajsd246bd92004-11-23 17:35:08 +0000124 va_list ac;
paul718e3742002-12-13 20:15:29 +0000125 time_print (zl->fp);
hassob04c6992004-10-04 19:10:31 +0000126 if (zl->record_priority)
127 fprintf (zl->fp, "%s: ", zlog_priority[priority]);
paul718e3742002-12-13 20:15:29 +0000128 fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
ajsd246bd92004-11-23 17:35:08 +0000129 va_copy(ac, args);
130 vfprintf (zl->fp, format, ac);
131 va_end(ac);
paul718e3742002-12-13 20:15:29 +0000132 fprintf (zl->fp, "\n");
133 fflush (zl->fp);
134 }
135
136 /* stdout output. */
ajs274a4a42004-12-07 15:39:31 +0000137 if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
paul718e3742002-12-13 20:15:29 +0000138 {
ajsd246bd92004-11-23 17:35:08 +0000139 va_list ac;
paul718e3742002-12-13 20:15:29 +0000140 time_print (stdout);
hassob04c6992004-10-04 19:10:31 +0000141 if (zl->record_priority)
142 fprintf (stdout, "%s: ", zlog_priority[priority]);
paul718e3742002-12-13 20:15:29 +0000143 fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
ajsd246bd92004-11-23 17:35:08 +0000144 va_copy(ac, args);
145 vfprintf (stdout, format, ac);
146 va_end(ac);
paul718e3742002-12-13 20:15:29 +0000147 fprintf (stdout, "\n");
148 fflush (stdout);
149 }
150
paul718e3742002-12-13 20:15:29 +0000151 /* Terminal monitor. */
ajs274a4a42004-12-07 15:39:31 +0000152 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);
paul718e3742002-12-13 20:15:29 +0000155}
156
ajs59a06a92004-11-23 18:19:14 +0000157static char *
158str_append(char *dst, int len, const char *src)
159{
160 while ((len-- > 0) && *src)
161 *dst++ = *src++;
162 return dst;
163}
164
165static char *
166num_append(char *s, int len, u_long x)
167{
168 char buf[30];
ajs7d149b82004-11-28 23:00:01 +0000169 char *t;
ajs59a06a92004-11-23 18:19:14 +0000170
ajs7d149b82004-11-28 23:00:01 +0000171 if (!x)
172 return str_append(s,len,"0");
173 *(t = &buf[sizeof(buf)-1]) = '\0';
ajs59a06a92004-11-23 18:19:14 +0000174 while (x && (t > buf))
175 {
176 *--t = '0'+(x % 10);
177 x /= 10;
178 }
179 return str_append(s,len,t);
180}
181
Paul Jakmafb66b292006-05-28 08:26:15 +0000182#if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE)
ajs7d149b82004-11-28 23:00:01 +0000183static char *
184hex_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}
ajs31364272005-01-18 22:18:59 +0000200#endif
ajs7d149b82004-11-28 23:00:01 +0000201
ajs7d149b82004-11-28 23:00:01 +0000202/* Needs to be enhanced to support Solaris. */
203static int
204syslog_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
233static void
234syslog_sigsafe(int priority, const char *msg, size_t msglen)
235{
ajs1e221352005-02-03 16:42:40 +0000236 static int syslog_fd = -1;
ajs7d149b82004-11-28 23:00:01 +0000237 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
ajs1e221352005-02-03 16:42:40 +0000262static int
263open_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
ajs7d149b82004-11-28 23:00:01 +0000294/* Note: the goal here is to use only async-signal-safe functions. */
ajs59a06a92004-11-23 18:19:14 +0000295void
ajs31364272005-01-18 22:18:59 +0000296zlog_signal(int signo, const char *action
297#ifdef SA_SIGINFO
298 , siginfo_t *siginfo, void *program_counter
299#endif
300 )
ajs59a06a92004-11-23 18:19:14 +0000301{
302 time_t now;
ajs40abf232005-01-12 17:27:27 +0000303 char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100];
ajs59a06a92004-11-23 18:19:14 +0000304 char *s = buf;
ajs7d149b82004-11-28 23:00:01 +0000305 char *msgstart = buf;
ajs59a06a92004-11-23 18:19:14 +0000306#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++ = ' ';
ajs7d149b82004-11-28 23:00:01 +0000314 msgstart = s;
ajs59a06a92004-11-23 18:19:14 +0000315 }
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);
ajs31364272005-01-18 22:18:59 +0000320#ifdef SA_SIGINFO
ajs40abf232005-01-12 17:27:27 +0000321 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,"); ");
ajs31364272005-01-18 22:18:59 +0000329#else /* SA_SIGINFO */
330 s = str_append(LOC,"; ");
331#endif /* SA_SIGINFO */
ajs59a06a92004-11-23 18:19:14 +0000332 s = str_append(LOC,action);
ajs7d149b82004-11-28 23:00:01 +0000333 if (s < buf+sizeof(buf))
334 *s++ = '\n';
ajs59a06a92004-11-23 18:19:14 +0000335
ajs274a4a42004-12-07 15:39:31 +0000336 /* N.B. implicit priority is most severe */
ajs1e221352005-02-03 16:42:40 +0000337#define PRI LOG_CRIT
ajs274a4a42004-12-07 15:39:31 +0000338
ajs1e221352005-02-03 16:42:40 +0000339#define DUMP(FD) write(FD, buf, s-buf);
340 /* If no file logging configured, try to write to fallback log file. */
ajsc4c7d0c2005-02-03 19:22:05 +0000341 if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
342 DUMP(logfile_fd)
ajs59a06a92004-11-23 18:19:14 +0000343 if (!zlog_default)
ajsc4c7d0c2005-02-03 19:22:05 +0000344 DUMP(STDERR_FILENO)
ajs59a06a92004-11-23 18:19:14 +0000345 else
346 {
ajs274a4a42004-12-07 15:39:31 +0000347 if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
ajsc4c7d0c2005-02-03 19:22:05 +0000348 DUMP(STDOUT_FILENO)
ajs274a4a42004-12-07 15:39:31 +0000349 /* 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);
ajs59a06a92004-11-23 18:19:14 +0000355 }
356#undef DUMP
357
ajs31364272005-01-18 22:18:59 +0000358 zlog_backtrace_sigsafe(PRI,
359#ifdef SA_SIGINFO
360 program_counter
361#else
362 NULL
363#endif
364 );
ajs274a4a42004-12-07 15:39:31 +0000365#undef PRI
ajs063ee522004-11-26 18:11:14 +0000366#undef LOC
367}
ajs59a06a92004-11-23 18:19:14 +0000368
ajs063ee522004-11-26 18:11:14 +0000369/* Log a backtrace using only async-signal-safe functions.
370 Needs to be enhanced to support syslog logging. */
371void
ajs239c26f2005-01-17 15:22:28 +0000372zlog_backtrace_sigsafe(int priority, void *program_counter)
ajs063ee522004-11-26 18:11:14 +0000373{
Paul Jakmafb66b292006-05-28 08:26:15 +0000374#ifdef HAVE_STACK_TRACE
ajs239c26f2005-01-17 15:22:28 +0000375 static const char pclabel[] = "Program counter: ";
ajs063ee522004-11-26 18:11:14 +0000376 void *array[20];
377 int size;
378 char buf[100];
379 char *s;
380#define LOC s,buf+sizeof(buf)-s
381
Paul Jakmafb66b292006-05-28 08:26:15 +0000382#ifdef HAVE_GLIBC_BACKTRACE
ajs063ee522004-11-26 18:11:14 +0000383 if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) ||
384 ((size_t)size > sizeof(array)/sizeof(array[0])))
385 return;
ajs59a06a92004-11-23 18:19:14 +0000386
ajs1e221352005-02-03 16:42:40 +0000387#define DUMP(FD) { \
ajs239c26f2005-01-17 15:22:28 +0000388 if (program_counter) \
389 { \
ajs1e221352005-02-03 16:42:40 +0000390 write(FD, pclabel, sizeof(pclabel)-1); \
391 backtrace_symbols_fd(&program_counter, 1, FD); \
ajs239c26f2005-01-17 15:22:28 +0000392 } \
ajs1e221352005-02-03 16:42:40 +0000393 write(FD, buf, s-buf); \
394 backtrace_symbols_fd(array, size, FD); \
ajs59a06a92004-11-23 18:19:14 +0000395}
Paul Jakmafb66b292006-05-28 08:26:15 +0000396#elif defined(HAVE_PRINTSTACK)
397#define DUMP(FD) { \
398 if (program_counter) \
399 write((FD), pclabel, sizeof(pclabel)-1); \
400 write((FD), buf, s-buf); \
401 printstack((FD)); \
402}
403#endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
404
405 s = buf;
406 s = str_append(LOC,"Backtrace for ");
407 s = num_append(LOC,size);
408 s = str_append(LOC," stack frames:\n");
ajs59a06a92004-11-23 18:19:14 +0000409
ajsc4c7d0c2005-02-03 19:22:05 +0000410 if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
411 DUMP(logfile_fd)
ajs59a06a92004-11-23 18:19:14 +0000412 if (!zlog_default)
ajsc4c7d0c2005-02-03 19:22:05 +0000413 DUMP(STDERR_FILENO)
ajs59a06a92004-11-23 18:19:14 +0000414 else
415 {
ajs274a4a42004-12-07 15:39:31 +0000416 if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
ajsc4c7d0c2005-02-03 19:22:05 +0000417 DUMP(STDOUT_FILENO)
ajs274a4a42004-12-07 15:39:31 +0000418 /* Remove trailing '\n' for monitor and syslog */
419 *--s = '\0';
420 if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
421 vty_log_fixed(buf,s-buf);
422 if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
423 syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
424 {
425 int i;
426 /* Just print the function addresses. */
427 for (i = 0; i < size; i++)
428 {
429 s = buf;
430 s = str_append(LOC,"[bt ");
431 s = num_append(LOC,i);
432 s = str_append(LOC,"] 0x");
433 s = hex_append(LOC,(u_long)(array[i]));
434 *s = '\0';
435 if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
436 vty_log_fixed(buf,s-buf);
437 if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
ajs7d149b82004-11-28 23:00:01 +0000438 syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
ajs274a4a42004-12-07 15:39:31 +0000439 }
440 }
ajs59a06a92004-11-23 18:19:14 +0000441 }
442#undef DUMP
ajs59a06a92004-11-23 18:19:14 +0000443#undef LOC
Paul Jakmafb66b292006-05-28 08:26:15 +0000444#endif /* HAVE_STRACK_TRACE */
ajs063ee522004-11-26 18:11:14 +0000445}
446
447void
448zlog_backtrace(int priority)
449{
450#ifndef HAVE_GLIBC_BACKTRACE
451 zlog(NULL, priority, "No backtrace available on this platform.");
452#else
453 void *array[20];
454 int size, i;
455 char **strings;
456
457 if (((size = backtrace(array,sizeof(array)/sizeof(array[0]))) <= 0) ||
458 ((size_t)size > sizeof(array)/sizeof(array[0])))
459 {
460 zlog_err("Cannot get backtrace, returned invalid # of frames %d "
461 "(valid range is between 1 and %u)",
462 size, sizeof(array)/sizeof(array[0]));
463 return;
464 }
465 zlog(NULL, priority, "Backtrace for %d stack frames:", size);
466 if (!(strings = backtrace_symbols(array, size)))
467 {
468 zlog_err("Cannot get backtrace symbols (out of memory?)");
469 for (i = 0; i < size; i++)
470 zlog(NULL, priority, "[bt %d] %p",i,array[i]);
471 }
472 else
473 {
474 for (i = 0; i < size; i++)
475 zlog(NULL, priority, "[bt %d] %s",i,strings[i]);
476 free(strings);
477 }
478#endif /* HAVE_GLIBC_BACKTRACE */
ajs59a06a92004-11-23 18:19:14 +0000479}
480
paul718e3742002-12-13 20:15:29 +0000481void
482zlog (struct zlog *zl, int priority, const char *format, ...)
483{
ajsd246bd92004-11-23 17:35:08 +0000484 va_list args;
paul718e3742002-12-13 20:15:29 +0000485
ajsd246bd92004-11-23 17:35:08 +0000486 va_start(args, format);
paul718e3742002-12-13 20:15:29 +0000487 vzlog (zl, priority, format, args);
ajsd246bd92004-11-23 17:35:08 +0000488 va_end (args);
paul718e3742002-12-13 20:15:29 +0000489}
490
ajsd246bd92004-11-23 17:35:08 +0000491#define ZLOG_FUNC(FUNCNAME,PRIORITY) \
492void \
493FUNCNAME(const char *format, ...) \
494{ \
495 va_list args; \
496 va_start(args, format); \
497 vzlog (NULL, PRIORITY, format, args); \
498 va_end(args); \
paul718e3742002-12-13 20:15:29 +0000499}
500
ajsd246bd92004-11-23 17:35:08 +0000501ZLOG_FUNC(zlog_err, LOG_ERR)
paul718e3742002-12-13 20:15:29 +0000502
ajsd246bd92004-11-23 17:35:08 +0000503ZLOG_FUNC(zlog_warn, LOG_WARNING)
paul718e3742002-12-13 20:15:29 +0000504
ajsd246bd92004-11-23 17:35:08 +0000505ZLOG_FUNC(zlog_info, LOG_INFO)
paul718e3742002-12-13 20:15:29 +0000506
ajsd246bd92004-11-23 17:35:08 +0000507ZLOG_FUNC(zlog_notice, LOG_NOTICE)
508
509ZLOG_FUNC(zlog_debug, LOG_DEBUG)
510
511#undef ZLOG_FUNC
512
513#define PLOG_FUNC(FUNCNAME,PRIORITY) \
514void \
515FUNCNAME(struct zlog *zl, const char *format, ...) \
516{ \
517 va_list args; \
518 va_start(args, format); \
519 vzlog (zl, PRIORITY, format, args); \
520 va_end(args); \
paul718e3742002-12-13 20:15:29 +0000521}
522
ajsd246bd92004-11-23 17:35:08 +0000523PLOG_FUNC(plog_err, LOG_ERR)
paul718e3742002-12-13 20:15:29 +0000524
ajsd246bd92004-11-23 17:35:08 +0000525PLOG_FUNC(plog_warn, LOG_WARNING)
paul718e3742002-12-13 20:15:29 +0000526
ajsd246bd92004-11-23 17:35:08 +0000527PLOG_FUNC(plog_info, LOG_INFO)
paul718e3742002-12-13 20:15:29 +0000528
ajsd246bd92004-11-23 17:35:08 +0000529PLOG_FUNC(plog_notice, LOG_NOTICE)
paul718e3742002-12-13 20:15:29 +0000530
ajsd246bd92004-11-23 17:35:08 +0000531PLOG_FUNC(plog_debug, LOG_DEBUG)
paul718e3742002-12-13 20:15:29 +0000532
ajsd246bd92004-11-23 17:35:08 +0000533#undef PLOG_FUNC
paul718e3742002-12-13 20:15:29 +0000534
ajscee3df12004-11-24 17:14:49 +0000535void
536_zlog_assert_failed (const char *assertion, const char *file,
537 unsigned int line, const char *function)
538{
ajsc4c7d0c2005-02-03 19:22:05 +0000539 /* Force fallback file logging? */
540 if (zlog_default && !zlog_default->fp &&
541 ((logfile_fd = open_crashlog()) >= 0) &&
542 ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL))
543 zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
ajs1e221352005-02-03 16:42:40 +0000544 zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
545 assertion,file,line,(function ? function : "?"));
546 zlog_backtrace(LOG_CRIT);
ajscee3df12004-11-24 17:14:49 +0000547 abort();
548}
549
paul718e3742002-12-13 20:15:29 +0000550
551/* Open log stream */
552struct zlog *
ajs274a4a42004-12-07 15:39:31 +0000553openzlog (const char *progname, zlog_proto_t protocol,
paul718e3742002-12-13 20:15:29 +0000554 int syslog_flags, int syslog_facility)
555{
556 struct zlog *zl;
ajs274a4a42004-12-07 15:39:31 +0000557 u_int i;
paul718e3742002-12-13 20:15:29 +0000558
ajs274a4a42004-12-07 15:39:31 +0000559 zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog));
paul718e3742002-12-13 20:15:29 +0000560
561 zl->ident = progname;
paul718e3742002-12-13 20:15:29 +0000562 zl->protocol = protocol;
563 zl->facility = syslog_facility;
ajs7d149b82004-11-28 23:00:01 +0000564 zl->syslog_options = syslog_flags;
paul718e3742002-12-13 20:15:29 +0000565
ajs274a4a42004-12-07 15:39:31 +0000566 /* Set default logging levels. */
567 for (i = 0; i < sizeof(zl->maxlvl)/sizeof(zl->maxlvl[0]); i++)
568 zl->maxlvl[i] = ZLOG_DISABLED;
569 zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG;
570 zl->default_lvl = LOG_DEBUG;
571
paul718e3742002-12-13 20:15:29 +0000572 openlog (progname, syslog_flags, zl->facility);
573
574 return zl;
575}
576
577void
578closezlog (struct zlog *zl)
579{
580 closelog();
581 fclose (zl->fp);
582
583 XFREE (MTYPE_ZLOG, zl);
584}
585
586/* Called from command.c. */
587void
ajs274a4a42004-12-07 15:39:31 +0000588zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level)
paul718e3742002-12-13 20:15:29 +0000589{
590 if (zl == NULL)
591 zl = zlog_default;
592
ajs274a4a42004-12-07 15:39:31 +0000593 zl->maxlvl[dest] = log_level;
paul718e3742002-12-13 20:15:29 +0000594}
595
596int
ajs274a4a42004-12-07 15:39:31 +0000597zlog_set_file (struct zlog *zl, const char *filename, int log_level)
paul718e3742002-12-13 20:15:29 +0000598{
599 FILE *fp;
gdtaa593d52003-12-22 20:15:53 +0000600 mode_t oldumask;
paul718e3742002-12-13 20:15:29 +0000601
602 /* There is opend file. */
603 zlog_reset_file (zl);
604
605 /* Set default zl. */
606 if (zl == NULL)
607 zl = zlog_default;
608
609 /* Open file. */
gdtaa593d52003-12-22 20:15:53 +0000610 oldumask = umask (0777 & ~LOGFILE_MASK);
paul718e3742002-12-13 20:15:29 +0000611 fp = fopen (filename, "a");
gdtaa593d52003-12-22 20:15:53 +0000612 umask(oldumask);
ajs274a4a42004-12-07 15:39:31 +0000613 if (fp == NULL)
614 return 0;
paul718e3742002-12-13 20:15:29 +0000615
616 /* Set flags. */
617 zl->filename = strdup (filename);
ajs274a4a42004-12-07 15:39:31 +0000618 zl->maxlvl[ZLOG_DEST_FILE] = log_level;
paul718e3742002-12-13 20:15:29 +0000619 zl->fp = fp;
ajsc4c7d0c2005-02-03 19:22:05 +0000620 logfile_fd = fileno(fp);
paul718e3742002-12-13 20:15:29 +0000621
622 return 1;
623}
624
625/* Reset opend file. */
626int
627zlog_reset_file (struct zlog *zl)
628{
629 if (zl == NULL)
630 zl = zlog_default;
631
paul718e3742002-12-13 20:15:29 +0000632 if (zl->fp)
633 fclose (zl->fp);
634 zl->fp = NULL;
ajsc4c7d0c2005-02-03 19:22:05 +0000635 logfile_fd = -1;
ajs274a4a42004-12-07 15:39:31 +0000636 zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
paul718e3742002-12-13 20:15:29 +0000637
638 if (zl->filename)
639 free (zl->filename);
640 zl->filename = NULL;
641
642 return 1;
643}
644
645/* Reopen log file. */
646int
647zlog_rotate (struct zlog *zl)
648{
ajs274a4a42004-12-07 15:39:31 +0000649 int level;
paul718e3742002-12-13 20:15:29 +0000650
651 if (zl == NULL)
652 zl = zlog_default;
653
654 if (zl->fp)
655 fclose (zl->fp);
656 zl->fp = NULL;
ajsc4c7d0c2005-02-03 19:22:05 +0000657 logfile_fd = -1;
ajs274a4a42004-12-07 15:39:31 +0000658 level = zl->maxlvl[ZLOG_DEST_FILE];
659 zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
paul718e3742002-12-13 20:15:29 +0000660
661 if (zl->filename)
662 {
gdtaa593d52003-12-22 20:15:53 +0000663 mode_t oldumask;
ajs274a4a42004-12-07 15:39:31 +0000664 int save_errno;
gdtaa593d52003-12-22 20:15:53 +0000665
666 oldumask = umask (0777 & ~LOGFILE_MASK);
ajs274a4a42004-12-07 15:39:31 +0000667 zl->fp = fopen (zl->filename, "a");
668 save_errno = errno;
669 umask(oldumask);
670 if (zl->fp == NULL)
gdtaa593d52003-12-22 20:15:53 +0000671 {
ajs274a4a42004-12-07 15:39:31 +0000672 zlog_err("Log rotate failed: cannot open file %s for append: %s",
673 zl->filename, safe_strerror(save_errno));
gdtaa593d52003-12-22 20:15:53 +0000674 return -1;
675 }
ajsc4c7d0c2005-02-03 19:22:05 +0000676 logfile_fd = fileno(zl->fp);
ajs274a4a42004-12-07 15:39:31 +0000677 zl->maxlvl[ZLOG_DEST_FILE] = level;
paul718e3742002-12-13 20:15:29 +0000678 }
679
680 return 1;
681}
682
paul718e3742002-12-13 20:15:29 +0000683/* Message lookup function. */
hasso8c328f12004-10-05 21:01:23 +0000684const char *
paul718e3742002-12-13 20:15:29 +0000685lookup (struct message *mes, int key)
686{
687 struct message *pnt;
688
689 for (pnt = mes; pnt->key != 0; pnt++)
690 if (pnt->key == key)
691 return pnt->str;
692
693 return "";
694}
695
Andrew J. Schorrafb88a62007-03-20 20:48:27 +0000696/* Older/faster version of message lookup function, but requires caller to pass
697 in the array size (instead of relying on a 0 key to terminate the search). */
hasso8c328f12004-10-05 21:01:23 +0000698const char *
paul718e3742002-12-13 20:15:29 +0000699mes_lookup (struct message *meslist, int max, int index)
700{
Andrew J. Schorrafb88a62007-03-20 20:48:27 +0000701 /* first check for best case: index is in range and matches the key
702 value in that slot */
703 if ((index >= 0) && (index < max) && (meslist[index].key == index))
704 return meslist[index].str;
705
706 /* fall back to linear search */
707 {
708 int i;
709
710 for (i = 0; i < max; i++, meslist++)
711 {
712 if (meslist->key == index)
713 {
714 zlog_warn("message index %d [%s] found in position %d (max is %d)",
715 index, meslist->str, i, max);
716 return meslist->str;
717 }
718 }
719 }
720 zlog_err("message index %d not found (max is %d)", index, max);
721 return NULL;
paul718e3742002-12-13 20:15:29 +0000722}
ajsca359762004-11-19 23:40:16 +0000723
724/* Wrapper around strerror to handle case where it returns NULL. */
725const char *
726safe_strerror(int errnum)
727{
728 const char *s = strerror(errnum);
729 return (s != NULL) ? s : "Unknown error";
730}
ajsf52d13c2005-10-01 17:38:06 +0000731
Paul Jakmad6d672a2006-05-15 16:56:51 +0000732struct zebra_desc_table
733{
734 unsigned int type;
ajsf52d13c2005-10-01 17:38:06 +0000735 const char *string;
736 char chr;
ajsf52d13c2005-10-01 17:38:06 +0000737};
738
Paul Jakmad6d672a2006-05-15 16:56:51 +0000739#define DESC_ENTRY(T,S,C) [(T)] = { (T), (S), (C) }
740static const struct zebra_desc_table route_types[] = {
741 DESC_ENTRY (ZEBRA_ROUTE_SYSTEM, "system", 'X' ),
742 DESC_ENTRY (ZEBRA_ROUTE_KERNEL, "kernel", 'K' ),
743 DESC_ENTRY (ZEBRA_ROUTE_CONNECT, "connected", 'C' ),
744 DESC_ENTRY (ZEBRA_ROUTE_STATIC, "static", 'S' ),
745 DESC_ENTRY (ZEBRA_ROUTE_RIP, "rip", 'R' ),
746 DESC_ENTRY (ZEBRA_ROUTE_RIPNG, "ripng", 'R' ),
747 DESC_ENTRY (ZEBRA_ROUTE_OSPF, "ospf", 'O' ),
748 DESC_ENTRY (ZEBRA_ROUTE_OSPF6, "ospf6", 'O' ),
749 DESC_ENTRY (ZEBRA_ROUTE_ISIS, "isis", 'I' ),
750 DESC_ENTRY (ZEBRA_ROUTE_BGP, "bgp", 'B' ),
751 DESC_ENTRY (ZEBRA_ROUTE_HSLS, "hsls", 'H' ),
752};
753#undef DESC_ENTRY
754
755#define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
756static const struct zebra_desc_table command_types[] = {
757 DESC_ENTRY (ZEBRA_INTERFACE_ADD),
758 DESC_ENTRY (ZEBRA_INTERFACE_DELETE),
759 DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_ADD),
760 DESC_ENTRY (ZEBRA_INTERFACE_ADDRESS_DELETE),
761 DESC_ENTRY (ZEBRA_INTERFACE_UP),
762 DESC_ENTRY (ZEBRA_INTERFACE_DOWN),
763 DESC_ENTRY (ZEBRA_IPV4_ROUTE_ADD),
764 DESC_ENTRY (ZEBRA_IPV4_ROUTE_DELETE),
765 DESC_ENTRY (ZEBRA_IPV6_ROUTE_ADD),
766 DESC_ENTRY (ZEBRA_IPV6_ROUTE_DELETE),
767 DESC_ENTRY (ZEBRA_REDISTRIBUTE_ADD),
768 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DELETE),
769 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_ADD),
770 DESC_ENTRY (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE),
771 DESC_ENTRY (ZEBRA_IPV4_NEXTHOP_LOOKUP),
772 DESC_ENTRY (ZEBRA_IPV6_NEXTHOP_LOOKUP),
773 DESC_ENTRY (ZEBRA_IPV4_IMPORT_LOOKUP),
774 DESC_ENTRY (ZEBRA_IPV6_IMPORT_LOOKUP),
775 DESC_ENTRY (ZEBRA_INTERFACE_RENAME),
776 DESC_ENTRY (ZEBRA_ROUTER_ID_ADD),
777 DESC_ENTRY (ZEBRA_ROUTER_ID_DELETE),
778 DESC_ENTRY (ZEBRA_ROUTER_ID_UPDATE),
779};
780#undef DESC_ENTRY
781
782static const struct zebra_desc_table unknown = { 0, "unknown", '?' };
783
784static const struct zebra_desc_table *
ajsf52d13c2005-10-01 17:38:06 +0000785zroute_lookup(u_int zroute)
786{
ajsf52d13c2005-10-01 17:38:06 +0000787 u_int i;
788
789 if (zroute >= sizeof(route_types)/sizeof(route_types[0]))
790 {
791 zlog_err("unknown zebra route type: %u", zroute);
792 return &unknown;
793 }
Paul Jakmad6d672a2006-05-15 16:56:51 +0000794 if (zroute == route_types[zroute].type)
ajsf52d13c2005-10-01 17:38:06 +0000795 return &route_types[zroute];
796 for (i = 0; i < sizeof(route_types)/sizeof(route_types[0]); i++)
797 {
Paul Jakmad6d672a2006-05-15 16:56:51 +0000798 if (zroute == route_types[i].type)
ajsf52d13c2005-10-01 17:38:06 +0000799 {
800 zlog_warn("internal error: route type table out of order "
801 "while searching for %u, please notify developers", zroute);
802 return &route_types[i];
803 }
804 }
805 zlog_err("internal error: cannot find route type %u in table!", zroute);
806 return &unknown;
807}
808
809const char *
810zebra_route_string(u_int zroute)
811{
812 return zroute_lookup(zroute)->string;
813}
814
815char
816zebra_route_char(u_int zroute)
817{
818 return zroute_lookup(zroute)->chr;
819}
Paul Jakmad6d672a2006-05-15 16:56:51 +0000820
821const char *
822zserv_command_string (unsigned int command)
823{
824 if (command >= sizeof(command_types)/sizeof(command_types[0]))
825 {
826 zlog_err ("unknown zserv command type: %u", command);
827 return unknown.string;
828 }
829 return command_types[command].string;
830}