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
,
684 PSCM_CONTROL_PACKET ControlPacket
;
685 SCM_REPLY_PACKET ReplyPacket
;
687 DWORD dwWriteCount
= 0;
688 DWORD dwReadCount
= 0;
690 DWORD dwError
= ERROR_SUCCESS
;
692 DPRINT("ScmControlService() called\n");
694 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
696 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
698 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
699 if (ControlPacket
== NULL
)
700 return ERROR_NOT_ENOUGH_MEMORY
;
702 ControlPacket
->dwControl
= dwControl
;
703 ControlPacket
->dwSize
= TotalLength
;
704 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
705 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
707 /* Send the control packet */
708 WriteFile(Service
->ControlPipeHandle
,
710 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
715 ReadFile(Service
->ControlPipeHandle
,
717 sizeof(SCM_REPLY_PACKET
),
721 /* Release the contol packet */
722 HeapFree(GetProcessHeap(),
726 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
728 dwError
= ReplyPacket
.dwError
;
731 DPRINT("ScmControlService() done\n");
738 ScmSendStartCommand(PSERVICE Service
,
742 PSCM_CONTROL_PACKET ControlPacket
;
743 SCM_REPLY_PACKET ReplyPacket
;
745 DWORD ArgsLength
= 0;
748 DWORD dwWriteCount
= 0;
749 DWORD dwReadCount
= 0;
750 DWORD dwError
= ERROR_SUCCESS
;
753 DPRINT("ScmSendStartCommand() called\n");
755 /* Calculate the total length of the start command line */
756 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
759 for (i
= 0; i
< argc
; i
++)
761 DPRINT("Arg: %S\n", argv
[i
]);
762 Length
= wcslen(argv
[i
]) + 1;
763 TotalLength
+= Length
;
764 ArgsLength
+= Length
;
768 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
770 /* Allocate a control packet */
771 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
773 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
774 if (ControlPacket
== NULL
)
775 return ERROR_NOT_ENOUGH_MEMORY
;
777 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
778 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
779 ControlPacket
->dwSize
= TotalLength
;
780 Ptr
= &ControlPacket
->szArguments
[0];
781 wcscpy(Ptr
, Service
->lpServiceName
);
782 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
784 /* Copy argument list */
788 DPRINT1("Arguments sent to service ignored!\n");
790 memcpy(Ptr
, Arguments
, ArgsLength
);
795 /* Terminate the argument list */
798 /* Send the start command */
799 WriteFile(Service
->ControlPipeHandle
,
801 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
806 ReadFile(Service
->ControlPipeHandle
,
808 sizeof(SCM_REPLY_PACKET
),
812 /* Release the contol packet */
813 HeapFree(GetProcessHeap(),
817 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
819 dwError
= ReplyPacket
.dwError
;
822 DPRINT("ScmSendStartCommand() done\n");
829 ScmStartUserModeService(PSERVICE Service
,
833 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
834 PROCESS_INFORMATION ProcessInformation
;
835 STARTUPINFOW StartupInfo
;
836 UNICODE_STRING ImagePath
;
838 DWORD ServiceCurrent
= 0;
841 DWORD dwError
= ERROR_SUCCESS
;
842 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
843 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
844 DWORD KeyDisposition
;
847 RtlInitUnicodeString(&ImagePath
, NULL
);
849 /* Get service data */
850 RtlZeroMemory(&QueryTable
,
853 QueryTable
[0].Name
= L
"Type";
854 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
855 QueryTable
[0].EntryContext
= &Type
;
857 QueryTable
[1].Name
= L
"ImagePath";
858 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
859 QueryTable
[1].EntryContext
= &ImagePath
;
861 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
862 Service
->lpServiceName
,
866 if (!NT_SUCCESS(Status
))
868 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
869 return RtlNtStatusToDosError(Status
);
871 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
872 DPRINT("Type: %lx\n", Type
);
874 /* Get the service number */
875 /* TODO: Create registry entry with correct write access */
876 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
877 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
879 KEY_WRITE
| KEY_READ
,
884 if (ERROR_SUCCESS
!= Status
)
886 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
890 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
892 DWORD KeySize
= sizeof(ServiceCurrent
);
893 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
895 if (ERROR_SUCCESS
!= Status
)
897 RegCloseKey(hServiceCurrentKey
);
898 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
905 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
907 RegCloseKey(hServiceCurrentKey
);
909 if (ERROR_SUCCESS
!= Status
)
911 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
915 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
916 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
917 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
919 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
925 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
926 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
928 DPRINT1("Failed to create control pipe!\n");
929 return GetLastError();
932 StartupInfo
.cb
= sizeof(StartupInfo
);
933 StartupInfo
.lpReserved
= NULL
;
934 StartupInfo
.lpDesktop
= NULL
;
935 StartupInfo
.lpTitle
= NULL
;
936 StartupInfo
.dwFlags
= 0;
937 StartupInfo
.cbReserved2
= 0;
938 StartupInfo
.lpReserved2
= 0;
940 Result
= CreateProcessW(NULL
,
945 DETACHED_PROCESS
| CREATE_SUSPENDED
,
949 &ProcessInformation
);
950 RtlFreeUnicodeString(&ImagePath
);
954 dwError
= GetLastError();
955 /* Close control pipe */
956 CloseHandle(Service
->ControlPipeHandle
);
957 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
959 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
963 DPRINT("Process Id: %lu Handle %lx\n",
964 ProcessInformation
.dwProcessId
,
965 ProcessInformation
.hProcess
);
966 DPRINT("Thread Id: %lu Handle %lx\n",
967 ProcessInformation
.dwThreadId
,
968 ProcessInformation
.hThread
);
970 /* Get process and thread ids */
971 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
972 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
975 ResumeThread(ProcessInformation
.hThread
);
977 /* Connect control pipe */
978 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
979 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
983 DPRINT("Control pipe connected!\n");
985 /* Read SERVICE_STATUS_HANDLE from pipe */
986 if (!ReadFile(Service
->ControlPipeHandle
,
987 (LPVOID
)&dwProcessId
,
992 dwError
= GetLastError();
993 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
998 DPRINT("Received service process ID %lu\n", dwProcessId
);
1000 /* Send start command */
1001 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1006 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1008 /* Close control pipe */
1009 CloseHandle(Service
->ControlPipeHandle
);
1010 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1011 Service
->ProcessId
= 0;
1012 Service
->ThreadId
= 0;
1015 /* Close process and thread handle */
1016 CloseHandle(ProcessInformation
.hThread
);
1017 CloseHandle(ProcessInformation
.hProcess
);
1024 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1026 PSERVICE_GROUP Group
= Service
->lpGroup
;
1027 DWORD dwError
= ERROR_SUCCESS
;
1029 DPRINT("ScmStartService() called\n");
1031 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1032 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1034 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1037 dwError
= ScmLoadDriver(Service
);
1038 if (dwError
== ERROR_SUCCESS
)
1040 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1041 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1046 /* Start user-mode service */
1047 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1048 if (dwError
== ERROR_SUCCESS
)
1050 #ifdef USE_SERVICE_START_PENDING
1051 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1053 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1058 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1060 if (dwError
== ERROR_SUCCESS
)
1064 Group
->ServicesRunning
= TRUE
;
1070 switch (Service
->ErrorControl
)
1072 case SERVICE_ERROR_NORMAL
:
1073 /* FIXME: Log error */
1076 case SERVICE_ERROR_SEVERE
:
1077 if (IsLastKnownGood
== FALSE
)
1079 /* FIXME: Boot last known good configuration */
1083 case SERVICE_ERROR_CRITICAL
:
1084 if (IsLastKnownGood
== FALSE
)
1086 /* FIXME: Boot last known good configuration */
1102 ScmAutoStartServices(VOID
)
1104 PLIST_ENTRY GroupEntry
;
1105 PLIST_ENTRY ServiceEntry
;
1106 PSERVICE_GROUP CurrentGroup
;
1107 PSERVICE CurrentService
;
1110 /* Clear 'ServiceVisited' flag */
1111 ServiceEntry
= ServiceListHead
.Flink
;
1112 while (ServiceEntry
!= &ServiceListHead
)
1114 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1115 CurrentService
->ServiceVisited
= FALSE
;
1116 ServiceEntry
= ServiceEntry
->Flink
;
1119 /* Start all services which are members of an existing group */
1120 GroupEntry
= GroupListHead
.Flink
;
1121 while (GroupEntry
!= &GroupListHead
)
1123 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1125 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1127 /* Start all services witch have a valid tag */
1128 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1130 ServiceEntry
= ServiceListHead
.Flink
;
1131 while (ServiceEntry
!= &ServiceListHead
)
1133 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1135 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1136 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1137 (CurrentService
->ServiceVisited
== FALSE
) &&
1138 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1140 CurrentService
->ServiceVisited
= TRUE
;
1141 ScmStartService(CurrentService
, 0, NULL
);
1144 ServiceEntry
= ServiceEntry
->Flink
;
1148 /* Start all services which have an invalid tag or which do not have a tag */
1149 ServiceEntry
= ServiceListHead
.Flink
;
1150 while (ServiceEntry
!= &ServiceListHead
)
1152 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1154 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1155 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1156 (CurrentService
->ServiceVisited
== FALSE
))
1158 CurrentService
->ServiceVisited
= TRUE
;
1159 ScmStartService(CurrentService
, 0, NULL
);
1162 ServiceEntry
= ServiceEntry
->Flink
;
1165 GroupEntry
= GroupEntry
->Flink
;
1168 /* Start all services which are members of any non-existing group */
1169 ServiceEntry
= ServiceListHead
.Flink
;
1170 while (ServiceEntry
!= &ServiceListHead
)
1172 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1174 if ((CurrentService
->lpGroup
!= NULL
) &&
1175 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1176 (CurrentService
->ServiceVisited
== FALSE
))
1178 CurrentService
->ServiceVisited
= TRUE
;
1179 ScmStartService(CurrentService
, 0, NULL
);
1182 ServiceEntry
= ServiceEntry
->Flink
;
1185 /* Start all services which are not a member of any group */
1186 ServiceEntry
= ServiceListHead
.Flink
;
1187 while (ServiceEntry
!= &ServiceListHead
)
1189 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1191 if ((CurrentService
->lpGroup
== NULL
) &&
1192 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1193 (CurrentService
->ServiceVisited
== FALSE
))
1195 CurrentService
->ServiceVisited
= TRUE
;
1196 ScmStartService(CurrentService
, 0, NULL
);
1199 ServiceEntry
= ServiceEntry
->Flink
;
1202 /* Clear 'ServiceVisited' flag again */
1203 ServiceEntry
= ServiceListHead
.Flink
;
1204 while (ServiceEntry
!= &ServiceListHead
)
1206 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1207 CurrentService
->ServiceVisited
= FALSE
;
1208 ServiceEntry
= ServiceEntry
->Flink
;
1214 ScmAutoShutdownServices(VOID
)
1216 PLIST_ENTRY ServiceEntry
;
1217 PSERVICE CurrentService
;
1219 DPRINT("ScmAutoShutdownServices() called\n");
1221 ServiceEntry
= ServiceListHead
.Flink
;
1222 while (ServiceEntry
!= &ServiceListHead
)
1224 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1226 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1227 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1229 /* shutdown service */
1230 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
);
1233 ServiceEntry
= ServiceEntry
->Flink
;
1236 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1241 ScmLockDatabaseExclusive(VOID
)
1243 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1248 ScmLockDatabaseShared(VOID
)
1250 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1255 ScmUnlockDatabase(VOID
)
1257 RtlReleaseResource(&DatabaseLock
);