mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
d31a557237
Fixes some typos like "alread"->"already" and kill g_dwServiceBits in rpcserver.cpp and omit points and exclamation marks at end of prints. On GCC8.4.0dbg RosBE2.2.1 this shrinks the file for me from 210.432 to 209.920 The file is loaded many times into memory, therefore optimization pays off here at runtime memory consumption. Also shorten to H. Poussineau in the header sections, to stop git from displaying diff in that line on each review due to that special char.
756 lines
21 KiB
C
756 lines
21 KiB
C
/*
|
|
* PROJECT: ReactOS Service Control Manager
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: base/system/services/controlset.c
|
|
* PURPOSE: Control Set Management
|
|
* COPYRIGHT: Copyright 2012 Eric Kohl
|
|
*
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "services.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
static BOOL bBootAccepted = FALSE;
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
#if (_WIN32_WINNT < 0x0600)
|
|
static
|
|
DWORD
|
|
ScmCopyTree(
|
|
HKEY hSrcKey,
|
|
HKEY hDstKey)
|
|
{
|
|
DWORD dwSubKeys;
|
|
DWORD dwValues;
|
|
DWORD dwType;
|
|
DWORD dwMaxSubKeyNameLength;
|
|
DWORD dwSubKeyNameLength;
|
|
DWORD dwMaxValueNameLength;
|
|
DWORD dwValueNameLength;
|
|
DWORD dwMaxValueLength;
|
|
DWORD dwValueLength;
|
|
DWORD dwDisposition;
|
|
DWORD i;
|
|
LPWSTR lpNameBuffer;
|
|
LPBYTE lpDataBuffer;
|
|
HKEY hDstSubKey;
|
|
HKEY hSrcSubKey;
|
|
DWORD dwError;
|
|
|
|
DPRINT("ScmCopyTree()\n");
|
|
|
|
dwError = RegQueryInfoKey(hSrcKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwSubKeys,
|
|
&dwMaxSubKeyNameLength,
|
|
NULL,
|
|
&dwValues,
|
|
&dwMaxValueNameLength,
|
|
&dwMaxValueLength,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("RegQueryInfoKey() failed (Error %lu)\n", dwError);
|
|
return dwError;
|
|
}
|
|
|
|
dwMaxSubKeyNameLength++;
|
|
dwMaxValueNameLength++;
|
|
|
|
DPRINT("dwSubKeys %lu\n", dwSubKeys);
|
|
DPRINT("dwMaxSubKeyNameLength %lu\n", dwMaxSubKeyNameLength);
|
|
DPRINT("dwValues %lu\n", dwValues);
|
|
DPRINT("dwMaxValueNameLength %lu\n", dwMaxValueNameLength);
|
|
DPRINT("dwMaxValueLength %lu\n", dwMaxValueLength);
|
|
|
|
/* Copy subkeys */
|
|
if (dwSubKeys != 0)
|
|
{
|
|
lpNameBuffer = HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
dwMaxSubKeyNameLength * sizeof(WCHAR));
|
|
if (lpNameBuffer == NULL)
|
|
{
|
|
DPRINT1("Buffer allocation failed\n");
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
for (i = 0; i < dwSubKeys; i++)
|
|
{
|
|
dwSubKeyNameLength = dwMaxSubKeyNameLength;
|
|
dwError = RegEnumKeyExW(hSrcKey,
|
|
i,
|
|
lpNameBuffer,
|
|
&dwSubKeyNameLength,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Subkey enumeration failed (Error %lu)\n", dwError);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
|
|
dwError = RegCreateKeyExW(hDstKey,
|
|
lpNameBuffer,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hDstSubKey,
|
|
&dwDisposition);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Subkey creation failed (Error %lu)\n", dwError);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
|
|
dwError = RegOpenKeyExW(hSrcKey,
|
|
lpNameBuffer,
|
|
0,
|
|
KEY_READ,
|
|
&hSrcSubKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", dwError);
|
|
RegCloseKey(hDstSubKey);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
|
|
dwError = ScmCopyTree(hSrcSubKey,
|
|
hDstSubKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", dwError);
|
|
RegCloseKey (hSrcSubKey);
|
|
RegCloseKey (hDstSubKey);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
|
|
RegCloseKey(hSrcSubKey);
|
|
RegCloseKey(hDstSubKey);
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
}
|
|
|
|
/* Copy values */
|
|
if (dwValues != 0)
|
|
{
|
|
lpNameBuffer = HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
dwMaxValueNameLength * sizeof(WCHAR));
|
|
if (lpNameBuffer == NULL)
|
|
{
|
|
DPRINT1("Buffer allocation failed\n");
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
/* RegSetValueExW tries to read behind the maximum length, so give it space for that */
|
|
lpDataBuffer = HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
dwMaxValueLength + sizeof(WCHAR));
|
|
if (lpDataBuffer == NULL)
|
|
{
|
|
DPRINT1("Buffer allocation failed\n");
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return ERROR_NOT_ENOUGH_MEMORY;
|
|
}
|
|
|
|
for (i = 0; i < dwValues; i++)
|
|
{
|
|
dwValueNameLength = dwMaxValueNameLength;
|
|
dwValueLength = dwMaxValueLength;
|
|
dwError = RegEnumValueW(hSrcKey,
|
|
i,
|
|
lpNameBuffer,
|
|
&dwValueNameLength,
|
|
NULL,
|
|
&dwType,
|
|
lpDataBuffer,
|
|
&dwValueLength);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", dwError);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpDataBuffer);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
|
|
dwError = RegSetValueExW(hDstKey,
|
|
lpNameBuffer,
|
|
0,
|
|
dwType,
|
|
lpDataBuffer,
|
|
dwValueLength);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
DPRINT1("Error: %lu\n", dwError);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpDataBuffer);
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
return dwError;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpDataBuffer);
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
lpNameBuffer);
|
|
}
|
|
|
|
DPRINT("ScmCopyTree() done\n");
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScmDeleteTree(
|
|
HKEY hKey,
|
|
PCWSTR pszSubKey)
|
|
{
|
|
DWORD dwMaxSubkeyLength, dwMaxValueLength;
|
|
DWORD dwMaxLength, dwSize;
|
|
PWSTR pszName = NULL;
|
|
HKEY hSubKey = NULL;
|
|
DWORD dwError;
|
|
|
|
if (pszSubKey != NULL)
|
|
{
|
|
dwError = RegOpenKeyExW(hKey, pszSubKey, 0, KEY_READ, &hSubKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
}
|
|
else
|
|
{
|
|
hSubKey = hKey;
|
|
}
|
|
|
|
/* Get highest length for keys, values */
|
|
dwError = RegQueryInfoKeyW(hSubKey,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxSubkeyLength,
|
|
NULL,
|
|
NULL,
|
|
&dwMaxValueLength,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
|
|
dwMaxSubkeyLength++;
|
|
dwMaxValueLength++;
|
|
dwMaxLength = max(dwMaxSubkeyLength, dwMaxValueLength);
|
|
|
|
/* Allocate a buffer for key and value names */
|
|
pszName = HeapAlloc(GetProcessHeap(),
|
|
0,
|
|
dwMaxLength * sizeof(WCHAR));
|
|
if (pszName == NULL)
|
|
{
|
|
dwError = ERROR_NOT_ENOUGH_MEMORY;
|
|
goto done;
|
|
}
|
|
|
|
/* Recursively delete all the subkeys */
|
|
while (TRUE)
|
|
{
|
|
dwSize = dwMaxLength;
|
|
if (RegEnumKeyExW(hSubKey,
|
|
0,
|
|
pszName,
|
|
&dwSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
break;
|
|
|
|
dwError = ScmDeleteTree(hSubKey, pszName);
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
}
|
|
|
|
if (pszSubKey != NULL)
|
|
{
|
|
dwError = RegDeleteKeyW(hKey, pszSubKey);
|
|
}
|
|
else
|
|
{
|
|
while (TRUE)
|
|
{
|
|
dwSize = dwMaxLength;
|
|
if (RegEnumValueW(hKey,
|
|
0,
|
|
pszName,
|
|
&dwSize,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL))
|
|
break;
|
|
|
|
dwError = RegDeleteValueW(hKey, pszName);
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
}
|
|
}
|
|
|
|
done:
|
|
if (pszName != NULL)
|
|
HeapFree(GetProcessHeap(), 0, pszName);
|
|
|
|
if (pszSubKey != NULL)
|
|
RegCloseKey(hSubKey);
|
|
|
|
return dwError;
|
|
}
|
|
#endif
|
|
|
|
|
|
static
|
|
DWORD
|
|
ScmGetControlSetValues(
|
|
PDWORD pdwCurrentControlSet,
|
|
PDWORD pdwDefaultControlSet,
|
|
PDWORD pdwFailedControlSet,
|
|
PDWORD pdwLastKnownGoodControlSet)
|
|
{
|
|
HKEY hSelectKey;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
DWORD dwError;
|
|
|
|
DPRINT("ScmGetControlSetValues() called\n");
|
|
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"System\\Select",
|
|
0,
|
|
KEY_READ,
|
|
&hSelectKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hSelectKey,
|
|
L"Current",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)pdwCurrentControlSet,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
*pdwCurrentControlSet = 0;
|
|
}
|
|
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hSelectKey,
|
|
L"Default",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)pdwDefaultControlSet,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
*pdwDefaultControlSet = 0;
|
|
}
|
|
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hSelectKey,
|
|
L"Failed",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)pdwFailedControlSet,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
*pdwFailedControlSet = 0;
|
|
}
|
|
|
|
dwSize = sizeof(DWORD);
|
|
dwError = RegQueryValueExW(hSelectKey,
|
|
L"LastKnownGood",
|
|
0,
|
|
&dwType,
|
|
(LPBYTE)pdwLastKnownGoodControlSet,
|
|
&dwSize);
|
|
if (dwError != ERROR_SUCCESS)
|
|
{
|
|
*pdwLastKnownGoodControlSet = 0;
|
|
}
|
|
|
|
RegCloseKey(hSelectKey);
|
|
|
|
DPRINT("ControlSets:\n");
|
|
DPRINT("Current: %lu\n", *pdwCurrentControlSet);
|
|
DPRINT("Default: %lu\n", *pdwDefaultControlSet);
|
|
DPRINT("Failed: %lu\n", *pdwFailedControlSet);
|
|
DPRINT("LastKnownGood: %lu\n", *pdwLastKnownGoodControlSet);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
static
|
|
DWORD
|
|
ScmSetLastKnownGoodControlSet(
|
|
DWORD dwControlSet)
|
|
{
|
|
HKEY hSelectKey;
|
|
DWORD dwError;
|
|
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"System\\Select",
|
|
0,
|
|
KEY_WRITE,
|
|
&hSelectKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
dwError = RegSetValueExW(hSelectKey,
|
|
L"LastKnownGood",
|
|
0,
|
|
REG_DWORD,
|
|
(LPBYTE)&dwControlSet,
|
|
sizeof(dwControlSet));
|
|
|
|
RegFlushKey(hSelectKey);
|
|
RegCloseKey(hSelectKey);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
static
|
|
DWORD
|
|
ScmGetSetupInProgress(VOID)
|
|
{
|
|
DWORD dwError;
|
|
HKEY hKey;
|
|
DWORD dwType;
|
|
DWORD dwSize;
|
|
DWORD dwSetupInProgress = (DWORD)-1;
|
|
|
|
DPRINT("ScmGetSetupInProgress()\n");
|
|
|
|
/* Open key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
L"SYSTEM\\Setup",
|
|
0,
|
|
KEY_QUERY_VALUE,
|
|
&hKey);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
/* Read key */
|
|
dwSize = sizeof(DWORD);
|
|
RegQueryValueExW(hKey,
|
|
L"SystemSetupInProgress",
|
|
NULL,
|
|
&dwType,
|
|
(LPBYTE)&dwSetupInProgress,
|
|
&dwSize);
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
DPRINT("SetupInProgress: %lu\n", dwSetupInProgress);
|
|
return dwSetupInProgress;
|
|
}
|
|
|
|
|
|
static
|
|
DWORD
|
|
ScmCopyControlSet(
|
|
DWORD dwSourceControlSet,
|
|
DWORD dwDestinationControlSet)
|
|
{
|
|
WCHAR szSourceControlSetName[32];
|
|
WCHAR szDestinationControlSetName[32];
|
|
HKEY hSourceControlSetKey = NULL;
|
|
HKEY hDestinationControlSetKey = NULL;
|
|
DWORD dwDisposition;
|
|
DWORD dwError;
|
|
|
|
/* Create the source control set name */
|
|
swprintf(szSourceControlSetName, L"SYSTEM\\ControlSet%03lu", dwSourceControlSet);
|
|
DPRINT("Source control set: %S\n", szSourceControlSetName);
|
|
|
|
/* Create the destination control set name */
|
|
swprintf(szDestinationControlSetName, L"SYSTEM\\ControlSet%03lu", dwDestinationControlSet);
|
|
DPRINT("Destination control set: %S\n", szDestinationControlSetName);
|
|
|
|
/* Open the source control set key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szSourceControlSetName,
|
|
0,
|
|
KEY_READ,
|
|
&hSourceControlSetKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
|
|
/* Create the destination control set key */
|
|
dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
|
|
szDestinationControlSetName,
|
|
0,
|
|
NULL,
|
|
REG_OPTION_NON_VOLATILE,
|
|
KEY_WRITE,
|
|
NULL,
|
|
&hDestinationControlSetKey,
|
|
&dwDisposition);
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
|
|
/* Copy the source control set to the destination control set */
|
|
#if (_WIN32_WINNT >= 0x0600)
|
|
dwError = RegCopyTreeW(hSourceControlSetKey,
|
|
NULL,
|
|
hDestinationControlSetKey);
|
|
#else
|
|
dwError = ScmCopyTree(hSourceControlSetKey,
|
|
hDestinationControlSetKey);
|
|
#endif
|
|
if (dwError != ERROR_SUCCESS)
|
|
goto done;
|
|
|
|
RegFlushKey(hDestinationControlSetKey);
|
|
|
|
done:
|
|
if (hDestinationControlSetKey != NULL)
|
|
RegCloseKey(hDestinationControlSetKey);
|
|
|
|
if (hSourceControlSetKey != NULL)
|
|
RegCloseKey(hSourceControlSetKey);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
static
|
|
DWORD
|
|
ScmDeleteControlSet(
|
|
DWORD dwControlSet)
|
|
{
|
|
WCHAR szControlSetName[32];
|
|
HKEY hControlSetKey = NULL;
|
|
DWORD dwError;
|
|
|
|
DPRINT("ScmDeleteControSet(%lu)\n", dwControlSet);
|
|
|
|
/* Create the control set name */
|
|
swprintf(szControlSetName, L"SYSTEM\\ControlSet%03lu", dwControlSet);
|
|
DPRINT("Control set: %S\n", szControlSetName);
|
|
|
|
/* Open the system key */
|
|
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
|
szControlSetName,
|
|
0,
|
|
DELETE | KEY_ENUMERATE_SUB_KEYS | KEY_QUERY_VALUE | KEY_SET_VALUE,
|
|
&hControlSetKey);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* Delete the control set */
|
|
#if (_WIN32_WINNT >= 0x0600)
|
|
dwError = RegDeleteTreeW(hControlSetKey,
|
|
NULL);
|
|
#else
|
|
dwError = ScmDeleteTree(hControlSetKey,
|
|
NULL);
|
|
#endif
|
|
|
|
/* Open the system key */
|
|
RegCloseKey(hControlSetKey);
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScmCreateLastKnownGoodControlSet(VOID)
|
|
{
|
|
DWORD dwCurrentControlSet, dwDefaultControlSet;
|
|
DWORD dwFailedControlSet, dwLastKnownGoodControlSet;
|
|
DWORD dwNewControlSet;
|
|
DWORD dwError;
|
|
|
|
/* Get the control set values */
|
|
dwError = ScmGetControlSetValues(&dwCurrentControlSet,
|
|
&dwDefaultControlSet,
|
|
&dwFailedControlSet,
|
|
&dwLastKnownGoodControlSet);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* First boot after setup? */
|
|
if ((ScmGetSetupInProgress() == 0) &&
|
|
(dwCurrentControlSet == dwLastKnownGoodControlSet))
|
|
{
|
|
DPRINT("First boot after setup\n");
|
|
|
|
/* Search for a new control set number */
|
|
for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++)
|
|
{
|
|
if ((dwNewControlSet != dwCurrentControlSet) &&
|
|
(dwNewControlSet != dwDefaultControlSet) &&
|
|
(dwNewControlSet != dwFailedControlSet) &&
|
|
(dwNewControlSet != dwLastKnownGoodControlSet))
|
|
break;
|
|
}
|
|
|
|
/* Fail if we did not find an unused control set!*/
|
|
if (dwNewControlSet >= 1000)
|
|
{
|
|
DPRINT1("Too many control sets\n");
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
|
|
/* Copy the current control set */
|
|
dwError = ScmCopyControlSet(dwCurrentControlSet,
|
|
dwNewControlSet);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* Set the new 'LastKnownGood' control set */
|
|
dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet);
|
|
if (dwError == ERROR_SUCCESS)
|
|
{
|
|
/*
|
|
* Accept the boot here in order to prevent the creation of
|
|
* another control set when a user is going to get logged on
|
|
*/
|
|
bBootAccepted = TRUE;
|
|
}
|
|
}
|
|
|
|
return dwError;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScmAcceptBoot(VOID)
|
|
{
|
|
DWORD dwCurrentControlSet, dwDefaultControlSet;
|
|
DWORD dwFailedControlSet, dwLastKnownGoodControlSet;
|
|
DWORD dwNewControlSet;
|
|
DWORD dwError;
|
|
|
|
DPRINT("ScmAcceptBoot()\n");
|
|
|
|
if (bBootAccepted)
|
|
{
|
|
DPRINT1("Boot has already been accepted\n");
|
|
return ERROR_BOOT_ALREADY_ACCEPTED;
|
|
}
|
|
|
|
/* Get the control set values */
|
|
dwError = ScmGetControlSetValues(&dwCurrentControlSet,
|
|
&dwDefaultControlSet,
|
|
&dwFailedControlSet,
|
|
&dwLastKnownGoodControlSet);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* Search for a new control set number */
|
|
for (dwNewControlSet = 1; dwNewControlSet < 1000; dwNewControlSet++)
|
|
{
|
|
if ((dwNewControlSet != dwCurrentControlSet) &&
|
|
(dwNewControlSet != dwDefaultControlSet) &&
|
|
(dwNewControlSet != dwFailedControlSet) &&
|
|
(dwNewControlSet != dwLastKnownGoodControlSet))
|
|
break;
|
|
}
|
|
|
|
/* Fail if we did not find an unused control set!*/
|
|
if (dwNewControlSet >= 1000)
|
|
{
|
|
DPRINT1("Too many control sets\n");
|
|
return ERROR_NO_MORE_ITEMS;
|
|
}
|
|
|
|
/* Copy the current control set */
|
|
dwError = ScmCopyControlSet(dwCurrentControlSet,
|
|
dwNewControlSet);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
/* Delete the current last known good contol set, if it is not used anywhere else */
|
|
if ((dwLastKnownGoodControlSet != dwCurrentControlSet) &&
|
|
(dwLastKnownGoodControlSet != dwDefaultControlSet) &&
|
|
(dwLastKnownGoodControlSet != dwFailedControlSet))
|
|
{
|
|
ScmDeleteControlSet(dwLastKnownGoodControlSet);
|
|
}
|
|
|
|
/* Set the new 'LastKnownGood' control set */
|
|
dwError = ScmSetLastKnownGoodControlSet(dwNewControlSet);
|
|
if (dwError != ERROR_SUCCESS)
|
|
return dwError;
|
|
|
|
bBootAccepted = TRUE;
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
DWORD
|
|
ScmRunLastKnownGood(VOID)
|
|
{
|
|
DPRINT("ScmRunLastKnownGood()\n");
|
|
|
|
if (bBootAccepted)
|
|
{
|
|
DPRINT1("Boot has already been accepted\n");
|
|
return ERROR_BOOT_ALREADY_ACCEPTED;
|
|
}
|
|
|
|
/* FIXME */
|
|
|
|
return ERROR_SUCCESS;
|
|
}
|
|
|
|
/* EOF */
|