[SERVICES] Fix indentation and remove an unused variable
[reactos.git] / base / system / services / controlset.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/controlset.c
5 * PURPOSE: Control Set Management
6 * COPYRIGHT: Copyright 2012 Eric Kohl
7 *
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "services.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 /* GLOBALS *******************************************************************/
19
20
21 /* FUNCTIONS *****************************************************************/
22
23 #if (_WIN32_WINNT < 0x0600)
24 static
25 DWORD
26 ScmCopyTree(
27 HKEY hSrcKey,
28 HKEY hDstKey)
29 {
30 DWORD dwSubKeys;
31 DWORD dwValues;
32 DWORD dwType;
33 DWORD dwMaxSubKeyNameLength;
34 DWORD dwSubKeyNameLength;
35 DWORD dwMaxValueNameLength;
36 DWORD dwValueNameLength;
37 DWORD dwMaxValueLength;
38 DWORD dwValueLength;
39 DWORD dwDisposition;
40 DWORD i;
41 LPWSTR lpNameBuffer;
42 LPBYTE lpDataBuffer;
43 HKEY hDstSubKey;
44 HKEY hSrcSubKey;
45 DWORD dwError;
46
47 DPRINT("ScmCopyTree()\n");
48
49 dwError = RegQueryInfoKey(hSrcKey,
50 NULL,
51 NULL,
52 NULL,
53 &dwSubKeys,
54 &dwMaxSubKeyNameLength,
55 NULL,
56 &dwValues,
57 &dwMaxValueNameLength,
58 &dwMaxValueLength,
59 NULL,
60 NULL);
61 if (dwError != ERROR_SUCCESS)
62 {
63 DPRINT1("RegQueryInfoKey() failed (Error %lu)\n", dwError);
64 return dwError;
65 }
66
67 dwMaxSubKeyNameLength++;
68 dwMaxValueNameLength++;
69
70 DPRINT("dwSubKeys %lu\n", dwSubKeys);
71 DPRINT("dwMaxSubKeyNameLength %lu\n", dwMaxSubKeyNameLength);
72 DPRINT("dwValues %lu\n", dwValues);
73 DPRINT("dwMaxValueNameLength %lu\n", dwMaxValueNameLength);
74 DPRINT("dwMaxValueLength %lu\n", dwMaxValueLength);
75
76 /* Copy subkeys */
77 if (dwSubKeys != 0)
78 {
79 lpNameBuffer = HeapAlloc(GetProcessHeap(),
80 0,
81 dwMaxSubKeyNameLength * sizeof(WCHAR));
82 if (lpNameBuffer == NULL)
83 {
84 DPRINT1("Buffer allocation failed\n");
85 return ERROR_NOT_ENOUGH_MEMORY;
86 }
87
88 for (i = 0; i < dwSubKeys; i++)
89 {
90 dwSubKeyNameLength = dwMaxSubKeyNameLength;
91 dwError = RegEnumKeyExW(hSrcKey,
92 i,
93 lpNameBuffer,
94 &dwSubKeyNameLength,
95 NULL,
96 NULL,
97 NULL,
98 NULL);
99 if (dwError != ERROR_SUCCESS)
100 {
101 DPRINT1("Subkey enumeration failed (Error %lu)\n", dwError);
102 HeapFree(GetProcessHeap(),
103 0,
104 lpNameBuffer);
105 return dwError;
106 }
107
108 dwError = RegCreateKeyExW(hDstKey,
109 lpNameBuffer,
110 0,
111 NULL,
112 REG_OPTION_NON_VOLATILE,
113 KEY_WRITE,
114 NULL,
115 &hDstSubKey,
116 &dwDisposition);
117 if (dwError != ERROR_SUCCESS)
118 {
119 DPRINT1("Subkey creation failed (Error %lu)\n", dwError);
120 HeapFree(GetProcessHeap(),
121 0,
122 lpNameBuffer);
123 return dwError;
124 }
125
126 dwError = RegOpenKeyExW(hSrcKey,
127 lpNameBuffer,
128 0,
129 KEY_READ,
130 &hSrcSubKey);
131 if (dwError != ERROR_SUCCESS)
132 {
133 DPRINT1("Error: %lu\n", dwError);
134 RegCloseKey(hDstSubKey);
135 HeapFree(GetProcessHeap(),
136 0,
137 lpNameBuffer);
138 return dwError;
139 }
140
141 dwError = ScmCopyTree(hSrcSubKey,
142 hDstSubKey);
143 if (dwError != ERROR_SUCCESS)
144 {
145 DPRINT1("Error: %lu\n", dwError);
146 RegCloseKey (hSrcSubKey);
147 RegCloseKey (hDstSubKey);
148 HeapFree(GetProcessHeap(),
149 0,
150 lpNameBuffer);
151 return dwError;
152 }
153
154 RegCloseKey(hSrcSubKey);
155 RegCloseKey(hDstSubKey);
156 }
157
158 HeapFree(GetProcessHeap(),
159 0,
160 lpNameBuffer);
161 }
162
163 /* Copy values */
164 if (dwValues != 0)
165 {
166 lpNameBuffer = HeapAlloc(GetProcessHeap(),
167 0,
168 dwMaxValueNameLength * sizeof(WCHAR));
169 if (lpNameBuffer == NULL)
170 {
171 DPRINT1("Buffer allocation failed\n");
172 return ERROR_NOT_ENOUGH_MEMORY;
173 }
174
175 lpDataBuffer = HeapAlloc(GetProcessHeap(),
176 0,
177 dwMaxValueLength);
178 if (lpDataBuffer == NULL)
179 {
180 DPRINT1("Buffer allocation failed\n");
181 HeapFree(GetProcessHeap(),
182 0,
183 lpNameBuffer);
184 return ERROR_NOT_ENOUGH_MEMORY;
185 }
186
187 for (i = 0; i < dwValues; i++)
188 {
189 dwValueNameLength = dwMaxValueNameLength;
190 dwValueLength = dwMaxValueLength;
191 dwError = RegEnumValueW(hSrcKey,
192 i,
193 lpNameBuffer,
194 &dwValueNameLength,
195 NULL,
196 &dwType,
197 lpDataBuffer,
198 &dwValueLength);
199 if (dwError != ERROR_SUCCESS)
200 {
201 DPRINT1("Error: %lu\n", dwError);
202 HeapFree(GetProcessHeap(),
203 0,
204 lpDataBuffer);
205 HeapFree(GetProcessHeap(),
206 0,
207 lpNameBuffer);
208 return dwError;
209 }
210
211 dwError = RegSetValueExW(hDstKey,
212 lpNameBuffer,
213 0,
214 dwType,
215 lpDataBuffer,
216 dwValueLength);
217 if (dwError != ERROR_SUCCESS)
218 {
219 DPRINT1("Error: %lu\n", dwError);
220 HeapFree(GetProcessHeap(),
221 0,
222 lpDataBuffer);
223 HeapFree(GetProcessHeap(),
224 0,
225 lpNameBuffer);
226 return dwError;
227 }
228 }
229
230 HeapFree(GetProcessHeap(),
231 0,
232 lpDataBuffer);
233
234 HeapFree(GetProcessHeap(),
235 0,
236 lpNameBuffer);
237 }
238
239 DPRINT("ScmCopyTree() done \n");
240
241 return ERROR_SUCCESS;
242 }
243 #endif
244
245
246 static
247 DWORD
248 ScmGetControlSetValues(
249 PDWORD pdwCurrentControlSet,
250 PDWORD pdwDefaultControlSet,
251 PDWORD pdwFailedControlSet,
252 PDWORD pdwLastKnownGoodControlSet)
253 {
254 HKEY hSelectKey;
255 DWORD dwType;
256 DWORD dwSize;
257 DWORD dwError;
258
259 DPRINT("ScmGetControlSetValues() called\n");
260
261 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
262 L"System\\Select",
263 0,
264 KEY_READ,
265 &hSelectKey);
266 if (dwError != ERROR_SUCCESS)
267 return dwError;
268
269 dwSize = sizeof(DWORD);
270 dwError = RegQueryValueExW(hSelectKey,
271 L"Current",
272 0,
273 &dwType,
274 (LPBYTE)pdwCurrentControlSet,
275 &dwSize);
276 if (dwError != ERROR_SUCCESS)
277 {
278 *pdwCurrentControlSet = 0;
279 }
280
281 dwSize = sizeof(DWORD);
282 dwError = RegQueryValueExW(hSelectKey,
283 L"Default",
284 0,
285 &dwType,
286 (LPBYTE)pdwDefaultControlSet,
287 &dwSize);
288 if (dwError != ERROR_SUCCESS)
289 {
290 *pdwDefaultControlSet = 0;
291 }
292
293 dwSize = sizeof(DWORD);
294 dwError = RegQueryValueExW(hSelectKey,
295 L"Failed",
296 0,
297 &dwType,
298 (LPBYTE)pdwFailedControlSet,
299 &dwSize);
300 if (dwError != ERROR_SUCCESS)
301 {
302 *pdwFailedControlSet = 0;
303 }
304
305 dwSize = sizeof(DWORD);
306 dwError = RegQueryValueExW(hSelectKey,
307 L"LastKnownGood",
308 0,
309 &dwType,
310 (LPBYTE)pdwLastKnownGoodControlSet,
311 &dwSize);
312 if (dwError != ERROR_SUCCESS)
313 {
314 *pdwLastKnownGoodControlSet = 0;
315 }
316
317 RegCloseKey(hSelectKey);
318
319 DPRINT("ControlSets:\n");
320 DPRINT("Current: %lu\n", *pdwCurrentControlSet);
321 DPRINT("Default: %lu\n", *pdwDefaultControlSet);
322 DPRINT("Failed: %lu\n", *pdwFailedControlSet);
323 DPRINT("LastKnownGood: %lu\n", *pdwLastKnownGoodControlSet);
324
325 return dwError;
326 }
327
328
329 static
330 DWORD
331 ScmSetLastKnownGoodControlSet(
332 DWORD dwControlSet)
333 {
334 HKEY hSelectKey;
335 DWORD dwError;
336
337 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
338 L"System\\Select",
339 0,
340 KEY_WRITE,
341 &hSelectKey);
342 if (dwError != ERROR_SUCCESS)
343 return dwError;
344
345 dwError = RegSetValueExW(hSelectKey,
346 L"LastKnownGood",
347 0,
348 REG_DWORD,
349 (LPBYTE)&dwControlSet,
350 sizeof(dwControlSet));
351
352 RegFlushKey(hSelectKey);
353 RegCloseKey(hSelectKey);
354
355 return dwError;
356 }
357
358
359 static
360 DWORD
361 ScmGetSetupInProgress(VOID)
362 {
363 DWORD dwError;
364 HKEY hKey;
365 DWORD dwType;
366 DWORD dwSize;
367 DWORD dwSetupInProgress = (DWORD)-1;
368
369 DPRINT("ScmGetSetupInProgress()\n");
370
371 /* Open key */
372 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
373 L"SYSTEM\\Setup",
374 0,
375 KEY_QUERY_VALUE,
376 &hKey);
377 if (dwError == ERROR_SUCCESS)
378 {
379 /* Read key */
380 dwSize = sizeof(DWORD);
381 RegQueryValueExW(hKey,
382 L"SystemSetupInProgress",
383 NULL,
384 &dwType,
385 (LPBYTE)&dwSetupInProgress,
386 &dwSize);
387 RegCloseKey(hKey);
388 }
389
390 DPRINT("SetupInProgress: %lu\n", dwSetupInProgress);
391 return dwSetupInProgress;
392 }
393
394
395 static
396 DWORD
397 ScmCopyControlSet(
398 DWORD dwSourceControlSet,
399 DWORD dwDestinationControlSet)
400 {
401 WCHAR szSourceControlSetName[32];
402 WCHAR szDestinationControlSetName[32];
403 HKEY hSourceControlSetKey = NULL;
404 HKEY hDestinationControlSetKey = NULL;
405 DWORD dwDisposition;
406 DWORD dwError;
407
408 /* Create the source control set name */
409 swprintf(szSourceControlSetName, L"SYSTEM\\ControlSet%03lu", dwSourceControlSet);
410 DPRINT("Source control set: %S\n", szSourceControlSetName);
411
412 /* Create the destination control set name */
413 swprintf(szDestinationControlSetName, L"SYSTEM\\ControlSet%03lu", dwDestinationControlSet);
414 DPRINT("Destination control set: %S\n", szDestinationControlSetName);
415
416 /* Open the source control set key */
417 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
418 szSourceControlSetName,
419 0,
420 KEY_READ,
421 &hSourceControlSetKey);
422 if (dwError != ERROR_SUCCESS)
423 goto done;
424
425 /* Create the destination control set key */
426 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
427 szDestinationControlSetName,
428 0,
429 NULL,
430 REG_OPTION_NON_VOLATILE,
431 KEY_WRITE,
432 NULL,
433 &hDestinationControlSetKey,
434 &dwDisposition);
435 if (dwError != ERROR_SUCCESS)
436 goto done;
437
438 /* Copy the source control set to the destination control set */
439 #if (_WIN32_WINNT >= 0x0600)
440 dwError = RegCopyTreeW(hSourceControlSetKey,
441 NULL,
442 hDestinationControlSetKey);
443 #else
444 dwError = ScmCopyTree(hSourceControlSetKey,
445 hDestinationControlSetKey);
446 #endif
447 if (dwError != ERROR_SUCCESS)
448 goto done;
449
450 RegFlushKey(hDestinationControlSetKey);
451
452 done:
453 if (hDestinationControlSetKey != NULL)
454 RegCloseKey(hDestinationControlSetKey);
455
456 if (hSourceControlSetKey != NULL)
457 RegCloseKey(hSourceControlSetKey);
458
459 return dwError;
460 }
461
462
463 DWORD
464 ScmCreateLastKnownGoodControlSet(VOID)
465 {
466 DWORD dwCurrentControlSet, dwDefaultControlSet;
467 DWORD dwFailedControlSet, dwLastKnownGoodControlSet;
468 DWORD dwNewControlSet;
469 DWORD dwError;
470
471 /* Get the control set values */
472 dwError = ScmGetControlSetValues(&dwCurrentControlSet,
473 &dwDefaultControlSet,
474 &dwFailedControlSet,
475 &dwLastKnownGoodControlSet);
476 if (dwError != ERROR_SUCCESS)
477 return dwError;
478
479 /* First boot after setup? */
480 if ((ScmGetSetupInProgress() == 0) &&
481 (dwCurrentControlSet == dwLastKnownGoodControlSet))
482 {
483 DPRINT("First boot after setup!\n");
484
485 /* Search for a new control set number */
486 for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++)
487 {
488 if ((dwNewControlSet != dwCurrentControlSet) &&
489 (dwNewControlSet != dwDefaultControlSet) &&
490 (dwNewControlSet != dwFailedControlSet) &&
491 (dwNewControlSet != dwLastKnownGoodControlSet))
492 break;
493 }
494
495 /* Fail if we did not find an unused control set!*/
496 if (dwNewControlSet >= 1000)
497 {
498 DPRINT1("Too many control sets!\n");
499 return ERROR_NO_MORE_ITEMS;
500 }
501
502 /* Copy the current control set */
503 dwError = ScmCopyControlSet(dwCurrentControlSet,
504 dwNewControlSet);
505 if (dwError != ERROR_SUCCESS)
506 return dwError;
507
508 /* Set the new 'LastKnownGood' control set */
509 dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet);
510 }
511
512 return dwError;
513 }
514
515 /* EOF */