services: Cleanup when a service fails to start so it is still fully considered to be stopped.
This commit is contained in:
parent
79ef408cd7
commit
9183a171f1
|
@ -2065,7 +2065,7 @@ cleanup:
|
||||||
CloseServiceHandle(scm_handle);
|
CloseServiceHandle(scm_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD try_start_stop(SC_HANDLE svc_handle, const char* name, int todo, DWORD is_nt4)
|
static DWORD try_start_stop(SC_HANDLE svc_handle, const char* name, DWORD is_nt4)
|
||||||
{
|
{
|
||||||
BOOL ret;
|
BOOL ret;
|
||||||
DWORD le1, le2;
|
DWORD le1, le2;
|
||||||
|
@ -2082,24 +2082,21 @@ static DWORD try_start_stop(SC_HANDLE svc_handle, const char* name, int todo, DW
|
||||||
|
|
||||||
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, (BYTE*)&statusproc, sizeof(statusproc), &needed);
|
ret = pQueryServiceStatusEx(svc_handle, SC_STATUS_PROCESS_INFO, (BYTE*)&statusproc, sizeof(statusproc), &needed);
|
||||||
ok(ret, "%s: QueryServiceStatusEx() failed le=%u\n", name, GetLastError());
|
ok(ret, "%s: QueryServiceStatusEx() failed le=%u\n", name, GetLastError());
|
||||||
todo_wine ok(statusproc.dwCurrentState == SERVICE_STOPPED, "%s: should be stopped state=%x\n", name, statusproc.dwCurrentState);
|
ok(statusproc.dwCurrentState == SERVICE_STOPPED, "%s: should be stopped state=%x\n", name, statusproc.dwCurrentState);
|
||||||
todo_wine ok(statusproc.dwProcessId == 0, "%s: ProcessId should be 0 instead of %x\n", name, statusproc.dwProcessId);
|
ok(statusproc.dwProcessId == 0, "%s: ProcessId should be 0 instead of %x\n", name, statusproc.dwProcessId);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = StartServiceA(svc_handle, 0, NULL);
|
ret = StartServiceA(svc_handle, 0, NULL);
|
||||||
le2 = GetLastError();
|
le2 = GetLastError();
|
||||||
ok(!ret, "%s: StartServiceA() should have failed\n", name);
|
ok(!ret, "%s: StartServiceA() should have failed\n", name);
|
||||||
if (todo)
|
ok(le2 == le1, "%s: the second try should yield the same error: %u != %u\n", name, le1, le2);
|
||||||
todo_wine ok(le2 == le1, "%s: the second try should yield the same error: %u != %u\n", name, le1, le2);
|
|
||||||
else
|
|
||||||
ok(le2 == le1, "%s: the second try should yield the same error: %u != %u\n", name, le1, le2);
|
|
||||||
|
|
||||||
status.dwCurrentState = 0xdeadbeef;
|
status.dwCurrentState = 0xdeadbeef;
|
||||||
ret = ControlService(svc_handle, SERVICE_CONTROL_STOP, &status);
|
ret = ControlService(svc_handle, SERVICE_CONTROL_STOP, &status);
|
||||||
le2 = GetLastError();
|
le2 = GetLastError();
|
||||||
ok(!ret, "%s: ControlService() should have failed\n", name);
|
ok(!ret, "%s: ControlService() should have failed\n", name);
|
||||||
todo_wine ok(le2 == ERROR_SERVICE_NOT_ACTIVE, "%s: %d != ERROR_SERVICE_NOT_ACTIVE\n", name, le2);
|
todo_wine ok(le2 == ERROR_SERVICE_NOT_ACTIVE, "%s: %d != ERROR_SERVICE_NOT_ACTIVE\n", name, le2);
|
||||||
todo_wine ok(status.dwCurrentState == SERVICE_STOPPED ||
|
ok(status.dwCurrentState == SERVICE_STOPPED ||
|
||||||
broken(is_nt4), /* NT4 returns a random value */
|
broken(is_nt4), /* NT4 returns a random value */
|
||||||
"%s: should be stopped state=%x\n", name, status.dwCurrentState);
|
"%s: should be stopped state=%x\n", name, status.dwCurrentState);
|
||||||
|
|
||||||
|
@ -2153,14 +2150,14 @@ static void test_start_stop(void)
|
||||||
ok(FALSE, "Could not create the service: %d\n", GetLastError());
|
ok(FALSE, "Could not create the service: %d\n", GetLastError());
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
le = try_start_stop(svc_handle, displayname, 1, is_nt4);
|
le = try_start_stop(svc_handle, displayname, is_nt4);
|
||||||
todo_wine ok(le == ERROR_SERVICE_DISABLED, "%d != ERROR_SERVICE_DISABLED\n", le);
|
todo_wine ok(le == ERROR_SERVICE_DISABLED, "%d != ERROR_SERVICE_DISABLED\n", le);
|
||||||
|
|
||||||
/* Then one with a bad path */
|
/* Then one with a bad path */
|
||||||
displayname = "Winetest Bad Path";
|
displayname = "Winetest Bad Path";
|
||||||
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, "c:\\no_such_file.exe", NULL, NULL, NULL, NULL, NULL, displayname);
|
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_DEMAND_START, SERVICE_NO_CHANGE, "c:\\no_such_file.exe", NULL, NULL, NULL, NULL, NULL, displayname);
|
||||||
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
||||||
try_start_stop(svc_handle, displayname, 0, is_nt4);
|
try_start_stop(svc_handle, displayname, is_nt4);
|
||||||
|
|
||||||
if (is_nt4)
|
if (is_nt4)
|
||||||
{
|
{
|
||||||
|
@ -2175,8 +2172,8 @@ static void test_start_stop(void)
|
||||||
displayname = "Winetest Exit Service";
|
displayname = "Winetest Exit Service";
|
||||||
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
|
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
|
||||||
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
||||||
le = try_start_stop(svc_handle, displayname, 0, is_nt4);
|
le = try_start_stop(svc_handle, displayname, is_nt4);
|
||||||
todo_wine ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
|
ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
|
||||||
|
|
||||||
/* And finally with a service that plays dead, forcing a timeout.
|
/* And finally with a service that plays dead, forcing a timeout.
|
||||||
* This time we will put no quotes. That should work too, even if there are
|
* This time we will put no quotes. That should work too, even if there are
|
||||||
|
@ -2187,8 +2184,8 @@ static void test_start_stop(void)
|
||||||
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
|
ret = ChangeServiceConfigA(svc_handle, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, cmd, NULL, NULL, NULL, NULL, NULL, displayname);
|
||||||
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
ok(ret, "ChangeServiceConfig() failed le=%u\n", GetLastError());
|
||||||
|
|
||||||
le = try_start_stop(svc_handle, displayname, 0, is_nt4);
|
le = try_start_stop(svc_handle, displayname, is_nt4);
|
||||||
todo_wine ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
|
ok(le == ERROR_SERVICE_REQUEST_TIMEOUT, "%d != ERROR_SERVICE_REQUEST_TIMEOUT\n", le);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
if (svc_handle)
|
if (svc_handle)
|
||||||
|
|
|
@ -772,25 +772,43 @@ DWORD service_start(struct service_entry *service, DWORD service_argc, LPCWSTR *
|
||||||
{
|
{
|
||||||
WINE_ERR("failed to create pipe for %s, error = %d\n",
|
WINE_ERR("failed to create pipe for %s, error = %d\n",
|
||||||
wine_dbgstr_w(service->name), GetLastError());
|
wine_dbgstr_w(service->name), GetLastError());
|
||||||
scmdatabase_unlock_startup(service->db);
|
err = GetLastError();
|
||||||
return GetLastError();
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
err = service_start_process(service, &process_handle);
|
|
||||||
|
|
||||||
if (err == ERROR_SUCCESS)
|
|
||||||
{
|
{
|
||||||
if (!service_send_start_message(service, process_handle, service_argv, service_argc))
|
err = service_start_process(service, &process_handle);
|
||||||
err = ERROR_SERVICE_REQUEST_TIMEOUT;
|
if (err == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
if (!service_send_start_message(service, process_handle, service_argv, service_argc))
|
||||||
|
err = ERROR_SERVICE_REQUEST_TIMEOUT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (err == ERROR_SUCCESS)
|
||||||
|
err = service_wait_for_startup(service, process_handle);
|
||||||
|
|
||||||
|
if (process_handle)
|
||||||
|
CloseHandle(process_handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err == ERROR_SUCCESS)
|
if (err == ERROR_SUCCESS)
|
||||||
err = service_wait_for_startup(service, process_handle);
|
ReleaseMutex(service->control_mutex);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
CloseHandle(service->overlapped_event);
|
||||||
|
service->overlapped_event = NULL;
|
||||||
|
CloseHandle(service->status_changed_event);
|
||||||
|
service->status_changed_event = NULL;
|
||||||
|
CloseHandle(service->control_mutex);
|
||||||
|
service->control_mutex = NULL;
|
||||||
|
if (service->control_pipe != INVALID_HANDLE_VALUE)
|
||||||
|
CloseHandle(service->control_pipe);
|
||||||
|
service->control_pipe = INVALID_HANDLE_VALUE;
|
||||||
|
|
||||||
if (process_handle)
|
service->status.dwProcessId = 0;
|
||||||
CloseHandle(process_handle);
|
service_lock_exclusive(service);
|
||||||
|
service->status.dwCurrentState = SERVICE_STOPPED;
|
||||||
ReleaseMutex(service->control_mutex);
|
service_unlock(service);
|
||||||
|
}
|
||||||
scmdatabase_unlock_startup(service->db);
|
scmdatabase_unlock_startup(service->db);
|
||||||
|
|
||||||
WINE_TRACE("returning %d\n", err);
|
WINE_TRACE("returning %d\n", err);
|
||||||
|
|
Loading…
Reference in New Issue