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