[KMTESTS:CC] Add tests for CcSetFileSizes
[reactos.git] / modules / rostests / kmtests / kmtest / service.c
1 /*
2 * PROJECT: ReactOS kernel-mode tests
3 * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4 * PURPOSE: Kernel-Mode Test Suite loader service control functions
5 * COPYRIGHT: Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6 * Copyright 2017 Ged Murphy <gedmurphy@reactos.org>
7 * Copyright 2018 Serge Gautherie <reactos-git_serge_171003@gautherie.fr>
8 */
9
10 #include <kmt_test.h>
11 #include "kmtest.h"
12
13 #include <assert.h>
14
15 #define SERVICE_ACCESS (SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP | DELETE)
16
17 /*
18 * This is an internal function not meant for use by the kmtests app,
19 * so we declare it here instead of kmtest.h
20 */
21 DWORD
22 KmtpCreateService(
23 IN PCWSTR ServiceName,
24 IN PCWSTR ServicePath,
25 IN PCWSTR DisplayName OPTIONAL,
26 IN DWORD ServiceType,
27 OUT SC_HANDLE *ServiceHandle);
28
29
30 static SC_HANDLE ScmHandle;
31
32 /**
33 * @name KmtServiceInit
34 *
35 * Initialize service management routines (by opening the service control manager)
36 *
37 * @return Win32 error code
38 */
39 DWORD
40 KmtServiceInit(VOID)
41 {
42 DWORD Error = ERROR_SUCCESS;
43
44 assert(!ScmHandle);
45
46 ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
47 if (!ScmHandle)
48 error(Error);
49
50 return Error;
51 }
52
53 /**
54 * @name KmtServiceCleanup
55 *
56 * Clean up resources used by service management routines.
57 *
58 * @param IgnoreErrors
59 * If TRUE, the function will never set ErrorLineAndFile, and always return ERROR_SUCCESS
60 *
61 * @return Win32 error code
62 */
63 DWORD
64 KmtServiceCleanup(
65 BOOLEAN IgnoreErrors)
66 {
67 DWORD Error = ERROR_SUCCESS;
68
69 if (ScmHandle && !CloseServiceHandle(ScmHandle) && !IgnoreErrors)
70 error(Error);
71
72 return Error;
73 }
74
75 /**
76 * @name KmtCreateService
77 *
78 * Create the specified driver service and return a handle to it
79 *
80 * @param ServiceName
81 * Name of the service to create
82 * @param ServicePath
83 * File name of the driver, relative to the current directory
84 * @param DisplayName
85 * Service display name
86 * @param ServiceHandle
87 * Pointer to a variable to receive the handle to the service
88 *
89 * @return Win32 error code
90 */
91 DWORD
92 KmtCreateService(
93 IN PCWSTR ServiceName,
94 IN PCWSTR ServicePath,
95 IN PCWSTR DisplayName OPTIONAL,
96 OUT SC_HANDLE *ServiceHandle)
97 {
98 return KmtpCreateService(ServiceName,
99 ServicePath,
100 DisplayName,
101 SERVICE_KERNEL_DRIVER,
102 ServiceHandle);
103 }
104
105 /**
106 * @name KmtGetServiceStateAsString
107 *
108 * @param ServiceState
109 * Service state as a number
110 *
111 * @return Service state as a string
112 */
113 static
114 PCSTR
115 KmtGetServiceStateAsString(
116 IN DWORD ServiceState)
117 {
118 switch(ServiceState)
119 {
120 case SERVICE_STOPPED:
121 return "STOPPED";
122 case SERVICE_START_PENDING:
123 return "START_PENDING";
124 case SERVICE_STOP_PENDING:
125 return "STOP_PENDING";
126 case SERVICE_RUNNING:
127 return "RUNNING";
128 case SERVICE_CONTINUE_PENDING:
129 return "CONTINUE_PENDING";
130 case SERVICE_PAUSE_PENDING:
131 return "PAUSE_PENDING";
132 case SERVICE_PAUSED:
133 return "PAUSED";
134 default:
135 ok(FALSE, "Unknown service state = %lu\n", ServiceState);
136 return "(Unknown)";
137 }
138 }
139
140 /**
141 * @name KmtEnsureServiceState
142 *
143 * @param ServiceName
144 * Name of the service to check,
145 * or NULL
146 * @param ServiceHandle
147 * Handle to the service
148 * @param ExpectedServiceState
149 * State which the service should be in
150 *
151 * @return Win32 error code
152 */
153 static
154 DWORD
155 KmtEnsureServiceState(
156 IN PCWSTR ServiceName OPTIONAL,
157 IN SC_HANDLE ServiceHandle,
158 IN DWORD ExpectedServiceState)
159 {
160 DWORD Error = ERROR_SUCCESS;
161 SERVICE_STATUS ServiceStatus;
162 DWORD StartTime = GetTickCount();
163 DWORD Timeout = 10 * 1000;
164 PCWSTR ServiceNameOut = ServiceName ? ServiceName : L"(handle only, no name)";
165
166 assert(ServiceHandle);
167 assert(ExpectedServiceState);
168
169 if (!QueryServiceStatus(ServiceHandle, &ServiceStatus))
170 error_goto(Error, cleanup);
171
172 while (ServiceStatus.dwCurrentState != ExpectedServiceState)
173 {
174 // NB: ServiceStatus.dwWaitHint and ServiceStatus.dwCheckPoint logic could be added, if need be.
175
176 Sleep(1 * 1000);
177
178 if (!QueryServiceStatus(ServiceHandle, &ServiceStatus))
179 error_goto(Error, cleanup);
180
181 if (GetTickCount() - StartTime >= Timeout)
182 break;
183 }
184
185 if (ServiceStatus.dwCurrentState != ExpectedServiceState)
186 {
187 ok(FALSE, "Service = %ls, state = %lu %s (!= %lu %s), waitHint = %lu, checkPoint = %lu\n",
188 ServiceNameOut,
189 ServiceStatus.dwCurrentState, KmtGetServiceStateAsString(ServiceStatus.dwCurrentState),
190 ExpectedServiceState, KmtGetServiceStateAsString(ExpectedServiceState),
191 ServiceStatus.dwWaitHint, ServiceStatus.dwCheckPoint);
192 goto cleanup;
193 }
194
195 trace("Service = %ls, state = %lu %s\n",
196 ServiceNameOut,
197 ExpectedServiceState, KmtGetServiceStateAsString(ExpectedServiceState));
198
199 cleanup:
200 return Error;
201 }
202
203 /**
204 * @name KmtStartService
205 *
206 * Start the specified driver service by handle or name (and return a handle to it)
207 *
208 * @param ServiceName
209 * If *ServiceHandle is NULL, name of the service to start
210 * @param ServiceHandle
211 * Pointer to a variable containing the service handle,
212 * or NULL (in which case it will be filled with a handle to the service)
213 *
214 * @return Win32 error code
215 */
216 DWORD
217 KmtStartService(
218 IN PCWSTR ServiceName OPTIONAL,
219 IN OUT SC_HANDLE *ServiceHandle)
220 {
221 DWORD Error = ERROR_SUCCESS;
222
223 assert(ServiceHandle);
224 assert(ServiceName || *ServiceHandle);
225
226 if (!*ServiceHandle)
227 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
228
229 if (!*ServiceHandle)
230 error_goto(Error, cleanup);
231
232 if (!StartService(*ServiceHandle, 0, NULL))
233 error_goto(Error, cleanup);
234
235 Error = KmtEnsureServiceState(ServiceName, *ServiceHandle, SERVICE_RUNNING);
236 if (Error)
237 goto cleanup;
238
239 cleanup:
240 return Error;
241 }
242
243 /**
244 * @name KmtCreateAndStartService
245 *
246 * Create and start the specified driver service and return a handle to it
247 *
248 * @param ServiceName
249 * Name of the service to create
250 * @param ServicePath
251 * File name of the driver, relative to the current directory
252 * @param DisplayName
253 * Service display name
254 * @param ServiceHandle
255 * Pointer to a variable to receive the handle to the service
256 * @param RestartIfRunning
257 * TRUE to stop and restart the service if it is already running
258 *
259 * @return Win32 error code
260 */
261 DWORD
262 KmtCreateAndStartService(
263 IN PCWSTR ServiceName,
264 IN PCWSTR ServicePath,
265 IN PCWSTR DisplayName OPTIONAL,
266 OUT SC_HANDLE *ServiceHandle,
267 IN BOOLEAN RestartIfRunning)
268 {
269 DWORD Error = ERROR_SUCCESS;
270
271 assert(ServiceHandle);
272
273 Error = KmtCreateService(ServiceName, ServicePath, DisplayName, ServiceHandle);
274
275 if (Error && Error != ERROR_SERVICE_EXISTS)
276 goto cleanup;
277
278 Error = KmtStartService(ServiceName, ServiceHandle);
279
280 if (Error != ERROR_SERVICE_ALREADY_RUNNING)
281 goto cleanup;
282
283 Error = ERROR_SUCCESS;
284
285 if (!RestartIfRunning)
286 goto cleanup;
287
288 Error = KmtStopService(ServiceName, ServiceHandle);
289 if (Error)
290 goto cleanup;
291
292 Error = KmtStartService(ServiceName, ServiceHandle);
293 if (Error)
294 goto cleanup;
295
296 cleanup:
297 assert(Error || *ServiceHandle);
298 return Error;
299 }
300
301 /**
302 * @name KmtStopService
303 *
304 * Stop the specified driver service by handle or name (and return a handle to it)
305 *
306 * @param ServiceName
307 * If *ServiceHandle is NULL, name of the service to stop
308 * @param ServiceHandle
309 * Pointer to a variable containing the service handle,
310 * or NULL (in which case it will be filled with a handle to the service)
311 *
312 * @return Win32 error code
313 */
314 DWORD
315 KmtStopService(
316 IN PCWSTR ServiceName OPTIONAL,
317 IN OUT SC_HANDLE *ServiceHandle)
318 {
319 DWORD Error = ERROR_SUCCESS;
320 SERVICE_STATUS ServiceStatus;
321
322 assert(ServiceHandle);
323 assert(ServiceName || *ServiceHandle);
324
325 if (!*ServiceHandle)
326 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
327
328 if (!*ServiceHandle)
329 error_goto(Error, cleanup);
330
331 if (!ControlService(*ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus))
332 error_goto(Error, cleanup);
333
334 Error = KmtEnsureServiceState(ServiceName, *ServiceHandle, SERVICE_STOPPED);
335 if (Error)
336 goto cleanup;
337
338 cleanup:
339 return Error;
340 }
341
342 /**
343 * @name KmtDeleteService
344 *
345 * Delete the specified driver service by handle or name (and return a handle to it)
346 *
347 * @param ServiceName
348 * If *ServiceHandle is NULL, name of the service to delete
349 * @param ServiceHandle
350 * Pointer to a variable containing the service handle.
351 * Will be set to NULL on success
352 *
353 * @return Win32 error code
354 */
355 DWORD
356 KmtDeleteService(
357 IN PCWSTR ServiceName OPTIONAL,
358 IN OUT SC_HANDLE *ServiceHandle)
359 {
360 DWORD Error = ERROR_SUCCESS;
361
362 assert(ServiceHandle);
363 assert(ServiceName || *ServiceHandle);
364
365 if (!*ServiceHandle)
366 *ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
367
368 if (!*ServiceHandle)
369 error_goto(Error, cleanup);
370
371 if (!DeleteService(*ServiceHandle))
372 error_goto(Error, cleanup);
373
374 if (*ServiceHandle)
375 CloseServiceHandle(*ServiceHandle);
376
377 cleanup:
378 return Error;
379 }
380
381 /**
382 * @name KmtCloseService
383 *
384 * Close the specified driver service handle
385 *
386 * @param ServiceHandle
387 * Pointer to a variable containing the service handle.
388 * Will be set to NULL on success
389 *
390 * @return Win32 error code
391 */
392 DWORD KmtCloseService(
393 IN OUT SC_HANDLE *ServiceHandle)
394 {
395 DWORD Error = ERROR_SUCCESS;
396
397 assert(ServiceHandle);
398
399 if (*ServiceHandle && !CloseServiceHandle(*ServiceHandle))
400 error_goto(Error, cleanup);
401
402 *ServiceHandle = NULL;
403
404 cleanup:
405 return Error;
406 }
407
408
409 /*
410 * Private function, not meant for use in kmtests
411 * See KmtCreateService & KmtFltCreateService
412 */
413 DWORD
414 KmtpCreateService(
415 IN PCWSTR ServiceName,
416 IN PCWSTR ServicePath,
417 IN PCWSTR DisplayName OPTIONAL,
418 IN DWORD ServiceType,
419 OUT SC_HANDLE *ServiceHandle)
420 {
421 DWORD Error = ERROR_SUCCESS;
422 WCHAR DriverPath[MAX_PATH];
423 HRESULT result = S_OK;
424
425 assert(ServiceHandle);
426 assert(ServiceName && ServicePath);
427
428 if (!GetModuleFileName(NULL, DriverPath, sizeof DriverPath / sizeof DriverPath[0]))
429 error_goto(Error, cleanup);
430
431 assert(wcsrchr(DriverPath, L'\\') != NULL);
432 wcsrchr(DriverPath, L'\\')[1] = L'\0';
433
434 result = StringCbCat(DriverPath, sizeof DriverPath, ServicePath);
435 if (FAILED(result))
436 error_value_goto(Error, result, cleanup);
437
438 if (GetFileAttributes(DriverPath) == INVALID_FILE_ATTRIBUTES)
439 error_goto(Error, cleanup);
440
441 *ServiceHandle = CreateService(ScmHandle, ServiceName, DisplayName,
442 SERVICE_ACCESS, ServiceType, SERVICE_DEMAND_START,
443 SERVICE_ERROR_NORMAL, DriverPath, NULL, NULL, NULL, NULL, NULL);
444
445 if (!*ServiceHandle)
446 error_goto(Error, cleanup);
447
448 cleanup:
449 return Error;
450 }