Allow adding or removing individual dependencies.
authorIain Patterson <me@iain.cx>
Sat, 23 Jul 2016 11:29:35 +0000 (12:29 +0100)
committerIain Patterson <me@iain.cx>
Thu, 28 Jul 2016 15:44:26 +0000 (16:44 +0100)
Specifying a DependOnService or DependOnGroup argument as +<dependency>
will add the dependency to the list.  Specifying it as -<dependency>
will remove it from the list.  The dependency may also be given as
:<dependency> to make scripting more legible.

Groups should technically be prefixed with a + symbol.  NSSM will follow
the rules above even when the + prefix is used.

README.txt
settings.cpp

index 12a8393..6f9004e 100644 (file)
@@ -729,6 +729,34 @@ separate command line arguments.  For example:
 \r
     nssm set <servicename> DependOnService RpcSs LanmanWorkstation\r
 \r
+Alternatively the dependency name can be prefixed with a + or - symbol to\r
+respectively add or remove a dependency.\r
+\r
+The following two lines set dependencies on RpcSs and LanmanWorkstation:\r
+\r
+    nssm set <servicename> DependOnService RpcSs\r
+    nssm set <servicename> DependOnService +LanmanWorkstation\r
+\r
+The follwing syntax removes the dependency on RpcSs:\r
+\r
+    nssm set <servicename> DependOnService -RpcSs\r
+\r
+Service groups should, strictly speaking, be prefixed with the + symbol.\r
+To specify a single dependency on a group, the + symbol can be prefixed\r
+with the : symbol.\r
+\r
+The following lines are equivalent, and each set a dependency ONLY on\r
+NetBIOSGroup:\r
+\r
+    nssm set <servicename> DependOnGroup NetBIOSGroup\r
+    nssm set <servicename> DependOnGroup :NetBIOSGroup\r
+    nssm set <servicename> DependOnGroup :+NetBIOSGroup\r
+\r
+Whereas these lines add to any existing dependencies:\r
+\r
+    nssm set <servicename> DependOnGroup +NetBIOSGroup\r
+    nssm set <servicename> DependOnGroup ++NetBIOSGroup\r
+\r
 \r
 The Name parameter can only be queried, not set.  It returns the service's\r
 registry key name.  This may be useful to know if you take advantage of\r
index 3ed5ec4..d978909 100644 (file)
@@ -499,6 +499,92 @@ static int setting_get_priority(const TCHAR *service_name, void *param, const TC
 }\r
 \r
 /* Functions to manage native service settings. */\r
