service->kill_console_delay = NSSM_KILL_CONSOLE_GRACE_PERIOD;\r
service->kill_window_delay = NSSM_KILL_WINDOW_GRACE_PERIOD;\r
service->kill_threads_delay = NSSM_KILL_THREADS_GRACE_PERIOD;\r
+ service->kill_process_tree = 1;\r
}\r
\r
/* Allocate and zero memory for a service. */\r
if (service->dependencies) HeapFree(GetProcessHeap(), 0, service->dependencies);\r
if (service->env) HeapFree(GetProcessHeap(), 0, service->env);\r
if (service->env_extra) HeapFree(GetProcessHeap(), 0, service->env_extra);\r
- if (service->handle) CloseHandle(service->handle);\r
+ if (service->handle) CloseServiceHandle(service->handle);\r
if (service->process_handle) CloseHandle(service->process_handle);\r
if (service->wait_handle) UnregisterWait(service->wait_handle);\r
if (service->throttle_section_initialised) DeleteCriticalSection(&service->throttle_section);\r
/* Get system details. */\r
QUERY_SERVICE_CONFIG *qsc = query_service_config(service->name, service->handle);\r
if (! qsc) {\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
return 4;\r
}\r
if (! (service->type & SERVICE_WIN32_OWN_PROCESS)) {\r
if (mode != MODE_GETTING) {\r
HeapFree(GetProcessHeap(), 0, qsc);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
print_message(stderr, NSSM_MESSAGE_CANNOT_EDIT, service->name, NSSM_WIN32_OWN_PROCESS, 0);\r
return 3;\r
if (get_service_startup(service->name, service->handle, qsc, &service->startup)) {\r
if (mode != MODE_GETTING) {\r
HeapFree(GetProcessHeap(), 0, qsc);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
return 4;\r
}\r
if (get_service_username(service->name, qsc, &service->username, &service->usernamelen)) {\r
if (mode != MODE_GETTING) {\r
HeapFree(GetProcessHeap(), 0, qsc);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
return 5;\r
}\r
/* Get extended system details. */\r
if (get_service_description(service->name, service->handle, _countof(service->description), service->description)) {\r
if (mode != MODE_GETTING) {\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
return 6;\r
}\r
\r
if (get_service_dependencies(service->name, service->handle, &service->dependencies, &service->dependencieslen)) {\r
if (mode != MODE_GETTING) {\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
CloseServiceHandle(services);\r
return 7;\r
}\r
\r
/* Trying to manage App* parameters for a non-NSSM service. */\r
if (! setting->native && service->native) {\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
print_message(stderr, NSSM_MESSAGE_NATIVE_PARAMETER, setting->name, NSSM);\r
return 1;\r
}\r
if (setting->native) ret = get_setting(service->name, service->handle, setting, &value, additional);\r
else ret = get_setting(service->name, key, setting, &value, additional);\r
if (ret < 0) {\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
return 5;\r
}\r
\r
}\r
\r
if (! service->native) RegCloseKey(key);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
return 0;\r
}\r
\r
value.string = (TCHAR *) HeapAlloc(GetProcessHeap(), 0, len * sizeof(TCHAR));\r
if (! value.string) {\r
print_message(stderr, NSSM_MESSAGE_OUT_OF_MEMORY, _T("value"), _T("edit_service()"));\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
return 2;\r
}\r
\r
if (value.string) HeapFree(GetProcessHeap(), 0, value.string);\r
if (ret < 0) {\r
if (! service->native) RegCloseKey(key);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
return 6;\r
}\r
\r
if (! service->native) RegCloseKey(key);\r
- CloseHandle(service->handle);\r
+ CloseServiceHandle(service->handle);\r
\r
return 0;\r
}\r
\r
if (ret) {\r
int response = await_service_control_response(control, service_handle, &service_status, initial_status);\r
- CloseHandle(service_handle);\r
+ CloseServiceHandle(service_handle);\r
\r
if (response) {\r
print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control));\r
return 0;\r
}\r
else {\r
- CloseHandle(service_handle);\r
+ CloseServiceHandle(service_handle);\r
_ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
return 1;\r
}\r
\r
if (ret) {\r
int response = await_service_control_response(control, service_handle, &service_status, initial_status);\r
- CloseHandle(service_handle);\r
+ CloseServiceHandle(service_handle);\r
\r
if (response) {\r
print_message(stderr, NSSM_MESSAGE_BAD_CONTROL_RESPONSE, canonical_name, service_status_text(service_status.dwCurrentState), service_control_text(control));\r
return 0;\r
}\r
else {\r
- CloseHandle(service_handle);\r
+ CloseServiceHandle(service_handle);\r
_ftprintf(stderr, _T("%s: %s: %s"), canonical_name, service_control_text(control), error_string(error));\r
if (error == ERROR_SERVICE_NOT_ACTIVE) {\r
if (control == SERVICE_CONTROL_SHUTDOWN || control == SERVICE_CONTROL_STOP) return 0;\r
/* Initialise status */\r
ZeroMemory(&service->status, sizeof(service->status));\r
service->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS;\r
- service->status.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;\r
+ service->status.dwControlsAccepted = SERVICE_ACCEPT_POWEREVENT | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;\r
service->status.dwWin32ExitCode = NO_ERROR;\r
service->status.dwServiceSpecificExitCode = 0;\r
service->status.dwCheckPoint = 0;\r
if (services) {\r
service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0);\r
set_service_recovery(service);\r
+\r
CloseServiceHandle(services);\r
}\r
}\r
case SERVICE_CONTROL_CONTINUE: return _T("CONTINUE");\r
case SERVICE_CONTROL_INTERROGATE: return _T("INTERROGATE");\r
case NSSM_SERVICE_CONTROL_ROTATE: return _T("ROTATE");\r
+ case SERVICE_CONTROL_POWEREVENT: return _T("POWEREVENT");\r
default: return 0;\r
}\r
}\r
if (service->rotate_stdout_online == NSSM_ROTATE_ONLINE) service->rotate_stdout_online = NSSM_ROTATE_ONLINE_ASAP;\r
if (service->rotate_stderr_online == NSSM_ROTATE_ONLINE) service->rotate_stderr_online = NSSM_ROTATE_ONLINE_ASAP;\r
return NO_ERROR;\r
+\r
+ case SERVICE_CONTROL_POWEREVENT:\r
+ if (event != PBT_APMRESUMEAUTOMATIC) {\r
+ log_service_control(service->name, control, false);\r
+ return NO_ERROR;\r
+ }\r
+ log_service_control(service->name, control, true);\r
+ end_service((void *) service, false);\r
+ return NO_ERROR;\r
}\r
\r
/* Unknown control */\r
but be mindful of the fact that we are blocking the service control manager\r
so abandon the wait before too much time has elapsed.\r
*/\r
- unsigned long delay = service->throttle_delay;\r
- if (delay > NSSM_SERVICE_STATUS_DEADLINE) {\r
- TCHAR delay_milliseconds[16];\r
- _sntprintf_s(delay_milliseconds, _countof(delay_milliseconds), _TRUNCATE, _T("%lu"), delay);\r
- TCHAR deadline_milliseconds[16];\r
- _sntprintf_s(deadline_milliseconds, _countof(deadline_milliseconds), _TRUNCATE, _T("%lu"), NSSM_SERVICE_STATUS_DEADLINE);\r
- log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_STARTUP_DELAY_TOO_LONG, service->name, delay_milliseconds, NSSM, deadline_milliseconds, 0);\r
- delay = NSSM_SERVICE_STATUS_DEADLINE;\r
- }\r
- unsigned long deadline = WaitForSingleObject(service->process_handle, delay);\r
+ service->status.dwCurrentState = SERVICE_START_PENDING;\r
+ if (await_single_handle(service->status_handle, &service->status, service->process_handle, service->name, _T("start_service"), service->throttle_delay) == 1) service->throttle = 0;\r
\r
/* Signal successful start */\r
service->status.dwCurrentState = SERVICE_RUNNING;\r
if (service->pid) {\r
/* Shut down service */\r
log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_TERMINATEPROCESS, service->name, service->exe, 0);\r
- kill_process(service, service->process_handle, service->pid, 0);\r
+ kill_t k;\r
+ service_kill_t(service, &k);\r
+ k.exitcode = 0;\r
+ kill_process(&k);\r
}\r
else log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_PROCESS_ALREADY_STOPPED, service->name, service->exe, 0);\r
\r
\r
/* Clean up. */\r
if (exitcode == STILL_ACTIVE) exitcode = 0;\r
- if (service->pid) kill_process_tree(service, service->pid, exitcode, service->pid);\r
+ if (service->pid && service->kill_process_tree) {\r
+ kill_t k;\r
+ service_kill_t(service, &k);\r
+ kill_process_tree(&k, service->pid);\r
+ }\r
service->pid = 0;\r
\r
/*\r
\r
Only doing both these things will prevent the system from killing the service.\r
\r
+ If the status_handle and service_status arguments are omitted, this function\r
+ will not try to update the service manager but it will still log to the\r
+ event log that it is waiting for a handle.\r
+\r
Returns: 1 if the wait timed out.\r
0 if the wait completed.\r
-1 on error.\r
*/\r
-int await_shutdown(nssm_service_t *service, TCHAR *function_name, unsigned long timeout) {\r
+int await_single_handle(SERVICE_STATUS_HANDLE status_handle, SERVICE_STATUS *status, HANDLE handle, TCHAR *name, TCHAR *function_name, unsigned long timeout) {\r
unsigned long interval;\r
- unsigned long waithint;\r
unsigned long ret;\r
unsigned long waited;\r
TCHAR interval_milliseconds[16];\r
\r
_sntprintf_s(timeout_milliseconds, _countof(timeout_milliseconds), _TRUNCATE, _T("%lu"), timeout);\r
\r
- waithint = service->status.dwWaitHint;\r
waited = 0;\r
while (waited < timeout) {\r
interval = timeout - waited;\r
if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE;\r
\r
- service->status.dwCurrentState = SERVICE_STOP_PENDING;\r
- service->status.dwWaitHint += interval;\r
- service->status.dwCheckPoint++;\r
- SetServiceStatus(service->status_handle, &service->status);\r
+ if (status) {\r
+ status->dwWaitHint += interval;\r
+ status->dwCheckPoint++;\r
+ SetServiceStatus(status_handle, status);\r
+ }\r
\r
if (waited) {\r
_sntprintf_s(waited_milliseconds, _countof(waited_milliseconds), _TRUNCATE, _T("%lu"), waited);\r
_sntprintf_s(interval_milliseconds, _countof(interval_milliseconds), _TRUNCATE, _T("%lu"), interval);\r
- log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SHUTDOWN, function, service->name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0);\r
+ log_event(EVENTLOG_INFORMATION_TYPE, NSSM_EVENT_AWAITING_SINGLE_HANDLE, function, name, waited_milliseconds, interval_milliseconds, timeout_milliseconds, 0);\r
}\r
\r
- switch (WaitForSingleObject(service->process_handle, interval)) {\r
+ switch (WaitForSingleObject(handle, interval)) {\r
case WAIT_OBJECT_0:\r
ret = 0;\r
goto awaited;\r
\r
case WAIT_TIMEOUT:\r
ret = 1;\r
- break;\r
+ break;\r
\r
default:\r
ret = -1;\r