New upstream release and new maintainer
[quagga-debian.git] / lib / log.c
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   "PIM",
55   "MASC",
56   "NHRP",
57   NULL,
58 };
59
60 const char *zlog_priority[] =
61 {
62   "emergencies",
63   "alerts",
64   "critical",
65   "errors",
66   "warnings",
67   "notifications",
68   "informational",
69   "debugging",
70   NULL,
71 };
72   
73
74
75 /* For time string format. */
76
77 size_t
78 quagga_timestamp(int timestamp_precision, char *buf, size_t buflen)
79 {
80   static struct {
81     time_t last;
82     size_t len;
83     char buf[28];
84   } cache;
85   struct timeval clock;
86
87   /* would it be sufficient to use global 'recent_time' here?  I fear not... */
88   gettimeofday(&clock, NULL);
89
90   /* first, we update the cache if the time has changed */
91   if (cache.last != clock.tv_sec)
92     {
93       struct tm *tm;
94       cache.last = clock.tv_sec;
95       tm = localtime(&cache.last);
96       cache.len = strftime(cache.buf, sizeof(cache.buf),
97                            "%Y/%m/%d %H:%M:%S", tm);
98     }
99   /* note: it's not worth caching the subsecond part, because
100      chances are that back-to-back calls are not sufficiently close together
101      for the clock not to have ticked forward */
102
103   if (buflen > cache.len)
104     {
105       memcpy(buf, cache.buf, cache.len);
106       if ((timestamp_precision > 0) &&
107           (buflen > cache.len+1+timestamp_precision))
108         {
109           /* should we worry about locale issues? */
110           static const int divisor[] = {0, 100000, 10000, 1000, 100, 10, 1};
111           int prec;
112           char *p = buf+cache.len+1+(prec = timestamp_precision);
113           *p-- = '\0';
114           while (prec > 6)
115             /* this is unlikely to happen, but protect anyway */
116             {
117               *p-- = '0';
118               prec--;
119             }
120           clock.tv_usec /= divisor[prec];
121           do
122             {
123               *p-- = '0'+(clock.tv_usec % 10);
124               clock.tv_usec /= 10;
125             }
126           while (--prec > 0);
127           *p = '.';
128           return cache.len+1+timestamp_precision;
129         }
130       buf[cache.len] = '\0';
131       return cache.len;
132     }
133   if (buflen > 0)
134     buf[0] = '\0';
135   return 0;
136 }
137
138 /* Utility routine for current time printing. */
139 static void
140 time_print(FILE *fp, struct timestamp_control *ctl)
141 {
142   if (!ctl->already_rendered)
143     {
144       ctl->len = quagga_timestamp(ctl->precision, ctl->buf, sizeof(ctl->buf));
145       ctl->already_rendered = 1;
146     }
147   fprintf(fp, "%s ", ctl->buf);
148 }
149   
150
151 /* va_list version of zlog. */
152 static void
153 vzlog (struct zlog *zl, int priority, const char *format, va_list args)
154 {
155   int original_errno = errno;
156   struct timestamp_control tsctl;
157   tsctl.already_rendered = 0;
158
159   /* If zlog is not specified, use default one. */
160   if (zl == NULL)
161     zl = zlog_default;
162
163   /* When zlog_default is also NULL, use stderr for logging. */
164   if (zl == NULL)
165     {
166       tsctl.precision = 0;
167       time_print(stderr, &tsctl);
168       fprintf (stderr, "%s: ", "unknown");
169       vfprintf (stderr, format, args);
170       fprintf (stderr, "\n");
171       fflush (stderr);
172
173       /* In this case we return at here. */
174       errno = original_errno;
175       return;
176     }
177   tsctl.precision = zl->timestamp_precision;
178
179   /* Syslog output */
180   if (priority <= zl->maxlvl[ZLOG_DEST_SYSLOG])
181     {
182       va_list ac;
183       va_copy(ac, args);
184       vsyslog (priority|zlog_default->facility, format, ac);
185       va_end(ac);
186     }
187
188   /* File output. */
189   if ((priority <= zl->maxlvl[ZLOG_DEST_FILE]) && zl->fp)
190     {
191       va_list ac;
192       time_print (zl->fp, &tsctl);
193       if (zl->record_priority)
194         fprintf (zl->fp, "%s: ", zlog_priority[priority]);
195       fprintf (zl->fp, "%s: ", zlog_proto_names[zl->protocol]);
196       va_copy(ac, args);
197       vfprintf (zl->fp, format, ac);
198       va_end(ac);
199       fprintf (zl->fp, "\n");
200       fflush (zl->fp);
201     }
202
203   /* stdout output. */
204   if (priority <= zl->maxlvl[ZLOG_DEST_STDOUT])
205     {
206       va_list ac;
207       time_print (stdout, &tsctl);
208       if (zl->record_priority)
209         fprintf (stdout, "%s: ", zlog_priority[priority]);
210       fprintf (stdout, "%s: ", zlog_proto_names[zl->protocol]);
211       va_copy(ac, args);
212       vfprintf (stdout, format, ac);
213       va_end(ac);
214       fprintf (stdout, "\n");
215       fflush (stdout);
216     }
217
218   /* Terminal monitor. */
219   if (priority <= zl->maxlvl[ZLOG_DEST_MONITOR])
220     vty_log ((zl->record_priority ? zlog_priority[priority] : NULL),
221              zlog_proto_names[zl->protocol], format, &tsctl, args);
222
223   errno = original_errno;
224 }
225
226 static char *
227 str_append(char *dst, int len, const char *src)
228 {
229   while ((len-- > 0) && *src)
230     *dst++ = *src++;
231   return dst;
232 }
233
234 static char *
235 num_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       *--t = '0'+(x % 10);
246       x /= 10;
247     }
248   return str_append(s,len,t);
249 }
250
251 #if defined(SA_SIGINFO) || defined(HAVE_STACK_TRACE)
252 static char *
253 hex_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 }
269 #endif
270
271 /* Needs to be enhanced to support Solaris. */
272 static int
273 syslog_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
302 static void
303 syslog_sigsafe(int priority, const char *msg, size_t msglen)
304 {
305   static int syslog_fd = -1;
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
331 static int
332 open_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
363 /* Note: the goal here is to use only async-signal-safe functions. */
364 void
365 zlog_signal(int signo, const char *action
366 #ifdef SA_SIGINFO
367             , siginfo_t *siginfo, void *program_counter
368 #endif
369            )
370 {
371   time_t now;
372   char buf[sizeof("DEFAULT: Received signal S at T (si_addr 0xP, PC 0xP); aborting...")+100];
373   char *s = buf;
374   char *msgstart = buf;
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++ = ' ';
383       msgstart = s;
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);
389 #ifdef SA_SIGINFO
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,"); ");
398 #else /* SA_SIGINFO */
399   s = str_append(LOC,"; ");
400 #endif /* SA_SIGINFO */
401   s = str_append(LOC,action);
402   if (s < buf+sizeof(buf))
403     *s++ = '\n';
404
405   /* N.B. implicit priority is most severe */
406 #define PRI LOG_CRIT
407
408 #define DUMP(FD) write(FD, buf, s-buf);
409   /* If no file logging configured, try to write to fallback log file. */
410   if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
411     DUMP(logfile_fd)
412   if (!zlog_default)
413     DUMP(STDERR_FILENO)
414   else
415     {
416       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
417         DUMP(STDOUT_FILENO)
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);
424     }
425 #undef DUMP
426
427   zlog_backtrace_sigsafe(PRI,
428 #ifdef SA_SIGINFO
429                          program_counter
430 #else
431                          NULL
432 #endif
433                         );
434
435   s = buf;
436   if (!thread_current)
437     s = str_append (LOC, "no thread information available\n");
438   else
439     {
440       s = str_append (LOC, "in thread ");
441       s = str_append (LOC, thread_current->funcname);
442       s = str_append (LOC, " scheduled from ");
443       s = str_append (LOC, thread_current->schedfrom);
444       s = str_append (LOC, ":");
445       s = num_append (LOC, thread_current->schedfrom_line);
446       s = str_append (LOC, "\n");
447     }
448
449 #define DUMP(FD) write(FD, buf, s-buf);
450   /* If no file logging configured, try to write to fallback log file. */
451   if (logfile_fd >= 0)
452     DUMP(logfile_fd)
453   if (!zlog_default)
454     DUMP(STDERR_FILENO)
455   else
456     {
457       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
458         DUMP(STDOUT_FILENO)
459       /* Remove trailing '\n' for monitor and syslog */
460       *--s = '\0';
461       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
462         vty_log_fixed(buf,s-buf);
463       if (PRI <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
464         syslog_sigsafe(PRI|zlog_default->facility,msgstart,s-msgstart);
465     }
466 #undef DUMP
467
468 #undef PRI
469 #undef LOC
470 }
471
472 /* Log a backtrace using only async-signal-safe functions.
473    Needs to be enhanced to support syslog logging. */
474 void
475 zlog_backtrace_sigsafe(int priority, void *program_counter)
476 {
477 #ifdef HAVE_STACK_TRACE
478   static const char pclabel[] = "Program counter: ";
479   void *array[64];
480   int size;
481   char buf[100];
482   char *s, **bt = NULL;
483 #define LOC s,buf+sizeof(buf)-s
484
485 #ifdef HAVE_GLIBC_BACKTRACE
486   size = backtrace(array, array_size(array));
487   if (size <= 0 || (size_t)size > array_size(array))
488     return;
489
490 #define DUMP(FD) { \
491   if (program_counter) \
492     { \
493       write(FD, pclabel, sizeof(pclabel)-1); \
494       backtrace_symbols_fd(&program_counter, 1, FD); \
495     } \
496   write(FD, buf, s-buf);        \
497   backtrace_symbols_fd(array, size, FD); \
498 }
499 #elif defined(HAVE_PRINTSTACK)
500 #define DUMP(FD) { \
501   if (program_counter) \
502     write((FD), pclabel, sizeof(pclabel)-1); \
503   write((FD), buf, s-buf); \
504   printstack((FD)); \
505 }
506 #endif /* HAVE_GLIBC_BACKTRACE, HAVE_PRINTSTACK */
507
508   s = buf;
509   s = str_append(LOC,"Backtrace for ");
510   s = num_append(LOC,size);
511   s = str_append(LOC," stack frames:\n");
512
513   if ((logfile_fd >= 0) || ((logfile_fd = open_crashlog()) >= 0))
514     DUMP(logfile_fd)
515   if (!zlog_default)
516     DUMP(STDERR_FILENO)
517   else
518     {
519       if (priority <= zlog_default->maxlvl[ZLOG_DEST_STDOUT])
520         DUMP(STDOUT_FILENO)
521       /* Remove trailing '\n' for monitor and syslog */
522       *--s = '\0';
523       if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
524         vty_log_fixed(buf,s-buf);
525       if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
526         syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
527       {
528         int i;
529 #ifdef HAVE_GLIBC_BACKTRACE
530         bt = backtrace_symbols(array, size);
531 #endif
532         /* Just print the function addresses. */
533         for (i = 0; i < size; i++)
534           {
535             s = buf;
536             if (bt) 
537               s = str_append(LOC, bt[i]);
538             else {
539               s = str_append(LOC,"[bt ");
540               s = num_append(LOC,i);
541               s = str_append(LOC,"] 0x");
542               s = hex_append(LOC,(u_long)(array[i]));
543             }
544             *s = '\0';
545             if (priority <= zlog_default->maxlvl[ZLOG_DEST_MONITOR])
546               vty_log_fixed(buf,s-buf);
547             if (priority <= zlog_default->maxlvl[ZLOG_DEST_SYSLOG])
548               syslog_sigsafe(priority|zlog_default->facility,buf,s-buf);
549           }
550           if (bt)
551             free(bt);
552       }
553     }
554 #undef DUMP
555 #undef LOC
556 #endif /* HAVE_STRACK_TRACE */
557 }
558
559 void
560 zlog_backtrace(int priority)
561 {
562 #ifndef HAVE_GLIBC_BACKTRACE
563   zlog(NULL, priority, "No backtrace available on this platform.");
564 #else
565   void *array[20];
566   int size, i;
567   char **strings;
568
569   size = backtrace(array, array_size(array));
570   if (size <= 0 || (size_t)size > array_size(array))
571     {
572       zlog_err("Cannot get backtrace, returned invalid # of frames %d "
573                "(valid range is between 1 and %lu)",
574                size, (unsigned long)(array_size(array)));
575       return;
576     }
577   zlog(NULL, priority, "Backtrace for %d stack frames:", size);
578   if (!(strings = backtrace_symbols(array, size)))
579     {
580       zlog_err("Cannot get backtrace symbols (out of memory?)");
581       for (i = 0; i < size; i++)
582         zlog(NULL, priority, "[bt %d] %p",i,array[i]);
583     }
584   else
585     {
586       for (i = 0; i < size; i++)
587         zlog(NULL, priority, "[bt %d] %s",i,strings[i]);
588       free(strings);
589     }
590 #endif /* HAVE_GLIBC_BACKTRACE */
591 }
592
593 void
594 zlog (struct zlog *zl, int priority, const char *format, ...)
595 {
596   va_list args;
597
598   va_start(args, format);
599   vzlog (zl, priority, format, args);
600   va_end (args);
601 }
602
603 #define ZLOG_FUNC(FUNCNAME,PRIORITY) \
604 void \
605 FUNCNAME(const char *format, ...) \
606 { \
607   va_list args; \
608   va_start(args, format); \
609   vzlog (NULL, PRIORITY, format, args); \
610   va_end(args); \
611 }
612
613 ZLOG_FUNC(zlog_err, LOG_ERR)
614
615 ZLOG_FUNC(zlog_warn, LOG_WARNING)
616
617 ZLOG_FUNC(zlog_info, LOG_INFO)
618
619 ZLOG_FUNC(zlog_notice, LOG_NOTICE)
620
621 ZLOG_FUNC(zlog_debug, LOG_DEBUG)
622
623 #undef ZLOG_FUNC
624
625 #define PLOG_FUNC(FUNCNAME,PRIORITY) \
626 void \
627 FUNCNAME(struct zlog *zl, const char *format, ...) \
628 { \
629   va_list args; \
630   va_start(args, format); \
631   vzlog (zl, PRIORITY, format, args); \
632   va_end(args); \
633 }
634
635 PLOG_FUNC(plog_err, LOG_ERR)
636
637 PLOG_FUNC(plog_warn, LOG_WARNING)
638
639 PLOG_FUNC(plog_info, LOG_INFO)
640
641 PLOG_FUNC(plog_notice, LOG_NOTICE)
642
643 PLOG_FUNC(plog_debug, LOG_DEBUG)
644
645 #undef PLOG_FUNC
646
647 void zlog_thread_info (int log_level)
648 {
649   if (thread_current)
650     zlog(NULL, log_level, "Current thread function %s, scheduled from "
651          "file %s, line %u", thread_current->funcname,
652          thread_current->schedfrom, thread_current->schedfrom_line);
653   else
654     zlog(NULL, log_level, "Current thread not known/applicable");
655 }
656
657 void
658 _zlog_assert_failed (const char *assertion, const char *file,
659                      unsigned int line, const char *function)
660 {
661   /* Force fallback file logging? */
662   if (zlog_default && !zlog_default->fp &&
663       ((logfile_fd = open_crashlog()) >= 0) &&
664       ((zlog_default->fp = fdopen(logfile_fd, "w")) != NULL))
665     zlog_default->maxlvl[ZLOG_DEST_FILE] = LOG_ERR;
666   zlog(NULL, LOG_CRIT, "Assertion `%s' failed in file %s, line %u, function %s",
667        assertion,file,line,(function ? function : "?"));
668   zlog_backtrace(LOG_CRIT);
669   zlog_thread_info(LOG_CRIT);
670   abort();
671 }
672
673
674 /* Open log stream */
675 struct zlog *
676 openzlog (const char *progname, zlog_proto_t protocol,
677           int syslog_flags, int syslog_facility)
678 {
679   struct zlog *zl;
680   u_int i;
681
682   zl = XCALLOC(MTYPE_ZLOG, sizeof (struct zlog));
683
684   zl->ident = progname;
685   zl->protocol = protocol;
686   zl->facility = syslog_facility;
687   zl->syslog_options = syslog_flags;
688
689   /* Set default logging levels. */
690   for (i = 0; i < array_size(zl->maxlvl); i++)
691     zl->maxlvl[i] = ZLOG_DISABLED;
692   zl->maxlvl[ZLOG_DEST_MONITOR] = LOG_DEBUG;
693   zl->default_lvl = LOG_DEBUG;
694
695   openlog (progname, syslog_flags, zl->facility);
696   
697   return zl;
698 }
699
700 void
701 closezlog (struct zlog *zl)
702 {
703   closelog();
704
705   if (zl->fp != NULL)
706     fclose (zl->fp);
707
708   if (zl->filename != NULL)
709     free (zl->filename);
710
711   XFREE (MTYPE_ZLOG, zl);
712 }
713
714 /* Called from command.c. */
715 void
716 zlog_set_level (struct zlog *zl, zlog_dest_t dest, int log_level)
717 {
718   if (zl == NULL)
719     zl = zlog_default;
720
721   zl->maxlvl[dest] = log_level;
722 }
723
724 int
725 zlog_set_file (struct zlog *zl, const char *filename, int log_level)
726 {
727   FILE *fp;
728   mode_t oldumask;
729
730   /* There is opend file.  */
731   zlog_reset_file (zl);
732
733   /* Set default zl. */
734   if (zl == NULL)
735     zl = zlog_default;
736
737   /* Open file. */
738   oldumask = umask (0777 & ~LOGFILE_MASK);
739   fp = fopen (filename, "a");
740   umask(oldumask);
741   if (fp == NULL)
742     return 0;
743
744   /* Set flags. */
745   zl->filename = strdup (filename);
746   zl->maxlvl[ZLOG_DEST_FILE] = log_level;
747   zl->fp = fp;
748   logfile_fd = fileno(fp);
749
750   return 1;
751 }
752
753 /* Reset opend file. */
754 int
755 zlog_reset_file (struct zlog *zl)
756 {
757   if (zl == NULL)
758     zl = zlog_default;
759
760   if (zl->fp)
761     fclose (zl->fp);
762   zl->fp = NULL;
763   logfile_fd = -1;
764   zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
765
766   if (zl->filename)
767     free (zl->filename);
768   zl->filename = NULL;
769
770   return 1;
771 }
772
773 /* Reopen log file. */
774 int
775 zlog_rotate (struct zlog *zl)
776 {
777   int level;
778
779   if (zl == NULL)
780     zl = zlog_default;
781
782   if (zl->fp)
783     fclose (zl->fp);
784   zl->fp = NULL;
785   logfile_fd = -1;
786   level = zl->maxlvl[ZLOG_DEST_FILE];
787   zl->maxlvl[ZLOG_DEST_FILE] = ZLOG_DISABLED;
788
789   if (zl->filename)
790     {
791       mode_t oldumask;
792       int save_errno;
793
794       oldumask = umask (0777 & ~LOGFILE_MASK);
795       zl->fp = fopen (zl->filename, "a");
796       save_errno = errno;
797       umask(oldumask);
798       if (zl->fp == NULL)
799         {
800           zlog_err("Log rotate failed: cannot open file %s for append: %s",
801                    zl->filename, safe_strerror(save_errno));
802           return -1;
803         }       
804       logfile_fd = fileno(zl->fp);
805       zl->maxlvl[ZLOG_DEST_FILE] = level;
806     }
807
808   return 1;
809 }
810
811 /* Message lookup function. */
812 const char *
813 lookup (const struct message *mes, int key)
814 {
815   const struct message *pnt;
816
817   for (pnt = mes; pnt->key != 0; pnt++) 
818     if (pnt->key == key) 
819       return pnt->str;
820
821   return "";
822 }
823
824 /* Older/faster version of message lookup function, but requires caller to pass
825  * in the array size (instead of relying on a 0 key to terminate the search). 
826  *
827  * The return value is the message string if found, or the 'none' pointer
828  * provided otherwise.
829  */
830 const char *
831 mes_lookup (const struct message *meslist, int max, int index,
832   const char *none, const char *mesname)
833 {
834   int pos = index - meslist[0].key;
835   
836   /* first check for best case: index is in range and matches the key
837    * value in that slot.
838    * NB: key numbering might be offset from 0. E.g. protocol constants
839    * often start at 1.
840    */
841   if ((pos >= 0) && (pos < max)
842       && (meslist[pos].key == index))
843     return meslist[pos].str;
844
845   /* fall back to linear search */
846   {
847     int i;
848
849     for (i = 0; i < max; i++, meslist++)
850       {
851         if (meslist->key == index)
852           {
853             const char *str = (meslist->str ? meslist->str : none);
854             
855             zlog_debug ("message index %d [%s] found in %s at position %d (max is %d)",
856                       index, str, mesname, i, max);
857             return str;
858           }
859       }
860   }
861   zlog_err("message index %d not found in %s (max is %d)", index, mesname, max);
862   assert (none);
863   return none;
864 }
865
866 /* Wrapper around strerror to handle case where it returns NULL. */
867 const char *
868 safe_strerror(int errnum)
869 {
870   const char *s = strerror(errnum);
871   return (s != NULL) ? s : "Unknown error";
872 }
873
874 #define DESC_ENTRY(T) [(T)] = { (T), (#T), '\0' }
875 static const struct zebra_desc_table command_types[] = {
876   DESC_ENTRY    (ZEBRA_INTERFACE_ADD),
877   DESC_ENTRY    (ZEBRA_INTERFACE_DELETE),
878   DESC_ENTRY    (ZEBRA_INTERFACE_ADDRESS_ADD),
879   DESC_ENTRY    (ZEBRA_INTERFACE_ADDRESS_DELETE),
880   DESC_ENTRY    (ZEBRA_INTERFACE_UP),
881   DESC_ENTRY    (ZEBRA_INTERFACE_DOWN),
882   DESC_ENTRY    (ZEBRA_IPV4_ROUTE_ADD),
883   DESC_ENTRY    (ZEBRA_IPV4_ROUTE_DELETE),
884   DESC_ENTRY    (ZEBRA_IPV6_ROUTE_ADD),
885   DESC_ENTRY    (ZEBRA_IPV6_ROUTE_DELETE),
886   DESC_ENTRY    (ZEBRA_REDISTRIBUTE_ADD),
887   DESC_ENTRY    (ZEBRA_REDISTRIBUTE_DELETE),
888   DESC_ENTRY    (ZEBRA_REDISTRIBUTE_DEFAULT_ADD),
889   DESC_ENTRY    (ZEBRA_REDISTRIBUTE_DEFAULT_DELETE),
890   DESC_ENTRY    (ZEBRA_IPV4_NEXTHOP_LOOKUP),
891   DESC_ENTRY    (ZEBRA_IPV6_NEXTHOP_LOOKUP),
892   DESC_ENTRY    (ZEBRA_IPV4_IMPORT_LOOKUP),
893   DESC_ENTRY    (ZEBRA_IPV6_IMPORT_LOOKUP),
894   DESC_ENTRY    (ZEBRA_INTERFACE_RENAME),
895   DESC_ENTRY    (ZEBRA_ROUTER_ID_ADD),
896   DESC_ENTRY    (ZEBRA_ROUTER_ID_DELETE),
897   DESC_ENTRY    (ZEBRA_ROUTER_ID_UPDATE),
898   DESC_ENTRY    (ZEBRA_HELLO),
899   DESC_ENTRY    (ZEBRA_NEXTHOP_REGISTER),
900   DESC_ENTRY    (ZEBRA_NEXTHOP_UNREGISTER),
901   DESC_ENTRY    (ZEBRA_NEXTHOP_UPDATE),
902 };
903 #undef DESC_ENTRY
904
905 static const struct zebra_desc_table unknown = { 0, "unknown", '?' };
906
907 static const struct zebra_desc_table *
908 zroute_lookup(u_int zroute)
909 {
910   u_int i;
911
912   if (zroute >= array_size(route_types))
913     {
914       zlog_err("unknown zebra route type: %u", zroute);
915       return &unknown;
916     }
917   if (zroute == route_types[zroute].type)
918     return &route_types[zroute];
919   for (i = 0; i < array_size(route_types); i++)
920     {
921       if (zroute == route_types[i].type)
922         {
923           zlog_warn("internal error: route type table out of order "
924                     "while searching for %u, please notify developers", zroute);
925           return &route_types[i];
926         }
927     }
928   zlog_err("internal error: cannot find route type %u in table!", zroute);
929   return &unknown;
930 }
931
932 const char *
933 zebra_route_string(u_int zroute)
934 {
935   return zroute_lookup(zroute)->string;
936 }
937
938 char
939 zebra_route_char(u_int zroute)
940 {
941   return zroute_lookup(zroute)->chr;
942 }
943
944 const char *
945 zserv_command_string (unsigned int command)
946 {
947   if (command >= array_size(command_types))
948     {
949       zlog_err ("unknown zserv command type: %u", command);
950       return unknown.string;
951     }
952   return command_types[command].string;
953 }
954
955 int
956 proto_name2num(const char *s)
957 {
958    unsigned i;
959
960    for (i=0; i<array_size(route_types); ++i)
961      if (strcasecmp(s, route_types[i].string) == 0)
962        return route_types[i].type;
963    return -1;
964 }
965
966 int
967 proto_redistnum(int afi, const char *s)
968 {
969   if (! s)
970     return -1;
971
972   if (afi == AFI_IP)
973     {
974       if (strncmp (s, "k", 1) == 0)
975         return ZEBRA_ROUTE_KERNEL;
976       else if (strncmp (s, "c", 1) == 0)
977         return ZEBRA_ROUTE_CONNECT;
978       else if (strncmp (s, "s", 1) == 0)
979         return ZEBRA_ROUTE_STATIC;
980       else if (strncmp (s, "r", 1) == 0)
981         return ZEBRA_ROUTE_RIP;
982       else if (strncmp (s, "o", 1) == 0)
983         return ZEBRA_ROUTE_OSPF;
984       else if (strncmp (s, "i", 1) == 0)
985         return ZEBRA_ROUTE_ISIS;
986       else if (strncmp (s, "bg", 2) == 0)
987         return ZEBRA_ROUTE_BGP;
988       else if (strncmp (s, "ba", 2) == 0)
989         return ZEBRA_ROUTE_BABEL;
990       else if (strncmp (s, "n", 1) == 0)
991         return ZEBRA_ROUTE_NHRP;
992     }
993   if (afi == AFI_IP6)
994     {
995       if (strncmp (s, "k", 1) == 0)
996         return ZEBRA_ROUTE_KERNEL;
997       else if (strncmp (s, "c", 1) == 0)
998         return ZEBRA_ROUTE_CONNECT;
999       else if (strncmp (s, "s", 1) == 0)
1000         return ZEBRA_ROUTE_STATIC;
1001       else if (strncmp (s, "r", 1) == 0)
1002         return ZEBRA_ROUTE_RIPNG;
1003       else if (strncmp (s, "o", 1) == 0)
1004         return ZEBRA_ROUTE_OSPF6;
1005       else if (strncmp (s, "i", 1) == 0)
1006         return ZEBRA_ROUTE_ISIS;
1007       else if (strncmp (s, "bg", 2) == 0)
1008         return ZEBRA_ROUTE_BGP;
1009       else if (strncmp (s, "ba", 2) == 0)
1010         return ZEBRA_ROUTE_BABEL;
1011       else if (strncmp (s, "n", 1) == 0)
1012         return ZEBRA_ROUTE_NHRP;
1013     }
1014   return -1;
1015 }
1016
1017 void
1018 zlog_hexdump (void *mem, unsigned int len) {
1019   unsigned long i = 0;
1020   unsigned int j = 0;
1021   unsigned int columns = 8;
1022   char buf[(len * 4) + ((len/4) * 20) + 30];
1023   char *s = buf;
1024
1025   for (i = 0; i < len + ((len % columns) ? (columns - len % columns) : 0); i++)
1026     {
1027       /* print offset */
1028       if (i % columns == 0)
1029         s += sprintf(s, "0x%016lx: ", (unsigned long)mem + i);
1030
1031       /* print hex data */
1032       if (i < len)
1033         s += sprintf(s, "%02x ", 0xFF & ((char*)mem)[i]);
1034
1035       /* end of block, just aligning for ASCII dump */
1036       else
1037         s += sprintf(s, "   ");
1038
1039       /* print ASCII dump */
1040       if (i % columns == (columns - 1))
1041         {
1042           for (j = i - (columns - 1); j <= i; j++)
1043             {
1044               if (j >= len) /* end of block, not really printing */
1045                 s += sprintf(s, " ");
1046
1047               else if(isprint((int)((char*)mem)[j])) /* printable char */
1048                 s += sprintf(s, "%c", 0xFF & ((char*)mem)[j]);
1049
1050               else /* other char */
1051                 s += sprintf(s, ".");
1052             }
1053           s += sprintf(s, "\n");
1054         }
1055     }
1056     zlog_debug("\n%s", buf);
1057 }