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 *****************************************************************/
34 /* TYPES *********************************************************************/
36 typedef struct _SERVICE_GROUP
38 LIST_ENTRY GroupListEntry
;
39 UNICODE_STRING GroupName
;
41 BOOLEAN ServicesRunning
;
45 } SERVICE_GROUP
, *PSERVICE_GROUP
;
48 /* GLOBALS *******************************************************************/
50 LIST_ENTRY GroupListHead
;
51 LIST_ENTRY ServiceListHead
;
53 static RTL_RESOURCE DatabaseLock
;
56 /* FUNCTIONS *****************************************************************/
59 ScmGetServiceEntryByName(LPWSTR lpServiceName
)
61 PLIST_ENTRY ServiceEntry
;
62 PSERVICE CurrentService
;
64 DPRINT("ScmGetServiceEntryByName() called\n");
66 ServiceEntry
= ServiceListHead
.Flink
;
67 while (ServiceEntry
!= &ServiceListHead
)
69 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
72 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
74 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
75 return CurrentService
;
78 ServiceEntry
= ServiceEntry
->Flink
;
81 DPRINT("Couldn't find a matching service\n");
88 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName
)
90 PLIST_ENTRY ServiceEntry
;
91 PSERVICE CurrentService
;
93 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
95 ServiceEntry
= ServiceListHead
.Flink
;
96 while (ServiceEntry
!= &ServiceListHead
)
98 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
101 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
103 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
104 return CurrentService
;
107 ServiceEntry
= ServiceEntry
->Flink
;
110 DPRINT("Couldn't find a matching service\n");
116 static NTSTATUS STDCALL
117 CreateGroupOrderListRoutine(PWSTR ValueName
,
124 PSERVICE_GROUP Group
;
126 DPRINT("CreateGroupOrderListRoutine(%S, %x, %x, %x, %x, %x)\n",
127 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
129 if (ValueType
== REG_BINARY
&&
131 ValueLength
>= sizeof(DWORD
) &&
132 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
134 Group
= (PSERVICE_GROUP
)Context
;
135 Group
->TagCount
= ((PULONG
)ValueData
)[0];
136 if (Group
->TagCount
> 0)
138 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
140 Group
->TagArray
= (PULONG
)HeapAlloc(GetProcessHeap(),
142 Group
->TagCount
* sizeof(DWORD
));
143 if (Group
->TagArray
== NULL
)
146 return STATUS_INSUFFICIENT_RESOURCES
;
149 RtlCopyMemory(Group
->TagArray
,
150 (PULONG
)ValueData
+ 1,
151 Group
->TagCount
* sizeof(DWORD
));
156 return STATUS_UNSUCCESSFUL
;
161 return STATUS_SUCCESS
;
165 static NTSTATUS STDCALL
166 CreateGroupListRoutine(PWSTR ValueName
,
173 PSERVICE_GROUP Group
;
174 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
177 if (ValueType
== REG_SZ
)
179 DPRINT("Data: '%S'\n", (PWCHAR
)ValueData
);
181 Group
= (PSERVICE_GROUP
)HeapAlloc(GetProcessHeap(),
183 sizeof(SERVICE_GROUP
));
186 return STATUS_INSUFFICIENT_RESOURCES
;
189 if (!RtlCreateUnicodeString(&Group
->GroupName
,
192 return STATUS_INSUFFICIENT_RESOURCES
;
195 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
196 QueryTable
[0].Name
= (PWSTR
)ValueData
;
197 QueryTable
[0].QueryRoutine
= CreateGroupOrderListRoutine
;
199 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
204 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
206 InsertTailList(&GroupListHead
,
207 &Group
->GroupListEntry
);
210 return STATUS_SUCCESS
;
215 ScmCreateNewServiceRecord(LPWSTR lpServiceName
,
216 PSERVICE
*lpServiceRecord
)
218 PSERVICE lpService
= NULL
;
220 DPRINT("Service: '%S'\n", lpServiceName
);
222 /* Allocate service entry */
223 lpService
= HeapAlloc(GetProcessHeap(),
225 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
226 if (lpService
== NULL
)
227 return ERROR_NOT_ENOUGH_MEMORY
;
229 *lpServiceRecord
= lpService
;
231 /* Copy service name */
232 wcscpy(lpService
->szServiceName
, lpServiceName
);
233 lpService
->lpServiceName
= lpService
->szServiceName
;
234 lpService
->lpDisplayName
= lpService
->lpServiceName
;
236 /* Append service entry */
237 InsertTailList(&ServiceListHead
,
238 &lpService
->ServiceListEntry
);
240 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
241 lpService
->Status
.dwControlsAccepted
= 0;
242 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
243 lpService
->Status
.dwServiceSpecificExitCode
= 0;
244 lpService
->Status
.dwCheckPoint
= 0;
245 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
247 return ERROR_SUCCESS
;
252 CreateServiceListEntry(LPWSTR lpServiceName
,
255 PSERVICE lpService
= NULL
;
256 LPWSTR lpDisplayName
= NULL
;
257 LPWSTR lpGroup
= NULL
;
262 DWORD dwErrorControl
;
265 DPRINT("Service: '%S'\n", lpServiceName
);
266 if (*lpServiceName
== L
'{')
267 return ERROR_SUCCESS
;
269 dwSize
= sizeof(DWORD
);
270 dwError
= RegQueryValueExW(hServiceKey
,
274 (LPBYTE
)&dwServiceType
,
276 if (dwError
!= ERROR_SUCCESS
)
277 return ERROR_SUCCESS
;
279 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
280 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
281 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
282 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
283 return ERROR_SUCCESS
;
285 DPRINT("Service type: %lx\n", dwServiceType
);
287 dwSize
= sizeof(DWORD
);
288 dwError
= RegQueryValueExW(hServiceKey
,
292 (LPBYTE
)&dwStartType
,
294 if (dwError
!= ERROR_SUCCESS
)
295 return ERROR_SUCCESS
;
297 DPRINT("Start type: %lx\n", dwStartType
);
299 dwSize
= sizeof(DWORD
);
300 dwError
= RegQueryValueExW(hServiceKey
,
304 (LPBYTE
)&dwErrorControl
,
306 if (dwError
!= ERROR_SUCCESS
)
307 return ERROR_SUCCESS
;
309 DPRINT("Error control: %lx\n", dwErrorControl
);
311 dwError
= RegQueryValueExW(hServiceKey
,
317 if (dwError
!= ERROR_SUCCESS
)
320 DPRINT("Tag: %lx\n", dwTagId
);
322 dwError
= ScmReadString(hServiceKey
,
325 if (dwError
!= ERROR_SUCCESS
)
328 DPRINT("Group: %S\n", lpGroup
);
330 dwError
= ScmReadString(hServiceKey
,
333 if (dwError
!= ERROR_SUCCESS
)
334 lpDisplayName
= NULL
;
336 DPRINT("Display name: %S\n", lpDisplayName
);
338 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
340 if (dwError
!= ERROR_SUCCESS
)
343 lpService
->Status
.dwServiceType
= dwServiceType
;
344 lpService
->dwStartType
= dwStartType
;
345 lpService
->dwErrorControl
= dwErrorControl
;
346 lpService
->dwTag
= dwTagId
;
350 lpService
->lpServiceGroup
= lpGroup
;
354 if (lpDisplayName
!= NULL
)
356 lpService
->lpDisplayName
= lpDisplayName
;
357 lpDisplayName
= NULL
;
360 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
361 DPRINT("Group: '%S'\n", lpService
->lpServiceGroup
);
362 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
363 lpService
->dwStartType
,
364 lpService
->Status
.dwServiceType
,
366 lpService
->dwErrorControl
);
368 if (ScmIsDeleteFlagSet(hServiceKey
))
369 lpService
->bDeleted
= TRUE
;
373 HeapFree(GetProcessHeap(), 0, lpGroup
);
375 if (lpDisplayName
!= NULL
)
376 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
383 ScmReadGroupList(VOID
)
385 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
388 InitializeListHead(&GroupListHead
);
390 /* Build group order list */
391 RtlZeroMemory(&QueryTable
,
394 QueryTable
[0].Name
= L
"List";
395 QueryTable
[0].QueryRoutine
= CreateGroupListRoutine
;
397 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
398 L
"ServiceGroupOrder",
403 return RtlNtStatusToDosError(Status
);
408 ScmDeleteMarkedServices(VOID
)
410 PLIST_ENTRY ServiceEntry
;
411 PSERVICE CurrentService
;
413 ServiceEntry
= ServiceListHead
.Flink
;
414 while (ServiceEntry
!= &ServiceListHead
)
416 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
418 ServiceEntry
= ServiceEntry
->Flink
;
420 if (CurrentService
->bDeleted
== TRUE
)
422 DPRINT1("Delete service: %S\n", CurrentService
->lpServiceName
);
424 /* FIXME: Delete the registry keys */
426 /* FIXME: Delete the service record from the list */
434 ScmCreateServiceDatabase(VOID
)
436 WCHAR szSubKey
[MAX_PATH
];
440 DWORD dwSubKeyLength
;
441 FILETIME ftLastChanged
;
444 DPRINT("ScmCreateServiceDatabase() called\n");
446 dwError
= ScmReadGroupList();
447 if (dwError
!= ERROR_SUCCESS
)
450 /* Initialize basic variables */
451 InitializeListHead(&ServiceListHead
);
453 /* Initialize the database lock */
454 RtlInitializeResource(&DatabaseLock
);
456 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
457 L
"System\\CurrentControlSet\\Services",
461 if (dwError
!= ERROR_SUCCESS
)
467 dwSubKeyLength
= MAX_PATH
;
468 dwError
= RegEnumKeyExW(hServicesKey
,
476 if (dwError
== ERROR_SUCCESS
&&
479 DPRINT("SubKeyName: '%S'\n", szSubKey
);
481 dwError
= RegOpenKeyExW(hServicesKey
,
486 if (dwError
== ERROR_SUCCESS
)
488 dwError
= CreateServiceListEntry(szSubKey
,
491 RegCloseKey(hServiceKey
);
495 if (dwError
!= ERROR_SUCCESS
)
501 RegCloseKey(hServicesKey
);
503 /* Delete services that are marked for delete */
504 ScmDeleteMarkedServices();
506 DPRINT("ScmCreateServiceDatabase() done\n");
508 return ERROR_SUCCESS
;
513 ScmCheckDriver(PSERVICE Service
)
515 OBJECT_ATTRIBUTES ObjectAttributes
;
516 UNICODE_STRING DirName
;
519 POBJECT_DIRECTORY_INFORMATION DirInfo
;
523 PLIST_ENTRY GroupEntry
;
524 PSERVICE_GROUP CurrentGroup
;
526 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
528 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
530 RtlInitUnicodeString(&DirName
,
535 RtlInitUnicodeString(&DirName
,
539 InitializeObjectAttributes(&ObjectAttributes
,
545 Status
= NtOpenDirectoryObject(&DirHandle
,
546 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
548 if (!NT_SUCCESS(Status
))
553 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
554 2 * MAX_PATH
* sizeof(WCHAR
);
555 DirInfo
= HeapAlloc(GetProcessHeap(),
562 Status
= NtQueryDirectoryObject(DirHandle
,
569 if (Status
== STATUS_NO_MORE_ENTRIES
)
571 /* FIXME: Add current service to 'failed service' list */
572 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
576 if (!NT_SUCCESS(Status
))
579 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->ObjectName
);
581 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->ObjectName
.Buffer
) == 0)
583 DPRINT("Found: '%S' '%wZ'\n",
584 Service
->lpServiceName
, &DirInfo
->ObjectName
);
586 /* Mark service as 'running' */
587 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
589 /* Find the driver's group and mark it as 'running' */
590 if (Service
->lpServiceGroup
!= NULL
)
592 GroupEntry
= GroupListHead
.Flink
;
593 while (GroupEntry
!= &GroupListHead
)
595 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
597 DPRINT("Checking group '%wZ'\n", &CurrentGroup
->GroupName
);
598 if (Service
->lpServiceGroup
!= NULL
&&
599 _wcsicmp(Service
->lpServiceGroup
, CurrentGroup
->GroupName
.Buffer
) == 0)
601 CurrentGroup
->ServicesRunning
= TRUE
;
604 GroupEntry
= GroupEntry
->Flink
;
611 HeapFree(GetProcessHeap(),
616 return STATUS_SUCCESS
;
621 ScmGetBootAndSystemDriverState(VOID
)
623 PLIST_ENTRY ServiceEntry
;
624 PSERVICE CurrentService
;
626 DPRINT("ScmGetBootAndSystemDriverState() called\n");
628 ServiceEntry
= ServiceListHead
.Flink
;
629 while (ServiceEntry
!= &ServiceListHead
)
631 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
633 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
634 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
637 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
639 ScmCheckDriver(CurrentService
);
642 ServiceEntry
= ServiceEntry
->Flink
;
645 DPRINT("ScmGetBootAndSystemDriverState() done\n");
650 ScmSendStartCommand(PSERVICE Service
, LPWSTR Arguments
)
652 PSCM_START_PACKET StartPacket
;
660 DPRINT("ScmSendStartCommand() called\n");
662 /* Calculate the total length of the start command line */
663 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
665 if (Arguments
!= NULL
)
670 Length
= wcslen(Ptr
) + 1;
671 TotalLength
+= Length
;
678 /* Allocate start command packet */
679 StartPacket
= HeapAlloc(GetProcessHeap(),
681 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
682 if (StartPacket
== NULL
)
683 return STATUS_INSUFFICIENT_RESOURCES
;
685 StartPacket
->Command
= SCM_START_COMMAND
;
686 StartPacket
->Size
= TotalLength
;
687 Ptr
= &StartPacket
->Arguments
[0];
688 wcscpy(Ptr
, Service
->lpServiceName
);
689 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
691 /* FIXME: Copy argument list */
695 /* Send the start command */
696 WriteFile(Service
->ControlPipeHandle
,
698 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
702 /* FIXME: Read the reply */
704 HeapFree(GetProcessHeap(),
708 DPRINT("ScmSendStartCommand() done\n");
710 return STATUS_SUCCESS
;
715 ScmStartUserModeService(PSERVICE Service
)
717 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
718 PROCESS_INFORMATION ProcessInformation
;
719 STARTUPINFOW StartupInfo
;
720 UNICODE_STRING ImagePath
;
725 RtlInitUnicodeString(&ImagePath
, NULL
);
727 /* Get service data */
728 RtlZeroMemory(&QueryTable
,
731 QueryTable
[0].Name
= L
"Type";
732 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
733 QueryTable
[0].EntryContext
= &Type
;
735 QueryTable
[1].Name
= L
"ImagePath";
736 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
737 QueryTable
[1].EntryContext
= &ImagePath
;
739 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
740 Service
->lpServiceName
,
744 if (!NT_SUCCESS(Status
))
746 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
749 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
750 DPRINT("Type: %lx\n", Type
);
752 /* Create '\\.\pipe\net\NtControlPipe' instance */
753 Service
->ControlPipeHandle
= CreateNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe",
755 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
761 DPRINT("CreateNamedPipeW() done\n");
762 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
764 DPRINT1("Failed to create control pipe!\n");
765 return STATUS_UNSUCCESSFUL
;
768 StartupInfo
.cb
= sizeof(StartupInfo
);
769 StartupInfo
.lpReserved
= NULL
;
770 StartupInfo
.lpDesktop
= NULL
;
771 StartupInfo
.lpTitle
= NULL
;
772 StartupInfo
.dwFlags
= 0;
773 StartupInfo
.cbReserved2
= 0;
774 StartupInfo
.lpReserved2
= 0;
776 Result
= CreateProcessW(ImagePath
.Buffer
,
781 DETACHED_PROCESS
| CREATE_SUSPENDED
,
785 &ProcessInformation
);
786 RtlFreeUnicodeString(&ImagePath
);
790 /* Close control pipe */
791 CloseHandle(Service
->ControlPipeHandle
);
792 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
794 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
795 return STATUS_UNSUCCESSFUL
;
798 DPRINT("Process Id: %lu Handle %lx\n",
799 ProcessInformation
.dwProcessId
,
800 ProcessInformation
.hProcess
);
801 DPRINT("Thread Id: %lu Handle %lx\n",
802 ProcessInformation
.dwThreadId
,
803 ProcessInformation
.hThread
);
805 /* Get process and thread ids */
806 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
807 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
810 ResumeThread(ProcessInformation
.hThread
);
812 /* Connect control pipe */
813 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
))
815 DWORD dwProcessId
= 0;
818 DPRINT("Control pipe connected!\n");
820 /* Read thread id from pipe */
821 if (!ReadFile(Service
->ControlPipeHandle
,
822 (LPVOID
)&dwProcessId
,
827 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
829 Status
= STATUS_UNSUCCESSFUL
;
833 DPRINT("Received process id %lu\n", dwProcessId
);
835 /* FIXME: Send start command */
837 Status
= STATUS_SUCCESS
;
842 DPRINT("Connecting control pipe failed!\n");
844 /* Close control pipe */
845 CloseHandle(Service
->ControlPipeHandle
);
846 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
847 Service
->ProcessId
= 0;
848 Service
->ThreadId
= 0;
849 Status
= STATUS_UNSUCCESSFUL
;
852 ScmSendStartCommand(Service
, NULL
);
854 /* Close process and thread handle */
855 CloseHandle(ProcessInformation
.hThread
);
856 CloseHandle(ProcessInformation
.hProcess
);
863 ScmStartService(PSERVICE Service
,
864 PSERVICE_GROUP Group
)
868 DPRINT("ScmStartService() called\n");
870 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
871 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
873 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
876 Status
= ScmLoadDriver(Service
);
877 if (Status
== STATUS_SUCCESS
)
878 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
882 /* Start user-mode service */
883 Status
= ScmStartUserModeService(Service
);
886 DPRINT("ScmStartService() done (Status %lx)\n", Status
);
888 if (NT_SUCCESS(Status
))
892 Group
->ServicesRunning
= TRUE
;
894 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
899 switch (Service
->ErrorControl
)
901 case SERVICE_ERROR_NORMAL
:
902 /* FIXME: Log error */
905 case SERVICE_ERROR_SEVERE
:
906 if (IsLastKnownGood
== FALSE
)
908 /* FIXME: Boot last known good configuration */
912 case SERVICE_ERROR_CRITICAL
:
913 if (IsLastKnownGood
== FALSE
)
915 /* FIXME: Boot last known good configuration */
931 ScmAutoStartServices(VOID
)
933 PLIST_ENTRY GroupEntry
;
934 PLIST_ENTRY ServiceEntry
;
935 PSERVICE_GROUP CurrentGroup
;
936 PSERVICE CurrentService
;
939 /* Clear 'ServiceVisited' flag */
940 ServiceEntry
= ServiceListHead
.Flink
;
941 while (ServiceEntry
!= &ServiceListHead
)
943 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
944 CurrentService
->ServiceVisited
= FALSE
;
945 ServiceEntry
= ServiceEntry
->Flink
;
948 /* Start all services which are members of an existing group */
949 GroupEntry
= GroupListHead
.Flink
;
950 while (GroupEntry
!= &GroupListHead
)
952 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
954 DPRINT("Group '%wZ'\n", &CurrentGroup
->GroupName
);
956 /* Start all services witch have a valid tag */
957 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
959 ServiceEntry
= ServiceListHead
.Flink
;
960 while (ServiceEntry
!= &ServiceListHead
)
962 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
964 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
965 (_wcsicmp(CurrentGroup
->GroupName
.Buffer
, CurrentService
->lpServiceGroup
) == 0) &&
966 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
967 (CurrentService
->ServiceVisited
== FALSE
) &&
968 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
970 CurrentService
->ServiceVisited
= TRUE
;
971 ScmStartService(CurrentService
,
975 ServiceEntry
= ServiceEntry
->Flink
;
979 /* Start all services which have an invalid tag or which do not have a tag */
980 ServiceEntry
= ServiceListHead
.Flink
;
981 while (ServiceEntry
!= &ServiceListHead
)
983 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
985 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
986 (_wcsicmp(CurrentGroup
->GroupName
.Buffer
, CurrentService
->lpServiceGroup
) == 0) &&
987 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
988 (CurrentService
->ServiceVisited
== FALSE
))
990 CurrentService
->ServiceVisited
= TRUE
;
991 ScmStartService(CurrentService
,
995 ServiceEntry
= ServiceEntry
->Flink
;
998 GroupEntry
= GroupEntry
->Flink
;
1001 /* Start all services which are members of any non-existing group */
1002 ServiceEntry
= ServiceListHead
.Flink
;
1003 while (ServiceEntry
!= &ServiceListHead
)
1005 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1007 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
1008 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1009 (CurrentService
->ServiceVisited
== FALSE
))
1011 CurrentService
->ServiceVisited
= TRUE
;
1012 ScmStartService(CurrentService
,
1016 ServiceEntry
= ServiceEntry
->Flink
;
1019 /* Start all services which are not a member of any group */
1020 ServiceEntry
= ServiceListHead
.Flink
;
1021 while (ServiceEntry
!= &ServiceListHead
)
1023 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1025 if ((CurrentService
->lpServiceGroup
== NULL
) &&
1026 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1027 (CurrentService
->ServiceVisited
== FALSE
))
1029 CurrentService
->ServiceVisited
= TRUE
;
1030 ScmStartService(CurrentService
,
1034 ServiceEntry
= ServiceEntry
->Flink
;
1037 /* Clear 'ServiceVisited' flag again */
1038 ServiceEntry
= ServiceListHead
.Flink
;
1039 while (ServiceEntry
!= &ServiceListHead
)
1041 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1042 CurrentService
->ServiceVisited
= FALSE
;
1043 ServiceEntry
= ServiceEntry
->Flink
;