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 *****************************************************************/
23 * Uncomment the line below to start services
24 * using the SERVICE_START_PENDING state.
26 #define USE_SERVICE_START_PENDING
29 * Uncomment the line below to use asynchronous IO operations
30 * on the service control pipes.
32 #define USE_ASYNCHRONOUS_IO
35 /* GLOBALS *******************************************************************/
37 LIST_ENTRY ImageListHead
;
38 LIST_ENTRY ServiceListHead
;
40 static RTL_RESOURCE DatabaseLock
;
41 static DWORD ResumeCount
= 1;
43 /* The critical section synchronizes service control requests */
44 static CRITICAL_SECTION ControlServiceCriticalSection
;
45 static DWORD PipeTimeout
= 30000; /* 30 Seconds */
48 /* FUNCTIONS *****************************************************************/
51 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage
)
53 WCHAR szControlPipeName
[MAX_PATH
+ 1];
54 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
55 DWORD ServiceCurrent
= 0;
60 /* Get the service number */
61 /* TODO: Create registry entry with correct write access */
62 dwError
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
63 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
69 if (dwError
!= ERROR_SUCCESS
)
71 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError
);
75 if (KeyDisposition
== REG_OPENED_EXISTING_KEY
)
77 dwKeySize
= sizeof(DWORD
);
78 dwError
= RegQueryValueExW(hServiceCurrentKey
,
79 L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &dwKeySize
);
81 if (dwError
!= ERROR_SUCCESS
)
83 RegCloseKey(hServiceCurrentKey
);
84 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError
);
91 dwError
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
93 RegCloseKey(hServiceCurrentKey
);
95 if (dwError
!= ERROR_SUCCESS
)
97 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError
);
101 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
102 swprintf(szControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent
);
104 DPRINT("PipeName: %S\n", szControlPipeName
);
106 pServiceImage
->hControlPipe
= CreateNamedPipeW(szControlPipeName
,
107 #ifdef USE_ASYNCHRONOUS_IO
108 PIPE_ACCESS_DUPLEX
| FILE_FLAG_OVERLAPPED
,
112 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
118 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName
);
119 if (pServiceImage
->hControlPipe
== INVALID_HANDLE_VALUE
)
121 DPRINT1("Failed to create control pipe!\n");
122 return GetLastError();
125 return ERROR_SUCCESS
;
129 static PSERVICE_IMAGE
130 ScmGetServiceImageByImagePath(LPWSTR lpImagePath
)
132 PLIST_ENTRY ImageEntry
;
133 PSERVICE_IMAGE CurrentImage
;
135 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath
);
137 ImageEntry
= ImageListHead
.Flink
;
138 while (ImageEntry
!= &ImageListHead
)
140 CurrentImage
= CONTAINING_RECORD(ImageEntry
,
143 if (_wcsicmp(CurrentImage
->szImagePath
, lpImagePath
) == 0)
145 DPRINT("Found image: '%S'\n", CurrentImage
->szImagePath
);
149 ImageEntry
= ImageEntry
->Flink
;
152 DPRINT("Couldn't find a matching image\n");
160 ScmCreateOrReferenceServiceImage(PSERVICE pService
)
162 RTL_QUERY_REGISTRY_TABLE QueryTable
[2];
163 UNICODE_STRING ImagePath
;
164 PSERVICE_IMAGE pServiceImage
= NULL
;
166 DWORD dwError
= ERROR_SUCCESS
;
168 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService
);
170 RtlInitUnicodeString(&ImagePath
, NULL
);
172 /* Get service data */
173 RtlZeroMemory(&QueryTable
,
176 QueryTable
[0].Name
= L
"ImagePath";
177 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
178 QueryTable
[0].EntryContext
= &ImagePath
;
180 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
181 pService
->lpServiceName
,
185 if (!NT_SUCCESS(Status
))
187 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
188 return RtlNtStatusToDosError(Status
);
191 DPRINT("ImagePath: '%wZ'\n", &ImagePath
);
193 pServiceImage
= ScmGetServiceImageByImagePath(ImagePath
.Buffer
);
194 if (pServiceImage
== NULL
)
196 /* Create a new service image */
197 pServiceImage
= HeapAlloc(GetProcessHeap(),
199 FIELD_OFFSET(SERVICE_IMAGE
, szImagePath
[ImagePath
.Length
/ sizeof(WCHAR
) + 1]));
200 if (pServiceImage
== NULL
)
202 dwError
= ERROR_NOT_ENOUGH_MEMORY
;
206 pServiceImage
->dwImageRunCount
= 1;
207 pServiceImage
->hControlPipe
= INVALID_HANDLE_VALUE
;
209 /* Set the image path */
210 wcscpy(pServiceImage
->szImagePath
,
213 RtlFreeUnicodeString(&ImagePath
);
215 /* Create the control pipe */
216 dwError
= ScmCreateNewControlPipe(pServiceImage
);
217 if (dwError
!= ERROR_SUCCESS
)
219 HeapFree(GetProcessHeap(), 0, pServiceImage
);
223 /* FIXME: Add more initialization code here */
226 /* Append service record */
227 InsertTailList(&ImageListHead
,
228 &pServiceImage
->ImageListEntry
);
232 /* Increment the run counter */
233 pServiceImage
->dwImageRunCount
++;
236 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage
->dwImageRunCount
);
238 /* Link the service image to the service */
239 pService
->lpImage
= pServiceImage
;
242 RtlFreeUnicodeString(&ImagePath
);
244 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError
);
251 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage
)
253 DPRINT1("ScmDereferenceServiceImage() called\n");
255 pServiceImage
->dwImageRunCount
--;
257 if (pServiceImage
->dwImageRunCount
== 0)
259 DPRINT1("dwImageRunCount == 0\n");
261 /* FIXME: Terminate the process */
263 /* Remove the service image from the list */
264 RemoveEntryList(&pServiceImage
->ImageListEntry
);
266 /* Close the control pipe */
267 if (pServiceImage
->hControlPipe
!= INVALID_HANDLE_VALUE
)
268 CloseHandle(pServiceImage
->hControlPipe
);
270 /* Release the service image */
271 HeapFree(GetProcessHeap(), 0, pServiceImage
);
277 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
279 PLIST_ENTRY ServiceEntry
;
280 PSERVICE CurrentService
;
282 DPRINT("ScmGetServiceEntryByName() called\n");
284 ServiceEntry
= ServiceListHead
.Flink
;
285 while (ServiceEntry
!= &ServiceListHead
)
287 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
290 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
292 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
293 return CurrentService
;
296 ServiceEntry
= ServiceEntry
->Flink
;
299 DPRINT("Couldn't find a matching service\n");
306 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
308 PLIST_ENTRY ServiceEntry
;
309 PSERVICE CurrentService
;
311 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
313 ServiceEntry
= ServiceListHead
.Flink
;
314 while (ServiceEntry
!= &ServiceListHead
)
316 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
319 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
321 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
322 return CurrentService
;
325 ServiceEntry
= ServiceEntry
->Flink
;
328 DPRINT("Couldn't find a matching service\n");
335 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
337 PLIST_ENTRY ServiceEntry
;
338 PSERVICE CurrentService
;
340 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
342 ServiceEntry
= ServiceListHead
.Flink
;
343 while (ServiceEntry
!= &ServiceListHead
)
345 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
348 if (CurrentService
->dwResumeCount
> dwResumeCount
)
350 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
351 return CurrentService
;
354 ServiceEntry
= ServiceEntry
->Flink
;
357 DPRINT("Couldn't find a matching service\n");
364 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
365 PSERVICE
* lpServiceRecord
)
367 PSERVICE lpService
= NULL
;
369 DPRINT("Service: '%S'\n", lpServiceName
);
371 /* Allocate service entry */
372 lpService
= HeapAlloc(GetProcessHeap(),
374 FIELD_OFFSET(SERVICE
, szServiceName
[wcslen(lpServiceName
) + 1]));
375 if (lpService
== NULL
)
376 return ERROR_NOT_ENOUGH_MEMORY
;
378 *lpServiceRecord
= lpService
;
380 /* Copy service name */
381 wcscpy(lpService
->szServiceName
, lpServiceName
);
382 lpService
->lpServiceName
= lpService
->szServiceName
;
383 lpService
->lpDisplayName
= lpService
->lpServiceName
;
385 /* Set the resume count */
386 lpService
->dwResumeCount
= ResumeCount
++;
388 /* Append service record */
389 InsertTailList(&ServiceListHead
,
390 &lpService
->ServiceListEntry
);
392 /* Initialize the service status */
393 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
394 lpService
->Status
.dwControlsAccepted
= 0;
395 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
396 lpService
->Status
.dwServiceSpecificExitCode
= 0;
397 lpService
->Status
.dwCheckPoint
= 0;
398 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
400 return ERROR_SUCCESS
;
405 ScmDeleteServiceRecord(PSERVICE lpService
)
407 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
409 /* Delete the display name */
410 if (lpService
->lpDisplayName
!= NULL
&&
411 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
412 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
414 /* Dereference the service image */
415 if (lpService
->lpImage
)
416 ScmDereferenceServiceImage(lpService
->lpImage
);
418 /* Decrement the group reference counter */
419 ScmSetServiceGroup(lpService
, NULL
);
421 /* FIXME: SecurityDescriptor */
424 /* Remove the Service from the List */
425 RemoveEntryList(&lpService
->ServiceListEntry
);
427 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
429 /* Delete the service record */
430 HeapFree(GetProcessHeap(), 0, lpService
);
437 CreateServiceListEntry(LPCWSTR lpServiceName
,
440 PSERVICE lpService
= NULL
;
441 LPWSTR lpDisplayName
= NULL
;
442 LPWSTR lpGroup
= NULL
;
447 DWORD dwErrorControl
;
450 DPRINT("Service: '%S'\n", lpServiceName
);
451 if (*lpServiceName
== L
'{')
452 return ERROR_SUCCESS
;
454 dwSize
= sizeof(DWORD
);
455 dwError
= RegQueryValueExW(hServiceKey
,
459 (LPBYTE
)&dwServiceType
,
461 if (dwError
!= ERROR_SUCCESS
)
462 return ERROR_SUCCESS
;
464 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
465 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
466 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
467 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
468 return ERROR_SUCCESS
;
470 DPRINT("Service type: %lx\n", dwServiceType
);
472 dwSize
= sizeof(DWORD
);
473 dwError
= RegQueryValueExW(hServiceKey
,
477 (LPBYTE
)&dwStartType
,
479 if (dwError
!= ERROR_SUCCESS
)
480 return ERROR_SUCCESS
;
482 DPRINT("Start type: %lx\n", dwStartType
);
484 dwSize
= sizeof(DWORD
);
485 dwError
= RegQueryValueExW(hServiceKey
,
489 (LPBYTE
)&dwErrorControl
,
491 if (dwError
!= ERROR_SUCCESS
)
492 return ERROR_SUCCESS
;
494 DPRINT("Error control: %lx\n", dwErrorControl
);
496 dwError
= RegQueryValueExW(hServiceKey
,
502 if (dwError
!= ERROR_SUCCESS
)
505 DPRINT("Tag: %lx\n", dwTagId
);
507 dwError
= ScmReadString(hServiceKey
,
510 if (dwError
!= ERROR_SUCCESS
)
513 DPRINT("Group: %S\n", lpGroup
);
515 dwError
= ScmReadString(hServiceKey
,
518 if (dwError
!= ERROR_SUCCESS
)
519 lpDisplayName
= NULL
;
521 DPRINT("Display name: %S\n", lpDisplayName
);
523 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
525 if (dwError
!= ERROR_SUCCESS
)
528 lpService
->Status
.dwServiceType
= dwServiceType
;
529 lpService
->dwStartType
= dwStartType
;
530 lpService
->dwErrorControl
= dwErrorControl
;
531 lpService
->dwTag
= dwTagId
;
535 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
536 if (dwError
!= ERROR_SUCCESS
)
540 if (lpDisplayName
!= NULL
)
542 lpService
->lpDisplayName
= lpDisplayName
;
543 lpDisplayName
= NULL
;
546 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
547 if (lpService
->lpGroup
!= NULL
)
549 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
551 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
552 lpService
->dwStartType
,
553 lpService
->Status
.dwServiceType
,
555 lpService
->dwErrorControl
);
557 if (ScmIsDeleteFlagSet(hServiceKey
))
558 lpService
->bDeleted
= TRUE
;
562 HeapFree(GetProcessHeap(), 0, lpGroup
);
564 if (lpDisplayName
!= NULL
)
565 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
567 if (lpService
!= NULL
)
569 if (lpService
->lpImage
!= NULL
)
570 ScmDereferenceServiceImage(lpService
->lpImage
);
578 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
580 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
581 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
584 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
587 /* Find the maximum subkey length so that we can allocate a buffer */
588 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
589 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
593 if (dwMaxSubkeyLen
> sizeof(szNameBuf
) / sizeof(WCHAR
))
595 /* Name too big: alloc a buffer for it */
596 lpszName
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, dwMaxSubkeyLen
* sizeof(WCHAR
));
600 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
603 while (dwRet
== ERROR_SUCCESS
)
605 dwSize
= dwMaxSubkeyLen
;
606 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
607 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
608 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
610 if (dwRet
== ERROR_NO_MORE_ITEMS
)
611 dwRet
= ERROR_SUCCESS
;
613 if (lpszName
!= szNameBuf
)
614 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
618 RegCloseKey(hSubKey
);
620 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
627 ScmDeleteMarkedServices(VOID
)
629 PLIST_ENTRY ServiceEntry
;
630 PSERVICE CurrentService
;
634 ServiceEntry
= ServiceListHead
.Flink
;
635 while (ServiceEntry
!= &ServiceListHead
)
637 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
639 ServiceEntry
= ServiceEntry
->Flink
;
641 if (CurrentService
->bDeleted
== TRUE
)
643 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
644 L
"System\\CurrentControlSet\\Services",
648 if (dwError
== ERROR_SUCCESS
)
650 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
651 RegCloseKey(hServicesKey
);
652 if (dwError
== ERROR_SUCCESS
)
654 RemoveEntryList(&CurrentService
->ServiceListEntry
);
655 HeapFree(GetProcessHeap(), 0, CurrentService
);
659 if (dwError
!= ERROR_SUCCESS
)
660 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
667 ScmCreateServiceDatabase(VOID
)
669 WCHAR szSubKey
[MAX_PATH
];
673 DWORD dwSubKeyLength
;
674 FILETIME ftLastChanged
;
677 DPRINT("ScmCreateServiceDatabase() called\n");
679 dwError
= ScmCreateGroupList();
680 if (dwError
!= ERROR_SUCCESS
)
683 /* Initialize basic variables */
684 InitializeListHead(&ImageListHead
);
685 InitializeListHead(&ServiceListHead
);
687 /* Initialize the database lock */
688 RtlInitializeResource(&DatabaseLock
);
690 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
691 L
"System\\CurrentControlSet\\Services",
695 if (dwError
!= ERROR_SUCCESS
)
701 dwSubKeyLength
= MAX_PATH
;
702 dwError
= RegEnumKeyExW(hServicesKey
,
710 if (dwError
== ERROR_SUCCESS
&&
713 DPRINT("SubKeyName: '%S'\n", szSubKey
);
715 dwError
= RegOpenKeyExW(hServicesKey
,
720 if (dwError
== ERROR_SUCCESS
)
722 dwError
= CreateServiceListEntry(szSubKey
,
725 RegCloseKey(hServiceKey
);
729 if (dwError
!= ERROR_SUCCESS
)
735 RegCloseKey(hServicesKey
);
737 /* Wait for the LSA server */
740 /* Delete services that are marked for delete */
741 ScmDeleteMarkedServices();
743 DPRINT("ScmCreateServiceDatabase() done\n");
745 return ERROR_SUCCESS
;
750 ScmShutdownServiceDatabase(VOID
)
752 DPRINT("ScmShutdownServiceDatabase() called\n");
754 ScmDeleteMarkedServices();
755 RtlDeleteResource(&DatabaseLock
);
757 DPRINT("ScmShutdownServiceDatabase() done\n");
762 ScmCheckDriver(PSERVICE Service
)
764 OBJECT_ATTRIBUTES ObjectAttributes
;
765 UNICODE_STRING DirName
;
768 POBJECT_DIRECTORY_INFORMATION DirInfo
;
773 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
775 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
777 RtlInitUnicodeString(&DirName
, L
"\\Driver");
779 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
781 ASSERT(Service
->Status
.dwServiceType
== SERVICE_FILE_SYSTEM_DRIVER
);
782 RtlInitUnicodeString(&DirName
, L
"\\FileSystem");
785 InitializeObjectAttributes(&ObjectAttributes
,
791 Status
= NtOpenDirectoryObject(&DirHandle
,
792 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
794 if (!NT_SUCCESS(Status
))
799 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
800 2 * MAX_PATH
* sizeof(WCHAR
);
801 DirInfo
= HeapAlloc(GetProcessHeap(),
808 Status
= NtQueryDirectoryObject(DirHandle
,
815 if (Status
== STATUS_NO_MORE_ENTRIES
)
817 /* FIXME: Add current service to 'failed service' list */
818 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
822 if (!NT_SUCCESS(Status
))
825 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
827 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
829 DPRINT("Found: '%S' '%wZ'\n",
830 Service
->lpServiceName
, &DirInfo
->Name
);
832 /* Mark service as 'running' */
833 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
835 /* Mark the service group as 'running' */
836 if (Service
->lpGroup
!= NULL
)
838 Service
->lpGroup
->ServicesRunning
= TRUE
;
845 HeapFree(GetProcessHeap(),
850 return STATUS_SUCCESS
;
855 ScmGetBootAndSystemDriverState(VOID
)
857 PLIST_ENTRY ServiceEntry
;
858 PSERVICE CurrentService
;
860 DPRINT("ScmGetBootAndSystemDriverState() called\n");
862 ServiceEntry
= ServiceListHead
.Flink
;
863 while (ServiceEntry
!= &ServiceListHead
)
865 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
867 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
868 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
871 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
873 ScmCheckDriver(CurrentService
);
876 ServiceEntry
= ServiceEntry
->Flink
;
879 DPRINT("ScmGetBootAndSystemDriverState() done\n");
884 ScmControlService(PSERVICE Service
,
887 PSCM_CONTROL_PACKET ControlPacket
;
888 SCM_REPLY_PACKET ReplyPacket
;
890 DWORD dwWriteCount
= 0;
891 DWORD dwReadCount
= 0;
894 DWORD dwError
= ERROR_SUCCESS
;
896 #ifdef USE_ASYNCHRONOUS_IO
897 OVERLAPPED Overlapped
= {0};
900 DPRINT("ScmControlService() called\n");
902 /* Acquire the service control critical section, to synchronize requests */
903 EnterCriticalSection(&ControlServiceCriticalSection
);
905 /* Calculate the total length of the start command line */
906 PacketSize
= sizeof(SCM_CONTROL_PACKET
);
907 PacketSize
+= (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
909 ControlPacket
= HeapAlloc(GetProcessHeap(),
912 if (ControlPacket
== NULL
)
914 LeaveCriticalSection(&ControlServiceCriticalSection
);
915 return ERROR_NOT_ENOUGH_MEMORY
;
918 ControlPacket
->dwSize
= PacketSize
;
919 ControlPacket
->dwControl
= dwControl
;
920 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
922 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
924 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
925 wcscpy(Ptr
, Service
->lpServiceName
);
927 ControlPacket
->dwArgumentsCount
= 0;
928 ControlPacket
->dwArgumentsOffset
= 0;
930 #ifdef USE_ASYNCHRONOUS_IO
931 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
936 if (bResult
== FALSE
)
938 DPRINT("WriteFile() returned FALSE\n");
940 dwError
= GetLastError();
941 if (dwError
== ERROR_IO_PENDING
)
943 DPRINT("dwError: ERROR_IO_PENDING\n");
945 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
947 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
949 if (dwError
== WAIT_TIMEOUT
)
951 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
952 if (bResult
== FALSE
)
954 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
957 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
960 else if (dwError
== WAIT_OBJECT_0
)
962 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
966 if (bResult
== FALSE
)
968 dwError
= GetLastError();
969 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
977 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
983 Overlapped
.hEvent
= (HANDLE
) NULL
;
985 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
987 sizeof(SCM_REPLY_PACKET
),
990 if (bResult
== FALSE
)
992 DPRINT("ReadFile() returned FALSE\n");
994 dwError
= GetLastError();
995 if (dwError
== ERROR_IO_PENDING
)
997 DPRINT("dwError: ERROR_IO_PENDING\n");
999 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1001 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1003 if (dwError
== WAIT_TIMEOUT
)
1005 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1006 if (bResult
== FALSE
)
1008 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1011 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1014 else if (dwError
== WAIT_OBJECT_0
)
1016 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1020 if (bResult
== FALSE
)
1022 dwError
= GetLastError();
1023 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1031 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1037 /* Send the control packet */
1038 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1043 if (bResult
== FALSE
)
1045 dwError
= GetLastError();
1046 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1048 if ((dwError
== ERROR_GEN_FAILURE
) &&
1049 (dwControl
== SERVICE_CONTROL_STOP
))
1051 /* Service is already terminated */
1052 Service
->Status
.dwCurrentState
= SERVICE_STOPPED
;
1053 Service
->Status
.dwControlsAccepted
= 0;
1054 Service
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NOT_ACTIVE
;
1055 dwError
= ERROR_SUCCESS
;
1060 /* Read the reply */
1061 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1063 sizeof(SCM_REPLY_PACKET
),
1066 if (bResult
== FALSE
)
1068 dwError
= GetLastError();
1069 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1074 /* Release the contol packet */
1075 HeapFree(GetProcessHeap(),
1079 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1081 dwError
= ReplyPacket
.dwError
;
1084 if (dwError
== ERROR_SUCCESS
&&
1085 dwControl
== SERVICE_CONTROL_STOP
)
1087 ScmDereferenceServiceImage(Service
->lpImage
);
1090 LeaveCriticalSection(&ControlServiceCriticalSection
);
1092 DPRINT("ScmControlService() done\n");
1099 ScmSendStartCommand(PSERVICE Service
,
1103 PSCM_CONTROL_PACKET ControlPacket
;
1104 SCM_REPLY_PACKET ReplyPacket
;
1107 DWORD dwWriteCount
= 0;
1108 DWORD dwReadCount
= 0;
1109 DWORD dwError
= ERROR_SUCCESS
;
1114 #ifdef USE_ASYNCHRONOUS_IO
1115 OVERLAPPED Overlapped
= {0};
1118 DPRINT("ScmSendStartCommand() called\n");
1120 /* Calculate the total length of the start command line */
1121 PacketSize
= sizeof(SCM_CONTROL_PACKET
) +
1122 (DWORD
)((wcslen(Service
->lpServiceName
) + 1) * sizeof(WCHAR
));
1124 /* Calculate the required packet size for the start arguments */
1125 if (argc
> 0 && argv
!= NULL
)
1127 PacketSize
= ALIGN_UP(PacketSize
, LPWSTR
);
1129 DPRINT("Argc: %lu\n", argc
);
1130 for (i
= 0; i
< argc
; i
++)
1132 DPRINT("Argv[%lu]: %S\n", i
, argv
[i
]);
1133 PacketSize
+= (DWORD
)((wcslen(argv
[i
]) + 1) * sizeof(WCHAR
) + sizeof(PWSTR
));
1137 /* Allocate a control packet */
1138 ControlPacket
= HeapAlloc(GetProcessHeap(),
1141 if (ControlPacket
== NULL
)
1142 return ERROR_NOT_ENOUGH_MEMORY
;
1144 ControlPacket
->dwSize
= PacketSize
;
1145 ControlPacket
->dwControl
= (Service
->Status
.dwServiceType
& SERVICE_WIN32_OWN_PROCESS
)
1146 ? SERVICE_CONTROL_START_OWN
1147 : SERVICE_CONTROL_START_SHARE
;
1148 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
1149 ControlPacket
->dwServiceNameOffset
= sizeof(SCM_CONTROL_PACKET
);
1151 Ptr
= (PWSTR
)((PBYTE
)ControlPacket
+ ControlPacket
->dwServiceNameOffset
);
1152 wcscpy(Ptr
, Service
->lpServiceName
);
1154 ControlPacket
->dwArgumentsCount
= 0;
1155 ControlPacket
->dwArgumentsOffset
= 0;
1157 /* Copy argument list */
1158 if (argc
> 0 && argv
!= NULL
)
1160 Ptr
+= wcslen(Service
->lpServiceName
) + 1;
1161 pOffPtr
= (PWSTR
*)ALIGN_UP_POINTER(Ptr
, PWSTR
);
1162 pArgPtr
= (PWSTR
)((ULONG_PTR
)pOffPtr
+ argc
* sizeof(PWSTR
));
1164 ControlPacket
->dwArgumentsCount
= argc
;
1165 ControlPacket
->dwArgumentsOffset
= (DWORD
)((ULONG_PTR
)pOffPtr
- (ULONG_PTR
)ControlPacket
);
1167 DPRINT("dwArgumentsCount: %lu\n", ControlPacket
->dwArgumentsCount
);
1168 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket
->dwArgumentsOffset
);
1170 for (i
= 0; i
< argc
; i
++)
1172 wcscpy(pArgPtr
, argv
[i
]);
1173 *pOffPtr
= (PWSTR
)((ULONG_PTR
)pArgPtr
- (ULONG_PTR
)pOffPtr
);
1174 DPRINT("offset: %p\n", *pOffPtr
);
1176 pArgPtr
+= wcslen(argv
[i
]) + 1;
1181 #ifdef USE_ASYNCHRONOUS_IO
1182 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1187 if (bResult
== FALSE
)
1189 DPRINT("WriteFile() returned FALSE\n");
1191 dwError
= GetLastError();
1192 if (dwError
== ERROR_IO_PENDING
)
1194 DPRINT("dwError: ERROR_IO_PENDING\n");
1196 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1198 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1200 if (dwError
== WAIT_TIMEOUT
)
1202 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1203 if (bResult
== FALSE
)
1205 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1208 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1211 else if (dwError
== WAIT_OBJECT_0
)
1213 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1217 if (bResult
== FALSE
)
1219 dwError
= GetLastError();
1220 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1228 DPRINT1("WriteFile() failed (Error %lu)\n", dwError
);
1233 /* Read the reply */
1234 Overlapped
.hEvent
= (HANDLE
) NULL
;
1236 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1238 sizeof(SCM_REPLY_PACKET
),
1241 if (bResult
== FALSE
)
1243 DPRINT("ReadFile() returned FALSE\n");
1245 dwError
= GetLastError();
1246 if (dwError
== ERROR_IO_PENDING
)
1248 DPRINT("dwError: ERROR_IO_PENDING\n");
1250 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1252 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1254 if (dwError
== WAIT_TIMEOUT
)
1256 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1257 if (bResult
== FALSE
)
1259 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1262 dwError
= ERROR_SERVICE_REQUEST_TIMEOUT
;
1265 else if (dwError
== WAIT_OBJECT_0
)
1267 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1271 if (bResult
== FALSE
)
1273 dwError
= GetLastError();
1274 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1282 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1288 /* Send the start command */
1289 bResult
= WriteFile(Service
->lpImage
->hControlPipe
,
1294 if (bResult
== FALSE
)
1296 dwError
= GetLastError();
1297 DPRINT("WriteFile() failed (Error %lu)\n", dwError
);
1301 /* Read the reply */
1302 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1304 sizeof(SCM_REPLY_PACKET
),
1307 if (bResult
== FALSE
)
1309 dwError
= GetLastError();
1310 DPRINT("ReadFile() failed (Error %lu)\n", dwError
);
1315 /* Release the contol packet */
1316 HeapFree(GetProcessHeap(),
1320 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
1322 dwError
= ReplyPacket
.dwError
;
1325 DPRINT("ScmSendStartCommand() done\n");
1332 ScmWaitForServiceConnect(PSERVICE Service
)
1335 DWORD dwProcessId
= 0;
1336 DWORD dwError
= ERROR_SUCCESS
;
1338 #ifdef USE_ASYNCHRONOUS_IO
1339 OVERLAPPED Overlapped
= {0};
1342 LPCWSTR lpLogStrings
[3];
1343 WCHAR szBuffer1
[20];
1344 WCHAR szBuffer2
[20];
1347 DPRINT("ScmWaitForServiceConnect()\n");
1349 #ifdef USE_ASYNCHRONOUS_IO
1350 Overlapped
.hEvent
= (HANDLE
)NULL
;
1352 bResult
= ConnectNamedPipe(Service
->lpImage
->hControlPipe
,
1354 if (bResult
== FALSE
)
1356 DPRINT("ConnectNamedPipe() returned FALSE\n");
1358 dwError
= GetLastError();
1359 if (dwError
== ERROR_IO_PENDING
)
1361 DPRINT("dwError: ERROR_IO_PENDING\n");
1363 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1365 DPRINT("WaitForSingleObject() returned %lu\n", dwError
);
1367 if (dwError
== WAIT_TIMEOUT
)
1369 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1371 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1372 if (bResult
== FALSE
)
1374 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1378 _ultow(PipeTimeout
, szBuffer1
, 10);
1379 lpLogStrings
[0] = Service
->lpDisplayName
;
1380 lpLogStrings
[1] = szBuffer1
;
1382 ScmLogEvent(EVENT_CONNECTION_TIMEOUT
,
1383 EVENTLOG_ERROR_TYPE
,
1387 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service
->lpDisplayName
);
1389 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1391 else if (dwError
== WAIT_OBJECT_0
)
1393 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1397 if (bResult
== FALSE
)
1399 dwError
= GetLastError();
1400 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError
);
1406 else if (dwError
!= ERROR_PIPE_CONNECTED
)
1408 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError
);
1413 DPRINT("Control pipe connected!\n");
1415 Overlapped
.hEvent
= (HANDLE
) NULL
;
1417 /* Read the process id from pipe */
1418 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1419 (LPVOID
)&dwProcessId
,
1423 if (bResult
== FALSE
)
1425 DPRINT("ReadFile() returned FALSE\n");
1427 dwError
= GetLastError();
1428 if (dwError
== ERROR_IO_PENDING
)
1430 DPRINT("dwError: ERROR_IO_PENDING\n");
1432 dwError
= WaitForSingleObject(Service
->lpImage
->hControlPipe
,
1434 if (dwError
== WAIT_TIMEOUT
)
1436 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
1438 bResult
= CancelIo(Service
->lpImage
->hControlPipe
);
1439 if (bResult
== FALSE
)
1441 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
1445 _ultow(PipeTimeout
, szBuffer1
, 10);
1446 lpLogStrings
[0] = szBuffer1
;
1448 ScmLogEvent(EVENT_READFILE_TIMEOUT
,
1449 EVENTLOG_ERROR_TYPE
,
1453 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service
->lpDisplayName
);
1455 return ERROR_SERVICE_REQUEST_TIMEOUT
;
1457 else if (dwError
== WAIT_OBJECT_0
)
1459 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
1461 DPRINT("Process Id: %lu\n", dwProcessId
);
1463 bResult
= GetOverlappedResult(Service
->lpImage
->hControlPipe
,
1467 if (bResult
== FALSE
)
1469 dwError
= GetLastError();
1470 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError
);
1477 DPRINT1("WaitForSingleObject() returned %lu\n", dwError
);
1482 DPRINT1("ReadFile() failed (Error %lu)\n", dwError
);
1487 if (dwProcessId
!= Service
->lpImage
->dwProcessId
)
1490 _ultow(Service
->lpImage
->dwProcessId
, szBuffer1
, 10);
1491 _ultow(dwProcessId
, szBuffer2
, 10);
1493 lpLogStrings
[0] = Service
->lpDisplayName
;
1494 lpLogStrings
[1] = szBuffer1
;
1495 lpLogStrings
[2] = szBuffer2
;
1497 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED
,
1498 EVENTLOG_WARNING_TYPE
,
1503 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service
->lpDisplayName
);
1506 DPRINT("ScmWaitForServiceConnect() done\n");
1508 return ERROR_SUCCESS
;
1511 /* Connect control pipe */
1512 if (ConnectNamedPipe(Service
->lpImage
->hControlPipe
, NULL
) ?
1513 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
1515 DPRINT("Control pipe connected!\n");
1517 /* Read SERVICE_STATUS_HANDLE from pipe */
1518 bResult
= ReadFile(Service
->lpImage
->hControlPipe
,
1519 (LPVOID
)&dwProcessId
,
1523 if (bResult
== FALSE
)
1525 dwError
= GetLastError();
1526 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1531 dwError
= ERROR_SUCCESS
;
1532 DPRINT("Read control pipe successfully\n");
1537 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1546 ScmStartUserModeService(PSERVICE Service
,
1550 PROCESS_INFORMATION ProcessInformation
;
1551 STARTUPINFOW StartupInfo
;
1553 DWORD dwError
= ERROR_SUCCESS
;
1555 DPRINT("ScmStartUserModeService(%p)\n", Service
);
1557 /* If the image is already running ... */
1558 if (Service
->lpImage
->dwImageRunCount
> 1)
1560 /* ... just send a start command */
1561 return ScmSendStartCommand(Service
, argc
, argv
);
1564 /* Otherwise start its process */
1565 ZeroMemory(&StartupInfo
, sizeof(StartupInfo
));
1566 StartupInfo
.cb
= sizeof(StartupInfo
);
1567 ZeroMemory(&ProcessInformation
, sizeof(ProcessInformation
));
1569 Result
= CreateProcessW(NULL
,
1570 Service
->lpImage
->szImagePath
,
1574 DETACHED_PROCESS
| CREATE_SUSPENDED
,
1578 &ProcessInformation
);
1581 dwError
= GetLastError();
1582 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
1586 DPRINT("Process Id: %lu Handle %p\n",
1587 ProcessInformation
.dwProcessId
,
1588 ProcessInformation
.hProcess
);
1589 DPRINT("Thread Id: %lu Handle %p\n",
1590 ProcessInformation
.dwThreadId
,
1591 ProcessInformation
.hThread
);
1593 /* Get process handle and id */
1594 Service
->lpImage
->dwProcessId
= ProcessInformation
.dwProcessId
;
1597 ResumeThread(ProcessInformation
.hThread
);
1599 /* Connect control pipe */
1600 dwError
= ScmWaitForServiceConnect(Service
);
1601 if (dwError
== ERROR_SUCCESS
)
1603 /* Send start command */
1604 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1608 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1609 Service
->lpImage
->dwProcessId
= 0;
1612 /* Close thread and process handle */
1613 CloseHandle(ProcessInformation
.hThread
);
1614 CloseHandle(ProcessInformation
.hProcess
);
1621 ScmLoadService(PSERVICE Service
,
1625 PSERVICE_GROUP Group
= Service
->lpGroup
;
1626 DWORD dwError
= ERROR_SUCCESS
;
1627 LPCWSTR lpLogStrings
[2];
1628 WCHAR szLogBuffer
[80];
1630 DPRINT("ScmLoadService() called\n");
1631 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1633 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1635 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1636 return ERROR_SERVICE_ALREADY_RUNNING
;
1639 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1641 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1644 dwError
= ScmLoadDriver(Service
);
1645 if (dwError
== ERROR_SUCCESS
)
1647 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1648 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1651 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
1653 /* Start user-mode service */
1654 dwError
= ScmCreateOrReferenceServiceImage(Service
);
1655 if (dwError
== ERROR_SUCCESS
)
1657 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1658 if (dwError
== ERROR_SUCCESS
)
1660 #ifdef USE_SERVICE_START_PENDING
1661 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1663 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1668 ScmDereferenceServiceImage(Service
->lpImage
);
1669 Service
->lpImage
= NULL
;
1674 DPRINT("ScmLoadService() done (Error %lu)\n", dwError
);
1676 if (dwError
== ERROR_SUCCESS
)
1680 Group
->ServicesRunning
= TRUE
;
1683 /* Log a successful service start */
1684 LoadStringW(GetModuleHandle(NULL
), IDS_SERVICE_START
, szLogBuffer
, 80);
1685 lpLogStrings
[0] = Service
->lpDisplayName
;
1686 lpLogStrings
[1] = szLogBuffer
;
1688 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS
,
1689 EVENTLOG_INFORMATION_TYPE
,
1695 if (Service
->dwErrorControl
!= SERVICE_ERROR_IGNORE
)
1697 /* Log a failed service start */
1698 swprintf(szLogBuffer
, L
"%lu", dwError
);
1699 lpLogStrings
[0] = Service
->lpServiceName
;
1700 lpLogStrings
[1] = szLogBuffer
;
1701 ScmLogEvent(EVENT_SERVICE_START_FAILED
,
1702 EVENTLOG_ERROR_TYPE
,
1708 switch (Service
->dwErrorControl
)
1710 case SERVICE_ERROR_SEVERE
:
1711 if (IsLastKnownGood
== FALSE
)
1713 /* FIXME: Boot last known good configuration */
1717 case SERVICE_ERROR_CRITICAL
:
1718 if (IsLastKnownGood
== FALSE
)
1720 /* FIXME: Boot last known good configuration */
1736 ScmStartService(PSERVICE Service
,
1740 DWORD dwError
= ERROR_SUCCESS
;
1741 SC_RPC_LOCK Lock
= NULL
;
1743 DPRINT("ScmStartService() called\n");
1744 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1746 /* Acquire the service control critical section, to synchronize starts */
1747 EnterCriticalSection(&ControlServiceCriticalSection
);
1750 * Acquire the user service start lock while the service is starting, if
1751 * needed (i.e. if we are not starting it during the initialization phase).
1752 * If we don't success, bail out.
1756 dwError
= ScmAcquireServiceStartLock(TRUE
, &Lock
);
1757 if (dwError
!= ERROR_SUCCESS
) goto done
;
1760 /* Really start the service */
1761 dwError
= ScmLoadService(Service
, argc
, argv
);
1763 /* Release the service start lock, if needed, and the critical section */
1764 if (Lock
) ScmReleaseServiceStartLock(&Lock
);
1767 LeaveCriticalSection(&ControlServiceCriticalSection
);
1769 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1776 ScmAutoStartServices(VOID
)
1779 PLIST_ENTRY GroupEntry
;
1780 PLIST_ENTRY ServiceEntry
;
1781 PSERVICE_GROUP CurrentGroup
;
1782 PSERVICE CurrentService
;
1783 WCHAR szSafeBootServicePath
[MAX_PATH
];
1784 DWORD SafeBootEnabled
;
1790 * This function MUST be called ONLY at initialization time.
1791 * Therefore, no need to acquire the user service start lock.
1793 ASSERT(ScmInitialize
);
1796 * Retrieve the SafeBoot parameter.
1798 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1799 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option",
1803 if (dwError
== ERROR_SUCCESS
)
1805 dwKeySize
= sizeof(SafeBootEnabled
);
1806 dwError
= RegQueryValueExW(hKey
,
1810 (LPBYTE
)&SafeBootEnabled
,
1815 /* Default to Normal boot if the value doesn't exist */
1816 if (dwError
!= ERROR_SUCCESS
)
1817 SafeBootEnabled
= 0;
1819 /* Acquire the service control critical section, to synchronize starts */
1820 EnterCriticalSection(&ControlServiceCriticalSection
);
1822 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1823 ServiceEntry
= ServiceListHead
.Flink
;
1824 while (ServiceEntry
!= &ServiceListHead
)
1826 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1828 /* Build the safe boot path */
1829 wcscpy(szSafeBootServicePath
,
1830 L
"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1832 switch (SafeBootEnabled
)
1834 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1837 wcscat(szSafeBootServicePath
, L
"\\Minimal\\");
1841 wcscat(szSafeBootServicePath
, L
"\\Network\\");
1845 if (SafeBootEnabled
!= 0)
1847 /* If key does not exist then do not assume safe mode */
1848 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1849 szSafeBootServicePath
,
1853 if (dwError
== ERROR_SUCCESS
)
1857 /* Finish Safe Boot path off */
1858 wcsncat(szSafeBootServicePath
,
1859 CurrentService
->lpServiceName
,
1860 MAX_PATH
- wcslen(szSafeBootServicePath
));
1862 /* Check that the key is in the Safe Boot path */
1863 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
1864 szSafeBootServicePath
,
1868 if (dwError
!= ERROR_SUCCESS
)
1870 /* Mark service as visited so it is not auto-started */
1871 CurrentService
->ServiceVisited
= TRUE
;
1875 /* Must be auto-started in safe mode - mark as unvisited */
1877 CurrentService
->ServiceVisited
= FALSE
;
1882 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1883 CurrentService
->ServiceVisited
= FALSE
;
1887 ServiceEntry
= ServiceEntry
->Flink
;
1890 /* Start all services which are members of an existing group */
1891 GroupEntry
= GroupListHead
.Flink
;
1892 while (GroupEntry
!= &GroupListHead
)
1894 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1896 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1898 /* Start all services witch have a valid tag */
1899 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1901 ServiceEntry
= ServiceListHead
.Flink
;
1902 while (ServiceEntry
!= &ServiceListHead
)
1904 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1906 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1907 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1908 (CurrentService
->ServiceVisited
== FALSE
) &&
1909 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1911 CurrentService
->ServiceVisited
= TRUE
;
1912 ScmLoadService(CurrentService
, 0, NULL
);
1915 ServiceEntry
= ServiceEntry
->Flink
;
1919 /* Start all services which have an invalid tag or which do not have a tag */
1920 ServiceEntry
= ServiceListHead
.Flink
;
1921 while (ServiceEntry
!= &ServiceListHead
)
1923 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1925 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1926 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1927 (CurrentService
->ServiceVisited
== FALSE
))
1929 CurrentService
->ServiceVisited
= TRUE
;
1930 ScmLoadService(CurrentService
, 0, NULL
);
1933 ServiceEntry
= ServiceEntry
->Flink
;
1936 GroupEntry
= GroupEntry
->Flink
;
1939 /* Start all services which are members of any non-existing group */
1940 ServiceEntry
= ServiceListHead
.Flink
;
1941 while (ServiceEntry
!= &ServiceListHead
)
1943 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1945 if ((CurrentService
->lpGroup
!= NULL
) &&
1946 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1947 (CurrentService
->ServiceVisited
== FALSE
))
1949 CurrentService
->ServiceVisited
= TRUE
;
1950 ScmLoadService(CurrentService
, 0, NULL
);
1953 ServiceEntry
= ServiceEntry
->Flink
;
1956 /* Start all services which are not a member of any group */
1957 ServiceEntry
= ServiceListHead
.Flink
;
1958 while (ServiceEntry
!= &ServiceListHead
)
1960 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1962 if ((CurrentService
->lpGroup
== NULL
) &&
1963 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1964 (CurrentService
->ServiceVisited
== FALSE
))
1966 CurrentService
->ServiceVisited
= TRUE
;
1967 ScmLoadService(CurrentService
, 0, NULL
);
1970 ServiceEntry
= ServiceEntry
->Flink
;
1973 /* Clear 'ServiceVisited' flag again */
1974 ServiceEntry
= ServiceListHead
.Flink
;
1975 while (ServiceEntry
!= &ServiceListHead
)
1977 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1978 CurrentService
->ServiceVisited
= FALSE
;
1979 ServiceEntry
= ServiceEntry
->Flink
;
1982 /* Release the critical section */
1983 LeaveCriticalSection(&ControlServiceCriticalSection
);
1988 ScmAutoShutdownServices(VOID
)
1990 PLIST_ENTRY ServiceEntry
;
1991 PSERVICE CurrentService
;
1993 DPRINT("ScmAutoShutdownServices() called\n");
1995 /* Lock the service database exclusively */
1996 ScmLockDatabaseExclusive();
1998 ServiceEntry
= ServiceListHead
.Flink
;
1999 while (ServiceEntry
!= &ServiceListHead
)
2001 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
2003 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
2004 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
2006 /* shutdown service */
2007 DPRINT("Shutdown service: %S\n", CurrentService
->szServiceName
);
2008 ScmControlService(CurrentService
, SERVICE_CONTROL_SHUTDOWN
);
2011 ServiceEntry
= ServiceEntry
->Flink
;
2014 /* Unlock the service database */
2015 ScmUnlockDatabase();
2017 DPRINT("ScmAutoShutdownServices() done\n");
2022 ScmLockDatabaseExclusive(VOID
)
2024 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
2029 ScmLockDatabaseShared(VOID
)
2031 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
2036 ScmUnlockDatabase(VOID
)
2038 RtlReleaseResource(&DatabaseLock
);
2043 ScmInitNamedPipeCriticalSection(VOID
)
2049 InitializeCriticalSection(&ControlServiceCriticalSection
);
2051 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
2052 L
"SYSTEM\\CurrentControlSet\\Control",
2056 if (dwError
== ERROR_SUCCESS
)
2058 dwKeySize
= sizeof(PipeTimeout
);
2059 RegQueryValueExW(hKey
,
2060 L
"ServicesPipeTimeout",
2063 (LPBYTE
)&PipeTimeout
,
2071 ScmDeleteNamedPipeCriticalSection(VOID
)
2073 DeleteCriticalSection(&ControlServiceCriticalSection
);