/* * logging.c - generic logging for snmp-agent * * Contributed by Ragnar Kjørstad, ucd@ragnark.vestdata.no 1999-06-26 */ #include #include #if HAVE_MALLOC_H #include #endif #if HAVE_STRING_H #include #else #include #endif #if HAVE_STDLIB_H #include #endif #include #include #include #include #if HAVE_SYSLOG_H #include #ifndef LOG_CONS /* Interesting Ultrix feature */ #include #endif #endif #if TIME_WITH_SYS_TIME # ifdef WIN32 # include # else # include # endif # include #else # if HAVE_SYS_TIME_H # include # else # include # endif #endif #if HAVE_NETINET_IN_H #include #endif #if HAVE_STDARG_H #include #else #include #endif #if HAVE_DMALLOC_H #include #endif #if HAVE_WINSOCK_H #include #endif #if HAVE_WINDOWS_H #include #endif #include #include #include /* For this file's "internal" definitions */ #include #include #include #define LOGLENGTH 1024 static int do_syslogging = 0; static int do_filelogging = 0; static int do_stderrlogging = 1; static int do_log_callback = 0; static int newline = 1; static FILE *logfile; #ifdef WIN32 static HANDLE eventlog_h; #endif #ifndef HAVE_VSNPRINTF /* * Need to use the UCD-provided one */ int vsnprintf(char *str, size_t count, const char *fmt, va_list arg); #endif void init_snmp_logging(void) { netsnmp_ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp", NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP); } int snmp_get_do_logging(void) { return (do_syslogging || do_filelogging || do_stderrlogging || do_log_callback); } static char * sprintf_stamp(time_t * now, char *sbuf) { time_t Now; struct tm *tm; if (now == NULL) { now = &Now; time(now); } tm = localtime(now); sprintf(sbuf, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ", tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec); return sbuf; } void snmp_disable_syslog(void) { #if HAVE_SYSLOG_H if (do_syslogging) closelog(); #endif #ifdef WIN32 if (eventlog_h != NULL) { if (!CloseEventLog(eventlog_h)) { fprintf(stderr, "Could not close event log. " "Last error: 0x%x\n", GetLastError()); } else { eventlog_h = NULL; } } #endif /* WIN32 */ do_syslogging = 0; } void snmp_disable_filelog(void) { if (do_filelogging) { fputs("\n", logfile); fclose(logfile); } do_filelogging = 0; } void snmp_disable_stderrlog(void) { do_stderrlogging = 0; } void snmp_disable_log(void) { snmp_disable_syslog(); snmp_disable_filelog(); snmp_disable_stderrlog(); snmp_disable_calllog(); } void snmp_enable_syslog(void) { /* * This default should probably be net-snmp at some point */ snmp_enable_syslog_ident(DEFAULT_LOG_ID, LOG_DAEMON); } void snmp_enable_syslog_ident(const char *ident, const int facility) { snmp_disable_syslog(); if (ident == NULL) /* * This default should probably be net-snmp at some point */ ident = DEFAULT_LOG_ID; #if HAVE_SYSLOG_H openlog(ident, LOG_CONS | LOG_PID, facility); do_syslogging = 1; #endif #ifdef WIN32 eventlog_h = OpenEventLog(NULL, ident); if (eventlog_h == NULL) { fprintf(stderr, "Could not open event log for %s. " "Last error: 0x%x\n", ident, GetLastError()); do_syslogging = 0; } else do_syslogging = 1; #endif /* WIN32 */ } void snmp_enable_filelog(const char *logfilename, int dont_zero_log) { snmp_disable_filelog(); logfile = fopen(logfilename, dont_zero_log ? "a" : "w"); if (logfile) { do_filelogging = 1; #ifdef WIN32 /* * Apparently, "line buffering" under Windows is * actually implemented as "full buffering". * Let's try turning off buffering completely. */ setvbuf(logfile, NULL, _IONBF, BUFSIZ); #else setvbuf(logfile, NULL, _IOLBF, BUFSIZ); #endif } else do_filelogging = 0; } void snmp_enable_stderrlog(void) { do_stderrlogging = 1; } void snmp_enable_calllog(void) { do_log_callback = 1; } void snmp_disable_calllog(void) { do_log_callback = 0; } void snmp_log_string(int priority, const char *string) { char sbuf[40]; struct snmp_log_message slm; #ifdef WIN32 WORD etype; LPCTSTR event_msg[2]; #endif /* WIN32 */ #if HAVE_SYSLOG_H if (do_syslogging) { syslog(priority, "%s", string); } #endif #ifdef WIN32 if (do_syslogging) { /* ** EVENT TYPES: ** ** Information (EVENTLOG_INFORMATION_TYPE) ** Information events indicate infrequent but significant ** successful operations. ** Warning (EVENTLOG_WARNING_TYPE) ** Warning events indicate problems that are not immediately ** significant, but that may indicate conditions that could ** cause future problems. Resource consumption is a good ** candidate for a warning event. ** Error (EVENTLOG_ERROR_TYPE) ** Error events indicate significant problems that the user ** should know about. Error events usually indicate a loss of ** functionality or data. */ switch (priority) { case LOG_EMERG: case LOG_ALERT: case LOG_CRIT: case LOG_ERR: etype = EVENTLOG_ERROR_TYPE; break; case LOG_WARNING: etype = EVENTLOG_WARNING_TYPE; break; case LOG_NOTICE: case LOG_INFO: case LOG_DEBUG: etype = EVENTLOG_INFORMATION_TYPE; break; default: etype = EVENTLOG_INFORMATION_TYPE; break; } event_msg[0] = string; event_msg[1] = NULL; if (!ReportEvent(eventlog_h, etype, 0, 0, NULL, 1, 0, event_msg, NULL)) fprintf(stderr, "Could not report event. Last error: " "0x%x\n", GetLastError()); } #endif /* WIN32 */ if (do_log_callback) { int dodebug = snmp_get_do_debugging(); slm.priority = priority; slm.msg = string; if (dodebug) /* turn off debugging inside the callbacks else will loop */ snmp_set_do_debugging(0); snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm); if (dodebug) snmp_set_do_debugging(dodebug); } if (do_filelogging || do_stderrlogging) { if (netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_LOG_TIMESTAMP) && newline) { sprintf_stamp(NULL, sbuf); } else { strcpy(sbuf, ""); } newline = string[strlen(string) - 1] == '\n'; if (do_filelogging) fprintf(logfile, "%s%s", sbuf, string); if (do_stderrlogging) fprintf(stderr, "%s%s", sbuf, string); } } int snmp_vlog(int priority, const char *format, va_list ap) { char buffer[LOGLENGTH]; int length; char *dynamic; length = vsnprintf(buffer, LOGLENGTH, format, ap); if (length == 0) return (0); /* Empty string */ if (length == -1) { snmp_log_string(LOG_ERR, "Could not format log-string\n"); return (-1); } if (length < LOGLENGTH) { snmp_log_string(priority, buffer); return (0); } dynamic = (char *) malloc(length + 1); if (dynamic == NULL) { snmp_log_string(LOG_ERR, "Could not allocate memory for log-message\n"); snmp_log_string(priority, buffer); return (-2); } vsnprintf(dynamic, length + 1, format, ap); snmp_log_string(priority, dynamic); free(dynamic); return 0; } int #if HAVE_STDARG_H snmp_log(int priority, const char *format, ...) #else snmp_log(va_alist) va_dcl #endif { va_list ap; int ret; #if HAVE_STDARG_H va_start(ap, format); #else int priority; const char *format; va_start(ap); priority = va_arg(ap, int); format = va_arg(ap, const char *); #endif ret = snmp_vlog(priority, format, ap); va_end(ap); return (ret); } /* * log a critical error. */ void snmp_log_perror(const char *s) { char *error = strerror(errno); if (s) { if (error) snmp_log(LOG_ERR, "%s: %s\n", s, error); else snmp_log(LOG_ERR, "%s: Error %d out-of-range\n", s, errno); } else { if (error) snmp_log(LOG_ERR, "%s\n", error); else snmp_log(LOG_ERR, "Error %d out-of-range\n", errno); } }