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 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
223 /* Link the service image to the service */
224 pService
->lpImage
= pServiceImage
;
227 RtlFreeUnicodeString(&ImagePath
);
229 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
236 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
238 DPRINT1("ScmDereferenceServiceImage() called\n");
240 pServiceImage
->dwImageRunCount
--;
242 if (pServiceImage
->dwImageRunCount
== 0)
244 DPRINT1("dwImageRunCount == 0\n");
246 /* FIXME: Terminate the process */
248 /* Remove the service image from the list */
249 RemoveEntryList(&pServiceImage
->ImageListEntry
);
251 /* Close the control pipe */
252 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
253 CloseHandle(pServiceImage
->hControlPipe
);
255 /* Close the process handle */
256 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
257 CloseHandle(pServiceImage
->hProcess
);
259 /* Release the service image */
260 HeapFree(GetProcessHeap(), 0, pServiceImage
);
266 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
268 PLIST_ENTRY ServiceEntry
;
269 PSERVICE CurrentService
;
271 DPRINT("ScmGetServiceEntryByName() called\n");
273 ServiceEntry
= ServiceListHead
.Flink
;
274 while (ServiceEntry
!= &ServiceListHead
)
276 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
279 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
281 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
282 return CurrentService
;
285 ServiceEntry
= ServiceEntry
->Flink
;
288 DPRINT("Couldn't find a matching service\n");
295 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
297 PLIST_ENTRY ServiceEntry
;
298 PSERVICE CurrentService
;
300 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
302 ServiceEntry
= ServiceListHead
.Flink
;
303 while (ServiceEntry
!= &ServiceListHead
)
305 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
308 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
310 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
311 return CurrentService
;
314 ServiceEntry
= ServiceEntry
->Flink
;
317 DPRINT("Couldn't find a matching service\n");
324 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
326 PLIST_ENTRY ServiceEntry
;
327 PSERVICE CurrentService
;
329 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
331 ServiceEntry
= ServiceListHead
.Flink
;
332 while (ServiceEntry
!= &ServiceListHead
)
334 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
337 if (CurrentService
->dwResumeCount
> dwResumeCount
)
339 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
340 return CurrentService
;
343 ServiceEntry
= ServiceEntry
->Flink
;
346 DPRINT("Couldn't find a matching service\n");
353 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
354 PSERVICE
*lpServiceRecord
)
356 PSERVICE lpService
= NULL
;
358 DPRINT("Service: '%S'\n", lpServiceName
);
360 /* Allocate service entry */
361 lpService
= (SERVICE
*)HeapAlloc(GetProcessHeap(),
363 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
364 if (lpService
== NULL
)
365 return ERROR_NOT_ENOUGH_MEMORY
;
367 *lpServiceRecord
= lpService
;
369 /* Copy service name */
370 wcscpy(lpService
->szServiceName
, lpServiceName
);
371 lpService
->lpServiceName
= lpService
->szServiceName
;
372 lpService
->lpDisplayName
= lpService
->lpServiceName
;
374 /* Set the resume count */
375 lpService
->dwResumeCount
= dwResumeCount
++;
377 /* Append service record */
378 InsertTailList(&ServiceListHead
,
379 &lpService
->ServiceListEntry
);
381 /* Initialize the service status */
382 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
383 lpService
->Status
.dwControlsAccepted
= 0;
384 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
385 lpService
->Status
.dwServiceSpecificExitCode
= 0;
386 lpService
->Status
.dwCheckPoint
= 0;
387 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
389 return ERROR_SUCCESS
;
394 ScmDeleteServiceRecord(PSERVICE lpService
)
396 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
398 /* Delete the display name */
399 if (lpService
->lpDisplayName
!= NULL
&&
400 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
401 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
403 /* Dereference the service image */
404 if (lpService
->lpImage
)
405 ScmDereferenceServiceImage(lpService
->lpImage
);
407 /* Decrement the group reference counter */
408 if (lpService
->lpGroup
)
409 lpService
->lpGroup
->dwRefCount
--;
411 /* FIXME: SecurityDescriptor */
414 /* Remove the Service from the List */
415 RemoveEntryList(&lpService
->ServiceListEntry
);
417 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
419 /* Delete the service record */
420 HeapFree(GetProcessHeap(), 0, lpService
);
427 CreateServiceListEntry(LPCWSTR lpServiceName
,
430 PSERVICE lpService
= NULL
;
431 LPWSTR lpDisplayName
= NULL
;
432 LPWSTR lpGroup
= NULL
;
437 DWORD dwErrorControl
;
440 DPRINT("Service: '%S'\n", lpServiceName
);
441 if (*lpServiceName
== L
'{')
442 return ERROR_SUCCESS
;
444 dwSize
= sizeof(DWORD
);
445 dwError
= RegQueryValueExW(hServiceKey
,
449 (LPBYTE
)&dwServiceType
,
451 if (dwError
!= ERROR_SUCCESS
)
452 return ERROR_SUCCESS
;
454 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
455 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
456 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
457 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
458 return ERROR_SUCCESS
;
460 DPRINT("Service type: %lx\n", dwServiceType
);
462 dwSize
= sizeof(DWORD
);
463 dwError
= RegQueryValueExW(hServiceKey
,
467 (LPBYTE
)&dwStartType
,
469 if (dwError
!= ERROR_SUCCESS
)
470 return ERROR_SUCCESS
;
472 DPRINT("Start type: %lx\n", dwStartType
);
474 dwSize
= sizeof(DWORD
);
475 dwError
= RegQueryValueExW(hServiceKey
,
479 (LPBYTE
)&dwErrorControl
,
481 if (dwError
!= ERROR_SUCCESS
)
482 return ERROR_SUCCESS
;
484 DPRINT("Error control: %lx\n", dwErrorControl
);
486 dwError
= RegQueryValueExW(hServiceKey
,
492 if (dwError
!= ERROR_SUCCESS
)
495 DPRINT("Tag: %lx\n", dwTagId
);
497 dwError
= ScmReadString(hServiceKey
,
500 if (dwError
!= ERROR_SUCCESS
)
503 DPRINT("Group: %S\n", lpGroup
);
505 dwError
= ScmReadString(hServiceKey
,
508 if (dwError
!= ERROR_SUCCESS
)
509 lpDisplayName
= NULL
;
511 DPRINT("Display name: %S\n", lpDisplayName
);
513 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
515 if (dwError
!= ERROR_SUCCESS
)
518 lpService
->Status
.dwServiceType
= dwServiceType
;
519 lpService
->dwStartType
= dwStartType
;
520 lpService
->dwErrorControl
= dwErrorControl
;
521 lpService
->dwTag
= dwTagId
;
525 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
526 if (dwError
!= ERROR_SUCCESS
)
530 if (lpDisplayName
!= NULL
)
532 lpService
->lpDisplayName
= lpDisplayName
;
533 lpDisplayName
= NULL
;
536 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
537 if (lpService
->lpGroup
!= NULL
)
539 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
541 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
542 lpService
->dwStartType
,
543 lpService
->Status
.dwServiceType
,
545 lpService
->dwErrorControl
);
547 if (ScmIsDeleteFlagSet(hServiceKey
))
548 lpService
->bDeleted
= TRUE
;
552 HeapFree(GetProcessHeap(), 0, lpGroup
);
554 if (lpDisplayName
!= NULL
)
555 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
557 if (lpService
!= NULL
)
559 if (lpService
->lpImage
!= NULL
)
560 ScmDereferenceServiceImage(lpService
->lpImage
);
568 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
570 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
571 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
574 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
577 /* Find the maximum subkey length so that we can allocate a buffer */
578 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
579 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
583 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
584 /* Name too big: alloc a buffer for it */
585 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
588 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
591 while (dwRet
== ERROR_SUCCESS
)
593 dwSize
= dwMaxSubkeyLen
;
594 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
595 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
596 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
598 if (dwRet
== ERROR_NO_MORE_ITEMS
)
599 dwRet
= ERROR_SUCCESS
;
601 if (lpszName
!= szNameBuf
)
602 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
606 RegCloseKey(hSubKey
);
608 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
615 ScmDeleteMarkedServices(VOID
)
617 PLIST_ENTRY ServiceEntry
;
618 PSERVICE CurrentService
;
622 ServiceEntry
= ServiceListHead
.Flink
;
623 while (ServiceEntry
!= &ServiceListHead
)
625 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
627 ServiceEntry
= ServiceEntry
->Flink
;
629 if (CurrentService
->bDeleted
== TRUE
)
631 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
632 L
"System\\CurrentControlSet\\Services",
636 if (dwError
== ERROR_SUCCESS
)
638 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
639 RegCloseKey(hServicesKey
);
640 if (dwError
== ERROR_SUCCESS
)
642 RemoveEntryList(&CurrentService
->ServiceListEntry
);
643 HeapFree(GetProcessHeap(), 0, CurrentService
);
647 if (dwError
!= ERROR_SUCCESS
)
648 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
660 DPRINT("WaitForLSA() called\n");
662 hEvent
= CreateEventW(NULL
,
665 L
"LSA_RPC_SERVER_ACTIVE");
668 dwError
= GetLastError();
669 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
671 if (dwError
== ERROR_ALREADY_EXISTS
)
673 hEvent
= OpenEventW(SYNCHRONIZE
,
675 L
"LSA_RPC_SERVER_ACTIVE");
678 DPRINT1("Could not open the notification event!\n");
684 DPRINT("Wait for LSA!\n");
685 WaitForSingleObject(hEvent
, INFINITE
);
686 DPRINT("LSA is available!\n");
690 DPRINT("WaitForLSA() done\n");
695 ScmCreateServiceDatabase(VOID
)
697 WCHAR szSubKey
[MAX_PATH
];
701 DWORD dwSubKeyLength
;
702 FILETIME ftLastChanged
;
705 DPRINT("ScmCreateServiceDatabase() called\n");
707 dwError
= ScmCreateGroupList();
708 if (dwError
!= ERROR_SUCCESS
)
711 /* Initialize basic variables */
712 InitializeListHead(&ImageListHead
);
713 InitializeListHead(&ServiceListHead
);
715 /* Initialize the database lock */
716 RtlInitializeResource(&DatabaseLock
);
718 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
719 L
"System\\CurrentControlSet\\Services",
723 if (dwError
!= ERROR_SUCCESS
)
729 dwSubKeyLength
= MAX_PATH
;
730 dwError
= RegEnumKeyExW(hServicesKey
,
738 if (dwError
== ERROR_SUCCESS
&&
741 DPRINT("SubKeyName: '%S'\n", szSubKey
);
743 dwError
= RegOpenKeyExW(hServicesKey
,
748 if (dwError
== ERROR_SUCCESS
)
750 dwError
= CreateServiceListEntry(szSubKey
,
753 RegCloseKey(hServiceKey
);
757 if (dwError
!= ERROR_SUCCESS
)
763 RegCloseKey(hServicesKey
);
768 /* Delete services that are marked for delete */
769 ScmDeleteMarkedServices();
771 DPRINT("ScmCreateServiceDatabase() done\n");
773 return ERROR_SUCCESS
;
778 ScmShutdownServiceDatabase(VOID
)
780 DPRINT("ScmShutdownServiceDatabase() called\n");
782 ScmDeleteMarkedServices();
783 RtlDeleteResource(&DatabaseLock
);
785 DPRINT("ScmShutdownServiceDatabase() done\n");
790 ScmCheckDriver(PSERVICE Service
)
792 OBJECT_ATTRIBUTES ObjectAttributes
;
793 UNICODE_STRING DirName
;
796 POBJECT_DIRECTORY_INFORMATION DirInfo
;
801 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
803 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
805 RtlInitUnicodeString(&DirName
,
810 RtlInitUnicodeString(&DirName
,
814 InitializeObjectAttributes(&ObjectAttributes
,
820 Status
= NtOpenDirectoryObject(&DirHandle
,
821 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
823 if (!NT_SUCCESS(Status
))
828 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
829 2 * MAX_PATH
* sizeof(WCHAR
);
830 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
837 Status
= NtQueryDirectoryObject(DirHandle
,
844 if (Status
== STATUS_NO_MORE_ENTRIES
)
846 /* FIXME: Add current service to 'failed service' list */
847 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
851 if (!NT_SUCCESS(Status
))
854 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
856 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
858 DPRINT("Found: '%S' '%wZ'\n",
859 Service
->lpServiceName
, &DirInfo
->Name
);
861 /* Mark service as 'running' */
862 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
864 /* Mark the service group as 'running' */
865 if (Service
->lpGroup
!= NULL
)
867 Service
->lpGroup
->ServicesRunning
= TRUE
;
874 HeapFree(GetProcessHeap(),
879 return STATUS_SUCCESS
;
884 ScmGetBootAndSystemDriverState(VOID
)
886 PLIST_ENTRY ServiceEntry
;
887 PSERVICE CurrentService
;
889 DPRINT("ScmGetBootAndSystemDriverState() called\n");
891 ServiceEntry
= ServiceListHead
.Flink
;
892 while (ServiceEntry
!= &ServiceListHead
)
894 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
896 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
897 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
900 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
902 ScmCheckDriver(CurrentService
);
905 ServiceEntry
= ServiceEntry
->Flink
;
908 DPRINT("ScmGetBootAndSystemDriverState() done\n");
913 ScmControlService(PSERVICE Service
,
916 PSCM_CONTROL_PACKET ControlPacket
;
917 SCM_REPLY_PACKET ReplyPacket
;
919 DWORD dwWriteCount
= 0;
920 DWORD dwReadCount
= 0;
922 DWORD dwError
= ERROR_SUCCESS
;
924 DPRINT("ScmControlService() called\n");
926 EnterCriticalSection(&ControlServiceCriticalSection
);
928 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
930 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
932 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
933 if (ControlPacket
== NULL
)
935 LeaveCriticalSection(&ControlServiceCriticalSection
);
936 return ERROR_NOT_ENOUGH_MEMORY
;
939 ControlPacket
->dwControl
= dwControl
;
940 ControlPacket
->dwSize
= TotalLength
;
941 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
942 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
944 /* Send the control packet */
945 WriteFile(Service
->lpImage
->hControlPipe
,
947 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
952 ReadFile(Service
->lpImage
->hControlPipe
,
954 sizeof(SCM_REPLY_PACKET
),
958 /* Release the contol packet */
959 HeapFree(GetProcessHeap(),
963 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
965 dwError
= ReplyPacket
.dwError
;
968 if (dwError
== ERROR_SUCCESS
&&
969 dwControl
== SERVICE_CONTROL_STOP
)
971 ScmDereferenceServiceImage(Service
->lpImage
);
974 LeaveCriticalSection(&ControlServiceCriticalSection
);
976 DPRINT("ScmControlService() done\n");
983 ScmSendStartCommand(PSERVICE Service
,
987 PSCM_CONTROL_PACKET ControlPacket
;
988 SCM_REPLY_PACKET ReplyPacket
;
990 DWORD ArgsLength
= 0;
993 DWORD dwWriteCount
= 0;
994 DWORD dwReadCount
= 0;
995 DWORD dwError
= ERROR_SUCCESS
;
998 DPRINT("ScmSendStartCommand() called\n");
1000 /* Calculate the total length of the start command line */
1001 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
1004 for (i
= 0; i
< argc
; i
++)
1006 DPRINT("Arg: %S\n", argv
[i
]);
1007 Length
= wcslen(argv
[i
]) + 1;
1008 TotalLength
+= Length
;
1009 ArgsLength
+= Length
;
1013 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
1015 /* Allocate a control packet */
1016 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
1018 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
1019 if (ControlPacket
== NULL
)
1020 return ERROR_NOT_ENOUGH_MEMORY
;
1022 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
1023 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1024 ControlPacket
->dwSize
= TotalLength
;
1025 Ptr
= &ControlPacket
->szArguments
[0];
1026 wcscpy(Ptr
, Service
->lpServiceName
);
1027 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
1029 /* Copy argument list */
1033 DPRINT1("Arguments sent to service ignored!\n");
1035 memcpy(Ptr
, Arguments
, ArgsLength
);
1040 /* Terminate the argument list */
1043 /* Send the start command */
1044 WriteFile(Service
->lpImage
->hControlPipe
,
1046 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
1050 /* Read the reply */
1051 ReadFile(Service
->lpImage
->hControlPipe
,
1053 sizeof(SCM_REPLY_PACKET
),
1057 /* Release the contol packet */
1058 HeapFree(GetProcessHeap(),
1062 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1064 dwError
= ReplyPacket
.dwError
;
1067 DPRINT("ScmSendStartCommand() done\n");
1074 ScmStartUserModeService(PSERVICE Service
,
1078 PROCESS_INFORMATION ProcessInformation
;
1079 STARTUPINFOW StartupInfo
;
1081 DWORD dwError
= ERROR_SUCCESS
;
1084 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1086 /* If the image is already running ... */
1087 if (Service
->lpImage
->dwImageRunCount
> 1)
1089 /* ... just send a start command */
1090 return ScmSendStartCommand(Service
, argc
, argv
);
1093 StartupInfo
.cb
= sizeof(StartupInfo
);
1094 StartupInfo
.lpReserved
= NULL
;
1095 StartupInfo
.lpDesktop
= NULL
;
1096 StartupInfo
.lpTitle
= NULL
;
1097 StartupInfo
.dwFlags
= 0;
1098 StartupInfo
.cbReserved2
= 0;
1099 StartupInfo
.lpReserved2
= 0;
1101 Result
= CreateProcessW(NULL
,
1102 Service
->lpImage
->szImagePath
,
1106 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1110 &ProcessInformation
);
1113 dwError
= GetLastError();
1114 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1118 DPRINT("Process Id: %lu Handle %lx\n",
1119 ProcessInformation
.dwProcessId
,
1120 ProcessInformation
.hProcess
);
1121 DPRINT("Thread Id: %lu Handle %lx\n",
1122 ProcessInformation
.dwThreadId
,
1123 ProcessInformation
.hThread
);
1125 /* Get process handle and id */
1126 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1127 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1130 ResumeThread(ProcessInformation
.hThread
);
1132 /* Connect control pipe */
1133 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1134 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1138 DPRINT("Control pipe connected!\n");
1140 /* Read SERVICE_STATUS_HANDLE from pipe */
1141 if (!ReadFile(Service
->lpImage
->hControlPipe
,
1142 (LPVOID
)&dwProcessId
,
1147 dwError
= GetLastError();
1148 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1153 DPRINT("Received service process ID %lu\n", dwProcessId
);
1155 /* Send start command */
1156 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1161 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1164 /* Close thread handle */
1165 CloseHandle(ProcessInformation
.hThread
);
1172 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1174 PSERVICE_GROUP Group
= Service
->lpGroup
;
1175 DWORD dwError
= ERROR_SUCCESS
;
1176 LPCWSTR ErrorLogStrings
[2];
1178 DPRINT("ScmStartService() called\n");
1180 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1182 EnterCriticalSection(&ControlServiceCriticalSection
);
1184 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1186 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1187 LeaveCriticalSection(&ControlServiceCriticalSection
);
1188 return ERROR_SERVICE_ALREADY_RUNNING
;
1191 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1193 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1196 dwError
= ScmLoadDriver(Service
);
1197 if (dwError
== ERROR_SUCCESS
)
1199 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1200 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1205 /* Start user-mode service */
1206 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1207 if (dwError
== ERROR_SUCCESS
)
1209 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1210 if (dwError
== ERROR_SUCCESS
)
1212 #ifdef USE_SERVICE_START_PENDING
1213 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1215 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1220 ScmDereferenceServiceImage(Service
->lpImage
);
1221 Service
->lpImage
= NULL
;
1226 LeaveCriticalSection(&ControlServiceCriticalSection
);
1228 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1230 if (dwError
== ERROR_SUCCESS
)
1234 Group
->ServicesRunning
= TRUE
;
1239 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1241 ErrorLogStrings
[0] = Service
->lpServiceName
;
1242 ErrorLogStrings
[1] = L
"Test";
1243 ScmLogError(EVENT_SERVICE_START_FAILED
,
1249 switch (Service
->dwErrorControl
)
1251 case SERVICE_ERROR_SEVERE
:
1252 if (IsLastKnownGood
== FALSE
)
1254 /* FIXME: Boot last known good configuration */
1258 case SERVICE_ERROR_CRITICAL
:
1259 if (IsLastKnownGood
== FALSE
)
1261 /* FIXME: Boot last known good configuration */
1277 ScmAutoStartServices(VOID
)
1279 PLIST_ENTRY GroupEntry
;
1280 PLIST_ENTRY ServiceEntry
;
1281 PSERVICE_GROUP CurrentGroup
;
1282 PSERVICE CurrentService
;
1283 WCHAR szSafeBootServicePath
[MAX_PATH
];
1288 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1289 ServiceEntry
= ServiceListHead
.Flink
;
1290 while (ServiceEntry
!= &ServiceListHead
)
1292 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1293 /* Build the safe boot path */
1294 wcscpy(szSafeBootServicePath
,
1295 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1296 switch(GetSystemMetrics(SM_CLEANBOOT
))
1298 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1300 case 3: wcscat(szSafeBootServicePath
, L
"\\Minimal\\"); break;
1301 case 2: wcscat(szSafeBootServicePath
, L
"\\Network\\"); break;
1303 if(GetSystemMetrics(SM_CLEANBOOT
))
1305 /* If key does not exist then do not assume safe mode */
1306 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1307 szSafeBootServicePath
,
1311 if(dwError
== ERROR_SUCCESS
)
1314 /* Finish Safe Boot path off */
1315 wcsncat(szSafeBootServicePath
,
1316 CurrentService
->lpServiceName
,
1317 MAX_PATH
- wcslen(szSafeBootServicePath
));
1318 /* Check that the key is in the Safe Boot path */
1319 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1320 szSafeBootServicePath
,
1324 if(dwError
!= ERROR_SUCCESS
)
1326 /* Mark service as visited so it is not auto-started */
1327 CurrentService
->ServiceVisited
= TRUE
;
1331 /* Must be auto-started in safe mode - mark as unvisited */
1333 CurrentService
->ServiceVisited
= FALSE
;
1338 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1339 CurrentService
->ServiceVisited
= FALSE
;
1342 ServiceEntry
= ServiceEntry
->Flink
;
1345 /* Start all services which are members of an existing group */
1346 GroupEntry
= GroupListHead
.Flink
;
1347 while (GroupEntry
!= &GroupListHead
)
1349 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1351 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1353 /* Start all services witch have a valid tag */
1354 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1356 ServiceEntry
= ServiceListHead
.Flink
;
1357 while (ServiceEntry
!= &ServiceListHead
)
1359 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1361 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1362 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1363 (CurrentService
->ServiceVisited
== FALSE
) &&
1364 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1366 CurrentService
->ServiceVisited
= TRUE
;
1367 ScmStartService(CurrentService
, 0, NULL
);
1370 ServiceEntry
= ServiceEntry
->Flink
;
1374 /* Start all services which have an invalid tag or which do not have a tag */
1375 ServiceEntry
= ServiceListHead
.Flink
;
1376 while (ServiceEntry
!= &ServiceListHead
)
1378 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1380 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1381 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1382 (CurrentService
->ServiceVisited
== FALSE
))
1384 CurrentService
->ServiceVisited
= TRUE
;
1385 ScmStartService(CurrentService
, 0, NULL
);
1388 ServiceEntry
= ServiceEntry
->Flink
;
1391 GroupEntry
= GroupEntry
->Flink
;
1394 /* Start all services which are members of any non-existing group */
1395 ServiceEntry
= ServiceListHead
.Flink
;
1396 while (ServiceEntry
!= &ServiceListHead
)
1398 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1400 if ((CurrentService
->lpGroup
!= NULL
) &&
1401 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1402 (CurrentService
->ServiceVisited
== FALSE
))
1404 CurrentService
->ServiceVisited
= TRUE
;
1405 ScmStartService(CurrentService
, 0, NULL
);
1408 ServiceEntry
= ServiceEntry
->Flink
;
1411 /* Start all services which are not a member of any group */
1412 ServiceEntry
= ServiceListHead
.Flink
;
1413 while (ServiceEntry
!= &ServiceListHead
)
1415 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1417 if ((CurrentService
->lpGroup
== NULL
) &&
1418 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1419 (CurrentService
->ServiceVisited
== FALSE
))
1421 CurrentService
->ServiceVisited
= TRUE
;
1422 ScmStartService(CurrentService
, 0, NULL
);
1425 ServiceEntry
= ServiceEntry
->Flink
;
1428 /* Clear 'ServiceVisited' flag again */
1429 ServiceEntry
= ServiceListHead
.Flink
;
1430 while (ServiceEntry
!= &ServiceListHead
)
1432 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1433 CurrentService
->ServiceVisited
= FALSE
;
1434 ServiceEntry
= ServiceEntry
->Flink
;
1440 ScmAutoShutdownServices(VOID
)
1442 PLIST_ENTRY ServiceEntry
;
1443 PSERVICE CurrentService
;
1445 DPRINT("ScmAutoShutdownServices() called\n");
1447 /* Lock the service database exclusively */
1448 ScmLockDatabaseExclusive();
1450 ServiceEntry
= ServiceListHead
.Flink
;
1451 while (ServiceEntry
!= &ServiceListHead
)
1453 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1455 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1456 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1458 /* shutdown service */
1459 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1460 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1463 ServiceEntry
= ServiceEntry
->Flink
;
1466 /* Unlock the service database */
1467 ScmUnlockDatabase();
1469 DPRINT("ScmAutoShutdownServices() done\n");
1474 ScmLockDatabaseExclusive(VOID
)
1476 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1481 ScmLockDatabaseShared(VOID
)
1483 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1488 ScmUnlockDatabase(VOID
)
1490 RtlReleaseResource(&DatabaseLock
);
1495 ScmInitNamedPipeCriticalSection(VOID
)
1497 InitializeCriticalSection(&ControlServiceCriticalSection
);
1502 ScmDeleteNamedPipeCriticalSection(VOID
)
1504 DeleteCriticalSection(&ControlServiceCriticalSection
);