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