Thanks to Peter Wagemans and Laszlo Keresztfalvi for suggesting throttling restarts.\r
Thanks to Eugene Lifshitz for finding an edge case in CreateProcess() and for\r
advising how to build messages.mc correctly in paths containing spaces.\r
+Thanks to Rob Sharp for pointing out that NSSM did not respect the\r
+AppEnvironment registry value used by srvany.\r
\r
Licence\r
-------\r
Throttled restarts will not be interruptible.
.
+MessageId = +1
+SymbolicName = NSSM_EVENT_CREATEPROCESS_FAILED_INVALID_ENVIRONMENT
+Severity = Error
+Language = English
+Failed to start service %1. Program %2 couldn't be launched.
+CreateProcess() failed with ERROR_INVALID_PARAMETER and a process environment was set in the %3 registry value. It is likely that the environment was incorrectly specified. %3 should be a REG_MULTI_SZ value comprising strings of the form KEY=VALUE.
+.
+
+MessageId = +1
+SymbolicName = NSSM_EVENT_INVALID_ENVIRONMENT_STRING_TYPE
+Severity = Warning
+Language = English
+Environment declaration %1 for service %2 is not of type REG_MULTI_SZ and will be ignored.
+.
+
return 0;\r
}\r
\r
+int set_environment(char *service_name, HKEY key, char **env) {\r
+ unsigned long type = REG_MULTI_SZ;\r
+ unsigned long envlen = 0;\r
+\r
+ /* Dummy test to find buffer size */\r
+ unsigned long ret = RegQueryValueEx(key, NSSM_REG_ENV, 0, &type, NULL, &envlen);\r
+ if (ret != ERROR_SUCCESS) {\r
+ /* The service probably doesn't have any environment configured */\r
+ if (ret == ERROR_FILE_NOT_FOUND) return 0;\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);\r
+ return 1;\r
+ }\r
+\r
+ if (type != REG_MULTI_SZ) {\r
+ log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_INVALID_ENVIRONMENT_STRING_TYPE, NSSM_REG_ENV, service_name, 0);\r
+ return 2;\r
+ }\r
+\r
+ /* Probably not possible */\r
+ if (! envlen) return 0;\r
+\r
+ *env = (char *) HeapAlloc(GetProcessHeap(), 0, envlen);\r
+ if (! *env) {\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "environment registry", "set_environment()", 0);\r
+ return 3;\r
+ }\r
+\r
+ /* Actually get the strings */\r
+ ret = RegQueryValueEx(key, NSSM_REG_ENV, 0, &type, (unsigned char *) *env, &envlen);\r
+ if (ret != ERROR_SUCCESS) {\r
+ HeapFree(GetProcessHeap(), 0, *env);\r
+ *env = 0;\r
+ log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0);\r
+ return 4;\r
+ }\r
+\r
+ return 0;\r
+}\r
+\r
int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, bool sanitise) {\r
unsigned char *buffer = (unsigned char *) HeapAlloc(GetProcessHeap(), 0, datalen);\r
if (! buffer) {\r
return 0;\r
}\r
\r
-int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, unsigned long *throttle_delay) {\r
+int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, char **env, unsigned long *throttle_delay) {\r
unsigned long ret;\r
\r
/* Get registry */\r
log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_NO_DIR, NSSM_REG_DIR, service_name, dir, 0);\r
}\r
\r
+ /* Try to get environment variables - may fail */\r
+ set_environment(service_name, key, env);\r
+\r
/* Try to get throttle restart delay */\r
unsigned long type = REG_DWORD;\r
unsigned long buflen = sizeof(*throttle_delay);\r
#define NSSM_REG_EXE "Application"\r
#define NSSM_REG_FLAGS "AppParameters"\r
#define NSSM_REG_DIR "AppDirectory"\r
+#define NSSM_REG_ENV "AppEnvironment"\r
#define NSSM_REG_EXIT "AppExit"\r
#define NSSM_REG_THROTTLE "AppThrottle"\r
\r
int create_messages();\r
int create_parameters(char *, char *, char *, char *);\r
int create_exit_action(char *, const char *);\r
+int set_environment(char *, HKEY, char **);\r
int expand_parameter(HKEY, char *, char *, unsigned long, bool);\r
-int get_parameters(char *, char *, int, char *, int, char *, int, unsigned long *);\r
+int get_parameters(char *, char *, int, char *, int, char *, int, char **, unsigned long *);\r
int get_exit_action(char *, unsigned long *, unsigned char *, bool *);\r
\r
#endif\r
ZeroMemory(&pi, sizeof(pi));\r
\r
/* Get startup parameters */\r
- int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &throttle_delay);\r
+ char *env = 0;\r
+ int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &env, &throttle_delay);\r
if (ret) {\r
log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_PARAMETERS_FAILED, service_name, 0);\r
return stop_service(2, true, true);\r
\r
throttle_restart();\r
\r
- if (! CreateProcess(0, cmd, 0, 0, false, 0, 0, dir, &si, &pi)) {\r
- log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, error_string(GetLastError()), 0);\r
+ if (! CreateProcess(0, cmd, 0, 0, false, 0, env, dir, &si, &pi)) {\r
+ unsigned long error = GetLastError();\r
+ if (error == ERROR_INVALID_PARAMETER && env) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED_INVALID_ENVIRONMENT, service_name, exe, NSSM_REG_ENV, 0);\r
+ else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, error_string(error), 0);\r
return stop_service(3, true, true);\r
}\r
process_handle = pi.hProcess;\r