+static int native_set_dependon(const TCHAR *service_name, SC_HANDLE service_handle, TCHAR **dependencies, unsigned long *dependencieslen, value_t *value, int type) {\r
+  *dependencieslen = 0;\r
+  if (! value || ! value->string || ! value->string[0]) return 0;\r
+\r
+  TCHAR *string = value->string;\r
+  unsigned long buflen;\r
+  int op = 0;\r
+  switch (string[0]) {\r
+    case _T('+'): op = 1; break;\r
+    case _T('-'): op = -1; break;\r
+    case _T(':'): string++; break;\r
+  }\r
+\r
+  if (op) {\r
+    string++;\r
+    TCHAR *buffer = 0;\r
+    if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, type)) return -1;\r
+    if (buffer) {\r
+      int ret;\r
+      if (op > 0) ret = append_to_dependencies(buffer, buflen, string, dependencies, dependencieslen, type);\r
+      else ret = remove_from_dependencies(buffer, buflen, string, dependencies, dependencieslen, type);\r
+      if (buflen) HeapFree(GetProcessHeap(), 0, buffer);\r
+      return ret;\r
+    }\r
+    else {\r
+      /*\r
+        No existing list.\r
+        We can't remove from an empty list so just treat an add\r
+        operation as setting a new string.\r
+      */\r
+      if (op < 0) return 0;\r
+      op = 0;\r
+    }\r
+  }\r
+\r
+  if (! op) {\r
+    TCHAR *unformatted = 0;\r
+    unsigned long newlen;\r
+    if (unformat_double_null(string, (unsigned long) _tcslen(string), &unformatted, &newlen)) return -1;\r
+\r
+    if (type == DEPENDENCY_GROUPS) {\r
+      /* Prepend group identifier. */\r
+      unsigned long missing = 0;\r
+      TCHAR *canon = unformatted;\r
+      size_t canonlen = 0;\r
+      TCHAR *s;\r
+      for (s = unformatted; *s; s++) {\r
+        if (*s != SC_GROUP_IDENTIFIER) missing++;\r
+        size_t len = _tcslen(s);\r
+        canonlen += len + 1;\r
+        s += len;\r
+      }\r
+\r
+      if (missing) {\r
+        /* Missing identifiers plus double NULL terminator. */\r
+        canonlen += missing + 1;\r
+\r
+        canon = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, canonlen * sizeof(TCHAR));\r
+        if (! canon) {\r
+          print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("native_set_dependon"));\r
+          if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
+          return -1;\r
+        }\r
+\r
+        size_t i = 0;\r
+        for (s = unformatted; *s; s++) {\r
+          if (*s != SC_GROUP_IDENTIFIER) canon[i++] = SC_GROUP_IDENTIFIER;\r
+          size_t len = _tcslen(s);\r
+          memmove(canon + i, s, (len + 1) * sizeof(TCHAR));\r
+          i += len + 1;\r
+          s += len;\r
+        }\r
+\r
+        HeapFree(GetProcessHeap(), 0, unformatted);\r
+        unformatted = canon;\r
+        newlen = (unsigned long) canonlen;\r
+      }\r
+    }\r
+\r
+    *dependencies = unformatted;\r
+    *dependencieslen = newlen;\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
 static int native_set_dependongroup(const TCHAR *service_name, void *param, const TCHAR *name, void *default_value, value_t *value, const TCHAR *additional) {\r
   SC_HANDLE service_handle = (SC_HANDLE) param;\r
   if (! service_handle) return -1;\r
@@ -506,86 +592,46 @@ static int native_set_dependongroup(const TCHAR *service_name, void *param, cons
   /*\r
     Get existing service dependencies because we must set both types together.\r
   */\r
-  TCHAR *buffer;\r
-  unsigned long buflen;\r
-  if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_SERVICES)) return -1;\r
+  TCHAR *services_buffer;\r
+  unsigned long services_buflen;\r
+  if (get_service_dependencies(service_name, service_handle, &services_buffer, &services_buflen, DEPENDENCY_SERVICES)) return -1;\r
 \r
   if (! value || ! value->string || ! value->string[0]) {\r
-    if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, buffer, 0, 0, 0)) {\r
+    if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, services_buffer, 0, 0, 0)) {\r
       print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));\r
-      if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+      if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
       return -1;\r
     }\r
 \r
-    if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+    if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
     return 0;\r
   }\r
 \r
-  unsigned long len = (unsigned long) _tcslen(value->string) + 1;\r
-  TCHAR *unformatted = 0;\r
-  unsigned long newlen;\r
-  if (unformat_double_null(value->string, len, &unformatted, &newlen)) {\r
-    if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
-    return -1;\r
-  }\r
-\r
-  /* Prepend group identifier. */\r
-  unsigned long missing = 0;\r
-  TCHAR *canon = unformatted;\r
-  size_t canonlen = 0;\r
-  TCHAR *s;\r
-  for (s = unformatted; *s; s++) {\r
-    if (*s != SC_GROUP_IDENTIFIER) missing++;\r
-    size_t len = _tcslen(s);\r
-    canonlen += len + 1;\r
-    s += len;\r
-  }\r
-\r
-  if (missing) {\r
-    /* Missing identifiers plus double NULL terminator. */\r
-    canonlen += missing + 1;\r
-    newlen = (unsigned long) canonlen;\r
-\r
-    canon = (TCHAR *) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, canonlen * sizeof(TCHAR));\r
-    if (! canon) {\r
-      print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("canon"), _T("native_set_dependongroup"));\r
-      if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
-      if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
-      return -1;\r
-    }\r
-\r
-    size_t i = 0;\r
-    for (s = unformatted; *s; s++) {\r
-      if (*s != SC_GROUP_IDENTIFIER) canon[i++] = SC_GROUP_IDENTIFIER;\r
-      size_t len = _tcslen(s);\r
-      memmove(canon + i, s, (len + 1) * sizeof(TCHAR));\r
-      i += len + 1;\r
-      s += len;\r
-    }\r
-  }\r
+  /* Update the group list. */\r
+  TCHAR *groups_buffer;\r
+  unsigned long groups_buflen;\r
+  if (native_set_dependon(service_name, service_handle, &groups_buffer, &groups_buflen, value, DEPENDENCY_GROUPS)) return -1;\r
 \r
   TCHAR *dependencies;\r
-  if (buflen > 2) {\r
-    dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (newlen + buflen) * sizeof(TCHAR));\r
+  if (services_buflen > 2) {\r
+    dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (groups_buflen + services_buflen) * sizeof(TCHAR));\r
     if (! dependencies) {\r
       print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("dependencies"), _T("native_set_dependongroup"));\r
