From 7c1d830045ea25ad3537e68b72900600d02fd135 Mon Sep 17 00:00:00 2001 From: Andreas Baumann Date: Tue, 17 Mar 2009 16:02:48 +0100 Subject: moved the logger (log and messages) into it's own subdirectory (is a subsystem of wolf in the end) --- src/log/log.c | 656 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 656 insertions(+) create mode 100644 src/log/log.c (limited to 'src/log') diff --git a/src/log/log.c b/src/log/log.c new file mode 100644 index 0000000..0412e75 --- /dev/null +++ b/src/log/log.c @@ -0,0 +1,656 @@ +/* + Copyright (C) 2008 Andreas Baumann + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "log/log.h" + +#include "log/messages.h" /* for i18n */ + +#include "port/stdio.h" /* for vsnprintf, snprintf */ +#include "port/string.h" /* for strcmp, strerror_r, strlen */ +#include "port/time.h" /* for localtime_r, strftime, time + * time_t, struct tm */ +#include "port/unused.h" /* for WOLF_UNUSED */ + +#include /* for variable arguments */ +#include /* for errno */ +#include /* for assertions */ +#include /* for abort */ + +#if defined HAVE_SYSLOG_H +#include /* for syslog, closelog and levels */ +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG +#define WIND32_LEAN_AND_MEAN +#include +#endif /* defined HAVE_EVENTLOG */ + +#if defined HAVE_SYSLOG_H +const char *wolf_log_syslog_facility_to_str( wolf_log_syslog_facility_t facility ) { + switch( facility ) { + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_KERN: return "KERN"; + case WOLF_LOG_USER: return "USER"; + case WOLF_LOG_MAIL: return "MAIL"; + case WOLF_LOG_DAEMON: return "DAEMON"; + case WOLF_LOG_AUTH: return "AUTH"; + case WOLF_LOG_SYSLOG: return "SYSLOG"; + case WOLF_LOG_LPR: return "LPR"; + case WOLF_LOG_NEWS: return "NEWS"; + case WOLF_LOG_UUCP: return "UUCP"; + case WOLF_LOG_CRON: return "CRON"; +#if defined LOG_AUTHPRIV + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_AUTHPRIV: return "AUTHPRIV"; +#else + case WOLF_LOG_AUTHPRIV: return ""; +#endif +#if defined LOG_FTP + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_FTP: return "FTP"; +#else + case WOLF_LOG_FTP: return ""; +#endif +#if defined LOG_NTP + /* FreeBSD */ + case WOLF_LOG_NTP: return "NTP"; +#else + case WOLF_LOG_NTP: return ""; +#endif +#if defined LOG_SECURITY + /* FreeBSD */ + case WOLF_LOG_SECURITY: return "SECURITY"; +#else + case WOLF_LOG_SECURITY: return ""; +#endif +#if defined LOG_CONSOLE + /* FreeBSD */ + case WOLF_LOG_CONSOLE: return "CONSOLE"; +#else + case WOLF_LOG_CONSOLE: return ""; +#endif +#if defined LOG_AUDIT + /* Solaris 10 */ + case WOLF_LOG_AUDIT: return "AUDIT"; +#else + case WOLF_LOG_AUDIT: return ""; +#endif + case WOLF_LOG_LOCAL0: return "LOCAL0"; + case WOLF_LOG_LOCAL1: return "LOCAL1"; + case WOLF_LOG_LOCAL2: return "LOCAL2"; + case WOLF_LOG_LOCAL3: return "LOCAL3"; + case WOLF_LOG_LOCAL4: return "LOCAL4"; + case WOLF_LOG_LOCAL5: return "LOCAL5"; + case WOLF_LOG_LOCAL6: return "LOCAL6"; + case WOLF_LOG_LOCAL7: return "LOCAL7"; + default: return ""; + } +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_SYSLOG_H +wolf_log_syslog_facility_t wolf_log_str_to_syslog_facility( const char *facility ) { + if( strcmp( facility, "KERN" ) == 0 ) return WOLF_LOG_KERN; + if( strcmp( facility, "USER" ) == 0 ) return WOLF_LOG_USER; + if( strcmp( facility, "MAIL" ) == 0 ) return WOLF_LOG_MAIL; + if( strcmp( facility, "DAEMON" ) == 0 ) return WOLF_LOG_DAEMON; + if( strcmp( facility, "AUTH" ) == 0 ) return WOLF_LOG_AUTH; + if( strcmp( facility, "SYSLOG" ) == 0 ) return WOLF_LOG_SYSLOG; + if( strcmp( facility, "LPR" ) == 0 ) return WOLF_LOG_LPR; + if( strcmp( facility, "NEWS" ) == 0 ) return WOLF_LOG_NEWS; + if( strcmp( facility, "UUCP" ) == 0 ) return WOLF_LOG_UUCP; + if( strcmp( facility, "CRON" ) == 0 ) return WOLF_LOG_CRON; + if( strcmp( facility, "AUTHPRIV" ) == 0 ) return WOLF_LOG_AUTHPRIV; + if( strcmp( facility, "FTP" ) == 0 ) return WOLF_LOG_FTP; + if( strcmp( facility, "NTP" ) == 0 ) return WOLF_LOG_NTP; + if( strcmp( facility, "SECURITY" ) == 0 ) return WOLF_LOG_SECURITY; + if( strcmp( facility, "CONSOLE" ) == 0 ) return WOLF_LOG_CONSOLE; + if( strcmp( facility, "AUDIT" ) == 0 ) return WOLF_LOG_AUDIT; + if( strcmp( facility, "LOCAL0" ) == 0 ) return WOLF_LOG_LOCAL0; + if( strcmp( facility, "LOCAL1" ) == 0 ) return WOLF_LOG_LOCAL1; + if( strcmp( facility, "LOCAL2" ) == 0 ) return WOLF_LOG_LOCAL2; + if( strcmp( facility, "LOCAL3" ) == 0 ) return WOLF_LOG_LOCAL3; + if( strcmp( facility, "LOCAL4" ) == 0 ) return WOLF_LOG_LOCAL4; + if( strcmp( facility, "LOCAL5" ) == 0 ) return WOLF_LOG_LOCAL5; + if( strcmp( facility, "LOCAL6" ) == 0 ) return WOLF_LOG_LOCAL6; + if( strcmp( facility, "LOCAL7" ) == 0 ) return WOLF_LOG_LOCAL7; + + /* this is a seasonable default if nothing else exists */ + return WOLF_LOG_DAEMON; +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_SYSLOG_H +bool wolf_log_platform_has_syslog_facility( wolf_log_syslog_facility_t facility ) { + switch( facility ) { + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_KERN: + case WOLF_LOG_USER: + case WOLF_LOG_MAIL: + case WOLF_LOG_DAEMON: + case WOLF_LOG_AUTH: + case WOLF_LOG_SYSLOG: + case WOLF_LOG_LPR: + case WOLF_LOG_NEWS: + case WOLF_LOG_UUCP: + case WOLF_LOG_CRON: + case WOLF_LOG_LOCAL0: + case WOLF_LOG_LOCAL1: + case WOLF_LOG_LOCAL2: + case WOLF_LOG_LOCAL3: + case WOLF_LOG_LOCAL4: + case WOLF_LOG_LOCAL5: + case WOLF_LOG_LOCAL6: + case WOLF_LOG_LOCAL7: + return true; +#if defined LOG_AUTHPRIV + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_AUTHPRIV: return true; +#else + case WOLF_LOG_AUTHPRIV: return false; +#endif +#if defined LOG_FTP + /* Linux, FreeBSD, OpenBSD, NetBSD */ + case WOLF_LOG_FTP: return true; +#else + case WOLF_LOG_FTP: return false; +#endif +#if defined LOG_NTP + /* FreeBSD */ + case WOLF_LOG_NTP: return true; +#else + case WOLF_LOG_NTP: return false; +#endif +#if defined LOG_SECURITY + /* FreeBSD */ + case WOLF_LOG_SECURITY: return true; +#else + case WOLF_LOG_SECURITY: return false; +#endif +#if defined LOG_CONSOLE + /* FreeBSD */ + case WOLF_LOG_CONSOLE: return true; +#else + case WOLF_LOG_CONSOLE: return false; +#endif +#if defined LOG_AUDIT + /* Solaris 10 */ + case WOLF_LOG_AUDIT: return true; +#else + case WOLF_LOG_AUDIT: return false; +#endif + } + + return false; +} +#endif /* defined HAVE_SYSLOG_H */ + +wolf_log_level_t wolf_log_str_to_level( const char *level ) { + if( strcmp( level, "EMERG" ) == 0 ) return WOLF_LOG_EMERG; + if( strcmp( level, "ALERT" ) == 0 ) return WOLF_LOG_ALERT; + if( strcmp( level, "CRIT" ) == 0 ) return WOLF_LOG_CRIT; + if( strcmp( level, "ERR" ) == 0 ) return WOLF_LOG_ERR; + if( strcmp( level, "WARNING" ) == 0 ) return WOLF_LOG_WARNING; + if( strcmp( level, "NOTICE" ) == 0 ) return WOLF_LOG_NOTICE; + if( strcmp( level, "INFO" ) == 0 ) return WOLF_LOG_INFO; + if( strcmp( level, "DEBUG" ) == 0 ) return WOLF_LOG_DEBUG; + if( strcmp( level, "DEBUG1" ) == 0 ) return WOLF_LOG_DEBUG1; + if( strcmp( level, "DEBUG2" ) == 0 ) return WOLF_LOG_DEBUG2; + if( strcmp( level, "DEBUG3" ) == 0 ) return WOLF_LOG_DEBUG3; + if( strcmp( level, "DEBUG4" ) == 0 ) return WOLF_LOG_DEBUG4; + if( strcmp( level, "DEBUG5" ) == 0 ) return WOLF_LOG_DEBUG5; + + return WOLF_LOG_EMERG; +} + +#if defined HAVE_SYSLOG_H +static int map_log_to_syslog_level( wolf_log_level_t level ) { + switch( level ) { + case WOLF_LOG_EMERG: return LOG_EMERG; + case WOLF_LOG_ALERT: return LOG_ALERT; + case WOLF_LOG_CRIT: return LOG_CRIT; + case WOLF_LOG_ERR: return LOG_ERR; + case WOLF_LOG_WARNING: return LOG_WARNING; + case WOLF_LOG_NOTICE: return LOG_NOTICE; + case WOLF_LOG_INFO: return LOG_INFO; + case WOLF_LOG_DEBUG: + case WOLF_LOG_DEBUG1: + case WOLF_LOG_DEBUG2: + case WOLF_LOG_DEBUG3: + case WOLF_LOG_DEBUG4: + case WOLF_LOG_DEBUG5: return LOG_DEBUG; + default: return LOG_EMERG; + } +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG +/* TODO: logging of audit success/fail and how to map this to the + * upper layer (so on Unix things can also go to LOG_SECURITY or + * LOG_AUDIT on special Unixes. But for this we have to read a + * log first! + */ +static WORD wolf_log_level_to_eventlog_type( wolf_log_level_t level ) { + switch( level ) { + case WOLF_LOG_EMERG: + case WOLF_LOG_ALERT: + case WOLF_LOG_CRIT: + case WOLF_LOG_ERR: return EVENTLOG_ERROR_TYPE; + case WOLF_LOG_WARNING: return EVENTLOG_WARNING_TYPE; + case WOLF_LOG_NOTICE: + case WOLF_LOG_INFO: + case WOLF_LOG_DEBUG: + case WOLF_LOG_DEBUG1: + case WOLF_LOG_DEBUG2: + case WOLF_LOG_DEBUG3: + case WOLF_LOG_DEBUG4: + case WOLF_LOG_DEBUG5: return EVENTLOG_INFORMATION_TYPE; + default: return EVENTLOG_ERROR_TYPE; + } +} +#endif /* defined HAVE_EVENTLOG */ + +#if defined HAVE_SYSLOG_H +static int map_log_facility_to_syslog_facility( int facility ) { + switch( facility ) { + case WOLF_LOG_KERN: return LOG_KERN; + case WOLF_LOG_USER: return LOG_USER; + case WOLF_LOG_MAIL: return LOG_MAIL; + case WOLF_LOG_DAEMON: return LOG_DAEMON; + case WOLF_LOG_AUTH: return LOG_AUTH; + case WOLF_LOG_SYSLOG: return LOG_SYSLOG; + case WOLF_LOG_LPR: return LOG_LPR; + case WOLF_LOG_NEWS: return LOG_NEWS; + case WOLF_LOG_UUCP: return LOG_UUCP; + case WOLF_LOG_CRON: return LOG_CRON; +#if defined LOG_AUTHPRIV + case WOLF_LOG_AUTHPRIV: return LOG_AUTHPRIV; +#else + case WOLF_LOG_AUTHPRIV: return LOG_DAEMON; +#endif +#if defined LOG_FTP + case WOLF_LOG_FTP: return LOG_FTP; +#else + case WOLF_LOG_FTP: return LOG_DAEMON; +#endif +#if defined LOG_NTP + case WOLF_LOG_NTP: return LOG_NTP; +#else + case WOLF_LOG_NTP: return LOG_DAEMON; +#endif +#if defined LOG_SECURITY + case WOLF_LOG_SECURITY: return LOG_SECURITY; +#else + case WOLF_LOG_SECURITY: return LOG_DAEMON; +#endif +#if defined LOG_CONSOLE + case WOLF_LOG_CONSOLE: return LOG_CONSOLE; +#else + case WOLF_LOG_CONSOLE: return LOG_DAEMON; +#endif +#if defined LOG_AUDIT + case WOLF_LOG_AUDIT: return LOG_AUDIT; +#else + case WOLF_LOG_AUDIT: return LOG_DAEMON; +#endif + case WOLF_LOG_LOCAL0: return LOG_LOCAL0; + case WOLF_LOG_LOCAL1: return LOG_LOCAL1; + case WOLF_LOG_LOCAL2: return LOG_LOCAL2; + case WOLF_LOG_LOCAL3: return LOG_LOCAL3; + case WOLF_LOG_LOCAL4: return LOG_LOCAL4; + case WOLF_LOG_LOCAL5: return LOG_LOCAL5; + case WOLF_LOG_LOCAL6: return LOG_LOCAL6; + case WOLF_LOG_LOCAL7: return LOG_LOCAL7; + default: return LOG_DAEMON; + } +} +#endif /* defined HAVE_SYSLOG_H */ + +const char *wolf_log_level_to_str( wolf_log_level_t level ) { + switch( level ) { + case WOLF_LOG_EMERG: return "EMERG"; + case WOLF_LOG_ALERT: return "ALERT"; + case WOLF_LOG_CRIT: return "CRIT"; + case WOLF_LOG_ERR: return "ERR"; + case WOLF_LOG_WARNING: return "WARNING"; + case WOLF_LOG_NOTICE: return "NOTICE"; + case WOLF_LOG_INFO: return "INFO"; + case WOLF_LOG_DEBUG: return "DEBUG"; + case WOLF_LOG_DEBUG1: return "DEBUG1"; + case WOLF_LOG_DEBUG2: return "DEBUG2"; + case WOLF_LOG_DEBUG3: return "DEBUG3"; + case WOLF_LOG_DEBUG4: return "DEBUG4"; + case WOLF_LOG_DEBUG5: return "DEBUG5"; + default: return ""; + } +} + +static const char *log_logfile_filename; +static FILE *log_file = NULL; +static wolf_log_level_t log_logfile_level; +static wolf_log_level_t log_stderr_level; +#if defined HAVE_SYSLOG_H +static const char *syslog_ident; +static int syslog_facility; +static int syslog_level; +static int syslog_options; +#endif /* defined HAVE_SYSLOG_H */ +#if defined HAVE_EVENTLOG +static HANDLE event_source = 0; +static int eventlog_level; +static const char *eventlog_server; +static const char *eventlog_log; +static const char *eventlog_source; +static PSID sid = NULL; +#endif /* defined HAVE_EVENTLOG */ + +void wolf_log_openlogtofile( const char *filename, wolf_log_level_t level ) { + log_logfile_filename = filename; + log_logfile_level = level; + wolf_log_reopenlogtofile( ); +} + +#if defined HAVE_SYSLOG_H +static int map_log_options_to_syslog_options( int opts ) { + int syslog_opts = LOG_NDELAY; + + if( ( opts & WOLF_LOG_SYSLOG_PID ) == WOLF_LOG_SYSLOG_PID ) { + syslog_opts |= LOG_PID; + } + if( ( opts & WOLF_LOG_SYSLOG_CONS ) == WOLF_LOG_SYSLOG_CONS ) { + syslog_opts |= LOG_CONS; + } + + return syslog_opts; +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_SYSLOG_H +void wolf_log_openlogtosyslog( const char *ident, + wolf_log_syslog_facility_t facility, + wolf_log_level_t level, + int options ) { + syslog_ident = ident; + syslog_facility = map_log_facility_to_syslog_facility( facility ); + syslog_level = map_log_to_syslog_level( level ); + syslog_options = map_log_options_to_syslog_options( options ); + + openlog( ident, LOG_CONS | LOG_NDELAY, facility ); + setlogmask( LOG_UPTO( level ) ); +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG + +static void registry_set_expandable_string( HKEY h, TCHAR *name, TCHAR *value ) { + RegSetValueEx( h, name, 0, REG_EXPAND_SZ, (LPBYTE)value, strlen( value ) ); +} + +static void registry_set_word( HKEY h, TCHAR *name, DWORD value ) { + RegSetValueEx( h, name, 0, REG_DWORD, (LPBYTE)&value, sizeof( DWORD ) ); +} + +static void register_event_source( const char *log, const char *source ) { + char key[256]; + HKEY h = 0; + DWORD disposition; + + /* compose the registry key and simply overwrite the values there, we know */ + snprintf( key, 256, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\%s\\%s", log, source ); + RegCreateKeyEx( HKEY_LOCAL_MACHINE, key, 0, NULL, REG_OPTION_NON_VOLATILE, + KEY_SET_VALUE, NULL, &h, &disposition ); + + /* make sure not to have hard-coded pathes here, otherwise remote + * event logging will not work! */ + registry_set_expandable_string( h, "EventMessageFile", "%SystemRoot%\\System32\\wolfmsg.dll" ); + registry_set_expandable_string( h, "CategoryMessageFile", "%SystemRoot%\\System32\\wolfmsg.dll" ); + registry_set_word( h, "TypesSupported", (DWORD)7 ); + registry_set_word( h, "CategoryCount", (DWORD)2 ); + RegCloseKey( h ); +} + +static PSID get_current_sid( void ) { + HANDLE process = NULL; + HANDLE token = NULL; + DWORD token_user_size = 0; + PTOKEN_USER token_user; + PSID token_sid = NULL; + DWORD sid_size = 0; + PSID sid = NULL; + + /* get the token for the current process */ + process = GetCurrentProcess( ); + if( process == NULL ) { + fprintf( stderr, "%s: Unable to get current process handle\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + abort( ); + } + if( !OpenProcessToken( process, TOKEN_QUERY, &token ) ) { + fprintf( stderr, "%s: Unable to get process token of current process\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + abort( ); + } + + /* get the required size to store the user token and allocate memory for it */ + (void)GetTokenInformation( token, TokenUser, NULL, 0, &token_user_size ); + token_user = (PTOKEN_USER)malloc( token_user_size * sizeof( BYTE ) ); + if( token_user == NULL ) { + fprintf( stderr, "%s: Unable to get memory to store user token\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + CloseHandle( token ); + abort( ); + } + + /* get the user token */ + if( !GetTokenInformation( token, TokenUser, (LPVOID)token_user, token_user_size, &token_user_size ) ) { + fprintf( stderr, "%s: Unable to get user token\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + free( token_user ); + CloseHandle( token ); + abort( ); + } + + /* finally we made our way to the SID. Make a local copy of it because it and return that one */ + token_sid = (PSID)token_user->User.Sid; + sid_size = GetLengthSid( token_sid ); + sid = (PSID)malloc( sid_size ); + if( sid != NULL ) { + if( !CopySid( sid_size, sid, token_sid ) ) { + fprintf( stderr, "%s: Unable to make a copy of the current SID\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + free( sid ); + free( token_user ); + CloseHandle( token ); + abort( ); + } + } + + /* process handle is a pseudo handle which doesn't need closing */ + free( token_user ); + CloseHandle( token ); + + return sid; +} + +void wolf_log_openlogtoeventlog( const char *server, + const char *log, + const char *source, + wolf_log_level_t level ) { + eventlog_server = server; + eventlog_log = log; + eventlog_source = source; + eventlog_level = level; + + /* fiddle in the registry and register the location of the + * message DLL, how many categories we define and what types + * of events we are supporting + */ + register_event_source( log, source ); + + /* for logging the user of the process into the event log */ + sid = get_current_sid( ); + + /* TODO: remote machine and event log source should be in the API, + * but we have Windows localized strings which are hard to unify + * with Unix. We also don't want to have a stupid string wrapper + * on top.. No clue for now + */ + event_source = RegisterEventSource( server, source ); + if( event_source == NULL ) { + /* TODO: add GetLastError here! */ + fprintf( stderr, "%s: Unable to register event source\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + } +} +#endif /* defined HAVE_EVENTLOG */ + +void wolf_log_openlogtostderr( wolf_log_level_t level ) { + log_stderr_level = level; +} + +void wolf_log_closelogtofile( void ) { + if( log_file != NULL ) { + fclose( log_file ); + log_file = NULL; + } +} + +#if defined HAVE_SYSLOG_H +void wolf_log_closelogtosyslog( void ) { + closelog( ); +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG +void wolf_log_closelogtoeventlog( void ) { + if( sid != NULL ) { + free( sid ); + sid = NULL; + } + + if( !DeregisterEventSource( event_source ) ) { + /* TODO: add GetLastError here! */ + fprintf( stderr, "%s: Unable to deregister event source handle\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + } +} +#endif /* defined HAVE_EVENTLOG */ + +void wolf_log_closelogtostderr( void ) { + /* do nothing here */ +} + +void wolf_log_reopenlogtofile( void ) { + if( log_file != NULL ) { + fclose( log_file ); + } + log_file = fopen( log_logfile_filename, "a" ); + if( log_file == NULL ) { + char errmsg[255]; + strerror_r( errno, errmsg, 255 ); + fprintf( stderr, "%s: Unable to open logfile '%s': %s\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ), + log_logfile_filename, errmsg ); + } +} + +#if defined HAVE_SYSLOG_H +void wolf_log_reopenlogtosyslog( void ) { + openlog( syslog_ident, syslog_options, syslog_facility ); + setlogmask( LOG_UPTO( syslog_level ) ); +} +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG +void wolf_log_reopenlogtoeventlog( void ) { + /* TODO: close and open? */ +} +#endif /* defined HAVE_EVENTLOG */ + +void wolf_log( wolf_log_level_t level, int category_id, int message_id, const char *format, ... ) { + va_list ap; + char s[1024]; + va_start( ap, format ); + vsnprintf( s, 1024, format, ap ); + va_end( ap ); + + WOLF_UNUSED( category_id ); + WOLF_UNUSED( message_id ); + + if( level <= log_stderr_level ) + fprintf( stderr, "%s: %s\n",wolf_log_level_to_str( level ), s ); + + if( level <= log_logfile_level && log_file != NULL ) { + time_t t; + struct tm local_time; + char date_str[100]; + + time( &t ); + assert( t >= 0 ); /* actually the only error known is an illegal buffer */ + if( localtime_r( &t, &local_time ) == NULL ) { + char errmsg[512]; + strerror_r( errno, errmsg, 512 ); + fprintf( stderr, "%s: localtime_r failed with errno %d (%s)!!\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ), errno, errmsg ); + abort( ); + } + + strftime( date_str, 100, "%b %d %H:%M:%S", &local_time ); + + fprintf( log_file, "%s %s %d-%d: %s\n", + date_str, wolf_log_level_to_str( level ), category_id, message_id, s ); + fflush( log_file ); + } + +#if defined HAVE_SYSLOG_H + syslog( map_log_to_syslog_level( level ), "%s", s ); +#endif /* defined HAVE_SYSLOG_H */ + +#if defined HAVE_EVENTLOG + if( level <= eventlog_level && event_source != 0 ) { + /* for now we map the snprintf-like format directly + * to one message string for event ID 0 (actually as + * most others like the .NET guys are doing! This + * is a bit TODO!) + */ + LPCTSTR msg_arr[2]; + + /* compose the message and the parameters */ + msg_arr[0] = wolf_log_level_to_str( level ); + msg_arr[1] = s; + + /* TODO: event categories and type, message numbers, + * resources for message DLLs etc. etc. etc. + */ + if( !ReportEvent( + event_source, /* event source handle */ + wolf_log_level_to_eventlog_type( level ), + 0x0FFF0001L, /* event category */ + 0xCFFF0101L, /* event identifier */ + sid, /* the security identifier */ + 2, /* at the moment only one string */ + 0, /* no binary raw data */ + msg_arr, /* the array of strings */ + NULL /* no binary raw data */ + ) ) { + /* TODO: add GetLastError here! */ + fprintf( stderr, "%s: Unable to log to event log\n", + wolf_log_level_to_str( WOLF_LOG_ALERT ) ); + } + } +#endif /* defined HAVE_EVENTLOG */ +} -- cgit v1.2.3-54-g00ecf