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