X-Git-Url: http://git.iain.cx/?a=blobdiff_plain;f=service.cpp;h=406196b41a16c6590b7558fb5d2fa6a4412db660;hb=f13f3f81d7ad3ccda728d06f615ce5f724023f4e;hp=8d1c0fea5d4a94df97d088d1c91eb7a20926230f;hpb=620fc9f56975c9319a1b0e0be556e264ad1d485d;p=nssm.git diff --git a/service.cpp b/service.cpp index 8d1c0fe..406196b 100644 --- a/service.cpp +++ b/service.cpp @@ -689,6 +689,7 @@ void set_nssm_service_defaults(nssm_service_t *service) { service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD; service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD; service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD; + service->kill_process_tree = 1; } /* Allocate and zero memory for a service. */ @@ -709,9 +710,9 @@ void cleanup_nssm_service(nssm_service_t *service) { if (service->dependencies) HeapFree(GetProcessHeap(), 0, service->dependencies); if (service->env) HeapFree(GetProcessHeap(), 0, service->env); if (service->env_extra) HeapFree(GetProcessHeap(), 0, service->env_extra); - if (service->handle) CloseHandle(service->handle); + if (service->handle) CloseServiceHandle(service->handle); if (service->process_handle) CloseHandle(service->process_handle); - if (service->wait_handle) UnregisterWait(service->process_handle); + if (service->wait_handle) UnregisterWait(service->wait_handle); if (service->throttle_section_initialised) DeleteCriticalSection(&service->throttle_section); if (service->throttle_timer) CloseHandle(service->throttle_timer); if (service->initial_env) FreeEnvironmentStrings(service->initial_env); @@ -856,7 +857,7 @@ int pre_edit_service(int argc, TCHAR **argv) { /* Get system details. */ QUERY_SERVICE_CONFIG *qsc = query_service_config(service->name, service->handle); if (! qsc) { - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); return 4; } @@ -865,7 +866,7 @@ int pre_edit_service(int argc, TCHAR **argv) { if (! (service->type & SERVICE_WIN32_OWN_PROCESS)) { if (mode != MODE_GETTING) { HeapFree(GetProcessHeap(), 0, qsc); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); print_message(stderr, NSSM_MESSAGE_CANNOT_EDIT, service->name, NSSM_WIN32_OWN_PROCESS, 0); return 3; @@ -875,7 +876,7 @@ int pre_edit_service(int argc, TCHAR **argv) { if (get_service_startup(service->name, service->handle, qsc, &service->startup)) { if (mode != MODE_GETTING) { HeapFree(GetProcessHeap(), 0, qsc); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); return 4; } @@ -884,7 +885,7 @@ int pre_edit_service(int argc, TCHAR **argv) { if (get_service_username(service->name, qsc, &service->username, &service->usernamelen)) { if (mode != MODE_GETTING) { HeapFree(GetProcessHeap(), 0, qsc); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); return 5; } @@ -903,7 +904,7 @@ int pre_edit_service(int argc, TCHAR **argv) { /* Get extended system details. */ if (get_service_description(service->name, service->handle, _countof(service->description), service->description)) { if (mode != MODE_GETTING) { - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); return 6; } @@ -911,7 +912,7 @@ int pre_edit_service(int argc, TCHAR **argv) { if (get_service_dependencies(service->name, service->handle, &service->dependencies, &service->dependencieslen)) { if (mode != MODE_GETTING) { - CloseHandle(service->handle); + CloseServiceHandle(service->handle); CloseServiceHandle(services); return 7; } @@ -935,7 +936,7 @@ int pre_edit_service(int argc, TCHAR **argv) { /* Trying to manage App* parameters for a non-NSSM service. */ if (! setting->native && service->native) { - CloseHandle(service->handle); + CloseServiceHandle(service->handle); print_message(stderr, NSSM_MESSAGE_NATIVE_PARAMETER, setting->name, NSSM); return 1; } @@ -953,7 +954,7 @@ int pre_edit_service(int argc, TCHAR **argv) { if (setting->native) ret = get_setting(service->name, service->handle, setting, &value, additional); else ret = get_setting(service->name, key, setting, &value, additional); if (ret < 0) { - CloseHandle(service->handle); + CloseServiceHandle(service->handle); return 5; } @@ -971,7 +972,7 @@ int pre_edit_service(int argc, TCHAR **argv) { } if (! service->native) RegCloseKey(key); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); return 0; } @@ -993,7 +994,7 @@ int pre_edit_service(int argc, TCHAR **argv) { value.string = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR)); if (! value.string) { print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("value"), _T("edit_service()")); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); return 2; } @@ -1026,12 +1027,12 @@ int pre_edit_service(int argc, TCHAR **argv) { if (value.string) HeapFree(GetProcessHeap(), 0, value.string); if (ret < 0) { if (! service->native) RegCloseKey(key); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); return 6; } if (! service->native) RegCloseKey(key); - CloseHandle(service->handle); + CloseServiceHandle(service->handle); return 0; } @@ -1119,17 +1120,19 @@ int edit_service(nssm_service_t *service, bool editing) { Empty passwords are valid but we won't allow them in the GUI. */ TCHAR *username = 0; + TCHAR *canon = 0; TCHAR *password = 0; if (service->usernamelen) { username = service->username; + if (canonicalise_username(username, &canon)) return 5; if (service->passwordlen) password = service->password; - else password = _T(""); } - else if (editing) username = NSSM_LOCALSYSTEM_ACCOUNT; + else if (editing) username = canon = NSSM_LOCALSYSTEM_ACCOUNT; - if (well_known_username(username)) password = _T(""); + if (well_known_username(canon)) password = _T(""); else { - if (grant_logon_as_service(username)) { + if (grant_logon_as_service(canon)) { + if (canon != username) HeapFree(GetProcessHeap(), 0, canon); print_message(stderr, NSSM_MESSAGE_GRANT_LOGON_AS_SERVICE_FAILED, username); return 5; } @@ -1138,10 +1141,12 @@ int edit_service(nssm_service_t *service, bool editing) { TCHAR *dependencies = _T(""); if (service->dependencieslen) dependencies = 0; /* Change later. */ - if (! ChangeServiceConfig(service->handle, service->type, startup, SERVICE_NO_CHANGE, 0, 0, 0, dependencies, username, password, service->displayname)) { + if (! ChangeServiceConfig(service->handle, service->type, startup, SERVICE_NO_CHANGE, 0, 0, 0, dependencies, canon, password, service->displayname)) { + if (canon != username) HeapFree(GetProcessHeap(), 0, canon); print_message(stderr, NSSM_MESSAGE_CHANGESERVICECONFIG_FAILED, error_string(GetLastError())); return 5; } + if (canon != username) HeapFree(GetProcessHeap(), 0, canon); if (service->dependencieslen) { if (set_service_dependencies(service->name, service->handle, service->dependencies)) return 5; @@ -1237,7 +1242,7 @@ 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); - CloseHandle(service_handle); + 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)); @@ -1247,7 +1252,7 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { return 0; } else { - CloseHandle(service_handle); + CloseServiceHandle(service_handle); _ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error)); return 1; } @@ -1283,7 +1288,7 @@ 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); - CloseHandle(service_handle); + 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)); @@ -1293,7 +1298,7 @@ int control_service(unsigned long control, int argc, TCHAR **argv) { return 0; } else { - CloseHandle(service_handle); + 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; @@ -1358,7 +1363,7 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) { /* Initialise status */ ZeroMemory(&service->status, sizeof(service->status)); service->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS; - service->status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; + service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; service->status.dwWin32ExitCode = NO_ERROR; service->status.dwServiceSpecificExitCode = 0; service->status.dwCheckPoint = 0; @@ -1389,6 +1394,7 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) { if (services) { service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0); set_service_recovery(service); + CloseServiceHandle(services); } } @@ -1456,6 +1462,7 @@ TCHAR *service_control_text(unsigned long control) { case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE"); case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE"); case NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE"); + case SERVICE_CONTROL_POWEREVENT: return _T("POWEREVENT"); default: return 0; } } @@ -1563,6 +1570,15 @@ unsigned long WINAPI service_control_handler(unsigned long control, unsigned lon if (service->rotate_stdout_online == NSSM_ROTATE_ONLINE) service->rotate_stdout_online = NSSM_ROTATE_ONLINE_ASAP; if (service->rotate_stderr_online == NSSM_ROTATE_ONLINE) service->rotate_stderr_online = NSSM_ROTATE_ONLINE_ASAP; return NO_ERROR; + + case SERVICE_CONTROL_POWEREVENT: + if (event != PBT_APMRESUMEAUTOMATIC) { + log_service_control(service->name, control, false); + return NO_ERROR; + } + log_service_control(service->name, control, true); + end_service((void *) service, false); + return NO_ERROR; } /* Unknown control */ @@ -1672,16 +1688,7 @@ int start_service(nssm_service_t *service) { but be mindful of the fact that we are blocking the service control manager so abandon the wait before too much time has elapsed. */ - unsigned long delay = service->throttle_delay; - if (delay > NSSM_SERVICE_STATUS_DEADLINE) { - TCHAR delay_milliseconds[16]; - _sntprintf_s(delay_milliseconds, _countof(delay_milliseconds), _TRUNCATE, _T("%lu"), delay); - TCHAR deadline_milliseconds[16]; - _sntprintf_s(deadline_milliseconds, _countof(deadline_milliseconds), _TRUNCATE, _T("%lu"), NSSM_SERVICE_STATUS_DEADLINE); - log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_STARTUP_DELAY_TOO_LONG, service->name, delay_milliseconds, NSSM, deadline_milliseconds, 0); - delay = NSSM_SERVICE_STATUS_DEADLINE; - } - unsigned long deadline = WaitForSingleObject(service->process_handle, delay); + if (await_service_status_change(service, SERVICE_START_PENDING, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0; /* Signal successful start */ service->status.dwCurrentState = SERVICE_RUNNING; @@ -1786,7 +1793,7 @@ void CALLBACK end_service(void *arg, unsigned char why) { /* Clean up. */ if (exitcode == STILL_ACTIVE) exitcode = 0; - if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid); + if (service->pid && service->kill_process_tree) kill_process_tree(service, service->pid, exitcode, service->pid); service->pid = 0; /* @@ -1912,7 +1919,7 @@ void throttle_restart(nssm_service_t *service) { 0 if the wait completed. -1 on error. */ -int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long timeout) { +int await_service_status_change(nssm_service_t *service, unsigned long status, unsigned long desired, TCHAR *function_name, unsigned long timeout) { unsigned long interval; unsigned long waithint; unsigned long ret; @@ -1937,7 +1944,7 @@ int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long interval = timeout - waited; if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE; - service->status.dwCurrentState = SERVICE_STOP_PENDING; + service->status.dwCurrentState = control; service->status.dwWaitHint += interval; service->status.dwCheckPoint++; SetServiceStatus(service->status_handle, &service->status); @@ -1945,7 +1952,7 @@ int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long if (waited) { _sntprintf_s(waited_milliseconds, _countof(waited_milliseconds), _TRUNCATE, _T("%lu"), waited); _sntprintf_s(interval_milliseconds, _countof(interval_milliseconds), _TRUNCATE, _T("%lu"), interval); - log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SHUTDOWN, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0); + log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SERVICE, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, service_status_text(status), 0); } switch (WaitForSingleObject(service->process_handle, interval)) { @@ -1955,7 +1962,7 @@ int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long case WAIT_TIMEOUT: ret = 1; - break; + break; default: ret = -1;