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 ImageListHead
;
29 LIST_ENTRY ServiceListHead
;
31 static RTL_RESOURCE DatabaseLock
;
32 static DWORD dwResumeCount
= 1;
34 static CRITICAL_SECTION ControlServiceCriticalSection
;
36 /* FUNCTIONS *****************************************************************/
39 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
41 WCHAR szControlPipeName
[MAX_PATH
+ 1];
42 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
43 DWORD ServiceCurrent
= 0;
48 /* Get the service number */
49 /* TODO: Create registry entry with correct write access */
50 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
51 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
57 if (dwError
!= ERROR_SUCCESS
)
59 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
63 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
65 dwKeySize
= sizeof(DWORD
);
66 dwError
= RegQueryValueExW(hServiceCurrentKey
,
67 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
69 if (dwError
!= ERROR_SUCCESS
)
71 RegCloseKey(hServiceCurrentKey
);
72 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
79 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
81 RegCloseKey(hServiceCurrentKey
);
83 if (dwError
!= ERROR_SUCCESS
)
85 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
89 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
90 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
92 DPRINT("PipeName: %S\n", szControlPipeName
);
94 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
96 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
102 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
103 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
105 DPRINT1("Failed to create control pipe!\n");
106 return GetLastError();
109 return ERROR_SUCCESS
;
113 static PSERVICE_IMAGE
114 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
116 PLIST_ENTRY ImageEntry
;
117 PSERVICE_IMAGE CurrentImage
;
119 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
121 ImageEntry
= ImageListHead
.Flink
;
122 while (ImageEntry
!= &ImageListHead
)
124 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
127 if (_wcsicmp(CurrentImage
->szImagePath
, lpImagePath
) == 0)
129 DPRINT("Found image: '%S'\n", CurrentImage
->szImagePath
);
133 ImageEntry
= ImageEntry
->Flink
;
136 DPRINT1("Couldn't find a matching image\n");
144 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
146 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
147 UNICODE_STRING ImagePath
;
148 PSERVICE_IMAGE pServiceImage
= NULL
;
150 DWORD dwError
= ERROR_SUCCESS
;
152 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
154 RtlInitUnicodeString(&ImagePath
, NULL
);
156 /* Get service data */
157 RtlZeroMemory(&QueryTable
,
160 QueryTable
[0].Name
= L
"ImagePath";
161 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
162 QueryTable
[0].EntryContext
= &ImagePath
;
164 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
165 pService
->lpServiceName
,
169 if (!NT_SUCCESS(Status
))
171 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
172 return RtlNtStatusToDosError(Status
);
175 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
177 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
178 if (pServiceImage
== NULL
)
180 /* Create a new service image */
181 pServiceImage
= (PSERVICE_IMAGE
)HeapAlloc(GetProcessHeap(),
183 sizeof(SERVICE_IMAGE
) + ((wcslen(ImagePath
.Buffer
) + 1) * sizeof(WCHAR
)));
184 if (pServiceImage
== NULL
)
186 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
190 pServiceImage
->dwImageRunCount
= 1;
191 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
192 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
194 /* Set the image path */
195 wcscpy(pServiceImage
->szImagePath
,
198 RtlFreeUnicodeString(&ImagePath
);
200 /* Create the control pipe */
201 dwError
= ScmCreateNewControlPipe(pServiceImage
);
202 if (dwError
!= ERROR_SUCCESS
)
204 HeapFree(GetProcessHeap(), 0, pServiceImage
);
208 /* FIXME: Add more initialization code here */
211 /* Append service record */
212 InsertTailList(&ImageListHead
,
213 &pServiceImage
->ImageListEntry
);
217 /* Increment the run counter */
218 pServiceImage
->dwImageRunCount
++;
221 /* Link the service image to the service */
222 pService
->lpImage
= pServiceImage
;
225 RtlFreeUnicodeString(&ImagePath
);
227 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
234 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
236 DPRINT1("ScmDereferenceServiceImage() called\n");
238 pServiceImage
->dwImageRunCount
--;
240 if (pServiceImage
->dwImageRunCount
== 0)
242 DPRINT1("dwImageRunCount == 0\n");
244 /* FIXME: Terminate the process */
246 /* Remove the service image from the list */
247 RemoveEntryList(&pServiceImage
->ImageListEntry
);
249 /* Close the control pipe */
250 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
251 CloseHandle(pServiceImage
->hControlPipe
);
253 /* Close the process handle */
254 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
255 CloseHandle(pServiceImage
->hProcess
);
257 /* Release the service image */
258 HeapFree(GetProcessHeap(), 0, pServiceImage
);
264 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
266 PLIST_ENTRY ServiceEntry
;
267 PSERVICE CurrentService
;
269 DPRINT("ScmGetServiceEntryByName() called\n");
271 ServiceEntry
= ServiceListHead
.Flink
;
272 while (ServiceEntry
!= &ServiceListHead
)
274 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
277 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
279 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
280 return CurrentService
;
283 ServiceEntry
= ServiceEntry
->Flink
;
286 DPRINT("Couldn't find a matching service\n");
293 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
295 PLIST_ENTRY ServiceEntry
;
296 PSERVICE CurrentService
;
298 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
300 ServiceEntry
= ServiceListHead
.Flink
;
301 while (ServiceEntry
!= &ServiceListHead
)
303 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
306 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
308 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
309 return CurrentService
;
312 ServiceEntry
= ServiceEntry
->Flink
;
315 DPRINT("Couldn't find a matching service\n");
322 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
324 PLIST_ENTRY ServiceEntry
;
325 PSERVICE CurrentService
;
327 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
329 ServiceEntry
= ServiceListHead
.Flink
;
330 while (ServiceEntry
!= &ServiceListHead
)
332 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
335 if (CurrentService
->dwResumeCount
> dwResumeCount
)
337 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
338 return CurrentService
;
341 ServiceEntry
= ServiceEntry
->Flink
;
344 DPRINT("Couldn't find a matching service\n");
351 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
352 PSERVICE
*lpServiceRecord
)
354 PSERVICE lpService
= NULL
;
356 DPRINT("Service: '%S'\n", lpServiceName
);
358 /* Allocate service entry */
359 lpService
= (SERVICE
*)HeapAlloc(GetProcessHeap(),
361 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
362 if (lpService
== NULL
)
363 return ERROR_NOT_ENOUGH_MEMORY
;
365 *lpServiceRecord
= lpService
;
367 /* Copy service name */
368 wcscpy(lpService
->szServiceName
, lpServiceName
);
369 lpService
->lpServiceName
= lpService
->szServiceName
;
370 lpService
->lpDisplayName
= lpService
->lpServiceName
;
372 /* Set the resume count */
373 lpService
->dwResumeCount
= dwResumeCount
++;
375 /* Append service record */
376 InsertTailList(&ServiceListHead
,
377 &lpService
->ServiceListEntry
);
379 /* Initialize the service status */
380 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
381 lpService
->Status
.dwControlsAccepted
= 0;
382 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
383 lpService
->Status
.dwServiceSpecificExitCode
= 0;
384 lpService
->Status
.dwCheckPoint
= 0;
385 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
387 return ERROR_SUCCESS
;
392 ScmDeleteServiceRecord(PSERVICE lpService
)
394 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
396 /* Delete the display name */
397 if (lpService
->lpDisplayName
!= NULL
&&
398 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
399 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
401 /* Dereference the service image */
402 if (lpService
->lpImage
)
403 ScmDereferenceServiceImage(lpService
->lpImage
);
405 /* Decrement the group reference counter */
406 if (lpService
->lpGroup
)
407 lpService
->lpGroup
->dwRefCount
--;
409 /* FIXME: SecurityDescriptor */
412 /* Remove the Service from the List */
413 RemoveEntryList(&lpService
->ServiceListEntry
);
415 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
417 /* Delete the service record */
418 HeapFree(GetProcessHeap(), 0, lpService
);
425 CreateServiceListEntry(LPCWSTR lpServiceName
,
428 PSERVICE lpService
= NULL
;
429 LPWSTR lpDisplayName
= NULL
;
430 LPWSTR lpGroup
= NULL
;
435 DWORD dwErrorControl
;
438 DPRINT("Service: '%S'\n", lpServiceName
);
439 if (*lpServiceName
== L
'{')
440 return ERROR_SUCCESS
;
442 dwSize
= sizeof(DWORD
);
443 dwError
= RegQueryValueExW(hServiceKey
,
447 (LPBYTE
)&dwServiceType
,
449 if (dwError
!= ERROR_SUCCESS
)
450 return ERROR_SUCCESS
;
452 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
453 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
454 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
455 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
456 return ERROR_SUCCESS
;
458 DPRINT("Service type: %lx\n", dwServiceType
);
460 dwSize
= sizeof(DWORD
);
461 dwError
= RegQueryValueExW(hServiceKey
,
465 (LPBYTE
)&dwStartType
,
467 if (dwError
!= ERROR_SUCCESS
)
468 return ERROR_SUCCESS
;
470 DPRINT("Start type: %lx\n", dwStartType
);
472 dwSize
= sizeof(DWORD
);
473 dwError
= RegQueryValueExW(hServiceKey
,
477 (LPBYTE
)&dwErrorControl
,
479 if (dwError
!= ERROR_SUCCESS
)
480 return ERROR_SUCCESS
;
482 DPRINT("Error control: %lx\n", dwErrorControl
);
484 dwError
= RegQueryValueExW(hServiceKey
,
490 if (dwError
!= ERROR_SUCCESS
)
493 DPRINT("Tag: %lx\n", dwTagId
);
495 dwError
= ScmReadString(hServiceKey
,
498 if (dwError
!= ERROR_SUCCESS
)
501 DPRINT("Group: %S\n", lpGroup
);
503 dwError
= ScmReadString(hServiceKey
,
506 if (dwError
!= ERROR_SUCCESS
)
507 lpDisplayName
= NULL
;
509 DPRINT("Display name: %S\n", lpDisplayName
);
511 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
513 if (dwError
!= ERROR_SUCCESS
)
516 lpService
->Status
.dwServiceType
= dwServiceType
;
517 lpService
->dwStartType
= dwStartType
;
518 lpService
->dwErrorControl
= dwErrorControl
;
519 lpService
->dwTag
= dwTagId
;
523 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
524 if (dwError
!= ERROR_SUCCESS
)
528 if (lpDisplayName
!= NULL
)
530 lpService
->lpDisplayName
= lpDisplayName
;
531 lpDisplayName
= NULL
;
534 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
535 if (lpService
->lpGroup
!= NULL
)
537 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
539 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
540 lpService
->dwStartType
,
541 lpService
->Status
.dwServiceType
,
543 lpService
->dwErrorControl
);
545 if (ScmIsDeleteFlagSet(hServiceKey
))
546 lpService
->bDeleted
= TRUE
;
550 HeapFree(GetProcessHeap(), 0, lpGroup
);
552 if (lpDisplayName
!= NULL
)
553 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
555 if (lpService
!= NULL
)
557 if (lpService
->lpImage
!= NULL
)
558 ScmDereferenceServiceImage(lpService
->lpImage
);
566 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
568 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
569 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
572 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
575 /* Find the maximum subkey length so that we can allocate a buffer */
576 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
577 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
581 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
582 /* Name too big: alloc a buffer for it */
583 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
586 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
589 while (dwRet
== ERROR_SUCCESS
)
591 dwSize
= dwMaxSubkeyLen
;
592 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
593 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
594 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
596 if (dwRet
== ERROR_NO_MORE_ITEMS
)
597 dwRet
= ERROR_SUCCESS
;
599 if (lpszName
!= szNameBuf
)
600 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
604 RegCloseKey(hSubKey
);
606 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
613 ScmDeleteMarkedServices(VOID
)
615 PLIST_ENTRY ServiceEntry
;
616 PSERVICE CurrentService
;
620 ServiceEntry
= ServiceListHead
.Flink
;
621 while (ServiceEntry
!= &ServiceListHead
)
623 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
625 ServiceEntry
= ServiceEntry
->Flink
;
627 if (CurrentService
->bDeleted
== TRUE
)
629 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
630 L
"System\\CurrentControlSet\\Services",
634 if (dwError
== ERROR_SUCCESS
)
636 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
637 RegCloseKey(hServicesKey
);
638 if (dwError
== ERROR_SUCCESS
)
640 RemoveEntryList(&CurrentService
->ServiceListEntry
);
641 HeapFree(GetProcessHeap(), 0, CurrentService
);
645 if (dwError
!= ERROR_SUCCESS
)
646 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
658 DPRINT("WaitForLSA() called\n");
660 hEvent
= CreateEventW(NULL
,
663 L
"LSA_RPC_SERVER_ACTIVE");
666 dwError
= GetLastError();
667 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
669 if (dwError
== ERROR_ALREADY_EXISTS
)
671 hEvent
= OpenEventW(SYNCHRONIZE
,
673 L
"LSA_RPC_SERVER_ACTIVE");
676 DPRINT1("Could not open the notification event!\n");
682 DPRINT("Wait for LSA!\n");
683 WaitForSingleObject(hEvent
, INFINITE
);
684 DPRINT("LSA is available!\n");
688 DPRINT("WaitForLSA() done\n");
693 ScmCreateServiceDatabase(VOID
)
695 WCHAR szSubKey
[MAX_PATH
];
699 DWORD dwSubKeyLength
;
700 FILETIME ftLastChanged
;
703 DPRINT("ScmCreateServiceDatabase() called\n");
705 dwError
= ScmCreateGroupList();
706 if (dwError
!= ERROR_SUCCESS
)
709 /* Initialize basic variables */
710 InitializeListHead(&ImageListHead
);
711 InitializeListHead(&ServiceListHead
);
713 /* Initialize the database lock */
714 RtlInitializeResource(&DatabaseLock
);
716 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
717 L
"System\\CurrentControlSet\\Services",
721 if (dwError
!= ERROR_SUCCESS
)
727 dwSubKeyLength
= MAX_PATH
;
728 dwError
= RegEnumKeyExW(hServicesKey
,
736 if (dwError
== ERROR_SUCCESS
&&
739 DPRINT("SubKeyName: '%S'\n", szSubKey
);
741 dwError
= RegOpenKeyExW(hServicesKey
,
746 if (dwError
== ERROR_SUCCESS
)
748 dwError
= CreateServiceListEntry(szSubKey
,
751 RegCloseKey(hServiceKey
);
755 if (dwError
!= ERROR_SUCCESS
)
761 RegCloseKey(hServicesKey
);
766 /* Delete services that are marked for delete */
767 ScmDeleteMarkedServices();
769 DPRINT("ScmCreateServiceDatabase() done\n");
771 return ERROR_SUCCESS
;
776 ScmShutdownServiceDatabase(VOID
)
778 DPRINT("ScmShutdownServiceDatabase() called\n");
780 ScmDeleteMarkedServices();
781 RtlDeleteResource(&DatabaseLock
);
783 DPRINT("ScmShutdownServiceDatabase() done\n");
788 ScmCheckDriver(PSERVICE Service
)
790 OBJECT_ATTRIBUTES ObjectAttributes
;
791 UNICODE_STRING DirName
;
794 POBJECT_DIRECTORY_INFORMATION DirInfo
;
799 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
801 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
803 RtlInitUnicodeString(&DirName
,
808 RtlInitUnicodeString(&DirName
,
812 InitializeObjectAttributes(&ObjectAttributes
,
818 Status
= NtOpenDirectoryObject(&DirHandle
,
819 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
821 if (!NT_SUCCESS(Status
))
826 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
827 2 * MAX_PATH
* sizeof(WCHAR
);
828 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
835 Status
= NtQueryDirectoryObject(DirHandle
,
842 if (Status
== STATUS_NO_MORE_ENTRIES
)
844 /* FIXME: Add current service to 'failed service' list */
845 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
849 if (!NT_SUCCESS(Status
))
852 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
854 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
856 DPRINT("Found: '%S' '%wZ'\n",
857 Service
->lpServiceName
, &DirInfo
->Name
);
859 /* Mark service as 'running' */
860 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
862 /* Mark the service group as 'running' */
863 if (Service
->lpGroup
!= NULL
)
865 Service
->lpGroup
->ServicesRunning
= TRUE
;
872 HeapFree(GetProcessHeap(),
877 return STATUS_SUCCESS
;
882 ScmGetBootAndSystemDriverState(VOID
)
884 PLIST_ENTRY ServiceEntry
;
885 PSERVICE CurrentService
;
887 DPRINT("ScmGetBootAndSystemDriverState() called\n");
889 ServiceEntry
= ServiceListHead
.Flink
;
890 while (ServiceEntry
!= &ServiceListHead
)
892 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
894 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
895 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
898 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
900 ScmCheckDriver(CurrentService
);
903 ServiceEntry
= ServiceEntry
->Flink
;
906 DPRINT("ScmGetBootAndSystemDriverState() done\n");
911 ScmControlService(PSERVICE Service
,
914 PSCM_CONTROL_PACKET ControlPacket
;
915 SCM_REPLY_PACKET ReplyPacket
;
917 DWORD dwWriteCount
= 0;
918 DWORD dwReadCount
= 0;
920 DWORD dwError
= ERROR_SUCCESS
;
922 DPRINT("ScmControlService() called\n");
924 EnterCriticalSection(&ControlServiceCriticalSection
);
926 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
928 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
930 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
931 if (ControlPacket
== NULL
)
933 LeaveCriticalSection(&ControlServiceCriticalSection
);
934 return ERROR_NOT_ENOUGH_MEMORY
;
937 ControlPacket
->dwControl
= dwControl
;
938 ControlPacket
->dwSize
= TotalLength
;
939 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
940 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
942 /* Send the control packet */
943 WriteFile(Service
->lpImage
->hControlPipe
,
945 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
950 ReadFile(Service
->lpImage
->hControlPipe
,
952 sizeof(SCM_REPLY_PACKET
),
956 /* Release the contol packet */
957 HeapFree(GetProcessHeap(),
961 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
963 dwError
= ReplyPacket
.dwError
;
966 if (dwError
== ERROR_SUCCESS
&&
967 dwControl
== SERVICE_CONTROL_STOP
)
969 ScmDereferenceServiceImage(Service
->lpImage
);
972 LeaveCriticalSection(&ControlServiceCriticalSection
);
974 DPRINT("ScmControlService() done\n");
981 ScmSendStartCommand(PSERVICE Service
,
985 PSCM_CONTROL_PACKET ControlPacket
;
986 SCM_REPLY_PACKET ReplyPacket
;
988 DWORD ArgsLength
= 0;
991 DWORD dwWriteCount
= 0;
992 DWORD dwReadCount
= 0;
993 DWORD dwError
= ERROR_SUCCESS
;
996 DPRINT("ScmSendStartCommand() called\n");
998 /* Calculate the total length of the start command line */
999 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
1002 for (i
= 0; i
< argc
; i
++)
1004 DPRINT("Arg: %S\n", argv
[i
]);
1005 Length
= wcslen(argv
[i
]) + 1;
1006 TotalLength
+= Length
;
1007 ArgsLength
+= Length
;
1011 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
1013 /* Allocate a control packet */
1014 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
1016 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
1017 if (ControlPacket
== NULL
)
1018 return ERROR_NOT_ENOUGH_MEMORY
;
1020 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
1021 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1022 ControlPacket
->dwSize
= TotalLength
;
1023 Ptr
= &ControlPacket
->szArguments
[0];
1024 wcscpy(Ptr
, Service
->lpServiceName
);
1025 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
1027 /* Copy argument list */
1031 DPRINT1("Arguments sent to service ignored!\n");
1033 memcpy(Ptr
, Arguments
, ArgsLength
);
1038 /* Terminate the argument list */
1041 /* Send the start command */
1042 WriteFile(Service
->lpImage
->hControlPipe
,
1044 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
1048 /* Read the reply */
1049 ReadFile(Service
->lpImage
->hControlPipe
,
1051 sizeof(SCM_REPLY_PACKET
),
1055 /* Release the contol packet */
1056 HeapFree(GetProcessHeap(),
1060 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1062 dwError
= ReplyPacket
.dwError
;
1065 DPRINT("ScmSendStartCommand() done\n");
1072 ScmStartUserModeService(PSERVICE Service
,
1076 PROCESS_INFORMATION ProcessInformation
;
1077 STARTUPINFOW StartupInfo
;
1079 DWORD dwError
= ERROR_SUCCESS
;
1082 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1084 StartupInfo
.cb
= sizeof(StartupInfo
);
1085 StartupInfo
.lpReserved
= NULL
;
1086 StartupInfo
.lpDesktop
= NULL
;
1087 StartupInfo
.lpTitle
= NULL
;
1088 StartupInfo
.dwFlags
= 0;
1089 StartupInfo
.cbReserved2
= 0;
1090 StartupInfo
.lpReserved2
= 0;
1092 Result
= CreateProcessW(NULL
,
1093 Service
->lpImage
->szImagePath
,
1097 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1101 &ProcessInformation
);
1104 dwError
= GetLastError();
1105 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1109 DPRINT("Process Id: %lu Handle %lx\n",
1110 ProcessInformation
.dwProcessId
,
1111 ProcessInformation
.hProcess
);
1112 DPRINT("Thread Id: %lu Handle %lx\n",
1113 ProcessInformation
.dwThreadId
,
1114 ProcessInformation
.hThread
);
1116 /* Get process handle and id */
1117 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1118 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1121 ResumeThread(ProcessInformation
.hThread
);
1123 /* Connect control pipe */
1124 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1125 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1129 DPRINT("Control pipe connected!\n");
1131 /* Read SERVICE_STATUS_HANDLE from pipe */
1132 if (!ReadFile(Service
->lpImage
->hControlPipe
,
1133 (LPVOID
)&dwProcessId
,
1138 dwError
= GetLastError();
1139 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1144 DPRINT("Received service process ID %lu\n", dwProcessId
);
1146 /* Send start command */
1147 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1152 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1155 /* Close thread handle */
1156 CloseHandle(ProcessInformation
.hThread
);
1163 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1165 PSERVICE_GROUP Group
= Service
->lpGroup
;
1166 DWORD dwError
= ERROR_SUCCESS
;
1167 LPCWSTR ErrorLogStrings
[2];
1169 DPRINT("ScmStartService() called\n");
1171 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1173 EnterCriticalSection(&ControlServiceCriticalSection
);
1175 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1177 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1178 LeaveCriticalSection(&ControlServiceCriticalSection
);
1179 return ERROR_SERVICE_ALREADY_RUNNING
;
1182 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1184 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1187 dwError
= ScmLoadDriver(Service
);
1188 if (dwError
== ERROR_SUCCESS
)
1190 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1191 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1196 /* Start user-mode service */
1197 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1198 if (dwError
== ERROR_SUCCESS
)
1200 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1201 if (dwError
== ERROR_SUCCESS
)
1203 #ifdef USE_SERVICE_START_PENDING
1204 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1206 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1211 ScmDereferenceServiceImage(Service
->lpImage
);
1212 Service
->lpImage
= NULL
;
1217 LeaveCriticalSection(&ControlServiceCriticalSection
);
1219 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1221 if (dwError
== ERROR_SUCCESS
)
1225 Group
->ServicesRunning
= TRUE
;
1230 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1232 ErrorLogStrings
[0] = Service
->lpServiceName
;
1233 ErrorLogStrings
[1] = L
"Test";
1234 ScmLogError(EVENT_SERVICE_START_FAILED
,
1240 switch (Service
->dwErrorControl
)
1242 case SERVICE_ERROR_SEVERE
:
1243 if (IsLastKnownGood
== FALSE
)
1245 /* FIXME: Boot last known good configuration */
1249 case SERVICE_ERROR_CRITICAL
:
1250 if (IsLastKnownGood
== FALSE
)
1252 /* FIXME: Boot last known good configuration */
1268 ScmAutoStartServices(VOID
)
1270 PLIST_ENTRY GroupEntry
;
1271 PLIST_ENTRY ServiceEntry
;
1272 PSERVICE_GROUP CurrentGroup
;
1273 PSERVICE CurrentService
;
1274 WCHAR szSafeBootServicePath
[MAX_PATH
];
1279 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1280 ServiceEntry
= ServiceListHead
.Flink
;
1281 while (ServiceEntry
!= &ServiceListHead
)
1283 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1284 /* Build the safe boot path */
1285 wcscpy(szSafeBootServicePath
,
1286 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1287 switch(GetSystemMetrics(SM_CLEANBOOT
))
1289 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1291 case 3: wcscat(szSafeBootServicePath
, L
"\\Minimal\\"); break;
1292 case 2: wcscat(szSafeBootServicePath
, L
"\\Network\\"); break;
1294 if(GetSystemMetrics(SM_CLEANBOOT
))
1296 /* If key does not exist then do not assume safe mode */
1297 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1298 szSafeBootServicePath
,
1302 if(dwError
== ERROR_SUCCESS
)
1305 /* Finish Safe Boot path off */
1306 wcsncat(szSafeBootServicePath
,
1307 CurrentService
->lpServiceName
,
1308 MAX_PATH
- wcslen(szSafeBootServicePath
));
1309 /* Check that the key is in the Safe Boot path */
1310 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1311 szSafeBootServicePath
,
1315 if(dwError
!= ERROR_SUCCESS
)
1317 /* Mark service as visited so it is not auto-started */
1318 CurrentService
->ServiceVisited
= TRUE
;
1322 /* Must be auto-started in safe mode - mark as unvisited */
1324 CurrentService
->ServiceVisited
= FALSE
;
1329 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1330 CurrentService
->ServiceVisited
= FALSE
;
1333 ServiceEntry
= ServiceEntry
->Flink
;
1336 /* Start all services which are members of an existing group */
1337 GroupEntry
= GroupListHead
.Flink
;
1338 while (GroupEntry
!= &GroupListHead
)
1340 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1342 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1344 /* Start all services witch have a valid tag */
1345 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1347 ServiceEntry
= ServiceListHead
.Flink
;
1348 while (ServiceEntry
!= &ServiceListHead
)
1350 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1352 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1353 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1354 (CurrentService
->ServiceVisited
== FALSE
) &&
1355 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1357 CurrentService
->ServiceVisited
= TRUE
;
1358 ScmStartService(CurrentService
, 0, NULL
);
1361 ServiceEntry
= ServiceEntry
->Flink
;
1365 /* Start all services which have an invalid tag or which do not have a tag */
1366 ServiceEntry
= ServiceListHead
.Flink
;
1367 while (ServiceEntry
!= &ServiceListHead
)
1369 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1371 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1372 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1373 (CurrentService
->ServiceVisited
== FALSE
))
1375 CurrentService
->ServiceVisited
= TRUE
;
1376 ScmStartService(CurrentService
, 0, NULL
);
1379 ServiceEntry
= ServiceEntry
->Flink
;
1382 GroupEntry
= GroupEntry
->Flink
;
1385 /* Start all services which are members of any non-existing group */
1386 ServiceEntry
= ServiceListHead
.Flink
;
1387 while (ServiceEntry
!= &ServiceListHead
)
1389 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1391 if ((CurrentService
->lpGroup
!= NULL
) &&
1392 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1393 (CurrentService
->ServiceVisited
== FALSE
))
1395 CurrentService
->ServiceVisited
= TRUE
;
1396 ScmStartService(CurrentService
, 0, NULL
);
1399 ServiceEntry
= ServiceEntry
->Flink
;
1402 /* Start all services which are not a member of any group */
1403 ServiceEntry
= ServiceListHead
.Flink
;
1404 while (ServiceEntry
!= &ServiceListHead
)
1406 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1408 if ((CurrentService
->lpGroup
== NULL
) &&
1409 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1410 (CurrentService
->ServiceVisited
== FALSE
))
1412 CurrentService
->ServiceVisited
= TRUE
;
1413 ScmStartService(CurrentService
, 0, NULL
);
1416 ServiceEntry
= ServiceEntry
->Flink
;
1419 /* Clear 'ServiceVisited' flag again */
1420 ServiceEntry
= ServiceListHead
.Flink
;
1421 while (ServiceEntry
!= &ServiceListHead
)
1423 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1424 CurrentService
->ServiceVisited
= FALSE
;
1425 ServiceEntry
= ServiceEntry
->Flink
;
1431 ScmAutoShutdownServices(VOID
)
1433 PLIST_ENTRY ServiceEntry
;
1434 PSERVICE CurrentService
;
1436 DPRINT("ScmAutoShutdownServices() called\n");
1438 /* Lock the service database exclusively */
1439 ScmLockDatabaseExclusive();
1441 ServiceEntry
= ServiceListHead
.Flink
;
1442 while (ServiceEntry
!= &ServiceListHead
)
1444 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1446 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1447 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1449 /* shutdown service */
1450 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1451 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1454 ServiceEntry
= ServiceEntry
->Flink
;
1457 /* Unlock the service database */
1458 ScmUnlockDatabase();
1460 DPRINT("ScmAutoShutdownServices() done\n");
1465 ScmLockDatabaseExclusive(VOID
)
1467 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1472 ScmLockDatabaseShared(VOID
)
1474 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1479 ScmUnlockDatabase(VOID
)
1481 RtlReleaseResource(&DatabaseLock
);
1486 ScmInitNamedPipeCriticalSection(VOID
)
1488 InitializeCriticalSection(&ControlServiceCriticalSection
);
1493 ScmDeleteNamedPipeCriticalSection(VOID
)
1495 DeleteCriticalSection(&ControlServiceCriticalSection
);