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 /* GLOBALS *******************************************************************/
23 LIST_ENTRY ServiceListHead
;
25 static RTL_RESOURCE DatabaseLock
;
26 static DWORD dwResumeCount
= 1;
29 /* FUNCTIONS *****************************************************************/
33 ScmGetServiceEntryByName(LPWSTR lpServiceName
)
35 PLIST_ENTRY ServiceEntry
;
36 PSERVICE CurrentService
;
38 DPRINT("ScmGetServiceEntryByName() called\n");
40 ServiceEntry
= ServiceListHead
.Flink
;
41 while (ServiceEntry
!= &ServiceListHead
)
43 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
46 if (_wcsicmp(CurrentService
->lpServiceName
, lpServiceName
) == 0)
48 DPRINT("Found service: '%S'\n", CurrentService
->lpServiceName
);
49 return CurrentService
;
52 ServiceEntry
= ServiceEntry
->Flink
;
55 DPRINT("Couldn't find a matching service\n");
62 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName
)
64 PLIST_ENTRY ServiceEntry
;
65 PSERVICE CurrentService
;
67 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
69 ServiceEntry
= ServiceListHead
.Flink
;
70 while (ServiceEntry
!= &ServiceListHead
)
72 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
75 if (_wcsicmp(CurrentService
->lpDisplayName
, lpDisplayName
) == 0)
77 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
78 return CurrentService
;
81 ServiceEntry
= ServiceEntry
->Flink
;
84 DPRINT("Couldn't find a matching service\n");
91 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount
)
93 PLIST_ENTRY ServiceEntry
;
94 PSERVICE CurrentService
;
96 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
98 ServiceEntry
= ServiceListHead
.Flink
;
99 while (ServiceEntry
!= &ServiceListHead
)
101 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
104 if (CurrentService
->dwResumeCount
> dwResumeCount
)
106 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
107 return CurrentService
;
110 ServiceEntry
= ServiceEntry
->Flink
;
113 DPRINT("Couldn't find a matching service\n");
120 ScmGetServiceEntryByClientHandle(HANDLE Handle
)
122 PLIST_ENTRY ServiceEntry
;
123 PSERVICE CurrentService
;
125 DPRINT("ScmGetServiceEntryByClientHandle() called\n");
126 DPRINT("looking for %p\n", Handle
);
128 ServiceEntry
= ServiceListHead
.Flink
;
129 while (ServiceEntry
!= &ServiceListHead
)
131 CurrentService
= CONTAINING_RECORD(ServiceEntry
,
135 if (CurrentService
->hClient
== Handle
)
137 DPRINT("Found service: '%S'\n", CurrentService
->lpDisplayName
);
138 return CurrentService
;
141 ServiceEntry
= ServiceEntry
->Flink
;
144 DPRINT("Couldn't find a matching service\n");
151 ScmCreateNewServiceRecord(LPWSTR lpServiceName
,
152 PSERVICE
*lpServiceRecord
)
154 PSERVICE lpService
= NULL
;
156 DPRINT("Service: '%S'\n", lpServiceName
);
158 /* Allocate service entry */
159 lpService
= (SERVICE
*) HeapAlloc(GetProcessHeap(),
161 sizeof(SERVICE
) + ((wcslen(lpServiceName
) + 1) * sizeof(WCHAR
)));
162 if (lpService
== NULL
)
163 return ERROR_NOT_ENOUGH_MEMORY
;
165 *lpServiceRecord
= lpService
;
167 /* Copy service name */
168 wcscpy(lpService
->szServiceName
, lpServiceName
);
169 lpService
->lpServiceName
= lpService
->szServiceName
;
170 lpService
->lpDisplayName
= lpService
->lpServiceName
;
172 /* Set the resume count */
173 lpService
->dwResumeCount
= dwResumeCount
++;
175 /* Append service record */
176 InsertTailList(&ServiceListHead
,
177 &lpService
->ServiceListEntry
);
179 /* Initialize the service status */
180 lpService
->Status
.dwCurrentState
= SERVICE_STOPPED
;
181 lpService
->Status
.dwControlsAccepted
= 0;
182 lpService
->Status
.dwWin32ExitCode
= ERROR_SERVICE_NEVER_STARTED
;
183 lpService
->Status
.dwServiceSpecificExitCode
= 0;
184 lpService
->Status
.dwCheckPoint
= 0;
185 lpService
->Status
.dwWaitHint
= 2000; /* 2 seconds */
187 return ERROR_SUCCESS
;
192 ScmDeleteServiceRecord(PSERVICE lpService
)
194 DPRINT1("Deleting Service %S\n", lpService
->lpServiceName
);
196 /* Delete the display name */
197 if (lpService
->lpDisplayName
!= NULL
&&
198 lpService
->lpDisplayName
!= lpService
->lpServiceName
)
199 HeapFree(GetProcessHeap(), 0, lpService
->lpDisplayName
);
201 /* Decrement the image reference counter */
202 if (lpService
->lpImage
)
203 lpService
->lpImage
->dwServiceRefCount
--;
205 /* Decrement the group reference counter */
206 if (lpService
->lpGroup
)
207 lpService
->lpGroup
->dwRefCount
--;
209 /* FIXME: SecurityDescriptor */
211 /* Close the control pipe */
212 if (lpService
->ControlPipeHandle
!= INVALID_HANDLE_VALUE
)
213 CloseHandle(lpService
->ControlPipeHandle
);
215 /* Remove the Service from the List */
216 RemoveEntryList(&lpService
->ServiceListEntry
);
218 DPRINT1("Deleted Service %S\n", lpService
->lpServiceName
);
220 /* Delete the service record */
221 HeapFree(GetProcessHeap(), 0, lpService
);
228 CreateServiceListEntry(LPWSTR lpServiceName
,
231 PSERVICE lpService
= NULL
;
232 LPWSTR lpDisplayName
= NULL
;
233 LPWSTR lpGroup
= NULL
;
238 DWORD dwErrorControl
;
241 DPRINT("Service: '%S'\n", lpServiceName
);
242 if (*lpServiceName
== L
'{')
243 return ERROR_SUCCESS
;
245 dwSize
= sizeof(DWORD
);
246 dwError
= RegQueryValueExW(hServiceKey
,
250 (LPBYTE
)&dwServiceType
,
252 if (dwError
!= ERROR_SUCCESS
)
253 return ERROR_SUCCESS
;
255 if (((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_OWN_PROCESS
) &&
256 ((dwServiceType
& ~SERVICE_INTERACTIVE_PROCESS
) != SERVICE_WIN32_SHARE_PROCESS
) &&
257 (dwServiceType
!= SERVICE_KERNEL_DRIVER
) &&
258 (dwServiceType
!= SERVICE_FILE_SYSTEM_DRIVER
))
259 return ERROR_SUCCESS
;
261 DPRINT("Service type: %lx\n", dwServiceType
);
263 dwSize
= sizeof(DWORD
);
264 dwError
= RegQueryValueExW(hServiceKey
,
268 (LPBYTE
)&dwStartType
,
270 if (dwError
!= ERROR_SUCCESS
)
271 return ERROR_SUCCESS
;
273 DPRINT("Start type: %lx\n", dwStartType
);
275 dwSize
= sizeof(DWORD
);
276 dwError
= RegQueryValueExW(hServiceKey
,
280 (LPBYTE
)&dwErrorControl
,
282 if (dwError
!= ERROR_SUCCESS
)
283 return ERROR_SUCCESS
;
285 DPRINT("Error control: %lx\n", dwErrorControl
);
287 dwError
= RegQueryValueExW(hServiceKey
,
293 if (dwError
!= ERROR_SUCCESS
)
296 DPRINT("Tag: %lx\n", dwTagId
);
298 dwError
= ScmReadString(hServiceKey
,
301 if (dwError
!= ERROR_SUCCESS
)
304 DPRINT("Group: %S\n", lpGroup
);
306 dwError
= ScmReadString(hServiceKey
,
309 if (dwError
!= ERROR_SUCCESS
)
310 lpDisplayName
= NULL
;
312 DPRINT("Display name: %S\n", lpDisplayName
);
314 dwError
= ScmCreateNewServiceRecord(lpServiceName
,
316 if (dwError
!= ERROR_SUCCESS
)
319 lpService
->Status
.dwServiceType
= dwServiceType
;
320 lpService
->dwStartType
= dwStartType
;
321 lpService
->dwErrorControl
= dwErrorControl
;
322 lpService
->dwTag
= dwTagId
;
326 dwError
= ScmSetServiceGroup(lpService
, lpGroup
);
327 if (dwError
!= ERROR_SUCCESS
)
331 if (lpDisplayName
!= NULL
)
333 lpService
->lpDisplayName
= lpDisplayName
;
334 lpDisplayName
= NULL
;
337 DPRINT("ServiceName: '%S'\n", lpService
->lpServiceName
);
338 if (lpService
->lpGroup
!= NULL
)
340 DPRINT("Group: '%S'\n", lpService
->lpGroup
->lpGroupName
);
342 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
343 lpService
->dwStartType
,
344 lpService
->Status
.dwServiceType
,
346 lpService
->dwErrorControl
);
348 if (ScmIsDeleteFlagSet(hServiceKey
))
349 lpService
->bDeleted
= TRUE
;
353 HeapFree(GetProcessHeap(), 0, lpGroup
);
355 if (lpDisplayName
!= NULL
)
356 HeapFree(GetProcessHeap(), 0, lpDisplayName
);
363 ScmDeleteRegKey(HKEY hKey
, LPCWSTR lpszSubKey
)
365 DWORD dwRet
, dwMaxSubkeyLen
= 0, dwSize
;
366 WCHAR szNameBuf
[MAX_PATH
], *lpszName
= szNameBuf
;
369 dwRet
= RegOpenKeyExW(hKey
, lpszSubKey
, 0, KEY_READ
, &hSubKey
);
372 /* Find the maximum subkey length so that we can allocate a buffer */
373 dwRet
= RegQueryInfoKeyW(hSubKey
, NULL
, NULL
, NULL
, NULL
,
374 &dwMaxSubkeyLen
, NULL
, NULL
, NULL
, NULL
, NULL
, NULL
);
378 if (dwMaxSubkeyLen
> sizeof(szNameBuf
)/sizeof(WCHAR
))
379 /* Name too big: alloc a buffer for it */
380 lpszName
= HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen
*sizeof(WCHAR
));
383 dwRet
= ERROR_NOT_ENOUGH_MEMORY
;
386 while (dwRet
== ERROR_SUCCESS
)
388 dwSize
= dwMaxSubkeyLen
;
389 dwRet
= RegEnumKeyExW(hSubKey
, 0, lpszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
390 if (dwRet
== ERROR_SUCCESS
|| dwRet
== ERROR_MORE_DATA
)
391 dwRet
= ScmDeleteRegKey(hSubKey
, lpszName
);
393 if (dwRet
== ERROR_NO_MORE_ITEMS
)
394 dwRet
= ERROR_SUCCESS
;
396 if (lpszName
!= szNameBuf
)
397 HeapFree(GetProcessHeap(), 0, lpszName
); /* Free buffer if allocated */
401 RegCloseKey(hSubKey
);
403 dwRet
= RegDeleteKeyW(hKey
, lpszSubKey
);
410 ScmDeleteMarkedServices(VOID
)
412 PLIST_ENTRY ServiceEntry
;
413 PSERVICE CurrentService
;
417 ServiceEntry
= ServiceListHead
.Flink
;
418 while (ServiceEntry
!= &ServiceListHead
)
420 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
422 ServiceEntry
= ServiceEntry
->Flink
;
424 if (CurrentService
->bDeleted
== TRUE
)
426 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
427 L
"System\\CurrentControlSet\\Services",
431 if (dwError
== ERROR_SUCCESS
)
433 dwError
= ScmDeleteRegKey(hServicesKey
, CurrentService
->lpServiceName
);
434 RegCloseKey(hServicesKey
);
435 if (dwError
== ERROR_SUCCESS
)
437 RemoveEntryList(&CurrentService
->ServiceListEntry
);
438 HeapFree(GetProcessHeap(), 0, CurrentService
);
442 if (dwError
!= ERROR_SUCCESS
)
443 DPRINT1("Delete service failed: %S\n", CurrentService
->lpServiceName
);
455 DPRINT1("WaitForLSA() called\n");
457 hEvent
= CreateEventW(NULL
,
460 L
"LSA_RPC_SERVER_ACTIVE");
463 dwError
= GetLastError();
464 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError
);
466 if (dwError
== ERROR_ALREADY_EXISTS
)
468 hEvent
= OpenEventW(SYNCHRONIZE
,
470 L
"LSA_RPC_SERVER_ACTIVE");
473 DPRINT1("Could not open the notification event!\n");
479 DPRINT1("Wait for LSA!\n");
480 WaitForSingleObject(hEvent
, INFINITE
);
481 DPRINT1("LSA is available!\n");
485 DPRINT1("WaitForLSA() done\n");
490 ScmCreateServiceDatabase(VOID
)
492 WCHAR szSubKey
[MAX_PATH
];
496 DWORD dwSubKeyLength
;
497 FILETIME ftLastChanged
;
500 DPRINT("ScmCreateServiceDatabase() called\n");
502 dwError
= ScmCreateGroupList();
503 if (dwError
!= ERROR_SUCCESS
)
506 /* Initialize basic variables */
507 InitializeListHead(&ServiceListHead
);
509 /* Initialize the database lock */
510 RtlInitializeResource(&DatabaseLock
);
512 dwError
= RegOpenKeyExW(HKEY_LOCAL_MACHINE
,
513 L
"System\\CurrentControlSet\\Services",
517 if (dwError
!= ERROR_SUCCESS
)
523 dwSubKeyLength
= MAX_PATH
;
524 dwError
= RegEnumKeyExW(hServicesKey
,
532 if (dwError
== ERROR_SUCCESS
&&
535 DPRINT("SubKeyName: '%S'\n", szSubKey
);
537 dwError
= RegOpenKeyExW(hServicesKey
,
542 if (dwError
== ERROR_SUCCESS
)
544 dwError
= CreateServiceListEntry(szSubKey
,
547 RegCloseKey(hServiceKey
);
551 if (dwError
!= ERROR_SUCCESS
)
557 RegCloseKey(hServicesKey
);
562 /* Delete services that are marked for delete */
563 ScmDeleteMarkedServices();
565 DPRINT("ScmCreateServiceDatabase() done\n");
567 return ERROR_SUCCESS
;
572 ScmShutdownServiceDatabase(VOID
)
574 DPRINT("ScmShutdownServiceDatabase() called\n");
576 ScmDeleteMarkedServices();
577 RtlDeleteResource(&DatabaseLock
);
579 DPRINT("ScmShutdownServiceDatabase() done\n");
584 ScmCheckDriver(PSERVICE Service
)
586 OBJECT_ATTRIBUTES ObjectAttributes
;
587 UNICODE_STRING DirName
;
590 POBJECT_DIRECTORY_INFORMATION DirInfo
;
595 DPRINT("ScmCheckDriver(%S) called\n", Service
->lpServiceName
);
597 if (Service
->Status
.dwServiceType
== SERVICE_KERNEL_DRIVER
)
599 RtlInitUnicodeString(&DirName
,
604 RtlInitUnicodeString(&DirName
,
608 InitializeObjectAttributes(&ObjectAttributes
,
614 Status
= NtOpenDirectoryObject(&DirHandle
,
615 DIRECTORY_QUERY
| DIRECTORY_TRAVERSE
,
617 if (!NT_SUCCESS(Status
))
622 BufferLength
= sizeof(OBJECT_DIRECTORY_INFORMATION
) +
623 2 * MAX_PATH
* sizeof(WCHAR
);
624 DirInfo
= (OBJECT_DIRECTORY_INFORMATION
*) HeapAlloc(GetProcessHeap(),
631 Status
= NtQueryDirectoryObject(DirHandle
,
638 if (Status
== STATUS_NO_MORE_ENTRIES
)
640 /* FIXME: Add current service to 'failed service' list */
641 DPRINT("Service '%S' failed\n", Service
->lpServiceName
);
645 if (!NT_SUCCESS(Status
))
648 DPRINT("Comparing: '%S' '%wZ'\n", Service
->lpServiceName
, &DirInfo
->Name
);
650 if (_wcsicmp(Service
->lpServiceName
, DirInfo
->Name
.Buffer
) == 0)
652 DPRINT("Found: '%S' '%wZ'\n",
653 Service
->lpServiceName
, &DirInfo
->Name
);
655 /* Mark service as 'running' */
656 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
658 /* Mark the service group as 'running' */
659 if (Service
->lpGroup
!= NULL
)
661 Service
->lpGroup
->ServicesRunning
= TRUE
;
668 HeapFree(GetProcessHeap(),
673 return STATUS_SUCCESS
;
678 ScmGetBootAndSystemDriverState(VOID
)
680 PLIST_ENTRY ServiceEntry
;
681 PSERVICE CurrentService
;
683 DPRINT("ScmGetBootAndSystemDriverState() called\n");
685 ServiceEntry
= ServiceListHead
.Flink
;
686 while (ServiceEntry
!= &ServiceListHead
)
688 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
690 if (CurrentService
->dwStartType
== SERVICE_BOOT_START
||
691 CurrentService
->dwStartType
== SERVICE_SYSTEM_START
)
694 DPRINT(" Checking service: %S\n", CurrentService
->lpServiceName
);
696 ScmCheckDriver(CurrentService
);
699 ServiceEntry
= ServiceEntry
->Flink
;
702 DPRINT("ScmGetBootAndSystemDriverState() done\n");
707 ScmControlService(PSERVICE Service
,
709 LPSERVICE_STATUS lpServiceStatus
)
711 PSCM_CONTROL_PACKET ControlPacket
;
715 DPRINT("ScmControlService() called\n");
717 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
719 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
721 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)));
722 if (ControlPacket
== NULL
)
723 return ERROR_NOT_ENOUGH_MEMORY
;
725 ControlPacket
->dwControl
= dwControl
;
726 ControlPacket
->hClient
= Service
->hClient
;
727 ControlPacket
->dwSize
= TotalLength
;
728 wcscpy(&ControlPacket
->szArguments
[0], Service
->lpServiceName
);
730 /* Send the start command */
731 WriteFile(Service
->ControlPipeHandle
,
733 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
* sizeof(WCHAR
)),
737 /* FIXME: Read the reply */
739 /* Release the contol packet */
740 HeapFree(GetProcessHeap(),
744 RtlCopyMemory(lpServiceStatus
,
746 sizeof(SERVICE_STATUS
));
748 DPRINT("ScmControlService) done\n");
750 return ERROR_SUCCESS
;
755 ScmSendStartCommand(PSERVICE Service
,
759 PSCM_CONTROL_PACKET ControlPacket
;
761 DWORD ArgsLength
= 0;
766 DPRINT("ScmSendStartCommand() called\n");
768 /* Calculate the total length of the start command line */
769 TotalLength
= wcslen(Service
->lpServiceName
) + 1;
772 for (Count
= 0; Count
< argc
; Count
++)
774 DPRINT("Arg: %S\n", argv
[Count
]);
775 Length
= wcslen(argv
[Count
]) + 1;
776 TotalLength
+= Length
;
777 ArgsLength
+= Length
;
781 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength
, TotalLength
);
783 /* Allocate a control packet */
784 ControlPacket
= (SCM_CONTROL_PACKET
*)HeapAlloc(GetProcessHeap(),
786 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
));
787 if (ControlPacket
== NULL
)
788 return ERROR_NOT_ENOUGH_MEMORY
;
790 ControlPacket
->dwControl
= SERVICE_CONTROL_START
;
791 ControlPacket
->hClient
= Service
->hClient
;
792 ControlPacket
->dwSize
= TotalLength
;
793 Ptr
= &ControlPacket
->szArguments
[0];
794 wcscpy(Ptr
, Service
->lpServiceName
);
795 Ptr
+= (wcslen(Service
->lpServiceName
) + 1);
797 /* Copy argument list */
801 DPRINT1("Arguments sent to service ignored!\n");
803 memcpy(Ptr
, Arguments
, ArgsLength
);
808 /* Terminate the argument list */
811 /* Send the start command */
812 WriteFile(Service
->ControlPipeHandle
,
814 sizeof(SCM_CONTROL_PACKET
) + (TotalLength
- 1) * sizeof(WCHAR
),
818 /* FIXME: Read the reply */
820 /* Release the contol packet */
821 HeapFree(GetProcessHeap(),
825 DPRINT("ScmSendStartCommand() done\n");
827 return ERROR_SUCCESS
;
832 ScmStartUserModeService(PSERVICE Service
,
836 RTL_QUERY_REGISTRY_TABLE QueryTable
[3];
837 PROCESS_INFORMATION ProcessInformation
;
838 STARTUPINFOW StartupInfo
;
839 UNICODE_STRING ImagePath
;
841 DWORD ServiceCurrent
= 0;
844 DWORD dwError
= ERROR_SUCCESS
;
845 WCHAR NtControlPipeName
[MAX_PATH
+ 1];
846 HKEY hServiceCurrentKey
= INVALID_HANDLE_VALUE
;
847 DWORD KeyDisposition
;
849 RtlInitUnicodeString(&ImagePath
, NULL
);
851 /* Get service data */
852 RtlZeroMemory(&QueryTable
,
855 QueryTable
[0].Name
= L
"Type";
856 QueryTable
[0].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
857 QueryTable
[0].EntryContext
= &Type
;
859 QueryTable
[1].Name
= L
"ImagePath";
860 QueryTable
[1].Flags
= RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_REQUIRED
;
861 QueryTable
[1].EntryContext
= &ImagePath
;
863 Status
= RtlQueryRegistryValues(RTL_REGISTRY_SERVICES
,
864 Service
->lpServiceName
,
868 if (!NT_SUCCESS(Status
))
870 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status
);
871 return RtlNtStatusToDosError(Status
);
873 DPRINT("ImagePath: '%S'\n", ImagePath
.Buffer
);
874 DPRINT("Type: %lx\n", Type
);
876 /* Get the service number */
877 /* TODO: Create registry entry with correct write access */
878 Status
= RegCreateKeyExW(HKEY_LOCAL_MACHINE
,
879 L
"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL
,
881 KEY_WRITE
| KEY_READ
,
886 if (ERROR_SUCCESS
!= Status
)
888 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status
);
892 if (REG_OPENED_EXISTING_KEY
== KeyDisposition
)
894 DWORD KeySize
= sizeof(ServiceCurrent
);
895 Status
= RegQueryValueExW(hServiceCurrentKey
, L
"", 0, NULL
, (BYTE
*)&ServiceCurrent
, &KeySize
);
897 if (ERROR_SUCCESS
!= Status
)
899 RegCloseKey(hServiceCurrentKey
);
900 DPRINT1("RegQueryValueEx() failed with status %u\n", Status
);
907 Status
= RegSetValueExW(hServiceCurrentKey
, L
"", 0, REG_DWORD
, (BYTE
*)&ServiceCurrent
, sizeof(ServiceCurrent
));
909 RegCloseKey(hServiceCurrentKey
);
911 if (ERROR_SUCCESS
!= Status
)
913 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status
);
917 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
918 swprintf(NtControlPipeName
, L
"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent
);
919 Service
->ControlPipeHandle
= CreateNamedPipeW(NtControlPipeName
,
921 PIPE_TYPE_MESSAGE
| PIPE_READMODE_MESSAGE
| PIPE_WAIT
,
927 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName
);
928 if (Service
->ControlPipeHandle
== INVALID_HANDLE_VALUE
)
930 DPRINT1("Failed to create control pipe!\n");
931 return GetLastError();
934 StartupInfo
.cb
= sizeof(StartupInfo
);
935 StartupInfo
.lpReserved
= NULL
;
936 StartupInfo
.lpDesktop
= NULL
;
937 StartupInfo
.lpTitle
= NULL
;
938 StartupInfo
.dwFlags
= 0;
939 StartupInfo
.cbReserved2
= 0;
940 StartupInfo
.lpReserved2
= 0;
942 Result
= CreateProcessW(NULL
,
947 DETACHED_PROCESS
| CREATE_SUSPENDED
,
951 &ProcessInformation
);
952 RtlFreeUnicodeString(&ImagePath
);
956 dwError
= GetLastError();
957 /* Close control pipe */
958 CloseHandle(Service
->ControlPipeHandle
);
959 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
961 DPRINT1("Starting '%S' failed!\n", Service
->lpServiceName
);
965 DPRINT("Process Id: %lu Handle %lx\n",
966 ProcessInformation
.dwProcessId
,
967 ProcessInformation
.hProcess
);
968 DPRINT("Thread Id: %lu Handle %lx\n",
969 ProcessInformation
.dwThreadId
,
970 ProcessInformation
.hThread
);
972 /* Get process and thread ids */
973 Service
->ProcessId
= ProcessInformation
.dwProcessId
;
974 Service
->ThreadId
= ProcessInformation
.dwThreadId
;
977 ResumeThread(ProcessInformation
.hThread
);
979 /* Connect control pipe */
980 if (ConnectNamedPipe(Service
->ControlPipeHandle
, NULL
) ?
981 TRUE
: (dwError
= GetLastError()) == ERROR_PIPE_CONNECTED
)
985 DPRINT("Control pipe connected!\n");
987 /* Read SERVICE_STATUS_HANDLE from pipe */
988 if (!ReadFile(Service
->ControlPipeHandle
,
989 (LPVOID
)&Service
->hClient
,
994 dwError
= GetLastError();
995 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1000 DPRINT("Received service status %lu\n", Service
->hClient
);
1002 /* Send start command */
1003 dwError
= ScmSendStartCommand(Service
, argc
, argv
);
1008 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError
);
1010 /* Close control pipe */
1011 CloseHandle(Service
->ControlPipeHandle
);
1012 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1013 Service
->ProcessId
= 0;
1014 Service
->ThreadId
= 0;
1017 /* Close process and thread handle */
1018 CloseHandle(ProcessInformation
.hThread
);
1019 CloseHandle(ProcessInformation
.hProcess
);
1026 ScmStartService(PSERVICE Service
, DWORD argc
, LPWSTR
*argv
)
1028 PSERVICE_GROUP Group
= Service
->lpGroup
;
1029 DWORD dwError
= ERROR_SUCCESS
;
1031 DPRINT("ScmStartService() called\n");
1033 Service
->ControlPipeHandle
= INVALID_HANDLE_VALUE
;
1034 DPRINT("Service->Type: %lu\n", Service
->Status
.dwServiceType
);
1036 if (Service
->Status
.dwServiceType
& SERVICE_DRIVER
)
1039 dwError
= ScmLoadDriver(Service
);
1040 if (dwError
== ERROR_SUCCESS
)
1041 Service
->Status
.dwControlsAccepted
= SERVICE_ACCEPT_STOP
;
1045 /* Start user-mode service */
1046 dwError
= ScmStartUserModeService(Service
, argc
, argv
);
1049 DPRINT("ScmStartService() done (Error %lu)\n", dwError
);
1051 if (dwError
== ERROR_SUCCESS
)
1055 Group
->ServicesRunning
= TRUE
;
1057 Service
->Status
.dwCurrentState
= SERVICE_RUNNING
;
1062 switch (Service
->ErrorControl
)
1064 case SERVICE_ERROR_NORMAL
:
1065 /* FIXME: Log error */
1068 case SERVICE_ERROR_SEVERE
:
1069 if (IsLastKnownGood
== FALSE
)
1071 /* FIXME: Boot last known good configuration */
1075 case SERVICE_ERROR_CRITICAL
:
1076 if (IsLastKnownGood
== FALSE
)
1078 /* FIXME: Boot last known good configuration */
1094 ScmAutoStartServices(VOID
)
1096 PLIST_ENTRY GroupEntry
;
1097 PLIST_ENTRY ServiceEntry
;
1098 PSERVICE_GROUP CurrentGroup
;
1099 PSERVICE CurrentService
;
1102 /* Clear 'ServiceVisited' flag */
1103 ServiceEntry
= ServiceListHead
.Flink
;
1104 while (ServiceEntry
!= &ServiceListHead
)
1106 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1107 CurrentService
->ServiceVisited
= FALSE
;
1108 ServiceEntry
= ServiceEntry
->Flink
;
1111 /* Start all services which are members of an existing group */
1112 GroupEntry
= GroupListHead
.Flink
;
1113 while (GroupEntry
!= &GroupListHead
)
1115 CurrentGroup
= CONTAINING_RECORD(GroupEntry
, SERVICE_GROUP
, GroupListEntry
);
1117 DPRINT("Group '%S'\n", CurrentGroup
->lpGroupName
);
1119 /* Start all services witch have a valid tag */
1120 for (i
= 0; i
< CurrentGroup
->TagCount
; i
++)
1122 ServiceEntry
= ServiceListHead
.Flink
;
1123 while (ServiceEntry
!= &ServiceListHead
)
1125 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1127 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1128 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1129 (CurrentService
->ServiceVisited
== FALSE
) &&
1130 (CurrentService
->dwTag
== CurrentGroup
->TagArray
[i
]))
1132 CurrentService
->ServiceVisited
= TRUE
;
1133 ScmStartService(CurrentService
, 0, NULL
);
1136 ServiceEntry
= ServiceEntry
->Flink
;
1140 /* Start all services which have an invalid tag or which do not have a tag */
1141 ServiceEntry
= ServiceListHead
.Flink
;
1142 while (ServiceEntry
!= &ServiceListHead
)
1144 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1146 if ((CurrentService
->lpGroup
== CurrentGroup
) &&
1147 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1148 (CurrentService
->ServiceVisited
== FALSE
))
1150 CurrentService
->ServiceVisited
= TRUE
;
1151 ScmStartService(CurrentService
, 0, NULL
);
1154 ServiceEntry
= ServiceEntry
->Flink
;
1157 GroupEntry
= GroupEntry
->Flink
;
1160 /* Start all services which are members of any non-existing group */
1161 ServiceEntry
= ServiceListHead
.Flink
;
1162 while (ServiceEntry
!= &ServiceListHead
)
1164 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1166 if ((CurrentService
->lpGroup
!= NULL
) &&
1167 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1168 (CurrentService
->ServiceVisited
== FALSE
))
1170 CurrentService
->ServiceVisited
= TRUE
;
1171 ScmStartService(CurrentService
, 0, NULL
);
1174 ServiceEntry
= ServiceEntry
->Flink
;
1177 /* Start all services which are not a member of any group */
1178 ServiceEntry
= ServiceListHead
.Flink
;
1179 while (ServiceEntry
!= &ServiceListHead
)
1181 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1183 if ((CurrentService
->lpGroup
== NULL
) &&
1184 (CurrentService
->dwStartType
== SERVICE_AUTO_START
) &&
1185 (CurrentService
->ServiceVisited
== FALSE
))
1187 CurrentService
->ServiceVisited
= TRUE
;
1188 ScmStartService(CurrentService
, 0, NULL
);
1191 ServiceEntry
= ServiceEntry
->Flink
;
1194 /* Clear 'ServiceVisited' flag again */
1195 ServiceEntry
= ServiceListHead
.Flink
;
1196 while (ServiceEntry
!= &ServiceListHead
)
1198 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1199 CurrentService
->ServiceVisited
= FALSE
;
1200 ServiceEntry
= ServiceEntry
->Flink
;
1206 ScmAutoShutdownServices(VOID
)
1208 PLIST_ENTRY ServiceEntry
;
1209 PSERVICE CurrentService
;
1210 SERVICE_STATUS ServiceStatus
;
1212 DPRINT("ScmAutoShutdownServices() called\n");
1214 ServiceEntry
= ServiceListHead
.Flink
;
1215 while (ServiceEntry
!= &ServiceListHead
)
1217 CurrentService
= CONTAINING_RECORD(ServiceEntry
, SERVICE
, ServiceListEntry
);
1219 if (CurrentService
->Status
.dwCurrentState
== SERVICE_RUNNING
||
1220 CurrentService
->Status
.dwCurrentState
== SERVICE_START_PENDING
)
1222 /* shutdown service */
1223 ScmControlService(CurrentService
, SERVICE_CONTROL_STOP
, &ServiceStatus
);
1226 ServiceEntry
= ServiceEntry
->Flink
;
1229 DPRINT("ScmGetBootAndSystemDriverState() done\n");