From: Iain Patterson Date: Wed, 1 Jan 2014 15:14:51 +0000 (+0000) Subject: Allow controlling services. X-Git-Tag: v2.22~91 X-Git-Url: http://git.iain.cx/?p=nssm.git;a=commitdiff_plain;h=9cf66b86846f97f0bd2efdfe2b8bd36ea0b00499 Allow controlling services. Send start/stop/query messages to services is easy so adding the ability to do so is a quick win. --- diff --git a/ChangeLog.txt b/ChangeLog.txt index bdc1aed..cfcbce6 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,6 +1,6 @@ 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. * NSSM can now optionally rotate existing files when diff --git a/README.txt b/README.txt index a7655d9..9a9a11e 100644 --- a/README.txt +++ b/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 type and log on details. -Since version 2.22, NSSM can edit existing services. +Since version 2.22, NSSM can manage existing services. Usage @@ -423,6 +423,17 @@ is in two stages as follows. nssm set Type SERVICE_INTERACTIVE_PROCESS +Controlling services using the command line +------------------------------------------- +NSSM offers rudimentary service control features. + + nssm start + + nssm stop + + nssm status + + Removing services using the GUI ------------------------------- NSSM can also remove services. Run diff --git a/messages.mc b/messages.mc index aaaeb8c..1be1d0a 100644 Binary files a/messages.mc and b/messages.mc differ diff --git a/nssm.cpp b/nssm.cpp index 43faa41..792b62b 100644 --- a/nssm.cpp +++ b/nssm.cpp @@ -79,7 +79,15 @@ int _tmain(int argc, TCHAR **argv) { /* Elevate */ 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 (! is_admin) { print_message(stderr, NSSM_MESSAGE_NOT_ADMINISTRATOR_CANNOT_INSTALL); diff --git a/service.cpp b/service.cpp index 296d416..8440038 100644 --- a/service.cpp +++ b/service.cpp @@ -802,6 +802,86 @@ int edit_service(nssm_service_t *service, bool editing) { 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 */ int remove_service(nssm_service_t *service) { if (! service) return 1; diff --git a/service.h b/service.h index 515b108..29c237e 100644 --- a/service.h +++ b/service.h @@ -108,6 +108,7 @@ int pre_edit_service(int, TCHAR **); int install_service(nssm_service_t *); int remove_service(nssm_service_t *); int edit_service(nssm_service_t *, bool); +int control_service(unsigned long, int, TCHAR **); void set_service_recovery(nssm_service_t *); int monitor_service(nssm_service_t *); int start_service(nssm_service_t *);