From 3e92dce8716991c7100ea55f0b5e202a05c1b56d Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Thu, 21 Jul 2016 17:23:21 +0100 Subject: [PATCH] Allow adding or removing individual environment variables. Specifying an environment string as +KEY=VALUE will append KEY=VALUE to the existing block, or create a new one if none was previously configured. If KEY is already present, +KEY=VALUE will override it in place. Specifying -KEY=VALUE will remove KEY=VALUE from the existing block. Specifying -KEY will remove KEY regardless of its value. Removing the last key will delete the whole block. Specifying :KEY=VALUE is equivalent to KEY=VALUE, ie it creates a new block with only KEY=VALUE present. Its main purpose is to make scripts easier to read. nssm set AppEnvironment :FIRST=one nssm set AppEnvironment +SECOND=two nssm set AppEnvironment +THIRD=two --- README.txt | 40 +++++++++++++++++++++++++++++++++++++--- settings.cpp | 47 ++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 79 insertions(+), 8 deletions(-) diff --git a/README.txt b/README.txt index 2158741..12a8393 100644 --- a/README.txt +++ b/README.txt @@ -638,9 +638,10 @@ would have the same effect. Non-standard parameters ----------------------- -The AppEnvironment and AppEnvironmentExtra parameters recognise an -additional argument when querying the environment. The following syntax -will print all extra environment variables configured for a service +The AppEnvironment, AppEnvironmentExtra and Environment parameters +recognise an additional argument when querying the environment. The +following syntax will print all extra environment variables configured +for a service nssm get AppEnvironmentExtra @@ -655,6 +656,39 @@ KEY=VALUE pair in separate command line arguments. For example: nssm set AppEnvironment CLASSPATH=C:\Classes TEMP=C:\Temp +Alternatively the KEY can be prefixed with a + or - symbol to respectively +add or remove a pair from the block. + +The following two lines set CLASSPATH and TEMP: + + nssm set AppEnvironment CLASSPATH=C:\Classes + nssm set AppEnvironment +TEMP=C:\Temp + +If the key is already present, specifying +KEY will override the value +while preserving the order of keys: + + nssm set AppEnvironment +CLASSPATH=C:\NewClasses + +The following syntax removes a single variable from the block while +leaving any other variables in place. + + nssm set AppEnvironment -TEMP + +Specifying -KEY=VALUE will remove the variable only if the existing +value matches. + +The following syntax would not remove TEMP=C:\Temp + + nssm set AppEnvironment -TEMP=C:\Work\Temporary + +The + and - symbols are valid characters in environment variables. +The syntax :KEY=VALUE is equivalent to KEY=VALUE and can be used to +set variables which start with +/- or to explicitly reset the block in +a script: + + nssm set AppEnvironment :CLASSPATH=C:\Classes + nssm set AppEnvironment +TEMP=C:\Temp + The AppExit parameter requires an additional argument specifying the exit code to get or set. The default action can be specified with the string diff --git a/settings.cpp b/settings.cpp index f50dcc4..3ed5ec4 100644 --- a/settings.cpp +++ b/settings.cpp @@ -339,17 +339,54 @@ static int setting_set_environment(const TCHAR *service_name, void *param, const HKEY key = (HKEY) param; if (! param) return -1; - if (! value || ! value->string || ! value->string[0]) { + TCHAR *string = 0; + TCHAR *unformatted = 0; + unsigned long envlen; + unsigned long newlen = 0; + int op = 0; + if (value && value->string && value->string[0]) { + string = value->string; + switch (string[0]) { + case _T('+'): op = 1; break; + case _T('-'): op = -1; break; + case _T(':'): string++; break; + } + } + + if (op) { + string++; + TCHAR *env = 0; + if (get_environment((TCHAR *) service_name, key, (TCHAR *) name, &env, &envlen)) return -1; + if (env) { + int ret; + if (op > 0) ret = append_to_environment_block(env, envlen, string, &unformatted, &newlen); + else ret = remove_from_environment_block(env, envlen, string, &unformatted, &newlen); + if (envlen) HeapFree(GetProcessHeap(), 0, env); + if (ret) return -1; + + string = unformatted; + } + else { + /* + No existing environment. + We can't remove from an empty environment so just treat an add + operation as setting a new string. + */ + if (op < 0) return 0; + op = 0; + } + } + + if (! string || ! string[0]) { long error = RegDeleteValue(key, name); if (error == ERROR_SUCCESS || error == ERROR_FILE_NOT_FOUND) return 0; print_message(stderr, NSSM_MESSAGE_REGDELETEVALUE_FAILED, name, service_name, error_string(error)); return -1; } - unsigned long envlen = (unsigned long) _tcslen(value->string) + 1; - TCHAR *unformatted = 0; - unsigned long newlen; - if (unformat_double_null(value->string, envlen, &unformatted, &newlen)) return -1; + if (! op) { + if (unformat_double_null(string, (unsigned long) _tcslen(string), &unformatted, &newlen)) return -1; + } if (test_environment(unformatted)) { HeapFree(GetProcessHeap(), 0, unformatted); -- 2.7.4