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 /* The critical section synchronizes service controls commands */
42 static CRITICAL_SECTION ControlServiceCriticalSection
;
43 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
46 /* FUNCTIONS *****************************************************************/
49 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
51 WCHAR szControlPipeName
[MAX_PATH
+ 1];
52 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
53 DWORD ServiceCurrent
= 0;
58 /* Get the service number */
59 /* TODO: Create registry entry with correct write access */
60 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
61 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
67 if (dwError
!= ERROR_SUCCESS
)
69 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
73 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
75 dwKeySize
= sizeof(DWORD
);
76 dwError
= RegQueryValueExW(hServiceCurrentKey
,
77 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
79 if (dwError
!= ERROR_SUCCESS
)
81 RegCloseKey(hServiceCurrentKey
);
82 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
89 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
91 RegCloseKey(hServiceCurrentKey
);
93 if (dwError
!= ERROR_SUCCESS
)
95 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
99 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
100 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
102 DPRINT("PipeName: %S\n", szControlPipeName
);
104 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
105 #ifdef USE_ASYNCHRONOUS_IO
106 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
110 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
116 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
117 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
119 DPRINT1("Failed to create control pipe!\n");
120 return GetLastError();
123 return ERROR_SUCCESS
;
127 static PSERVICE_IMAGE
128 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
130 PLIST_ENTRY ImageEntry
;
131 PSERVICE_IMAGE CurrentImage
;
133 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
135 ImageEntry
= ImageListHead
.Flink
;
136 while (ImageEntry
!= &ImageListHead
)
138 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
141 if (_wcsicmp(CurrentImage
->szImagePath
, lpImagePath
) == 0)
143 DPRINT("Found image: '%S'\n", CurrentImage
->szImagePath
);
147 ImageEntry
= ImageEntry
->Flink
;
150 DPRINT("Couldn't find a matching image\n");
158 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
160 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
161 UNICODE_STRING ImagePath
;
162 PSERVICE_IMAGE pServiceImage
= NULL
;
164 DWORD dwError
= ERROR_SUCCESS
;
166 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
168 RtlInitUnicodeString(&ImagePath
, NULL
);
170 /* Get service data */
171 RtlZeroMemory(&QueryTable
,
174 QueryTable
[0].Name
= L
"ImagePath";
175 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
176 QueryTable
[0].EntryContext
= &ImagePath
;
178 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
179 pService
->lpServiceName
,
183 if (!NT_SUCCESS(Status
))
185 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
186 return RtlNtStatusToDosError(Status
);
189 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
191 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
192 if (pServiceImage
== NULL
)
194 /* Create a new service image */
195 pServiceImage
= HeapAlloc(GetProcessHeap(),
197 FIELD_OFFSET(SERVICE_IMAGE
, szImagePath
[ImagePath
.Length
/ sizeof(WCHAR
) + 1]));
198 if (pServiceImage
== NULL
)
200 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
204 pServiceImage
->dwImageRunCount
= 1;
205 pServiceImage
->hControlPipe
= 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 /* Release the service image */
269 HeapFree(GetProcessHeap(), 0, pServiceImage
);
275 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
277 PLIST_ENTRY ServiceEntry
;
278 PSERVICE CurrentService
;
280 DPRINT("ScmGetServiceEntryByName() called\n");
282 ServiceEntry
= ServiceListHead
.Flink
;
283 while (ServiceEntry
!= &ServiceListHead
)
285 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
288 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
290 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
291 return CurrentService
;
294 ServiceEntry
= ServiceEntry
->Flink
;
297 DPRINT("Couldn't find a matching service\n");
304 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
306 PLIST_ENTRY ServiceEntry
;
307 PSERVICE CurrentService
;
309 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
311 ServiceEntry
= ServiceListHead
.Flink
;
312 while (ServiceEntry
!= &ServiceListHead
)
314 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
317 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
319 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
320 return CurrentService
;
323 ServiceEntry
= ServiceEntry
->Flink
;
326 DPRINT("Couldn't find a matching service\n");
333 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
335 PLIST_ENTRY ServiceEntry
;
336 PSERVICE CurrentService
;
338 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
340 ServiceEntry
= ServiceListHead
.Flink
;
341 while (ServiceEntry
!= &ServiceListHead
)
343 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
346 if (CurrentService
->dwResumeCount
> dwResumeCount
)
348 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
349 return CurrentService
;
352 ServiceEntry
= ServiceEntry
->Flink
;
355 DPRINT("Couldn't find a matching service\n");
362 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
363 PSERVICE
* lpServiceRecord
)
365 PSERVICE lpService
= NULL
;
367 DPRINT("Service: '%S'\n", lpServiceName
);
369 /* Allocate service entry */
370 lpService
= HeapAlloc(GetProcessHeap(),
372 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
373 if (lpService
== NULL
)
374 return ERROR_NOT_ENOUGH_MEMORY
;
376 *lpServiceRecord
= lpService
;
378 /* Copy service name */
379 wcscpy(lpService
->szServiceName
, lpServiceName
);
380 lpService
->lpServiceName
= lpService
->szServiceName
;
381 lpService
->lpDisplayName
= lpService
->lpServiceName
;
383 /* Set the resume count */
384 lpService
->dwResumeCount
= ResumeCount
++;
386 /* Append service record */
387 InsertTailList(&ServiceListHead
,
388 &lpService
->ServiceListEntry
);
390 /* Initialize the service status */
391 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
392 lpService
->Status
.dwControlsAccepted
= 0;
393 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
394 lpService
->Status
.dwServiceSpecificExitCode
= 0;
395 lpService
->Status
.dwCheckPoint
= 0;
396 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
398 return ERROR_SUCCESS
;
403 ScmDeleteServiceRecord(PSERVICE lpService
)
405 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
407 /* Delete the display name */
408 if (lpService
->lpDisplayName
!= NULL
&&
409 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
410 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
412 /* Dereference the service image */
413 if (lpService
->lpImage
)
414 ScmDereferenceServiceImage(lpService
->lpImage
);
416 /* Decrement the group reference counter */
417 if (lpService
->lpGroup
)
418 lpService
->lpGroup
->dwRefCount
--;
420 /* FIXME: SecurityDescriptor */
423 /* Remove the Service from the List */
424 RemoveEntryList(&lpService
->ServiceListEntry
);
426 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
428 /* Delete the service record */
429 HeapFree(GetProcessHeap(), 0, lpService
);
436 CreateServiceListEntry(LPCWSTR lpServiceName
,
439 PSERVICE lpService
= NULL
;
440 LPWSTR lpDisplayName
= NULL
;
441 LPWSTR lpGroup
= NULL
;
446 DWORD dwErrorControl
;
449 DPRINT("Service: '%S'\n", lpServiceName
);
450 if (*lpServiceName
== L
'{')
451 return ERROR_SUCCESS
;
453 dwSize
= sizeof(DWORD
);
454 dwError
= RegQueryValueExW(hServiceKey
,
458 (LPBYTE
)&dwServiceType
,
460 if (dwError
!= ERROR_SUCCESS
)
461 return ERROR_SUCCESS
;
463 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
464 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
465 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
466 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
467 return ERROR_SUCCESS
;
469 DPRINT("Service type: %lx\n", dwServiceType
);
471 dwSize
= sizeof(DWORD
);
472 dwError
= RegQueryValueExW(hServiceKey
,
476 (LPBYTE
)&dwStartType
,
478 if (dwError
!= ERROR_SUCCESS
)
479 return ERROR_SUCCESS
;
481 DPRINT("Start type: %lx\n", dwStartType
);
483 dwSize
= sizeof(DWORD
);
484 dwError
= RegQueryValueExW(hServiceKey
,
488 (LPBYTE
)&dwErrorControl
,
490 if (dwError
!= ERROR_SUCCESS
)
491 return ERROR_SUCCESS
;
493 DPRINT("Error control: %lx\n", dwErrorControl
);
495 dwError
= RegQueryValueExW(hServiceKey
,
501 if (dwError
!= ERROR_SUCCESS
)
504 DPRINT("Tag: %lx\n", dwTagId
);
506 dwError
= ScmReadString(hServiceKey
,
509 if (dwError
!= ERROR_SUCCESS
)
512 DPRINT("Group: %S\n", lpGroup
);
514 dwError
= ScmReadString(hServiceKey
,
517 if (dwError
!= ERROR_SUCCESS
)
518 lpDisplayName
= NULL
;
520 DPRINT("Display name: %S\n", lpDisplayName
);
522 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
524 if (dwError
!= ERROR_SUCCESS
)
527 lpService
->Status
.dwServiceType
= dwServiceType
;
528 lpService
->dwStartType
= dwStartType
;
529 lpService
->dwErrorControl
= dwErrorControl
;
530 lpService
->dwTag
= dwTagId
;
534 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
535 if (dwError
!= ERROR_SUCCESS
)
539 if (lpDisplayName
!= NULL
)
541 lpService
->lpDisplayName
= lpDisplayName
;
542 lpDisplayName
= NULL
;
545 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
546 if (lpService
->lpGroup
!= NULL
)
548 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
550 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
551 lpService
->dwStartType
,
552 lpService
->Status
.dwServiceType
,
554 lpService
->dwErrorControl
);
556 if (ScmIsDeleteFlagSet(hServiceKey
))
557 lpService
->bDeleted
= TRUE
;
561 HeapFree(GetProcessHeap(), 0, lpGroup
);
563 if (lpDisplayName
!= NULL
)
564 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
566 if (lpService
!= NULL
)
568 if (lpService
->lpImage
!= NULL
)
569 ScmDereferenceServiceImage(lpService
->lpImage
);
577 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
579 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
580 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
583 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
586 /* Find the maximum subkey length so that we can allocate a buffer */
587 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
588 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
592 if (dwMaxSubkeyLen
> sizeof(szNameBuf
) / sizeof(WCHAR
))
594 /* Name too big: alloc a buffer for it */
595 lpszName
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMaxSubkeyLen
* sizeof(WCHAR
));
599 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
602 while (dwRet
== ERROR_SUCCESS
)
604 dwSize
= dwMaxSubkeyLen
;
605 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
606 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
607 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
609 if (dwRet
== ERROR_NO_MORE_ITEMS
)
610 dwRet
= ERROR_SUCCESS
;
612 if (lpszName
!= szNameBuf
)
613 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
617 RegCloseKey(hSubKey
);
619 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
626 ScmDeleteMarkedServices(VOID
)
628 PLIST_ENTRY ServiceEntry
;
629 PSERVICE CurrentService
;
633 ServiceEntry
= ServiceListHead
.Flink
;
634 while (ServiceEntry
!= &ServiceListHead
)
636 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
638 ServiceEntry
= ServiceEntry
->Flink
;
640 if (CurrentService
->bDeleted
== TRUE
)
642 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
643 L
"System\\CurrentControlSet\\Services",
647 if (dwError
== ERROR_SUCCESS
)
649 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
650 RegCloseKey(hServicesKey
);
651 if (dwError
== ERROR_SUCCESS
)
653 RemoveEntryList(&CurrentService
->ServiceListEntry
);
654 HeapFree(GetProcessHeap(), 0, CurrentService
);
658 if (dwError
!= ERROR_SUCCESS
)
659 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
666 ScmCreateServiceDatabase(VOID
)
668 WCHAR szSubKey
[MAX_PATH
];
672 DWORD dwSubKeyLength
;
673 FILETIME ftLastChanged
;
676 DPRINT("ScmCreateServiceDatabase() called\n");
678 dwError
= ScmCreateGroupList();
679 if (dwError
!= ERROR_SUCCESS
)
682 /* Initialize basic variables */
683 InitializeListHead(&ImageListHead
);
684 InitializeListHead(&ServiceListHead
);
686 /* Initialize the database lock */
687 RtlInitializeResource(&DatabaseLock
);
689 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
690 L
"System\\CurrentControlSet\\Services",
694 if (dwError
!= ERROR_SUCCESS
)
700 dwSubKeyLength
= MAX_PATH
;
701 dwError
= RegEnumKeyExW(hServicesKey
,
709 if (dwError
== ERROR_SUCCESS
&&
712 DPRINT("SubKeyName: '%S'\n", szSubKey
);
714 dwError
= RegOpenKeyExW(hServicesKey
,
719 if (dwError
== ERROR_SUCCESS
)
721 dwError
= CreateServiceListEntry(szSubKey
,
724 RegCloseKey(hServiceKey
);
728 if (dwError
!= ERROR_SUCCESS
)
734 RegCloseKey(hServicesKey
);
736 /* Wait for the LSA server */
739 /* Delete services that are marked for delete */
740 ScmDeleteMarkedServices();
742 DPRINT("ScmCreateServiceDatabase() done\n");
744 return ERROR_SUCCESS
;
749 ScmShutdownServiceDatabase(VOID
)
751 DPRINT("ScmShutdownServiceDatabase() called\n");
753 ScmDeleteMarkedServices();
754 RtlDeleteResource(&DatabaseLock
);
756 DPRINT("ScmShutdownServiceDatabase() done\n");
761 ScmCheckDriver(PSERVICE Service
)
763 OBJECT_ATTRIBUTES ObjectAttributes
;
764 UNICODE_STRING DirName
;
767 POBJECT_DIRECTORY_INFORMATION DirInfo
;
772 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
774 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
776 RtlInitUnicodeString(&DirName
, L
"\\Driver");
778 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
780 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
783 InitializeObjectAttributes(&ObjectAttributes
,
789 Status
= NtOpenDirectoryObject(&DirHandle
,
790 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
792 if (!NT_SUCCESS(Status
))
797 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
798 2 * MAX_PATH
* sizeof(WCHAR
);
799 DirInfo
= HeapAlloc(GetProcessHeap(),
806 Status
= NtQueryDirectoryObject(DirHandle
,
813 if (Status
== STATUS_NO_MORE_ENTRIES
)
815 /* FIXME: Add current service to 'failed service' list */
816 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
820 if (!NT_SUCCESS(Status
))
823 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
825 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
827 DPRINT("Found: '%S' '%wZ'\n",
828 Service
->lpServiceName
, &DirInfo
->Name
);
830 /* Mark service as 'running' */
831 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
833 /* Mark the service group as 'running' */
834 if (Service
->lpGroup
!= NULL
)
836 Service
->lpGroup
->ServicesRunning
= TRUE
;
843 HeapFree(GetProcessHeap(),
848 return STATUS_SUCCESS
;
853 ScmGetBootAndSystemDriverState(VOID
)
855 PLIST_ENTRY ServiceEntry
;
856 PSERVICE CurrentService
;
858 DPRINT("ScmGetBootAndSystemDriverState() called\n");
860 ServiceEntry
= ServiceListHead
.Flink
;
861 while (ServiceEntry
!= &ServiceListHead
)
863 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
865 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
866 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
869 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
871 ScmCheckDriver(CurrentService
);
874 ServiceEntry
= ServiceEntry
->Flink
;
877 DPRINT("ScmGetBootAndSystemDriverState() done\n");
882 ScmControlService(PSERVICE Service
,
885 PSCM_CONTROL_PACKET ControlPacket
;
886 SCM_REPLY_PACKET ReplyPacket
;
888 DWORD dwWriteCount
= 0;
889 DWORD dwReadCount
= 0;
892 DWORD dwError
= ERROR_SUCCESS
;
894 #ifdef USE_ASYNCHRONOUS_IO
895 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
898 DPRINT("ScmControlService() called\n");
900 EnterCriticalSection(&ControlServiceCriticalSection
);
902 /* Calculate the total length of the start command line */
903 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
904 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
906 ControlPacket
= HeapAlloc(GetProcessHeap(),
909 if (ControlPacket
== NULL
)
911 LeaveCriticalSection(&ControlServiceCriticalSection
);
912 return ERROR_NOT_ENOUGH_MEMORY
;
915 ControlPacket
->dwSize
= PacketSize
;
916 ControlPacket
->dwControl
= dwControl
;
917 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
919 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
921 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
922 wcscpy(Ptr
, Service
->lpServiceName
);
924 ControlPacket
->dwArgumentsCount
= 0;
925 ControlPacket
->dwArgumentsOffset
= 0;
927 #ifdef USE_ASYNCHRONOUS_IO
928 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
933 if (bResult
== FALSE
)
935 DPRINT1("WriteFile() returned FALSE\n");
937 dwError
= GetLastError();
938 if (dwError
== ERROR_IO_PENDING
)
940 DPRINT1("dwError: ERROR_IO_PENDING\n");
942 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
944 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
946 if (dwError
== WAIT_TIMEOUT
)
948 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
949 if (bResult
== FALSE
)
951 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
954 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
957 else if (dwError
== ERROR_SUCCESS
)
959 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
963 if (bResult
== FALSE
)
965 dwError
= GetLastError();
966 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
974 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
980 Overlapped
.hEvent
= (HANDLE
) NULL
;
982 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
984 sizeof(SCM_REPLY_PACKET
),
987 if (bResult
== FALSE
)
989 DPRINT1("ReadFile() returned FALSE\n");
991 dwError
= GetLastError();
992 if (dwError
== ERROR_IO_PENDING
)
994 DPRINT1("dwError: ERROR_IO_PENDING\n");
996 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
998 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1000 if (dwError
== WAIT_TIMEOUT
)
1002 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1003 if (bResult
== FALSE
)
1005 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1008 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1011 else if (dwError
== ERROR_SUCCESS
)
1013 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1017 if (bResult
== FALSE
)
1019 dwError
= GetLastError();
1020 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1028 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1034 /* Send the control packet */
1035 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1040 if (bResult
== FALSE
)
1042 dwError
= GetLastError();
1043 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1045 if ((dwError
== ERROR_GEN_FAILURE
) &&
1046 (dwControl
== SERVICE_CONTROL_STOP
))
1048 /* Service is already terminated */
1049 Service
->Status
.dwCurrentState
= SERVICE_STOPPED
;
1050 Service
->Status
.dwControlsAccepted
= 0;
1051 Service
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NOT_ACTIVE
;
1052 dwError
= ERROR_SUCCESS
;
1057 /* Read the reply */
1058 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1060 sizeof(SCM_REPLY_PACKET
),
1063 if (bResult
== FALSE
)
1065 dwError
= GetLastError();
1066 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1071 /* Release the contol packet */
1072 HeapFree(GetProcessHeap(),
1076 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1078 dwError
= ReplyPacket
.dwError
;
1081 if (dwError
== ERROR_SUCCESS
&&
1082 dwControl
== SERVICE_CONTROL_STOP
)
1084 ScmDereferenceServiceImage(Service
->lpImage
);
1087 LeaveCriticalSection(&ControlServiceCriticalSection
);
1089 DPRINT("ScmControlService() done\n");
1096 ScmSendStartCommand(PSERVICE Service
,
1100 PSCM_CONTROL_PACKET ControlPacket
;
1101 SCM_REPLY_PACKET ReplyPacket
;
1104 DWORD dwWriteCount
= 0;
1105 DWORD dwReadCount
= 0;
1106 DWORD dwError
= ERROR_SUCCESS
;
1111 #ifdef USE_ASYNCHRONOUS_IO
1112 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1115 DPRINT("ScmSendStartCommand() called\n");
1117 /* Calculate the total length of the start command line */
1118 PacketSize
= sizeof(SCM_CONTROL_PACKET
) +
1119 (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1121 /* Calculate the required packet size for the start arguments */
1122 if (argc
> 0 && argv
!= NULL
)
1124 PacketSize
= ALIGN_UP(PacketSize
, LPWSTR
);
1126 DPRINT("Argc: %lu\n", argc
);
1127 for (i
= 0; i
< argc
; i
++)
1129 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1130 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
) + sizeof(PWSTR
));
1134 /* Allocate a control packet */
1135 ControlPacket
= HeapAlloc(GetProcessHeap(),
1138 if (ControlPacket
== NULL
)
1139 return ERROR_NOT_ENOUGH_MEMORY
;
1141 ControlPacket
->dwSize
= PacketSize
;
1142 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1143 ? SERVICE_CONTROL_START_OWN
1144 : SERVICE_CONTROL_START_SHARE
;
1145 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1146 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1148 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1149 wcscpy(Ptr
, Service
->lpServiceName
);
1151 ControlPacket
->dwArgumentsCount
= 0;
1152 ControlPacket
->dwArgumentsOffset
= 0;
1154 /* Copy argument list */
1155 if (argc
> 0 && argv
!= NULL
)
1157 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1158 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1159 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1161 ControlPacket
->dwArgumentsCount
= argc
;
1162 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1164 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1165 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1167 for (i
= 0; i
< argc
; i
++)
1169 wcscpy(pArgPtr
, argv
[i
]);
1170 *pOffPtr
= (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1171 DPRINT("offset: %p\n", *pOffPtr
);
1173 pArgPtr
+= wcslen(argv
[i
]) + 1;
1178 #ifdef USE_ASYNCHRONOUS_IO
1179 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1184 if (bResult
== FALSE
)
1186 DPRINT1("WriteFile() returned FALSE\n");
1188 dwError
= GetLastError();
1189 if (dwError
== ERROR_IO_PENDING
)
1191 DPRINT1("dwError: ERROR_IO_PENDING\n");
1193 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1195 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1197 if (dwError
== WAIT_TIMEOUT
)
1199 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1200 if (bResult
== FALSE
)
1202 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1205 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1208 else if (dwError
== ERROR_SUCCESS
)
1210 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1214 if (bResult
== FALSE
)
1216 dwError
= GetLastError();
1217 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1225 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1230 /* Read the reply */
1231 Overlapped
.hEvent
= (HANDLE
) NULL
;
1233 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1235 sizeof(SCM_REPLY_PACKET
),
1238 if (bResult
== FALSE
)
1240 DPRINT1("ReadFile() returned FALSE\n");
1242 dwError
= GetLastError();
1243 if (dwError
== ERROR_IO_PENDING
)
1245 DPRINT1("dwError: ERROR_IO_PENDING\n");
1247 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1249 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1251 if (dwError
== WAIT_TIMEOUT
)
1253 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1254 if (bResult
== FALSE
)
1256 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1259 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1262 else if (dwError
== ERROR_SUCCESS
)
1264 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1268 if (bResult
== FALSE
)
1270 dwError
= GetLastError();
1271 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1279 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1285 /* Send the start command */
1286 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1291 if (bResult
== FALSE
)
1293 dwError
= GetLastError();
1294 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1298 /* Read the reply */
1299 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1301 sizeof(SCM_REPLY_PACKET
),
1304 if (bResult
== FALSE
)
1306 dwError
= GetLastError();
1307 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1312 /* Release the contol packet */
1313 HeapFree(GetProcessHeap(),
1317 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1319 dwError
= ReplyPacket
.dwError
;
1322 DPRINT("ScmSendStartCommand() done\n");
1329 ScmWaitForServiceConnect(PSERVICE Service
)
1332 DWORD dwProcessId
= 0;
1333 DWORD dwError
= ERROR_SUCCESS
;
1335 #ifdef USE_ASYNCHRONOUS_IO
1336 OVERLAPPED Overlapped
= {0, 0, 0, 0, 0};
1339 DPRINT("ScmWaitForServiceConnect()\n");
1341 #ifdef USE_ASYNCHRONOUS_IO
1342 Overlapped
.hEvent
= (HANDLE
)NULL
;
1344 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1346 if (bResult
== FALSE
)
1348 DPRINT("ConnectNamedPipe() returned FALSE\n");
1350 dwError
= GetLastError();
1351 if (dwError
== ERROR_IO_PENDING
)
1353 DPRINT("dwError: ERROR_IO_PENDING\n");
1355 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1357 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1359 if (dwError
== WAIT_TIMEOUT
)
1361 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1363 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1364 if (bResult
== FALSE
)
1366 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1369 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1371 else if (dwError
== WAIT_OBJECT_0
)
1373 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1377 if (bResult
== FALSE
)
1379 dwError
= GetLastError();
1380 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1386 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1388 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1393 DPRINT("Control pipe connected!\n");
1395 Overlapped
.hEvent
= (HANDLE
) NULL
;
1397 /* Read the process id from pipe */
1398 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1399 (LPVOID
)&dwProcessId
,
1403 if (bResult
== FALSE
)
1405 DPRINT("ReadFile() returned FALSE\n");
1407 dwError
= GetLastError();
1408 if (dwError
== ERROR_IO_PENDING
)
1410 DPRINT("dwError: ERROR_IO_PENDING\n");
1412 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1414 if (dwError
== WAIT_TIMEOUT
)
1416 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1418 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1419 if (bResult
== FALSE
)
1421 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1424 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1426 else if (dwError
== ERROR_SUCCESS
)
1428 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
1430 DPRINT("Process Id: %lu\n", dwProcessId
);
1432 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1436 if (bResult
== FALSE
)
1438 dwError
= GetLastError();
1439 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1446 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1451 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1456 DPRINT1("ScmWaitForServiceConnect() done\n");
1458 return ERROR_SUCCESS
;
1461 /* Connect control pipe */
1462 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1463 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1465 DPRINT("Control pipe connected!\n");
1467 /* Read SERVICE_STATUS_HANDLE from pipe */
1468 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1469 (LPVOID
)&dwProcessId
,
1473 if (bResult
== FALSE
)
1475 dwError
= GetLastError();
1476 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1481 dwError
= ERROR_SUCCESS
;
1482 DPRINT("Read control pipe successfully\n");
1487 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1496 ScmStartUserModeService(PSERVICE Service
,
1500 PROCESS_INFORMATION ProcessInformation
;
1501 STARTUPINFOW StartupInfo
;
1503 DWORD dwError
= ERROR_SUCCESS
;
1505 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1507 /* If the image is already running ... */
1508 if (Service
->lpImage
->dwImageRunCount
> 1)
1510 /* ... just send a start command */
1511 return ScmSendStartCommand(Service
, argc
, argv
);
1514 /* Otherwise start its process */
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
, argc
, argv
);
1558 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1559 Service
->lpImage
->dwProcessId
= 0;
1562 /* Close thread and process handle */
1563 CloseHandle(ProcessInformation
.hThread
);
1564 CloseHandle(ProcessInformation
.hProcess
);
1571 ScmLoadService(PSERVICE Service
,
1575 PSERVICE_GROUP Group
= Service
->lpGroup
;
1576 DWORD dwError
= ERROR_SUCCESS
;
1577 LPCWSTR ErrorLogStrings
[2];
1578 WCHAR szErrorBuffer
[32];
1580 DPRINT("ScmLoadService() called\n");
1581 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1583 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1585 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1586 return ERROR_SERVICE_ALREADY_RUNNING
;
1589 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1591 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1594 dwError
= ScmLoadDriver(Service
);
1595 if (dwError
== ERROR_SUCCESS
)
1597 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1598 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1601 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1603 /* Start user-mode service */
1604 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1605 if (dwError
== ERROR_SUCCESS
)
1607 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1608 if (dwError
== ERROR_SUCCESS
)
1610 #ifdef USE_SERVICE_START_PENDING
1611 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1613 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1618 ScmDereferenceServiceImage(Service
->lpImage
);
1619 Service
->lpImage
= NULL
;
1624 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1626 if (dwError
== ERROR_SUCCESS
)
1630 Group
->ServicesRunning
= TRUE
;
1635 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1637 /* Log a failed service start */
1638 swprintf(szErrorBuffer
, L
"%lu", dwError
);
1639 ErrorLogStrings
[0] = Service
->lpServiceName
;
1640 ErrorLogStrings
[1] = szErrorBuffer
;
1641 ScmLogError(EVENT_SERVICE_START_FAILED
,
1647 switch (Service
->dwErrorControl
)
1649 case SERVICE_ERROR_SEVERE
:
1650 if (IsLastKnownGood
== FALSE
)
1652 /* FIXME: Boot last known good configuration */
1656 case SERVICE_ERROR_CRITICAL
:
1657 if (IsLastKnownGood
== FALSE
)
1659 /* FIXME: Boot last known good configuration */
1675 ScmStartService(PSERVICE Service
,
1679 DWORD dwError
= ERROR_SUCCESS
;
1680 SC_RPC_LOCK Lock
= NULL
;
1682 DPRINT("ScmStartService() called\n");
1683 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1685 /* Acquire the service control critical section, to synchronize starts */
1686 EnterCriticalSection(&ControlServiceCriticalSection
);
1689 * Acquire the user service start lock while the service is starting, if
1690 * needed (i.e. if we are not starting it during the initialization phase).
1691 * If we don't success, bail out.
1695 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1696 if (dwError
!= ERROR_SUCCESS
) goto done
;
1699 /* Really start the service */
1700 dwError
= ScmLoadService(Service
, argc
, argv
);
1702 /* Release the service start lock, if needed, and the critical section */
1703 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1706 LeaveCriticalSection(&ControlServiceCriticalSection
);
1708 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1715 ScmAutoStartServices(VOID
)
1717 DWORD dwError
= ERROR_SUCCESS
;
1718 SC_RPC_LOCK Lock
= NULL
;
1720 PLIST_ENTRY GroupEntry
;
1721 PLIST_ENTRY ServiceEntry
;
1722 PSERVICE_GROUP CurrentGroup
;
1723 PSERVICE CurrentService
;
1724 WCHAR szSafeBootServicePath
[MAX_PATH
];
1728 /* Acquire the service control critical section, to synchronize starts */
1729 EnterCriticalSection(&ControlServiceCriticalSection
);
1732 * Acquire the user service start lock while the service is starting, if
1733 * needed (i.e. if we are not starting it during the initialization phase).
1734 * If we don't success, bail out.
1739 * Actually this code is never executed since we are called
1740 * at initialization time, so that ScmInitialize == TRUE.
1741 * But keep the code here if someday we are called later on
1742 * for whatever reason...
1744 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1745 if (dwError
!= ERROR_SUCCESS
) goto done
;
1749 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1750 ServiceEntry
= ServiceListHead
.Flink
;
1751 while (ServiceEntry
!= &ServiceListHead
)
1753 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1755 /* Build the safe boot path */
1756 wcscpy(szSafeBootServicePath
,
1757 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1759 switch (GetSystemMetrics(SM_CLEANBOOT
))
1761 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1764 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1768 wcscat(szSafeBootServicePath
, L
"\\Network\\");
1772 if (GetSystemMetrics(SM_CLEANBOOT
))
1774 /* If key does not exist then do not assume safe mode */
1775 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1776 szSafeBootServicePath
,
1780 if (dwError
== ERROR_SUCCESS
)
1784 /* Finish Safe Boot path off */
1785 wcsncat(szSafeBootServicePath
,
1786 CurrentService
->lpServiceName
,
1787 MAX_PATH
- wcslen(szSafeBootServicePath
));
1789 /* Check that the key is in the Safe Boot path */
1790 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1791 szSafeBootServicePath
,
1795 if (dwError
!= ERROR_SUCCESS
)
1797 /* Mark service as visited so it is not auto-started */
1798 CurrentService
->ServiceVisited
= TRUE
;
1802 /* Must be auto-started in safe mode - mark as unvisited */
1804 CurrentService
->ServiceVisited
= FALSE
;
1809 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1810 CurrentService
->ServiceVisited
= FALSE
;
1814 ServiceEntry
= ServiceEntry
->Flink
;
1817 /* Start all services which are members of an existing group */
1818 GroupEntry
= GroupListHead
.Flink
;
1819 while (GroupEntry
!= &GroupListHead
)
1821 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1823 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1825 /* Start all services witch have a valid tag */
1826 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1828 ServiceEntry
= ServiceListHead
.Flink
;
1829 while (ServiceEntry
!= &ServiceListHead
)
1831 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1833 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1834 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1835 (CurrentService
->ServiceVisited
== FALSE
) &&
1836 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1838 CurrentService
->ServiceVisited
= TRUE
;
1839 ScmLoadService(CurrentService
, 0, NULL
);
1842 ServiceEntry
= ServiceEntry
->Flink
;
1846 /* Start all services which have an invalid tag or which do not have a tag */
1847 ServiceEntry
= ServiceListHead
.Flink
;
1848 while (ServiceEntry
!= &ServiceListHead
)
1850 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1852 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1853 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1854 (CurrentService
->ServiceVisited
== FALSE
))
1856 CurrentService
->ServiceVisited
= TRUE
;
1857 ScmLoadService(CurrentService
, 0, NULL
);
1860 ServiceEntry
= ServiceEntry
->Flink
;
1863 GroupEntry
= GroupEntry
->Flink
;
1866 /* Start all services which are members of any non-existing group */
1867 ServiceEntry
= ServiceListHead
.Flink
;
1868 while (ServiceEntry
!= &ServiceListHead
)
1870 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1872 if ((CurrentService
->lpGroup
!= NULL
) &&
1873 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1874 (CurrentService
->ServiceVisited
== FALSE
))
1876 CurrentService
->ServiceVisited
= TRUE
;
1877 ScmLoadService(CurrentService
, 0, NULL
);
1880 ServiceEntry
= ServiceEntry
->Flink
;
1883 /* Start all services which are not a member of any group */
1884 ServiceEntry
= ServiceListHead
.Flink
;
1885 while (ServiceEntry
!= &ServiceListHead
)
1887 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1889 if ((CurrentService
->lpGroup
== NULL
) &&
1890 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1891 (CurrentService
->ServiceVisited
== FALSE
))
1893 CurrentService
->ServiceVisited
= TRUE
;
1894 ScmLoadService(CurrentService
, 0, NULL
);
1897 ServiceEntry
= ServiceEntry
->Flink
;
1900 /* Clear 'ServiceVisited' flag again */
1901 ServiceEntry
= ServiceListHead
.Flink
;
1902 while (ServiceEntry
!= &ServiceListHead
)
1904 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1905 CurrentService
->ServiceVisited
= FALSE
;
1906 ServiceEntry
= ServiceEntry
->Flink
;
1910 /* Release the service start lock, if needed, and the critical section */
1911 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1914 LeaveCriticalSection(&ControlServiceCriticalSection
);
1919 ScmAutoShutdownServices(VOID
)
1921 PLIST_ENTRY ServiceEntry
;
1922 PSERVICE CurrentService
;
1924 DPRINT("ScmAutoShutdownServices() called\n");
1926 /* Lock the service database exclusively */
1927 ScmLockDatabaseExclusive();
1929 ServiceEntry
= ServiceListHead
.Flink
;
1930 while (ServiceEntry
!= &ServiceListHead
)
1932 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1934 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1935 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1937 /* shutdown service */
1938 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
1939 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
1942 ServiceEntry
= ServiceEntry
->Flink
;
1945 /* Unlock the service database */
1946 ScmUnlockDatabase();
1948 DPRINT("ScmAutoShutdownServices() done\n");
1953 ScmLockDatabaseExclusive(VOID
)
1955 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1960 ScmLockDatabaseShared(VOID
)
1962 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1967 ScmUnlockDatabase(VOID
)
1969 RtlReleaseResource(&DatabaseLock
);
1974 ScmInitNamedPipeCriticalSection(VOID
)
1980 InitializeCriticalSection(&ControlServiceCriticalSection
);
1982 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1983 L
"SYSTEM\\CurrentControlSet\\Control",
1987 if (dwError
== ERROR_SUCCESS
)
1989 dwKeySize
= sizeof(DWORD
);
1990 RegQueryValueExW(hKey
,
1991 L
"ServicesPipeTimeout",
1994 (LPBYTE
)&PipeTimeout
,
2003 ScmDeleteNamedPipeCriticalSection(VOID
)
2005 DeleteCriticalSection(&ControlServiceCriticalSection
);