-      if (canon != unformatted) HeapFree(GetProcessHeap(), 0, canon);\r
-      if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
-      if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+      if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
+      if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
       return -1;\r
     }\r
 \r
-    memmove(dependencies, buffer, buflen * sizeof(TCHAR));\r
-    memmove(dependencies + buflen - 1, canon, newlen * sizeof(TCHAR));\r
+    memmove(dependencies, services_buffer, services_buflen * sizeof(TCHAR));\r
+    memmove(dependencies + services_buflen - 1, groups_buffer, groups_buflen * sizeof(TCHAR));\r
   }\r
-  else dependencies = canon;\r
+  else dependencies = groups_buffer;\r
 \r
   int ret = 1;\r
   if (set_service_dependencies(service_name, service_handle, dependencies)) ret = -1;\r
-  if (dependencies != unformatted) HeapFree(GetProcessHeap(), 0, dependencies);\r
-  if (canon != unformatted) HeapFree(GetProcessHeap(), 0, canon);\r
-  if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
-  if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+  if (dependencies != groups_buffer) HeapFree(GetProcessHeap(), 0, dependencies);\r
+  if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
+  if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
 \r
   return ret;\r
 }\r
@@ -626,49 +672,46 @@ static int native_set_dependonservice(const TCHAR *service_name, void *param, co
   /*\r
     Get existing group dependencies because we must set both types together.\r
   */\r
-  TCHAR *buffer;\r
-  unsigned long buflen;\r
-  if (get_service_dependencies(service_name, service_handle, &buffer, &buflen, DEPENDENCY_GROUPS)) return -1;\r
+  TCHAR *groups_buffer;\r
+  unsigned long groups_buflen;\r
+  if (get_service_dependencies(service_name, service_handle, &groups_buffer, &groups_buflen, DEPENDENCY_GROUPS)) return -1;\r
 \r
   if (! value || ! value->string || ! value->string[0]) {\r
-    if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, buffer, 0, 0, 0)) {\r
+    if (! ChangeServiceConfig(service_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, 0, 0, 0, groups_buffer, 0, 0, 0)) {\r
       print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError()));\r
-      if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+      if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
       return -1;\r
     }\r
 \r
-    if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+    if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
     return 0;\r
   }\r
 \r
-  unsigned long len = (unsigned long) _tcslen(value->string) + 1;\r
-  TCHAR *unformatted = 0;\r
-  unsigned long newlen;\r
-  if (unformat_double_null(value->string, len, &unformatted, &newlen)) {\r
-    if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
-    return -1;\r
-  }\r
+  /* Update the service list. */\r
+  TCHAR *services_buffer;\r
+  unsigned long services_buflen;\r
+  if (native_set_dependon(service_name, service_handle, &services_buffer, &services_buflen, value, DEPENDENCY_SERVICES)) return -1;\r
 \r
   TCHAR *dependencies;\r
-  if (buflen > 2) {\r
-    dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (newlen + buflen) * sizeof(TCHAR));\r
+  if (groups_buflen > 2) {\r
+    dependencies = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, (services_buflen + groups_buflen) * sizeof(TCHAR));\r
     if (! dependencies) {\r
       print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("dependencies"), _T("native_set_dependonservice"));\r
-      if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
-      if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+      if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
+      if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
       return -1;\r
     }\r
 \r
-    memmove(dependencies, buffer, buflen * sizeof(TCHAR));\r
-    memmove(dependencies + buflen - 1, unformatted, newlen * sizeof(TCHAR));\r
+    memmove(dependencies, services_buffer, services_buflen * sizeof(TCHAR));\r
+    memmove(dependencies + services_buflen - 1, groups_buffer, groups_buflen * sizeof(TCHAR));\r
   }\r
-  else dependencies = unformatted;\r
+  else dependencies = services_buffer;\r
 \r
   int ret = 1;\r
   if (set_service_dependencies(service_name, service_handle, dependencies)) ret = -1;\r
-  if (dependencies != unformatted) HeapFree(GetProcessHeap(), 0, dependencies);\r
-  if (unformatted) HeapFree(GetProcessHeap(), 0, unformatted);\r
-  if (buffer) HeapFree(GetProcessHeap(), 0, buffer);\r
+  if (dependencies != services_buffer) HeapFree(GetProcessHeap(), 0, dependencies);\r
+  if (groups_buffer) HeapFree(GetProcessHeap(), 0, groups_buffer);\r
+  if (services_buffer) HeapFree(GetProcessHeap(), 0, services_buffer);\r
 \r
   return ret;\r
 }\r