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