https://git.reactos.org/?p=reactos.git;a=commitdiff;h=26e1afaffc63c99f5a7fd…
commit 26e1afaffc63c99f5a7fde08b86c883bc523deb0
Author: Eric Kohl <eric.kohl(a)reactos.org>
AuthorDate: Sat Aug 10 14:24:11 2019 +0200
Commit: Eric Kohl <eric.kohl(a)reactos.org>
CommitDate: Sat Aug 10 14:24:11 2019 +0200
[SERVICES] Improvements to registry control sets
- Add a function that creates a new control set and deletes unused control sets in
case of a successful boot.
- Add a stub function that will soon switch to the last known good control set in case
of an unsuccessful boot.
---
base/system/services/controlset.c | 240 ++++++++++++++++++++++++++++++++++++++
base/system/services/rpcserver.c | 10 +-
base/system/services/services.h | 6 +
3 files changed, 252 insertions(+), 4 deletions(-)
diff --git a/base/system/services/controlset.c b/base/system/services/controlset.c
index ad43aa2658a..e9ac8ddc7e2 100644
--- a/base/system/services/controlset.c
+++ b/base/system/services/controlset.c
@@ -17,6 +17,8 @@
/* GLOBALS *******************************************************************/
+static BOOL bBootAccepted = FALSE;
+
/* FUNCTIONS *****************************************************************/
@@ -240,6 +242,113 @@ ScmCopyTree(
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
@@ -460,6 +569,46 @@ done:
}
+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)
{
@@ -507,9 +656,100 @@ ScmCreateLastKnownGoodControlSet(VOID)
/* 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 alread 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 alread been accepted!\n");
+ return ERROR_BOOT_ALREADY_ACCEPTED;
+ }
+
+ /* FIXME */
+
+ return ERROR_SUCCESS;
+}
+
/* EOF */
diff --git a/base/system/services/rpcserver.c b/base/system/services/rpcserver.c
index 83d83dd9c9b..0c1dbcfb08a 100644
--- a/base/system/services/rpcserver.c
+++ b/base/system/services/rpcserver.c
@@ -1848,11 +1848,13 @@ RNotifyBootConfigStatus(
SVCCTL_HANDLEW lpMachineName,
DWORD BootAcceptable)
{
- DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName,
BootAcceptable);
- return ERROR_SUCCESS;
+ DPRINT("RNotifyBootConfigStatus(%p %lu)\n",
+ lpMachineName, BootAcceptable);
+
+ if (BootAcceptable)
+ return ScmAcceptBoot();
-// UNIMPLEMENTED;
-// return ERROR_CALL_NOT_IMPLEMENTED;
+ return ScmRunLastKnownGood();
}
diff --git a/base/system/services/services.h b/base/system/services/services.h
index 647df6a0da0..6e3ca20e11b 100644
--- a/base/system/services/services.h
+++ b/base/system/services/services.h
@@ -164,6 +164,12 @@ ScmDecryptPassword(
DWORD
ScmCreateLastKnownGoodControlSet(VOID);
+DWORD
+ScmAcceptBoot(VOID);
+
+DWORD
+ScmRunLastKnownGood(VOID);
+
/* database.c */