From: Iain Patterson Date: Sun, 1 Apr 2012 10:35:54 +0000 (+0100) Subject: Support srvany's AppEnvironment registry value. X-Git-Tag: v2.11~2 X-Git-Url: http://git.iain.cx/?a=commitdiff_plain;h=530bd80072effe809a6d3a2fc5fd847e51342021;p=nssm.git Support srvany's AppEnvironment registry value. Allow setting one or more environment variables for the application by creating the AppEnvironment value of type REG_MULTI_SZ. Each string should be of the form KEY=VALUE. VALUE may be omitted to set an empty environment variable but the equals sign must be present. This support is for compatibility with srvany. In accordance with the documented behaviour of srvany, only environment variables specified in AppEnvironment will be passed to the service. Any other variables, even system variables such as %PATH%, will be ignored if they are not explicitly listed. Note that Windows supports adding environment variables to the service's existing environment by creating the Environment value (also of type REG_MULTI_SZ) under HKLM\SYSTEM\CurrentControlSet\Services\ instead. It is recommended that new services use this standard functionality rather than AppEnvironment. Thanks Rob Sharp. --- diff --git a/README.txt b/README.txt index 590e396..5494575 100644 --- a/README.txt +++ b/README.txt @@ -180,6 +180,8 @@ registry value for AppDirectory confused NSSM. Thanks to Peter Wagemans and Laszlo Keresztfalvi for suggesting throttling restarts. Thanks to Eugene Lifshitz for finding an edge case in CreateProcess() and for advising how to build messages.mc correctly in paths containing spaces. +Thanks to Rob Sharp for pointing out that NSSM did not respect the +AppEnvironment registry value used by srvany. Licence ------- diff --git a/messages.mc b/messages.mc index 07ed432..28f12e8 100644 --- a/messages.mc +++ b/messages.mc @@ -290,3 +290,18 @@ Failed to create waitable timer for service %1: 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. +. + diff --git a/registry.cpp b/registry.cpp index 6b70a96..5172c50 100644 --- a/registry.cpp +++ b/registry.cpp @@ -102,6 +102,45 @@ int create_exit_action(char *service_name, const char *action_string) { return 0; } +int set_environment(char *service_name, HKEY key, char **env) { + unsigned long type = REG_MULTI_SZ; + unsigned long envlen = 0; + + /* Dummy test to find buffer size */ + unsigned long ret = RegQueryValueEx(key, NSSM_REG_ENV, 0, &type, NULL, &envlen); + if (ret != ERROR_SUCCESS) { + /* The service probably doesn't have any environment configured */ + if (ret == ERROR_FILE_NOT_FOUND) return 0; + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0); + return 1; + } + + if (type != REG_MULTI_SZ) { + log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_INVALID_ENVIRONMENT_STRING_TYPE, NSSM_REG_ENV, service_name, 0); + return 2; + } + + /* Probably not possible */ + if (! envlen) return 0; + + *env = (char *) HeapAlloc(GetProcessHeap(), 0, envlen); + if (! *env) { + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_OUT_OF_MEMORY, "environment registry", "set_environment()", 0); + return 3; + } + + /* Actually get the strings */ + ret = RegQueryValueEx(key, NSSM_REG_ENV, 0, &type, (unsigned char *) *env, &envlen); + if (ret != ERROR_SUCCESS) { + HeapFree(GetProcessHeap(), 0, *env); + *env = 0; + log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_ENV, error_string(GetLastError()), 0); + return 4; + } + + return 0; +} + int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, bool sanitise) { unsigned char *buffer = (unsigned char *) HeapAlloc(GetProcessHeap(), 0, datalen); if (! buffer) { @@ -142,7 +181,7 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b return 0; } -int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, unsigned long *throttle_delay) { +int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, char **env, unsigned long *throttle_delay) { unsigned long ret; /* Get registry */ @@ -192,6 +231,9 @@ int get_parameters(char *service_name, char *exe, int exelen, char *flags, int f log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_NO_DIR, NSSM_REG_DIR, service_name, dir, 0); } + /* Try to get environment variables - may fail */ + set_environment(service_name, key, env); + /* Try to get throttle restart delay */ unsigned long type = REG_DWORD; unsigned long buflen = sizeof(*throttle_delay); diff --git a/registry.h b/registry.h index 261b0e9..aae45ac 100644 --- a/registry.h +++ b/registry.h @@ -5,14 +5,16 @@ #define NSSM_REG_EXE "Application" #define NSSM_REG_FLAGS "AppParameters" #define NSSM_REG_DIR "AppDirectory" +#define NSSM_REG_ENV "AppEnvironment" #define NSSM_REG_EXIT "AppExit" #define NSSM_REG_THROTTLE "AppThrottle" int create_messages(); int create_parameters(char *, char *, char *, char *); int create_exit_action(char *, const char *); +int set_environment(char *, HKEY, char **); int expand_parameter(HKEY, char *, char *, unsigned long, bool); -int get_parameters(char *, char *, int, char *, int, char *, int, unsigned long *); +int get_parameters(char *, char *, int, char *, int, char *, int, char **, unsigned long *); int get_exit_action(char *, unsigned long *, unsigned char *, bool *); #endif diff --git a/service.cpp b/service.cpp index 4011484..ac329bc 100644 --- a/service.cpp +++ b/service.cpp @@ -300,7 +300,8 @@ int start_service() { ZeroMemory(&pi, sizeof(pi)); /* Get startup parameters */ - int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &throttle_delay); + char *env = 0; + int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &env, &throttle_delay); if (ret) { log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_PARAMETERS_FAILED, service_name, 0); return stop_service(2, true, true); @@ -315,8 +316,10 @@ int start_service() { throttle_restart(); - if (! CreateProcess(0, cmd, 0, 0, false, 0, 0, dir, &si, &pi)) { - log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, error_string(GetLastError()), 0); + if (! CreateProcess(0, cmd, 0, 0, false, 0, env, dir, &si, &pi)) { + unsigned long error = GetLastError(); + if (error == ERROR_INVALID_PARAMETER && env) log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED_INVALID_ENVIRONMENT, service_name, exe, NSSM_REG_ENV, 0); + else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_CREATEPROCESS_FAILED, service_name, exe, error_string(error), 0); return stop_service(3, true, true); } process_handle = pi.hProcess;