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
27 * Uncomment the line below to use asynchronous IO operations
28 * on the service control pipes.
30 // #define USE_ASYNCHRONOUS_IO
33 /* GLOBALS *******************************************************************/
35 LIST_ENTRY ImageListHead
;
36 LIST_ENTRY ServiceListHead
;
38 static RTL_RESOURCE DatabaseLock
;
39 static DWORD dwResumeCount
= 1;
41 static CRITICAL_SECTION ControlServiceCriticalSection
;
42 static DWORD dwPipeTimeout
= 30000; /* 30 Seconds */
45 /* FUNCTIONS *****************************************************************/
48 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
50 WCHAR szControlPipeName
[MAX_PATH
+ 1];
51 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
52 DWORD ServiceCurrent
= 0;
57 /* Get the service number */
58 /* TODO: Create registry entry with correct write access */
59 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
60 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
66 if (dwError
!= ERROR_SUCCESS
)
68 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
72 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
74 dwKeySize
= sizeof(DWORD
);
75 dwError
= RegQueryValueExW(hServiceCurrentKey
,
76 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
78 if (dwError
!= ERROR_SUCCESS
)
80 RegCloseKey(hServiceCurrentKey
);
81 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
88 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
90 RegCloseKey(hServiceCurrentKey
);
92 if (dwError
!= ERROR_SUCCESS
)
94 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
98 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
99 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
101 DPRINT("PipeName: %S\n", szControlPipeName
);
103 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
104 #ifdef USE_ASYNCHRONOUS_IO
105 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
109 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
115 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
116 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
118 DPRINT1("Failed to create control pipe!\n");
119 return GetLastError();
122 return ERROR_SUCCESS
;
126 static PSERVICE_IMAGE
127 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
129 PLIST_ENTRY ImageEntry
;
130 PSERVICE_IMAGE CurrentImage
;
132 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
134 ImageEntry
= ImageListHead
.Flink
;
135 while (ImageEntry
!= &ImageListHead
)
137 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
140 if (_wcsicmp(CurrentImage
->szImagePath
, lpImagePath
) == 0)
142 DPRINT("Found image: '%S'\n", CurrentImage
->szImagePath
);
146 ImageEntry
= ImageEntry
->Flink
;
149 DPRINT1("Couldn't find a matching image\n");
157 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
159 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
160 UNICODE_STRING ImagePath
;
161 PSERVICE_IMAGE pServiceImage
= NULL
;
163 DWORD dwError
= ERROR_SUCCESS
;
165 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
167 RtlInitUnicodeString(&ImagePath
, NULL
);
169 /* Get service data */
170 RtlZeroMemory(&QueryTable
,
173 QueryTable
[0].Name
= L
"ImagePath";
174 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
175 QueryTable
[0].EntryContext
= &ImagePath
;
177 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
178 pService
->lpServiceName
,
182 if (!NT_SUCCESS(Status
))
184 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
185 return RtlNtStatusToDosError(Status
);
188 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
190 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
191 if (pServiceImage
== NULL
)
193 /* Create a new service image */
194 pServiceImage
= (PSERVICE_IMAGE
)HeapAlloc(GetProcessHeap(),
196 sizeof(SERVICE_IMAGE
) + ((wcslen(ImagePath
.Buffer
) + 1) * sizeof(WCHAR
)));
197 if (pServiceImage
== NULL
)
199 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
203 pServiceImage
->dwImageRunCount
= 1;
204 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
205 pServiceImage
->hProcess
= INVALID_HANDLE_VALUE
;
207 /* Set the image path */
208 wcscpy(pServiceImage
->szImagePath
,
211 RtlFreeUnicodeString(&ImagePath
);
213 /* Create the control pipe */
214 dwError
= ScmCreateNewControlPipe(pServiceImage
);
215 if (dwError
!= ERROR_SUCCESS
)
217 HeapFree(GetProcessHeap(), 0, pServiceImage
);
221 /* FIXME: Add more initialization code here */
224 /* Append service record */
225 InsertTailList(&ImageListHead
,
226 &pServiceImage
->ImageListEntry
);
230 /* Increment the run counter */
231 pServiceImage
->dwImageRunCount
++;
234 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
236 /* Link the service image to the service */
237 pService
->lpImage
= pServiceImage
;
240 RtlFreeUnicodeString(&ImagePath
);
242 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
249 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
251 DPRINT1("ScmDereferenceServiceImage() called\n");
253 pServiceImage
->dwImageRunCount
--;
255 if (pServiceImage
->dwImageRunCount
== 0)
257 DPRINT1("dwImageRunCount == 0\n");
259 /* FIXME: Terminate the process */
261 /* Remove the service image from the list */
262 RemoveEntryList(&pServiceImage
->ImageListEntry
);
264 /* Close the control pipe */
265 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
266 CloseHandle(pServiceImage
->hControlPipe
);
268 /* Close the process handle */
269 if (pServiceImage
->hProcess
!= INVALID_HANDLE_VALUE
)
270 CloseHandle(pServiceImage
->hProcess
);
272 /* Release the service image */
273 HeapFree(GetProcessHeap(), 0, pServiceImage
);
279 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
281 PLIST_ENTRY ServiceEntry
;
282 PSERVICE CurrentService
;
284 DPRINT("ScmGetServiceEntryByName() called\n");
286 ServiceEntry
= ServiceListHead
.Flink
;
287 while (ServiceEntry
!= &ServiceListHead
)
289 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
292 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
294 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
295 return CurrentService
;
298 ServiceEntry
= ServiceEntry
->Flink
;
301 DPRINT("Couldn't find a matching service\n");
308 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
310 PLIST_ENTRY ServiceEntry
;
311 PSERVICE CurrentService
;
313 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
315 ServiceEntry
= ServiceListHead
.Flink
;
316 while (ServiceEntry
!= &ServiceListHead
)
318 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
321 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
323 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
324 return CurrentService
;
327 ServiceEntry
= ServiceEntry
->Flink
;
330 DPRINT("Couldn't find a matching service\n");
337 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
339 PLIST_ENTRY ServiceEntry
;
340 PSERVICE CurrentService
;
342 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
344 ServiceEntry
= ServiceListHead
.Flink
;
345 while (ServiceEntry
!= &ServiceListHead
)
347 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
350 if (CurrentService
->dwResumeCount
> dwResumeCount
)
352 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
353 return CurrentService
;
356 ServiceEntry
= ServiceEntry
->Flink
;
359 DPRINT("Couldn't find a matching service\n");
366 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
367 PSERVICE
*lpServiceRecord
)
369 PSERVICE lpService
= NULL
;
371 DPRINT("Service: '%S'\n", lpServiceName
);
373 /* Allocate service entry */
374 lpService
= (SERVICE
*)HeapAlloc(GetProcessHeap(),
376 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
377 if (lpService
== NULL
)
378 return ERROR_NOT_ENOUGH_MEMORY
;
380 *lpServiceRecord
= lpService
;
382 /* Copy service name */
383 wcscpy(lpService
->szServiceName
, lpServiceName
);
384 lpService
->lpServiceName
= lpService
->szServiceName
;
385 lpService
->lpDisplayName
= lpService
->lpServiceName
;
387 /* Set the resume count */
388 lpService
->dwResumeCount
= dwResumeCount
++;
390 /* Append service record */
391 InsertTailList(&ServiceListHead
,
392 &lpService
->ServiceListEntry
);
394 /* Initialize the service status */
395 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
396 lpService
->Status
.dwControlsAccepted
= 0;
397 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
398 lpService
->Status
.dwServiceSpecificExitCode
= 0;
399 lpService
->Status
.dwCheckPoint
= 0;
400 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
402 return ERROR_SUCCESS
;
407 ScmDeleteServiceRecord(PSERVICE lpService
)
409 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
411 /* Delete the display name */
412 if (lpService
->lpDisplayName
!= NULL
&&
413 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
414 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
416 /* Dereference the service image */
417 if (lpService
->lpImage
)
418 ScmDereferenceServiceImage(lpService
->lpImage
);
420 /* Decrement the group reference counter */
421 if (lpService
->lpGroup
)
422 lpService
->lpGroup
->dwRefCount
--;
424 /* FIXME: SecurityDescriptor */
427 /* Remove the Service from the List */
428 RemoveEntryList(&lpService
->ServiceListEntry
);
430 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
432 /* Delete the service record */
433 HeapFree(GetProcessHeap(), 0, lpService
);
440 CreateServiceListEntry(LPCWSTR lpServiceName
,
443 PSERVICE lpService
= NULL
;
444 LPWSTR lpDisplayName
= NULL
;
445 LPWSTR lpGroup
= NULL
;
450 DWORD dwErrorControl
;
453 DPRINT("Service: '%S'\n", lpServiceName
);
454 if (*lpServiceName
== L
'{')
455 return ERROR_SUCCESS
;
457 dwSize
= sizeof(DWORD
);
458 dwError
= RegQueryValueExW(hServiceKey
,
462 (LPBYTE
)&dwServiceType
,
464 if (dwError
!= ERROR_SUCCESS
)
465 return ERROR_SUCCESS
;
467 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
468 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
469 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
470 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
471 return ERROR_SUCCESS
;
473 DPRINT("Service type: %lx\n", dwServiceType
);
475 dwSize
= sizeof(DWORD
);
476 dwError
= RegQueryValueExW(hServiceKey
,
480 (LPBYTE
)&dwStartType
,
482 if (dwError
!= ERROR_SUCCESS
)
483 return ERROR_SUCCESS
;
485 DPRINT("Start type: %lx\n", dwStartType
);
487 dwSize
= sizeof(DWORD
);
488 dwError
= RegQueryValueExW(hServiceKey
,
492 (LPBYTE
)&dwErrorControl
,
494 if (dwError
!= ERROR_SUCCESS
)
495 return ERROR_SUCCESS
;
497 DPRINT("Error control: %lx\n", dwErrorControl
);
499 dwError
= RegQueryValueExW(hServiceKey
,
505 if (dwError
!= ERROR_SUCCESS
)
508 DPRINT("Tag: %lx\n", dwTagId
);
510 dwError
= ScmReadString(hServiceKey
,
513 if (dwError
!= ERROR_SUCCESS
)
516 DPRINT("Group: %S\n", lpGroup
);
518 dwError
= ScmReadString(hServiceKey
,
521 if (dwError
!= ERROR_SUCCESS
)
522 lpDisplayName
= NULL
;
524 DPRINT("Display name: %S\n", lpDisplayName
);
526 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
528 if (dwError
!= ERROR_SUCCESS
)
531 lpService
->Status
.dwServiceType
= dwServiceType
;
532 lpService
->dwStartType
= dwStartType
;
533 lpService
->dwErrorControl
= dwErrorControl
;
534 lpService
->dwTag
= dwTagId
;
538 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
539 if (dwError
!= ERROR_SUCCESS
)
543 if (lpDisplayName
!= NULL
)
545 lpService
->lpDisplayName
= lpDisplayName
;
546 lpDisplayName
= NULL
;
549 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
550 if (lpService
->lpGroup
!= NULL
)
552 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
554 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
555 lpService
->dwStartType
,
556 lpService
->Status
.dwServiceType
,
558 lpService
->dwErrorControl
);
560 if (ScmIsDeleteFlagSet(hServiceKey
))
561 lpService
->bDeleted
= TRUE
;
565 HeapFree(GetProcessHeap(), 0, lpGroup
);
567 if (lpDisplayName
!= NULL
)
568 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
570 if (lpService
!= NULL
)
572 if (lpService
->lpImage
!= NULL
)
573 ScmDereferenceServiceImage(lpService
->lpImage
);
581 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
583 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
584 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
587 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
590 /* Find the maximum subkey length so that we can allocate a buffer */
591 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
592 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
596 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
597 /* Name too big: alloc a buffer for it */
598 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
601 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
604 while (dwRet
== ERROR_SUCCESS
)
606 dwSize
= dwMaxSubkeyLen
;
607 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
608 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
609 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
611 if (dwRet
== ERROR_NO_MORE_ITEMS
)
612 dwRet
= ERROR_SUCCESS
;
614 if (lpszName
!= szNameBuf
)
615 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
619 RegCloseKey(hSubKey
);
621 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
628 ScmDeleteMarkedServices(VOID
)
630 PLIST_ENTRY ServiceEntry
;
631 PSERVICE CurrentService
;
635 ServiceEntry
= ServiceListHead
.Flink
;
636 while (ServiceEntry
!= &ServiceListHead
)
638 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
640 ServiceEntry
= ServiceEntry
->Flink
;
642 if (CurrentService
->bDeleted
== TRUE
)
644 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
645 L
"System\\CurrentControlSet\\Services",
649 if (dwError
== ERROR_SUCCESS
)
651 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
652 RegCloseKey(hServicesKey
);
653 if (dwError
== ERROR_SUCCESS
)
655 RemoveEntryList(&CurrentService
->ServiceListEntry
);
656 HeapFree(GetProcessHeap(), 0, CurrentService
);
660 if (dwError
!= ERROR_SUCCESS
)
661 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
673 DPRINT("WaitForLSA() called\n");
675 hEvent
= CreateEventW(NULL
,
678 L
"LSA_RPC_SERVER_ACTIVE");
681 dwError
= GetLastError();
682 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
684 if (dwError
== ERROR_ALREADY_EXISTS
)
686 hEvent
= OpenEventW(SYNCHRONIZE
,
688 L
"LSA_RPC_SERVER_ACTIVE");
691 DPRINT1("Could not open the notification event!\n");
697 DPRINT("Wait for LSA!\n");
698 WaitForSingleObject(hEvent
, INFINITE
);
699 DPRINT("LSA is available!\n");
703 DPRINT("WaitForLSA() done\n");
708 ScmCreateServiceDatabase(VOID
)
710 WCHAR szSubKey
[MAX_PATH
];
714 DWORD dwSubKeyLength
;
715 FILETIME ftLastChanged
;
718 DPRINT("ScmCreateServiceDatabase() called\n");
720 dwError
= ScmCreateGroupList();
721 if (dwError
!= ERROR_SUCCESS
)
724 /* Initialize basic variables */
725 InitializeListHead(&ImageListHead
);
726 InitializeListHead(&ServiceListHead
);
728 /* Initialize the database lock */
729 RtlInitializeResource(&DatabaseLock
);
731 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
732 L
"System\\CurrentControlSet\\Services",
736 if (dwError
!= ERROR_SUCCESS
)
742 dwSubKeyLength
= MAX_PATH
;
743 dwError
= RegEnumKeyExW(hServicesKey
,
751 if (dwError
== ERROR_SUCCESS
&&
754 DPRINT("SubKeyName: '%S'\n", szSubKey
);
756 dwError
= RegOpenKeyExW(hServicesKey
,
761 if (dwError
== ERROR_SUCCESS
)
763 dwError
= CreateServiceListEntry(szSubKey
,
766 RegCloseKey(hServiceKey
);
770 if (dwError
!= ERROR_SUCCESS
)
776 RegCloseKey(hServicesKey
);
781 /* Delete services that are marked for delete */
782 ScmDeleteMarkedServices();
784 DPRINT("ScmCreateServiceDatabase() done\n");
786 return ERROR_SUCCESS
;
791 ScmShutdownServiceDatabase(VOID
)
793 DPRINT("ScmShutdownServiceDatabase() called\n");
795 ScmDeleteMarkedServices();
796 RtlDeleteResource(&DatabaseLock
);
798 DPRINT("ScmShutdownServiceDatabase() done\n");
803 ScmCheckDriver(PSERVICE Service
)
805 OBJECT_ATTRIBUTES ObjectAttributes
;
806 UNICODE_STRING DirName
;
809 POBJECT_DIRECTORY_INFORMATION DirInfo
;
814 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
816 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
818 RtlInitUnicodeString(&DirName
,
823 RtlInitUnicodeString(&DirName
,
827 InitializeObjectAttributes(&ObjectAttributes
,
833 Status
= NtOpenDirectoryObject(&DirHandle
,
834 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
836 if (!NT_SUCCESS(Status
))
841 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
842 2 * MAX_PATH
* sizeof(WCHAR
);
843 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
850 Status
= NtQueryDirectoryObject(DirHandle
,
857 if (Status
== STATUS_NO_MORE_ENTRIES
)
859 /* FIXME: Add current service to 'failed service' list */
860 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
864 if (!NT_SUCCESS(Status
))
867 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
869 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
871 DPRINT("Found: '%S' '%wZ'\n",
872 Service
->lpServiceName
, &DirInfo
->Name
);
874 /* Mark service as 'running' */
875 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
877 /* Mark the service group as 'running' */
878 if (Service
->lpGroup
!= NULL
)
880 Service
->lpGroup
->ServicesRunning
= TRUE
;
887 HeapFree(GetProcessHeap(),
892 return STATUS_SUCCESS
;
897 ScmGetBootAndSystemDriverState(VOID
)
899 PLIST_ENTRY ServiceEntry
;
900 PSERVICE CurrentService
;
902 DPRINT("ScmGetBootAndSystemDriverState() called\n");
904 ServiceEntry
= ServiceListHead
.Flink
;
905 while (ServiceEntry
!= &ServiceListHead
)
907 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
909 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
910 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
913 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
915 ScmCheckDriver(CurrentService
);
918 ServiceEntry
= ServiceEntry
->Flink
;
921 DPRINT("ScmGetBootAndSystemDriverState() done\n");
926 ScmControlService(PSERVICE Service
,
929 PSCM_CONTROL_PACKET ControlPacket
;
930 SCM_REPLY_PACKET ReplyPacket
;
932 DWORD dwWriteCount
= 0;
933 DWORD dwReadCount
= 0;
936 DWORD dwError
= ERROR_SUCCESS
;
938 #ifdef USE_ASYNCHRONOUS_IO
939 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
942 DPRINT("ScmControlService() called\n");
944 EnterCriticalSection(&ControlServiceCriticalSection
);
946 /* Calculate the total length of the start command line */
947 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
948 PacketSize
+= (wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
);
950 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
953 if (ControlPacket
== NULL
)
955 LeaveCriticalSection(&ControlServiceCriticalSection
);
956 return ERROR_NOT_ENOUGH_MEMORY
;
959 ControlPacket
->dwSize
= PacketSize
;
960 ControlPacket
->dwControl
= dwControl
;
961 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
963 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
965 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
966 wcscpy(Ptr
, Service
->lpServiceName
);
968 ControlPacket
->dwArgumentsCount
= 0;
969 ControlPacket
->dwArgumentsOffset
= 0;
971 #ifdef USE_ASYNCHRONOUS_IO
972 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
977 if (bResult
== FALSE
)
979 DPRINT1("WriteFile() returned FALSE\n");
981 dwError
= GetLastError();
982 if (dwError
== ERROR_IO_PENDING
)
984 DPRINT1("dwError: ERROR_IO_PENDING\n");
986 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
988 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
990 if (dwError
== WAIT_TIMEOUT
)
992 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
993 if (bResult
== FALSE
)
995 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
998 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1001 else if (dwError
== ERROR_SUCCESS
)
1003 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1007 if (bResult
== FALSE
)
1009 dwError
= GetLastError();
1010 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1018 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1023 /* Read the reply */
1024 Overlapped
.hEvent
= (HANDLE
) NULL
;
1026 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1028 sizeof(SCM_REPLY_PACKET
),
1031 if (bResult
== FALSE
)
1033 DPRINT1("ReadFile() returned FALSE\n");
1035 dwError
= GetLastError();
1036 if (dwError
== ERROR_IO_PENDING
)
1038 DPRINT1("dwError: ERROR_IO_PENDING\n");
1040 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1042 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1044 if (dwError
== WAIT_TIMEOUT
)
1046 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1047 if (bResult
== FALSE
)
1049 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1052 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1055 else if (dwError
== ERROR_SUCCESS
)
1057 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1061 if (bResult
== FALSE
)
1063 dwError
= GetLastError();
1064 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1072 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1078 /* Send the control packet */
1079 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1084 if (bResult
== FALSE
)
1086 dwError
= GetLastError();
1087 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1091 /* Read the reply */
1092 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1094 sizeof(SCM_REPLY_PACKET
),
1097 if (bResult
== FALSE
)
1099 dwError
= GetLastError();
1100 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1105 /* Release the contol packet */
1106 HeapFree(GetProcessHeap(),
1110 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1112 dwError
= ReplyPacket
.dwError
;
1115 if (dwError
== ERROR_SUCCESS
&&
1116 dwControl
== SERVICE_CONTROL_STOP
)
1118 ScmDereferenceServiceImage(Service
->lpImage
);
1121 LeaveCriticalSection(&ControlServiceCriticalSection
);
1123 DPRINT("ScmControlService() done\n");
1130 ScmSendStartCommand(PSERVICE Service
,
1134 PSCM_CONTROL_PACKET ControlPacket
;
1135 SCM_REPLY_PACKET ReplyPacket
;
1138 DWORD dwWriteCount
= 0;
1139 DWORD dwReadCount
= 0;
1140 DWORD dwError
= ERROR_SUCCESS
;
1145 #ifdef USE_ASYNCHRONOUS_IO
1146 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1149 DPRINT("ScmSendStartCommand() called\n");
1151 /* Calculate the total length of the start command line */
1152 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1153 PacketSize
+= (wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
);
1155 /* Calculate the required packet size for the start arguments */
1156 if (argc
> 0 && argv
!= NULL
)
1158 PacketSize
= ALIGN_UP(PacketSize
, LPWSTR
);
1160 DPRINT("Argc: %lu\n", argc
);
1161 for (i
= 0; i
< argc
; i
++)
1163 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1164 PacketSize
+= (wcslen(argv
[i
]) + 1) * sizeof(WCHAR
) + sizeof(PWSTR
);
1168 /* Allocate a control packet */
1169 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
1172 if (ControlPacket
== NULL
)
1173 return ERROR_NOT_ENOUGH_MEMORY
;
1175 ControlPacket
->dwSize
= PacketSize
;
1176 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
1177 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1178 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1180 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1181 wcscpy(Ptr
, Service
->lpServiceName
);
1183 ControlPacket
->dwArgumentsCount
= 0;
1184 ControlPacket
->dwArgumentsOffset
= 0;
1186 /* Copy argument list */
1187 if (argc
> 0 && argv
!= NULL
)
1189 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1190 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1191 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1193 ControlPacket
->dwArgumentsCount
= argc
;
1194 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1196 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1197 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1199 for (i
= 0; i
< argc
; i
++)
1201 wcscpy(pArgPtr
, argv
[i
]);
1202 *pOffPtr
= (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1203 DPRINT("offset: %p\n", *pOffPtr
);
1205 pArgPtr
+= wcslen(argv
[i
]) + 1;
1210 #ifdef USE_ASYNCHRONOUS_IO
1211 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1216 if (bResult
== FALSE
)
1218 DPRINT1("WriteFile() returned FALSE\n");
1220 dwError
= GetLastError();
1221 if (dwError
== ERROR_IO_PENDING
)
1223 DPRINT1("dwError: ERROR_IO_PENDING\n");
1225 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1227 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1229 if (dwError
== WAIT_TIMEOUT
)
1231 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1232 if (bResult
== FALSE
)
1234 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1237 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1240 else if (dwError
== ERROR_SUCCESS
)
1242 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1246 if (bResult
== FALSE
)
1248 dwError
= GetLastError();
1249 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1257 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1262 /* Read the reply */
1263 Overlapped
.hEvent
= (HANDLE
) NULL
;
1265 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1267 sizeof(SCM_REPLY_PACKET
),
1270 if (bResult
== FALSE
)
1272 DPRINT1("ReadFile() returned FALSE\n");
1274 dwError
= GetLastError();
1275 if (dwError
== ERROR_IO_PENDING
)
1277 DPRINT1("dwError: ERROR_IO_PENDING\n");
1279 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1281 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1283 if (dwError
== WAIT_TIMEOUT
)
1285 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1286 if (bResult
== FALSE
)
1288 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1291 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1294 else if (dwError
== ERROR_SUCCESS
)
1296 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1300 if (bResult
== FALSE
)
1302 dwError
= GetLastError();
1303 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1311 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1317 /* Send the start command */
1318 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1323 if (bResult
== FALSE
)
1325 dwError
= GetLastError();
1326 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1330 /* Read the reply */
1331 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1333 sizeof(SCM_REPLY_PACKET
),
1336 if (bResult
== FALSE
)
1338 dwError
= GetLastError();
1339 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1344 /* Release the contol packet */
1345 HeapFree(GetProcessHeap(),
1349 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1351 dwError
= ReplyPacket
.dwError
;
1354 DPRINT("ScmSendStartCommand() done\n");
1361 ScmWaitForServiceConnect(PSERVICE Service
)
1364 DWORD dwProcessId
= 0;
1365 DWORD dwError
= ERROR_SUCCESS
;
1367 #ifdef USE_ASYNCHRONOUS_IO
1368 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1371 DPRINT1("ScmWaitForServiceConnect()\n");
1373 #ifdef USE_ASYNCHRONOUS_IO
1374 Overlapped
.hEvent
= (HANDLE
)NULL
;
1376 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1378 if (bResult
== FALSE
)
1380 DPRINT1("ConnectNamedPipe() returned FALSE\n");
1382 dwError
= GetLastError();
1383 if (dwError
== ERROR_IO_PENDING
)
1385 DPRINT1("dwError: ERROR_IO_PENDING\n");
1387 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1389 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1391 if (dwError
== WAIT_TIMEOUT
)
1393 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1394 if (bResult
== FALSE
)
1396 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1399 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1401 else if (dwError
== ERROR_SUCCESS
)
1403 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1407 if (bResult
== FALSE
)
1409 dwError
= GetLastError();
1410 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1416 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1418 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1423 DPRINT1("Control pipe connected!\n");
1425 Overlapped
.hEvent
= (HANDLE
) NULL
;
1427 /* Read the process id from pipe */
1428 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1429 (LPVOID
)&dwProcessId
,
1433 if (bResult
== FALSE
)
1435 DPRINT1("ReadFile() returned FALSE\n");
1437 dwError
= GetLastError();
1438 if (dwError
== ERROR_IO_PENDING
)
1440 DPRINT1("dwError: ERROR_IO_PENDING\n");
1442 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1444 if (dwError
== WAIT_TIMEOUT
)
1446 DPRINT1("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1448 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1449 if (bResult
== FALSE
)
1451 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1454 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1456 else if (dwError
== ERROR_SUCCESS
)
1458 DPRINT1("WaitForSingleObject() returned ERROR_SUCCESS\n");
1460 DPRINT1("Process Id: %lu\n", dwProcessId
);
1462 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1466 if (bResult
== FALSE
)
1468 dwError
= GetLastError();
1469 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1476 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1481 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1486 DPRINT1("ScmWaitForServiceConnect() done\n");
1488 return ERROR_SUCCESS
;
1491 /* Connect control pipe */
1492 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1493 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1495 DPRINT("Control pipe connected!\n");
1497 /* Read SERVICE_STATUS_HANDLE from pipe */
1498 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1499 (LPVOID
)&dwProcessId
,
1503 if (bResult
== FALSE
)
1505 dwError
= GetLastError();
1506 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1512 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1521 ScmStartUserModeService(PSERVICE Service
,
1525 PROCESS_INFORMATION ProcessInformation
;
1526 STARTUPINFOW StartupInfo
;
1528 DWORD dwError
= ERROR_SUCCESS
;
1530 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1532 /* If the image is already running ... */
1533 if (Service
->lpImage
->dwImageRunCount
> 1)
1535 /* ... just send a start command */
1536 return ScmSendStartCommand(Service
, argc
, argv
);
1539 StartupInfo
.cb
= sizeof(StartupInfo
);
1540 StartupInfo
.lpReserved
= NULL
;
1541 StartupInfo
.lpDesktop
= NULL
;
1542 StartupInfo
.lpTitle
= NULL
;
1543 StartupInfo
.dwFlags
= 0;
1544 StartupInfo
.cbReserved2
= 0;
1545 StartupInfo
.lpReserved2
= 0;
1547 Result
= CreateProcessW(NULL
,
1548 Service
->lpImage
->szImagePath
,
1552 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1556 &ProcessInformation
);
1559 dwError
= GetLastError();
1560 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1564 DPRINT("Process Id: %lu Handle %lx\n",
1565 ProcessInformation
.dwProcessId
,
1566 ProcessInformation
.hProcess
);
1567 DPRINT("Thread Id: %lu Handle %lx\n",
1568 ProcessInformation
.dwThreadId
,
1569 ProcessInformation
.hThread
);
1571 /* Get process handle and id */
1572 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1573 Service
->lpImage
->hProcess
= ProcessInformation
.hProcess
;
1576 ResumeThread(ProcessInformation
.hThread
);
1578 /* Connect control pipe */
1579 dwError
= ScmWaitForServiceConnect(Service
);
1580 if (dwError
== ERROR_SUCCESS
)
1582 /* Send start command */
1583 dwError
= ScmSendStartCommand(Service
,
1589 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1590 Service
->lpImage
->dwProcessId
= 0;
1591 Service
->lpImage
->hProcess
= NULL
;
1592 CloseHandle(ProcessInformation
.hProcess
);
1595 /* Close thread handle */
1596 CloseHandle(ProcessInformation
.hThread
);
1603 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1605 PSERVICE_GROUP Group
= Service
->lpGroup
;
1606 DWORD dwError
= ERROR_SUCCESS
;
1607 LPCWSTR ErrorLogStrings
[2];
1609 DPRINT("ScmStartService() called\n");
1611 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1613 EnterCriticalSection(&ControlServiceCriticalSection
);
1615 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1617 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1618 LeaveCriticalSection(&ControlServiceCriticalSection
);
1619 return ERROR_SERVICE_ALREADY_RUNNING
;
1622 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1624 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1627 dwError
= ScmLoadDriver(Service
);
1628 if (dwError
== ERROR_SUCCESS
)
1630 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1631 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1636 /* Start user-mode service */
1637 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1638 if (dwError
== ERROR_SUCCESS
)
1640 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1641 if (dwError
== ERROR_SUCCESS
)
1643 #ifdef USE_SERVICE_START_PENDING
1644 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1646 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1651 ScmDereferenceServiceImage(Service
->lpImage
);
1652 Service
->lpImage
= NULL
;
1657 LeaveCriticalSection(&ControlServiceCriticalSection
);
1659 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1661 if (dwError
== ERROR_SUCCESS
)
1665 Group
->ServicesRunning
= TRUE
;
1670 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1672 ErrorLogStrings
[0] = Service
->lpServiceName
;
1673 ErrorLogStrings
[1] = L
"Test";
1674 ScmLogError(EVENT_SERVICE_START_FAILED
,
1680 switch (Service
->dwErrorControl
)
1682 case SERVICE_ERROR_SEVERE
:
1683 if (IsLastKnownGood
== FALSE
)
1685 /* FIXME: Boot last known good configuration */
1689 case SERVICE_ERROR_CRITICAL
:
1690 if (IsLastKnownGood
== FALSE
)
1692 /* FIXME: Boot last known good configuration */
1708 ScmAutoStartServices(VOID
)
1710 PLIST_ENTRY GroupEntry
;
1711 PLIST_ENTRY ServiceEntry
;
1712 PSERVICE_GROUP CurrentGroup
;
1713 PSERVICE CurrentService
;
1714 WCHAR szSafeBootServicePath
[MAX_PATH
];
1719 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1720 ServiceEntry
= ServiceListHead
.Flink
;
1721 while (ServiceEntry
!= &ServiceListHead
)
1723 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1725 /* Build the safe boot path */
1726 wcscpy(szSafeBootServicePath
,
1727 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1729 switch (GetSystemMetrics(SM_CLEANBOOT
))
1731 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1734 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1738 wcscat(szSafeBootServicePath
, L
"\\Network\\");
1742 if (GetSystemMetrics(SM_CLEANBOOT
))
1744 /* If key does not exist then do not assume safe mode */
1745 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1746 szSafeBootServicePath
,
1750 if (dwError
== ERROR_SUCCESS
)
1754 /* Finish Safe Boot path off */
1755 wcsncat(szSafeBootServicePath
,
1756 CurrentService
->lpServiceName
,
1757 MAX_PATH
- wcslen(szSafeBootServicePath
));
1759 /* Check that the key is in the Safe Boot path */
1760 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1761 szSafeBootServicePath
,
1765 if (dwError
!= ERROR_SUCCESS
)
1767 /* Mark service as visited so it is not auto-started */
1768 CurrentService
->ServiceVisited
= TRUE
;
1772 /* Must be auto-started in safe mode - mark as unvisited */
1774 CurrentService
->ServiceVisited
= FALSE
;
1779 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1780 CurrentService
->ServiceVisited
= FALSE
;
1784 ServiceEntry
= ServiceEntry
->Flink
;
1787 /* Start all services which are members of an existing group */
1788 GroupEntry
= GroupListHead
.Flink
;
1789 while (GroupEntry
!= &GroupListHead
)
1791 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1793 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1795 /* Start all services witch have a valid tag */
1796 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1798 ServiceEntry
= ServiceListHead
.Flink
;
1799 while (ServiceEntry
!= &ServiceListHead
)
1801 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1803 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1804 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1805 (CurrentService
->ServiceVisited
== FALSE
) &&
1806 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1808 CurrentService
->ServiceVisited
= TRUE
;
1809 ScmStartService(CurrentService
, 0, NULL
);
1812 ServiceEntry
= ServiceEntry
->Flink
;
1816 /* Start all services which have an invalid tag or which do not have a tag */
1817 ServiceEntry
= ServiceListHead
.Flink
;
1818 while (ServiceEntry
!= &ServiceListHead
)
1820 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1822 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1823 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1824 (CurrentService
->ServiceVisited
== FALSE
))
1826 CurrentService
->ServiceVisited
= TRUE
;
1827 ScmStartService(CurrentService
, 0, NULL
);
1830 ServiceEntry
= ServiceEntry
->Flink
;
1833 GroupEntry
= GroupEntry
->Flink
;
1836 /* Start all services which are members of any non-existing group */
1837 ServiceEntry
= ServiceListHead
.Flink
;
1838 while (ServiceEntry
!= &ServiceListHead
)
1840 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1842 if ((CurrentService
->lpGroup
!= NULL
) &&
1843 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1844 (CurrentService
->ServiceVisited
== FALSE
))
1846 CurrentService
->ServiceVisited
= TRUE
;
1847 ScmStartService(CurrentService
, 0, NULL
);
1850 ServiceEntry
= ServiceEntry
->Flink
;
1853 /* Start all services which are not a member of any group */
1854 ServiceEntry
= ServiceListHead
.Flink
;
1855 while (ServiceEntry
!= &ServiceListHead
)
1857 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1859 if ((CurrentService
->lpGroup
== NULL
) &&
1860 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1861 (CurrentService
->ServiceVisited
== FALSE
))
1863 CurrentService
->ServiceVisited
= TRUE
;
1864 ScmStartService(CurrentService
, 0, NULL
);
1867 ServiceEntry
= ServiceEntry
->Flink
;
1870 /* Clear 'ServiceVisited' flag again */
1871 ServiceEntry
= ServiceListHead
.Flink
;
1872 while (ServiceEntry
!= &ServiceListHead
)
1874 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1875 CurrentService
->ServiceVisited
= FALSE
;
1876 ServiceEntry
= ServiceEntry
->Flink
;
1882 ScmAutoShutdownServices(VOID
)
1884 PLIST_ENTRY ServiceEntry
;
1885 PSERVICE CurrentService
;
1887 DPRINT("ScmAutoShutdownServices() called\n");
1889 /* Lock the service database exclusively */
1890 ScmLockDatabaseExclusive();
1892 ServiceEntry
= ServiceListHead
.Flink
;
1893 while (ServiceEntry
!= &ServiceListHead
)
1895 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1897 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1898 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1900 /* shutdown service */
1901 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1902 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1905 ServiceEntry
= ServiceEntry
->Flink
;
1908 /* Unlock the service database */
1909 ScmUnlockDatabase();
1911 DPRINT("ScmAutoShutdownServices() done\n");
1916 ScmLockDatabaseExclusive(VOID
)
1918 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1923 ScmLockDatabaseShared(VOID
)
1925 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1930 ScmUnlockDatabase(VOID
)
1932 RtlReleaseResource(&DatabaseLock
);
1937 ScmInitNamedPipeCriticalSection(VOID
)
1943 InitializeCriticalSection(&ControlServiceCriticalSection
);
1945 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1946 L
"SYSTEM\\CurrentControlSet\\Control",
1950 if (dwError
== ERROR_SUCCESS
)
1952 dwKeySize
= sizeof(DWORD
);
1953 RegQueryValueExW(hKey
,
1954 L
"ServicesPipeTimeout",
1957 (LPBYTE
)&dwPipeTimeout
,
1966 ScmDeleteNamedPipeCriticalSection(VOID
)
1968 DeleteCriticalSection(&ControlServiceCriticalSection
);