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 ResumeCount
= 1;
41 static CRITICAL_SECTION ControlServiceCriticalSection
;
42 static DWORD PipeTimeout
= 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 DPRINT("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
= HeapAlloc(GetProcessHeap(),
196 FIELD_OFFSET(SERVICE_IMAGE
, szImagePath
[ImagePath
.Length
/ sizeof(WCHAR
) + 1]));
197 if (pServiceImage
== NULL
)
199 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
203 pServiceImage
->dwImageRunCount
= 1;
204 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
206 /* Set the image path */
207 wcscpy(pServiceImage
->szImagePath
,
210 RtlFreeUnicodeString(&ImagePath
);
212 /* Create the control pipe */
213 dwError
= ScmCreateNewControlPipe(pServiceImage
);
214 if (dwError
!= ERROR_SUCCESS
)
216 HeapFree(GetProcessHeap(), 0, pServiceImage
);
220 /* FIXME: Add more initialization code here */
223 /* Append service record */
224 InsertTailList(&ImageListHead
,
225 &pServiceImage
->ImageListEntry
);
229 /* Increment the run counter */
230 pServiceImage
->dwImageRunCount
++;
233 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
235 /* Link the service image to the service */
236 pService
->lpImage
= pServiceImage
;
239 RtlFreeUnicodeString(&ImagePath
);
241 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
248 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
250 DPRINT1("ScmDereferenceServiceImage() called\n");
252 pServiceImage
->dwImageRunCount
--;
254 if (pServiceImage
->dwImageRunCount
== 0)
256 DPRINT1("dwImageRunCount == 0\n");
258 /* FIXME: Terminate the process */
260 /* Remove the service image from the list */
261 RemoveEntryList(&pServiceImage
->ImageListEntry
);
263 /* Close the control pipe */
264 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
265 CloseHandle(pServiceImage
->hControlPipe
);
267 /* Release the service image */
268 HeapFree(GetProcessHeap(), 0, pServiceImage
);
274 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
276 PLIST_ENTRY ServiceEntry
;
277 PSERVICE CurrentService
;
279 DPRINT("ScmGetServiceEntryByName() called\n");
281 ServiceEntry
= ServiceListHead
.Flink
;
282 while (ServiceEntry
!= &ServiceListHead
)
284 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
287 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
289 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
290 return CurrentService
;
293 ServiceEntry
= ServiceEntry
->Flink
;
296 DPRINT("Couldn't find a matching service\n");
303 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
305 PLIST_ENTRY ServiceEntry
;
306 PSERVICE CurrentService
;
308 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
310 ServiceEntry
= ServiceListHead
.Flink
;
311 while (ServiceEntry
!= &ServiceListHead
)
313 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
316 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
318 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
319 return CurrentService
;
322 ServiceEntry
= ServiceEntry
->Flink
;
325 DPRINT("Couldn't find a matching service\n");
332 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
334 PLIST_ENTRY ServiceEntry
;
335 PSERVICE CurrentService
;
337 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
339 ServiceEntry
= ServiceListHead
.Flink
;
340 while (ServiceEntry
!= &ServiceListHead
)
342 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
345 if (CurrentService
->dwResumeCount
> dwResumeCount
)
347 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
348 return CurrentService
;
351 ServiceEntry
= ServiceEntry
->Flink
;
354 DPRINT("Couldn't find a matching service\n");
361 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
362 PSERVICE
*lpServiceRecord
)
364 PSERVICE lpService
= NULL
;
366 DPRINT("Service: '%S'\n", lpServiceName
);
368 /* Allocate service entry */
369 lpService
= HeapAlloc(GetProcessHeap(),
371 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
372 if (lpService
== NULL
)
373 return ERROR_NOT_ENOUGH_MEMORY
;
375 *lpServiceRecord
= lpService
;
377 /* Copy service name */
378 wcscpy(lpService
->szServiceName
, lpServiceName
);
379 lpService
->lpServiceName
= lpService
->szServiceName
;
380 lpService
->lpDisplayName
= lpService
->lpServiceName
;
382 /* Set the resume count */
383 lpService
->dwResumeCount
= ResumeCount
++;
385 /* Append service record */
386 InsertTailList(&ServiceListHead
,
387 &lpService
->ServiceListEntry
);
389 /* Initialize the service status */
390 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
391 lpService
->Status
.dwControlsAccepted
= 0;
392 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
393 lpService
->Status
.dwServiceSpecificExitCode
= 0;
394 lpService
->Status
.dwCheckPoint
= 0;
395 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
397 return ERROR_SUCCESS
;
402 ScmDeleteServiceRecord(PSERVICE lpService
)
404 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
406 /* Delete the display name */
407 if (lpService
->lpDisplayName
!= NULL
&&
408 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
409 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
411 /* Dereference the service image */
412 if (lpService
->lpImage
)
413 ScmDereferenceServiceImage(lpService
->lpImage
);
415 /* Decrement the group reference counter */
416 if (lpService
->lpGroup
)
417 lpService
->lpGroup
->dwRefCount
--;
419 /* FIXME: SecurityDescriptor */
422 /* Remove the Service from the List */
423 RemoveEntryList(&lpService
->ServiceListEntry
);
425 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
427 /* Delete the service record */
428 HeapFree(GetProcessHeap(), 0, lpService
);
435 CreateServiceListEntry(LPCWSTR lpServiceName
,
438 PSERVICE lpService
= NULL
;
439 LPWSTR lpDisplayName
= NULL
;
440 LPWSTR lpGroup
= NULL
;
445 DWORD dwErrorControl
;
448 DPRINT("Service: '%S'\n", lpServiceName
);
449 if (*lpServiceName
== L
'{')
450 return ERROR_SUCCESS
;
452 dwSize
= sizeof(DWORD
);
453 dwError
= RegQueryValueExW(hServiceKey
,
457 (LPBYTE
)&dwServiceType
,
459 if (dwError
!= ERROR_SUCCESS
)
460 return ERROR_SUCCESS
;
462 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
463 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
464 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
465 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
466 return ERROR_SUCCESS
;
468 DPRINT("Service type: %lx\n", dwServiceType
);
470 dwSize
= sizeof(DWORD
);
471 dwError
= RegQueryValueExW(hServiceKey
,
475 (LPBYTE
)&dwStartType
,
477 if (dwError
!= ERROR_SUCCESS
)
478 return ERROR_SUCCESS
;
480 DPRINT("Start type: %lx\n", dwStartType
);
482 dwSize
= sizeof(DWORD
);
483 dwError
= RegQueryValueExW(hServiceKey
,
487 (LPBYTE
)&dwErrorControl
,
489 if (dwError
!= ERROR_SUCCESS
)
490 return ERROR_SUCCESS
;
492 DPRINT("Error control: %lx\n", dwErrorControl
);
494 dwError
= RegQueryValueExW(hServiceKey
,
500 if (dwError
!= ERROR_SUCCESS
)
503 DPRINT("Tag: %lx\n", dwTagId
);
505 dwError
= ScmReadString(hServiceKey
,
508 if (dwError
!= ERROR_SUCCESS
)
511 DPRINT("Group: %S\n", lpGroup
);
513 dwError
= ScmReadString(hServiceKey
,
516 if (dwError
!= ERROR_SUCCESS
)
517 lpDisplayName
= NULL
;
519 DPRINT("Display name: %S\n", lpDisplayName
);
521 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
523 if (dwError
!= ERROR_SUCCESS
)
526 lpService
->Status
.dwServiceType
= dwServiceType
;
527 lpService
->dwStartType
= dwStartType
;
528 lpService
->dwErrorControl
= dwErrorControl
;
529 lpService
->dwTag
= dwTagId
;
533 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
534 if (dwError
!= ERROR_SUCCESS
)
538 if (lpDisplayName
!= NULL
)
540 lpService
->lpDisplayName
= lpDisplayName
;
541 lpDisplayName
= NULL
;
544 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
545 if (lpService
->lpGroup
!= NULL
)
547 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
549 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
550 lpService
->dwStartType
,
551 lpService
->Status
.dwServiceType
,
553 lpService
->dwErrorControl
);
555 if (ScmIsDeleteFlagSet(hServiceKey
))
556 lpService
->bDeleted
= TRUE
;
560 HeapFree(GetProcessHeap(), 0, lpGroup
);
562 if (lpDisplayName
!= NULL
)
563 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
565 if (lpService
!= NULL
)
567 if (lpService
->lpImage
!= NULL
)
568 ScmDereferenceServiceImage(lpService
->lpImage
);
576 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
578 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
579 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
582 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
585 /* Find the maximum subkey length so that we can allocate a buffer */
586 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
587 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
591 if (dwMaxSubkeyLen
> sizeof(szNameBuf
) / sizeof(WCHAR
))
593 /* Name too big: alloc a buffer for it */
594 lpszName
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMaxSubkeyLen
* sizeof(WCHAR
));
598 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
601 while (dwRet
== ERROR_SUCCESS
)
603 dwSize
= dwMaxSubkeyLen
;
604 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
605 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
606 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
608 if (dwRet
== ERROR_NO_MORE_ITEMS
)
609 dwRet
= ERROR_SUCCESS
;
611 if (lpszName
!= szNameBuf
)
612 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
616 RegCloseKey(hSubKey
);
618 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
625 ScmDeleteMarkedServices(VOID
)
627 PLIST_ENTRY ServiceEntry
;
628 PSERVICE CurrentService
;
632 ServiceEntry
= ServiceListHead
.Flink
;
633 while (ServiceEntry
!= &ServiceListHead
)
635 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
637 ServiceEntry
= ServiceEntry
->Flink
;
639 if (CurrentService
->bDeleted
== TRUE
)
641 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
642 L
"System\\CurrentControlSet\\Services",
646 if (dwError
== ERROR_SUCCESS
)
648 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
649 RegCloseKey(hServicesKey
);
650 if (dwError
== ERROR_SUCCESS
)
652 RemoveEntryList(&CurrentService
->ServiceListEntry
);
653 HeapFree(GetProcessHeap(), 0, CurrentService
);
657 if (dwError
!= ERROR_SUCCESS
)
658 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
665 ScmCreateServiceDatabase(VOID
)
667 WCHAR szSubKey
[MAX_PATH
];
671 DWORD dwSubKeyLength
;
672 FILETIME ftLastChanged
;
675 DPRINT("ScmCreateServiceDatabase() called\n");
677 dwError
= ScmCreateGroupList();
678 if (dwError
!= ERROR_SUCCESS
)
681 /* Initialize basic variables */
682 InitializeListHead(&ImageListHead
);
683 InitializeListHead(&ServiceListHead
);
685 /* Initialize the database lock */
686 RtlInitializeResource(&DatabaseLock
);
688 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
689 L
"System\\CurrentControlSet\\Services",
693 if (dwError
!= ERROR_SUCCESS
)
699 dwSubKeyLength
= MAX_PATH
;
700 dwError
= RegEnumKeyExW(hServicesKey
,
708 if (dwError
== ERROR_SUCCESS
&&
711 DPRINT("SubKeyName: '%S'\n", szSubKey
);
713 dwError
= RegOpenKeyExW(hServicesKey
,
718 if (dwError
== ERROR_SUCCESS
)
720 dwError
= CreateServiceListEntry(szSubKey
,
723 RegCloseKey(hServiceKey
);
727 if (dwError
!= ERROR_SUCCESS
)
733 RegCloseKey(hServicesKey
);
735 /* Wait for the LSA server */
738 /* Delete services that are marked for delete */
739 ScmDeleteMarkedServices();
741 DPRINT("ScmCreateServiceDatabase() done\n");
743 return ERROR_SUCCESS
;
748 ScmShutdownServiceDatabase(VOID
)
750 DPRINT("ScmShutdownServiceDatabase() called\n");
752 ScmDeleteMarkedServices();
753 RtlDeleteResource(&DatabaseLock
);
755 DPRINT("ScmShutdownServiceDatabase() done\n");
760 ScmCheckDriver(PSERVICE Service
)
762 OBJECT_ATTRIBUTES ObjectAttributes
;
763 UNICODE_STRING DirName
;
766 POBJECT_DIRECTORY_INFORMATION DirInfo
;
771 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
773 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
775 RtlInitUnicodeString(&DirName
,
780 RtlInitUnicodeString(&DirName
,
784 InitializeObjectAttributes(&ObjectAttributes
,
790 Status
= NtOpenDirectoryObject(&DirHandle
,
791 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
793 if (!NT_SUCCESS(Status
))
798 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
799 2 * MAX_PATH
* sizeof(WCHAR
);
800 DirInfo
= HeapAlloc(GetProcessHeap(),
807 Status
= NtQueryDirectoryObject(DirHandle
,
814 if (Status
== STATUS_NO_MORE_ENTRIES
)
816 /* FIXME: Add current service to 'failed service' list */
817 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
821 if (!NT_SUCCESS(Status
))
824 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
826 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
828 DPRINT("Found: '%S' '%wZ'\n",
829 Service
->lpServiceName
, &DirInfo
->Name
);
831 /* Mark service as 'running' */
832 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
834 /* Mark the service group as 'running' */
835 if (Service
->lpGroup
!= NULL
)
837 Service
->lpGroup
->ServicesRunning
= TRUE
;
844 HeapFree(GetProcessHeap(),
849 return STATUS_SUCCESS
;
854 ScmGetBootAndSystemDriverState(VOID
)
856 PLIST_ENTRY ServiceEntry
;
857 PSERVICE CurrentService
;
859 DPRINT("ScmGetBootAndSystemDriverState() called\n");
861 ServiceEntry
= ServiceListHead
.Flink
;
862 while (ServiceEntry
!= &ServiceListHead
)
864 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
866 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
867 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
870 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
872 ScmCheckDriver(CurrentService
);
875 ServiceEntry
= ServiceEntry
->Flink
;
878 DPRINT("ScmGetBootAndSystemDriverState() done\n");
883 ScmControlService(PSERVICE Service
,
886 PSCM_CONTROL_PACKET ControlPacket
;
887 SCM_REPLY_PACKET ReplyPacket
;
889 DWORD dwWriteCount
= 0;
890 DWORD dwReadCount
= 0;
893 DWORD dwError
= ERROR_SUCCESS
;
895 #ifdef USE_ASYNCHRONOUS_IO
896 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
899 DPRINT("ScmControlService() called\n");
901 EnterCriticalSection(&ControlServiceCriticalSection
);
903 /* Calculate the total length of the start command line */
904 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
905 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
907 ControlPacket
= HeapAlloc(GetProcessHeap(),
910 if (ControlPacket
== NULL
)
912 LeaveCriticalSection(&ControlServiceCriticalSection
);
913 return ERROR_NOT_ENOUGH_MEMORY
;
916 ControlPacket
->dwSize
= PacketSize
;
917 ControlPacket
->dwControl
= dwControl
;
918 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
920 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
922 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
923 wcscpy(Ptr
, Service
->lpServiceName
);
925 ControlPacket
->dwArgumentsCount
= 0;
926 ControlPacket
->dwArgumentsOffset
= 0;
928 #ifdef USE_ASYNCHRONOUS_IO
929 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
934 if (bResult
== FALSE
)
936 DPRINT1("WriteFile() returned FALSE\n");
938 dwError
= GetLastError();
939 if (dwError
== ERROR_IO_PENDING
)
941 DPRINT1("dwError: ERROR_IO_PENDING\n");
943 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
945 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
947 if (dwError
== WAIT_TIMEOUT
)
949 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
950 if (bResult
== FALSE
)
952 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
955 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
958 else if (dwError
== ERROR_SUCCESS
)
960 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
964 if (bResult
== FALSE
)
966 dwError
= GetLastError();
967 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
975 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
981 Overlapped
.hEvent
= (HANDLE
) NULL
;
983 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
985 sizeof(SCM_REPLY_PACKET
),
988 if (bResult
== FALSE
)
990 DPRINT1("ReadFile() returned FALSE\n");
992 dwError
= GetLastError();
993 if (dwError
== ERROR_IO_PENDING
)
995 DPRINT1("dwError: ERROR_IO_PENDING\n");
997 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
999 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1001 if (dwError
== WAIT_TIMEOUT
)
1003 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1004 if (bResult
== FALSE
)
1006 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1009 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1012 else if (dwError
== ERROR_SUCCESS
)
1014 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1018 if (bResult
== FALSE
)
1020 dwError
= GetLastError();
1021 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1029 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1035 /* Send the control packet */
1036 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1041 if (bResult
== FALSE
)
1043 dwError
= GetLastError();
1044 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1046 if ((dwError
== ERROR_GEN_FAILURE
) &&
1047 (dwControl
== SERVICE_CONTROL_STOP
))
1049 /* Service is already terminated */
1050 Service
->Status
.dwCurrentState
= SERVICE_STOPPED
;
1051 Service
->Status
.dwControlsAccepted
= 0;
1052 Service
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NOT_ACTIVE
;
1053 dwError
= ERROR_SUCCESS
;
1058 /* Read the reply */
1059 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1061 sizeof(SCM_REPLY_PACKET
),
1064 if (bResult
== FALSE
)
1066 dwError
= GetLastError();
1067 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1072 /* Release the contol packet */
1073 HeapFree(GetProcessHeap(),
1077 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1079 dwError
= ReplyPacket
.dwError
;
1082 if (dwError
== ERROR_SUCCESS
&&
1083 dwControl
== SERVICE_CONTROL_STOP
)
1085 ScmDereferenceServiceImage(Service
->lpImage
);
1088 LeaveCriticalSection(&ControlServiceCriticalSection
);
1090 DPRINT("ScmControlService() done\n");
1097 ScmSendStartCommand(PSERVICE Service
,
1101 PSCM_CONTROL_PACKET ControlPacket
;
1102 SCM_REPLY_PACKET ReplyPacket
;
1105 DWORD dwWriteCount
= 0;
1106 DWORD dwReadCount
= 0;
1107 DWORD dwError
= ERROR_SUCCESS
;
1112 #ifdef USE_ASYNCHRONOUS_IO
1113 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1116 DPRINT("ScmSendStartCommand() called\n");
1118 /* Calculate the total length of the start command line */
1119 PacketSize
= sizeof(SCM_CONTROL_PACKET
) +
1120 (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1122 /* Calculate the required packet size for the start arguments */
1123 if (argc
> 0 && argv
!= NULL
)
1125 PacketSize
= ALIGN_UP(PacketSize
, LPWSTR
);
1127 DPRINT("Argc: %lu\n", argc
);
1128 for (i
= 0; i
< argc
; i
++)
1130 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1131 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
) + sizeof(PWSTR
));
1135 /* Allocate a control packet */
1136 ControlPacket
= HeapAlloc(GetProcessHeap(),
1139 if (ControlPacket
== NULL
)
1140 return ERROR_NOT_ENOUGH_MEMORY
;
1142 ControlPacket
->dwSize
= PacketSize
;
1143 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1144 ? SERVICE_CONTROL_START_OWN
1145 : SERVICE_CONTROL_START_SHARE
;
1146 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1147 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1149 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1150 wcscpy(Ptr
, Service
->lpServiceName
);
1152 ControlPacket
->dwArgumentsCount
= 0;
1153 ControlPacket
->dwArgumentsOffset
= 0;
1155 /* Copy argument list */
1156 if (argc
> 0 && argv
!= NULL
)
1158 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1159 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1160 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1162 ControlPacket
->dwArgumentsCount
= argc
;
1163 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1165 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1166 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1168 for (i
= 0; i
< argc
; i
++)
1170 wcscpy(pArgPtr
, argv
[i
]);
1171 *pOffPtr
= (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1172 DPRINT("offset: %p\n", *pOffPtr
);
1174 pArgPtr
+= wcslen(argv
[i
]) + 1;
1179 #ifdef USE_ASYNCHRONOUS_IO
1180 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1185 if (bResult
== FALSE
)
1187 DPRINT1("WriteFile() returned FALSE\n");
1189 dwError
= GetLastError();
1190 if (dwError
== ERROR_IO_PENDING
)
1192 DPRINT1("dwError: ERROR_IO_PENDING\n");
1194 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1196 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1198 if (dwError
== WAIT_TIMEOUT
)
1200 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1201 if (bResult
== FALSE
)
1203 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1206 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1209 else if (dwError
== ERROR_SUCCESS
)
1211 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1215 if (bResult
== FALSE
)
1217 dwError
= GetLastError();
1218 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1226 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1231 /* Read the reply */
1232 Overlapped
.hEvent
= (HANDLE
) NULL
;
1234 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1236 sizeof(SCM_REPLY_PACKET
),
1239 if (bResult
== FALSE
)
1241 DPRINT1("ReadFile() returned FALSE\n");
1243 dwError
= GetLastError();
1244 if (dwError
== ERROR_IO_PENDING
)
1246 DPRINT1("dwError: ERROR_IO_PENDING\n");
1248 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1250 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1252 if (dwError
== WAIT_TIMEOUT
)
1254 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1255 if (bResult
== FALSE
)
1257 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1260 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1263 else if (dwError
== ERROR_SUCCESS
)
1265 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1269 if (bResult
== FALSE
)
1271 dwError
= GetLastError();
1272 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1280 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1286 /* Send the start command */
1287 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1292 if (bResult
== FALSE
)
1294 dwError
= GetLastError();
1295 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1299 /* Read the reply */
1300 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1302 sizeof(SCM_REPLY_PACKET
),
1305 if (bResult
== FALSE
)
1307 dwError
= GetLastError();
1308 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1313 /* Release the contol packet */
1314 HeapFree(GetProcessHeap(),
1318 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1320 dwError
= ReplyPacket
.dwError
;
1323 DPRINT("ScmSendStartCommand() done\n");
1330 ScmWaitForServiceConnect(PSERVICE Service
)
1333 DWORD dwProcessId
= 0;
1334 DWORD dwError
= ERROR_SUCCESS
;
1336 #ifdef USE_ASYNCHRONOUS_IO
1337 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1340 DPRINT("ScmWaitForServiceConnect()\n");
1342 #ifdef USE_ASYNCHRONOUS_IO
1343 Overlapped
.hEvent
= (HANDLE
)NULL
;
1345 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1347 if (bResult
== FALSE
)
1349 DPRINT("ConnectNamedPipe() returned FALSE\n");
1351 dwError
= GetLastError();
1352 if (dwError
== ERROR_IO_PENDING
)
1354 DPRINT("dwError: ERROR_IO_PENDING\n");
1356 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1358 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1360 if (dwError
== WAIT_TIMEOUT
)
1362 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1364 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1365 if (bResult
== FALSE
)
1367 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1370 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1372 else if (dwError
== WAIT_OBJECT_0
)
1374 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1378 if (bResult
== FALSE
)
1380 dwError
= GetLastError();
1381 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1387 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1389 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1394 DPRINT("Control pipe connected!\n");
1396 Overlapped
.hEvent
= (HANDLE
) NULL
;
1398 /* Read the process id from pipe */
1399 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1400 (LPVOID
)&dwProcessId
,
1404 if (bResult
== FALSE
)
1406 DPRINT("ReadFile() returned FALSE\n");
1408 dwError
= GetLastError();
1409 if (dwError
== ERROR_IO_PENDING
)
1411 DPRINT("dwError: ERROR_IO_PENDING\n");
1413 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1415 if (dwError
== WAIT_TIMEOUT
)
1417 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1419 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1420 if (bResult
== FALSE
)
1422 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1425 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1427 else if (dwError
== ERROR_SUCCESS
)
1429 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
1431 DPRINT("Process Id: %lu\n", dwProcessId
);
1433 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1437 if (bResult
== FALSE
)
1439 dwError
= GetLastError();
1440 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1447 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1452 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1457 DPRINT1("ScmWaitForServiceConnect() done\n");
1459 return ERROR_SUCCESS
;
1462 /* Connect control pipe */
1463 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1464 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1466 DPRINT("Control pipe connected!\n");
1468 /* Read SERVICE_STATUS_HANDLE from pipe */
1469 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1470 (LPVOID
)&dwProcessId
,
1474 if (bResult
== FALSE
)
1476 dwError
= GetLastError();
1477 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1482 dwError
= ERROR_SUCCESS
;
1483 DPRINT("Read control pipe successfully\n");
1488 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1497 ScmStartUserModeService(PSERVICE Service
,
1501 PROCESS_INFORMATION ProcessInformation
;
1502 STARTUPINFOW StartupInfo
;
1504 DWORD dwError
= ERROR_SUCCESS
;
1506 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1508 /* If the image is already running ... */
1509 if (Service
->lpImage
->dwImageRunCount
> 1)
1511 /* ... just send a start command */
1512 return ScmSendStartCommand(Service
, argc
, argv
);
1515 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1516 StartupInfo
.cb
= sizeof(StartupInfo
);
1517 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1519 Result
= CreateProcessW(NULL
,
1520 Service
->lpImage
->szImagePath
,
1524 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1528 &ProcessInformation
);
1531 dwError
= GetLastError();
1532 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1536 DPRINT("Process Id: %lu Handle %p\n",
1537 ProcessInformation
.dwProcessId
,
1538 ProcessInformation
.hProcess
);
1539 DPRINT("Thread Id: %lu Handle %p\n",
1540 ProcessInformation
.dwThreadId
,
1541 ProcessInformation
.hThread
);
1543 /* Get process handle and id */
1544 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1547 ResumeThread(ProcessInformation
.hThread
);
1549 /* Connect control pipe */
1550 dwError
= ScmWaitForServiceConnect(Service
);
1551 if (dwError
== ERROR_SUCCESS
)
1553 /* Send start command */
1554 dwError
= ScmSendStartCommand(Service
,
1560 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1561 Service
->lpImage
->dwProcessId
= 0;
1564 /* Close thread and process handle */
1565 CloseHandle(ProcessInformation
.hThread
);
1566 CloseHandle(ProcessInformation
.hProcess
);
1573 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1575 PSERVICE_GROUP Group
= Service
->lpGroup
;
1576 DWORD dwError
= ERROR_SUCCESS
;
1577 LPCWSTR ErrorLogStrings
[2];
1578 WCHAR szErrorBuffer
[32];
1580 DPRINT("ScmStartService() called\n");
1582 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1584 EnterCriticalSection(&ControlServiceCriticalSection
);
1586 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1588 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1589 LeaveCriticalSection(&ControlServiceCriticalSection
);
1590 return ERROR_SERVICE_ALREADY_RUNNING
;
1593 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1595 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1598 dwError
= ScmLoadDriver(Service
);
1599 if (dwError
== ERROR_SUCCESS
)
1601 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1602 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1607 /* Start user-mode service */
1608 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1609 if (dwError
== ERROR_SUCCESS
)
1611 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1612 if (dwError
== ERROR_SUCCESS
)
1614 #ifdef USE_SERVICE_START_PENDING
1615 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1617 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1622 ScmDereferenceServiceImage(Service
->lpImage
);
1623 Service
->lpImage
= NULL
;
1628 LeaveCriticalSection(&ControlServiceCriticalSection
);
1630 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1632 if (dwError
== ERROR_SUCCESS
)
1636 Group
->ServicesRunning
= TRUE
;
1641 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1643 /* Log a failed service start */
1644 swprintf(szErrorBuffer
, L
"%lu", dwError
);
1645 ErrorLogStrings
[0] = Service
->lpServiceName
;
1646 ErrorLogStrings
[1] = szErrorBuffer
;
1647 ScmLogError(EVENT_SERVICE_START_FAILED
,
1653 switch (Service
->dwErrorControl
)
1655 case SERVICE_ERROR_SEVERE
:
1656 if (IsLastKnownGood
== FALSE
)
1658 /* FIXME: Boot last known good configuration */
1662 case SERVICE_ERROR_CRITICAL
:
1663 if (IsLastKnownGood
== FALSE
)
1665 /* FIXME: Boot last known good configuration */
1681 ScmAutoStartServices(VOID
)
1683 PLIST_ENTRY GroupEntry
;
1684 PLIST_ENTRY ServiceEntry
;
1685 PSERVICE_GROUP CurrentGroup
;
1686 PSERVICE CurrentService
;
1687 WCHAR szSafeBootServicePath
[MAX_PATH
];
1692 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1693 ServiceEntry
= ServiceListHead
.Flink
;
1694 while (ServiceEntry
!= &ServiceListHead
)
1696 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1698 /* Build the safe boot path */
1699 wcscpy(szSafeBootServicePath
,
1700 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1702 switch (GetSystemMetrics(SM_CLEANBOOT
))
1704 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1707 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1711 wcscat(szSafeBootServicePath
, L
"\\Network\\");
1715 if (GetSystemMetrics(SM_CLEANBOOT
))
1717 /* If key does not exist then do not assume safe mode */
1718 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1719 szSafeBootServicePath
,
1723 if (dwError
== ERROR_SUCCESS
)
1727 /* Finish Safe Boot path off */
1728 wcsncat(szSafeBootServicePath
,
1729 CurrentService
->lpServiceName
,
1730 MAX_PATH
- wcslen(szSafeBootServicePath
));
1732 /* Check that the key is in the Safe Boot path */
1733 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1734 szSafeBootServicePath
,
1738 if (dwError
!= ERROR_SUCCESS
)
1740 /* Mark service as visited so it is not auto-started */
1741 CurrentService
->ServiceVisited
= TRUE
;
1745 /* Must be auto-started in safe mode - mark as unvisited */
1747 CurrentService
->ServiceVisited
= FALSE
;
1752 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1753 CurrentService
->ServiceVisited
= FALSE
;
1757 ServiceEntry
= ServiceEntry
->Flink
;
1760 /* Start all services which are members of an existing group */
1761 GroupEntry
= GroupListHead
.Flink
;
1762 while (GroupEntry
!= &GroupListHead
)
1764 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1766 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1768 /* Start all services witch have a valid tag */
1769 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1771 ServiceEntry
= ServiceListHead
.Flink
;
1772 while (ServiceEntry
!= &ServiceListHead
)
1774 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1776 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1777 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1778 (CurrentService
->ServiceVisited
== FALSE
) &&
1779 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1781 CurrentService
->ServiceVisited
= TRUE
;
1782 ScmStartService(CurrentService
, 0, NULL
);
1785 ServiceEntry
= ServiceEntry
->Flink
;
1789 /* Start all services which have an invalid tag or which do not have a tag */
1790 ServiceEntry
= ServiceListHead
.Flink
;
1791 while (ServiceEntry
!= &ServiceListHead
)
1793 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1795 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1796 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1797 (CurrentService
->ServiceVisited
== FALSE
))
1799 CurrentService
->ServiceVisited
= TRUE
;
1800 ScmStartService(CurrentService
, 0, NULL
);
1803 ServiceEntry
= ServiceEntry
->Flink
;
1806 GroupEntry
= GroupEntry
->Flink
;
1809 /* Start all services which are members of any non-existing group */
1810 ServiceEntry
= ServiceListHead
.Flink
;
1811 while (ServiceEntry
!= &ServiceListHead
)
1813 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1815 if ((CurrentService
->lpGroup
!= NULL
) &&
1816 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1817 (CurrentService
->ServiceVisited
== FALSE
))
1819 CurrentService
->ServiceVisited
= TRUE
;
1820 ScmStartService(CurrentService
, 0, NULL
);
1823 ServiceEntry
= ServiceEntry
->Flink
;
1826 /* Start all services which are not a member of any group */
1827 ServiceEntry
= ServiceListHead
.Flink
;
1828 while (ServiceEntry
!= &ServiceListHead
)
1830 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1832 if ((CurrentService
->lpGroup
== NULL
) &&
1833 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1834 (CurrentService
->ServiceVisited
== FALSE
))
1836 CurrentService
->ServiceVisited
= TRUE
;
1837 ScmStartService(CurrentService
, 0, NULL
);
1840 ServiceEntry
= ServiceEntry
->Flink
;
1843 /* Clear 'ServiceVisited' flag again */
1844 ServiceEntry
= ServiceListHead
.Flink
;
1845 while (ServiceEntry
!= &ServiceListHead
)
1847 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1848 CurrentService
->ServiceVisited
= FALSE
;
1849 ServiceEntry
= ServiceEntry
->Flink
;
1855 ScmAutoShutdownServices(VOID
)
1857 PLIST_ENTRY ServiceEntry
;
1858 PSERVICE CurrentService
;
1860 DPRINT("ScmAutoShutdownServices() called\n");
1862 /* Lock the service database exclusively */
1863 ScmLockDatabaseExclusive();
1865 ServiceEntry
= ServiceListHead
.Flink
;
1866 while (ServiceEntry
!= &ServiceListHead
)
1868 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1870 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1871 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1873 /* shutdown service */
1874 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1875 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1878 ServiceEntry
= ServiceEntry
->Flink
;
1881 /* Unlock the service database */
1882 ScmUnlockDatabase();
1884 DPRINT("ScmAutoShutdownServices() done\n");
1889 ScmLockDatabaseExclusive(VOID
)
1891 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1896 ScmLockDatabaseShared(VOID
)
1898 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1903 ScmUnlockDatabase(VOID
)
1905 RtlReleaseResource(&DatabaseLock
);
1910 ScmInitNamedPipeCriticalSection(VOID
)
1916 InitializeCriticalSection(&ControlServiceCriticalSection
);
1918 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1919 L
"SYSTEM\\CurrentControlSet\\Control",
1923 if (dwError
== ERROR_SUCCESS
)
1925 dwKeySize
= sizeof(DWORD
);
1926 RegQueryValueExW(hKey
,
1927 L
"ServicesPipeTimeout",
1930 (LPBYTE
)&PipeTimeout
,
1939 ScmDeleteNamedPipeCriticalSection(VOID
)
1941 DeleteCriticalSection(&ControlServiceCriticalSection
);