reactos/base/system/services/controlset.c
Joachim Henze d31a557237 [SERVICES] Tweak the binary size a bit CORE-18071
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.
2022-03-20 20:12:56 +01:00

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 */