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 ScmGetServiceEntryByClientHandle(HANDLE Handle
)
127 PLIST_ENTRY ServiceEntry
;
128 PSERVICE CurrentService
;
130 DPRINT("ScmGetServiceEntryByClientHandle() called\n");
131 DPRINT("looking for %p\n", Handle
);
133 ServiceEntry
= ServiceListHead
.Flink
;
134 while (ServiceEntry
!= &ServiceListHead
)
136 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
140 if (CurrentService
->hClient
== Handle
)
142 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
143 return CurrentService
;
146 ServiceEntry
= ServiceEntry
->Flink
;
149 DPRINT("Couldn't find a matching service\n");
156 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
157 PSERVICE
*lpServiceRecord
)
159 PSERVICE lpService
= NULL
;
161 DPRINT("Service: '%S'\n", lpServiceName
);
163 /* Allocate service entry */
164 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
166 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
167 if (lpService
== NULL
)
168 return ERROR_NOT_ENOUGH_MEMORY
;
170 *lpServiceRecord
= lpService
;
172 /* Copy service name */
173 wcscpy(lpService
->szServiceName
, lpServiceName
);
174 lpService
->lpServiceName
= lpService
->szServiceName
;
175 lpService
->lpDisplayName
= lpService
->lpServiceName
;
177 /* Set the resume count */
178 lpService
->dwResumeCount
= dwResumeCount
++;
180 /* Append service record */
181 InsertTailList(&ServiceListHead
,
182 &lpService
->ServiceListEntry
);
184 /* Initialize the service status */
185 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
186 lpService
->Status
.dwControlsAccepted
= 0;
187 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
188 lpService
->Status
.dwServiceSpecificExitCode
= 0;
189 lpService
->Status
.dwCheckPoint
= 0;
190 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
192 return ERROR_SUCCESS
;
197 ScmDeleteServiceRecord(PSERVICE lpService
)
199 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
201 /* Delete the display name */
202 if (lpService
->lpDisplayName
!= NULL
&&
203 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
204 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
206 /* Decrement the image reference counter */
207 if (lpService
->lpImage
)
208 lpService
->lpImage
->dwServiceRefCount
--;
210 /* Decrement the group reference counter */
211 if (lpService
->lpGroup
)
212 lpService
->lpGroup
->dwRefCount
--;
214 /* FIXME: SecurityDescriptor */
216 /* Close the control pipe */
217 if (lpService
->ControlPipeHandle
!= INVALID_HANDLE_VALUE
)
218 CloseHandle(lpService
->ControlPipeHandle
);
220 /* Remove the Service from the List */
221 RemoveEntryList(&lpService
->ServiceListEntry
);
223 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
225 /* Delete the service record */
226 HeapFree(GetProcessHeap(), 0, lpService
);
233 CreateServiceListEntry(LPCWSTR lpServiceName
,
236 PSERVICE lpService
= NULL
;
237 LPWSTR lpDisplayName
= NULL
;
238 LPWSTR lpGroup
= NULL
;
243 DWORD dwErrorControl
;
246 DPRINT("Service: '%S'\n", lpServiceName
);
247 if (*lpServiceName
== L
'{')
248 return ERROR_SUCCESS
;
250 dwSize
= sizeof(DWORD
);
251 dwError
= RegQueryValueExW(hServiceKey
,
255 (LPBYTE
)&dwServiceType
,
257 if (dwError
!= ERROR_SUCCESS
)
258 return ERROR_SUCCESS
;
260 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
261 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
262 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
263 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
264 return ERROR_SUCCESS
;
266 DPRINT("Service type: %lx\n", dwServiceType
);
268 dwSize
= sizeof(DWORD
);
269 dwError
= RegQueryValueExW(hServiceKey
,
273 (LPBYTE
)&dwStartType
,
275 if (dwError
!= ERROR_SUCCESS
)
276 return ERROR_SUCCESS
;
278 DPRINT("Start type: %lx\n", dwStartType
);
280 dwSize
= sizeof(DWORD
);
281 dwError
= RegQueryValueExW(hServiceKey
,
285 (LPBYTE
)&dwErrorControl
,
287 if (dwError
!= ERROR_SUCCESS
)
288 return ERROR_SUCCESS
;
290 DPRINT("Error control: %lx\n", dwErrorControl
);
292 dwError
= RegQueryValueExW(hServiceKey
,
298 if (dwError
!= ERROR_SUCCESS
)
301 DPRINT("Tag: %lx\n", dwTagId
);
303 dwError
= ScmReadString(hServiceKey
,
306 if (dwError
!= ERROR_SUCCESS
)
309 DPRINT("Group: %S\n", lpGroup
);
311 dwError
= ScmReadString(hServiceKey
,
314 if (dwError
!= ERROR_SUCCESS
)
315 lpDisplayName
= NULL
;
317 DPRINT("Display name: %S\n", lpDisplayName
);
319 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
321 if (dwError
!= ERROR_SUCCESS
)
324 lpService
->Status
.dwServiceType
= dwServiceType
;
325 lpService
->dwStartType
= dwStartType
;
326 lpService
->dwErrorControl
= dwErrorControl
;
327 lpService
->dwTag
= dwTagId
;
331 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
332 if (dwError
!= ERROR_SUCCESS
)
336 if (lpDisplayName
!= NULL
)
338 lpService
->lpDisplayName
= lpDisplayName
;
339 lpDisplayName
= NULL
;
342 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
343 if (lpService
->lpGroup
!= NULL
)
345 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
347 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
348 lpService
->dwStartType
,
349 lpService
->Status
.dwServiceType
,
351 lpService
->dwErrorControl
);
353 if (ScmIsDeleteFlagSet(hServiceKey
))
354 lpService
->bDeleted
= TRUE
;
358 HeapFree(GetProcessHeap(), 0, lpGroup
);
360 if (lpDisplayName
!= NULL
)
361 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
368 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
370 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
371 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
374 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
377 /* Find the maximum subkey length so that we can allocate a buffer */
378 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
379 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
383 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
384 /* Name too big: alloc a buffer for it */
385 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
388 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
391 while (dwRet
== ERROR_SUCCESS
)
393 dwSize
= dwMaxSubkeyLen
;
394 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
395 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
396 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
398 if (dwRet
== ERROR_NO_MORE_ITEMS
)
399 dwRet
= ERROR_SUCCESS
;
401 if (lpszName
!= szNameBuf
)
402 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
406 RegCloseKey(hSubKey
);
408 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
415 ScmDeleteMarkedServices(VOID
)
417 PLIST_ENTRY ServiceEntry
;
418 PSERVICE CurrentService
;
422 ServiceEntry
= ServiceListHead
.Flink
;
423 while (ServiceEntry
!= &ServiceListHead
)
425 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
427 ServiceEntry
= ServiceEntry
->Flink
;
429 if (CurrentService
->bDeleted
== TRUE
)
431 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
432 L
"System\\CurrentControlSet\\Services",
436 if (dwError
== ERROR_SUCCESS
)
438 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
439 RegCloseKey(hServicesKey
);
440 if (dwError
== ERROR_SUCCESS
)
442 RemoveEntryList(&CurrentService
->ServiceListEntry
);
443 HeapFree(GetProcessHeap(), 0, CurrentService
);
447 if (dwError
!= ERROR_SUCCESS
)
448 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
460 DPRINT("WaitForLSA() called\n");
462 hEvent
= CreateEventW(NULL
,
465 L
"LSA_RPC_SERVER_ACTIVE");
468 dwError
= GetLastError();
469 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
471 if (dwError
== ERROR_ALREADY_EXISTS
)
473 hEvent
= OpenEventW(SYNCHRONIZE
,
475 L
"LSA_RPC_SERVER_ACTIVE");
478 DPRINT1("Could not open the notification event!\n");
484 DPRINT("Wait for LSA!\n");
485 WaitForSingleObject(hEvent
, INFINITE
);
486 DPRINT("LSA is available!\n");
490 DPRINT("WaitForLSA() done\n");
495 ScmCreateServiceDatabase(VOID
)
497 WCHAR szSubKey
[MAX_PATH
];
501 DWORD dwSubKeyLength
;
502 FILETIME ftLastChanged
;
505 DPRINT("ScmCreateServiceDatabase() called\n");
507 dwError
= ScmCreateGroupList();
508 if (dwError
!= ERROR_SUCCESS
)
511 /* Initialize basic variables */
512 InitializeListHead(&ServiceListHead
);
514 /* Initialize the database lock */
515 RtlInitializeResource(&DatabaseLock
);
517 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
518 L
"System\\CurrentControlSet\\Services",
522 if (dwError
!= ERROR_SUCCESS
)
528 dwSubKeyLength
= MAX_PATH
;
529 dwError
= RegEnumKeyExW(hServicesKey
,
537 if (dwError
== ERROR_SUCCESS
&&
540 DPRINT("SubKeyName: '%S'\n", szSubKey
);
542 dwError
= RegOpenKeyExW(hServicesKey
,
547 if (dwError
== ERROR_SUCCESS
)
549 dwError
= CreateServiceListEntry(szSubKey
,
552 RegCloseKey(hServiceKey
);
556 if (dwError
!= ERROR_SUCCESS
)
562 RegCloseKey(hServicesKey
);
567 /* Delete services that are marked for delete */
568 ScmDeleteMarkedServices();
570 DPRINT("ScmCreateServiceDatabase() done\n");
572 return ERROR_SUCCESS
;
577 ScmShutdownServiceDatabase(VOID
)
579 DPRINT("ScmShutdownServiceDatabase() called\n");
581 ScmDeleteMarkedServices();
582 RtlDeleteResource(&DatabaseLock
);
584 DPRINT("ScmShutdownServiceDatabase() done\n");
589 ScmCheckDriver(PSERVICE Service
)
591 OBJECT_ATTRIBUTES ObjectAttributes
;
592 UNICODE_STRING DirName
;
595 POBJECT_DIRECTORY_INFORMATION DirInfo
;
600 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
602 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
604 RtlInitUnicodeString(&DirName
,
609 RtlInitUnicodeString(&DirName
,
613 InitializeObjectAttributes(&ObjectAttributes
,
619 Status
= NtOpenDirectoryObject(&DirHandle
,
620 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
622 if (!NT_SUCCESS(Status
))
627 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
628 2 * MAX_PATH
* sizeof(WCHAR
);
629 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
636 Status
= NtQueryDirectoryObject(DirHandle
,
643 if (Status
== STATUS_NO_MORE_ENTRIES
)
645 /* FIXME: Add current service to 'failed service' list */
646 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
650 if (!NT_SUCCESS(Status
))
653 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
655 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
657 DPRINT("Found: '%S' '%wZ'\n",
658 Service
->lpServiceName
, &DirInfo
->Name
);
660 /* Mark service as 'running' */
661 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
663 /* Mark the service group as 'running' */
664 if (Service
->lpGroup
!= NULL
)
666 Service
->lpGroup
->ServicesRunning
= TRUE
;
673 HeapFree(GetProcessHeap(),
678 return STATUS_SUCCESS
;
683 ScmGetBootAndSystemDriverState(VOID
)
685 PLIST_ENTRY ServiceEntry
;
686 PSERVICE CurrentService
;
688 DPRINT("ScmGetBootAndSystemDriverState() called\n");
690 ServiceEntry
= ServiceListHead
.Flink
;
691 while (ServiceEntry
!= &ServiceListHead
)
693 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
695 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
696 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
699 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
701 ScmCheckDriver(CurrentService
);
704 ServiceEntry
= ServiceEntry
->Flink
;
707 DPRINT("ScmGetBootAndSystemDriverState() done\n");
712 ScmControlService(PSERVICE Service
,
714 LPSERVICE_STATUS lpServiceStatus
)
716 PSCM_CONTROL_PACKET ControlPacket
;
720 DPRINT("ScmControlService() called\n");
722 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
724 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
726 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
727 if (ControlPacket
== NULL
)
728 return ERROR_NOT_ENOUGH_MEMORY
;
730 ControlPacket
->dwControl
= dwControl
;
731 ControlPacket
->hClient
= Service
->hClient
;
732 ControlPacket
->dwSize
= TotalLength
;
733 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
735 /* Send the control packet */
736 WriteFile(Service
->ControlPipeHandle
,
738 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
742 /* FIXME: Read the reply */
744 /* Release the contol packet */
745 HeapFree(GetProcessHeap(),
749 RtlCopyMemory(lpServiceStatus
,
751 sizeof(SERVICE_STATUS
));
753 DPRINT("ScmControlService) done\n");
755 return ERROR_SUCCESS
;
760 ScmSendStartCommand(PSERVICE Service
,
764 PSCM_CONTROL_PACKET ControlPacket
;
766 DWORD ArgsLength
= 0;
771 DPRINT("ScmSendStartCommand() called\n");
773 /* Calculate the total length of the start command line */
774 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
777 for (Count
= 0; Count
< argc
; Count
++)
779 DPRINT("Arg: %S\n", argv
[Count
]);
780 Length
= wcslen(argv
[Count
]) + 1;
781 TotalLength
+= Length
;
782 ArgsLength
+= Length
;
786 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
788 /* Allocate a control packet */
789 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
791 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
792 if (ControlPacket
== NULL
)
793 return ERROR_NOT_ENOUGH_MEMORY
;
795 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
796 ControlPacket
->hClient
= Service
->hClient
;
797 ControlPacket
->dwSize
= TotalLength
;
798 Ptr
= &ControlPacket
->szArguments
[0];
799 wcscpy(Ptr
, Service
->lpServiceName
);
800 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
802 /* Copy argument list */
806 DPRINT1("Arguments sent to service ignored!\n");
808 memcpy(Ptr
, Arguments
, ArgsLength
);
813 /* Terminate the argument list */
816 /* Send the start command */
817 WriteFile(Service
->ControlPipeHandle
,
819 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
823 /* FIXME: Read the reply */
825 /* Release the contol packet */
826 HeapFree(GetProcessHeap(),
830 DPRINT("ScmSendStartCommand() done\n");
832 return ERROR_SUCCESS
;
837 ScmStartUserModeService(PSERVICE Service
,
841 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
842 PROCESS_INFORMATION ProcessInformation
;
843 STARTUPINFOW StartupInfo
;
844 UNICODE_STRING ImagePath
;
846 DWORD ServiceCurrent
= 0;
849 DWORD dwError
= ERROR_SUCCESS
;
850 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
851 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
852 DWORD KeyDisposition
;
854 RtlInitUnicodeString(&ImagePath
, NULL
);
856 /* Get service data */
857 RtlZeroMemory(&QueryTable
,
860 QueryTable
[0].Name
= L
"Type";
861 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
862 QueryTable
[0].EntryContext
= &Type
;
864 QueryTable
[1].Name
= L
"ImagePath";
865 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
866 QueryTable
[1].EntryContext
= &ImagePath
;
868 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
869 Service
->lpServiceName
,
873 if (!NT_SUCCESS(Status
))
875 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
876 return RtlNtStatusToDosError(Status
);
878 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
879 DPRINT("Type: %lx\n", Type
);
881 /* Get the service number */
882 /* TODO: Create registry entry with correct write access */
883 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
884 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
886 KEY_WRITE
| KEY_READ
,
891 if (ERROR_SUCCESS
!= Status
)
893 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
897 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
899 DWORD KeySize
= sizeof(ServiceCurrent
);
900 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
902 if (ERROR_SUCCESS
!= Status
)
904 RegCloseKey(hServiceCurrentKey
);
905 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
912 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
914 RegCloseKey(hServiceCurrentKey
);
916 if (ERROR_SUCCESS
!= Status
)
918 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
922 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
923 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
924 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
926 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
932 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
933 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
935 DPRINT1("Failed to create control pipe!\n");
936 return GetLastError();
939 StartupInfo
.cb
= sizeof(StartupInfo
);
940 StartupInfo
.lpReserved
= NULL
;
941 StartupInfo
.lpDesktop
= NULL
;
942 StartupInfo
.lpTitle
= NULL
;
943 StartupInfo
.dwFlags
= 0;
944 StartupInfo
.cbReserved2
= 0;
945 StartupInfo
.lpReserved2
= 0;
947 Result
= CreateProcessW(NULL
,
952 DETACHED_PROCESS
| CREATE_SUSPENDED
,
956 &ProcessInformation
);
957 RtlFreeUnicodeString(&ImagePath
);
961 dwError
= GetLastError();
962 /* Close control pipe */
963 CloseHandle(Service
->ControlPipeHandle
);
964 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
966 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
970 DPRINT("Process Id: %lu Handle %lx\n",
971 ProcessInformation
.dwProcessId
,
972 ProcessInformation
.hProcess
);
973 DPRINT("Thread Id: %lu Handle %lx\n",
974 ProcessInformation
.dwThreadId
,
975 ProcessInformation
.hThread
);
977 /* Get process and thread ids */
978 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
979 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
982 ResumeThread(ProcessInformation
.hThread
);
984 /* Connect control pipe */
985 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
986 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
990 DPRINT("Control pipe connected!\n");
992 /* Read SERVICE_STATUS_HANDLE from pipe */
993 if (!ReadFile(Service
->ControlPipeHandle
,
994 (LPVOID
)&Service
->hClient
,
999 dwError
= GetLastError();
1000 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1005 DPRINT("Received service status %lu\n", Service
->hClient
);
1007 /* Send start command */
1008 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1013 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1015 /* Close control pipe */
1016 CloseHandle(Service
->ControlPipeHandle
);
1017 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1018 Service
->ProcessId
= 0;
1019 Service
->ThreadId
= 0;
1022 /* Close process and thread handle */
1023 CloseHandle(ProcessInformation
.hThread
);
1024 CloseHandle(ProcessInformation
.hProcess
);
1031 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1033 PSERVICE_GROUP Group
= Service
->lpGroup
;
1034 DWORD dwError
= ERROR_SUCCESS
;
1036 DPRINT("ScmStartService() called\n");
1038 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1039 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1041 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1044 dwError
= ScmLoadDriver(Service
);
1045 if (dwError
== ERROR_SUCCESS
)
1047 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1048 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1053 /* Start user-mode service */
1054 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1055 if (dwError
== ERROR_SUCCESS
)
1057 #ifdef USE_SERVICE_START_PENDING
1058 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1060 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1065 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1067 if (dwError
== ERROR_SUCCESS
)
1071 Group
->ServicesRunning
= TRUE
;
1077 switch (Service
->ErrorControl
)
1079 case SERVICE_ERROR_NORMAL
:
1080 /* FIXME: Log error */
1083 case SERVICE_ERROR_SEVERE
:
1084 if (IsLastKnownGood
== FALSE
)
1086 /* FIXME: Boot last known good configuration */
1090 case SERVICE_ERROR_CRITICAL
:
1091 if (IsLastKnownGood
== FALSE
)
1093 /* FIXME: Boot last known good configuration */
1109 ScmAutoStartServices(VOID
)
1111 PLIST_ENTRY GroupEntry
;
1112 PLIST_ENTRY ServiceEntry
;
1113 PSERVICE_GROUP CurrentGroup
;
1114 PSERVICE CurrentService
;
1117 /* Clear 'ServiceVisited' flag */
1118 ServiceEntry
= ServiceListHead
.Flink
;
1119 while (ServiceEntry
!= &ServiceListHead
)
1121 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1122 CurrentService
->ServiceVisited
= FALSE
;
1123 ServiceEntry
= ServiceEntry
->Flink
;
1126 /* Start all services which are members of an existing group */
1127 GroupEntry
= GroupListHead
.Flink
;
1128 while (GroupEntry
!= &GroupListHead
)
1130 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1132 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1134 /* Start all services witch have a valid tag */
1135 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1137 ServiceEntry
= ServiceListHead
.Flink
;
1138 while (ServiceEntry
!= &ServiceListHead
)
1140 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1142 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1143 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1144 (CurrentService
->ServiceVisited
== FALSE
) &&
1145 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1147 CurrentService
->ServiceVisited
= TRUE
;
1148 ScmStartService(CurrentService
, 0, NULL
);
1151 ServiceEntry
= ServiceEntry
->Flink
;
1155 /* Start all services which have an invalid tag or which do not have a tag */
1156 ServiceEntry
= ServiceListHead
.Flink
;
1157 while (ServiceEntry
!= &ServiceListHead
)
1159 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1161 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1162 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1163 (CurrentService
->ServiceVisited
== FALSE
))
1165 CurrentService
->ServiceVisited
= TRUE
;
1166 ScmStartService(CurrentService
, 0, NULL
);
1169 ServiceEntry
= ServiceEntry
->Flink
;
1172 GroupEntry
= GroupEntry
->Flink
;
1175 /* Start all services which are members of any non-existing group */
1176 ServiceEntry
= ServiceListHead
.Flink
;
1177 while (ServiceEntry
!= &ServiceListHead
)
1179 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1181 if ((CurrentService
->lpGroup
!= NULL
) &&
1182 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1183 (CurrentService
->ServiceVisited
== FALSE
))
1185 CurrentService
->ServiceVisited
= TRUE
;
1186 ScmStartService(CurrentService
, 0, NULL
);
1189 ServiceEntry
= ServiceEntry
->Flink
;
1192 /* Start all services which are not a member of any group */
1193 ServiceEntry
= ServiceListHead
.Flink
;
1194 while (ServiceEntry
!= &ServiceListHead
)
1196 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1198 if ((CurrentService
->lpGroup
== NULL
) &&
1199 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1200 (CurrentService
->ServiceVisited
== FALSE
))
1202 CurrentService
->ServiceVisited
= TRUE
;
1203 ScmStartService(CurrentService
, 0, NULL
);
1206 ServiceEntry
= ServiceEntry
->Flink
;
1209 /* Clear 'ServiceVisited' flag again */
1210 ServiceEntry
= ServiceListHead
.Flink
;
1211 while (ServiceEntry
!= &ServiceListHead
)
1213 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1214 CurrentService
->ServiceVisited
= FALSE
;
1215 ServiceEntry
= ServiceEntry
->Flink
;
1221 ScmAutoShutdownServices(VOID
)
1223 PLIST_ENTRY ServiceEntry
;
1224 PSERVICE CurrentService
;
1225 SERVICE_STATUS ServiceStatus
;
1227 DPRINT("ScmAutoShutdownServices() called\n");
1229 ServiceEntry
= ServiceListHead
.Flink
;
1230 while (ServiceEntry
!= &ServiceListHead
)
1232 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1234 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1235 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1237 /* shutdown service */
1238 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1241 ServiceEntry
= ServiceEntry
->Flink
;
1244 DPRINT("ScmGetBootAndSystemDriverState() done\n");