X-Git-Url: http://git.iain.cx/?a=blobdiff_plain;f=service.cpp;h=dbac12b9b3580094c8b3588107e5307672cde0fb;hb=62f28c55d444d846579159133dbe091809a2c08b;hp=c9f47000515e4a4a65ce63b2e2ce47a9bca81600;hpb=71764fe41e37f36bcbc89ac62f664aeda4240790;p=nssm.git diff --git a/service.cpp b/service.cpp index c9f4700..dbac12b 100644 --- a/service.cpp +++ b/service.cpp @@ -83,10 +83,11 @@ static inline int service_control_response(unsigned long control, unsigned long return 0; } -static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status) { +static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status, unsigned long cutoff) { int tries = 0; unsigned long checkpoint = 0; unsigned long waithint = 0; + unsigned long waited = 0; while (QueryServiceStatus(service_handle, service_status)) { int response = service_control_response(control, service_status->dwCurrentState); /* Alas we can't WaitForSingleObject() on an SC_HANDLE. */ @@ -96,13 +97,22 @@ static inline int await_service_control_response(unsigned long control, SC_HANDL checkpoint = service_status->dwCheckPoint; waithint = service_status->dwWaitHint; if (++tries > 10) tries = 10; - Sleep(50 * tries); + unsigned long wait = 50 * tries; + if (cutoff) { + if (waited > cutoff) return response; + waited += wait; + } + Sleep(wait); } else return response; } return -1; } +static inline int await_service_control_response(unsigned long control, SC_HANDLE service_handle, SERVICE_STATUS *service_status, unsigned long initial_status) { + return await_service_control_response(control, service_handle, service_status, initial_status, 0); +} + static inline void wait_for_hooks(nssm_service_t *service, bool notify) { SERVICE_STATUS_HANDLE status_handle; SERVICE_STATUS *status; @@ -1350,7 +1360,7 @@ int edit_service(nssm_service_t *service, bool editing) { } /* Control a service. */ -int control_service(unsigned long control, int argc, TCHAR **argv) { +int control_service(unsigned long control, int argc, TCHAR **argv, bool return_status) { if (argc < 1) return usage(1); TCHAR *service_name = argv[0]; TCHAR canonical_name[SERVICE_NAME_LENGTH]; @@ -1358,6 +1368,7 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { SC_HANDLE services = open_service_manager(SC_MANAGER_CONNECT | SC_MANAGER_ENUMERATE_SERVICE); if (! services) { print_message(stderr, NSSM_MESSAGE_OPEN_SERVICE_MANAGER_FAILED); + if (return_status) return 0; return 2; } @@ -1384,6 +1395,7 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { SC_HANDLE service_handle = open_service(services, service_name, access, canonical_name, _countof(canonical_name)); if (! service_handle) { CloseServiceHandle(services); + if (return_status) return 0; return 3; } @@ -1407,11 +1419,21 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { } if (ret) { - int response = await_service_control_response(control, service_handle, &service_status, initial_status); + unsigned long cutoff = 0; + + /* If we manage the service, respect the throttle time. */ + HKEY key = open_registry(service_name, 0, KEY_READ, false); + if (key) { + if (get_number(key, NSSM_REG_THROTTLE, &cutoff, false) != 1) cutoff = NSSM_RESET_THROTTLE_RESTART; + RegCloseKey(key); + } + + int response = await_service_control_response(control, service_handle, &service_status, initial_status, cutoff); CloseServiceHandle(service_handle); if (response) { print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control)); + if (return_status) return 0; return 1; } else _tprintf(_T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error)); @@ -1420,6 +1442,7 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { else { CloseServiceHandle(service_handle); _ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error)); + if (return_status) return 0; return 1; } } @@ -1434,10 +1457,12 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { if (ret) { _tprintf(_T("%s\n"), service_status_text(service_status.dwCurrentState)); + if (return_status) return service_status.dwCurrentState; return 0; } else { _ftprintf(stderr, _T("%s: %s\n"), canonical_name, error_string(error)); + if (return_status) return 0; return 1; } } @@ -1458,22 +1483,32 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { if (response) { print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control)); + if (return_status) return 0; return 1; } else _tprintf(_T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error)); + if (return_status) return service_status.dwCurrentState; return 0; } else { CloseServiceHandle(service_handle); _ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error)); if (error == ERROR_SERVICE_NOT_ACTIVE) { - if (control == SERVICE_CONTROL_SHUTDOWN || control == SERVICE_CONTROL_STOP) return 0; + if (control == SERVICE_CONTROL_SHUTDOWN || control == SERVICE_CONTROL_STOP) { + if (return_status) return SERVICE_STOPPED; + return 0; + } } + if (return_status) return 0; return 1; } } } +int control_service(unsigned long control, int argc, TCHAR **argv) { + return control_service(control, argc, argv, false); +} + /* Remove the service */ int remove_service(nssm_service_t *service) { if (! service) return 1; @@ -2041,6 +2076,9 @@ void CALLBACK end_service(void *arg, unsigned char why) { service->exit_count++; (void) nssm_hook(&hook_threads, service, NSSM_HOOK_EVENT_EXIT, NSSM_HOOK_ACTION_POST, NULL, NSSM_HOOK_DEADLINE, true); + /* Exit logging threads. */ + cleanup_loggers(service); + /* The why argument is true if our wait timed out or false otherwise. Our wait is infinite so why will never be true when called by the system. @@ -2091,7 +2129,6 @@ void CALLBACK end_service(void *arg, unsigned char why) { log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_EXIT_UNCLEAN, service->name, code, exit_action_strings[action], 0); stop_service(service, exitcode, false, default_action); wait_for_hooks(service, false); - free_imports(); nssm_exit(exitcode); } }