Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

snmp_logging.c

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 

Generated on Fri Dec 30 13:47:49 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


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.