mirror of
https://github.com/reactos/reactos.git
synced 2025-08-06 11:43:04 +00:00
723 lines
18 KiB
C
723 lines
18 KiB
C
/* $Id: database.c,v 1.16 2004/04/12 17:20:47 navaraf Exp $
|
|
*
|
|
* service control manager
|
|
*
|
|
* ReactOS Operating System
|
|
*
|
|
* --------------------------------------------------------------------
|
|
*
|
|
* This software is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License as
|
|
* published by the Free Software Foundation; either version 2 of the
|
|
* License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this software; see the file COPYING.LIB. If not, write
|
|
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
|
|
* MA 02139, USA.
|
|
*
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#define NTOS_MODE_USER
|
|
#include <ntos.h>
|
|
#include <rosrtl/string.h>
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
|
|
#include "services.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
|
|
/* TYPES *********************************************************************/
|
|
|
|
typedef struct _SERVICE_GROUP
|
|
{
|
|
LIST_ENTRY GroupListEntry;
|
|
UNICODE_STRING GroupName;
|
|
|
|
BOOLEAN ServicesRunning;
|
|
|
|
} SERVICE_GROUP, *PSERVICE_GROUP;
|
|
|
|
|
|
typedef struct _SERVICE
|
|
{
|
|
LIST_ENTRY ServiceListEntry;
|
|
UNICODE_STRING ServiceName;
|
|
UNICODE_STRING RegistryPath;
|
|
UNICODE_STRING ServiceGroup;
|
|
|
|
ULONG Start;
|
|
ULONG Type;
|
|
ULONG ErrorControl;
|
|
ULONG Tag;
|
|
|
|
BOOLEAN ServiceRunning;
|
|
BOOLEAN ServiceVisited;
|
|
|
|
HANDLE ControlPipeHandle;
|
|
ULONG ProcessId;
|
|
ULONG ThreadId;
|
|
} SERVICE, *PSERVICE;
|
|
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
LIST_ENTRY GroupListHead;
|
|
LIST_ENTRY ServiceListHead;
|
|
|
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
static NTSTATUS STDCALL
|
|
CreateGroupListRoutine(PWSTR ValueName,
|
|
ULONG ValueType,
|
|
PVOID ValueData,
|
|
ULONG ValueLength,
|
|
PVOID Context,
|
|
PVOID EntryContext)
|
|
{
|
|
PSERVICE_GROUP Group;
|
|
|
|
if (ValueType == REG_SZ)
|
|
{
|
|
DPRINT("Data: '%S'\n", (PWCHAR)ValueData);
|
|
|
|
Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
sizeof(SERVICE_GROUP));
|
|
if (Group == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
if (!RtlCreateUnicodeString(&Group->GroupName,
|
|
(PWSTR)ValueData))
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
|
|
InsertTailList(&GroupListHead,
|
|
&Group->GroupListEntry);
|
|
}
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS STDCALL
|
|
CreateServiceListEntry(PUNICODE_STRING ServiceName)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[6];
|
|
PSERVICE Service = NULL;
|
|
NTSTATUS Status;
|
|
|
|
DPRINT("Service: '%wZ'\n", ServiceName);
|
|
|
|
/* Allocate service entry */
|
|
Service = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
sizeof(SERVICE));
|
|
if (Service == NULL)
|
|
{
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
/* Copy service name */
|
|
Service->ServiceName.Length = ServiceName->Length;
|
|
Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
|
|
Service->ServiceName.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
Service->ServiceName.MaximumLength);
|
|
if (Service->ServiceName.Buffer == NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, Service);
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
RtlCopyMemory(Service->ServiceName.Buffer,
|
|
ServiceName->Buffer,
|
|
ServiceName->Length);
|
|
Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
|
|
|
|
/* Build registry path */
|
|
Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
|
|
Service->RegistryPath.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
|
|
MAX_PATH * sizeof(WCHAR));
|
|
if (Service->ServiceName.Buffer == NULL)
|
|
{
|
|
HeapFree(GetProcessHeap(), 0, Service->ServiceName.Buffer);
|
|
HeapFree(GetProcessHeap(), 0, Service);
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
wcscpy(Service->RegistryPath.Buffer,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
|
|
wcscat(Service->RegistryPath.Buffer,
|
|
Service->ServiceName.Buffer);
|
|
Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
|
|
|
|
/* Get service data */
|
|
RtlZeroMemory(&QueryTable,
|
|
sizeof(QueryTable));
|
|
|
|
QueryTable[0].Name = L"Start";
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[0].EntryContext = &Service->Start;
|
|
|
|
QueryTable[1].Name = L"Type";
|
|
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[1].EntryContext = &Service->Type;
|
|
|
|
QueryTable[2].Name = L"ErrorControl";
|
|
QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[2].EntryContext = &Service->ErrorControl;
|
|
|
|
QueryTable[3].Name = L"Group";
|
|
QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
|
|
QueryTable[3].EntryContext = &Service->ServiceGroup;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|
ServiceName->Buffer,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
PrintString("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
|
|
RtlFreeUnicodeString(&Service->RegistryPath);
|
|
RtlFreeUnicodeString(&Service->ServiceName);
|
|
HeapFree(GetProcessHeap(), 0, Service);
|
|
return(Status);
|
|
}
|
|
|
|
DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
|
|
DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
|
|
DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
|
|
DPRINT("Start %lx Type %lx ErrorControl %lx\n",
|
|
Service->Start, Service->Type, Service->ErrorControl);
|
|
|
|
/* Append service entry */
|
|
InsertTailList(&ServiceListHead,
|
|
&Service->ServiceListEntry);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ScmCreateServiceDataBase(VOID)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[2];
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING ServicesKeyName;
|
|
UNICODE_STRING SubKeyName;
|
|
HKEY ServicesKey;
|
|
ULONG Index;
|
|
NTSTATUS Status;
|
|
|
|
PKEY_BASIC_INFORMATION KeyInfo = NULL;
|
|
ULONG KeyInfoLength = 0;
|
|
ULONG ReturnedLength;
|
|
|
|
DPRINT("ScmCreateServiceDataBase() called\n");
|
|
|
|
/* Initialize basic variables */
|
|
InitializeListHead(&GroupListHead);
|
|
InitializeListHead(&ServiceListHead);
|
|
|
|
/* Build group order list */
|
|
RtlZeroMemory(&QueryTable,
|
|
sizeof(QueryTable));
|
|
|
|
QueryTable[0].Name = L"List";
|
|
QueryTable[0].QueryRoutine = CreateGroupListRoutine;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
|
|
L"ServiceGroupOrder",
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status))
|
|
return(Status);
|
|
|
|
RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName,
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&ServicesKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = RtlpNtOpenKey(&ServicesKey,
|
|
0x10001,
|
|
&ObjectAttributes,
|
|
0);
|
|
if (!NT_SUCCESS(Status))
|
|
return(Status);
|
|
|
|
/* Allocate key info buffer */
|
|
KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
|
|
KeyInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KeyInfoLength);
|
|
if (KeyInfo == NULL)
|
|
{
|
|
NtClose(ServicesKey);
|
|
return(STATUS_INSUFFICIENT_RESOURCES);
|
|
}
|
|
|
|
Index = 0;
|
|
while (TRUE)
|
|
{
|
|
Status = NtEnumerateKey(ServicesKey,
|
|
Index,
|
|
KeyBasicInformation,
|
|
KeyInfo,
|
|
KeyInfoLength,
|
|
&ReturnedLength);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
|
|
{
|
|
|
|
SubKeyName.Length = KeyInfo->NameLength;
|
|
SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
|
|
SubKeyName.Buffer = KeyInfo->Name;
|
|
SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
|
|
|
|
DPRINT("KeyName: '%wZ'\n", &SubKeyName);
|
|
Status = CreateServiceListEntry(&SubKeyName);
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
Index++;
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(), 0, KeyInfo);
|
|
NtClose(ServicesKey);
|
|
|
|
DPRINT("ScmCreateServiceDataBase() done\n");
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ScmCheckDriver(PSERVICE Service)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING DirName;
|
|
HANDLE DirHandle;
|
|
NTSTATUS Status;
|
|
PDIRECTORY_BASIC_INFORMATION DirInfo;
|
|
ULONG BufferLength;
|
|
ULONG DataLength;
|
|
ULONG Index;
|
|
PLIST_ENTRY GroupEntry;
|
|
PSERVICE_GROUP CurrentGroup;
|
|
|
|
DPRINT("ScmCheckDriver(%wZ) called\n", &Service->ServiceName);
|
|
|
|
if (Service->Type == SERVICE_KERNEL_DRIVER)
|
|
{
|
|
RtlRosInitUnicodeStringFromLiteral(&DirName,
|
|
L"\\Driver");
|
|
}
|
|
else
|
|
{
|
|
RtlRosInitUnicodeStringFromLiteral(&DirName,
|
|
L"\\FileSystem");
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&DirName,
|
|
0,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = NtOpenDirectoryObject(&DirHandle,
|
|
DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
return(Status);
|
|
}
|
|
|
|
BufferLength = sizeof(DIRECTORY_BASIC_INFORMATION) +
|
|
2 * MAX_PATH * sizeof(WCHAR);
|
|
DirInfo = HeapAlloc(GetProcessHeap(),
|
|
HEAP_ZERO_MEMORY,
|
|
BufferLength);
|
|
|
|
Index = 0;
|
|
while (TRUE)
|
|
{
|
|
Status = NtQueryDirectoryObject(DirHandle,
|
|
DirInfo,
|
|
BufferLength,
|
|
TRUE,
|
|
FALSE,
|
|
&Index,
|
|
&DataLength);
|
|
if (Status == STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
/* FIXME: Add current service to 'failed service' list */
|
|
DPRINT("Service '%wZ' failed\n", &Service->ServiceName);
|
|
break;
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
break;
|
|
|
|
DPRINT("Comparing: '%wZ' '%wZ'\n", &Service->ServiceName, &DirInfo->ObjectName);
|
|
|
|
if (RtlEqualUnicodeString(&Service->ServiceName, &DirInfo->ObjectName, TRUE))
|
|
{
|
|
DPRINT("Found: '%wZ' '%wZ'\n", &Service->ServiceName, &DirInfo->ObjectName);
|
|
|
|
/* Mark service as 'running' */
|
|
Service->ServiceRunning = TRUE;
|
|
|
|
/* Find the driver's group and mark it as 'running' */
|
|
if (Service->ServiceGroup.Buffer != NULL)
|
|
{
|
|
GroupEntry = GroupListHead.Flink;
|
|
while (GroupEntry != &GroupListHead)
|
|
{
|
|
CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
|
|
|
|
DPRINT("Checking group '%wZ'\n", &CurrentGroup->GroupName);
|
|
if (RtlEqualUnicodeString(&Service->ServiceGroup, &CurrentGroup->GroupName, TRUE))
|
|
{
|
|
CurrentGroup->ServicesRunning = TRUE;
|
|
}
|
|
|
|
GroupEntry = GroupEntry->Flink;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
HeapFree(GetProcessHeap(),
|
|
0,
|
|
DirInfo);
|
|
NtClose(DirHandle);
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
ScmGetBootAndSystemDriverState(VOID)
|
|
{
|
|
PLIST_ENTRY ServiceEntry;
|
|
PSERVICE CurrentService;
|
|
|
|
DPRINT("ScmGetBootAndSystemDriverState() called\n");
|
|
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
|
|
if (CurrentService->Start == SERVICE_BOOT_START ||
|
|
CurrentService->Start == SERVICE_SYSTEM_START)
|
|
{
|
|
/* Check driver */
|
|
DPRINT(" Checking service: %wZ\n", &CurrentService->ServiceName);
|
|
|
|
ScmCheckDriver(CurrentService);
|
|
}
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
|
|
DPRINT("ScmGetBootAndSystemDriverState() done\n");
|
|
}
|
|
|
|
|
|
static NTSTATUS
|
|
ScmStartService(PSERVICE Service,
|
|
PSERVICE_GROUP Group)
|
|
{
|
|
RTL_QUERY_REGISTRY_TABLE QueryTable[3];
|
|
PROCESS_INFORMATION ProcessInformation;
|
|
STARTUPINFOW StartupInfo;
|
|
UNICODE_STRING ImagePath;
|
|
NTSTATUS Status;
|
|
ULONG Type;
|
|
BOOL Result;
|
|
|
|
DPRINT("ScmStartService() called\n");
|
|
|
|
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
|
|
DPRINT("Service->Type: %u\n", Service->Type);
|
|
|
|
if (Service->Type == SERVICE_KERNEL_DRIVER ||
|
|
Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
|
|
Service->Type == SERVICE_RECOGNIZER_DRIVER)
|
|
{
|
|
/* Load driver */
|
|
DPRINT(" Path: %wZ\n", &Service->RegistryPath);
|
|
Status = NtLoadDriver(&Service->RegistryPath);
|
|
}
|
|
else
|
|
{
|
|
RtlInitUnicodeString(&ImagePath, NULL);
|
|
|
|
/* Get service data */
|
|
RtlZeroMemory(&QueryTable,
|
|
sizeof(QueryTable));
|
|
|
|
QueryTable[0].Name = L"Type";
|
|
QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[0].EntryContext = &Type;
|
|
|
|
QueryTable[1].Name = L"ImagePath";
|
|
QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
|
|
QueryTable[1].EntryContext = &ImagePath;
|
|
|
|
Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
|
|
Service->ServiceName.Buffer,
|
|
QueryTable,
|
|
NULL,
|
|
NULL);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
|
|
DPRINT("Type: %lx\n", Type);
|
|
|
|
/* FIXME: create '\\.\pipe\net\NtControlPipe' instance */
|
|
Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
|
|
PIPE_ACCESS_DUPLEX,
|
|
PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
|
|
100,
|
|
8000,
|
|
4,
|
|
30000,
|
|
NULL);
|
|
DPRINT("CreateNamedPipeW() done\n");
|
|
if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
|
|
{
|
|
DPRINT1("Failed to create control pipe!\n");
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
goto Done;
|
|
}
|
|
|
|
StartupInfo.cb = sizeof(StartupInfo);
|
|
StartupInfo.lpReserved = NULL;
|
|
StartupInfo.lpDesktop = NULL;
|
|
StartupInfo.lpTitle = NULL;
|
|
StartupInfo.dwFlags = 0;
|
|
StartupInfo.cbReserved2 = 0;
|
|
StartupInfo.lpReserved2 = 0;
|
|
|
|
Result = CreateProcessW(ImagePath.Buffer,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
FALSE,
|
|
DETACHED_PROCESS | CREATE_SUSPENDED,
|
|
NULL,
|
|
NULL,
|
|
&StartupInfo,
|
|
&ProcessInformation);
|
|
RtlFreeUnicodeString(&ImagePath);
|
|
|
|
if (!Result)
|
|
{
|
|
/* Close control pipe */
|
|
CloseHandle(Service->ControlPipeHandle);
|
|
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
|
|
|
|
DPRINT("Starting '%S' failed!\n", Service->ServiceName.Buffer);
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
else
|
|
{
|
|
DPRINT("Process Id: %lu Handle %lx\n",
|
|
ProcessInformation.dwProcessId,
|
|
ProcessInformation.hProcess);
|
|
DPRINT("Thread Id: %lu Handle %lx\n",
|
|
ProcessInformation.dwThreadId,
|
|
ProcessInformation.hThread);
|
|
|
|
/* Get process and thread ids */
|
|
Service->ProcessId = ProcessInformation.dwProcessId;
|
|
Service->ThreadId = ProcessInformation.dwThreadId;
|
|
|
|
/* Resume Thread */
|
|
ResumeThread(ProcessInformation.hThread);
|
|
|
|
/* FIXME: connect control pipe */
|
|
if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
|
|
{
|
|
DPRINT("Control pipe connected!\n");
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
DPRINT1("Connecting control pipe failed!\n");
|
|
|
|
/* Close control pipe */
|
|
CloseHandle(Service->ControlPipeHandle);
|
|
Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
|
|
Service->ProcessId = 0;
|
|
Service->ThreadId = 0;
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* Close process and thread handle */
|
|
CloseHandle(ProcessInformation.hThread);
|
|
CloseHandle(ProcessInformation.hProcess);
|
|
}
|
|
}
|
|
}
|
|
|
|
Done:
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (Group != NULL)
|
|
{
|
|
Group->ServicesRunning = TRUE;
|
|
}
|
|
Service->ServiceRunning = TRUE;
|
|
}
|
|
#if 0
|
|
else
|
|
{
|
|
if (CurrentService->ErrorControl == 1)
|
|
{
|
|
/* Log error */
|
|
|
|
}
|
|
else if (CurrentService->ErrorControl == 2)
|
|
{
|
|
if (IsLastKnownGood == FALSE)
|
|
{
|
|
/* Boot last known good configuration */
|
|
|
|
}
|
|
}
|
|
else if (CurrentService->ErrorControl == 3)
|
|
{
|
|
if (IsLastKnownGood == FALSE)
|
|
{
|
|
/* Boot last known good configuration */
|
|
|
|
}
|
|
else
|
|
{
|
|
/* BSOD! */
|
|
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return(STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
VOID
|
|
ScmAutoStartServices(VOID)
|
|
{
|
|
PLIST_ENTRY GroupEntry;
|
|
PLIST_ENTRY ServiceEntry;
|
|
PSERVICE_GROUP CurrentGroup;
|
|
PSERVICE CurrentService;
|
|
|
|
/* Clear 'ServiceVisited' flag */
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
CurrentService->ServiceVisited = FALSE;
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
|
|
/* Start all services which are members of an existing group */
|
|
GroupEntry = GroupListHead.Flink;
|
|
while (GroupEntry != &GroupListHead)
|
|
{
|
|
CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
|
|
|
|
DPRINT("Group '%wZ'\n", &CurrentGroup->GroupName);
|
|
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
|
|
if ((RtlEqualUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE)) &&
|
|
(CurrentService->Start == SERVICE_AUTO_START) &&
|
|
(CurrentService->ServiceVisited == FALSE))
|
|
{
|
|
CurrentService->ServiceVisited = TRUE;
|
|
ScmStartService(CurrentService,
|
|
CurrentGroup);
|
|
}
|
|
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
|
|
GroupEntry = GroupEntry->Flink;
|
|
}
|
|
|
|
/* Start all services which are members of any non-existing group */
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
|
|
if ((CurrentGroup->GroupName.Length > 0) &&
|
|
(CurrentService->Start == SERVICE_AUTO_START) &&
|
|
(CurrentService->ServiceVisited == FALSE))
|
|
{
|
|
CurrentService->ServiceVisited = TRUE;
|
|
ScmStartService(CurrentService,
|
|
NULL);
|
|
}
|
|
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
|
|
/* Start all services which are not a member of any group */
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
|
|
if ((CurrentGroup->GroupName.Length == 0) &&
|
|
(CurrentService->Start == SERVICE_AUTO_START) &&
|
|
(CurrentService->ServiceVisited == FALSE))
|
|
{
|
|
CurrentService->ServiceVisited = TRUE;
|
|
ScmStartService(CurrentService,
|
|
NULL);
|
|
}
|
|
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
|
|
/* Clear 'ServiceVisited' flag again */
|
|
ServiceEntry = ServiceListHead.Flink;
|
|
while (ServiceEntry != &ServiceListHead)
|
|
{
|
|
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
|
|
CurrentService->ServiceVisited = FALSE;
|
|
ServiceEntry = ServiceEntry->Flink;
|
|
}
|
|
}
|
|
|
|
/* EOF */
|