Browse Source

Allow controlling services.

Send start/stop/query messages to services is easy so adding the ability
to do so is a quick win.
Iain Patterson 10 years ago
parent
commit
9cf66b8684
6 changed files with 103 additions and 3 deletions
  1. 1 1
      ChangeLog.txt
  2. 12 1
      README.txt
  3. BIN
      messages.mc
  4. 9 1
      nssm.cpp
  5. 80 0
      service.cpp
  6. 1 0
      service.h

+ 1 - 1
ChangeLog.txt

@@ -1,6 +1,6 @@
 Changes since 2.21
 Changes since 2.21
 ------------------
 ------------------
-  * Existing services can now be edited using the GUI
+  * Existing services can now be managed using the GUI
     or on the command line.
     or on the command line.
 
 
   * NSSM can now optionally rotate existing files when
   * NSSM can now optionally rotate existing files when

+ 12 - 1
README.txt

@@ -58,7 +58,7 @@ Since version 2.22, NSSM can rotate existing output files when redirecting I/O.
 Since version 2.22, NSSM can set service display name, description, startup
 Since version 2.22, NSSM can set service display name, description, startup
 type and log on details.
 type and log on details.
 
 
-Since version 2.22, NSSM can edit existing services.
+Since version 2.22, NSSM can manage existing services.
 
 
 
 
 Usage
 Usage
@@ -423,6 +423,17 @@ is in two stages as follows.
     nssm set <servicename> Type SERVICE_INTERACTIVE_PROCESS
     nssm set <servicename> Type SERVICE_INTERACTIVE_PROCESS
 
 
 
 
+Controlling services using the command line
+-------------------------------------------
+NSSM offers rudimentary service control features.
+
+    nssm start <servicename>
+
+    nssm stop <servicename>
+
+    nssm status <servicename>
+
+
 Removing services using the GUI
 Removing services using the GUI
 -------------------------------
 -------------------------------
 NSSM can also remove services.  Run
 NSSM can also remove services.  Run

BIN
messages.mc


+ 9 - 1
nssm.cpp

@@ -79,7 +79,15 @@ int _tmain(int argc, TCHAR **argv) {
 
 
   /* Elevate */
   /* Elevate */
   if (argc > 1) {
   if (argc > 1) {
-    /* Valid commands are install, edit, get, set, reset, unset or remove */
+    /*
+      Valid commands are:
+      start, stop, pause, continue, install, edit, get, set, reset, unset, remove
+    */
+    if (str_equiv(argv[1], _T("start"))) exit(control_service(0, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("stop"))) exit(control_service(SERVICE_CONTROL_STOP, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("pause"))) exit(control_service(SERVICE_CONTROL_PAUSE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("continue"))) exit(control_service(SERVICE_CONTROL_CONTINUE, argc - 2, argv + 2));
+    if (str_equiv(argv[1], _T("status"))) exit(control_service(SERVICE_CONTROL_INTERROGATE, argc - 2, argv + 2));
     if (str_equiv(argv[1], _T("install"))) {
     if (str_equiv(argv[1], _T("install"))) {
       if (! is_admin) {
       if (! is_admin) {
         print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);
         print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL);

+ 80 - 0
service.cpp

@@ -802,6 +802,86 @@ int edit_service(nssm_service_t *service, bool editing) {
   return 0;
   return 0;
 }
 }
 
 
+/* Control a service. */
+int control_service(unsigned long control, int argc, TCHAR **argv) {
+  if (argc < 1) return usage(1);
+  TCHAR *service_name = argv[0];
+
+  SC_HANDLE services = open_service_manager();
+  if (! services) {
+    print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED);
+    return 2;
+  }
+
+  SC_HANDLE service_handle = OpenService(services, service_name, SC_MANAGER_ALL_ACCESS);
+  if (! service_handle) {
+    print_message(stderr, NSSM_MESSAGE_OPENSERVICE_FAILED);
+    CloseServiceHandle(services);
+    return 3;
+  }
+
+  int ret;
+  unsigned long error;
+  SERVICE_STATUS service_status;
+  if (control == 0) {
+    ret = StartService(service_handle, (unsigned long) argc, (const TCHAR **) argv);
+    error = GetLastError();
+    CloseHandle(service_handle);
+    CloseServiceHandle(services);
+
+    if (ret) {
+      _tprintf(_T("%s: %s"), canonical_name, error_string(error));
+      return 0;
+    }
+    else {
+      _ftprintf(stderr, _T("%s: %s"), canonical_name, error_string(error));
+      return 1;
+    }
+  }
+  else if (control == SERVICE_CONTROL_INTERROGATE) {
+    /*
+      We could actually send an INTERROGATE control but that won't return
+      any information if the service is stopped and we don't care about
+      the extra details it might give us in any case.  So we'll fake it.
+    */
+    ret = QueryServiceStatus(service_handle, &service_status);
+    error = GetLastError();
+
+    if (ret) {
+      switch (service_status.dwCurrentState) {
+        case SERVICE_STOPPED: _tprintf(_T("SERVICE_STOPPED\n")); break;
+        case SERVICE_START_PENDING: _tprintf(_T("SERVICE_START_PENDING\n")); break;
+        case SERVICE_STOP_PENDING: _tprintf(_T("SERVICE_STOP_PENDING\n")); break;
+        case SERVICE_RUNNING: _tprintf(_T("SERVICE_RUNNING\n")); break;
+        case SERVICE_CONTINUE_PENDING: _tprintf(_T("SERVICE_CONTINUE_PENDING\n")); break;
+        case SERVICE_PAUSE_PENDING: _tprintf(_T("SERVICE_PAUSE_PENDING\n")); break;
+        case SERVICE_PAUSED: _tprintf(_T("SERVICE_PAUSED\n")); break;
+        default: _tprintf(_T("?\n")); return 1;
+      }
+      return 0;
+    }
+    else {
+      _ftprintf(stderr, _T("%s: %s\n"), service_name, error_string(error));
+      return 1;
+    }
+  }
+  else {
+    ret = ControlService(service_handle, control, &service_status);
+    error = GetLastError();
+    CloseHandle(service_handle);
+    CloseServiceHandle(services);
+
+    if (ret) {
+      _tprintf(_T("%s: %s"), canonical_name, error_string(error));
+      return 0;
+    }
+    else {
+      _ftprintf(stderr, _T("%s: %s"), canonical_name, error_string(error));
+      return 1;
+    }
+  }
+}
+
 /* Remove the service */
 /* Remove the service */
 int remove_service(nssm_service_t *service) {
 int remove_service(nssm_service_t *service) {
   if (! service) return 1;
   if (! service) return 1;

+ 1 - 0
service.h

@@ -108,6 +108,7 @@ int pre_edit_service(int, TCHAR **);
 int install_service(nssm_service_t *);
 int install_service(nssm_service_t *);
 int remove_service(nssm_service_t *);
 int remove_service(nssm_service_t *);
 int edit_service(nssm_service_t *, bool);
 int edit_service(nssm_service_t *, bool);
+int control_service(unsigned long, int, TCHAR **);
 void set_service_recovery(nssm_service_t *);
 void set_service_recovery(nssm_service_t *);
 int monitor_service(nssm_service_t *);
 int monitor_service(nssm_service_t *);
 int start_service(nssm_service_t *);
 int start_service(nssm_service_t *);