diff --git a/daemon/unbound.c b/daemon/unbound.c index 14a3e45b7..19cd456da 100644 --- a/daemon/unbound.c +++ b/daemon/unbound.c @@ -582,6 +582,7 @@ main(int argc, char* argv[]) const char* winopt = NULL; int cmdline_verbose = 0; int debug_mode = 0; + int cmdline_cfg = 0; #ifdef HAVE_SBRK /* take debug snapshot of heap */ @@ -594,6 +595,7 @@ main(int argc, char* argv[]) switch(c) { case 'c': cfgfile = optarg; + cmdline_cfg = 1; break; case 'v': cmdline_verbose ++; @@ -617,7 +619,8 @@ main(int argc, char* argv[]) if(winopt) { #ifdef UB_ON_WINDOWS - wsvc_command_option(winopt, cfgfile, cmdline_verbose); + wsvc_command_option(winopt, cfgfile, cmdline_verbose, + cmdline_cfg); #else fatal_exit("option not supported"); #endif diff --git a/doc/Changelog b/doc/Changelog index fa897e839..0038b5fa7 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -3,6 +3,11 @@ - winsock event handler tests if signals are really signalled. - install and service with log to file works on XP and Vista on default install location. + - on windows logging to the Application logbook works (as a service). + - fix RUN_DIR on windows compile setting in makedist. + - windows registry has Software\Unbound\ConfigFile element. + If does not exist, the default is used. The -c switch overrides it. + - fix makedist version cleanup function. 10 March 2009: Wouter - makedist -w strips out old rc.. and snapshot info from version. diff --git a/makedist.sh b/makedist.sh index 80e9229b7..7d33d1a03 100755 --- a/makedist.sh +++ b/makedist.sh @@ -149,13 +149,14 @@ done if [ "$DOWIN" = "yes" ]; then version=`./configure --version | head -1 | awk '{ print $3 }'` \ || error_cleanup "Cannot determine version number." - version=`echo $version | sed -e 's/rc.*$//' -e 's/_20.*$//'` if [ "$RC" != "no" -o "$SNAPSHOT" != "no" ]; then if [ "$RC" != "no" ]; then - version2=`echo $version | sed -e 's/rc.*//'`"rc$RC" + version2=`echo $version | sed -e 's/rc.*$//' -e 's/_20.*$//'` + version2=`echo $version2 | sed -e 's/rc.*//'`"rc$RC" fi if [ "$SNAPSHOT" != "no" ]; then - version2="${version}_`date +%Y%m%d`" + version2=`echo $version | sed -e 's/rc.*$//' -e 's/_20.*$//'` + version2="${version2}_`date +%Y%m%d`" fi replace_text "configure.ac" "AC_INIT(unbound, $version" "AC_INIT(unbound, $version2" version="$version2" @@ -170,8 +171,7 @@ if [ "$DOWIN" = "yes" ]; then echo './configure --enable-debug --enable-static-exe "--with-conf-file=C:\Program Files\Unbound\service.conf" --with-run-dir="" --with-pidfile="" --with-chroot-dir="" '"$*" ./configure --enable-debug --enable-static-exe \ "--with-conf-file=C:\Program Files\Unbound\service.conf" \ - "--with-run-dir=C:\Program Files\Unbound" --with-pidfile="" \ - --with-chroot-dir="" $* \ + --with-run-dir="" --with-pidfile="" --with-chroot-dir="" $* \ || error_cleanup "Could not configure" info "Calling make" make || error_cleanup "Could not make" diff --git a/util/log.c b/util/log.c index 25e98fc51..0f6ef07da 100644 --- a/util/log.c +++ b/util/log.c @@ -54,6 +54,9 @@ # define LOG_INFO 6 # define LOG_DEBUG 7 #endif +#ifdef UB_ON_WINDOWS +# include "winrc/win_svc.h" +#endif /* default verbosity */ enum verbosity_value verbosity = 0; @@ -65,7 +68,7 @@ static int key_created = 0; static ub_thread_key_t logkey; /** the identity of this executable/process */ static const char* ident="unbound"; -#ifdef HAVE_SYSLOG_H +#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS) /** are we using syslog(3) to log to */ static int logging_to_syslog = 0; #endif /* HAVE_SYSLOG_H */ @@ -83,7 +86,7 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) ub_thread_key_create(&logkey, NULL); } if(logfile -#ifdef HAVE_SYSLOG_H +#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS) || logging_to_syslog #endif ) @@ -103,6 +106,14 @@ log_init(const char* filename, int use_syslog, const char* chrootdir) logging_to_syslog = 1; return; } +#elif defined(UB_ON_WINDOWS) + if(logging_to_syslog) { + logging_to_syslog = 0; + } + if(use_syslog) { + logging_to_syslog = 1; + return; + } #endif /* HAVE_SYSLOG_H */ if(!filename || !filename[0]) { logfile = stderr; @@ -165,6 +176,32 @@ log_vmsg(int pri, const char* type, (int)getpid(), tid?*tid:0, type, message); return; } +#elif defined(UB_ON_WINDOWS) + if(logging_to_syslog) { + char m[32768]; + HANDLE* s; + LPCTSTR str = m; + DWORD tp = MSG_GENERIC_ERR; + WORD wt = EVENTLOG_ERROR_TYPE; + if(strcmp(type, "info") == 0) { + tp=MSG_GENERIC_INFO; + wt=EVENTLOG_INFORMATION_TYPE; + } else if(strcmp(type, "warning") == 0) { + tp=MSG_GENERIC_WARN; + wt=EVENTLOG_WARNING_TYPE; + } else if(strcmp(type, "notice") == 0 + || strcmp(type, "debug") == 0) { + tp=MSG_GENERIC_SUCCESS; + wt=EVENTLOG_SUCCESS; + } + snprintf(m, sizeof(m), "[unbound:%x] %s: %s", + tid?*tid:0, type, message); + s = RegisterEventSource(NULL, SERVICE_NAME); + if(!s) return; + ReportEvent(s, wt, 0, tp, NULL, 1, 0, &str, NULL); + DeregisterEventSource(s); + return; + } #endif /* HAVE_SYSLOG_H */ if(!logfile) return; if(log_now) diff --git a/winrc/service.conf b/winrc/service.conf index 8334adfb1..4b6b49060 100644 --- a/winrc/service.conf +++ b/winrc/service.conf @@ -1,8 +1,13 @@ # Unbound configuration file on windows. # See example.conf for more settings and syntax server: - # if you want to log to a file use - logfile: "unbound.log" # verbosity level 0-4 of logging - #verbosity: 1 + verbosity: 0 + + # if you want to log to a file use + #logfile: "unbound.log" + + # on Windows, this setting makes reports go into the Application log + # found in ControlPanels - System tasks - Logs + #use-syslog: yes diff --git a/winrc/setup.nsi b/winrc/setup.nsi index 7de5c72cb..baa3443b8 100644 --- a/winrc/setup.nsi +++ b/winrc/setup.nsi @@ -112,7 +112,8 @@ section "-hidden.postinstall" ${EndIf} # store installation folder - WriteRegStr HKLM "Software\Unbound" "InstallLocation" $INSTDIR + WriteRegStr HKLM "Software\Unbound" "InstallLocation" "$INSTDIR" + WriteRegStr HKLM "Software\Unbound" "ConfigFile" "$INSTDIR\service.conf" # uninstaller WriteUninstaller "uninst.exe" diff --git a/winrc/win_svc.c b/winrc/win_svc.c index 5a18f5478..f04fc0fdf 100644 --- a/winrc/win_svc.c +++ b/winrc/win_svc.c @@ -52,15 +52,6 @@ #include "util/netevent.h" #include "util/winsock_event.h" -/** from gen_msg.h - success message record for windows message log */ -#define MSG_GENERIC_SUCCESS ((DWORD)0x20010001L) -/** from gen_msg.h - informational message record for windows message log */ -#define MSG_GENERIC_INFO ((DWORD)0x60010002L) -/** from gen_msg.h - warning message record for windows message log */ -#define MSG_GENERIC_WARN ((DWORD)0xA0010003L) -/** from gen_msg.h - error message record for windows message log */ -#define MSG_GENERIC_ERR ((DWORD)0xE0010004L) - /** global service status */ SERVICE_STATUS service_status; /** global service status handle */ @@ -70,7 +61,7 @@ WSAEVENT service_stop_event = NULL; /** event struct for stop callbacks */ struct event service_stop_ev; /** config file to open. global communication to service_main() */ -const char* service_cfgfile = CONFIGFILE; +char* service_cfgfile = CONFIGFILE; /** commandline verbosity. global communication to service_main() */ int service_cmdline_verbose = 0; @@ -80,7 +71,7 @@ int service_cmdline_verbose = 0; * @param exitcode: error code (when stopped) * @param wait: pending operation estimated time in milliseconds. */ -void report_status(DWORD state, DWORD exitcode, DWORD wait) +static void report_status(DWORD state, DWORD exitcode, DWORD wait) { static DWORD checkpoint = 1; service_status.dwCurrentState = state; @@ -145,6 +136,47 @@ reportev(const char* str) DeregisterEventSource(s); } +/** + * Obtain registry string (if it exists). + * @param key: key string + * @param name: name of value to fetch. + * @return malloced string with the result or NULL if it did not + * exist on an error (logged) was encountered. + */ +static char* +lookup_reg_str(const char* key, const char* name) +{ + HKEY hk = NULL; + DWORD type = 0; + BYTE buf[1024]; + DWORD len = (DWORD)sizeof(buf); + LONG ret; + char* result = NULL; + ret = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &hk); + if(ret == ERROR_FILE_NOT_FOUND) + return NULL; /* key does not exist */ + else if(ret != ERROR_SUCCESS) { + reportev("RegOpenKeyEx failed"); + return NULL; + } + ret = RegQueryValueEx(hk, (LPCTSTR)name, 0, &type, buf, &len); + if(RegCloseKey(hk)) + reportev("RegCloseKey"); + if(ret == ERROR_FILE_NOT_FOUND) + return NULL; /* name does not exist */ + else if(ret != ERROR_SUCCESS) { + reportev("RegQueryValueEx failed"); + return NULL; + } + if(type == REG_SZ || type == REG_MULTI_SZ || type == REG_EXPAND_SZ) { + buf[sizeof(buf)-1] = 0; + buf[sizeof(buf)-2] = 0; /* for multi_sz */ + result = strdup(buf); + if(!result) reportev("out of memory"); + } + return result; +} + /** * Init service. Keeps calling status pending to tell service control * manager that this process is not hanging. @@ -157,9 +189,13 @@ service_init(struct daemon** d, struct config_file** c) { struct config_file* cfg = NULL; struct daemon* daemon = NULL; - const char* logfile= "C:\\unbound.log"; - verbosity=4; service_cmdline_verbose=4; - log_init(logfile, 0, NULL); /* DEBUG logfile */ + + if(!service_cfgfile) { + char* newf = lookup_reg_str("Software\\Unbound", "ConfigFile"); + if(newf) service_cfgfile = newf; + else service_cfgfile = strdup(CONFIGFILE); + if(!service_cfgfile) fatal_exit("out of memory"); + } /* create daemon */ daemon = daemon_init(); @@ -191,7 +227,7 @@ service_init(struct daemon** d, struct config_file** c) } else verbose(VERB_QUERY, "chdir to %s", cfg->directory); } - /* log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); DEBUG*/ + log_init(cfg->logfile, cfg->use_syslog, cfg->chrootdir); report_status(SERVICE_START_PENDING, NO_ERROR, 2400); verbose(VERB_QUERY, "winservice - apply cfg"); daemon_apply_cfg(daemon, cfg); @@ -222,8 +258,6 @@ service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) struct config_file* cfg = NULL; struct daemon* daemon = NULL; - reportev("Trying to report event"); - service_status_handle = RegisterServiceCtrlHandler(SERVICE_NAME, (LPHANDLER_FUNCTION)hdlr); if(!service_status_handle) { @@ -269,25 +303,29 @@ service_main(DWORD ATTR_UNUSED(argc), LPTSTR* ATTR_UNUSED(argv)) config_delete(cfg); daemon_delete(daemon); (void)WSACloseEvent(service_stop_event); + free(service_cfgfile); verbose(VERB_QUERY, "winservice - full stop"); report_status(SERVICE_STOPPED, NO_ERROR, 0); } /** start the service */ static void -service_start(const char* cfgfile, int v) +service_start(const char* cfgfile, int v, int c) { SERVICE_TABLE_ENTRY myservices[2] = { {SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION)service_main}, {NULL, NULL} }; verbosity=v; - if(1) { - /* DEBUG log to file */ + if(verbosity >= VERB_QUERY) { + /* log to file about start sequence */ fclose(fopen("C:\\unbound.log", "w")); log_init("C:\\unbound.log", 0, 0); verbose(VERB_QUERY, "open logfile"); - } - service_cfgfile = cfgfile; + } else log_init(0, 1, 0); /* otherwise, use Application log */ + if(c) { + service_cfgfile = strdup(cfgfile); + if(!service_cfgfile) fatal_exit("out of memory"); + } else service_cfgfile = NULL; service_cmdline_verbose = v; /* this call returns when service has stopped. */ if(!StartServiceCtrlDispatcher(myservices)) { @@ -296,14 +334,14 @@ service_start(const char* cfgfile, int v) } void -wsvc_command_option(const char* wopt, const char* cfgfile, int v) +wsvc_command_option(const char* wopt, const char* cfgfile, int v, int c) { if(strcmp(wopt, "install") == 0) wsvc_install(stdout, NULL); else if(strcmp(wopt, "remove") == 0) wsvc_remove(stdout); else if(strcmp(wopt, "service") == 0) - service_start(cfgfile, v); + service_start(cfgfile, v, c); else fatal_exit("unknown option: %s", wopt); exit(0); } diff --git a/winrc/win_svc.h b/winrc/win_svc.h index 0b4ecfa60..332a5268c 100644 --- a/winrc/win_svc.h +++ b/winrc/win_svc.h @@ -51,13 +51,23 @@ struct worker; /** service name for unbound (internal to ServiceManager) */ #define SERVICE_NAME "unbound" +/** from gen_msg.h - success message record for windows message log */ +#define MSG_GENERIC_SUCCESS ((DWORD)0x20010001L) +/** from gen_msg.h - informational message record for windows message log */ +#define MSG_GENERIC_INFO ((DWORD)0x60010002L) +/** from gen_msg.h - warning message record for windows message log */ +#define MSG_GENERIC_WARN ((DWORD)0xA0010003L) +/** from gen_msg.h - error message record for windows message log */ +#define MSG_GENERIC_ERR ((DWORD)0xE0010004L) + /** * Handle commandline service for windows. * @param wopt: windows option string (install, remove, service). * @param cfgfile: configfile to open (default or passed with -c). * @param v: amount of commandline verbosity added with -v. + * @param c: true if cfgfile was set by commandline -c option. */ -void wsvc_command_option(const char* wopt, const char* cfgfile, int v); +void wsvc_command_option(const char* wopt, const char* cfgfile, int v, int c); /** * Setup lead worker events.