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 LSTATUS WINAPI RegCopyTreeW(_In_ HKEY, _In_opt_ LPCWSTR, _In_ HKEY); 18 LSTATUS WINAPI RegDeleteTreeW(_In_ HKEY, _In_opt_ LPCWSTR); 19 20 /* GLOBALS *******************************************************************/ 21 22 static BOOL bBootAccepted = FALSE; 23 24 25 /* FUNCTIONS *****************************************************************/ 26 27 static 28 DWORD 29 ScmGetControlSetValues( 30 PDWORD pdwCurrentControlSet, 31 PDWORD pdwDefaultControlSet, 32 PDWORD pdwFailedControlSet, 33 PDWORD pdwLastKnownGoodControlSet) 34 { 35 HKEY hSelectKey; 36 DWORD dwType; 37 DWORD dwSize; 38 DWORD dwError; 39 40 DPRINT("ScmGetControlSetValues() called\n"); 41 42 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 43 L"System\\Select", 44 0, 45 KEY_READ, 46 &hSelectKey); 47 if (dwError != ERROR_SUCCESS) 48 return dwError; 49 50 dwSize = sizeof(DWORD); 51 dwError = RegQueryValueExW(hSelectKey, 52 L"Current", 53 0, 54 &dwType, 55 (LPBYTE)pdwCurrentControlSet, 56 &dwSize); 57 if (dwError != ERROR_SUCCESS) 58 { 59 *pdwCurrentControlSet = 0; 60 } 61 62 dwSize = sizeof(DWORD); 63 dwError = RegQueryValueExW(hSelectKey, 64 L"Default", 65 0, 66 &dwType, 67 (LPBYTE)pdwDefaultControlSet, 68 &dwSize); 69 if (dwError != ERROR_SUCCESS) 70 { 71 *pdwDefaultControlSet = 0; 72 } 73 74 dwSize = sizeof(DWORD); 75 dwError = RegQueryValueExW(hSelectKey, 76 L"Failed", 77 0, 78 &dwType, 79 (LPBYTE)pdwFailedControlSet, 80 &dwSize); 81 if (dwError != ERROR_SUCCESS) 82 { 83 *pdwFailedControlSet = 0; 84 } 85 86 dwSize = sizeof(DWORD); 87 dwError = RegQueryValueExW(hSelectKey, 88 L"LastKnownGood", 89 0, 90 &dwType, 91 (LPBYTE)pdwLastKnownGoodControlSet, 92 &dwSize); 93 if (dwError != ERROR_SUCCESS) 94 { 95 *pdwLastKnownGoodControlSet = 0; 96 } 97 98 RegCloseKey(hSelectKey); 99 100 DPRINT("ControlSets:\n"); 101 DPRINT("Current: %lu\n", *pdwCurrentControlSet); 102 DPRINT("Default: %lu\n", *pdwDefaultControlSet); 103 DPRINT("Failed: %lu\n", *pdwFailedControlSet); 104 DPRINT("LastKnownGood: %lu\n", *pdwLastKnownGoodControlSet); 105 106 return dwError; 107 } 108 109 110 static 111 DWORD 112 ScmSetLastKnownGoodControlSet( 113 DWORD dwControlSet) 114 { 115 HKEY hSelectKey; 116 DWORD dwError; 117 118 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 119 L"System\\Select", 120 0, 121 KEY_WRITE, 122 &hSelectKey); 123 if (dwError != ERROR_SUCCESS) 124 return dwError; 125 126 dwError = RegSetValueExW(hSelectKey, 127 L"LastKnownGood", 128 0, 129 REG_DWORD, 130 (LPBYTE)&dwControlSet, 131 sizeof(dwControlSet)); 132 133 RegFlushKey(hSelectKey); 134 RegCloseKey(hSelectKey); 135 136 return dwError; 137 } 138 139 140 static 141 DWORD 142 ScmGetSetupInProgress(VOID) 143 { 144 DWORD dwError; 145 HKEY hKey; 146 DWORD dwType; 147 DWORD dwSize; 148 DWORD dwSetupInProgress = (DWORD)-1; 149 150 DPRINT("ScmGetSetupInProgress()\n"); 151 152 /* Open key */ 153 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 154 L"SYSTEM\\Setup", 155 0, 156 KEY_QUERY_VALUE, 157 &hKey); 158 if (dwError == ERROR_SUCCESS) 159 { 160 /* Read key */ 161 dwSize = sizeof(DWORD); 162 RegQueryValueExW(hKey, 163 L"SystemSetupInProgress", 164 NULL, 165 &dwType, 166 (LPBYTE)&dwSetupInProgress, 167 &dwSize); 168 RegCloseKey(hKey); 169 } 170 171 DPRINT("SetupInProgress: %lu\n", dwSetupInProgress); 172 return dwSetupInProgress; 173 } 174 175 176 static 177 DWORD 178 ScmCopyControlSet( 179 DWORD dwSourceControlSet, 180 DWORD dwDestinationControlSet) 181 { 182 WCHAR szSourceControlSetName[32]; 183 WCHAR szDestinationControlSetName[32]; 184 HKEY hSourceControlSetKey = NULL; 185 HKEY hDestinationControlSetKey = NULL; 186 DWORD dwDisposition; 187 DWORD dwError; 188 189 /* Create the source control set name */ 190 swprintf(szSourceControlSetName, L"SYSTEM\\ControlSet%03lu", dwSourceControlSet); 191 DPRINT("Source control set: %S\n", szSourceControlSetName); 192 193 /* Create the destination control set name */ 194 swprintf(szDestinationControlSetName, L"SYSTEM\\ControlSet%03lu", dwDestinationControlSet); 195 DPRINT("Destination control set: %S\n", szDestinationControlSetName); 196 197 /* Open the source control set key */ 198 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 199 szSourceControlSetName, 200 0, 201 KEY_READ, 202 &hSourceControlSetKey); 203 if (dwError != ERROR_SUCCESS) 204 goto done; 205 206 /* Create the destination control set key */ 207 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 208 szDestinationControlSetName, 209 0, 210 NULL, 211 REG_OPTION_NON_VOLATILE, 212 KEY_WRITE, 213 NULL, 214 &hDestinationControlSetKey, 215 &dwDisposition); 216 if (dwError != ERROR_SUCCESS) 217 goto done; 218 219 /* Copy the source control set to the destination control set */ 220 dwError = RegCopyTreeW(hSourceControlSetKey, 221 NULL, 222 hDestinationControlSetKey); 223 if (dwError != ERROR_SUCCESS) 224 goto done; 225 226 RegFlushKey(hDestinationControlSetKey); 227 228 done: 229 if (hDestinationControlSetKey != NULL) 230 RegCloseKey(hDestinationControlSetKey); 231 232 if (hSourceControlSetKey != NULL) 233 RegCloseKey(hSourceControlSetKey); 234 235 return dwError; 236 } 237 238 239 static 240 DWORD 241 ScmDeleteControlSet( 242 DWORD dwControlSet) 243 { 244 WCHAR szControlSetName[32]; 245 HKEY hControlSetKey = NULL; 246 DWORD dwError; 247 248 DPRINT("ScmDeleteControSet(%lu)\n", dwControlSet); 249 250 /* Create the control set name */ 251 swprintf(szControlSetName, L"SYSTEM\\ControlSet%03lu", dwControlSet); 252 DPRINT("Control set: %S\n", szControlSetName); 253 254 /* Open the system key */ 255 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 256 szControlSetName, 257 0, 258 DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE, 259 &hControlSetKey); 260 if (dwError != ERROR_SUCCESS) 261 return dwError; 262 263 /* Delete the control set */ 264 dwError = RegDeleteTreeW(hControlSetKey, 265 NULL); 266 267 /* Open the system key */ 268 RegCloseKey(hControlSetKey); 269 270 return dwError; 271 } 272 273 274 DWORD 275 ScmCreateLastKnownGoodControlSet(VOID) 276 { 277 DWORD dwCurrentControlSet, dwDefaultControlSet; 278 DWORD dwFailedControlSet, dwLastKnownGoodControlSet; 279 DWORD dwNewControlSet; 280 DWORD dwError; 281 282 /* Get the control set values */ 283 dwError = ScmGetControlSetValues(&dwCurrentControlSet, 284 &dwDefaultControlSet, 285 &dwFailedControlSet, 286 &dwLastKnownGoodControlSet); 287 if (dwError != ERROR_SUCCESS) 288 return dwError; 289 290 /* First boot after setup? */ 291 if ((ScmGetSetupInProgress() == 0) && 292 (dwCurrentControlSet == dwLastKnownGoodControlSet)) 293 { 294 DPRINT("First boot after setup\n"); 295 296 /* Search for a new control set number */ 297 for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++) 298 { 299 if ((dwNewControlSet != dwCurrentControlSet) && 300 (dwNewControlSet != dwDefaultControlSet) && 301 (dwNewControlSet != dwFailedControlSet) && 302 (dwNewControlSet != dwLastKnownGoodControlSet)) 303 break; 304 } 305 306 /* Fail if we did not find an unused control set!*/ 307 if (dwNewControlSet >= 1000) 308 { 309 DPRINT1("Too many control sets\n"); 310 return ERROR_NO_MORE_ITEMS; 311 } 312 313 /* Copy the current control set */ 314 dwError = ScmCopyControlSet(dwCurrentControlSet, 315 dwNewControlSet); 316 if (dwError != ERROR_SUCCESS) 317 return dwError; 318 319 /* Set the new 'LastKnownGood' control set */ 320 dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet); 321 if (dwError == ERROR_SUCCESS) 322 { 323 /* 324 * Accept the boot here in order to prevent the creation of 325 * another control set when a user is going to get logged on 326 */ 327 bBootAccepted = TRUE; 328 } 329 } 330 331 return dwError; 332 } 333 334 335 DWORD 336 ScmAcceptBoot(VOID) 337 { 338 DWORD dwCurrentControlSet, dwDefaultControlSet; 339 DWORD dwFailedControlSet, dwLastKnownGoodControlSet; 340 DWORD dwNewControlSet; 341 DWORD dwError; 342 343 DPRINT("ScmAcceptBoot()\n"); 344 345 if (bBootAccepted) 346 { 347 DPRINT1("Boot has already been accepted\n"); 348 return ERROR_BOOT_ALREADY_ACCEPTED; 349 } 350 351 /* Get the control set values */ 352 dwError = ScmGetControlSetValues(&dwCurrentControlSet, 353 &dwDefaultControlSet, 354 &dwFailedControlSet, 355 &dwLastKnownGoodControlSet); 356 if (dwError != ERROR_SUCCESS) 357 return dwError; 358 359 /* Search for a new control set number */ 360 for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++) 361 { 362 if ((dwNewControlSet != dwCurrentControlSet) && 363 (dwNewControlSet != dwDefaultControlSet) && 364 (dwNewControlSet != dwFailedControlSet) && 365 (dwNewControlSet != dwLastKnownGoodControlSet)) 366 break; 367 } 368 369 /* Fail if we did not find an unused control set!*/ 370 if (dwNewControlSet >= 1000) 371 { 372 DPRINT1("Too many control sets\n"); 373 return ERROR_NO_MORE_ITEMS; 374 } 375 376 /* Copy the current control set */ 377 dwError = ScmCopyControlSet(dwCurrentControlSet, 378 dwNewControlSet); 379 if (dwError != ERROR_SUCCESS) 380 return dwError; 381 382 /* Delete the current last known good contol set, if it is not used anywhere else */ 383 if ((dwLastKnownGoodControlSet != dwCurrentControlSet) && 384 (dwLastKnownGoodControlSet != dwDefaultControlSet) && 385 (dwLastKnownGoodControlSet != dwFailedControlSet)) 386 { 387 ScmDeleteControlSet(dwLastKnownGoodControlSet); 388 } 389 390 /* Set the new 'LastKnownGood' control set */ 391 dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet); 392 if (dwError != ERROR_SUCCESS) 393 return dwError; 394 395 bBootAccepted = TRUE; 396 397 return ERROR_SUCCESS; 398 } 399 400 401 DWORD 402 ScmRunLastKnownGood(VOID) 403 { 404 DPRINT("ScmRunLastKnownGood()\n"); 405 406 if (bBootAccepted) 407 { 408 DPRINT1("Boot has already been accepted\n"); 409 return ERROR_BOOT_ALREADY_ACCEPTED; 410 } 411 412 /* FIXME */ 413 414 return ERROR_SUCCESS; 415 } 416 417 /* EOF */ 418