00001 /* 00002 * logging.c - generic logging for snmp-agent 00003 * * Contributed by Ragnar Kjørstad, ucd@ragnark.vestdata.no 1999-06-26 00004 */ 00005 /* Portions of this file are subject to the following copyright(s). See 00006 * the Net-SNMP's COPYING file for more details and other copyrights 00007 * that may apply: 00008 */ 00009 /* 00010 * Portions of this file are copyrighted by: 00011 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00012 * Use is subject to license terms specified in the COPYING file 00013 * distributed with the Net-SNMP package. 00014 */ 00020 #include <net-snmp/net-snmp-config.h> 00021 #include <stdio.h> 00022 #if HAVE_MALLOC_H 00023 #include <malloc.h> 00024 #endif 00025 #if HAVE_STRING_H 00026 #include <string.h> 00027 #else 00028 #include <strings.h> 00029 #endif 00030 #include <ctype.h> 00031 #if HAVE_STDLIB_H 00032 #include <stdlib.h> 00033 #endif 00034 #include <sys/types.h> 00035 #include <sys/stat.h> 00036 #include <fcntl.h> 00037 #include <errno.h> 00038 #if HAVE_SYSLOG_H 00039 #include <syslog.h> 00040 #ifndef LOG_CONS /* Interesting Ultrix feature */ 00041 #include <sys/syslog.h> 00042 #endif 00043 #endif 00044 #if TIME_WITH_SYS_TIME 00045 # ifdef WIN32 00046 # include <sys/timeb.h> 00047 # else 00048 # include <sys/time.h> 00049 # endif 00050 # include <time.h> 00051 #else 00052 # if HAVE_SYS_TIME_H 00053 # include <sys/time.h> 00054 # else 00055 # include <time.h> 00056 # endif 00057 #endif 00058 #if HAVE_NETINET_IN_H 00059 #include <netinet/in.h> 00060 #endif 00061 00062 #if HAVE_STDARG_H 00063 #include <stdarg.h> 00064 #else 00065 #include <varargs.h> 00066 #endif 00067 00068 #if HAVE_DMALLOC_H 00069 #include <dmalloc.h> 00070 #endif 00071 00072 #if HAVE_WINSOCK_H 00073 #include <winsock.h> 00074 #endif 00075 00076 #if HAVE_WINDOWS_H 00077 #include <windows.h> 00078 #endif 00079 00080 #include <net-snmp/types.h> 00081 #include <net-snmp/output_api.h> 00082 #include <net-snmp/library/snmp_logging.h> /* For this file's "internal" definitions */ 00083 #include <net-snmp/config_api.h> 00084 #include <net-snmp/utilities.h> 00085 00086 #include <net-snmp/library/callback.h> 00087 #define LOGLENGTH 1024 00088 00089 /* 00090 * logh_head: A list of all log handlers, in increasing order of priority 00091 * logh_priorities: 'Indexes' into this list, by priority 00092 */ 00093 netsnmp_log_handler *logh_head = NULL; 00094 netsnmp_log_handler *logh_priorities[LOG_DEBUG+1]; 00095 00096 static int newline = 1; /* MTCRITICAL_RESOURCE */ 00097 00098 static char syslogname[64] = DEFAULT_LOG_ID; 00099 00100 void 00101 netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log); 00102 00103 #ifndef HAVE_VSNPRINTF 00104 /* 00105 * Need to use the UCD-provided one 00106 */ 00107 int vsnprintf(char *str, size_t count, const char *fmt, 00108 va_list arg); 00109 #endif 00110 00111 void 00112 init_snmp_logging(void) 00113 { 00114 netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp", 00115 NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP); 00116 } 00117 00118 /* 00119 * These definitions handle 4.2 systems without additional syslog facilities. 00120 */ 00121 #ifndef LOG_CONS 00122 #define LOG_CONS 0 /* Don't bother if not defined... */ 00123 #endif 00124 #ifndef LOG_PID 00125 #define LOG_PID 0 /* Don't bother if not defined... */ 00126 #endif 00127 #ifndef LOG_LOCAL0 00128 #define LOG_LOCAL0 0 00129 #endif 00130 #ifndef LOG_LOCAL1 00131 #define LOG_LOCAL1 0 00132 #endif 00133 #ifndef LOG_LOCAL2 00134 #define LOG_LOCAL2 0 00135 #endif 00136 #ifndef LOG_LOCAL3 00137 #define LOG_LOCAL3 0 00138 #endif 00139 #ifndef LOG_LOCAL4 00140 #define LOG_LOCAL4 0 00141 #endif 00142 #ifndef LOG_LOCAL5 00143 #define LOG_LOCAL5 0 00144 #endif 00145 #ifndef LOG_LOCAL6 00146 #define LOG_LOCAL6 0 00147 #endif 00148 #ifndef LOG_LOCAL7 00149 #define LOG_LOCAL7 0 00150 #endif 00151 #ifndef LOG_DAEMON 00152 #define LOG_DAEMON 0 00153 #endif 00154 #ifndef LOG_USER 00155 #define LOG_USER 0 00156 #endif 00157 00158 int 00159 decode_priority( char *optarg, int *pri_max ) 00160 { 00161 int pri_low = LOG_DEBUG; 00162 00163 switch (*optarg) { 00164 case '0': 00165 case '!': 00166 pri_low = LOG_EMERG; 00167 break; 00168 case '1': 00169 case 'a': 00170 case 'A': 00171 pri_low = LOG_ALERT; 00172 break; 00173 case '2': 00174 case 'c': 00175 case 'C': 00176 pri_low = LOG_CRIT; 00177 break; 00178 case '3': 00179 case 'e': 00180 case 'E': 00181 pri_low = LOG_ERR; 00182 break; 00183 case '4': 00184 case 'w': 00185 case 'W': 00186 pri_low = LOG_WARNING; 00187 break; 00188 case '5': 00189 case 'n': 00190 case 'N': 00191 pri_low = LOG_NOTICE; 00192 break; 00193 case '6': 00194 case 'i': 00195 case 'I': 00196 pri_low = LOG_INFO; 00197 break; 00198 case '7': 00199 case 'd': 00200 case 'D': 00201 pri_low = LOG_DEBUG; 00202 break; 00203 default: 00204 fprintf(stderr, "invalid priority: %c\n",*optarg); 00205 return -1; 00206 } 00207 00208 if (pri_max && *(optarg+1)=='-') { 00209 *pri_max = decode_priority( optarg+2, NULL ); 00210 if (*pri_max == -1) return -1; 00211 } 00212 return pri_low; 00213 } 00214 00215 int 00216 decode_facility( char *optarg ) 00217 { 00218 if (optarg == NULL) 00219 return -1; 00220 00221 switch (*optarg) { 00222 case 'd': 00223 case 'D': 00224 return LOG_DAEMON; 00225 case 'u': 00226 case 'U': 00227 return LOG_USER; 00228 case '0': 00229 return LOG_LOCAL0; 00230 case '1': 00231 return LOG_LOCAL1; 00232 case '2': 00233 return LOG_LOCAL2; 00234 case '3': 00235 return LOG_LOCAL3; 00236 case '4': 00237 return LOG_LOCAL4; 00238 case '5': 00239 return LOG_LOCAL5; 00240 case '6': 00241 return LOG_LOCAL6; 00242 case '7': 00243 return LOG_LOCAL7; 00244 default: 00245 fprintf(stderr, "invalid syslog facility: %c\n",*optarg); 00246 return -1; 00247 } 00248 } 00249 00250 int 00251 snmp_log_options(char *optarg, int argc, char *const *argv) 00252 { 00253 char *cp = optarg; 00254 /* 00255 * Hmmm... this doesn't seem to work. 00256 * The main agent 'getopt' handling assumes 00257 * that the -L option takes an argument, 00258 * and objects if this is missing. 00259 * Trying to differentiate between 00260 * new-style "-Lx", and old-style "-L xx" 00261 * is likely to be a major headache. 00262 */ 00263 char missing_opt = 'e'; /* old -L is new -Le */ 00264 int priority = LOG_DEBUG; 00265 int pri_max = LOG_EMERG; 00266 int inc_optind = 0; 00267 netsnmp_log_handler *logh; 00268 00269 optarg++; 00270 if (!*cp) 00271 cp = &missing_opt; 00272 00273 /* 00274 * Support '... -Lx=value ....' syntax 00275 */ 00276 if (*optarg == '=') { 00277 optarg++; 00278 } 00279 /* 00280 * and '.... "-Lx value" ....' (*with* the quotes) 00281 */ 00282 while (*optarg && isspace(*optarg)) { 00283 optarg++; 00284 } 00285 /* 00286 * Finally, handle ".... -Lx value ...." syntax 00287 * (*without* surrounding quotes) 00288 */ 00289 if ((!*optarg) && (NULL != argv)) { 00290 /* 00291 * We've run off the end of the argument 00292 * so move on to the next. 00293 * But we might not actually need it, so don't 00294 * increment optind just yet! 00295 */ 00296 optarg = argv[optind]; 00297 inc_optind = 1; 00298 } 00299 00300 switch (*cp) { 00301 00302 /* 00303 * Log to Standard Error 00304 */ 00305 case 'E': 00306 priority = decode_priority( optarg, &pri_max ); 00307 if (priority == -1) return -1; 00308 if (inc_optind) 00309 optind++; 00310 /* Fallthrough */ 00311 case 'e': 00312 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority); 00313 if (logh) { 00314 logh->pri_max = pri_max; 00315 logh->token = strdup("stderr"); 00316 } 00317 break; 00318 00319 /* 00320 * Log to Standard Output 00321 */ 00322 case 'O': 00323 priority = decode_priority( optarg, &pri_max ); 00324 if (priority == -1) return -1; 00325 if (inc_optind) 00326 optind++; 00327 /* Fallthrough */ 00328 case 'o': 00329 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, priority); 00330 if (logh) { 00331 logh->pri_max = pri_max; 00332 logh->token = strdup("stdout"); 00333 logh->imagic = 1; /* stdout, not stderr */ 00334 } 00335 break; 00336 00337 /* 00338 * Log to a named file 00339 */ 00340 case 'F': 00341 priority = decode_priority( optarg, &pri_max ); 00342 if (priority == -1) return -1; 00343 optarg = argv[++optind]; 00344 /* Fallthrough */ 00345 case 'f': 00346 if (inc_optind) 00347 optind++; 00348 if (!optarg) { 00349 fprintf(stderr, "Missing log file\n"); 00350 return -1; 00351 } 00352 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE, priority); 00353 if (logh) { 00354 logh->pri_max = pri_max; 00355 logh->token = strdup(optarg); 00356 netsnmp_enable_filelog(logh, 00357 netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00358 NETSNMP_DS_LIB_APPEND_LOGFILES)); 00359 } 00360 break; 00361 00362 /* 00363 * Log to syslog 00364 */ 00365 case 'S': 00366 priority = decode_priority( optarg, &pri_max ); 00367 if (priority == -1) return -1; 00368 optarg = argv[++optind]; 00369 /* Fallthrough */ 00370 case 's': 00371 if (inc_optind) 00372 optind++; 00373 if (!optarg) { 00374 fprintf(stderr, "Missing syslog facility\n"); 00375 return -1; 00376 } 00377 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, priority); 00378 if (logh) { 00379 int facility = decode_facility(optarg); 00380 if (facility == -1) return -1; 00381 logh->pri_max = pri_max; 00382 logh->token = strdup(snmp_log_syslogname(0)); 00383 logh->magic = (void *)facility; 00384 snmp_enable_syslog_ident(snmp_log_syslogname(0), facility); 00385 } 00386 break; 00387 00388 /* 00389 * Don't log 00390 */ 00391 case 'N': 00392 priority = decode_priority( optarg, &pri_max ); 00393 if (priority == -1) return -1; 00394 if (inc_optind) 00395 optind++; 00396 /* Fallthrough */ 00397 case 'n': 00398 /* 00399 * disable all logs to clean them up (close files, etc), 00400 * remove all log handlers, then register a null handler. 00401 */ 00402 snmp_disable_log(); 00403 while(NULL != logh_head) 00404 netsnmp_remove_loghandler( logh_head ); 00405 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_NONE, priority); 00406 if (logh) { 00407 logh->pri_max = pri_max; 00408 } 00409 break; 00410 00411 default: 00412 fprintf(stderr, "Unknown logging option passed to -L: %c.\n", *cp); 00413 return -1; 00414 } 00415 return 0; 00416 } 00417 00418 char * 00419 snmp_log_syslogname(const char *pstr) 00420 { 00421 if (pstr) 00422 strncpy (syslogname, pstr, sizeof(syslogname)); 00423 00424 return syslogname; 00425 } 00426 00427 void 00428 snmp_log_options_usage(const char *lead, FILE * outf) 00429 { 00430 const char *pri1_msg = " for level 'pri' and above"; 00431 const char *pri2_msg = " for levels 'p1' to 'p2'"; 00432 fprintf(outf, "%se: log to standard error\n", lead); 00433 fprintf(outf, "%so: log to standard output\n", lead); 00434 fprintf(outf, "%sn: don't log at all\n", lead); 00435 fprintf(outf, "%sf file: log to the specified file\n", lead); 00436 fprintf(outf, "%ss facility: log to syslog (via the specified facility)\n", lead); 00437 fprintf(outf, "\n%s(variants)\n", lead); 00438 fprintf(outf, "%s[EON] pri: log to standard error, output or /dev/null%s\n", lead, pri1_msg); 00439 fprintf(outf, "%s[EON] p1-p2: log to standard error, output or /dev/null%s\n", lead, pri2_msg); 00440 fprintf(outf, "%s[FS] pri token: log to file/syslog%s\n", lead, pri1_msg); 00441 fprintf(outf, "%s[FS] p1-p2 token: log to file/syslog%s\n", lead, pri2_msg); 00442 } 00443 00475 int 00476 snmp_get_do_logging(void) 00477 { 00478 netsnmp_log_handler *logh; 00479 for (logh = logh_head; logh; logh = logh->next) 00480 if (logh->enabled) 00481 return 1; 00482 return 0; 00483 } 00484 00485 00486 static char * 00487 sprintf_stamp(time_t * now, char *sbuf) 00488 { 00489 time_t Now; 00490 struct tm *tm; 00491 00492 if (now == NULL) { 00493 now = &Now; 00494 time(now); 00495 } 00496 tm = localtime(now); 00497 sprintf(sbuf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ", 00498 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, 00499 tm->tm_hour, tm->tm_min, tm->tm_sec); 00500 return sbuf; 00501 } 00502 00503 void 00504 snmp_disable_syslog_entry(netsnmp_log_handler *logh) 00505 { 00506 if (!logh || !logh->enabled || logh->type != NETSNMP_LOGHANDLER_SYSLOG) 00507 return; 00508 00509 #ifdef WIN32 00510 if (logh->magic) { 00511 HANDLE eventlog_h = (HANDLE)logh->magic; 00512 CloseEventLog(eventlog_h); 00513 logh->magic = NULL; 00514 } 00515 #else 00516 closelog(); 00517 logh->imagic = 0; 00518 #endif 00519 00520 logh->enabled = 0; 00521 } 00522 00523 void 00524 snmp_disable_syslog(void) 00525 { 00526 netsnmp_log_handler *logh; 00527 00528 for (logh = logh_head; logh; logh = logh->next) 00529 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_SYSLOG) 00530 snmp_disable_syslog_entry(logh); 00531 } 00532 00533 void 00534 snmp_disable_filelog_entry(netsnmp_log_handler *logh) 00535 { 00536 if (!logh /* || !logh->enabled */ || logh->type != NETSNMP_LOGHANDLER_FILE) 00537 return; 00538 00539 if (logh->magic) { 00540 fputs("\n", (FILE*)logh->magic); /* XXX - why? */ 00541 fclose((FILE*)logh->magic); 00542 logh->magic = NULL; 00543 } 00544 logh->enabled = 0; 00545 } 00546 00547 void 00548 snmp_disable_filelog(void) 00549 { 00550 netsnmp_log_handler *logh; 00551 00552 for (logh = logh_head; logh; logh = logh->next) 00553 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_FILE) 00554 snmp_disable_filelog_entry(logh); 00555 } 00556 00557 /* 00558 * returns that status of stderr logging 00559 * 00560 * @retval 0 : stderr logging disabled 00561 * @retval 1 : stderr logging enabled 00562 */ 00563 int 00564 snmp_stderrlog_status(void) 00565 { 00566 netsnmp_log_handler *logh; 00567 00568 for (logh = logh_head; logh; logh = logh->next) 00569 if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT || 00570 logh->type == NETSNMP_LOGHANDLER_STDERR)) { 00571 return 1; 00572 } 00573 00574 return 0; 00575 } 00576 00577 void 00578 snmp_disable_stderrlog(void) 00579 { 00580 netsnmp_log_handler *logh; 00581 00582 for (logh = logh_head; logh; logh = logh->next) 00583 if (logh->enabled && (logh->type == NETSNMP_LOGHANDLER_STDOUT || 00584 logh->type == NETSNMP_LOGHANDLER_STDERR)) { 00585 logh->enabled = 0; 00586 } 00587 } 00588 00589 void 00590 snmp_disable_calllog(void) 00591 { 00592 netsnmp_log_handler *logh; 00593 00594 for (logh = logh_head; logh; logh = logh->next) 00595 if (logh->enabled && logh->type == NETSNMP_LOGHANDLER_CALLBACK) { 00596 logh->enabled = 0; 00597 } 00598 } 00599 00600 void 00601 snmp_disable_log(void) 00602 { 00603 netsnmp_log_handler *logh; 00604 00605 for (logh = logh_head; logh; logh = logh->next) { 00606 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) 00607 snmp_disable_syslog_entry(logh); 00608 if (logh->type == NETSNMP_LOGHANDLER_FILE) 00609 snmp_disable_filelog_entry(logh); 00610 logh->enabled = 0; 00611 } 00612 } 00613 00614 /* 00615 * close and reopen all file based logs, to allow logfile 00616 * rotation. 00617 */ 00618 void 00619 netsnmp_logging_restart(void) 00620 { 00621 netsnmp_log_handler *logh; 00622 00623 for (logh = logh_head; logh; logh = logh->next) { 00624 if (0 == logh->enabled) 00625 continue; 00626 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) { 00627 snmp_disable_syslog_entry(logh); 00628 snmp_enable_syslog_ident(logh->token,(int)logh->magic); 00629 } 00630 else if (logh->type == NETSNMP_LOGHANDLER_FILE) { 00631 snmp_disable_filelog_entry(logh); 00636 netsnmp_enable_filelog(logh, 1); 00637 } 00638 } 00639 } 00640 00641 /* ================================================== */ 00642 00643 void 00644 snmp_enable_syslog(void) 00645 { 00646 snmp_enable_syslog_ident(snmp_log_syslogname(0), LOG_DAEMON); 00647 } 00648 00649 void 00650 snmp_enable_syslog_ident(const char *ident, const int facility) 00651 { 00652 netsnmp_log_handler *logh; 00653 int found = 0; 00654 int enable = 1; 00655 #ifdef WIN32 00656 HANDLE eventlog_h; 00657 #else 00658 void *eventlog_h = NULL; 00659 #endif 00660 00661 snmp_disable_syslog(); /* ??? */ 00662 #ifdef WIN32 00663 eventlog_h = OpenEventLog(NULL, ident); 00664 if (eventlog_h == NULL) { 00665 /* 00666 * Hmmm..... 00667 * Maybe disable this handler, and log the error ? 00668 */ 00669 fprintf(stderr, "Could not open event log for %s. " 00670 "Last error: 0x%x\n", ident, GetLastError()); 00671 enable = 0; 00672 } 00673 #else 00674 openlog(snmp_log_syslogname(ident), LOG_CONS | LOG_PID, facility); 00675 #endif 00676 00677 for (logh = logh_head; logh; logh = logh->next) 00678 if (logh->type == NETSNMP_LOGHANDLER_SYSLOG) { 00679 logh->magic = (void*)eventlog_h; 00680 logh->imagic = enable; /* syslog open */ 00681 logh->enabled = enable; 00682 found = 1; 00683 } 00684 00685 if (!found) { 00686 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_SYSLOG, 00687 LOG_DEBUG ); 00688 if (logh) { 00689 logh->magic = (void*)eventlog_h; 00690 logh->token = strdup(ident); 00691 logh->imagic = enable; /* syslog open */ 00692 logh->enabled = enable; 00693 } 00694 } 00695 } 00696 00697 void 00698 netsnmp_enable_filelog(netsnmp_log_handler *logh, int dont_zero_log) 00699 { 00700 FILE *logfile; 00701 00702 if (!logh) 00703 return; 00704 00705 if (!logh->magic) { 00706 logfile = fopen(logh->token, dont_zero_log ? "a" : "w"); 00707 if (!logfile) 00708 return; 00709 logh->magic = (void*)logfile; 00710 #ifdef WIN32 00711 /* 00712 * Apparently, "line buffering" under Windows is 00713 * actually implemented as "full buffering". 00714 * Let's try turning off buffering completely. 00715 */ 00716 setvbuf(logfile, NULL, _IONBF, BUFSIZ); 00717 #else 00718 setvbuf(logfile, NULL, _IOLBF, BUFSIZ); 00719 #endif 00720 } 00721 logh->enabled = 1; 00722 } 00723 00724 void 00725 snmp_enable_filelog(const char *logfilename, int dont_zero_log) 00726 { 00727 netsnmp_log_handler *logh; 00728 00729 /* 00730 * don't disable ALL filelogs whenever a new one is enabled. 00731 * this prevents '-Lf file' from working in snmpd, as the 00732 * call to set up /var/log/snmpd.log will disable the previous 00733 * log setup. 00734 * snmp_disable_filelog(); 00735 */ 00736 00737 if (logfilename) { 00738 logh = netsnmp_find_loghandler( logfilename ); 00739 if (!logh) { 00740 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_FILE, 00741 LOG_DEBUG ); 00742 if (logh) 00743 logh->token = strdup(logfilename); 00744 } 00745 if (logh) 00746 netsnmp_enable_filelog(logh, dont_zero_log); 00747 } else { 00748 for (logh = logh_head; logh; logh = logh->next) 00749 if (logh->type == NETSNMP_LOGHANDLER_FILE) 00750 netsnmp_enable_filelog(logh, dont_zero_log); 00751 } 00752 } 00753 00754 00755 void 00756 snmp_enable_stderrlog(void) 00757 { 00758 netsnmp_log_handler *logh; 00759 int found = 0; 00760 00761 for (logh = logh_head; logh; logh = logh->next) 00762 if (logh->type == NETSNMP_LOGHANDLER_STDOUT || 00763 logh->type == NETSNMP_LOGHANDLER_STDERR) { 00764 logh->enabled = 1; 00765 found = 1; 00766 } 00767 00768 if (!found) { 00769 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_STDERR, 00770 LOG_DEBUG ); 00771 if (logh) 00772 logh->token = strdup("stderr"); 00773 } 00774 } 00775 00776 00777 void 00778 snmp_enable_calllog(void) /* XXX - or take a callback routine ??? */ 00779 { 00780 netsnmp_log_handler *logh; 00781 int found = 0; 00782 00783 for (logh = logh_head; logh; logh = logh->next) { 00784 if (logh->type == NETSNMP_LOGHANDLER_CALLBACK) 00785 logh->enabled = 1; 00786 found = 1; 00787 } 00788 00789 if (!found) { 00790 logh = netsnmp_register_loghandler(NETSNMP_LOGHANDLER_CALLBACK, 00791 LOG_DEBUG ); 00792 if (logh) 00793 logh->token = strdup("callback"); 00794 } 00795 } 00796 00797 00798 00799 /* ==================================================== */ 00800 00801 00802 netsnmp_log_handler * 00803 netsnmp_find_loghandler( const char *token ) 00804 { 00805 netsnmp_log_handler *logh; 00806 if (!token) 00807 return NULL; 00808 00809 for (logh = logh_head; logh; logh = logh->next) 00810 if (logh->token && !strcmp( token, logh->token )) 00811 break; 00812 00813 return logh; 00814 } 00815 00816 int 00817 netsnmp_add_loghandler( netsnmp_log_handler *logh ) 00818 { 00819 int i; 00820 netsnmp_log_handler *logh2; 00821 00822 if (!logh) 00823 return 0; 00824 00825 /* 00826 * Find the appropriate point for the new entry... 00827 * (logh2 will point to the entry immediately following) 00828 */ 00829 for (logh2 = logh_head; logh2; logh2 = logh2->next) 00830 if ( logh2->priority >= logh->priority ) 00831 break; 00832 00833 /* 00834 * ... and link it into the main list. 00835 */ 00836 if (logh2) { 00837 if (logh2->prev) 00838 logh2->prev->next = logh; 00839 else 00840 logh_head = logh; 00841 logh->next = logh2; 00842 logh2->prev = logh; 00843 } else if (logh_head ) { 00844 /* 00845 * If logh2 is NULL, we're tagging on to the end 00846 */ 00847 for (logh2 = logh_head; logh2->next; logh2 = logh2->next) 00848 ; 00849 logh2->next = logh; 00850 } else { 00851 logh_head = logh; 00852 } 00853 00854 /* 00855 * Also tweak the relevant priority-'index' array. 00856 */ 00857 for (i=LOG_EMERG; i<=logh->priority; i++) 00858 if (!logh_priorities[i] || 00859 logh_priorities[i]->priority >= logh->priority) 00860 logh_priorities[i] = logh; 00861 00862 return 1; 00863 } 00864 00865 netsnmp_log_handler * 00866 netsnmp_register_loghandler( int type, int priority ) 00867 { 00868 netsnmp_log_handler *logh; 00869 00870 logh = SNMP_MALLOC_TYPEDEF(netsnmp_log_handler); 00871 if (!logh) 00872 return NULL; 00873 00874 logh->type = type; 00875 switch ( type ) { 00876 case NETSNMP_LOGHANDLER_STDOUT: 00877 logh->imagic = 1; 00878 /* fallthrough */ 00879 case NETSNMP_LOGHANDLER_STDERR: 00880 logh->handler = log_handler_stdouterr; 00881 break; 00882 00883 case NETSNMP_LOGHANDLER_FILE: 00884 logh->handler = log_handler_file; 00885 logh->imagic = 1; 00886 break; 00887 case NETSNMP_LOGHANDLER_SYSLOG: 00888 logh->handler = log_handler_syslog; 00889 break; 00890 case NETSNMP_LOGHANDLER_CALLBACK: 00891 logh->handler = log_handler_callback; 00892 break; 00893 case NETSNMP_LOGHANDLER_NONE: 00894 logh->handler = log_handler_null; 00895 break; 00896 default: 00897 free(logh); 00898 return NULL; 00899 } 00900 logh->priority = priority; 00901 logh->enabled = 1; 00902 netsnmp_add_loghandler( logh ); 00903 return logh; 00904 } 00905 00906 00907 int 00908 netsnmp_enable_loghandler( const char *token ) 00909 { 00910 netsnmp_log_handler *logh; 00911 00912 logh = netsnmp_find_loghandler( token ); 00913 if (!logh) 00914 return 0; 00915 logh->enabled = 1; 00916 return 1; 00917 } 00918 00919 00920 int 00921 netsnmp_disable_loghandler( const char *token ) 00922 { 00923 netsnmp_log_handler *logh; 00924 00925 logh = netsnmp_find_loghandler( token ); 00926 if (!logh) 00927 return 0; 00928 logh->enabled = 0; 00929 return 1; 00930 } 00931 00932 int 00933 netsnmp_remove_loghandler( netsnmp_log_handler *logh ) 00934 { 00935 if (!logh) 00936 return 0; 00937 00938 if (logh->prev) 00939 logh->prev->next = logh->next; 00940 else 00941 logh_head = logh->next; 00942 00943 if (logh->next) 00944 logh->next->prev = logh->prev; 00945 return 1; 00946 } 00947 00948 /* ==================================================== */ 00949 00950 int 00951 log_handler_stdouterr( netsnmp_log_handler* logh, int pri, const char *str) 00952 { 00953 char sbuf[40]; 00954 00955 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00956 NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) { 00957 sprintf_stamp(NULL, sbuf); 00958 } else { 00959 strcpy(sbuf, ""); 00960 } 00961 newline = str[strlen(str) - 1] == '\n'; /* XXX - Eh ? */ 00962 00963 if (logh->imagic) 00964 printf( "%s%s", sbuf, str); 00965 else 00966 fprintf(stderr, "%s%s", sbuf, str); 00967 00968 return 1; 00969 } 00970 00971 00972 #ifdef WIN32 00973 int 00974 log_handler_syslog( netsnmp_log_handler* logh, int pri, const char *str) 00975 { 00976 WORD etype; 00977 LPCTSTR event_msg[2]; 00978 HANDLE eventlog_h = logh->magic; 00979 00980 /* 00981 ** EVENT TYPES: 00982 ** 00983 ** Information (EVENTLOG_INFORMATION_TYPE) 00984 ** Information events indicate infrequent but significant 00985 ** successful operations. 00986 ** Warning (EVENTLOG_WARNING_TYPE) 00987 ** Warning events indicate problems that are not immediately 00988 ** significant, but that may indicate conditions that could 00989 ** cause future problems. Resource consumption is a good 00990 ** candidate for a warning event. 00991 ** Error (EVENTLOG_ERROR_TYPE) 00992 ** Error events indicate significant problems that the user 00993 ** should know about. Error events usually indicate a loss of 00994 ** functionality or data. 00995 */ 00996 switch (pri) { 00997 case LOG_EMERG: 00998 case LOG_ALERT: 00999 case LOG_CRIT: 01000 case LOG_ERR: 01001 etype = EVENTLOG_ERROR_TYPE; 01002 break; 01003 case LOG_WARNING: 01004 etype = EVENTLOG_WARNING_TYPE; 01005 break; 01006 case LOG_NOTICE: 01007 case LOG_INFO: 01008 case LOG_DEBUG: 01009 etype = EVENTLOG_INFORMATION_TYPE; 01010 break; 01011 default: 01012 etype = EVENTLOG_INFORMATION_TYPE; 01013 break; 01014 } 01015 event_msg[0] = str; 01016 event_msg[1] = NULL; 01017 /* NOTE: 4th parameter must match winservice.mc:MessageId value */ 01018 if (!ReportEvent(eventlog_h, etype, 0, 100, NULL, 1, 0, event_msg, NULL)) { 01019 /* 01020 * Hmmm..... 01021 * Maybe disable this handler, and log the error ? 01022 */ 01023 fprintf(stderr, "Could not report event. Last error: 0x%x\n", 01024 GetLastError()); 01025 return 0; 01026 } 01027 return 1; 01028 } 01029 #else 01030 int 01031 log_handler_syslog( netsnmp_log_handler* logh, int pri, const char *str) 01032 { 01033 /* 01034 * XXX 01035 * We've got three items of information to work with: 01036 * Is the syslog currently open? 01037 * What ident string to use? 01038 * What facility to log to? 01039 * 01040 * We've got two "magic" locations (imagic & magic) plus the token 01041 */ 01042 if (!(logh->imagic)) { 01043 const char *ident = logh->token; 01044 int facility = (int)logh->magic; 01045 if (!ident) 01046 ident = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 01047 NETSNMP_DS_LIB_APPTYPE); 01048 openlog(ident, LOG_CONS | LOG_PID, facility); 01049 logh->imagic = 1; 01050 } 01051 syslog( pri, "%s", str ); 01052 return 1; 01053 } 01054 #endif /* !WIN32 */ 01055 01056 01057 int 01058 log_handler_file( netsnmp_log_handler* logh, int pri, const char *str) 01059 { 01060 FILE *fhandle; 01061 char sbuf[40]; 01062 01063 /* 01064 * We use imagic to save information about whether the next output 01065 * will start a new line, and thus might need a timestamp 01066 */ 01067 if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 01068 NETSNMP_DS_LIB_LOG_TIMESTAMP) && logh->imagic) { 01069 sprintf_stamp(NULL, sbuf); 01070 } else { 01071 strcpy(sbuf, ""); 01072 } 01073 01074 /* 01075 * If we haven't already opened the file, then do so. 01076 * Save the filehandle pointer for next time. 01077 * 01078 * Note that this should still work, even if the file 01079 * is closed in the meantime (e.g. a regular "cleanup" sweep) 01080 */ 01081 fhandle = (FILE*)logh->magic; 01082 if (!logh->magic) { 01083 fhandle = fopen(logh->token, "a+"); 01084 if (!fhandle) 01085 return 0; 01086 logh->magic = (void*)fhandle; 01087 } 01088 fprintf(fhandle, "%s%s", sbuf, str); 01089 fflush(fhandle); 01090 logh->imagic = str[strlen(str) - 1] == '\n'; 01091 return 1; 01092 } 01093 01094 int 01095 log_handler_callback(netsnmp_log_handler* logh, int pri, const char *str) 01096 { 01097 /* 01098 * XXX - perhaps replace 'snmp_call_callbacks' processing 01099 * with individual callback log_handlers ?? 01100 */ 01101 struct snmp_log_message slm; 01102 int dodebug = snmp_get_do_debugging(); 01103 01104 slm.priority = pri; 01105 slm.msg = str; 01106 if (dodebug) /* turn off debugging inside the callbacks else will loop */ 01107 snmp_set_do_debugging(0); 01108 snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm); 01109 if (dodebug) 01110 snmp_set_do_debugging(dodebug); 01111 return 1; 01112 } 01113 01114 int 01115 log_handler_null( netsnmp_log_handler* logh, int pri, const char *str) 01116 { 01117 /* 01118 * Dummy log handler - just throw away the error completely 01119 * You probably don't really want to do this! 01120 */ 01121 return 1; 01122 } 01123 01124 void 01125 snmp_log_string(int priority, const char *str) 01126 { 01127 netsnmp_log_handler *logh; 01128 01129 /* 01130 * We've got to be able to log messages *somewhere*! 01131 * If you don't want stderr logging, then enable something else. 01132 */ 01133 if (!logh_head) { 01134 snmp_enable_stderrlog(); 01135 snmp_log_string(LOG_WARNING, 01136 "No log handling enabled - turning on stderr logging\n"); 01137 } 01138 01139 /* 01140 * Start at the given priority, and work "upwards".... 01141 */ 01142 logh = logh_priorities[priority]; 01143 for ( ; logh; logh = logh->next ) { 01144 /* 01145 * ... but skipping any handlers with a "maximum priority" 01146 * that we have already exceeded. And don't forget to 01147 * ensure this logging is turned on (see snmp_disable_stderrlog 01148 * and its cohorts). 01149 */ 01150 if (logh->enabled && (priority >= logh->pri_max)) 01151 logh->handler( logh, priority, str ); 01152 } 01153 } 01154 01155 /* ==================================================== */ 01156 01157 01158 int 01159 snmp_vlog(int priority, const char *format, va_list ap) 01160 { 01161 char buffer[LOGLENGTH]; 01162 int length; 01163 char *dynamic; 01164 01165 length = vsnprintf(buffer, LOGLENGTH, format, ap); 01166 01167 if (length == 0) 01168 return (0); /* Empty string */ 01169 01170 if (length == -1) { 01171 snmp_log_string(LOG_ERR, "Could not format log-string\n"); 01172 return (-1); 01173 } 01174 01175 if (length < LOGLENGTH) { 01176 snmp_log_string(priority, buffer); 01177 return (0); 01178 } 01179 01180 dynamic = (char *) malloc(length + 1); 01181 if (dynamic == NULL) { 01182 snmp_log_string(LOG_ERR, 01183 "Could not allocate memory for log-message\n"); 01184 snmp_log_string(priority, buffer); 01185 return (-2); 01186 } 01187 01188 vsnprintf(dynamic, length + 1, format, ap); 01189 snmp_log_string(priority, dynamic); 01190 free(dynamic); 01191 return 0; 01192 } 01193 01201 int 01202 #if HAVE_STDARG_H 01203 snmp_log(int priority, const char *format, ...) 01204 #else 01205 snmp_log(va_alist) 01206 va_dcl 01207 #endif 01208 { 01209 va_list ap; 01210 int ret; 01211 #if HAVE_STDARG_H 01212 va_start(ap, format); 01213 #else 01214 int priority; 01215 const char *format; 01216 va_start(ap); 01217 01218 priority = va_arg(ap, int); 01219 format = va_arg(ap, const char *); 01220 #endif 01221 ret = snmp_vlog(priority, format, ap); 01222 va_end(ap); 01223 return (ret); 01224 } 01225 01226 /* 01227 * log a critical error. 01228 */ 01229 void 01230 snmp_log_perror(const char *s) 01231 { 01232 char *error = strerror(errno); 01233 if (s) { 01234 if (error) 01235 snmp_log(LOG_ERR, "%s: %s\n", s, error); 01236 else 01237 snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno); 01238 } else { 01239 if (error) 01240 snmp_log(LOG_ERR, "%s\n", error); 01241 else 01242 snmp_log(LOG_ERR, "Error %d out-of-range\n", errno); 01243 } 01244 } 01245 01246 /* external access to logh_head variable */ 01247 netsnmp_log_handler * 01248 get_logh_head(void) 01249 { 01250 return logh_head; 01251 } 01252
1.3.9.1
Last modified: Thursday, 01-Mar-2007 16:20:02 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.