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
;
54 static DWORD dwResumeCount
= 1;
57 /* FUNCTIONS *****************************************************************/
60 ScmGetServiceEntryByName(LPWSTR lpServiceName
)
62 PLIST_ENTRY ServiceEntry
;
63 PSERVICE CurrentService
;
65 DPRINT("ScmGetServiceEntryByName() called\n");
67 ServiceEntry
= ServiceListHead
.Flink
;
68 while (ServiceEntry
!= &ServiceListHead
)
70 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
73 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
75 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
76 return CurrentService
;
79 ServiceEntry
= ServiceEntry
->Flink
;
82 DPRINT("Couldn't find a matching service\n");
89 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName
)
91 PLIST_ENTRY ServiceEntry
;
92 PSERVICE CurrentService
;
94 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
96 ServiceEntry
= ServiceListHead
.Flink
;
97 while (ServiceEntry
!= &ServiceListHead
)
99 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
102 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
104 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
105 return CurrentService
;
108 ServiceEntry
= ServiceEntry
->Flink
;
111 DPRINT("Couldn't find a matching service\n");
118 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
120 PLIST_ENTRY ServiceEntry
;
121 PSERVICE CurrentService
;
123 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
125 ServiceEntry
= ServiceListHead
.Flink
;
126 while (ServiceEntry
!= &ServiceListHead
)
128 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
131 if (CurrentService
->dwResumeCount
> dwResumeCount
)
133 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
134 return CurrentService
;
137 ServiceEntry
= ServiceEntry
->Flink
;
140 DPRINT("Couldn't find a matching service\n");
146 static NTSTATUS STDCALL
147 CreateGroupOrderListRoutine(PWSTR ValueName
,
154 PSERVICE_GROUP Group
;
156 DPRINT("CreateGroupOrderListRoutine(%S, %x, %x, %x, %x, %x)\n",
157 ValueName
, ValueType
, ValueData
, ValueLength
, Context
, EntryContext
);
159 if (ValueType
== REG_BINARY
&&
161 ValueLength
>= sizeof(DWORD
) &&
162 ValueLength
>= (*(PULONG
)ValueData
+ 1) * sizeof(DWORD
))
164 Group
= (PSERVICE_GROUP
)Context
;
165 Group
->TagCount
= ((PULONG
)ValueData
)[0];
166 if (Group
->TagCount
> 0)
168 if (ValueLength
>= (Group
->TagCount
+ 1) * sizeof(DWORD
))
170 Group
->TagArray
= (PULONG
)HeapAlloc(GetProcessHeap(),
172 Group
->TagCount
* sizeof(DWORD
));
173 if (Group
->TagArray
== NULL
)
176 return STATUS_INSUFFICIENT_RESOURCES
;
179 RtlCopyMemory(Group
->TagArray
,
180 (PULONG
)ValueData
+ 1,
181 Group
->TagCount
* sizeof(DWORD
));
186 return STATUS_UNSUCCESSFUL
;
191 return STATUS_SUCCESS
;
195 static NTSTATUS STDCALL
196 CreateGroupListRoutine(PWSTR ValueName
,
203 PSERVICE_GROUP Group
;
204 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
207 if (ValueType
== REG_SZ
)
209 DPRINT("Data: '%S'\n", (PWCHAR
)ValueData
);
211 Group
= (PSERVICE_GROUP
)HeapAlloc(GetProcessHeap(),
213 sizeof(SERVICE_GROUP
));
216 return STATUS_INSUFFICIENT_RESOURCES
;
219 if (!RtlCreateUnicodeString(&Group
->GroupName
,
222 return STATUS_INSUFFICIENT_RESOURCES
;
225 RtlZeroMemory(&QueryTable
, sizeof(QueryTable
));
226 QueryTable
[0].Name
= (PWSTR
)ValueData
;
227 QueryTable
[0].QueryRoutine
= CreateGroupOrderListRoutine
;
229 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
234 DPRINT("%x %d %S\n", Status
, Group
->TagCount
, (PWSTR
)ValueData
);
236 InsertTailList(&GroupListHead
,
237 &Group
->GroupListEntry
);
240 return STATUS_SUCCESS
;
245 ScmCreateNewServiceRecord(LPWSTR lpServiceName
,
246 PSERVICE
*lpServiceRecord
)
248 PSERVICE lpService
= NULL
;
250 DPRINT("Service: '%S'\n", lpServiceName
);
252 /* Allocate service entry */
253 lpService
= HeapAlloc(GetProcessHeap(),
255 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
256 if (lpService
== NULL
)
257 return ERROR_NOT_ENOUGH_MEMORY
;
259 *lpServiceRecord
= lpService
;
261 /* Copy service name */
262 wcscpy(lpService
->szServiceName
, lpServiceName
);
263 lpService
->lpServiceName
= lpService
->szServiceName
;
264 lpService
->lpDisplayName
= lpService
->lpServiceName
;
266 /* Set the resume count */
267 lpService
->dwResumeCount
= dwResumeCount
++;
269 /* Append service entry */
270 InsertTailList(&ServiceListHead
,
271 &lpService
->ServiceListEntry
);
273 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
274 lpService
->Status
.dwControlsAccepted
= 0;
275 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
276 lpService
->Status
.dwServiceSpecificExitCode
= 0;
277 lpService
->Status
.dwCheckPoint
= 0;
278 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
280 return ERROR_SUCCESS
;
285 CreateServiceListEntry(LPWSTR lpServiceName
,
288 PSERVICE lpService
= NULL
;
289 LPWSTR lpDisplayName
= NULL
;
290 LPWSTR lpGroup
= NULL
;
295 DWORD dwErrorControl
;
298 DPRINT("Service: '%S'\n", lpServiceName
);
299 if (*lpServiceName
== L
'{')
300 return ERROR_SUCCESS
;
302 dwSize
= sizeof(DWORD
);
303 dwError
= RegQueryValueExW(hServiceKey
,
307 (LPBYTE
)&dwServiceType
,
309 if (dwError
!= ERROR_SUCCESS
)
310 return ERROR_SUCCESS
;
312 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
313 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
314 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
315 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
316 return ERROR_SUCCESS
;
318 DPRINT("Service type: %lx\n", dwServiceType
);
320 dwSize
= sizeof(DWORD
);
321 dwError
= RegQueryValueExW(hServiceKey
,
325 (LPBYTE
)&dwStartType
,
327 if (dwError
!= ERROR_SUCCESS
)
328 return ERROR_SUCCESS
;
330 DPRINT("Start type: %lx\n", dwStartType
);
332 dwSize
= sizeof(DWORD
);
333 dwError
= RegQueryValueExW(hServiceKey
,
337 (LPBYTE
)&dwErrorControl
,
339 if (dwError
!= ERROR_SUCCESS
)
340 return ERROR_SUCCESS
;
342 DPRINT("Error control: %lx\n", dwErrorControl
);
344 dwError
= RegQueryValueExW(hServiceKey
,
350 if (dwError
!= ERROR_SUCCESS
)
353 DPRINT("Tag: %lx\n", dwTagId
);
355 dwError
= ScmReadString(hServiceKey
,
358 if (dwError
!= ERROR_SUCCESS
)
361 DPRINT("Group: %S\n", lpGroup
);
363 dwError
= ScmReadString(hServiceKey
,
366 if (dwError
!= ERROR_SUCCESS
)
367 lpDisplayName
= NULL
;
369 DPRINT("Display name: %S\n", lpDisplayName
);
371 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
373 if (dwError
!= ERROR_SUCCESS
)
376 lpService
->Status
.dwServiceType
= dwServiceType
;
377 lpService
->dwStartType
= dwStartType
;
378 lpService
->dwErrorControl
= dwErrorControl
;
379 lpService
->dwTag
= dwTagId
;
383 lpService
->lpServiceGroup
= lpGroup
;
387 if (lpDisplayName
!= NULL
)
389 lpService
->lpDisplayName
= lpDisplayName
;
390 lpDisplayName
= NULL
;
393 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
394 DPRINT("Group: '%S'\n", lpService
->lpServiceGroup
);
395 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
396 lpService
->dwStartType
,
397 lpService
->Status
.dwServiceType
,
399 lpService
->dwErrorControl
);
401 if (ScmIsDeleteFlagSet(hServiceKey
))
402 lpService
->bDeleted
= TRUE
;
406 HeapFree(GetProcessHeap(), 0, lpGroup
);
408 if (lpDisplayName
!= NULL
)
409 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
416 ScmReadGroupList(VOID
)
418 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
421 InitializeListHead(&GroupListHead
);
423 /* Build group order list */
424 RtlZeroMemory(&QueryTable
,
427 QueryTable
[0].Name
= L
"List";
428 QueryTable
[0].QueryRoutine
= CreateGroupListRoutine
;
430 Status
= RtlQueryRegistryValues(RTL_REGISTRY_CONTROL
,
431 L
"ServiceGroupOrder",
436 return RtlNtStatusToDosError(Status
);
441 ScmDeleteMarkedServices(VOID
)
443 PLIST_ENTRY ServiceEntry
;
444 PSERVICE CurrentService
;
446 ServiceEntry
= ServiceListHead
.Flink
;
447 while (ServiceEntry
!= &ServiceListHead
)
449 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
451 ServiceEntry
= ServiceEntry
->Flink
;
453 if (CurrentService
->bDeleted
== TRUE
)
455 DPRINT1("Delete service: %S\n", CurrentService
->lpServiceName
);
457 /* FIXME: Delete the registry keys */
459 /* FIXME: Delete the service record from the list */
467 ScmCreateServiceDatabase(VOID
)
469 WCHAR szSubKey
[MAX_PATH
];
473 DWORD dwSubKeyLength
;
474 FILETIME ftLastChanged
;
477 DPRINT("ScmCreateServiceDatabase() called\n");
479 dwError
= ScmReadGroupList();
480 if (dwError
!= ERROR_SUCCESS
)
483 /* Initialize basic variables */
484 InitializeListHead(&ServiceListHead
);
486 /* Initialize the database lock */
487 RtlInitializeResource(&DatabaseLock
);
489 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
490 L
"System\\CurrentControlSet\\Services",
494 if (dwError
!= ERROR_SUCCESS
)
500 dwSubKeyLength
= MAX_PATH
;
501 dwError
= RegEnumKeyExW(hServicesKey
,
509 if (dwError
== ERROR_SUCCESS
&&
512 DPRINT("SubKeyName: '%S'\n", szSubKey
);
514 dwError
= RegOpenKeyExW(hServicesKey
,
519 if (dwError
== ERROR_SUCCESS
)
521 dwError
= CreateServiceListEntry(szSubKey
,
524 RegCloseKey(hServiceKey
);
528 if (dwError
!= ERROR_SUCCESS
)
534 RegCloseKey(hServicesKey
);
536 /* Delete services that are marked for delete */
537 ScmDeleteMarkedServices();
539 DPRINT("ScmCreateServiceDatabase() done\n");
541 return ERROR_SUCCESS
;
546 ScmCheckDriver(PSERVICE Service
)
548 OBJECT_ATTRIBUTES ObjectAttributes
;
549 UNICODE_STRING DirName
;
552 POBJECT_DIRECTORY_INFORMATION DirInfo
;
556 PLIST_ENTRY GroupEntry
;
557 PSERVICE_GROUP CurrentGroup
;
559 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
561 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
563 RtlInitUnicodeString(&DirName
,
568 RtlInitUnicodeString(&DirName
,
572 InitializeObjectAttributes(&ObjectAttributes
,
578 Status
= NtOpenDirectoryObject(&DirHandle
,
579 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
581 if (!NT_SUCCESS(Status
))
586 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
587 2 * MAX_PATH
* sizeof(WCHAR
);
588 DirInfo
= HeapAlloc(GetProcessHeap(),
595 Status
= NtQueryDirectoryObject(DirHandle
,
602 if (Status
== STATUS_NO_MORE_ENTRIES
)
604 /* FIXME: Add current service to 'failed service' list */
605 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
609 if (!NT_SUCCESS(Status
))
612 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->ObjectName
);
614 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->ObjectName
.Buffer
) == 0)
616 DPRINT("Found: '%S' '%wZ'\n",
617 Service
->lpServiceName
, &DirInfo
->ObjectName
);
619 /* Mark service as 'running' */
620 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
622 /* Find the driver's group and mark it as 'running' */
623 if (Service
->lpServiceGroup
!= NULL
)
625 GroupEntry
= GroupListHead
.Flink
;
626 while (GroupEntry
!= &GroupListHead
)
628 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
630 DPRINT("Checking group '%wZ'\n", &CurrentGroup
->GroupName
);
631 if (Service
->lpServiceGroup
!= NULL
&&
632 _wcsicmp(Service
->lpServiceGroup
, CurrentGroup
->GroupName
.Buffer
) == 0)
634 CurrentGroup
->ServicesRunning
= TRUE
;
637 GroupEntry
= GroupEntry
->Flink
;
644 HeapFree(GetProcessHeap(),
649 return STATUS_SUCCESS
;
654 ScmGetBootAndSystemDriverState(VOID
)
656 PLIST_ENTRY ServiceEntry
;
657 PSERVICE CurrentService
;
659 DPRINT("ScmGetBootAndSystemDriverState() called\n");
661 ServiceEntry
= ServiceListHead
.Flink
;
662 while (ServiceEntry
!= &ServiceListHead
)
664 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
666 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
667 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
670 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
672 ScmCheckDriver(CurrentService
);
675 ServiceEntry
= ServiceEntry
->Flink
;
678 DPRINT("ScmGetBootAndSystemDriverState() done\n");
683 ScmSendStartCommand(PSERVICE Service
, LPWSTR Arguments
)
685 PSCM_START_PACKET StartPacket
;
693 DPRINT("ScmSendStartCommand() called\n");
695 /* Calculate the total length of the start command line */
696 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
698 if (Arguments
!= NULL
)
703 Length
= wcslen(Ptr
) + 1;
704 TotalLength
+= Length
;
711 /* Allocate start command packet */
712 StartPacket
= HeapAlloc(GetProcessHeap(),
714 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
715 if (StartPacket
== NULL
)
716 return STATUS_INSUFFICIENT_RESOURCES
;
718 StartPacket
->Command
= SCM_START_COMMAND
;
719 StartPacket
->Size
= TotalLength
;
720 Ptr
= &StartPacket
->Arguments
[0];
721 wcscpy(Ptr
, Service
->lpServiceName
);
722 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
724 /* FIXME: Copy argument list */
728 /* Send the start command */
729 WriteFile(Service
->ControlPipeHandle
,
731 sizeof(SCM_START_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
735 /* FIXME: Read the reply */
737 HeapFree(GetProcessHeap(),
741 DPRINT("ScmSendStartCommand() done\n");
743 return STATUS_SUCCESS
;
748 ScmStartUserModeService(PSERVICE Service
)
750 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
751 PROCESS_INFORMATION ProcessInformation
;
752 STARTUPINFOW StartupInfo
;
753 UNICODE_STRING ImagePath
;
758 RtlInitUnicodeString(&ImagePath
, NULL
);
760 /* Get service data */
761 RtlZeroMemory(&QueryTable
,
764 QueryTable
[0].Name
= L
"Type";
765 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
766 QueryTable
[0].EntryContext
= &Type
;
768 QueryTable
[1].Name
= L
"ImagePath";
769 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
770 QueryTable
[1].EntryContext
= &ImagePath
;
772 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
773 Service
->lpServiceName
,
777 if (!NT_SUCCESS(Status
))
779 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
782 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
783 DPRINT("Type: %lx\n", Type
);
785 /* Create '\\.\pipe\net\NtControlPipe' instance */
786 Service
->ControlPipeHandle
= CreateNamedPipeW(L
"\\\\.\\pipe\\net\\NtControlPipe",
788 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
794 DPRINT("CreateNamedPipeW() done\n");
795 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
797 DPRINT1("Failed to create control pipe!\n");
798 return STATUS_UNSUCCESSFUL
;
801 StartupInfo
.cb
= sizeof(StartupInfo
);
802 StartupInfo
.lpReserved
= NULL
;
803 StartupInfo
.lpDesktop
= NULL
;
804 StartupInfo
.lpTitle
= NULL
;
805 StartupInfo
.dwFlags
= 0;
806 StartupInfo
.cbReserved2
= 0;
807 StartupInfo
.lpReserved2
= 0;
809 Result
= CreateProcessW(ImagePath
.Buffer
,
814 DETACHED_PROCESS
| CREATE_SUSPENDED
,
818 &ProcessInformation
);
819 RtlFreeUnicodeString(&ImagePath
);
823 /* Close control pipe */
824 CloseHandle(Service
->ControlPipeHandle
);
825 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
827 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
828 return STATUS_UNSUCCESSFUL
;
831 DPRINT("Process Id: %lu Handle %lx\n",
832 ProcessInformation
.dwProcessId
,
833 ProcessInformation
.hProcess
);
834 DPRINT("Thread Id: %lu Handle %lx\n",
835 ProcessInformation
.dwThreadId
,
836 ProcessInformation
.hThread
);
838 /* Get process and thread ids */
839 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
840 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
843 ResumeThread(ProcessInformation
.hThread
);
845 /* Connect control pipe */
846 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
))
848 DWORD dwProcessId
= 0;
851 DPRINT("Control pipe connected!\n");
853 /* Read thread id from pipe */
854 if (!ReadFile(Service
->ControlPipeHandle
,
855 (LPVOID
)&dwProcessId
,
860 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
862 Status
= STATUS_UNSUCCESSFUL
;
866 DPRINT("Received process id %lu\n", dwProcessId
);
868 /* FIXME: Send start command */
870 Status
= STATUS_SUCCESS
;
875 DPRINT("Connecting control pipe failed!\n");
877 /* Close control pipe */
878 CloseHandle(Service
->ControlPipeHandle
);
879 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
880 Service
->ProcessId
= 0;
881 Service
->ThreadId
= 0;
882 Status
= STATUS_UNSUCCESSFUL
;
885 ScmSendStartCommand(Service
, NULL
);
887 /* Close process and thread handle */
888 CloseHandle(ProcessInformation
.hThread
);
889 CloseHandle(ProcessInformation
.hProcess
);
896 ScmStartService(PSERVICE Service
,
897 PSERVICE_GROUP Group
)
901 DPRINT("ScmStartService() called\n");
903 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
904 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
906 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
909 Status
= ScmLoadDriver(Service
);
910 if (Status
== STATUS_SUCCESS
)
911 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
915 /* Start user-mode service */
916 Status
= ScmStartUserModeService(Service
);
919 DPRINT("ScmStartService() done (Status %lx)\n", Status
);
921 if (NT_SUCCESS(Status
))
925 Group
->ServicesRunning
= TRUE
;
927 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
932 switch (Service
->ErrorControl
)
934 case SERVICE_ERROR_NORMAL
:
935 /* FIXME: Log error */
938 case SERVICE_ERROR_SEVERE
:
939 if (IsLastKnownGood
== FALSE
)
941 /* FIXME: Boot last known good configuration */
945 case SERVICE_ERROR_CRITICAL
:
946 if (IsLastKnownGood
== FALSE
)
948 /* FIXME: Boot last known good configuration */
964 ScmAutoStartServices(VOID
)
966 PLIST_ENTRY GroupEntry
;
967 PLIST_ENTRY ServiceEntry
;
968 PSERVICE_GROUP CurrentGroup
;
969 PSERVICE CurrentService
;
972 /* Clear 'ServiceVisited' flag */
973 ServiceEntry
= ServiceListHead
.Flink
;
974 while (ServiceEntry
!= &ServiceListHead
)
976 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
977 CurrentService
->ServiceVisited
= FALSE
;
978 ServiceEntry
= ServiceEntry
->Flink
;
981 /* Start all services which are members of an existing group */
982 GroupEntry
= GroupListHead
.Flink
;
983 while (GroupEntry
!= &GroupListHead
)
985 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
987 DPRINT("Group '%wZ'\n", &CurrentGroup
->GroupName
);
989 /* Start all services witch have a valid tag */
990 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
992 ServiceEntry
= ServiceListHead
.Flink
;
993 while (ServiceEntry
!= &ServiceListHead
)
995 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
997 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
998 (_wcsicmp(CurrentGroup
->GroupName
.Buffer
, CurrentService
->lpServiceGroup
) == 0) &&
999 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1000 (CurrentService
->ServiceVisited
== FALSE
) &&
1001 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1003 CurrentService
->ServiceVisited
= TRUE
;
1004 ScmStartService(CurrentService
,
1008 ServiceEntry
= ServiceEntry
->Flink
;
1012 /* Start all services which have an invalid tag or which do not have a tag */
1013 ServiceEntry
= ServiceListHead
.Flink
;
1014 while (ServiceEntry
!= &ServiceListHead
)
1016 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1018 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
1019 (_wcsicmp(CurrentGroup
->GroupName
.Buffer
, CurrentService
->lpServiceGroup
) == 0) &&
1020 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1021 (CurrentService
->ServiceVisited
== FALSE
))
1023 CurrentService
->ServiceVisited
= TRUE
;
1024 ScmStartService(CurrentService
,
1028 ServiceEntry
= ServiceEntry
->Flink
;
1031 GroupEntry
= GroupEntry
->Flink
;
1034 /* Start all services which are members of any non-existing group */
1035 ServiceEntry
= ServiceListHead
.Flink
;
1036 while (ServiceEntry
!= &ServiceListHead
)
1038 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1040 if ((CurrentService
->lpServiceGroup
!= NULL
) &&
1041 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1042 (CurrentService
->ServiceVisited
== FALSE
))
1044 CurrentService
->ServiceVisited
= TRUE
;
1045 ScmStartService(CurrentService
,
1049 ServiceEntry
= ServiceEntry
->Flink
;
1052 /* Start all services which are not a member of any group */
1053 ServiceEntry
= ServiceListHead
.Flink
;
1054 while (ServiceEntry
!= &ServiceListHead
)
1056 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1058 if ((CurrentService
->lpServiceGroup
== NULL
) &&
1059 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1060 (CurrentService
->ServiceVisited
== FALSE
))
1062 CurrentService
->ServiceVisited
= TRUE
;
1063 ScmStartService(CurrentService
,
1067 ServiceEntry
= ServiceEntry
->Flink
;
1070 /* Clear 'ServiceVisited' flag again */
1071 ServiceEntry
= ServiceListHead
.Flink
;
1072 while (ServiceEntry
!= &ServiceListHead
)
1074 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1075 CurrentService
->ServiceVisited
= FALSE
;
1076 ServiceEntry
= ServiceEntry
->Flink
;