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 * Uncomment the line below to start services
22 * using the SERVICE_START_PENDING state
24 // #define USE_SERVICE_START_PENDING
26 /* GLOBALS *******************************************************************/
28 LIST_ENTRY ServiceListHead
;
30 static RTL_RESOURCE DatabaseLock
;
31 static DWORD dwResumeCount
= 1;
34 /* FUNCTIONS *****************************************************************/
38 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
40 PLIST_ENTRY ServiceEntry
;
41 PSERVICE CurrentService
;
43 DPRINT("ScmGetServiceEntryByName() called\n");
45 ServiceEntry
= ServiceListHead
.Flink
;
46 while (ServiceEntry
!= &ServiceListHead
)
48 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
51 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
53 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
54 return CurrentService
;
57 ServiceEntry
= ServiceEntry
->Flink
;
60 DPRINT("Couldn't find a matching service\n");
67 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
69 PLIST_ENTRY ServiceEntry
;
70 PSERVICE CurrentService
;
72 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
74 ServiceEntry
= ServiceListHead
.Flink
;
75 while (ServiceEntry
!= &ServiceListHead
)
77 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
80 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
82 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
83 return CurrentService
;
86 ServiceEntry
= ServiceEntry
->Flink
;
89 DPRINT("Couldn't find a matching service\n");
96 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
98 PLIST_ENTRY ServiceEntry
;
99 PSERVICE CurrentService
;
101 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
103 ServiceEntry
= ServiceListHead
.Flink
;
104 while (ServiceEntry
!= &ServiceListHead
)
106 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
109 if (CurrentService
->dwResumeCount
> dwResumeCount
)
111 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
112 return CurrentService
;
115 ServiceEntry
= ServiceEntry
->Flink
;
118 DPRINT("Couldn't find a matching service\n");
125 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
126 PSERVICE
*lpServiceRecord
)
128 PSERVICE lpService
= NULL
;
130 DPRINT("Service: '%S'\n", lpServiceName
);
132 /* Allocate service entry */
133 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
135 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
136 if (lpService
== NULL
)
137 return ERROR_NOT_ENOUGH_MEMORY
;
139 *lpServiceRecord
= lpService
;
141 /* Copy service name */
142 wcscpy(lpService
->szServiceName
, lpServiceName
);
143 lpService
->lpServiceName
= lpService
->szServiceName
;
144 lpService
->lpDisplayName
= lpService
->lpServiceName
;
146 /* Set the resume count */
147 lpService
->dwResumeCount
= dwResumeCount
++;
149 /* Append service record */
150 InsertTailList(&ServiceListHead
,
151 &lpService
->ServiceListEntry
);
153 /* Initialize the service status */
154 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
155 lpService
->Status
.dwControlsAccepted
= 0;
156 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
157 lpService
->Status
.dwServiceSpecificExitCode
= 0;
158 lpService
->Status
.dwCheckPoint
= 0;
159 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
161 return ERROR_SUCCESS
;
166 ScmDeleteServiceRecord(PSERVICE lpService
)
168 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
170 /* Delete the display name */
171 if (lpService
->lpDisplayName
!= NULL
&&
172 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
173 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
175 /* Decrement the image reference counter */
176 if (lpService
->lpImage
)
177 lpService
->lpImage
->dwServiceRefCount
--;
179 /* Decrement the group reference counter */
180 if (lpService
->lpGroup
)
181 lpService
->lpGroup
->dwRefCount
--;
183 /* FIXME: SecurityDescriptor */
185 /* Close the control pipe */
186 if (lpService
->ControlPipeHandle
!= INVALID_HANDLE_VALUE
)
187 CloseHandle(lpService
->ControlPipeHandle
);
189 /* Remove the Service from the List */
190 RemoveEntryList(&lpService
->ServiceListEntry
);
192 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
194 /* Delete the service record */
195 HeapFree(GetProcessHeap(), 0, lpService
);
202 CreateServiceListEntry(LPCWSTR lpServiceName
,
205 PSERVICE lpService
= NULL
;
206 LPWSTR lpDisplayName
= NULL
;
207 LPWSTR lpGroup
= NULL
;
212 DWORD dwErrorControl
;
215 DPRINT("Service: '%S'\n", lpServiceName
);
216 if (*lpServiceName
== L
'{')
217 return ERROR_SUCCESS
;
219 dwSize
= sizeof(DWORD
);
220 dwError
= RegQueryValueExW(hServiceKey
,
224 (LPBYTE
)&dwServiceType
,
226 if (dwError
!= ERROR_SUCCESS
)
227 return ERROR_SUCCESS
;
229 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
230 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
231 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
232 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
233 return ERROR_SUCCESS
;
235 DPRINT("Service type: %lx\n", dwServiceType
);
237 dwSize
= sizeof(DWORD
);
238 dwError
= RegQueryValueExW(hServiceKey
,
242 (LPBYTE
)&dwStartType
,
244 if (dwError
!= ERROR_SUCCESS
)
245 return ERROR_SUCCESS
;
247 DPRINT("Start type: %lx\n", dwStartType
);
249 dwSize
= sizeof(DWORD
);
250 dwError
= RegQueryValueExW(hServiceKey
,
254 (LPBYTE
)&dwErrorControl
,
256 if (dwError
!= ERROR_SUCCESS
)
257 return ERROR_SUCCESS
;
259 DPRINT("Error control: %lx\n", dwErrorControl
);
261 dwError
= RegQueryValueExW(hServiceKey
,
267 if (dwError
!= ERROR_SUCCESS
)
270 DPRINT("Tag: %lx\n", dwTagId
);
272 dwError
= ScmReadString(hServiceKey
,
275 if (dwError
!= ERROR_SUCCESS
)
278 DPRINT("Group: %S\n", lpGroup
);
280 dwError
= ScmReadString(hServiceKey
,
283 if (dwError
!= ERROR_SUCCESS
)
284 lpDisplayName
= NULL
;
286 DPRINT("Display name: %S\n", lpDisplayName
);
288 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
290 if (dwError
!= ERROR_SUCCESS
)
293 lpService
->Status
.dwServiceType
= dwServiceType
;
294 lpService
->dwStartType
= dwStartType
;
295 lpService
->dwErrorControl
= dwErrorControl
;
296 lpService
->dwTag
= dwTagId
;
300 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
301 if (dwError
!= ERROR_SUCCESS
)
305 if (lpDisplayName
!= NULL
)
307 lpService
->lpDisplayName
= lpDisplayName
;
308 lpDisplayName
= NULL
;
311 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
312 if (lpService
->lpGroup
!= NULL
)
314 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
316 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
317 lpService
->dwStartType
,
318 lpService
->Status
.dwServiceType
,
320 lpService
->dwErrorControl
);
322 if (ScmIsDeleteFlagSet(hServiceKey
))
323 lpService
->bDeleted
= TRUE
;
327 HeapFree(GetProcessHeap(), 0, lpGroup
);
329 if (lpDisplayName
!= NULL
)
330 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
337 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
339 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
340 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
343 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
346 /* Find the maximum subkey length so that we can allocate a buffer */
347 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
348 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
352 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
353 /* Name too big: alloc a buffer for it */
354 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
357 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
360 while (dwRet
== ERROR_SUCCESS
)
362 dwSize
= dwMaxSubkeyLen
;
363 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
364 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
365 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
367 if (dwRet
== ERROR_NO_MORE_ITEMS
)
368 dwRet
= ERROR_SUCCESS
;
370 if (lpszName
!= szNameBuf
)
371 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
375 RegCloseKey(hSubKey
);
377 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
384 ScmDeleteMarkedServices(VOID
)
386 PLIST_ENTRY ServiceEntry
;
387 PSERVICE CurrentService
;
391 ServiceEntry
= ServiceListHead
.Flink
;
392 while (ServiceEntry
!= &ServiceListHead
)
394 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
396 ServiceEntry
= ServiceEntry
->Flink
;
398 if (CurrentService
->bDeleted
== TRUE
)
400 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
401 L
"System\\CurrentControlSet\\Services",
405 if (dwError
== ERROR_SUCCESS
)
407 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
408 RegCloseKey(hServicesKey
);
409 if (dwError
== ERROR_SUCCESS
)
411 RemoveEntryList(&CurrentService
->ServiceListEntry
);
412 HeapFree(GetProcessHeap(), 0, CurrentService
);
416 if (dwError
!= ERROR_SUCCESS
)
417 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
429 DPRINT("WaitForLSA() called\n");
431 hEvent
= CreateEventW(NULL
,
434 L
"LSA_RPC_SERVER_ACTIVE");
437 dwError
= GetLastError();
438 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
440 if (dwError
== ERROR_ALREADY_EXISTS
)
442 hEvent
= OpenEventW(SYNCHRONIZE
,
444 L
"LSA_RPC_SERVER_ACTIVE");
447 DPRINT1("Could not open the notification event!\n");
453 DPRINT("Wait for LSA!\n");
454 WaitForSingleObject(hEvent
, INFINITE
);
455 DPRINT("LSA is available!\n");
459 DPRINT("WaitForLSA() done\n");
464 ScmCreateServiceDatabase(VOID
)
466 WCHAR szSubKey
[MAX_PATH
];
470 DWORD dwSubKeyLength
;
471 FILETIME ftLastChanged
;
474 DPRINT("ScmCreateServiceDatabase() called\n");
476 dwError
= ScmCreateGroupList();
477 if (dwError
!= ERROR_SUCCESS
)
480 /* Initialize basic variables */
481 InitializeListHead(&ServiceListHead
);
483 /* Initialize the database lock */
484 RtlInitializeResource(&DatabaseLock
);
486 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
487 L
"System\\CurrentControlSet\\Services",
491 if (dwError
!= ERROR_SUCCESS
)
497 dwSubKeyLength
= MAX_PATH
;
498 dwError
= RegEnumKeyExW(hServicesKey
,
506 if (dwError
== ERROR_SUCCESS
&&
509 DPRINT("SubKeyName: '%S'\n", szSubKey
);
511 dwError
= RegOpenKeyExW(hServicesKey
,
516 if (dwError
== ERROR_SUCCESS
)
518 dwError
= CreateServiceListEntry(szSubKey
,
521 RegCloseKey(hServiceKey
);
525 if (dwError
!= ERROR_SUCCESS
)
531 RegCloseKey(hServicesKey
);
536 /* Delete services that are marked for delete */
537 ScmDeleteMarkedServices();
539 DPRINT("ScmCreateServiceDatabase() done\n");
541 return ERROR_SUCCESS
;
546 ScmShutdownServiceDatabase(VOID
)
548 DPRINT("ScmShutdownServiceDatabase() called\n");
550 ScmDeleteMarkedServices();
551 RtlDeleteResource(&DatabaseLock
);
553 DPRINT("ScmShutdownServiceDatabase() done\n");
558 ScmCheckDriver(PSERVICE Service
)
560 OBJECT_ATTRIBUTES ObjectAttributes
;
561 UNICODE_STRING DirName
;
564 POBJECT_DIRECTORY_INFORMATION DirInfo
;
569 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
571 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
573 RtlInitUnicodeString(&DirName
,
578 RtlInitUnicodeString(&DirName
,
582 InitializeObjectAttributes(&ObjectAttributes
,
588 Status
= NtOpenDirectoryObject(&DirHandle
,
589 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
591 if (!NT_SUCCESS(Status
))
596 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
597 2 * MAX_PATH
* sizeof(WCHAR
);
598 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
605 Status
= NtQueryDirectoryObject(DirHandle
,
612 if (Status
== STATUS_NO_MORE_ENTRIES
)
614 /* FIXME: Add current service to 'failed service' list */
615 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
619 if (!NT_SUCCESS(Status
))
622 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
624 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
626 DPRINT("Found: '%S' '%wZ'\n",
627 Service
->lpServiceName
, &DirInfo
->Name
);
629 /* Mark service as 'running' */
630 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
632 /* Mark the service group as 'running' */
633 if (Service
->lpGroup
!= NULL
)
635 Service
->lpGroup
->ServicesRunning
= TRUE
;
642 HeapFree(GetProcessHeap(),
647 return STATUS_SUCCESS
;
652 ScmGetBootAndSystemDriverState(VOID
)
654 PLIST_ENTRY ServiceEntry
;
655 PSERVICE CurrentService
;
657 DPRINT("ScmGetBootAndSystemDriverState() called\n");
659 ServiceEntry
= ServiceListHead
.Flink
;
660 while (ServiceEntry
!= &ServiceListHead
)
662 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
664 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
665 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
668 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
670 ScmCheckDriver(CurrentService
);
673 ServiceEntry
= ServiceEntry
->Flink
;
676 DPRINT("ScmGetBootAndSystemDriverState() done\n");
681 ScmControlService(PSERVICE Service
,
683 LPSERVICE_STATUS lpServiceStatus
)
685 PSCM_CONTROL_PACKET ControlPacket
;
689 DPRINT("ScmControlService() called\n");
691 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
693 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
695 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
696 if (ControlPacket
== NULL
)
697 return ERROR_NOT_ENOUGH_MEMORY
;
699 ControlPacket
->dwControl
= dwControl
;
700 ControlPacket
->dwSize
= TotalLength
;
701 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
702 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
704 /* Send the control packet */
705 WriteFile(Service
->ControlPipeHandle
,
707 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
711 /* FIXME: Read the reply */
713 /* Release the contol packet */
714 HeapFree(GetProcessHeap(),
718 RtlCopyMemory(lpServiceStatus
,
720 sizeof(SERVICE_STATUS
));
722 DPRINT("ScmControlService) done\n");
724 return ERROR_SUCCESS
;
729 ScmSendStartCommand(PSERVICE Service
,
733 PSCM_CONTROL_PACKET ControlPacket
;
735 DWORD ArgsLength
= 0;
740 DPRINT("ScmSendStartCommand() called\n");
742 /* Calculate the total length of the start command line */
743 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
746 for (Count
= 0; Count
< argc
; Count
++)
748 DPRINT("Arg: %S\n", argv
[Count
]);
749 Length
= wcslen(argv
[Count
]) + 1;
750 TotalLength
+= Length
;
751 ArgsLength
+= Length
;
755 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
757 /* Allocate a control packet */
758 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
760 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
761 if (ControlPacket
== NULL
)
762 return ERROR_NOT_ENOUGH_MEMORY
;
764 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
765 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
766 ControlPacket
->dwSize
= TotalLength
;
767 Ptr
= &ControlPacket
->szArguments
[0];
768 wcscpy(Ptr
, Service
->lpServiceName
);
769 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
771 /* Copy argument list */
775 DPRINT1("Arguments sent to service ignored!\n");
777 memcpy(Ptr
, Arguments
, ArgsLength
);
782 /* Terminate the argument list */
785 /* Send the start command */
786 WriteFile(Service
->ControlPipeHandle
,
788 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
792 /* FIXME: Read the reply */
794 /* Release the contol packet */
795 HeapFree(GetProcessHeap(),
799 DPRINT("ScmSendStartCommand() done\n");
801 return ERROR_SUCCESS
;
806 ScmStartUserModeService(PSERVICE Service
,
810 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
811 PROCESS_INFORMATION ProcessInformation
;
812 STARTUPINFOW StartupInfo
;
813 UNICODE_STRING ImagePath
;
815 DWORD ServiceCurrent
= 0;
818 DWORD dwError
= ERROR_SUCCESS
;
819 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
820 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
821 DWORD KeyDisposition
;
824 RtlInitUnicodeString(&ImagePath
, NULL
);
826 /* Get service data */
827 RtlZeroMemory(&QueryTable
,
830 QueryTable
[0].Name
= L
"Type";
831 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
832 QueryTable
[0].EntryContext
= &Type
;
834 QueryTable
[1].Name
= L
"ImagePath";
835 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
836 QueryTable
[1].EntryContext
= &ImagePath
;
838 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
839 Service
->lpServiceName
,
843 if (!NT_SUCCESS(Status
))
845 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
846 return RtlNtStatusToDosError(Status
);
848 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
849 DPRINT("Type: %lx\n", Type
);
851 /* Get the service number */
852 /* TODO: Create registry entry with correct write access */
853 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
854 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
856 KEY_WRITE
| KEY_READ
,
861 if (ERROR_SUCCESS
!= Status
)
863 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
867 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
869 DWORD KeySize
= sizeof(ServiceCurrent
);
870 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
872 if (ERROR_SUCCESS
!= Status
)
874 RegCloseKey(hServiceCurrentKey
);
875 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
882 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
884 RegCloseKey(hServiceCurrentKey
);
886 if (ERROR_SUCCESS
!= Status
)
888 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
892 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
893 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
894 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
896 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
902 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
903 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
905 DPRINT1("Failed to create control pipe!\n");
906 return GetLastError();
909 StartupInfo
.cb
= sizeof(StartupInfo
);
910 StartupInfo
.lpReserved
= NULL
;
911 StartupInfo
.lpDesktop
= NULL
;
912 StartupInfo
.lpTitle
= NULL
;
913 StartupInfo
.dwFlags
= 0;
914 StartupInfo
.cbReserved2
= 0;
915 StartupInfo
.lpReserved2
= 0;
917 Result
= CreateProcessW(NULL
,
922 DETACHED_PROCESS
| CREATE_SUSPENDED
,
926 &ProcessInformation
);
927 RtlFreeUnicodeString(&ImagePath
);
931 dwError
= GetLastError();
932 /* Close control pipe */
933 CloseHandle(Service
->ControlPipeHandle
);
934 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
936 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
940 DPRINT("Process Id: %lu Handle %lx\n",
941 ProcessInformation
.dwProcessId
,
942 ProcessInformation
.hProcess
);
943 DPRINT("Thread Id: %lu Handle %lx\n",
944 ProcessInformation
.dwThreadId
,
945 ProcessInformation
.hThread
);
947 /* Get process and thread ids */
948 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
949 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
952 ResumeThread(ProcessInformation
.hThread
);
954 /* Connect control pipe */
955 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
956 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
960 DPRINT("Control pipe connected!\n");
962 /* Read SERVICE_STATUS_HANDLE from pipe */
963 if (!ReadFile(Service
->ControlPipeHandle
,
964 (LPVOID
)&dwProcessId
,
969 dwError
= GetLastError();
970 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
975 DPRINT("Received service process ID %lu\n", dwProcessId
);
977 /* Send start command */
978 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
983 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
985 /* Close control pipe */
986 CloseHandle(Service
->ControlPipeHandle
);
987 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
988 Service
->ProcessId
= 0;
989 Service
->ThreadId
= 0;
992 /* Close process and thread handle */
993 CloseHandle(ProcessInformation
.hThread
);
994 CloseHandle(ProcessInformation
.hProcess
);
1001 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1003 PSERVICE_GROUP Group
= Service
->lpGroup
;
1004 DWORD dwError
= ERROR_SUCCESS
;
1006 DPRINT("ScmStartService() called\n");
1008 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1009 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1011 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1014 dwError
= ScmLoadDriver(Service
);
1015 if (dwError
== ERROR_SUCCESS
)
1017 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1018 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1023 /* Start user-mode service */
1024 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1025 if (dwError
== ERROR_SUCCESS
)
1027 #ifdef USE_SERVICE_START_PENDING
1028 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1030 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1035 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1037 if (dwError
== ERROR_SUCCESS
)
1041 Group
->ServicesRunning
= TRUE
;
1047 switch (Service
->ErrorControl
)
1049 case SERVICE_ERROR_NORMAL
:
1050 /* FIXME: Log error */
1053 case SERVICE_ERROR_SEVERE
:
1054 if (IsLastKnownGood
== FALSE
)
1056 /* FIXME: Boot last known good configuration */
1060 case SERVICE_ERROR_CRITICAL
:
1061 if (IsLastKnownGood
== FALSE
)
1063 /* FIXME: Boot last known good configuration */
1079 ScmAutoStartServices(VOID
)
1081 PLIST_ENTRY GroupEntry
;
1082 PLIST_ENTRY ServiceEntry
;
1083 PSERVICE_GROUP CurrentGroup
;
1084 PSERVICE CurrentService
;
1087 /* Clear 'ServiceVisited' flag */
1088 ServiceEntry
= ServiceListHead
.Flink
;
1089 while (ServiceEntry
!= &ServiceListHead
)
1091 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1092 CurrentService
->ServiceVisited
= FALSE
;
1093 ServiceEntry
= ServiceEntry
->Flink
;
1096 /* Start all services which are members of an existing group */
1097 GroupEntry
= GroupListHead
.Flink
;
1098 while (GroupEntry
!= &GroupListHead
)
1100 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1102 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1104 /* Start all services witch have a valid tag */
1105 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1107 ServiceEntry
= ServiceListHead
.Flink
;
1108 while (ServiceEntry
!= &ServiceListHead
)
1110 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1112 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1113 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1114 (CurrentService
->ServiceVisited
== FALSE
) &&
1115 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1117 CurrentService
->ServiceVisited
= TRUE
;
1118 ScmStartService(CurrentService
, 0, NULL
);
1121 ServiceEntry
= ServiceEntry
->Flink
;
1125 /* Start all services which have an invalid tag or which do not have a tag */
1126 ServiceEntry
= ServiceListHead
.Flink
;
1127 while (ServiceEntry
!= &ServiceListHead
)
1129 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1131 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1132 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1133 (CurrentService
->ServiceVisited
== FALSE
))
1135 CurrentService
->ServiceVisited
= TRUE
;
1136 ScmStartService(CurrentService
, 0, NULL
);
1139 ServiceEntry
= ServiceEntry
->Flink
;
1142 GroupEntry
= GroupEntry
->Flink
;
1145 /* Start all services which are members of any non-existing group */
1146 ServiceEntry
= ServiceListHead
.Flink
;
1147 while (ServiceEntry
!= &ServiceListHead
)
1149 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1151 if ((CurrentService
->lpGroup
!= NULL
) &&
1152 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1153 (CurrentService
->ServiceVisited
== FALSE
))
1155 CurrentService
->ServiceVisited
= TRUE
;
1156 ScmStartService(CurrentService
, 0, NULL
);
1159 ServiceEntry
= ServiceEntry
->Flink
;
1162 /* Start all services which are not a member of any group */
1163 ServiceEntry
= ServiceListHead
.Flink
;
1164 while (ServiceEntry
!= &ServiceListHead
)
1166 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1168 if ((CurrentService
->lpGroup
== NULL
) &&
1169 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1170 (CurrentService
->ServiceVisited
== FALSE
))
1172 CurrentService
->ServiceVisited
= TRUE
;
1173 ScmStartService(CurrentService
, 0, NULL
);
1176 ServiceEntry
= ServiceEntry
->Flink
;
1179 /* Clear 'ServiceVisited' flag again */
1180 ServiceEntry
= ServiceListHead
.Flink
;
1181 while (ServiceEntry
!= &ServiceListHead
)
1183 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1184 CurrentService
->ServiceVisited
= FALSE
;
1185 ServiceEntry
= ServiceEntry
->Flink
;
1191 ScmAutoShutdownServices(VOID
)
1193 PLIST_ENTRY ServiceEntry
;
1194 PSERVICE CurrentService
;
1195 SERVICE_STATUS ServiceStatus
;
1197 DPRINT("ScmAutoShutdownServices() called\n");
1199 ServiceEntry
= ServiceListHead
.Flink
;
1200 while (ServiceEntry
!= &ServiceListHead
)
1202 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1204 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1205 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1207 /* shutdown service */
1208 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1211 ServiceEntry
= ServiceEntry
->Flink
;
1214 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1219 ScmLockDatabaseExclusive(VOID
)
1221 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1226 ScmLockDatabaseShared(VOID
)
1228 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1233 ScmUnlockDatabase(VOID
)
1235 RtlReleaseResource(&DatabaseLock
);