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() called\n");
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()");
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
);
215 pService
->lpImage
= pServiceImage
;
219 /* Create a new service image */
220 pService
->lpImage
->dwImageRunCount
++;
224 RtlFreeUnicodeString(&ImagePath
);
231 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
233 DPRINT1("ScmDereferenceServiceImage() called\n");
235 pServiceImage
->dwImageRunCount
--;
237 if (pServiceImage
->dwImageRunCount
== 0)
239 DPRINT1("dwImageRunCount == 0\n");
241 /* FIXME: Terminate the process */
243 /* Remove the service image from the list */
244 RemoveEntryList(&pServiceImage
->ImageListEntry
);
246 /* Close the control pipe */
247 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
248 CloseHandle(pServiceImage
->hControlPipe
);
250 /* Close the process handle */
251 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
252 CloseHandle(pServiceImage
->hProcess
);
254 /* Release the service image */
255 HeapFree(GetProcessHeap(), 0, pServiceImage
);
261 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
263 PLIST_ENTRY ServiceEntry
;
264 PSERVICE CurrentService
;
266 DPRINT("ScmGetServiceEntryByName() called\n");
268 ServiceEntry
= ServiceListHead
.Flink
;
269 while (ServiceEntry
!= &ServiceListHead
)
271 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
274 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
276 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
277 return CurrentService
;
280 ServiceEntry
= ServiceEntry
->Flink
;
283 DPRINT("Couldn't find a matching service\n");
290 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
292 PLIST_ENTRY ServiceEntry
;
293 PSERVICE CurrentService
;
295 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
297 ServiceEntry
= ServiceListHead
.Flink
;
298 while (ServiceEntry
!= &ServiceListHead
)
300 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
303 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
305 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
306 return CurrentService
;
309 ServiceEntry
= ServiceEntry
->Flink
;
312 DPRINT("Couldn't find a matching service\n");
319 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
321 PLIST_ENTRY ServiceEntry
;
322 PSERVICE CurrentService
;
324 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
326 ServiceEntry
= ServiceListHead
.Flink
;
327 while (ServiceEntry
!= &ServiceListHead
)
329 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
332 if (CurrentService
->dwResumeCount
> dwResumeCount
)
334 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
335 return CurrentService
;
338 ServiceEntry
= ServiceEntry
->Flink
;
341 DPRINT("Couldn't find a matching service\n");
348 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
349 PSERVICE
*lpServiceRecord
)
351 PSERVICE lpService
= NULL
;
353 DPRINT("Service: '%S'\n", lpServiceName
);
355 /* Allocate service entry */
356 lpService
= (SERVICE
*)HeapAlloc(GetProcessHeap(),
358 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
359 if (lpService
== NULL
)
360 return ERROR_NOT_ENOUGH_MEMORY
;
362 *lpServiceRecord
= lpService
;
364 /* Copy service name */
365 wcscpy(lpService
->szServiceName
, lpServiceName
);
366 lpService
->lpServiceName
= lpService
->szServiceName
;
367 lpService
->lpDisplayName
= lpService
->lpServiceName
;
369 /* Set the resume count */
370 lpService
->dwResumeCount
= dwResumeCount
++;
372 /* Append service record */
373 InsertTailList(&ServiceListHead
,
374 &lpService
->ServiceListEntry
);
376 /* Initialize the service status */
377 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
378 lpService
->Status
.dwControlsAccepted
= 0;
379 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
380 lpService
->Status
.dwServiceSpecificExitCode
= 0;
381 lpService
->Status
.dwCheckPoint
= 0;
382 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
384 return ERROR_SUCCESS
;
389 ScmDeleteServiceRecord(PSERVICE lpService
)
391 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
393 /* Delete the display name */
394 if (lpService
->lpDisplayName
!= NULL
&&
395 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
396 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
398 /* Dereference the service image */
399 if (lpService
->lpImage
)
400 ScmDereferenceServiceImage(lpService
->lpImage
);
402 /* Decrement the group reference counter */
403 if (lpService
->lpGroup
)
404 lpService
->lpGroup
->dwRefCount
--;
406 /* FIXME: SecurityDescriptor */
409 /* Remove the Service from the List */
410 RemoveEntryList(&lpService
->ServiceListEntry
);
412 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
414 /* Delete the service record */
415 HeapFree(GetProcessHeap(), 0, lpService
);
422 CreateServiceListEntry(LPCWSTR lpServiceName
,
425 PSERVICE lpService
= NULL
;
426 LPWSTR lpDisplayName
= NULL
;
427 LPWSTR lpGroup
= NULL
;
432 DWORD dwErrorControl
;
435 DPRINT("Service: '%S'\n", lpServiceName
);
436 if (*lpServiceName
== L
'{')
437 return ERROR_SUCCESS
;
439 dwSize
= sizeof(DWORD
);
440 dwError
= RegQueryValueExW(hServiceKey
,
444 (LPBYTE
)&dwServiceType
,
446 if (dwError
!= ERROR_SUCCESS
)
447 return ERROR_SUCCESS
;
449 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
450 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
451 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
452 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
453 return ERROR_SUCCESS
;
455 DPRINT("Service type: %lx\n", dwServiceType
);
457 dwSize
= sizeof(DWORD
);
458 dwError
= RegQueryValueExW(hServiceKey
,
462 (LPBYTE
)&dwStartType
,
464 if (dwError
!= ERROR_SUCCESS
)
465 return ERROR_SUCCESS
;
467 DPRINT("Start type: %lx\n", dwStartType
);
469 dwSize
= sizeof(DWORD
);
470 dwError
= RegQueryValueExW(hServiceKey
,
474 (LPBYTE
)&dwErrorControl
,
476 if (dwError
!= ERROR_SUCCESS
)
477 return ERROR_SUCCESS
;
479 DPRINT("Error control: %lx\n", dwErrorControl
);
481 dwError
= RegQueryValueExW(hServiceKey
,
487 if (dwError
!= ERROR_SUCCESS
)
490 DPRINT("Tag: %lx\n", dwTagId
);
492 dwError
= ScmReadString(hServiceKey
,
495 if (dwError
!= ERROR_SUCCESS
)
498 DPRINT("Group: %S\n", lpGroup
);
500 dwError
= ScmReadString(hServiceKey
,
503 if (dwError
!= ERROR_SUCCESS
)
504 lpDisplayName
= NULL
;
506 DPRINT("Display name: %S\n", lpDisplayName
);
508 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
510 if (dwError
!= ERROR_SUCCESS
)
513 lpService
->Status
.dwServiceType
= dwServiceType
;
514 lpService
->dwStartType
= dwStartType
;
515 lpService
->dwErrorControl
= dwErrorControl
;
516 lpService
->dwTag
= dwTagId
;
520 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
521 if (dwError
!= ERROR_SUCCESS
)
525 if (lpDisplayName
!= NULL
)
527 lpService
->lpDisplayName
= lpDisplayName
;
528 lpDisplayName
= NULL
;
531 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
532 if (lpService
->lpGroup
!= NULL
)
534 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
536 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
537 lpService
->dwStartType
,
538 lpService
->Status
.dwServiceType
,
540 lpService
->dwErrorControl
);
542 if (ScmIsDeleteFlagSet(hServiceKey
))
543 lpService
->bDeleted
= TRUE
;
547 HeapFree(GetProcessHeap(), 0, lpGroup
);
549 if (lpDisplayName
!= NULL
)
550 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
552 if (lpService
!= NULL
)
554 if (lpService
->lpImage
!= NULL
)
555 ScmDereferenceServiceImage(lpService
->lpImage
);
563 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
565 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
566 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
569 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
572 /* Find the maximum subkey length so that we can allocate a buffer */
573 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
574 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
578 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
579 /* Name too big: alloc a buffer for it */
580 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
583 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
586 while (dwRet
== ERROR_SUCCESS
)
588 dwSize
= dwMaxSubkeyLen
;
589 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
590 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
591 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
593 if (dwRet
== ERROR_NO_MORE_ITEMS
)
594 dwRet
= ERROR_SUCCESS
;
596 if (lpszName
!= szNameBuf
)
597 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
601 RegCloseKey(hSubKey
);
603 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
610 ScmDeleteMarkedServices(VOID
)
612 PLIST_ENTRY ServiceEntry
;
613 PSERVICE CurrentService
;
617 ServiceEntry
= ServiceListHead
.Flink
;
618 while (ServiceEntry
!= &ServiceListHead
)
620 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
622 ServiceEntry
= ServiceEntry
->Flink
;
624 if (CurrentService
->bDeleted
== TRUE
)
626 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
627 L
"System\\CurrentControlSet\\Services",
631 if (dwError
== ERROR_SUCCESS
)
633 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
634 RegCloseKey(hServicesKey
);
635 if (dwError
== ERROR_SUCCESS
)
637 RemoveEntryList(&CurrentService
->ServiceListEntry
);
638 HeapFree(GetProcessHeap(), 0, CurrentService
);
642 if (dwError
!= ERROR_SUCCESS
)
643 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
655 DPRINT("WaitForLSA() called\n");
657 hEvent
= CreateEventW(NULL
,
660 L
"LSA_RPC_SERVER_ACTIVE");
663 dwError
= GetLastError();
664 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
666 if (dwError
== ERROR_ALREADY_EXISTS
)
668 hEvent
= OpenEventW(SYNCHRONIZE
,
670 L
"LSA_RPC_SERVER_ACTIVE");
673 DPRINT1("Could not open the notification event!\n");
679 DPRINT("Wait for LSA!\n");
680 WaitForSingleObject(hEvent
, INFINITE
);
681 DPRINT("LSA is available!\n");
685 DPRINT("WaitForLSA() done\n");
690 ScmCreateServiceDatabase(VOID
)
692 WCHAR szSubKey
[MAX_PATH
];
696 DWORD dwSubKeyLength
;
697 FILETIME ftLastChanged
;
700 DPRINT("ScmCreateServiceDatabase() called\n");
702 dwError
= ScmCreateGroupList();
703 if (dwError
!= ERROR_SUCCESS
)
706 /* Initialize basic variables */
707 InitializeListHead(&ImageListHead
);
708 InitializeListHead(&ServiceListHead
);
710 /* Initialize the database lock */
711 RtlInitializeResource(&DatabaseLock
);
713 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
714 L
"System\\CurrentControlSet\\Services",
718 if (dwError
!= ERROR_SUCCESS
)
724 dwSubKeyLength
= MAX_PATH
;
725 dwError
= RegEnumKeyExW(hServicesKey
,
733 if (dwError
== ERROR_SUCCESS
&&
736 DPRINT("SubKeyName: '%S'\n", szSubKey
);
738 dwError
= RegOpenKeyExW(hServicesKey
,
743 if (dwError
== ERROR_SUCCESS
)
745 dwError
= CreateServiceListEntry(szSubKey
,
748 RegCloseKey(hServiceKey
);
752 if (dwError
!= ERROR_SUCCESS
)
758 RegCloseKey(hServicesKey
);
763 /* Delete services that are marked for delete */
764 ScmDeleteMarkedServices();
766 DPRINT("ScmCreateServiceDatabase() done\n");
768 return ERROR_SUCCESS
;
773 ScmShutdownServiceDatabase(VOID
)
775 DPRINT("ScmShutdownServiceDatabase() called\n");
777 ScmDeleteMarkedServices();
778 RtlDeleteResource(&DatabaseLock
);
780 DPRINT("ScmShutdownServiceDatabase() done\n");
785 ScmCheckDriver(PSERVICE Service
)
787 OBJECT_ATTRIBUTES ObjectAttributes
;
788 UNICODE_STRING DirName
;
791 POBJECT_DIRECTORY_INFORMATION DirInfo
;
796 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
798 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
800 RtlInitUnicodeString(&DirName
,
805 RtlInitUnicodeString(&DirName
,
809 InitializeObjectAttributes(&ObjectAttributes
,
815 Status
= NtOpenDirectoryObject(&DirHandle
,
816 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
818 if (!NT_SUCCESS(Status
))
823 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
824 2 * MAX_PATH
* sizeof(WCHAR
);
825 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
832 Status
= NtQueryDirectoryObject(DirHandle
,
839 if (Status
== STATUS_NO_MORE_ENTRIES
)
841 /* FIXME: Add current service to 'failed service' list */
842 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
846 if (!NT_SUCCESS(Status
))
849 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
851 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
853 DPRINT("Found: '%S' '%wZ'\n",
854 Service
->lpServiceName
, &DirInfo
->Name
);
856 /* Mark service as 'running' */
857 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
859 /* Mark the service group as 'running' */
860 if (Service
->lpGroup
!= NULL
)
862 Service
->lpGroup
->ServicesRunning
= TRUE
;
869 HeapFree(GetProcessHeap(),
874 return STATUS_SUCCESS
;
879 ScmGetBootAndSystemDriverState(VOID
)
881 PLIST_ENTRY ServiceEntry
;
882 PSERVICE CurrentService
;
884 DPRINT("ScmGetBootAndSystemDriverState() called\n");
886 ServiceEntry
= ServiceListHead
.Flink
;
887 while (ServiceEntry
!= &ServiceListHead
)
889 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
891 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
892 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
895 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
897 ScmCheckDriver(CurrentService
);
900 ServiceEntry
= ServiceEntry
->Flink
;
903 DPRINT("ScmGetBootAndSystemDriverState() done\n");
908 ScmControlService(PSERVICE Service
,
911 PSCM_CONTROL_PACKET ControlPacket
;
912 SCM_REPLY_PACKET ReplyPacket
;
914 DWORD dwWriteCount
= 0;
915 DWORD dwReadCount
= 0;
917 DWORD dwError
= ERROR_SUCCESS
;
919 DPRINT("ScmControlService() called\n");
921 EnterCriticalSection(&ControlServiceCriticalSection
);
923 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
925 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
927 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
928 if (ControlPacket
== NULL
)
930 LeaveCriticalSection(&ControlServiceCriticalSection
);
931 return ERROR_NOT_ENOUGH_MEMORY
;
934 ControlPacket
->dwControl
= dwControl
;
935 ControlPacket
->dwSize
= TotalLength
;
936 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
937 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
939 /* Send the control packet */
940 WriteFile(Service
->lpImage
->hControlPipe
,
942 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
947 ReadFile(Service
->lpImage
->hControlPipe
,
949 sizeof(SCM_REPLY_PACKET
),
953 /* Release the contol packet */
954 HeapFree(GetProcessHeap(),
958 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
960 dwError
= ReplyPacket
.dwError
;
963 if (dwError
== ERROR_SUCCESS
&&
964 dwControl
== SERVICE_CONTROL_STOP
)
966 ScmDereferenceServiceImage(Service
->lpImage
);
969 LeaveCriticalSection(&ControlServiceCriticalSection
);
971 DPRINT("ScmControlService() done\n");
978 ScmSendStartCommand(PSERVICE Service
,
982 PSCM_CONTROL_PACKET ControlPacket
;
983 SCM_REPLY_PACKET ReplyPacket
;
985 DWORD ArgsLength
= 0;
988 DWORD dwWriteCount
= 0;
989 DWORD dwReadCount
= 0;
990 DWORD dwError
= ERROR_SUCCESS
;
993 DPRINT("ScmSendStartCommand() called\n");
995 /* Calculate the total length of the start command line */
996 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
999 for (i
= 0; i
< argc
; i
++)
1001 DPRINT("Arg: %S\n", argv
[i
]);
1002 Length
= wcslen(argv
[i
]) + 1;
1003 TotalLength
+= Length
;
1004 ArgsLength
+= Length
;
1008 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
1010 /* Allocate a control packet */
1011 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
1013 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
1014 if (ControlPacket
== NULL
)
1015 return ERROR_NOT_ENOUGH_MEMORY
;
1017 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
1018 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1019 ControlPacket
->dwSize
= TotalLength
;
1020 Ptr
= &ControlPacket
->szArguments
[0];
1021 wcscpy(Ptr
, Service
->lpServiceName
);
1022 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
1024 /* Copy argument list */
1028 DPRINT1("Arguments sent to service ignored!\n");
1030 memcpy(Ptr
, Arguments
, ArgsLength
);
1035 /* Terminate the argument list */
1038 /* Send the start command */
1039 WriteFile(Service
->lpImage
->hControlPipe
,
1041 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
1045 /* Read the reply */
1046 ReadFile(Service
->lpImage
->hControlPipe
,
1048 sizeof(SCM_REPLY_PACKET
),
1052 /* Release the contol packet */
1053 HeapFree(GetProcessHeap(),
1057 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1059 dwError
= ReplyPacket
.dwError
;
1062 DPRINT("ScmSendStartCommand() done\n");
1069 ScmStartUserModeService(PSERVICE Service
,
1073 PROCESS_INFORMATION ProcessInformation
;
1074 STARTUPINFOW StartupInfo
;
1076 DWORD dwError
= ERROR_SUCCESS
;
1079 StartupInfo
.cb
= sizeof(StartupInfo
);
1080 StartupInfo
.lpReserved
= NULL
;
1081 StartupInfo
.lpDesktop
= NULL
;
1082 StartupInfo
.lpTitle
= NULL
;
1083 StartupInfo
.dwFlags
= 0;
1084 StartupInfo
.cbReserved2
= 0;
1085 StartupInfo
.lpReserved2
= 0;
1087 Result
= CreateProcessW(NULL
,
1088 Service
->lpImage
->szImagePath
,
1092 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1096 &ProcessInformation
);
1099 dwError
= GetLastError();
1100 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1104 DPRINT("Process Id: %lu Handle %lx\n",
1105 ProcessInformation
.dwProcessId
,
1106 ProcessInformation
.hProcess
);
1107 DPRINT("Thread Id: %lu Handle %lx\n",
1108 ProcessInformation
.dwThreadId
,
1109 ProcessInformation
.hThread
);
1111 /* Get process handle and id */
1112 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1113 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1116 ResumeThread(ProcessInformation
.hThread
);
1118 /* Connect control pipe */
1119 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1120 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1124 DPRINT("Control pipe connected!\n");
1126 /* Read SERVICE_STATUS_HANDLE from pipe */
1127 if (!ReadFile(Service
->lpImage
->hControlPipe
,
1128 (LPVOID
)&dwProcessId
,
1133 dwError
= GetLastError();
1134 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1139 DPRINT("Received service process ID %lu\n", dwProcessId
);
1141 /* Send start command */
1142 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1147 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1150 /* Close thread handle */
1151 CloseHandle(ProcessInformation
.hThread
);
1158 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1160 PSERVICE_GROUP Group
= Service
->lpGroup
;
1161 DWORD dwError
= ERROR_SUCCESS
;
1162 LPCWSTR ErrorLogStrings
[2];
1164 DPRINT("ScmStartService() called\n");
1166 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1168 EnterCriticalSection(&ControlServiceCriticalSection
);
1170 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1172 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1173 LeaveCriticalSection(&ControlServiceCriticalSection
);
1174 return ERROR_SERVICE_ALREADY_RUNNING
;
1177 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1179 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1182 dwError
= ScmLoadDriver(Service
);
1183 if (dwError
== ERROR_SUCCESS
)
1185 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1186 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1191 /* Start user-mode service */
1192 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1193 if (dwError
== ERROR_SUCCESS
)
1195 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1196 if (dwError
== ERROR_SUCCESS
)
1198 #ifdef USE_SERVICE_START_PENDING
1199 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1201 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1206 ScmDereferenceServiceImage(Service
->lpImage
);
1207 Service
->lpImage
= NULL
;
1212 LeaveCriticalSection(&ControlServiceCriticalSection
);
1214 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1216 if (dwError
== ERROR_SUCCESS
)
1220 Group
->ServicesRunning
= TRUE
;
1225 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1227 ErrorLogStrings
[0] = Service
->lpServiceName
;
1228 ErrorLogStrings
[1] = L
"Test";
1229 ScmLogError(EVENT_SERVICE_START_FAILED
,
1235 switch (Service
->dwErrorControl
)
1237 case SERVICE_ERROR_SEVERE
:
1238 if (IsLastKnownGood
== FALSE
)
1240 /* FIXME: Boot last known good configuration */
1244 case SERVICE_ERROR_CRITICAL
:
1245 if (IsLastKnownGood
== FALSE
)
1247 /* FIXME: Boot last known good configuration */
1263 ScmAutoStartServices(VOID
)
1265 PLIST_ENTRY GroupEntry
;
1266 PLIST_ENTRY ServiceEntry
;
1267 PSERVICE_GROUP CurrentGroup
;
1268 PSERVICE CurrentService
;
1269 WCHAR szSafeBootServicePath
[MAX_PATH
];
1274 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1275 ServiceEntry
= ServiceListHead
.Flink
;
1276 while (ServiceEntry
!= &ServiceListHead
)
1278 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1279 /* Build the safe boot path */
1280 wcscpy(szSafeBootServicePath
,
1281 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1282 switch(GetSystemMetrics(SM_CLEANBOOT
))
1284 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1286 case 3: wcscat(szSafeBootServicePath
, L
"\\Minimal\\"); break;
1287 case 2: wcscat(szSafeBootServicePath
, L
"\\Network\\"); break;
1289 if(GetSystemMetrics(SM_CLEANBOOT
))
1291 /* If key does not exist then do not assume safe mode */
1292 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1293 szSafeBootServicePath
,
1297 if(dwError
== ERROR_SUCCESS
)
1300 /* Finish Safe Boot path off */
1301 wcsncat(szSafeBootServicePath
,
1302 CurrentService
->lpServiceName
,
1303 MAX_PATH
- wcslen(szSafeBootServicePath
));
1304 /* Check that the key is in the Safe Boot path */
1305 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1306 szSafeBootServicePath
,
1310 if(dwError
!= ERROR_SUCCESS
)
1312 /* Mark service as visited so it is not auto-started */
1313 CurrentService
->ServiceVisited
= TRUE
;
1317 /* Must be auto-started in safe mode - mark as unvisited */
1319 CurrentService
->ServiceVisited
= FALSE
;
1324 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1325 CurrentService
->ServiceVisited
= FALSE
;
1328 ServiceEntry
= ServiceEntry
->Flink
;
1331 /* Start all services which are members of an existing group */
1332 GroupEntry
= GroupListHead
.Flink
;
1333 while (GroupEntry
!= &GroupListHead
)
1335 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1337 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1339 /* Start all services witch have a valid tag */
1340 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1342 ServiceEntry
= ServiceListHead
.Flink
;
1343 while (ServiceEntry
!= &ServiceListHead
)
1345 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1347 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1348 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1349 (CurrentService
->ServiceVisited
== FALSE
) &&
1350 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1352 CurrentService
->ServiceVisited
= TRUE
;
1353 ScmStartService(CurrentService
, 0, NULL
);
1356 ServiceEntry
= ServiceEntry
->Flink
;
1360 /* Start all services which have an invalid tag or which do not have a tag */
1361 ServiceEntry
= ServiceListHead
.Flink
;
1362 while (ServiceEntry
!= &ServiceListHead
)
1364 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1366 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1367 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1368 (CurrentService
->ServiceVisited
== FALSE
))
1370 CurrentService
->ServiceVisited
= TRUE
;
1371 ScmStartService(CurrentService
, 0, NULL
);
1374 ServiceEntry
= ServiceEntry
->Flink
;
1377 GroupEntry
= GroupEntry
->Flink
;
1380 /* Start all services which are members of any non-existing group */
1381 ServiceEntry
= ServiceListHead
.Flink
;
1382 while (ServiceEntry
!= &ServiceListHead
)
1384 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1386 if ((CurrentService
->lpGroup
!= NULL
) &&
1387 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1388 (CurrentService
->ServiceVisited
== FALSE
))
1390 CurrentService
->ServiceVisited
= TRUE
;
1391 ScmStartService(CurrentService
, 0, NULL
);
1394 ServiceEntry
= ServiceEntry
->Flink
;
1397 /* Start all services which are not a member of any group */
1398 ServiceEntry
= ServiceListHead
.Flink
;
1399 while (ServiceEntry
!= &ServiceListHead
)
1401 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1403 if ((CurrentService
->lpGroup
== NULL
) &&
1404 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1405 (CurrentService
->ServiceVisited
== FALSE
))
1407 CurrentService
->ServiceVisited
= TRUE
;
1408 ScmStartService(CurrentService
, 0, NULL
);
1411 ServiceEntry
= ServiceEntry
->Flink
;
1414 /* Clear 'ServiceVisited' flag again */
1415 ServiceEntry
= ServiceListHead
.Flink
;
1416 while (ServiceEntry
!= &ServiceListHead
)
1418 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1419 CurrentService
->ServiceVisited
= FALSE
;
1420 ServiceEntry
= ServiceEntry
->Flink
;
1426 ScmAutoShutdownServices(VOID
)
1428 PLIST_ENTRY ServiceEntry
;
1429 PSERVICE CurrentService
;
1431 DPRINT("ScmAutoShutdownServices() called\n");
1433 /* Lock the service database exclusively */
1434 ScmLockDatabaseExclusive();
1436 ServiceEntry
= ServiceListHead
.Flink
;
1437 while (ServiceEntry
!= &ServiceListHead
)
1439 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1441 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1442 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1444 /* shutdown service */
1445 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1446 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1449 ServiceEntry
= ServiceEntry
->Flink
;
1452 /* Unlock the service database */
1453 ScmUnlockDatabase();
1455 DPRINT("ScmAutoShutdownServices() done\n");
1460 ScmLockDatabaseExclusive(VOID
)
1462 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1467 ScmLockDatabaseShared(VOID
)
1469 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1474 ScmUnlockDatabase(VOID
)
1476 RtlReleaseResource(&DatabaseLock
);
1481 ScmInitNamedPipeCriticalSection(VOID
)
1483 InitializeCriticalSection(&ControlServiceCriticalSection
);
1488 ScmDeleteNamedPipeCriticalSection(VOID
)
1490 DeleteCriticalSection(&ControlServiceCriticalSection
);