From: Iain Patterson Date: Sat, 25 Sep 2010 13:37:28 +0000 (+0100) Subject: Don't suicide on exit status 0. X-Git-Tag: v2.5~2 X-Git-Url: http://git.iain.cx/?p=nssm.git;a=commitdiff_plain;h=b465216f3ec97443952f64ba5d068354c1296d3c Don't suicide on exit status 0. Suiciding when the application exits 0 will cause recovery actions to be taken. Usually this is inappropriate. Only suicide if there is an explicit AppExit value for 0 in the registry. Technically such behaviour could be abused to do something like run a script after successful completion of a service but in most cases a suicide is undesirable when no actual failure occurred. --- diff --git a/README.txt b/README.txt index 022e5ed..d9e6ee0 100644 --- a/README.txt +++ b/README.txt @@ -97,7 +97,10 @@ of Windows you should use "Suicide" instead. If the value data is "Suicide" NSSM will simulate a crash and exit without informing the service manager. This option should only be used for -pre-Vista systems where you wish to apply a service recovery action. +pre-Vista systems where you wish to apply a service recovery action. Note +that if the monitored application exits with code 0, NSSM will only honour a +request to suicide if you explicitly configure a registry key for exit code 0. +If only the default action is set to Suicide NSSM will instead exit gracefully. Removing services using the GUI diff --git a/messages.mc b/messages.mc index 4363171..6048077 100644 --- a/messages.mc +++ b/messages.mc @@ -155,3 +155,13 @@ Language = English Service %1 action for exit code %2 is %3. Exiting. . + +MessageId = +1 +SymbolicName = NSSM_EVENT_GRACEFUL_SUICIDE +Severity = Informational +Language = English +Service %1 application %2 exited with exit code 0 but the default exit action is %3. +Honouring the %4 action would result in the service being flagged as failed and subject to recovery actions. +The service will instead be stopped gracefully. To suppress this message, explicitly configure the exit action for exit code 0 to either %5 or %6. +. + diff --git a/registry.cpp b/registry.cpp index 5dbadd2..ed01303 100644 --- a/registry.cpp +++ b/registry.cpp @@ -146,7 +146,10 @@ int get_parameters(char *service_name, char *exe, int exelen, char *flags, int f return 0; } -int get_exit_action(char *service_name, unsigned long *ret, unsigned char *action) { +int get_exit_action(char *service_name, unsigned long *ret, unsigned char *action, bool *default_action) { + /* Are we returning the default action or a status-specific one? */ + *default_action = ! ret; + /* Get registry */ char registry[KEY_LENGTH]; if (_snprintf(registry, sizeof(registry), NSSM_REGISTRY "\\%s", service_name, NSSM_REG_EXIT) < 0) { @@ -169,12 +172,12 @@ int get_exit_action(char *service_name, unsigned long *ret, unsigned char *actio if (! ret) code[0] = '\0'; else if (_snprintf(code, sizeof(code), "%lu", *ret) < 0) { RegCloseKey(key); - return get_exit_action(service_name, 0, action); + return get_exit_action(service_name, 0, action, default_action); } if (RegQueryValueEx(key, code, 0, &type, action, &action_len) != ERROR_SUCCESS) { RegCloseKey(key); /* Try again with * as the key if an exit code was defined */ - if (ret) return get_exit_action(service_name, 0, action); + if (ret) return get_exit_action(service_name, 0, action, default_action); return 0; } diff --git a/registry.h b/registry.h index 2f45f99..901a6ba 100644 --- a/registry.h +++ b/registry.h @@ -11,6 +11,6 @@ int create_messages(); int create_parameters(char *, char *, char *, char *); int create_exit_action(char *, const char *); int get_parameters(char *, char *, int, char *, int, char *, int); -int get_exit_action(char *, unsigned long *, unsigned char *); +int get_exit_action(char *, unsigned long *, unsigned char *, bool *); #endif diff --git a/service.cpp b/service.cpp index ccc8e89..8c42972 100644 --- a/service.cpp +++ b/service.cpp @@ -225,7 +225,7 @@ unsigned long WINAPI service_control_handler(unsigned long control, unsigned lon switch (control) { case SERVICE_CONTROL_SHUTDOWN: case SERVICE_CONTROL_STOP: - stop_service(0, true); + stop_service(0, true, true); return NO_ERROR; } @@ -250,11 +250,11 @@ int start_service() { char cmd[CMD_LENGTH]; if (_snprintf(cmd, sizeof(cmd), "%s %s", exe, flags) < 0) { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "command line", "start_service", 0); - return stop_service(2, true); + return stop_service(2, true, true); } if (! CreateProcess(0, cmd, 0, 0, 0, 0, 0, dir, &si, &pi)) { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, GetLastError(), 0); - return stop_service(3, true); + return stop_service(3, true, true); } pid = pi.hProcess; @@ -266,7 +266,12 @@ int start_service() { } /* Stop the service */ -int stop_service(unsigned long exitcode, bool graceful) { +int stop_service(unsigned long exitcode, bool graceful, bool default_action) { + if (default_action && ! exitcode && ! graceful) { + log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_GRACEFUL_SUICIDE, service_name, exe, exit_action_strings[NSSM_EXIT_UNCLEAN], exit_action_strings[NSSM_EXIT_UNCLEAN], exit_action_strings[NSSM_EXIT_UNCLEAN], exit_action_strings[NSSM_EXIT_REALLY] ,0); + graceful = true; + } + /* Signal we are stopping */ if (graceful) { service_status.dwCurrentState = SERVICE_STOP_PENDING; @@ -312,7 +317,8 @@ void CALLBACK end_service(void *arg, unsigned char why) { /* What action should we take? */ int action = NSSM_EXIT_RESTART; unsigned char action_string[ACTION_LEN]; - if (! get_exit_action(service_name, &ret, action_string)) { + bool default_action; + if (! get_exit_action(service_name, &ret, action_string, &default_action)) { for (int i = 0; exit_action_strings[i]; i++) { if (! _strnicmp((const char *) action_string, exit_action_strings[i], ACTION_LEN)) { action = i; @@ -341,13 +347,13 @@ void CALLBACK end_service(void *arg, unsigned char why) { /* Tell the service manager we are finished */ case NSSM_EXIT_REALLY: log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_REALLY, service_name, code, exit_action_strings[action], 0); - stop_service(ret, true); + stop_service(ret, true, default_action); break; /* Fake a crash so pre-Vista service managers will run recovery actions. */ case NSSM_EXIT_UNCLEAN: log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_UNCLEAN, service_name, code, exit_action_strings[action], 0); - exit(stop_service(ret, false)); + exit(stop_service(ret, false, default_action)); break; } } diff --git a/service.h b/service.h index 75d97ff..fb52c16 100644 --- a/service.h +++ b/service.h @@ -14,7 +14,7 @@ int remove_service(char *); void set_service_recovery(char *); int monitor_service(); int start_service(); -int stop_service(unsigned long, bool); +int stop_service(unsigned long, bool, bool); void CALLBACK end_service(void *, unsigned char); #endif