Annotation of embedaddon/quagga/lib/log.c, revision 1.1
1.1 ! misho 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:
! 36: static int logfile_fd = -1; /* Used in signal handler. */
! 37:
! 38: struct zlog *zlog_default = NULL;
! 39:
! 40: const 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:
! 55: const 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:
! 72: size_t
! 73: quagga_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. */
! 134: static void
! 135: time_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. */
! 147: static void
! 148: vzlog (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:
! 217: static char *
! 218: str_append(char *dst, int len, const char *src)
! 219: {
! 220: while ((len-- > 0) && *src)
! 221: *dst++ = *src++;
! 222: return dst;
! 223: }
! 224:
! 225: static char *
! 226: num_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)
! 243: static char *
! 244: hex_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. */
! 263: static int
! 264: syslog_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:
! 293: static void
! 294: syslog_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:
! 322: static int
! 323: open_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. */
! 355: void
! 356: zlog_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. */
! 431: void
! 432: zlog_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:
! 516: void
! 517: zlog_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:
! 550: void
! 551: zlog (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) \
! 561: void \
! 562: FUNCNAME(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:
! 570: ZLOG_FUNC(zlog_err, LOG_ERR)
! 571:
! 572: ZLOG_FUNC(zlog_warn, LOG_WARNING)
! 573:
! 574: ZLOG_FUNC(zlog_info, LOG_INFO)
! 575:
! 576: ZLOG_FUNC(zlog_notice, LOG_NOTICE)
! 577:
! 578: ZLOG_FUNC(zlog_debug, LOG_DEBUG)
! 579:
! 580: #undef ZLOG_FUNC
! 581:
! 582: #define PLOG_FUNC(FUNCNAME,PRIORITY) \
! 583: void \
! 584: FUNCNAME(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:
! 592: PLOG_FUNC(plog_err, LOG_ERR)
! 593:
! 594: PLOG_FUNC(plog_warn, LOG_WARNING)
! 595:
! 596: PLOG_FUNC(plog_info, LOG_INFO)
! 597:
! 598: PLOG_FUNC(plog_notice, LOG_NOTICE)
! 599:
! 600: PLOG_FUNC(plog_debug, LOG_DEBUG)
! 601:
! 602: #undef PLOG_FUNC
! 603:
! 604: void
! 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 */
! 621: struct zlog *
! 622: openzlog (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:
! 646: void
! 647: closezlog (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. */
! 661: void
! 662: zlog_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:
! 670: int
! 671: zlog_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. */
! 700: int
! 701: zlog_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. */
! 720: int
! 721: zlog_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. */
! 758: const char *
! 759: lookup (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: */
! 776: const char *
! 777: mes_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. */
! 813: const char *
! 814: safe_strerror(int errnum)
! 815: {
! 816: const char *s = strerror(errnum);
! 817: return (s != NULL) ? s : "Unknown error";
! 818: }
! 819:
! 820: struct 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) }
! 828: static 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' }
! 844: static 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:
! 870: static const struct zebra_desc_table unknown = { 0, "unknown", '?' };
! 871:
! 872: static const struct zebra_desc_table *
! 873: zroute_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:
! 897: const char *
! 898: zebra_route_string(u_int zroute)
! 899: {
! 900: return zroute_lookup(zroute)->string;
! 901: }
! 902:
! 903: char
! 904: zebra_route_char(u_int zroute)
! 905: {
! 906: return zroute_lookup(zroute)->chr;
! 907: }
! 908:
! 909: const char *
! 910: zserv_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:
! 922: int
! 923: proto_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
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>