2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/database.c
5 * PURPOSE: Database control interface
6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl
7 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 * Gregor Brunmar <gregor.brunmar@home.se>
13 /* INCLUDES *****************************************************************/
21 /* GLOBALS *******************************************************************/
23 LIST_ENTRY ServiceListHead
;
25 static RTL_RESOURCE DatabaseLock
;
26 static DWORD dwResumeCount
= 1;
29 /* FUNCTIONS *****************************************************************/
33 ScmGetServiceEntryByName(LPWSTR lpServiceName
)
35 PLIST_ENTRY ServiceEntry
;
36 PSERVICE CurrentService
;
38 DPRINT("ScmGetServiceEntryByName() called\n");
40 ServiceEntry
= ServiceListHead
.Flink
;
41 while (ServiceEntry
!= &ServiceListHead
)
43 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
46 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
48 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
49 return CurrentService
;
52 ServiceEntry
= ServiceEntry
->Flink
;
55 DPRINT("Couldn't find a matching service\n");
62 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName
)
64 PLIST_ENTRY ServiceEntry
;
65 PSERVICE CurrentService
;
67 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
69 ServiceEntry
= ServiceListHead
.Flink
;
70 while (ServiceEntry
!= &ServiceListHead
)
72 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
75 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
77 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
78 return CurrentService
;
81 ServiceEntry
= ServiceEntry
->Flink
;
84 DPRINT("Couldn't find a matching service\n");
91 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
93 PLIST_ENTRY ServiceEntry
;
94 PSERVICE CurrentService
;
96 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
98 ServiceEntry
= ServiceListHead
.Flink
;
99 while (ServiceEntry
!= &ServiceListHead
)
101 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
104 if (CurrentService
->dwResumeCount
> dwResumeCount
)
106 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
107 return CurrentService
;
110 ServiceEntry
= ServiceEntry
->Flink
;
113 DPRINT("Couldn't find a matching service\n");
120 ScmGetServiceEntryByClientHandle(ULONG Handle
)
122 PLIST_ENTRY ServiceEntry
;
123 PSERVICE CurrentService
;
125 DPRINT("ScmGetServiceEntryByClientHandle() called\n");
126 DPRINT("looking for %lu\n", Handle
);
128 ServiceEntry
= ServiceListHead
.Flink
;
129 while (ServiceEntry
!= &ServiceListHead
)
131 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
135 if (CurrentService
->hClient
== Handle
)
137 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
138 return CurrentService
;
141 ServiceEntry
= ServiceEntry
->Flink
;
144 DPRINT("Couldn't find a matching service\n");
151 ScmCreateNewServiceRecord(LPWSTR lpServiceName
,
152 PSERVICE
*lpServiceRecord
)
154 PSERVICE lpService
= NULL
;
156 DPRINT("Service: '%S'\n", lpServiceName
);
158 /* Allocate service entry */
159 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
161 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
162 if (lpService
== NULL
)
163 return ERROR_NOT_ENOUGH_MEMORY
;
165 *lpServiceRecord
= lpService
;
167 /* Copy service name */
168 wcscpy(lpService
->szServiceName
, lpServiceName
);
169 lpService
->lpServiceName
= lpService
->szServiceName
;
170 lpService
->lpDisplayName
= lpService
->lpServiceName
;
172 /* Set the resume count */
173 lpService
->dwResumeCount
= dwResumeCount
++;
175 /* Append service entry */
176 InsertTailList(&ServiceListHead
,
177 &lpService
->ServiceListEntry
);
179 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
180 lpService
->Status
.dwControlsAccepted
= 0;
181 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
182 lpService
->Status
.dwServiceSpecificExitCode
= 0;
183 lpService
->Status
.dwCheckPoint
= 0;
184 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
186 return ERROR_SUCCESS
;
191 CreateServiceListEntry(LPWSTR lpServiceName
,
194 PSERVICE lpService
= NULL
;
195 LPWSTR lpDisplayName
= NULL
;
196 LPWSTR lpGroup
= NULL
;
201 DWORD dwErrorControl
;
204 DPRINT("Service: '%S'\n", lpServiceName
);
205 if (*lpServiceName
== L
'{')
206 return ERROR_SUCCESS
;
208 dwSize
= sizeof(DWORD
);
209 dwError
= RegQueryValueExW(hServiceKey
,
213 (LPBYTE
)&dwServiceType
,
215 if (dwError
!= ERROR_SUCCESS
)
216 return ERROR_SUCCESS
;
218 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
219 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
220 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
221 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
222 return ERROR_SUCCESS
;
224 DPRINT("Service type: %lx\n", dwServiceType
);
226 dwSize
= sizeof(DWORD
);
227 dwError
= RegQueryValueExW(hServiceKey
,
231 (LPBYTE
)&dwStartType
,
233 if (dwError
!= ERROR_SUCCESS
)
234 return ERROR_SUCCESS
;
236 DPRINT("Start type: %lx\n", dwStartType
);
238 dwSize
= sizeof(DWORD
);
239 dwError
= RegQueryValueExW(hServiceKey
,
243 (LPBYTE
)&dwErrorControl
,
245 if (dwError
!= ERROR_SUCCESS
)
246 return ERROR_SUCCESS
;
248 DPRINT("Error control: %lx\n", dwErrorControl
);
250 dwError
= RegQueryValueExW(hServiceKey
,
256 if (dwError
!= ERROR_SUCCESS
)
259 DPRINT("Tag: %lx\n", dwTagId
);
261 dwError
= ScmReadString(hServiceKey
,
264 if (dwError
!= ERROR_SUCCESS
)
267 DPRINT("Group: %S\n", lpGroup
);
269 dwError
= ScmReadString(hServiceKey
,
272 if (dwError
!= ERROR_SUCCESS
)
273 lpDisplayName
= NULL
;
275 DPRINT("Display name: %S\n", lpDisplayName
);
277 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
279 if (dwError
!= ERROR_SUCCESS
)
282 lpService
->Status
.dwServiceType
= dwServiceType
;
283 lpService
->dwStartType
= dwStartType
;
284 lpService
->dwErrorControl
= dwErrorControl
;
285 lpService
->dwTag
= dwTagId
;
289 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
290 if (dwError
!= ERROR_SUCCESS
)
294 if (lpDisplayName
!= NULL
)
296 lpService
->lpDisplayName
= lpDisplayName
;
297 lpDisplayName
= NULL
;
300 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
301 if (lpService
->lpGroup
!= NULL
)
303 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
305 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
306 lpService
->dwStartType
,
307 lpService
->Status
.dwServiceType
,
309 lpService
->dwErrorControl
);
311 if (ScmIsDeleteFlagSet(hServiceKey
))
312 lpService
->bDeleted
= TRUE
;
316 HeapFree(GetProcessHeap(), 0, lpGroup
);
318 if (lpDisplayName
!= NULL
)
319 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
326 ScmDeleteMarkedServices(VOID
)
328 PLIST_ENTRY ServiceEntry
;
329 PSERVICE CurrentService
;
331 ServiceEntry
= ServiceListHead
.Flink
;
332 while (ServiceEntry
!= &ServiceListHead
)
334 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
336 ServiceEntry
= ServiceEntry
->Flink
;
338 if (CurrentService
->bDeleted
== TRUE
)
340 DPRINT1("Delete service: %S\n", CurrentService
->lpServiceName
);
342 /* FIXME: Delete the registry keys */
344 /* FIXME: Delete the service record from the list */
352 ScmCreateServiceDatabase(VOID
)
354 WCHAR szSubKey
[MAX_PATH
];
358 DWORD dwSubKeyLength
;
359 FILETIME ftLastChanged
;
362 DPRINT("ScmCreateServiceDatabase() called\n");
364 dwError
= ScmCreateGroupList();
365 if (dwError
!= ERROR_SUCCESS
)
368 /* Initialize basic variables */
369 InitializeListHead(&ServiceListHead
);
371 /* Initialize the database lock */
372 RtlInitializeResource(&DatabaseLock
);
374 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
375 L
"System\\CurrentControlSet\\Services",
379 if (dwError
!= ERROR_SUCCESS
)
385 dwSubKeyLength
= MAX_PATH
;
386 dwError
= RegEnumKeyExW(hServicesKey
,
394 if (dwError
== ERROR_SUCCESS
&&
397 DPRINT("SubKeyName: '%S'\n", szSubKey
);
399 dwError
= RegOpenKeyExW(hServicesKey
,
404 if (dwError
== ERROR_SUCCESS
)
406 dwError
= CreateServiceListEntry(szSubKey
,
409 RegCloseKey(hServiceKey
);
413 if (dwError
!= ERROR_SUCCESS
)
419 RegCloseKey(hServicesKey
);
421 /* Delete services that are marked for delete */
422 ScmDeleteMarkedServices();
424 DPRINT("ScmCreateServiceDatabase() done\n");
426 return ERROR_SUCCESS
;
431 ScmShutdownServiceDatabase(VOID
)
433 DPRINT("ScmShutdownServiceDatabase() called\n");
435 ScmDeleteMarkedServices();
436 RtlDeleteResource(&DatabaseLock
);
438 DPRINT("ScmShutdownServiceDatabase() done\n");
443 ScmCheckDriver(PSERVICE Service
)
445 OBJECT_ATTRIBUTES ObjectAttributes
;
446 UNICODE_STRING DirName
;
449 POBJECT_DIRECTORY_INFORMATION DirInfo
;
454 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
456 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
458 RtlInitUnicodeString(&DirName
,
463 RtlInitUnicodeString(&DirName
,
467 InitializeObjectAttributes(&ObjectAttributes
,
473 Status
= NtOpenDirectoryObject(&DirHandle
,
474 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
476 if (!NT_SUCCESS(Status
))
481 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
482 2 * MAX_PATH
* sizeof(WCHAR
);
483 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
490 Status
= NtQueryDirectoryObject(DirHandle
,
497 if (Status
== STATUS_NO_MORE_ENTRIES
)
499 /* FIXME: Add current service to 'failed service' list */
500 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
504 if (!NT_SUCCESS(Status
))
507 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
509 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
511 DPRINT("Found: '%S' '%wZ'\n",
512 Service
->lpServiceName
, &DirInfo
->Name
);
514 /* Mark service as 'running' */
515 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
517 /* Mark the service group as 'running' */
518 if (Service
->lpGroup
!= NULL
)
520 Service
->lpGroup
->ServicesRunning
= TRUE
;
527 HeapFree(GetProcessHeap(),
532 return STATUS_SUCCESS
;
537 ScmGetBootAndSystemDriverState(VOID
)
539 PLIST_ENTRY ServiceEntry
;
540 PSERVICE CurrentService
;
542 DPRINT("ScmGetBootAndSystemDriverState() called\n");
544 ServiceEntry
= ServiceListHead
.Flink
;
545 while (ServiceEntry
!= &ServiceListHead
)
547 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
549 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
550 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
553 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
555 ScmCheckDriver(CurrentService
);
558 ServiceEntry
= ServiceEntry
->Flink
;
561 DPRINT("ScmGetBootAndSystemDriverState() done\n");
566 ScmControlService(PSERVICE Service
,
568 LPSERVICE_STATUS lpServiceStatus
)
570 PSCM_CONTROL_PACKET ControlPacket
;
574 DPRINT("ScmControlService() called\n");
576 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
578 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
580 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
581 if (ControlPacket
== NULL
)
582 return ERROR_NOT_ENOUGH_MEMORY
;
584 ControlPacket
->dwControl
= dwControl
;
585 ControlPacket
->hClient
= Service
->hClient
;
586 ControlPacket
->dwSize
= TotalLength
;
587 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
589 /* Send the start command */
590 WriteFile(Service
->ControlPipeHandle
,
592 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
596 /* FIXME: Read the reply */
598 /* Release the contol packet */
599 HeapFree(GetProcessHeap(),
603 RtlCopyMemory(lpServiceStatus
,
605 sizeof(SERVICE_STATUS
));
607 DPRINT("ScmControlService) done\n");
609 return ERROR_SUCCESS
;
614 ScmSendStartCommand(PSERVICE Service
,
617 PSCM_CONTROL_PACKET ControlPacket
;
619 DWORD ArgsLength
= 0;
624 DPRINT("ScmSendStartCommand() called\n");
626 /* Calculate the total length of the start command line */
627 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
628 if (Arguments
!= NULL
)
633 Length
= wcslen(Ptr
) + 1;
634 TotalLength
+= Length
;
635 ArgsLength
+= Length
;
637 DPRINT("Arg: %S\n", Ptr
);
641 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
643 /* Allocate a control packet */
644 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
646 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
647 if (ControlPacket
== NULL
)
648 return ERROR_NOT_ENOUGH_MEMORY
;
650 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
651 ControlPacket
->hClient
= Service
->hClient
;
652 ControlPacket
->dwSize
= TotalLength
;
653 Ptr
= &ControlPacket
->szArguments
[0];
654 wcscpy(Ptr
, Service
->lpServiceName
);
655 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
657 /* Copy argument list */
658 if (Arguments
!= NULL
)
660 memcpy(Ptr
, Arguments
, ArgsLength
);
664 /* Terminate the argument list */
667 /* Send the start command */
668 WriteFile(Service
->ControlPipeHandle
,
670 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
674 /* FIXME: Read the reply */
676 /* Release the contol packet */
677 HeapFree(GetProcessHeap(),
681 DPRINT("ScmSendStartCommand() done\n");
683 return ERROR_SUCCESS
;
688 ScmStartUserModeService(PSERVICE Service
,
691 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
692 PROCESS_INFORMATION ProcessInformation
;
693 STARTUPINFOW StartupInfo
;
694 UNICODE_STRING ImagePath
;
696 DWORD ServiceCurrent
= 0;
699 DWORD dwError
= ERROR_SUCCESS
;
700 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
701 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
702 DWORD KeyDisposition
;
704 RtlInitUnicodeString(&ImagePath
, NULL
);
706 /* Get service data */
707 RtlZeroMemory(&QueryTable
,
710 QueryTable
[0].Name
= L
"Type";
711 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
712 QueryTable
[0].EntryContext
= &Type
;
714 QueryTable
[1].Name
= L
"ImagePath";
715 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
716 QueryTable
[1].EntryContext
= &ImagePath
;
718 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
719 Service
->lpServiceName
,
723 if (!NT_SUCCESS(Status
))
725 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
726 return RtlNtStatusToDosError(Status
);
728 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
729 DPRINT("Type: %lx\n", Type
);
731 /* Get the service number */
732 /* TODO: Create registry entry with correct write access */
733 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
734 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
736 KEY_WRITE
| KEY_READ
,
741 if (ERROR_SUCCESS
!= Status
)
743 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
747 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
749 DWORD KeySize
= sizeof(ServiceCurrent
);
750 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
752 if (ERROR_SUCCESS
!= Status
)
754 RegCloseKey(hServiceCurrentKey
);
755 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
762 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
764 RegCloseKey(hServiceCurrentKey
);
766 if (ERROR_SUCCESS
!= Status
)
768 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
772 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
773 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
774 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
776 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
782 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
783 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
785 DPRINT1("Failed to create control pipe!\n");
786 return GetLastError();
789 StartupInfo
.cb
= sizeof(StartupInfo
);
790 StartupInfo
.lpReserved
= NULL
;
791 StartupInfo
.lpDesktop
= NULL
;
792 StartupInfo
.lpTitle
= NULL
;
793 StartupInfo
.dwFlags
= 0;
794 StartupInfo
.cbReserved2
= 0;
795 StartupInfo
.lpReserved2
= 0;
797 Result
= CreateProcessW(ImagePath
.Buffer
,
802 DETACHED_PROCESS
| CREATE_SUSPENDED
,
806 &ProcessInformation
);
807 RtlFreeUnicodeString(&ImagePath
);
811 dwError
= GetLastError();
812 /* Close control pipe */
813 CloseHandle(Service
->ControlPipeHandle
);
814 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
816 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
820 DPRINT("Process Id: %lu Handle %lx\n",
821 ProcessInformation
.dwProcessId
,
822 ProcessInformation
.hProcess
);
823 DPRINT("Thread Id: %lu Handle %lx\n",
824 ProcessInformation
.dwThreadId
,
825 ProcessInformation
.hThread
);
827 /* Get process and thread ids */
828 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
829 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
832 ResumeThread(ProcessInformation
.hThread
);
834 /* Connect control pipe */
835 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
836 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
840 DPRINT("Control pipe connected!\n");
842 /* Read SERVICE_STATUS_HANDLE from pipe */
843 if (!ReadFile(Service
->ControlPipeHandle
,
844 (LPVOID
)&Service
->hClient
,
849 dwError
= GetLastError();
850 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
855 DPRINT("Received service status %lu\n", Service
->hClient
);
857 /* Send start command */
858 dwError
= ScmSendStartCommand(Service
, lpArgs
);
863 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
865 /* Close control pipe */
866 CloseHandle(Service
->ControlPipeHandle
);
867 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
868 Service
->ProcessId
= 0;
869 Service
->ThreadId
= 0;
872 /* Close process and thread handle */
873 CloseHandle(ProcessInformation
.hThread
);
874 CloseHandle(ProcessInformation
.hProcess
);
881 ScmStartService(PSERVICE Service
, LPWSTR lpArgs
)
883 PSERVICE_GROUP Group
= Service
->lpGroup
;
884 DWORD dwError
= ERROR_SUCCESS
;
886 DPRINT("ScmStartService() called\n");
888 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
889 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
891 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
894 dwError
= ScmLoadDriver(Service
);
895 if (dwError
== ERROR_SUCCESS
)
896 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
900 /* Start user-mode service */
901 dwError
= ScmStartUserModeService(Service
, lpArgs
);
904 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
906 if (dwError
== ERROR_SUCCESS
)
910 Group
->ServicesRunning
= TRUE
;
912 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
917 switch (Service
->ErrorControl
)
919 case SERVICE_ERROR_NORMAL
:
920 /* FIXME: Log error */
923 case SERVICE_ERROR_SEVERE
:
924 if (IsLastKnownGood
== FALSE
)
926 /* FIXME: Boot last known good configuration */
930 case SERVICE_ERROR_CRITICAL
:
931 if (IsLastKnownGood
== FALSE
)
933 /* FIXME: Boot last known good configuration */
949 ScmAutoStartServices(VOID
)
951 PLIST_ENTRY GroupEntry
;
952 PLIST_ENTRY ServiceEntry
;
953 PSERVICE_GROUP CurrentGroup
;
954 PSERVICE CurrentService
;
957 /* Clear 'ServiceVisited' flag */
958 ServiceEntry
= ServiceListHead
.Flink
;
959 while (ServiceEntry
!= &ServiceListHead
)
961 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
962 CurrentService
->ServiceVisited
= FALSE
;
963 ServiceEntry
= ServiceEntry
->Flink
;
966 /* Start all services which are members of an existing group */
967 GroupEntry
= GroupListHead
.Flink
;
968 while (GroupEntry
!= &GroupListHead
)
970 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
972 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
974 /* Start all services witch have a valid tag */
975 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
977 ServiceEntry
= ServiceListHead
.Flink
;
978 while (ServiceEntry
!= &ServiceListHead
)
980 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
982 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
983 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
984 (CurrentService
->ServiceVisited
== FALSE
) &&
985 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
987 CurrentService
->ServiceVisited
= TRUE
;
988 ScmStartService(CurrentService
, NULL
);
991 ServiceEntry
= ServiceEntry
->Flink
;
995 /* Start all services which have an invalid tag or which do not have a tag */
996 ServiceEntry
= ServiceListHead
.Flink
;
997 while (ServiceEntry
!= &ServiceListHead
)
999 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1001 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1002 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1003 (CurrentService
->ServiceVisited
== FALSE
))
1005 CurrentService
->ServiceVisited
= TRUE
;
1006 ScmStartService(CurrentService
, NULL
);
1009 ServiceEntry
= ServiceEntry
->Flink
;
1012 GroupEntry
= GroupEntry
->Flink
;
1015 /* Start all services which are members of any non-existing group */
1016 ServiceEntry
= ServiceListHead
.Flink
;
1017 while (ServiceEntry
!= &ServiceListHead
)
1019 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1021 if ((CurrentService
->lpGroup
!= NULL
) &&
1022 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1023 (CurrentService
->ServiceVisited
== FALSE
))
1025 CurrentService
->ServiceVisited
= TRUE
;
1026 ScmStartService(CurrentService
, NULL
);
1029 ServiceEntry
= ServiceEntry
->Flink
;
1032 /* Start all services which are not a member of any group */
1033 ServiceEntry
= ServiceListHead
.Flink
;
1034 while (ServiceEntry
!= &ServiceListHead
)
1036 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1038 if ((CurrentService
->lpGroup
== NULL
) &&
1039 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1040 (CurrentService
->ServiceVisited
== FALSE
))
1042 CurrentService
->ServiceVisited
= TRUE
;
1043 ScmStartService(CurrentService
, NULL
);
1046 ServiceEntry
= ServiceEntry
->Flink
;
1049 /* Clear 'ServiceVisited' flag again */
1050 ServiceEntry
= ServiceListHead
.Flink
;
1051 while (ServiceEntry
!= &ServiceListHead
)
1053 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1054 CurrentService
->ServiceVisited
= FALSE
;
1055 ServiceEntry
= ServiceEntry
->Flink
;
1061 ScmAutoShutdownServices(VOID
)
1063 PLIST_ENTRY ServiceEntry
;
1064 PSERVICE CurrentService
;
1065 SERVICE_STATUS ServiceStatus
;
1067 DPRINT("ScmAutoShutdownServices() called\n");
1069 ServiceEntry
= ServiceListHead
.Flink
;
1070 while (ServiceEntry
!= &ServiceListHead
)
1072 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1074 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1075 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1077 /* shutdown service */
1078 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1081 ServiceEntry
= ServiceEntry
->Flink
;
1084 DPRINT("ScmGetBootAndSystemDriverState() done\n");