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;
33 static CRITICAL_SECTION NamedPipeCriticalSection
;
34 static CRITICAL_SECTION StartServiceCriticalSection
;
36 /* FUNCTIONS *****************************************************************/
40 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
42 PLIST_ENTRY ServiceEntry
;
43 PSERVICE CurrentService
;
45 DPRINT("ScmGetServiceEntryByName() called\n");
47 ServiceEntry
= ServiceListHead
.Flink
;
48 while (ServiceEntry
!= &ServiceListHead
)
50 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
53 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
55 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
56 return CurrentService
;
59 ServiceEntry
= ServiceEntry
->Flink
;
62 DPRINT("Couldn't find a matching service\n");
69 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
71 PLIST_ENTRY ServiceEntry
;
72 PSERVICE CurrentService
;
74 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
76 ServiceEntry
= ServiceListHead
.Flink
;
77 while (ServiceEntry
!= &ServiceListHead
)
79 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
82 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
84 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
85 return CurrentService
;
88 ServiceEntry
= ServiceEntry
->Flink
;
91 DPRINT("Couldn't find a matching service\n");
98 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
100 PLIST_ENTRY ServiceEntry
;
101 PSERVICE CurrentService
;
103 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
105 ServiceEntry
= ServiceListHead
.Flink
;
106 while (ServiceEntry
!= &ServiceListHead
)
108 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
111 if (CurrentService
->dwResumeCount
> dwResumeCount
)
113 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
114 return CurrentService
;
117 ServiceEntry
= ServiceEntry
->Flink
;
120 DPRINT("Couldn't find a matching service\n");
127 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
128 PSERVICE
*lpServiceRecord
)
130 PSERVICE lpService
= NULL
;
132 DPRINT("Service: '%S'\n", lpServiceName
);
134 /* Allocate service entry */
135 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
137 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
138 if (lpService
== NULL
)
139 return ERROR_NOT_ENOUGH_MEMORY
;
141 *lpServiceRecord
= lpService
;
143 /* Copy service name */
144 wcscpy(lpService
->szServiceName
, lpServiceName
);
145 lpService
->lpServiceName
= lpService
->szServiceName
;
146 lpService
->lpDisplayName
= lpService
->lpServiceName
;
148 /* Set the resume count */
149 lpService
->dwResumeCount
= dwResumeCount
++;
151 /* Append service record */
152 InsertTailList(&ServiceListHead
,
153 &lpService
->ServiceListEntry
);
155 /* Initialize the service status */
156 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
157 lpService
->Status
.dwControlsAccepted
= 0;
158 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
159 lpService
->Status
.dwServiceSpecificExitCode
= 0;
160 lpService
->Status
.dwCheckPoint
= 0;
161 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
163 return ERROR_SUCCESS
;
168 ScmDeleteServiceRecord(PSERVICE lpService
)
170 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
172 /* Delete the display name */
173 if (lpService
->lpDisplayName
!= NULL
&&
174 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
175 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
177 /* Decrement the image reference counter */
178 if (lpService
->lpImage
)
179 lpService
->lpImage
->dwServiceRefCount
--;
181 /* Decrement the group reference counter */
182 if (lpService
->lpGroup
)
183 lpService
->lpGroup
->dwRefCount
--;
185 /* FIXME: SecurityDescriptor */
187 /* Close the control pipe */
188 if (lpService
->ControlPipeHandle
!= INVALID_HANDLE_VALUE
)
189 CloseHandle(lpService
->ControlPipeHandle
);
191 /* Remove the Service from the List */
192 RemoveEntryList(&lpService
->ServiceListEntry
);
194 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
196 /* Delete the service record */
197 HeapFree(GetProcessHeap(), 0, lpService
);
204 CreateServiceListEntry(LPCWSTR lpServiceName
,
207 PSERVICE lpService
= NULL
;
208 LPWSTR lpDisplayName
= NULL
;
209 LPWSTR lpGroup
= NULL
;
214 DWORD dwErrorControl
;
217 DPRINT("Service: '%S'\n", lpServiceName
);
218 if (*lpServiceName
== L
'{')
219 return ERROR_SUCCESS
;
221 dwSize
= sizeof(DWORD
);
222 dwError
= RegQueryValueExW(hServiceKey
,
226 (LPBYTE
)&dwServiceType
,
228 if (dwError
!= ERROR_SUCCESS
)
229 return ERROR_SUCCESS
;
231 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
232 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
233 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
234 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
235 return ERROR_SUCCESS
;
237 DPRINT("Service type: %lx\n", dwServiceType
);
239 dwSize
= sizeof(DWORD
);
240 dwError
= RegQueryValueExW(hServiceKey
,
244 (LPBYTE
)&dwStartType
,
246 if (dwError
!= ERROR_SUCCESS
)
247 return ERROR_SUCCESS
;
249 DPRINT("Start type: %lx\n", dwStartType
);
251 dwSize
= sizeof(DWORD
);
252 dwError
= RegQueryValueExW(hServiceKey
,
256 (LPBYTE
)&dwErrorControl
,
258 if (dwError
!= ERROR_SUCCESS
)
259 return ERROR_SUCCESS
;
261 DPRINT("Error control: %lx\n", dwErrorControl
);
263 dwError
= RegQueryValueExW(hServiceKey
,
269 if (dwError
!= ERROR_SUCCESS
)
272 DPRINT("Tag: %lx\n", dwTagId
);
274 dwError
= ScmReadString(hServiceKey
,
277 if (dwError
!= ERROR_SUCCESS
)
280 DPRINT("Group: %S\n", lpGroup
);
282 dwError
= ScmReadString(hServiceKey
,
285 if (dwError
!= ERROR_SUCCESS
)
286 lpDisplayName
= NULL
;
288 DPRINT("Display name: %S\n", lpDisplayName
);
290 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
292 if (dwError
!= ERROR_SUCCESS
)
295 lpService
->Status
.dwServiceType
= dwServiceType
;
296 lpService
->dwStartType
= dwStartType
;
297 lpService
->dwErrorControl
= dwErrorControl
;
298 lpService
->dwTag
= dwTagId
;
302 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
303 if (dwError
!= ERROR_SUCCESS
)
307 if (lpDisplayName
!= NULL
)
309 lpService
->lpDisplayName
= lpDisplayName
;
310 lpDisplayName
= NULL
;
313 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
314 if (lpService
->lpGroup
!= NULL
)
316 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
318 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
319 lpService
->dwStartType
,
320 lpService
->Status
.dwServiceType
,
322 lpService
->dwErrorControl
);
324 if (ScmIsDeleteFlagSet(hServiceKey
))
325 lpService
->bDeleted
= TRUE
;
329 HeapFree(GetProcessHeap(), 0, lpGroup
);
331 if (lpDisplayName
!= NULL
)
332 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
339 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
341 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
342 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
345 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
348 /* Find the maximum subkey length so that we can allocate a buffer */
349 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
350 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
354 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
355 /* Name too big: alloc a buffer for it */
356 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
359 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
362 while (dwRet
== ERROR_SUCCESS
)
364 dwSize
= dwMaxSubkeyLen
;
365 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
366 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
367 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
369 if (dwRet
== ERROR_NO_MORE_ITEMS
)
370 dwRet
= ERROR_SUCCESS
;
372 if (lpszName
!= szNameBuf
)
373 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
377 RegCloseKey(hSubKey
);
379 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
386 ScmDeleteMarkedServices(VOID
)
388 PLIST_ENTRY ServiceEntry
;
389 PSERVICE CurrentService
;
393 ServiceEntry
= ServiceListHead
.Flink
;
394 while (ServiceEntry
!= &ServiceListHead
)
396 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
398 ServiceEntry
= ServiceEntry
->Flink
;
400 if (CurrentService
->bDeleted
== TRUE
)
402 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
403 L
"System\\CurrentControlSet\\Services",
407 if (dwError
== ERROR_SUCCESS
)
409 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
410 RegCloseKey(hServicesKey
);
411 if (dwError
== ERROR_SUCCESS
)
413 RemoveEntryList(&CurrentService
->ServiceListEntry
);
414 HeapFree(GetProcessHeap(), 0, CurrentService
);
418 if (dwError
!= ERROR_SUCCESS
)
419 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
431 DPRINT("WaitForLSA() called\n");
433 hEvent
= CreateEventW(NULL
,
436 L
"LSA_RPC_SERVER_ACTIVE");
439 dwError
= GetLastError();
440 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
442 if (dwError
== ERROR_ALREADY_EXISTS
)
444 hEvent
= OpenEventW(SYNCHRONIZE
,
446 L
"LSA_RPC_SERVER_ACTIVE");
449 DPRINT1("Could not open the notification event!\n");
455 DPRINT("Wait for LSA!\n");
456 WaitForSingleObject(hEvent
, INFINITE
);
457 DPRINT("LSA is available!\n");
461 DPRINT("WaitForLSA() done\n");
466 ScmCreateServiceDatabase(VOID
)
468 WCHAR szSubKey
[MAX_PATH
];
472 DWORD dwSubKeyLength
;
473 FILETIME ftLastChanged
;
476 DPRINT("ScmCreateServiceDatabase() called\n");
478 dwError
= ScmCreateGroupList();
479 if (dwError
!= ERROR_SUCCESS
)
482 /* Initialize basic variables */
483 InitializeListHead(&ServiceListHead
);
485 /* Initialize the database lock */
486 RtlInitializeResource(&DatabaseLock
);
488 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
489 L
"System\\CurrentControlSet\\Services",
493 if (dwError
!= ERROR_SUCCESS
)
499 dwSubKeyLength
= MAX_PATH
;
500 dwError
= RegEnumKeyExW(hServicesKey
,
508 if (dwError
== ERROR_SUCCESS
&&
511 DPRINT("SubKeyName: '%S'\n", szSubKey
);
513 dwError
= RegOpenKeyExW(hServicesKey
,
518 if (dwError
== ERROR_SUCCESS
)
520 dwError
= CreateServiceListEntry(szSubKey
,
523 RegCloseKey(hServiceKey
);
527 if (dwError
!= ERROR_SUCCESS
)
533 RegCloseKey(hServicesKey
);
538 /* Delete services that are marked for delete */
539 ScmDeleteMarkedServices();
541 DPRINT("ScmCreateServiceDatabase() done\n");
543 return ERROR_SUCCESS
;
548 ScmShutdownServiceDatabase(VOID
)
550 DPRINT("ScmShutdownServiceDatabase() called\n");
552 ScmDeleteMarkedServices();
553 RtlDeleteResource(&DatabaseLock
);
555 DPRINT("ScmShutdownServiceDatabase() done\n");
560 ScmCheckDriver(PSERVICE Service
)
562 OBJECT_ATTRIBUTES ObjectAttributes
;
563 UNICODE_STRING DirName
;
566 POBJECT_DIRECTORY_INFORMATION DirInfo
;
571 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
573 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
575 RtlInitUnicodeString(&DirName
,
580 RtlInitUnicodeString(&DirName
,
584 InitializeObjectAttributes(&ObjectAttributes
,
590 Status
= NtOpenDirectoryObject(&DirHandle
,
591 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
593 if (!NT_SUCCESS(Status
))
598 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
599 2 * MAX_PATH
* sizeof(WCHAR
);
600 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
607 Status
= NtQueryDirectoryObject(DirHandle
,
614 if (Status
== STATUS_NO_MORE_ENTRIES
)
616 /* FIXME: Add current service to 'failed service' list */
617 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
621 if (!NT_SUCCESS(Status
))
624 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
626 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
628 DPRINT("Found: '%S' '%wZ'\n",
629 Service
->lpServiceName
, &DirInfo
->Name
);
631 /* Mark service as 'running' */
632 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
634 /* Mark the service group as 'running' */
635 if (Service
->lpGroup
!= NULL
)
637 Service
->lpGroup
->ServicesRunning
= TRUE
;
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 ScmControlService(PSERVICE Service
,
686 PSCM_CONTROL_PACKET ControlPacket
;
687 SCM_REPLY_PACKET ReplyPacket
;
689 DWORD dwWriteCount
= 0;
690 DWORD dwReadCount
= 0;
692 DWORD dwError
= ERROR_SUCCESS
;
694 DPRINT("ScmControlService() called\n");
696 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
698 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
700 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
701 if (ControlPacket
== NULL
)
702 return ERROR_NOT_ENOUGH_MEMORY
;
704 ControlPacket
->dwControl
= dwControl
;
705 ControlPacket
->dwSize
= TotalLength
;
706 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
707 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
709 EnterCriticalSection(&NamedPipeCriticalSection
);
711 /* Send the control packet */
712 WriteFile(Service
->ControlPipeHandle
,
714 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
719 ReadFile(Service
->ControlPipeHandle
,
721 sizeof(SCM_REPLY_PACKET
),
725 LeaveCriticalSection(&NamedPipeCriticalSection
);
727 /* Release the contol packet */
728 HeapFree(GetProcessHeap(),
732 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
734 dwError
= ReplyPacket
.dwError
;
737 DPRINT("ScmControlService() done\n");
744 ScmSendStartCommand(PSERVICE Service
,
748 PSCM_CONTROL_PACKET ControlPacket
;
749 SCM_REPLY_PACKET ReplyPacket
;
751 DWORD ArgsLength
= 0;
754 DWORD dwWriteCount
= 0;
755 DWORD dwReadCount
= 0;
756 DWORD dwError
= ERROR_SUCCESS
;
759 DPRINT("ScmSendStartCommand() called\n");
761 /* Calculate the total length of the start command line */
762 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
765 for (i
= 0; i
< argc
; i
++)
767 DPRINT("Arg: %S\n", argv
[i
]);
768 Length
= wcslen(argv
[i
]) + 1;
769 TotalLength
+= Length
;
770 ArgsLength
+= Length
;
774 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
776 /* Allocate a control packet */
777 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
779 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
780 if (ControlPacket
== NULL
)
781 return ERROR_NOT_ENOUGH_MEMORY
;
783 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
784 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
785 ControlPacket
->dwSize
= TotalLength
;
786 Ptr
= &ControlPacket
->szArguments
[0];
787 wcscpy(Ptr
, Service
->lpServiceName
);
788 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
790 /* Copy argument list */
794 DPRINT1("Arguments sent to service ignored!\n");
796 memcpy(Ptr
, Arguments
, ArgsLength
);
801 /* Terminate the argument list */
804 EnterCriticalSection(&NamedPipeCriticalSection
);
806 /* Send the start command */
807 WriteFile(Service
->ControlPipeHandle
,
809 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
814 ReadFile(Service
->ControlPipeHandle
,
816 sizeof(SCM_REPLY_PACKET
),
820 LeaveCriticalSection(&NamedPipeCriticalSection
);
822 /* Release the contol packet */
823 HeapFree(GetProcessHeap(),
827 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
829 dwError
= ReplyPacket
.dwError
;
832 DPRINT("ScmSendStartCommand() done\n");
839 ScmStartUserModeService(PSERVICE Service
,
843 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
844 PROCESS_INFORMATION ProcessInformation
;
845 STARTUPINFOW StartupInfo
;
846 UNICODE_STRING ImagePath
;
848 DWORD ServiceCurrent
= 0;
851 DWORD dwError
= ERROR_SUCCESS
;
852 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
853 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
854 DWORD KeyDisposition
;
857 RtlInitUnicodeString(&ImagePath
, NULL
);
859 /* Get service data */
860 RtlZeroMemory(&QueryTable
,
863 QueryTable
[0].Name
= L
"Type";
864 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
865 QueryTable
[0].EntryContext
= &Type
;
867 QueryTable
[1].Name
= L
"ImagePath";
868 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
869 QueryTable
[1].EntryContext
= &ImagePath
;
871 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
872 Service
->lpServiceName
,
876 if (!NT_SUCCESS(Status
))
878 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
879 return RtlNtStatusToDosError(Status
);
881 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
882 DPRINT("Type: %lx\n", Type
);
884 /* Get the service number */
885 /* TODO: Create registry entry with correct write access */
886 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
887 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
889 KEY_WRITE
| KEY_READ
,
894 if (ERROR_SUCCESS
!= Status
)
896 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
900 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
902 DWORD KeySize
= sizeof(ServiceCurrent
);
903 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
905 if (ERROR_SUCCESS
!= Status
)
907 RegCloseKey(hServiceCurrentKey
);
908 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
915 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
917 RegCloseKey(hServiceCurrentKey
);
919 if (ERROR_SUCCESS
!= Status
)
921 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
925 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
926 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
927 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
929 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
935 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
936 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
938 DPRINT1("Failed to create control pipe!\n");
939 return GetLastError();
942 StartupInfo
.cb
= sizeof(StartupInfo
);
943 StartupInfo
.lpReserved
= NULL
;
944 StartupInfo
.lpDesktop
= NULL
;
945 StartupInfo
.lpTitle
= NULL
;
946 StartupInfo
.dwFlags
= 0;
947 StartupInfo
.cbReserved2
= 0;
948 StartupInfo
.lpReserved2
= 0;
950 Result
= CreateProcessW(NULL
,
955 DETACHED_PROCESS
| CREATE_SUSPENDED
,
959 &ProcessInformation
);
960 RtlFreeUnicodeString(&ImagePath
);
964 dwError
= GetLastError();
965 /* Close control pipe */
966 CloseHandle(Service
->ControlPipeHandle
);
967 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
969 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
973 DPRINT("Process Id: %lu Handle %lx\n",
974 ProcessInformation
.dwProcessId
,
975 ProcessInformation
.hProcess
);
976 DPRINT("Thread Id: %lu Handle %lx\n",
977 ProcessInformation
.dwThreadId
,
978 ProcessInformation
.hThread
);
980 /* Get process and thread ids */
981 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
982 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
985 ResumeThread(ProcessInformation
.hThread
);
987 /* Connect control pipe */
988 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
989 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
993 DPRINT("Control pipe connected!\n");
995 /* Read SERVICE_STATUS_HANDLE from pipe */
996 if (!ReadFile(Service
->ControlPipeHandle
,
997 (LPVOID
)&dwProcessId
,
1002 dwError
= GetLastError();
1003 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1008 DPRINT("Received service process ID %lu\n", dwProcessId
);
1010 /* Send start command */
1011 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1016 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1018 /* Close control pipe */
1019 CloseHandle(Service
->ControlPipeHandle
);
1020 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1021 Service
->ProcessId
= 0;
1022 Service
->ThreadId
= 0;
1025 /* Close process and thread handle */
1026 CloseHandle(ProcessInformation
.hThread
);
1027 CloseHandle(ProcessInformation
.hProcess
);
1034 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1036 PSERVICE_GROUP Group
= Service
->lpGroup
;
1037 DWORD dwError
= ERROR_SUCCESS
;
1039 EnterCriticalSection(&StartServiceCriticalSection
);
1041 DPRINT("ScmStartService() called\n");
1043 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1044 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1046 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1049 dwError
= ScmLoadDriver(Service
);
1050 if (dwError
== ERROR_SUCCESS
)
1052 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1053 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1058 /* Start user-mode service */
1059 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1060 if (dwError
== ERROR_SUCCESS
)
1062 #ifdef USE_SERVICE_START_PENDING
1063 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1065 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1070 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1071 LeaveCriticalSection(&StartServiceCriticalSection
);
1073 if (dwError
== ERROR_SUCCESS
)
1077 Group
->ServicesRunning
= TRUE
;
1083 switch (Service
->ErrorControl
)
1085 case SERVICE_ERROR_NORMAL
:
1086 /* FIXME: Log error */
1089 case SERVICE_ERROR_SEVERE
:
1090 if (IsLastKnownGood
== FALSE
)
1092 /* FIXME: Boot last known good configuration */
1096 case SERVICE_ERROR_CRITICAL
:
1097 if (IsLastKnownGood
== FALSE
)
1099 /* FIXME: Boot last known good configuration */
1115 ScmAutoStartServices(VOID
)
1117 PLIST_ENTRY GroupEntry
;
1118 PLIST_ENTRY ServiceEntry
;
1119 PSERVICE_GROUP CurrentGroup
;
1120 PSERVICE CurrentService
;
1123 /* Clear 'ServiceVisited' flag */
1124 ServiceEntry
= ServiceListHead
.Flink
;
1125 while (ServiceEntry
!= &ServiceListHead
)
1127 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1128 CurrentService
->ServiceVisited
= FALSE
;
1129 ServiceEntry
= ServiceEntry
->Flink
;
1132 /* Start all services which are members of an existing group */
1133 GroupEntry
= GroupListHead
.Flink
;
1134 while (GroupEntry
!= &GroupListHead
)
1136 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1138 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1140 /* Start all services witch have a valid tag */
1141 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1143 ServiceEntry
= ServiceListHead
.Flink
;
1144 while (ServiceEntry
!= &ServiceListHead
)
1146 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1148 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1149 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1150 (CurrentService
->ServiceVisited
== FALSE
) &&
1151 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1153 CurrentService
->ServiceVisited
= TRUE
;
1154 ScmStartService(CurrentService
, 0, NULL
);
1157 ServiceEntry
= ServiceEntry
->Flink
;
1161 /* Start all services which have an invalid tag or which do not have a tag */
1162 ServiceEntry
= ServiceListHead
.Flink
;
1163 while (ServiceEntry
!= &ServiceListHead
)
1165 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1167 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1168 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1169 (CurrentService
->ServiceVisited
== FALSE
))
1171 CurrentService
->ServiceVisited
= TRUE
;
1172 ScmStartService(CurrentService
, 0, NULL
);
1175 ServiceEntry
= ServiceEntry
->Flink
;
1178 GroupEntry
= GroupEntry
->Flink
;
1181 /* Start all services which are members of any non-existing group */
1182 ServiceEntry
= ServiceListHead
.Flink
;
1183 while (ServiceEntry
!= &ServiceListHead
)
1185 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1187 if ((CurrentService
->lpGroup
!= NULL
) &&
1188 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1189 (CurrentService
->ServiceVisited
== FALSE
))
1191 CurrentService
->ServiceVisited
= TRUE
;
1192 ScmStartService(CurrentService
, 0, NULL
);
1195 ServiceEntry
= ServiceEntry
->Flink
;
1198 /* Start all services which are not a member of any group */
1199 ServiceEntry
= ServiceListHead
.Flink
;
1200 while (ServiceEntry
!= &ServiceListHead
)
1202 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1204 if ((CurrentService
->lpGroup
== NULL
) &&
1205 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1206 (CurrentService
->ServiceVisited
== FALSE
))
1208 CurrentService
->ServiceVisited
= TRUE
;
1209 ScmStartService(CurrentService
, 0, NULL
);
1212 ServiceEntry
= ServiceEntry
->Flink
;
1215 /* Clear 'ServiceVisited' flag again */
1216 ServiceEntry
= ServiceListHead
.Flink
;
1217 while (ServiceEntry
!= &ServiceListHead
)
1219 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1220 CurrentService
->ServiceVisited
= FALSE
;
1221 ServiceEntry
= ServiceEntry
->Flink
;
1227 ScmAutoShutdownServices(VOID
)
1229 PLIST_ENTRY ServiceEntry
;
1230 PSERVICE CurrentService
;
1232 DPRINT("ScmAutoShutdownServices() called\n");
1234 ServiceEntry
= ServiceListHead
.Flink
;
1235 while (ServiceEntry
!= &ServiceListHead
)
1237 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1239 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1240 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1242 /* shutdown service */
1243 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
);
1246 ServiceEntry
= ServiceEntry
->Flink
;
1249 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1254 ScmLockDatabaseExclusive(VOID
)
1256 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1261 ScmLockDatabaseShared(VOID
)
1263 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1268 ScmUnlockDatabase(VOID
)
1270 RtlReleaseResource(&DatabaseLock
);
1275 ScmInitNamedPipeCriticalSection(VOID
)
1277 InitializeCriticalSection(&NamedPipeCriticalSection
);
1278 InitializeCriticalSection(&StartServiceCriticalSection
);
1283 ScmDeleteNamedPipeCriticalSection(VOID
)
1285 DeleteCriticalSection(&StartServiceCriticalSection
);
1286 DeleteCriticalSection(&NamedPipeCriticalSection
);