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 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
= dwResumeCount
++;
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(), 0, 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
);
670 DPRINT("WaitForLSA() called\n");
672 hEvent
= CreateEventW(NULL
,
675 L
"LSA_RPC_SERVER_ACTIVE");
678 dwError
= GetLastError();
679 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
681 if (dwError
== ERROR_ALREADY_EXISTS
)
683 hEvent
= OpenEventW(SYNCHRONIZE
,
685 L
"LSA_RPC_SERVER_ACTIVE");
688 DPRINT1("Could not open the notification event!\n");
694 DPRINT("Wait for LSA!\n");
695 WaitForSingleObject(hEvent
, INFINITE
);
696 DPRINT("LSA is available!\n");
700 DPRINT("WaitForLSA() done\n");
705 ScmCreateServiceDatabase(VOID
)
707 WCHAR szSubKey
[MAX_PATH
];
711 DWORD dwSubKeyLength
;
712 FILETIME ftLastChanged
;
715 DPRINT("ScmCreateServiceDatabase() called\n");
717 dwError
= ScmCreateGroupList();
718 if (dwError
!= ERROR_SUCCESS
)
721 /* Initialize basic variables */
722 InitializeListHead(&ImageListHead
);
723 InitializeListHead(&ServiceListHead
);
725 /* Initialize the database lock */
726 RtlInitializeResource(&DatabaseLock
);
728 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
729 L
"System\\CurrentControlSet\\Services",
733 if (dwError
!= ERROR_SUCCESS
)
739 dwSubKeyLength
= MAX_PATH
;
740 dwError
= RegEnumKeyExW(hServicesKey
,
748 if (dwError
== ERROR_SUCCESS
&&
751 DPRINT("SubKeyName: '%S'\n", szSubKey
);
753 dwError
= RegOpenKeyExW(hServicesKey
,
758 if (dwError
== ERROR_SUCCESS
)
760 dwError
= CreateServiceListEntry(szSubKey
,
763 RegCloseKey(hServiceKey
);
767 if (dwError
!= ERROR_SUCCESS
)
773 RegCloseKey(hServicesKey
);
778 /* Delete services that are marked for delete */
779 ScmDeleteMarkedServices();
781 DPRINT("ScmCreateServiceDatabase() done\n");
783 return ERROR_SUCCESS
;
788 ScmShutdownServiceDatabase(VOID
)
790 DPRINT("ScmShutdownServiceDatabase() called\n");
792 ScmDeleteMarkedServices();
793 RtlDeleteResource(&DatabaseLock
);
795 DPRINT("ScmShutdownServiceDatabase() done\n");
800 ScmCheckDriver(PSERVICE Service
)
802 OBJECT_ATTRIBUTES ObjectAttributes
;
803 UNICODE_STRING DirName
;
806 POBJECT_DIRECTORY_INFORMATION DirInfo
;
811 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
813 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
815 RtlInitUnicodeString(&DirName
,
820 RtlInitUnicodeString(&DirName
,
824 InitializeObjectAttributes(&ObjectAttributes
,
830 Status
= NtOpenDirectoryObject(&DirHandle
,
831 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
833 if (!NT_SUCCESS(Status
))
838 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
839 2 * MAX_PATH
* sizeof(WCHAR
);
840 DirInfo
= HeapAlloc(GetProcessHeap(),
847 Status
= NtQueryDirectoryObject(DirHandle
,
854 if (Status
== STATUS_NO_MORE_ENTRIES
)
856 /* FIXME: Add current service to 'failed service' list */
857 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
861 if (!NT_SUCCESS(Status
))
864 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
866 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
868 DPRINT("Found: '%S' '%wZ'\n",
869 Service
->lpServiceName
, &DirInfo
->Name
);
871 /* Mark service as 'running' */
872 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
874 /* Mark the service group as 'running' */
875 if (Service
->lpGroup
!= NULL
)
877 Service
->lpGroup
->ServicesRunning
= TRUE
;
884 HeapFree(GetProcessHeap(),
889 return STATUS_SUCCESS
;
894 ScmGetBootAndSystemDriverState(VOID
)
896 PLIST_ENTRY ServiceEntry
;
897 PSERVICE CurrentService
;
899 DPRINT("ScmGetBootAndSystemDriverState() called\n");
901 ServiceEntry
= ServiceListHead
.Flink
;
902 while (ServiceEntry
!= &ServiceListHead
)
904 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
906 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
907 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
910 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
912 ScmCheckDriver(CurrentService
);
915 ServiceEntry
= ServiceEntry
->Flink
;
918 DPRINT("ScmGetBootAndSystemDriverState() done\n");
923 ScmControlService(PSERVICE Service
,
926 PSCM_CONTROL_PACKET ControlPacket
;
927 SCM_REPLY_PACKET ReplyPacket
;
929 DWORD dwWriteCount
= 0;
930 DWORD dwReadCount
= 0;
933 DWORD dwError
= ERROR_SUCCESS
;
935 #ifdef USE_ASYNCHRONOUS_IO
936 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
939 DPRINT("ScmControlService() called\n");
941 EnterCriticalSection(&ControlServiceCriticalSection
);
943 /* Calculate the total length of the start command line */
944 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
945 PacketSize
+= (wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
);
947 ControlPacket
= HeapAlloc(GetProcessHeap(),
950 if (ControlPacket
== NULL
)
952 LeaveCriticalSection(&ControlServiceCriticalSection
);
953 return ERROR_NOT_ENOUGH_MEMORY
;
956 ControlPacket
->dwSize
= PacketSize
;
957 ControlPacket
->dwControl
= dwControl
;
958 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
960 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
962 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
963 wcscpy(Ptr
, Service
->lpServiceName
);
965 ControlPacket
->dwArgumentsCount
= 0;
966 ControlPacket
->dwArgumentsOffset
= 0;
968 #ifdef USE_ASYNCHRONOUS_IO
969 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
974 if (bResult
== FALSE
)
976 DPRINT1("WriteFile() returned FALSE\n");
978 dwError
= GetLastError();
979 if (dwError
== ERROR_IO_PENDING
)
981 DPRINT1("dwError: ERROR_IO_PENDING\n");
983 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
985 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
987 if (dwError
== WAIT_TIMEOUT
)
989 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
990 if (bResult
== FALSE
)
992 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
995 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
998 else if (dwError
== ERROR_SUCCESS
)
1000 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1004 if (bResult
== FALSE
)
1006 dwError
= GetLastError();
1007 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1015 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1020 /* Read the reply */
1021 Overlapped
.hEvent
= (HANDLE
) NULL
;
1023 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1025 sizeof(SCM_REPLY_PACKET
),
1028 if (bResult
== FALSE
)
1030 DPRINT1("ReadFile() returned FALSE\n");
1032 dwError
= GetLastError();
1033 if (dwError
== ERROR_IO_PENDING
)
1035 DPRINT1("dwError: ERROR_IO_PENDING\n");
1037 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1039 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1041 if (dwError
== WAIT_TIMEOUT
)
1043 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1044 if (bResult
== FALSE
)
1046 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1049 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1052 else if (dwError
== ERROR_SUCCESS
)
1054 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1058 if (bResult
== FALSE
)
1060 dwError
= GetLastError();
1061 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1069 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1075 /* Send the control packet */
1076 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1081 if (bResult
== FALSE
)
1083 dwError
= GetLastError();
1084 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1086 if ((dwError
== ERROR_GEN_FAILURE
) &&
1087 (dwControl
== SERVICE_CONTROL_STOP
))
1089 /* Service is already terminated */
1090 Service
->Status
.dwCurrentState
= SERVICE_STOPPED
;
1091 Service
->Status
.dwControlsAccepted
= 0;
1092 Service
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NOT_ACTIVE
;
1093 dwError
= ERROR_SUCCESS
;
1098 /* Read the reply */
1099 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1101 sizeof(SCM_REPLY_PACKET
),
1104 if (bResult
== FALSE
)
1106 dwError
= GetLastError();
1107 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1112 /* Release the contol packet */
1113 HeapFree(GetProcessHeap(),
1117 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1119 dwError
= ReplyPacket
.dwError
;
1122 if (dwError
== ERROR_SUCCESS
&&
1123 dwControl
== SERVICE_CONTROL_STOP
)
1125 ScmDereferenceServiceImage(Service
->lpImage
);
1128 LeaveCriticalSection(&ControlServiceCriticalSection
);
1130 DPRINT("ScmControlService() done\n");
1137 ScmSendStartCommand(PSERVICE Service
,
1141 PSCM_CONTROL_PACKET ControlPacket
;
1142 SCM_REPLY_PACKET ReplyPacket
;
1145 DWORD dwWriteCount
= 0;
1146 DWORD dwReadCount
= 0;
1147 DWORD dwError
= ERROR_SUCCESS
;
1152 #ifdef USE_ASYNCHRONOUS_IO
1153 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1156 DPRINT("ScmSendStartCommand() called\n");
1158 /* Calculate the total length of the start command line */
1159 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
1160 PacketSize
+= (wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
);
1162 /* Calculate the required packet size for the start arguments */
1163 if (argc
> 0 && argv
!= NULL
)
1165 PacketSize
= ALIGN_UP(PacketSize
, LPWSTR
);
1167 DPRINT("Argc: %lu\n", argc
);
1168 for (i
= 0; i
< argc
; i
++)
1170 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1171 PacketSize
+= (wcslen(argv
[i
]) + 1) * sizeof(WCHAR
) + sizeof(PWSTR
);
1175 /* Allocate a control packet */
1176 ControlPacket
= HeapAlloc(GetProcessHeap(),
1179 if (ControlPacket
== NULL
)
1180 return ERROR_NOT_ENOUGH_MEMORY
;
1182 ControlPacket
->dwSize
= PacketSize
;
1183 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
1184 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1185 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1187 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1188 wcscpy(Ptr
, Service
->lpServiceName
);
1190 ControlPacket
->dwArgumentsCount
= 0;
1191 ControlPacket
->dwArgumentsOffset
= 0;
1193 /* Copy argument list */
1194 if (argc
> 0 && argv
!= NULL
)
1196 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1197 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1198 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1200 ControlPacket
->dwArgumentsCount
= argc
;
1201 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1203 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1204 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1206 for (i
= 0; i
< argc
; i
++)
1208 wcscpy(pArgPtr
, argv
[i
]);
1209 *pOffPtr
= (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1210 DPRINT("offset: %p\n", *pOffPtr
);
1212 pArgPtr
+= wcslen(argv
[i
]) + 1;
1217 #ifdef USE_ASYNCHRONOUS_IO
1218 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1223 if (bResult
== FALSE
)
1225 DPRINT1("WriteFile() returned FALSE\n");
1227 dwError
= GetLastError();
1228 if (dwError
== ERROR_IO_PENDING
)
1230 DPRINT1("dwError: ERROR_IO_PENDING\n");
1232 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1234 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1236 if (dwError
== WAIT_TIMEOUT
)
1238 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1239 if (bResult
== FALSE
)
1241 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1244 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1247 else if (dwError
== ERROR_SUCCESS
)
1249 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1253 if (bResult
== FALSE
)
1255 dwError
= GetLastError();
1256 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1264 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1269 /* Read the reply */
1270 Overlapped
.hEvent
= (HANDLE
) NULL
;
1272 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1274 sizeof(SCM_REPLY_PACKET
),
1277 if (bResult
== FALSE
)
1279 DPRINT1("ReadFile() returned FALSE\n");
1281 dwError
= GetLastError();
1282 if (dwError
== ERROR_IO_PENDING
)
1284 DPRINT1("dwError: ERROR_IO_PENDING\n");
1286 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1288 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1290 if (dwError
== WAIT_TIMEOUT
)
1292 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1293 if (bResult
== FALSE
)
1295 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1298 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1301 else if (dwError
== ERROR_SUCCESS
)
1303 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1307 if (bResult
== FALSE
)
1309 dwError
= GetLastError();
1310 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1318 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1324 /* Send the start command */
1325 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1330 if (bResult
== FALSE
)
1332 dwError
= GetLastError();
1333 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1337 /* Read the reply */
1338 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1340 sizeof(SCM_REPLY_PACKET
),
1343 if (bResult
== FALSE
)
1345 dwError
= GetLastError();
1346 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1351 /* Release the contol packet */
1352 HeapFree(GetProcessHeap(),
1356 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1358 dwError
= ReplyPacket
.dwError
;
1361 DPRINT("ScmSendStartCommand() done\n");
1368 ScmWaitForServiceConnect(PSERVICE Service
)
1371 DWORD dwProcessId
= 0;
1372 DWORD dwError
= ERROR_SUCCESS
;
1374 #ifdef USE_ASYNCHRONOUS_IO
1375 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1378 DPRINT("ScmWaitForServiceConnect()\n");
1380 #ifdef USE_ASYNCHRONOUS_IO
1381 Overlapped
.hEvent
= (HANDLE
)NULL
;
1383 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1385 if (bResult
== FALSE
)
1387 DPRINT("ConnectNamedPipe() returned FALSE\n");
1389 dwError
= GetLastError();
1390 if (dwError
== ERROR_IO_PENDING
)
1392 DPRINT("dwError: ERROR_IO_PENDING\n");
1394 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1396 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1398 if (dwError
== WAIT_TIMEOUT
)
1400 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1402 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1403 if (bResult
== FALSE
)
1405 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1408 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1410 else if (dwError
== WAIT_OBJECT_0
)
1412 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1416 if (bResult
== FALSE
)
1418 dwError
= GetLastError();
1419 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1425 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1427 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1432 DPRINT("Control pipe connected!\n");
1434 Overlapped
.hEvent
= (HANDLE
) NULL
;
1436 /* Read the process id from pipe */
1437 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1438 (LPVOID
)&dwProcessId
,
1442 if (bResult
== FALSE
)
1444 DPRINT("ReadFile() returned FALSE\n");
1446 dwError
= GetLastError();
1447 if (dwError
== ERROR_IO_PENDING
)
1449 DPRINT("dwError: ERROR_IO_PENDING\n");
1451 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1453 if (dwError
== WAIT_TIMEOUT
)
1455 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1457 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1458 if (bResult
== FALSE
)
1460 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1463 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1465 else if (dwError
== ERROR_SUCCESS
)
1467 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
1469 DPRINT("Process Id: %lu\n", dwProcessId
);
1471 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1475 if (bResult
== FALSE
)
1477 dwError
= GetLastError();
1478 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1485 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1490 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1495 DPRINT1("ScmWaitForServiceConnect() done\n");
1497 return ERROR_SUCCESS
;
1500 /* Connect control pipe */
1501 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1502 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1504 DPRINT("Control pipe connected!\n");
1506 /* Read SERVICE_STATUS_HANDLE from pipe */
1507 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1508 (LPVOID
)&dwProcessId
,
1512 if (bResult
== FALSE
)
1514 dwError
= GetLastError();
1515 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1520 dwError
= ERROR_SUCCESS
;
1521 DPRINT("Read control pipe successfully\n");
1526 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1535 ScmStartUserModeService(PSERVICE Service
,
1539 PROCESS_INFORMATION ProcessInformation
;
1540 STARTUPINFOW StartupInfo
;
1542 DWORD dwError
= ERROR_SUCCESS
;
1544 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1546 /* If the image is already running ... */
1547 if (Service
->lpImage
->dwImageRunCount
> 1)
1549 /* ... just send a start command */
1550 return ScmSendStartCommand(Service
, argc
, argv
);
1553 StartupInfo
.cb
= sizeof(StartupInfo
);
1554 StartupInfo
.lpReserved
= NULL
;
1555 StartupInfo
.lpDesktop
= NULL
;
1556 StartupInfo
.lpTitle
= NULL
;
1557 StartupInfo
.dwFlags
= 0;
1558 StartupInfo
.cbReserved2
= 0;
1559 StartupInfo
.lpReserved2
= 0;
1561 Result
= CreateProcessW(NULL
,
1562 Service
->lpImage
->szImagePath
,
1566 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1570 &ProcessInformation
);
1573 dwError
= GetLastError();
1574 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1578 DPRINT("Process Id: %lu Handle %p\n",
1579 ProcessInformation
.dwProcessId
,
1580 ProcessInformation
.hProcess
);
1581 DPRINT("Thread Id: %lu Handle %p\n",
1582 ProcessInformation
.dwThreadId
,
1583 ProcessInformation
.hThread
);
1585 /* Get process handle and id */
1586 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1589 ResumeThread(ProcessInformation
.hThread
);
1591 /* Connect control pipe */
1592 dwError
= ScmWaitForServiceConnect(Service
);
1593 if (dwError
== ERROR_SUCCESS
)
1595 /* Send start command */
1596 dwError
= ScmSendStartCommand(Service
,
1602 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1603 Service
->lpImage
->dwProcessId
= 0;
1606 /* Close thread and process handle */
1607 CloseHandle(ProcessInformation
.hThread
);
1608 CloseHandle(ProcessInformation
.hProcess
);
1615 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1617 PSERVICE_GROUP Group
= Service
->lpGroup
;
1618 DWORD dwError
= ERROR_SUCCESS
;
1619 LPCWSTR ErrorLogStrings
[2];
1621 DPRINT("ScmStartService() called\n");
1623 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1625 EnterCriticalSection(&ControlServiceCriticalSection
);
1627 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1629 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1630 LeaveCriticalSection(&ControlServiceCriticalSection
);
1631 return ERROR_SERVICE_ALREADY_RUNNING
;
1634 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1636 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1639 dwError
= ScmLoadDriver(Service
);
1640 if (dwError
== ERROR_SUCCESS
)
1642 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1643 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1648 /* Start user-mode service */
1649 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1650 if (dwError
== ERROR_SUCCESS
)
1652 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1653 if (dwError
== ERROR_SUCCESS
)
1655 #ifdef USE_SERVICE_START_PENDING
1656 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1658 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1663 ScmDereferenceServiceImage(Service
->lpImage
);
1664 Service
->lpImage
= NULL
;
1669 LeaveCriticalSection(&ControlServiceCriticalSection
);
1671 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1673 if (dwError
== ERROR_SUCCESS
)
1677 Group
->ServicesRunning
= TRUE
;
1682 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1684 ErrorLogStrings
[0] = Service
->lpServiceName
;
1685 ErrorLogStrings
[1] = L
"Test";
1686 ScmLogError(EVENT_SERVICE_START_FAILED
,
1692 switch (Service
->dwErrorControl
)
1694 case SERVICE_ERROR_SEVERE
:
1695 if (IsLastKnownGood
== FALSE
)
1697 /* FIXME: Boot last known good configuration */
1701 case SERVICE_ERROR_CRITICAL
:
1702 if (IsLastKnownGood
== FALSE
)
1704 /* FIXME: Boot last known good configuration */
1720 ScmAutoStartServices(VOID
)
1722 PLIST_ENTRY GroupEntry
;
1723 PLIST_ENTRY ServiceEntry
;
1724 PSERVICE_GROUP CurrentGroup
;
1725 PSERVICE CurrentService
;
1726 WCHAR szSafeBootServicePath
[MAX_PATH
];
1731 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1732 ServiceEntry
= ServiceListHead
.Flink
;
1733 while (ServiceEntry
!= &ServiceListHead
)
1735 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1737 /* Build the safe boot path */
1738 wcscpy(szSafeBootServicePath
,
1739 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1741 switch (GetSystemMetrics(SM_CLEANBOOT
))
1743 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1746 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1750 wcscat(szSafeBootServicePath
, L
"\\Network\\");
1754 if (GetSystemMetrics(SM_CLEANBOOT
))
1756 /* If key does not exist then do not assume safe mode */
1757 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1758 szSafeBootServicePath
,
1762 if (dwError
== ERROR_SUCCESS
)
1766 /* Finish Safe Boot path off */
1767 wcsncat(szSafeBootServicePath
,
1768 CurrentService
->lpServiceName
,
1769 MAX_PATH
- wcslen(szSafeBootServicePath
));
1771 /* Check that the key is in the Safe Boot path */
1772 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1773 szSafeBootServicePath
,
1777 if (dwError
!= ERROR_SUCCESS
)
1779 /* Mark service as visited so it is not auto-started */
1780 CurrentService
->ServiceVisited
= TRUE
;
1784 /* Must be auto-started in safe mode - mark as unvisited */
1786 CurrentService
->ServiceVisited
= FALSE
;
1791 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1792 CurrentService
->ServiceVisited
= FALSE
;
1796 ServiceEntry
= ServiceEntry
->Flink
;
1799 /* Start all services which are members of an existing group */
1800 GroupEntry
= GroupListHead
.Flink
;
1801 while (GroupEntry
!= &GroupListHead
)
1803 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1805 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1807 /* Start all services witch have a valid tag */
1808 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1810 ServiceEntry
= ServiceListHead
.Flink
;
1811 while (ServiceEntry
!= &ServiceListHead
)
1813 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1815 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1816 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1817 (CurrentService
->ServiceVisited
== FALSE
) &&
1818 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1820 CurrentService
->ServiceVisited
= TRUE
;
1821 ScmStartService(CurrentService
, 0, NULL
);
1824 ServiceEntry
= ServiceEntry
->Flink
;
1828 /* Start all services which have an invalid tag or which do not have a tag */
1829 ServiceEntry
= ServiceListHead
.Flink
;
1830 while (ServiceEntry
!= &ServiceListHead
)
1832 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1834 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1835 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1836 (CurrentService
->ServiceVisited
== FALSE
))
1838 CurrentService
->ServiceVisited
= TRUE
;
1839 ScmStartService(CurrentService
, 0, NULL
);
1842 ServiceEntry
= ServiceEntry
->Flink
;
1845 GroupEntry
= GroupEntry
->Flink
;
1848 /* Start all services which are members of any non-existing group */
1849 ServiceEntry
= ServiceListHead
.Flink
;
1850 while (ServiceEntry
!= &ServiceListHead
)
1852 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1854 if ((CurrentService
->lpGroup
!= NULL
) &&
1855 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1856 (CurrentService
->ServiceVisited
== FALSE
))
1858 CurrentService
->ServiceVisited
= TRUE
;
1859 ScmStartService(CurrentService
, 0, NULL
);
1862 ServiceEntry
= ServiceEntry
->Flink
;
1865 /* Start all services which are not a member of any group */
1866 ServiceEntry
= ServiceListHead
.Flink
;
1867 while (ServiceEntry
!= &ServiceListHead
)
1869 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1871 if ((CurrentService
->lpGroup
== NULL
) &&
1872 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1873 (CurrentService
->ServiceVisited
== FALSE
))
1875 CurrentService
->ServiceVisited
= TRUE
;
1876 ScmStartService(CurrentService
, 0, NULL
);
1879 ServiceEntry
= ServiceEntry
->Flink
;
1882 /* Clear 'ServiceVisited' flag again */
1883 ServiceEntry
= ServiceListHead
.Flink
;
1884 while (ServiceEntry
!= &ServiceListHead
)
1886 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1887 CurrentService
->ServiceVisited
= FALSE
;
1888 ServiceEntry
= ServiceEntry
->Flink
;
1894 ScmAutoShutdownServices(VOID
)
1896 PLIST_ENTRY ServiceEntry
;
1897 PSERVICE CurrentService
;
1899 DPRINT("ScmAutoShutdownServices() called\n");
1901 /* Lock the service database exclusively */
1902 ScmLockDatabaseExclusive();
1904 ServiceEntry
= ServiceListHead
.Flink
;
1905 while (ServiceEntry
!= &ServiceListHead
)
1907 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1909 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1910 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1912 /* shutdown service */
1913 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1914 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1917 ServiceEntry
= ServiceEntry
->Flink
;
1920 /* Unlock the service database */
1921 ScmUnlockDatabase();
1923 DPRINT("ScmAutoShutdownServices() done\n");
1928 ScmLockDatabaseExclusive(VOID
)
1930 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1935 ScmLockDatabaseShared(VOID
)
1937 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1942 ScmUnlockDatabase(VOID
)
1944 RtlReleaseResource(&DatabaseLock
);
1949 ScmInitNamedPipeCriticalSection(VOID
)
1955 InitializeCriticalSection(&ControlServiceCriticalSection
);
1957 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1958 L
"SYSTEM\\CurrentControlSet\\Control",
1962 if (dwError
== ERROR_SUCCESS
)
1964 dwKeySize
= sizeof(DWORD
);
1965 RegQueryValueExW(hKey
,
1966 L
"ServicesPipeTimeout",
1969 (LPBYTE
)&dwPipeTimeout
,
1978 ScmDeleteNamedPipeCriticalSection(VOID
)
1980 DeleteCriticalSection(&ControlServiceCriticalSection
);