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
26 /* GLOBALS *******************************************************************/
28 LIST_ENTRY ServiceListHead
;
30 static RTL_RESOURCE DatabaseLock
;
31 static DWORD dwResumeCount
= 1;
33 static CRITICAL_SECTION ControlServiceCriticalSection
;
35 /* FUNCTIONS *****************************************************************/
39 ScmGetServiceEntryByName(LPCWSTR lpServiceName
)
41 PLIST_ENTRY ServiceEntry
;
42 PSERVICE CurrentService
;
44 DPRINT("ScmGetServiceEntryByName() called\n");
46 ServiceEntry
= ServiceListHead
.Flink
;
47 while (ServiceEntry
!= &ServiceListHead
)
49 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
52 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
54 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
55 return CurrentService
;
58 ServiceEntry
= ServiceEntry
->Flink
;
61 DPRINT("Couldn't find a matching service\n");
68 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName
)
70 PLIST_ENTRY ServiceEntry
;
71 PSERVICE CurrentService
;
73 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
75 ServiceEntry
= ServiceListHead
.Flink
;
76 while (ServiceEntry
!= &ServiceListHead
)
78 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
81 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
83 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
84 return CurrentService
;
87 ServiceEntry
= ServiceEntry
->Flink
;
90 DPRINT("Couldn't find a matching service\n");
97 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
99 PLIST_ENTRY ServiceEntry
;
100 PSERVICE CurrentService
;
102 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
104 ServiceEntry
= ServiceListHead
.Flink
;
105 while (ServiceEntry
!= &ServiceListHead
)
107 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
110 if (CurrentService
->dwResumeCount
> dwResumeCount
)
112 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
113 return CurrentService
;
116 ServiceEntry
= ServiceEntry
->Flink
;
119 DPRINT("Couldn't find a matching service\n");
126 ScmCreateNewServiceRecord(LPCWSTR lpServiceName
,
127 PSERVICE
*lpServiceRecord
)
129 PSERVICE lpService
= NULL
;
131 DPRINT("Service: '%S'\n", lpServiceName
);
133 /* Allocate service entry */
134 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
136 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
137 if (lpService
== NULL
)
138 return ERROR_NOT_ENOUGH_MEMORY
;
140 *lpServiceRecord
= lpService
;
142 /* Copy service name */
143 wcscpy(lpService
->szServiceName
, lpServiceName
);
144 lpService
->lpServiceName
= lpService
->szServiceName
;
145 lpService
->lpDisplayName
= lpService
->lpServiceName
;
147 /* Set the resume count */
148 lpService
->dwResumeCount
= dwResumeCount
++;
150 /* Append service record */
151 InsertTailList(&ServiceListHead
,
152 &lpService
->ServiceListEntry
);
154 /* Initialize the service status */
155 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
156 lpService
->Status
.dwControlsAccepted
= 0;
157 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
158 lpService
->Status
.dwServiceSpecificExitCode
= 0;
159 lpService
->Status
.dwCheckPoint
= 0;
160 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
162 return ERROR_SUCCESS
;
167 ScmDeleteServiceRecord(PSERVICE lpService
)
169 DPRINT("Deleting Service %S\n", lpService
->lpServiceName
);
171 /* Delete the display name */
172 if (lpService
->lpDisplayName
!= NULL
&&
173 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
174 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
176 /* Decrement the image reference counter */
177 if (lpService
->lpImage
)
178 lpService
->lpImage
->dwServiceRefCount
--;
180 /* Decrement the group reference counter */
181 if (lpService
->lpGroup
)
182 lpService
->lpGroup
->dwRefCount
--;
184 /* FIXME: SecurityDescriptor */
186 /* Close the control pipe */
187 if (lpService
->ControlPipeHandle
!= INVALID_HANDLE_VALUE
)
188 CloseHandle(lpService
->ControlPipeHandle
);
190 /* Remove the Service from the List */
191 RemoveEntryList(&lpService
->ServiceListEntry
);
193 DPRINT("Deleted Service %S\n", lpService
->lpServiceName
);
195 /* Delete the service record */
196 HeapFree(GetProcessHeap(), 0, lpService
);
203 CreateServiceListEntry(LPCWSTR lpServiceName
,
206 PSERVICE lpService
= NULL
;
207 LPWSTR lpDisplayName
= NULL
;
208 LPWSTR lpGroup
= NULL
;
213 DWORD dwErrorControl
;
216 DPRINT("Service: '%S'\n", lpServiceName
);
217 if (*lpServiceName
== L
'{')
218 return ERROR_SUCCESS
;
220 dwSize
= sizeof(DWORD
);
221 dwError
= RegQueryValueExW(hServiceKey
,
225 (LPBYTE
)&dwServiceType
,
227 if (dwError
!= ERROR_SUCCESS
)
228 return ERROR_SUCCESS
;
230 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
231 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
232 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
233 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
234 return ERROR_SUCCESS
;
236 DPRINT("Service type: %lx\n", dwServiceType
);
238 dwSize
= sizeof(DWORD
);
239 dwError
= RegQueryValueExW(hServiceKey
,
243 (LPBYTE
)&dwStartType
,
245 if (dwError
!= ERROR_SUCCESS
)
246 return ERROR_SUCCESS
;
248 DPRINT("Start type: %lx\n", dwStartType
);
250 dwSize
= sizeof(DWORD
);
251 dwError
= RegQueryValueExW(hServiceKey
,
255 (LPBYTE
)&dwErrorControl
,
257 if (dwError
!= ERROR_SUCCESS
)
258 return ERROR_SUCCESS
;
260 DPRINT("Error control: %lx\n", dwErrorControl
);
262 dwError
= RegQueryValueExW(hServiceKey
,
268 if (dwError
!= ERROR_SUCCESS
)
271 DPRINT("Tag: %lx\n", dwTagId
);
273 dwError
= ScmReadString(hServiceKey
,
276 if (dwError
!= ERROR_SUCCESS
)
279 DPRINT("Group: %S\n", lpGroup
);
281 dwError
= ScmReadString(hServiceKey
,
284 if (dwError
!= ERROR_SUCCESS
)
285 lpDisplayName
= NULL
;
287 DPRINT("Display name: %S\n", lpDisplayName
);
289 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
291 if (dwError
!= ERROR_SUCCESS
)
294 lpService
->Status
.dwServiceType
= dwServiceType
;
295 lpService
->dwStartType
= dwStartType
;
296 lpService
->dwErrorControl
= dwErrorControl
;
297 lpService
->dwTag
= dwTagId
;
301 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
302 if (dwError
!= ERROR_SUCCESS
)
306 if (lpDisplayName
!= NULL
)
308 lpService
->lpDisplayName
= lpDisplayName
;
309 lpDisplayName
= NULL
;
312 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
313 if (lpService
->lpGroup
!= NULL
)
315 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
317 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
318 lpService
->dwStartType
,
319 lpService
->Status
.dwServiceType
,
321 lpService
->dwErrorControl
);
323 if (ScmIsDeleteFlagSet(hServiceKey
))
324 lpService
->bDeleted
= TRUE
;
328 HeapFree(GetProcessHeap(), 0, lpGroup
);
330 if (lpDisplayName
!= NULL
)
331 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
338 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
340 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
341 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
344 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
347 /* Find the maximum subkey length so that we can allocate a buffer */
348 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
349 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
353 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
354 /* Name too big: alloc a buffer for it */
355 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
358 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
361 while (dwRet
== ERROR_SUCCESS
)
363 dwSize
= dwMaxSubkeyLen
;
364 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
365 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
366 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
368 if (dwRet
== ERROR_NO_MORE_ITEMS
)
369 dwRet
= ERROR_SUCCESS
;
371 if (lpszName
!= szNameBuf
)
372 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
376 RegCloseKey(hSubKey
);
378 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
385 ScmDeleteMarkedServices(VOID
)
387 PLIST_ENTRY ServiceEntry
;
388 PSERVICE CurrentService
;
392 ServiceEntry
= ServiceListHead
.Flink
;
393 while (ServiceEntry
!= &ServiceListHead
)
395 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
397 ServiceEntry
= ServiceEntry
->Flink
;
399 if (CurrentService
->bDeleted
== TRUE
)
401 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
402 L
"System\\CurrentControlSet\\Services",
406 if (dwError
== ERROR_SUCCESS
)
408 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
409 RegCloseKey(hServicesKey
);
410 if (dwError
== ERROR_SUCCESS
)
412 RemoveEntryList(&CurrentService
->ServiceListEntry
);
413 HeapFree(GetProcessHeap(), 0, CurrentService
);
417 if (dwError
!= ERROR_SUCCESS
)
418 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
430 DPRINT("WaitForLSA() called\n");
432 hEvent
= CreateEventW(NULL
,
435 L
"LSA_RPC_SERVER_ACTIVE");
438 dwError
= GetLastError();
439 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
441 if (dwError
== ERROR_ALREADY_EXISTS
)
443 hEvent
= OpenEventW(SYNCHRONIZE
,
445 L
"LSA_RPC_SERVER_ACTIVE");
448 DPRINT1("Could not open the notification event!\n");
454 DPRINT("Wait for LSA!\n");
455 WaitForSingleObject(hEvent
, INFINITE
);
456 DPRINT("LSA is available!\n");
460 DPRINT("WaitForLSA() done\n");
465 ScmCreateServiceDatabase(VOID
)
467 WCHAR szSubKey
[MAX_PATH
];
471 DWORD dwSubKeyLength
;
472 FILETIME ftLastChanged
;
475 DPRINT("ScmCreateServiceDatabase() called\n");
477 dwError
= ScmCreateGroupList();
478 if (dwError
!= ERROR_SUCCESS
)
481 /* Initialize basic variables */
482 InitializeListHead(&ServiceListHead
);
484 /* Initialize the database lock */
485 RtlInitializeResource(&DatabaseLock
);
487 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
488 L
"System\\CurrentControlSet\\Services",
492 if (dwError
!= ERROR_SUCCESS
)
498 dwSubKeyLength
= MAX_PATH
;
499 dwError
= RegEnumKeyExW(hServicesKey
,
507 if (dwError
== ERROR_SUCCESS
&&
510 DPRINT("SubKeyName: '%S'\n", szSubKey
);
512 dwError
= RegOpenKeyExW(hServicesKey
,
517 if (dwError
== ERROR_SUCCESS
)
519 dwError
= CreateServiceListEntry(szSubKey
,
522 RegCloseKey(hServiceKey
);
526 if (dwError
!= ERROR_SUCCESS
)
532 RegCloseKey(hServicesKey
);
537 /* Delete services that are marked for delete */
538 ScmDeleteMarkedServices();
540 DPRINT("ScmCreateServiceDatabase() done\n");
542 return ERROR_SUCCESS
;
547 ScmShutdownServiceDatabase(VOID
)
549 DPRINT("ScmShutdownServiceDatabase() called\n");
551 ScmDeleteMarkedServices();
552 RtlDeleteResource(&DatabaseLock
);
554 DPRINT("ScmShutdownServiceDatabase() done\n");
559 ScmCheckDriver(PSERVICE Service
)
561 OBJECT_ATTRIBUTES ObjectAttributes
;
562 UNICODE_STRING DirName
;
565 POBJECT_DIRECTORY_INFORMATION DirInfo
;
570 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
572 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
574 RtlInitUnicodeString(&DirName
,
579 RtlInitUnicodeString(&DirName
,
583 InitializeObjectAttributes(&ObjectAttributes
,
589 Status
= NtOpenDirectoryObject(&DirHandle
,
590 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
592 if (!NT_SUCCESS(Status
))
597 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
598 2 * MAX_PATH
* sizeof(WCHAR
);
599 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
606 Status
= NtQueryDirectoryObject(DirHandle
,
613 if (Status
== STATUS_NO_MORE_ENTRIES
)
615 /* FIXME: Add current service to 'failed service' list */
616 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
620 if (!NT_SUCCESS(Status
))
623 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
625 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
627 DPRINT("Found: '%S' '%wZ'\n",
628 Service
->lpServiceName
, &DirInfo
->Name
);
630 /* Mark service as 'running' */
631 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
633 /* Mark the service group as 'running' */
634 if (Service
->lpGroup
!= NULL
)
636 Service
->lpGroup
->ServicesRunning
= TRUE
;
643 HeapFree(GetProcessHeap(),
648 return STATUS_SUCCESS
;
653 ScmGetBootAndSystemDriverState(VOID
)
655 PLIST_ENTRY ServiceEntry
;
656 PSERVICE CurrentService
;
658 DPRINT("ScmGetBootAndSystemDriverState() called\n");
660 ServiceEntry
= ServiceListHead
.Flink
;
661 while (ServiceEntry
!= &ServiceListHead
)
663 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
665 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
666 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
669 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
671 ScmCheckDriver(CurrentService
);
674 ServiceEntry
= ServiceEntry
->Flink
;
677 DPRINT("ScmGetBootAndSystemDriverState() done\n");
682 ScmControlService(PSERVICE Service
,
685 PSCM_CONTROL_PACKET ControlPacket
;
686 SCM_REPLY_PACKET ReplyPacket
;
688 DWORD dwWriteCount
= 0;
689 DWORD dwReadCount
= 0;
691 DWORD dwError
= ERROR_SUCCESS
;
693 DPRINT("ScmControlService() called\n");
695 EnterCriticalSection(&ControlServiceCriticalSection
);
697 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
699 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
701 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
702 if (ControlPacket
== NULL
)
704 LeaveCriticalSection(&ControlServiceCriticalSection
);
705 return ERROR_NOT_ENOUGH_MEMORY
;
708 ControlPacket
->dwControl
= dwControl
;
709 ControlPacket
->dwSize
= TotalLength
;
710 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
711 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
713 /* Send the control packet */
714 WriteFile(Service
->ControlPipeHandle
,
716 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
721 ReadFile(Service
->ControlPipeHandle
,
723 sizeof(SCM_REPLY_PACKET
),
727 /* Release the contol packet */
728 HeapFree(GetProcessHeap(),
732 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
734 dwError
= ReplyPacket
.dwError
;
737 LeaveCriticalSection(&ControlServiceCriticalSection
);
739 DPRINT("ScmControlService() done\n");
746 ScmSendStartCommand(PSERVICE Service
,
750 PSCM_CONTROL_PACKET ControlPacket
;
751 SCM_REPLY_PACKET ReplyPacket
;
753 DWORD ArgsLength
= 0;
756 DWORD dwWriteCount
= 0;
757 DWORD dwReadCount
= 0;
758 DWORD dwError
= ERROR_SUCCESS
;
761 DPRINT("ScmSendStartCommand() called\n");
763 /* Calculate the total length of the start command line */
764 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
767 for (i
= 0; i
< argc
; i
++)
769 DPRINT("Arg: %S\n", argv
[i
]);
770 Length
= wcslen(argv
[i
]) + 1;
771 TotalLength
+= Length
;
772 ArgsLength
+= Length
;
776 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
778 /* Allocate a control packet */
779 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
781 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
782 if (ControlPacket
== NULL
)
783 return ERROR_NOT_ENOUGH_MEMORY
;
785 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
786 ControlPacket
->hServiceStatus
= (SERVICE_STATUS_HANDLE
)Service
;
787 ControlPacket
->dwSize
= TotalLength
;
788 Ptr
= &ControlPacket
->szArguments
[0];
789 wcscpy(Ptr
, Service
->lpServiceName
);
790 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
792 /* Copy argument list */
796 DPRINT1("Arguments sent to service ignored!\n");
798 memcpy(Ptr
, Arguments
, ArgsLength
);
803 /* Terminate the argument list */
806 /* Send the start command */
807 WriteFile(Service
->ControlPipeHandle
,
809 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
814 ReadFile(Service
->ControlPipeHandle
,
816 sizeof(SCM_REPLY_PACKET
),
820 /* Release the contol packet */
821 HeapFree(GetProcessHeap(),
825 if (dwReadCount
== sizeof(SCM_REPLY_PACKET
))
827 dwError
= ReplyPacket
.dwError
;
830 DPRINT("ScmSendStartCommand() done\n");
837 ScmStartUserModeService(PSERVICE Service
,
841 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
842 PROCESS_INFORMATION ProcessInformation
;
843 STARTUPINFOW StartupInfo
;
844 UNICODE_STRING ImagePath
;
846 DWORD ServiceCurrent
= 0;
849 DWORD dwError
= ERROR_SUCCESS
;
850 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
851 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
852 DWORD KeyDisposition
;
855 RtlInitUnicodeString(&ImagePath
, NULL
);
857 /* Get service data */
858 RtlZeroMemory(&QueryTable
,
861 QueryTable
[0].Name
= L
"Type";
862 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
863 QueryTable
[0].EntryContext
= &Type
;
865 QueryTable
[1].Name
= L
"ImagePath";
866 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
867 QueryTable
[1].EntryContext
= &ImagePath
;
869 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
870 Service
->lpServiceName
,
874 if (!NT_SUCCESS(Status
))
876 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
877 return RtlNtStatusToDosError(Status
);
879 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
880 DPRINT("Type: %lx\n", Type
);
882 /* Get the service number */
883 /* TODO: Create registry entry with correct write access */
884 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
885 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
887 KEY_WRITE
| KEY_READ
,
892 if (ERROR_SUCCESS
!= Status
)
894 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
898 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
900 DWORD KeySize
= sizeof(ServiceCurrent
);
901 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
903 if (ERROR_SUCCESS
!= Status
)
905 RegCloseKey(hServiceCurrentKey
);
906 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
913 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
915 RegCloseKey(hServiceCurrentKey
);
917 if (ERROR_SUCCESS
!= Status
)
919 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
923 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
924 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
926 DPRINT("Service: %p ImagePath: %wZ PipeName: %S\n", Service
, &ImagePath
, NtControlPipeName
);
928 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
930 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
936 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
937 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
939 DPRINT1("Failed to create control pipe!\n");
940 return GetLastError();
943 StartupInfo
.cb
= sizeof(StartupInfo
);
944 StartupInfo
.lpReserved
= NULL
;
945 StartupInfo
.lpDesktop
= NULL
;
946 StartupInfo
.lpTitle
= NULL
;
947 StartupInfo
.dwFlags
= 0;
948 StartupInfo
.cbReserved2
= 0;
949 StartupInfo
.lpReserved2
= 0;
951 Result
= CreateProcessW(NULL
,
956 DETACHED_PROCESS
| CREATE_SUSPENDED
,
960 &ProcessInformation
);
961 RtlFreeUnicodeString(&ImagePath
);
965 dwError
= GetLastError();
966 /* Close control pipe */
967 CloseHandle(Service
->ControlPipeHandle
);
968 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
970 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
974 DPRINT("Process Id: %lu Handle %lx\n",
975 ProcessInformation
.dwProcessId
,
976 ProcessInformation
.hProcess
);
977 DPRINT("Thread Id: %lu Handle %lx\n",
978 ProcessInformation
.dwThreadId
,
979 ProcessInformation
.hThread
);
981 /* Get process and thread ids */
982 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
983 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
986 ResumeThread(ProcessInformation
.hThread
);
988 /* Connect control pipe */
989 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
990 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
994 DPRINT("Control pipe connected!\n");
996 /* Read SERVICE_STATUS_HANDLE from pipe */
997 if (!ReadFile(Service
->ControlPipeHandle
,
998 (LPVOID
)&dwProcessId
,
1003 dwError
= GetLastError();
1004 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1009 DPRINT("Received service process ID %lu\n", dwProcessId
);
1011 /* Send start command */
1012 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1017 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1019 /* Close control pipe */
1020 CloseHandle(Service
->ControlPipeHandle
);
1021 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1022 Service
->ProcessId
= 0;
1023 Service
->ThreadId
= 0;
1026 /* Close process and thread handle */
1027 CloseHandle(ProcessInformation
.hThread
);
1028 CloseHandle(ProcessInformation
.hProcess
);
1035 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1037 PSERVICE_GROUP Group
= Service
->lpGroup
;
1038 DWORD dwError
= ERROR_SUCCESS
;
1040 DPRINT("ScmStartService() called\n");
1042 DPRINT("Start Service %p (%S)\n", Service
, Service
->lpServiceName
);
1044 EnterCriticalSection(&ControlServiceCriticalSection
);
1046 if (Service
->Status
.dwCurrentState
!= SERVICE_STOPPED
)
1048 DPRINT("Service %S is already running!\n", Service
->lpServiceName
);
1049 LeaveCriticalSection(&ControlServiceCriticalSection
);
1050 return ERROR_SERVICE_ALREADY_RUNNING
;
1053 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1054 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1056 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1059 dwError
= ScmLoadDriver(Service
);
1060 if (dwError
== ERROR_SUCCESS
)
1062 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1063 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1068 /* Start user-mode service */
1069 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1070 if (dwError
== ERROR_SUCCESS
)
1072 #ifdef USE_SERVICE_START_PENDING
1073 Service
->Status
.dwCurrentState
= SERVICE_START_PENDING
;
1075 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1080 LeaveCriticalSection(&ControlServiceCriticalSection
);
1082 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1084 if (dwError
== ERROR_SUCCESS
)
1088 Group
->ServicesRunning
= TRUE
;
1094 switch (Service
->ErrorControl
)
1096 case SERVICE_ERROR_NORMAL
:
1097 /* FIXME: Log error */
1100 case SERVICE_ERROR_SEVERE
:
1101 if (IsLastKnownGood
== FALSE
)
1103 /* FIXME: Boot last known good configuration */
1107 case SERVICE_ERROR_CRITICAL
:
1108 if (IsLastKnownGood
== FALSE
)
1110 /* FIXME: Boot last known good configuration */
1126 ScmAutoStartServices(VOID
)
1128 PLIST_ENTRY GroupEntry
;
1129 PLIST_ENTRY ServiceEntry
;
1130 PSERVICE_GROUP CurrentGroup
;
1131 PSERVICE CurrentService
;
1134 /* Clear 'ServiceVisited' flag */
1135 ServiceEntry
= ServiceListHead
.Flink
;
1136 while (ServiceEntry
!= &ServiceListHead
)
1138 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1139 CurrentService
->ServiceVisited
= FALSE
;
1140 ServiceEntry
= ServiceEntry
->Flink
;
1143 /* Start all services which are members of an existing group */
1144 GroupEntry
= GroupListHead
.Flink
;
1145 while (GroupEntry
!= &GroupListHead
)
1147 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1149 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1151 /* Start all services witch have a valid tag */
1152 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1154 ServiceEntry
= ServiceListHead
.Flink
;
1155 while (ServiceEntry
!= &ServiceListHead
)
1157 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1159 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1160 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1161 (CurrentService
->ServiceVisited
== FALSE
) &&
1162 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1164 CurrentService
->ServiceVisited
= TRUE
;
1165 ScmStartService(CurrentService
, 0, NULL
);
1168 ServiceEntry
= ServiceEntry
->Flink
;
1172 /* Start all services which have an invalid tag or which do not have a tag */
1173 ServiceEntry
= ServiceListHead
.Flink
;
1174 while (ServiceEntry
!= &ServiceListHead
)
1176 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1178 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1179 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1180 (CurrentService
->ServiceVisited
== FALSE
))
1182 CurrentService
->ServiceVisited
= TRUE
;
1183 ScmStartService(CurrentService
, 0, NULL
);
1186 ServiceEntry
= ServiceEntry
->Flink
;
1189 GroupEntry
= GroupEntry
->Flink
;
1192 /* Start all services which are members of any non-existing group */
1193 ServiceEntry
= ServiceListHead
.Flink
;
1194 while (ServiceEntry
!= &ServiceListHead
)
1196 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1198 if ((CurrentService
->lpGroup
!= NULL
) &&
1199 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1200 (CurrentService
->ServiceVisited
== FALSE
))
1202 CurrentService
->ServiceVisited
= TRUE
;
1203 ScmStartService(CurrentService
, 0, NULL
);
1206 ServiceEntry
= ServiceEntry
->Flink
;
1209 /* Start all services which are not a member of any group */
1210 ServiceEntry
= ServiceListHead
.Flink
;
1211 while (ServiceEntry
!= &ServiceListHead
)
1213 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1215 if ((CurrentService
->lpGroup
== NULL
) &&
1216 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1217 (CurrentService
->ServiceVisited
== FALSE
))
1219 CurrentService
->ServiceVisited
= TRUE
;
1220 ScmStartService(CurrentService
, 0, NULL
);
1223 ServiceEntry
= ServiceEntry
->Flink
;
1226 /* Clear 'ServiceVisited' flag again */
1227 ServiceEntry
= ServiceListHead
.Flink
;
1228 while (ServiceEntry
!= &ServiceListHead
)
1230 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1231 CurrentService
->ServiceVisited
= FALSE
;
1232 ServiceEntry
= ServiceEntry
->Flink
;
1238 ScmAutoShutdownServices(VOID
)
1240 PLIST_ENTRY ServiceEntry
;
1241 PSERVICE CurrentService
;
1243 DPRINT("ScmAutoShutdownServices() called\n");
1245 ServiceEntry
= ServiceListHead
.Flink
;
1246 while (ServiceEntry
!= &ServiceListHead
)
1248 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1250 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1251 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1253 /* shutdown service */
1254 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
);
1257 ServiceEntry
= ServiceEntry
->Flink
;
1260 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1265 ScmLockDatabaseExclusive(VOID
)
1267 return RtlAcquireResourceExclusive(&DatabaseLock
, TRUE
);
1272 ScmLockDatabaseShared(VOID
)
1274 return RtlAcquireResourceShared(&DatabaseLock
, TRUE
);
1279 ScmUnlockDatabase(VOID
)
1281 RtlReleaseResource(&DatabaseLock
);
1286 ScmInitNamedPipeCriticalSection(VOID
)
1288 InitializeCriticalSection(&ControlServiceCriticalSection
);
1293 ScmDeleteNamedPipeCriticalSection(VOID
)
1295 DeleteCriticalSection(&ControlServiceCriticalSection
);