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