| /* logging.c - generic logging for snmp-agent |
| * Contributed by Ragnar Kjørstad, ucd@ragnark.vestdata.no 1999-06-26 */ |
| |
| #include "config.h" |
| #include <stdio.h> |
| #if HAVE_MALLOC_H |
| #include <malloc.h> |
| #endif |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| #if HAVE_STDLIB_H |
| #include <stdlib.h> |
| #endif |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <errno.h> |
| #if HAVE_SYSLOG_H |
| #include <syslog.h> |
| #ifndef LOG_CONS /* Interesting Ultrix feature */ |
| #include <sys/syslog.h> |
| #endif |
| #endif |
| #if TIME_WITH_SYS_TIME |
| # ifdef WIN32 |
| # include <sys/timeb.h> |
| # else |
| # include <sys/time.h> |
| # endif |
| # include <time.h> |
| #else |
| # if HAVE_SYS_TIME_H |
| # include <sys/time.h> |
| # else |
| # include <time.h> |
| # endif |
| #endif |
| #if HAVE_NETINET_IN_H |
| #include <netinet/in.h> |
| #endif |
| |
| #if HAVE_STDARG_H |
| #include <stdarg.h> |
| #else |
| #include <varargs.h> |
| #endif |
| |
| #if HAVE_DMALLOC_H |
| #include <dmalloc.h> |
| #endif |
| |
| #if HAVE_WINSOCK_H |
| #include <winsock.h> |
| #endif |
| |
| #if HAVE_WINDOWS_H |
| #include <windows.h> |
| #endif |
| |
| #include "asn1.h" |
| #include "default_store.h" |
| #include "snmp_logging.h" |
| #include "callback.h" |
| #include "system.h" |
| #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) { |
| ds_register_premib(ASN_BOOLEAN, "snmp", "logTimestamp", DS_LIBRARY_ID, |
| 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); |
| } |
| |
| void |
| snmp_enable_syslog_ident(const char *ident) |
| { |
| 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, LOG_DAEMON); |
| 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; |
| setvbuf(logfile, NULL, _IOLBF, BUFSIZ); |
| } |
| 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) { |
| slm.priority = priority; |
| slm.msg = string; |
| snmp_call_callbacks(SNMP_CALLBACK_LIBRARY, SNMP_CALLBACK_LOGGING, &slm); |
| } |
| |
| if (do_filelogging || do_stderrlogging) { |
| |
| if (ds_get_boolean(DS_LIBRARY_ID, 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); |
| } |
| } |
| |