source: src/router/quagga/lib/log.c @ 18797

Last change on this file since 18797 was 18797, checked in by BrainSlayer, 14 months ago

update quagga

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