3 * service control manager
5 * ReactOS Operating System
7 * --------------------------------------------------------------------
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
26 /* INCLUDES *****************************************************************/
28 #define NTOS_MODE_USER
30 #include <rosrtl/string.h>
35 #include <services/services.h>
42 /* TYPES *********************************************************************/
44 typedef struct _SERVICE_GROUP
46 LIST_ENTRY GroupListEntry
;
47 UNICODE_STRING GroupName
;
49 BOOLEAN ServicesRunning
;
53 } SERVICE_GROUP
, *PSERVICE_GROUP
;
58 /* GLOBALS *******************************************************************/
60 LIST_ENTRY GroupListHead
;
61 LIST_ENTRY ServiceListHead
;
64 /* FUNCTIONS *****************************************************************/
67 ScmGetServiceEntryByName(PUNICODE_STRING ServiceName
)
69 PLIST_ENTRY ServiceEntry
;
70 PSERVICE CurrentService
;
72 DPRINT("ScmGetServiceEntryByName() called\n");
74 ServiceEntry
= ServiceListHead
.Flink
;
75 while (ServiceEntry
!= &ServiceListHead
)
77 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
80 if (RtlEqualUnicodeString(&CurrentService
->ServiceName
, ServiceName
, TRUE
))
82 DPRINT("Found service: '%wZ'\n", &CurrentService
->ServiceName
);
83 return CurrentService
;
86 ServiceEntry
= ServiceEntry
->Flink
;
89 DPRINT("Couldn't find a matching service\n");
95 static NTSTATUS STDCALL
96 CreateGroupOrderListRoutine(PWSTR ValueName
,
103 PSERVICE_GROUP Group
;
105 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
106 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
108 if (ValueType
== REG_BINARY
&&
110 ValueLength
>= sizeof(DWORD
) &&
111 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
113 Group
= (PSERVICE_GROUP
)Context
;
114 Group
->TagCount
= ((PULONG
)ValueData
)[0];
115 if (Group
->TagCount
> 0)
117 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
119 Group
->TagArray
= (PULONG
)HeapAlloc(GetProcessHeap(),
121 Group
->TagCount
* sizeof(DWORD
));
122 if (Group
->TagArray
== NULL
)
125 return STATUS_INSUFFICIENT_RESOURCES
;
127 RtlCopyMemory(Group
->TagArray
,
128 (PULONG
)ValueData
+ 1,
129 Group
->TagCount
* sizeof(DWORD
));
134 return STATUS_UNSUCCESSFUL
;
138 return STATUS_SUCCESS
;
142 static NTSTATUS STDCALL
143 CreateGroupListRoutine(PWSTR ValueName
,
150 PSERVICE_GROUP Group
;
151 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
154 if (ValueType
== REG_SZ
)
156 DPRINT("Data: '%S'\n", (PWCHAR
)ValueData
);
158 Group
= (PSERVICE_GROUP
)HeapAlloc(GetProcessHeap(),
160 sizeof(SERVICE_GROUP
));
163 return STATUS_INSUFFICIENT_RESOURCES
;
166 if (!RtlCreateUnicodeString(&Group
->GroupName
,
169 return STATUS_INSUFFICIENT_RESOURCES
;
172 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
173 QueryTable
[0].Name
= (PWSTR
)ValueData
;
174 QueryTable
[0].QueryRoutine
= CreateGroupOrderListRoutine
;
176 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
181 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
184 InsertTailList(&GroupListHead
,
185 &Group
->GroupListEntry
);
188 return STATUS_SUCCESS
;
192 static NTSTATUS STDCALL
193 CreateServiceListEntry(PUNICODE_STRING ServiceName
)
195 RTL_QUERY_REGISTRY_TABLE QueryTable
[6];
196 PSERVICE Service
= NULL
;
199 DPRINT("Service: '%wZ'\n", ServiceName
);
201 /* Allocate service entry */
202 Service
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
206 return STATUS_INSUFFICIENT_RESOURCES
;
209 /* Copy service name */
210 Service
->ServiceName
.Length
= ServiceName
->Length
;
211 Service
->ServiceName
.MaximumLength
= ServiceName
->Length
+ sizeof(WCHAR
);
212 Service
->ServiceName
.Buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
213 Service
->ServiceName
.MaximumLength
);
214 if (Service
->ServiceName
.Buffer
== NULL
)
216 HeapFree(GetProcessHeap(), 0, Service
);
217 return STATUS_INSUFFICIENT_RESOURCES
;
220 RtlCopyMemory(Service
->ServiceName
.Buffer
,
222 ServiceName
->Length
);
223 Service
->ServiceName
.Buffer
[ServiceName
->Length
/ sizeof(WCHAR
)] = 0;
225 /* Build registry path */
226 Service
->RegistryPath
.MaximumLength
= MAX_PATH
* sizeof(WCHAR
);
227 Service
->RegistryPath
.Buffer
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
,
228 MAX_PATH
* sizeof(WCHAR
));
229 if (Service
->ServiceName
.Buffer
== NULL
)
231 HeapFree(GetProcessHeap(), 0, Service
->ServiceName
.Buffer
);
232 HeapFree(GetProcessHeap(), 0, Service
);
233 return STATUS_INSUFFICIENT_RESOURCES
;
236 wcscpy(Service
->RegistryPath
.Buffer
,
237 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
238 wcscat(Service
->RegistryPath
.Buffer
,
239 Service
->ServiceName
.Buffer
);
240 Service
->RegistryPath
.Length
= wcslen(Service
->RegistryPath
.Buffer
) * sizeof(WCHAR
);
242 /* Get service data */
243 RtlZeroMemory(&QueryTable
,
246 QueryTable
[0].Name
= L
"Start";
247 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
248 QueryTable
[0].EntryContext
= &Service
->Start
;
250 QueryTable
[1].Name
= L
"Type";
251 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
252 QueryTable
[1].EntryContext
= &Service
->Type
;
254 QueryTable
[2].Name
= L
"ErrorControl";
255 QueryTable
[2].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
256 QueryTable
[2].EntryContext
= &Service
->ErrorControl
;
258 QueryTable
[3].Name
= L
"Group";
259 QueryTable
[3].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
260 QueryTable
[3].EntryContext
= &Service
->ServiceGroup
;
262 QueryTable
[4].Name
= L
"Tag";
263 QueryTable
[4].Flags
= RTL_QUERY_REGISTRY_DIRECT
;
264 QueryTable
[4].EntryContext
= &Service
->Tag
;
266 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
271 if (!NT_SUCCESS(Status
))
273 PrintString("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
274 RtlFreeUnicodeString(&Service
->RegistryPath
);
275 RtlFreeUnicodeString(&Service
->ServiceName
);
276 HeapFree(GetProcessHeap(), 0, Service
);
280 DPRINT("ServiceName: '%wZ'\n", &Service
->ServiceName
);
281 DPRINT("RegistryPath: '%wZ'\n", &Service
->RegistryPath
);
282 DPRINT("ServiceGroup: '%wZ'\n", &Service
->ServiceGroup
);
283 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
284 Service
->Start
, Service
->Type
, Service
->Tag
, Service
->ErrorControl
);
286 /* Append service entry */
287 InsertTailList(&ServiceListHead
,
288 &Service
->ServiceListEntry
);
290 Service
->CurrentState
= SERVICE_STOPPED
;
291 Service
->ControlsAccepted
= 0;
292 Service
->Win32ExitCode
= 0;
293 Service
->ServiceSpecificExitCode
= 0;
294 Service
->CheckPoint
= 0;
295 Service
->WaitHint
= 2000; /* 2 seconds */
297 return STATUS_SUCCESS
;
302 ScmCreateServiceDataBase(VOID
)
304 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
305 OBJECT_ATTRIBUTES ObjectAttributes
;
306 UNICODE_STRING ServicesKeyName
;
307 UNICODE_STRING SubKeyName
;
312 PKEY_BASIC_INFORMATION KeyInfo
= NULL
;
313 ULONG KeyInfoLength
= 0;
314 ULONG ReturnedLength
;
316 DPRINT("ScmCreateServiceDataBase() called\n");
318 /* Initialize basic variables */
319 InitializeListHead(&GroupListHead
);
320 InitializeListHead(&ServiceListHead
);
322 /* Build group order list */
323 RtlZeroMemory(&QueryTable
,
326 QueryTable
[0].Name
= L
"List";
327 QueryTable
[0].QueryRoutine
= CreateGroupListRoutine
;
329 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
330 L
"ServiceGroupOrder",
334 if (!NT_SUCCESS(Status
))
337 RtlRosInitUnicodeStringFromLiteral(&ServicesKeyName
,
338 L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
340 InitializeObjectAttributes(&ObjectAttributes
,
342 OBJ_CASE_INSENSITIVE
,
346 Status
= RtlpNtOpenKey(&ServicesKey
,
347 KEY_QUERY_VALUE
| KEY_ENUMERATE_SUB_KEYS
,
350 if (!NT_SUCCESS(Status
))
353 /* Allocate key info buffer */
354 KeyInfoLength
= sizeof(KEY_BASIC_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
);
355 KeyInfo
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, KeyInfoLength
);
358 NtClose(ServicesKey
);
359 return STATUS_INSUFFICIENT_RESOURCES
;
365 Status
= NtEnumerateKey(ServicesKey
,
371 if (NT_SUCCESS(Status
))
373 if (KeyInfo
->NameLength
< MAX_PATH
* sizeof(WCHAR
))
376 SubKeyName
.Length
= KeyInfo
->NameLength
;
377 SubKeyName
.MaximumLength
= KeyInfo
->NameLength
+ sizeof(WCHAR
);
378 SubKeyName
.Buffer
= KeyInfo
->Name
;
379 SubKeyName
.Buffer
[SubKeyName
.Length
/ sizeof(WCHAR
)] = 0;
381 DPRINT("KeyName: '%wZ'\n", &SubKeyName
);
382 Status
= CreateServiceListEntry(&SubKeyName
);
384 /* Ignore services without proper registry. */
385 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
387 Status
= STATUS_SUCCESS
;
392 if (!NT_SUCCESS(Status
))
398 HeapFree(GetProcessHeap(), 0, KeyInfo
);
399 NtClose(ServicesKey
);
401 DPRINT("ScmCreateServiceDataBase() done\n");
403 return STATUS_SUCCESS
;
408 ScmCheckDriver(PSERVICE Service
)
410 OBJECT_ATTRIBUTES ObjectAttributes
;
411 UNICODE_STRING DirName
;
414 POBJECT_DIRECTORY_INFORMATION DirInfo
;
418 PLIST_ENTRY GroupEntry
;
419 PSERVICE_GROUP CurrentGroup
;
421 DPRINT("ScmCheckDriver(%wZ) called\n", &Service
->ServiceName
);
423 if (Service
->Type
== SERVICE_KERNEL_DRIVER
)
425 RtlRosInitUnicodeStringFromLiteral(&DirName
,
430 RtlRosInitUnicodeStringFromLiteral(&DirName
,
434 InitializeObjectAttributes(&ObjectAttributes
,
440 Status
= NtOpenDirectoryObject(&DirHandle
,
441 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
443 if (!NT_SUCCESS(Status
))
448 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
449 2 * MAX_PATH
* sizeof(WCHAR
);
450 DirInfo
= HeapAlloc(GetProcessHeap(),
457 Status
= NtQueryDirectoryObject(DirHandle
,
464 if (Status
== STATUS_NO_MORE_ENTRIES
)
466 /* FIXME: Add current service to 'failed service' list */
467 DPRINT("Service '%wZ' failed\n", &Service
->ServiceName
);
471 if (!NT_SUCCESS(Status
))
474 DPRINT("Comparing: '%wZ' '%wZ'\n", &Service
->ServiceName
, &DirInfo
->ObjectName
);
476 if (RtlEqualUnicodeString(&Service
->ServiceName
, &DirInfo
->ObjectName
, TRUE
))
478 DPRINT("Found: '%wZ' '%wZ'\n", &Service
->ServiceName
, &DirInfo
->ObjectName
);
480 /* Mark service as 'running' */
481 Service
->CurrentState
= SERVICE_RUNNING
;
483 /* Find the driver's group and mark it as 'running' */
484 if (Service
->ServiceGroup
.Buffer
!= NULL
)
486 GroupEntry
= GroupListHead
.Flink
;
487 while (GroupEntry
!= &GroupListHead
)
489 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
491 DPRINT("Checking group '%wZ'\n", &CurrentGroup
->GroupName
);
492 if (RtlEqualUnicodeString(&Service
->ServiceGroup
, &CurrentGroup
->GroupName
, TRUE
))
494 CurrentGroup
->ServicesRunning
= TRUE
;
497 GroupEntry
= GroupEntry
->Flink
;
504 HeapFree(GetProcessHeap(),
509 return STATUS_SUCCESS
;
514 ScmGetBootAndSystemDriverState(VOID
)
516 PLIST_ENTRY ServiceEntry
;
517 PSERVICE CurrentService
;
519 DPRINT("ScmGetBootAndSystemDriverState() called\n");
521 ServiceEntry
= ServiceListHead
.Flink
;
522 while (ServiceEntry
!= &ServiceListHead
)
524 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
526 if (CurrentService
->Start
== SERVICE_BOOT_START
||
527 CurrentService
->Start
== SERVICE_SYSTEM_START
)
530 DPRINT(" Checking service: %wZ\n", &CurrentService
->ServiceName
);
532 ScmCheckDriver(CurrentService
);
534 ServiceEntry
= ServiceEntry
->Flink
;
537 DPRINT("ScmGetBootAndSystemDriverState() done\n");
542 ScmSendStartCommand(PSERVICE Service
, LPWSTR Arguments
)
544 PSCM_START_PACKET StartPacket
;
552 DPRINT("ScmSendStartCommand() called\n");
554 /* Calculate the total length of the start command line */
555 TotalLength
= wcslen(Service
->ServiceName
.Buffer
) + 1;
557 if (Arguments
!= NULL
)
562 Length
= wcslen(Ptr
) + 1;
563 TotalLength
+= Length
;
570 /* Allocate start command packet */
571 StartPacket
= HeapAlloc(GetProcessHeap(),
573 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
574 if (StartPacket
== NULL
)
575 return STATUS_INSUFFICIENT_RESOURCES
;
577 StartPacket
->Command
= SCM_START_COMMAND
;
578 StartPacket
->Size
= TotalLength
;
579 Ptr
= &StartPacket
->Arguments
[0];
580 wcscpy(Ptr
, Service
->ServiceName
.Buffer
);
581 Ptr
+= (wcslen(Service
->ServiceName
.Buffer
) + 1);
583 /* FIXME: Copy argument list */
587 /* Send the start command */
588 WriteFile(Service
->ControlPipeHandle
,
590 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
594 /* FIXME: Read the reply */
596 HeapFree(GetProcessHeap(),
600 DPRINT("ScmSendStartCommand() done\n");
602 return STATUS_SUCCESS
;
607 ScmStartUserModeService(PSERVICE Service
)
609 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
610 PROCESS_INFORMATION ProcessInformation
;
611 STARTUPINFOW StartupInfo
;
612 UNICODE_STRING ImagePath
;
617 RtlInitUnicodeString(&ImagePath
, NULL
);
619 /* Get service data */
620 RtlZeroMemory(&QueryTable
,
623 QueryTable
[0].Name
= L
"Type";
624 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
625 QueryTable
[0].EntryContext
= &Type
;
627 QueryTable
[1].Name
= L
"ImagePath";
628 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
629 QueryTable
[1].EntryContext
= &ImagePath
;
631 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
632 Service
->ServiceName
.Buffer
,
636 if (!NT_SUCCESS(Status
))
638 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
641 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
642 DPRINT("Type: %lx\n", Type
);
644 /* Create '\\.\pipe\net\NtControlPipe' instance */
645 Service
->ControlPipeHandle
= CreateNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe",
647 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
653 DPRINT("CreateNamedPipeW() done\n");
654 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
656 DPRINT1("Failed to create control pipe!\n");
657 return STATUS_UNSUCCESSFUL
;
660 StartupInfo
.cb
= sizeof(StartupInfo
);
661 StartupInfo
.lpReserved
= NULL
;
662 StartupInfo
.lpDesktop
= NULL
;
663 StartupInfo
.lpTitle
= NULL
;
664 StartupInfo
.dwFlags
= 0;
665 StartupInfo
.cbReserved2
= 0;
666 StartupInfo
.lpReserved2
= 0;
668 Result
= CreateProcessW(ImagePath
.Buffer
,
673 DETACHED_PROCESS
| CREATE_SUSPENDED
,
677 &ProcessInformation
);
678 RtlFreeUnicodeString(&ImagePath
);
682 /* Close control pipe */
683 CloseHandle(Service
->ControlPipeHandle
);
684 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
686 DPRINT1("Starting '%S' failed!\n", Service
->ServiceName
.Buffer
);
687 return STATUS_UNSUCCESSFUL
;
690 DPRINT("Process Id: %lu Handle %lx\n",
691 ProcessInformation
.dwProcessId
,
692 ProcessInformation
.hProcess
);
693 DPRINT("Thread Id: %lu Handle %lx\n",
694 ProcessInformation
.dwThreadId
,
695 ProcessInformation
.hThread
);
697 /* Get process and thread ids */
698 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
699 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
702 ResumeThread(ProcessInformation
.hThread
);
704 /* Connect control pipe */
705 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
))
707 DWORD dwProcessId
= 0;
710 DPRINT("Control pipe connected!\n");
712 /* Read thread id from pipe */
713 if (!ReadFile(Service
->ControlPipeHandle
,
714 (LPVOID
)&dwProcessId
,
719 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
721 Status
= STATUS_UNSUCCESSFUL
;
725 DPRINT("Received process id %lu\n", dwProcessId
);
727 /* FIXME: Send start command */
729 Status
= STATUS_SUCCESS
;
734 DPRINT("Connecting control pipe failed!\n");
736 /* Close control pipe */
737 CloseHandle(Service
->ControlPipeHandle
);
738 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
739 Service
->ProcessId
= 0;
740 Service
->ThreadId
= 0;
741 Status
= STATUS_UNSUCCESSFUL
;
744 ScmSendStartCommand(Service
, NULL
);
746 /* Close process and thread handle */
747 CloseHandle(ProcessInformation
.hThread
);
748 CloseHandle(ProcessInformation
.hProcess
);
755 ScmStartService(PSERVICE Service
,
756 PSERVICE_GROUP Group
)
760 DPRINT("ScmStartService() called\n");
762 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
763 DPRINT("Service->Type: %u\n", Service
->Type
);
765 if (Service
->Type
== SERVICE_KERNEL_DRIVER
||
766 Service
->Type
== SERVICE_FILE_SYSTEM_DRIVER
||
767 Service
->Type
== SERVICE_RECOGNIZER_DRIVER
)
770 DPRINT(" Path: %wZ\n", &Service
->RegistryPath
);
771 Status
= NtLoadDriver(&Service
->RegistryPath
);
775 /* Start user-mode service */
776 Status
= ScmStartUserModeService(Service
);
779 DPRINT("ScmStartService() done (Status %lx)\n", Status
);
781 if (NT_SUCCESS(Status
))
785 Group
->ServicesRunning
= TRUE
;
787 Service
->CurrentState
= SERVICE_RUNNING
;
792 switch (Service
->ErrorControl
)
794 case SERVICE_ERROR_NORMAL
:
795 /* FIXME: Log error */
798 case SERVICE_ERROR_SEVERE
:
799 if (IsLastKnownGood
== FALSE
)
801 /* FIXME: Boot last known good configuration */
805 case SERVICE_ERROR_CRITICAL
:
806 if (IsLastKnownGood
== FALSE
)
808 /* FIXME: Boot last known good configuration */
824 ScmAutoStartServices(VOID
)
826 PLIST_ENTRY GroupEntry
;
827 PLIST_ENTRY ServiceEntry
;
828 PSERVICE_GROUP CurrentGroup
;
829 PSERVICE CurrentService
;
832 /* Clear 'ServiceVisited' flag */
833 ServiceEntry
= ServiceListHead
.Flink
;
834 while (ServiceEntry
!= &ServiceListHead
)
836 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
837 CurrentService
->ServiceVisited
= FALSE
;
838 ServiceEntry
= ServiceEntry
->Flink
;
841 /* Start all services which are members of an existing group */
842 GroupEntry
= GroupListHead
.Flink
;
843 while (GroupEntry
!= &GroupListHead
)
845 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
847 DPRINT("Group '%wZ'\n", &CurrentGroup
->GroupName
);
849 /* Start all services witch have a valid tag */
850 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
852 ServiceEntry
= ServiceListHead
.Flink
;
853 while (ServiceEntry
!= &ServiceListHead
)
855 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
857 if ((RtlEqualUnicodeString(&CurrentGroup
->GroupName
, &CurrentService
->ServiceGroup
, TRUE
)) &&
858 (CurrentService
->Start
== SERVICE_AUTO_START
) &&
859 (CurrentService
->ServiceVisited
== FALSE
) &&
860 (CurrentService
->Tag
== CurrentGroup
->TagArray
[i
]))
862 CurrentService
->ServiceVisited
= TRUE
;
863 ScmStartService(CurrentService
,
867 ServiceEntry
= ServiceEntry
->Flink
;
871 /* Start all services which have an invalid tag or which do not have a tag */
872 ServiceEntry
= ServiceListHead
.Flink
;
873 while (ServiceEntry
!= &ServiceListHead
)
875 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
877 if ((RtlEqualUnicodeString(&CurrentGroup
->GroupName
, &CurrentService
->ServiceGroup
, TRUE
)) &&
878 (CurrentService
->Start
== SERVICE_AUTO_START
) &&
879 (CurrentService
->ServiceVisited
== FALSE
))
881 CurrentService
->ServiceVisited
= TRUE
;
882 ScmStartService(CurrentService
,
886 ServiceEntry
= ServiceEntry
->Flink
;
889 GroupEntry
= GroupEntry
->Flink
;
892 /* Start all services which are members of any non-existing group */
893 ServiceEntry
= ServiceListHead
.Flink
;
894 while (ServiceEntry
!= &ServiceListHead
)
896 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
898 if ((CurrentService
->ServiceGroup
.Length
!= 0) &&
899 (CurrentService
->Start
== SERVICE_AUTO_START
) &&
900 (CurrentService
->ServiceVisited
== FALSE
))
902 CurrentService
->ServiceVisited
= TRUE
;
903 ScmStartService(CurrentService
,
907 ServiceEntry
= ServiceEntry
->Flink
;
910 /* Start all services which are not a member of any group */
911 ServiceEntry
= ServiceListHead
.Flink
;
912 while (ServiceEntry
!= &ServiceListHead
)
914 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
916 if ((CurrentService
->ServiceGroup
.Length
== 0) &&
917 (CurrentService
->Start
== SERVICE_AUTO_START
) &&
918 (CurrentService
->ServiceVisited
== FALSE
))
920 CurrentService
->ServiceVisited
= TRUE
;
921 ScmStartService(CurrentService
,
925 ServiceEntry
= ServiceEntry
->Flink
;
928 /* Clear 'ServiceVisited' flag again */
929 ServiceEntry
= ServiceListHead
.Flink
;
930 while (ServiceEntry
!= &ServiceListHead
)
932 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
933 CurrentService
->ServiceVisited
= FALSE
;
934 ServiceEntry
= ServiceEntry
->Flink
;