8473509ca80151656bac12f5769a6bd3b8c239eb
[reactos.git] / reactos / subsys / system / services / database.c
1 /*
2 *
3 * service control manager
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "services.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 /* TYPES *********************************************************************/
35
36 typedef struct _SERVICE_GROUP
37 {
38 LIST_ENTRY GroupListEntry;
39 UNICODE_STRING GroupName;
40
41 BOOLEAN ServicesRunning;
42 ULONG TagCount;
43 PULONG TagArray;
44
45 } SERVICE_GROUP, *PSERVICE_GROUP;
46
47
48 /* GLOBALS *******************************************************************/
49
50 LIST_ENTRY GroupListHead;
51 LIST_ENTRY ServiceListHead;
52
53 static RTL_RESOURCE DatabaseLock;
54
55
56 /* FUNCTIONS *****************************************************************/
57
58 PSERVICE
59 ScmGetServiceEntryByName(LPWSTR lpServiceName)
60 {
61 PLIST_ENTRY ServiceEntry;
62 PSERVICE CurrentService;
63
64 DPRINT("ScmGetServiceEntryByName() called\n");
65
66 ServiceEntry = ServiceListHead.Flink;
67 while (ServiceEntry != &ServiceListHead)
68 {
69 CurrentService = CONTAINING_RECORD(ServiceEntry,
70 SERVICE,
71 ServiceListEntry);
72 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
73 {
74 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
75 return CurrentService;
76 }
77
78 ServiceEntry = ServiceEntry->Flink;
79 }
80
81 DPRINT("Couldn't find a matching service\n");
82
83 return NULL;
84 }
85
86
87 PSERVICE
88 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
89 {
90 PLIST_ENTRY ServiceEntry;
91 PSERVICE CurrentService;
92
93 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
94
95 ServiceEntry = ServiceListHead.Flink;
96 while (ServiceEntry != &ServiceListHead)
97 {
98 CurrentService = CONTAINING_RECORD(ServiceEntry,
99 SERVICE,
100 ServiceListEntry);
101 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
102 {
103 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
104 return CurrentService;
105 }
106
107 ServiceEntry = ServiceEntry->Flink;
108 }
109
110 DPRINT("Couldn't find a matching service\n");
111
112 return NULL;
113 }
114
115
116 static NTSTATUS STDCALL
117 CreateGroupOrderListRoutine(PWSTR ValueName,
118 ULONG ValueType,
119 PVOID ValueData,
120 ULONG ValueLength,
121 PVOID Context,
122 PVOID EntryContext)
123 {
124 PSERVICE_GROUP Group;
125
126 DPRINT("CreateGroupOrderListRoutine(%S, %x, %x, %x, %x, %x)\n",
127 ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
128
129 if (ValueType == REG_BINARY &&
130 ValueData != NULL &&
131 ValueLength >= sizeof(DWORD) &&
132 ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
133 {
134 Group = (PSERVICE_GROUP)Context;
135 Group->TagCount = ((PULONG)ValueData)[0];
136 if (Group->TagCount > 0)
137 {
138 if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
139 {
140 Group->TagArray = (PULONG)HeapAlloc(GetProcessHeap(),
141 HEAP_ZERO_MEMORY,
142 Group->TagCount * sizeof(DWORD));
143 if (Group->TagArray == NULL)
144 {
145 Group->TagCount = 0;
146 return STATUS_INSUFFICIENT_RESOURCES;
147 }
148
149 RtlCopyMemory(Group->TagArray,
150 (PULONG)ValueData + 1,
151 Group->TagCount * sizeof(DWORD));
152 }
153 else
154 {
155 Group->TagCount = 0;
156 return STATUS_UNSUCCESSFUL;
157 }
158 }
159 }
160
161 return STATUS_SUCCESS;
162 }
163
164
165 static NTSTATUS STDCALL
166 CreateGroupListRoutine(PWSTR ValueName,
167 ULONG ValueType,
168 PVOID ValueData,
169 ULONG ValueLength,
170 PVOID Context,
171 PVOID EntryContext)
172 {
173 PSERVICE_GROUP Group;
174 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
175 NTSTATUS Status;
176
177 if (ValueType == REG_SZ)
178 {
179 DPRINT("Data: '%S'\n", (PWCHAR)ValueData);
180
181 Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(),
182 HEAP_ZERO_MEMORY,
183 sizeof(SERVICE_GROUP));
184 if (Group == NULL)
185 {
186 return STATUS_INSUFFICIENT_RESOURCES;
187 }
188
189 if (!RtlCreateUnicodeString(&Group->GroupName,
190 (PWSTR)ValueData))
191 {
192 return STATUS_INSUFFICIENT_RESOURCES;
193 }
194
195 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
196 QueryTable[0].Name = (PWSTR)ValueData;
197 QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine;
198
199 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
200 L"GroupOrderList",
201 QueryTable,
202 (PVOID)Group,
203 NULL);
204 DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
205
206 InsertTailList(&GroupListHead,
207 &Group->GroupListEntry);
208 }
209
210 return STATUS_SUCCESS;
211 }
212
213
214 DWORD
215 ScmCreateNewServiceRecord(LPWSTR lpServiceName,
216 PSERVICE *lpServiceRecord)
217 {
218 PSERVICE lpService = NULL;
219
220 DPRINT("Service: '%S'\n", lpServiceName);
221
222 /* Allocate service entry */
223 lpService = HeapAlloc(GetProcessHeap(),
224 HEAP_ZERO_MEMORY,
225 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
226 if (lpService == NULL)
227 return ERROR_NOT_ENOUGH_MEMORY;
228
229 *lpServiceRecord = lpService;
230
231 /* Copy service name */
232 wcscpy(lpService->szServiceName, lpServiceName);
233 lpService->lpServiceName = lpService->szServiceName;
234 lpService->lpDisplayName = lpService->lpServiceName;
235
236 /* Append service entry */
237 InsertTailList(&ServiceListHead,
238 &lpService->ServiceListEntry);
239
240 lpService->Status.dwCurrentState = SERVICE_STOPPED;
241 lpService->Status.dwControlsAccepted = 0;
242 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
243 lpService->Status.dwServiceSpecificExitCode = 0;
244 lpService->Status.dwCheckPoint = 0;
245 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
246
247 return ERROR_SUCCESS;
248 }
249
250
251 static DWORD
252 CreateServiceListEntry(LPWSTR lpServiceName,
253 HKEY hServiceKey)
254 {
255 PSERVICE lpService = NULL;
256 LPWSTR lpDisplayName = NULL;
257 LPWSTR lpGroup = NULL;
258 DWORD dwSize;
259 DWORD dwError;
260 DWORD dwServiceType;
261 DWORD dwStartType;
262 DWORD dwErrorControl;
263 DWORD dwTagId;
264
265 DPRINT("Service: '%S'\n", lpServiceName);
266 if (*lpServiceName == L'{')
267 return ERROR_SUCCESS;
268
269 dwSize = sizeof(DWORD);
270 dwError = RegQueryValueExW(hServiceKey,
271 L"Type",
272 NULL,
273 NULL,
274 (LPBYTE)&dwServiceType,
275 &dwSize);
276 if (dwError != ERROR_SUCCESS)
277 return ERROR_SUCCESS;
278
279 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
280 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
281 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
282 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
283 return ERROR_SUCCESS;
284
285 DPRINT("Service type: %lx\n", dwServiceType);
286
287 dwSize = sizeof(DWORD);
288 dwError = RegQueryValueExW(hServiceKey,
289 L"Start",
290 NULL,
291 NULL,
292 (LPBYTE)&dwStartType,
293 &dwSize);
294 if (dwError != ERROR_SUCCESS)
295 return ERROR_SUCCESS;
296
297 DPRINT("Start type: %lx\n", dwStartType);
298
299 dwSize = sizeof(DWORD);
300 dwError = RegQueryValueExW(hServiceKey,
301 L"ErrorControl",
302 NULL,
303 NULL,
304 (LPBYTE)&dwErrorControl,
305 &dwSize);
306 if (dwError != ERROR_SUCCESS)
307 return ERROR_SUCCESS;
308
309 DPRINT("Error control: %lx\n", dwErrorControl);
310
311 dwError = RegQueryValueExW(hServiceKey,
312 L"Tag",
313 NULL,
314 NULL,
315 (LPBYTE)&dwTagId,
316 &dwSize);
317 if (dwError != ERROR_SUCCESS)
318 dwTagId = 0;
319
320 DPRINT("Tag: %lx\n", dwTagId);
321
322 dwError = ScmReadString(hServiceKey,
323 L"Group",
324 &lpGroup);
325 if (dwError != ERROR_SUCCESS)
326 lpGroup = NULL;
327
328 DPRINT("Group: %S\n", lpGroup);
329
330 dwError = ScmReadString(hServiceKey,
331 L"DisplayName",
332 &lpDisplayName);
333 if (dwError != ERROR_SUCCESS)
334 lpDisplayName = NULL;
335
336 DPRINT("Display name: %S\n", lpDisplayName);
337
338 dwError = ScmCreateNewServiceRecord(lpServiceName,
339 &lpService);
340 if (dwError != ERROR_SUCCESS)
341 goto done;
342
343 lpService->Status.dwServiceType = dwServiceType;
344 lpService->dwStartType = dwStartType;
345 lpService->dwErrorControl = dwErrorControl;
346 lpService->dwTag = dwTagId;
347
348 if (lpGroup != NULL)
349 {
350 lpService->lpServiceGroup = lpGroup;
351 lpGroup = NULL;
352 }
353
354 if (lpDisplayName != NULL)
355 {
356 lpService->lpDisplayName = lpDisplayName;
357 lpDisplayName = NULL;
358 }
359
360 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
361 DPRINT("Group: '%S'\n", lpService->lpServiceGroup);
362 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
363 lpService->dwStartType,
364 lpService->Status.dwServiceType,
365 lpService->dwTag,
366 lpService->dwErrorControl);
367
368 if (ScmIsDeleteFlagSet(hServiceKey))
369 lpService->bDeleted = TRUE;
370
371 done:;
372 if (lpGroup != NULL)
373 HeapFree(GetProcessHeap(), 0, lpGroup);
374
375 if (lpDisplayName != NULL)
376 HeapFree(GetProcessHeap(), 0, lpDisplayName);
377
378 return dwError;
379 }
380
381
382 DWORD
383 ScmReadGroupList(VOID)
384 {
385 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
386 NTSTATUS Status;
387
388 InitializeListHead(&GroupListHead);
389
390 /* Build group order list */
391 RtlZeroMemory(&QueryTable,
392 sizeof(QueryTable));
393
394 QueryTable[0].Name = L"List";
395 QueryTable[0].QueryRoutine = CreateGroupListRoutine;
396
397 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
398 L"ServiceGroupOrder",
399 QueryTable,
400 NULL,
401 NULL);
402
403 return RtlNtStatusToDosError(Status);
404 }
405
406
407 VOID
408 ScmDeleteMarkedServices(VOID)
409 {
410 PLIST_ENTRY ServiceEntry;
411 PSERVICE CurrentService;
412
413 ServiceEntry = ServiceListHead.Flink;
414 while (ServiceEntry != &ServiceListHead)
415 {
416 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
417
418 ServiceEntry = ServiceEntry->Flink;
419
420 if (CurrentService->bDeleted == TRUE)
421 {
422 DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
423
424 /* FIXME: Delete the registry keys */
425
426 /* FIXME: Delete the service record from the list */
427
428 }
429 }
430 }
431
432
433 DWORD
434 ScmCreateServiceDatabase(VOID)
435 {
436 WCHAR szSubKey[MAX_PATH];
437 HKEY hServicesKey;
438 HKEY hServiceKey;
439 DWORD dwSubKey;
440 DWORD dwSubKeyLength;
441 FILETIME ftLastChanged;
442 DWORD dwError;
443
444 DPRINT("ScmCreateServiceDatabase() called\n");
445
446 dwError = ScmReadGroupList();
447 if (dwError != ERROR_SUCCESS)
448 return dwError;
449
450 /* Initialize basic variables */
451 InitializeListHead(&ServiceListHead);
452
453 /* Initialize the database lock */
454 RtlInitializeResource(&DatabaseLock);
455
456 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
457 L"System\\CurrentControlSet\\Services",
458 0,
459 KEY_READ,
460 &hServicesKey);
461 if (dwError != ERROR_SUCCESS)
462 return dwError;
463
464 dwSubKey = 0;
465 for (;;)
466 {
467 dwSubKeyLength = MAX_PATH;
468 dwError = RegEnumKeyExW(hServicesKey,
469 dwSubKey,
470 szSubKey,
471 &dwSubKeyLength,
472 NULL,
473 NULL,
474 NULL,
475 &ftLastChanged);
476 if (dwError == ERROR_SUCCESS &&
477 szSubKey[0] != L'{')
478 {
479 DPRINT("SubKeyName: '%S'\n", szSubKey);
480
481 dwError = RegOpenKeyExW(hServicesKey,
482 szSubKey,
483 0,
484 KEY_READ,
485 &hServiceKey);
486 if (dwError == ERROR_SUCCESS)
487 {
488 dwError = CreateServiceListEntry(szSubKey,
489 hServiceKey);
490
491 RegCloseKey(hServiceKey);
492 }
493 }
494
495 if (dwError != ERROR_SUCCESS)
496 break;
497
498 dwSubKey++;
499 }
500
501 RegCloseKey(hServicesKey);
502
503 /* Delete services that are marked for delete */
504 ScmDeleteMarkedServices();
505
506 DPRINT("ScmCreateServiceDatabase() done\n");
507
508 return ERROR_SUCCESS;
509 }
510
511
512 static NTSTATUS
513 ScmCheckDriver(PSERVICE Service)
514 {
515 OBJECT_ATTRIBUTES ObjectAttributes;
516 UNICODE_STRING DirName;
517 HANDLE DirHandle;
518 NTSTATUS Status;
519 POBJECT_DIRECTORY_INFORMATION DirInfo;
520 ULONG BufferLength;
521 ULONG DataLength;
522 ULONG Index;
523 PLIST_ENTRY GroupEntry;
524 PSERVICE_GROUP CurrentGroup;
525
526 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
527
528 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
529 {
530 RtlInitUnicodeString(&DirName,
531 L"\\Driver");
532 }
533 else
534 {
535 RtlInitUnicodeString(&DirName,
536 L"\\FileSystem");
537 }
538
539 InitializeObjectAttributes(&ObjectAttributes,
540 &DirName,
541 0,
542 NULL,
543 NULL);
544
545 Status = NtOpenDirectoryObject(&DirHandle,
546 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
547 &ObjectAttributes);
548 if (!NT_SUCCESS(Status))
549 {
550 return Status;
551 }
552
553 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
554 2 * MAX_PATH * sizeof(WCHAR);
555 DirInfo = HeapAlloc(GetProcessHeap(),
556 HEAP_ZERO_MEMORY,
557 BufferLength);
558
559 Index = 0;
560 while (TRUE)
561 {
562 Status = NtQueryDirectoryObject(DirHandle,
563 DirInfo,
564 BufferLength,
565 TRUE,
566 FALSE,
567 &Index,
568 &DataLength);
569 if (Status == STATUS_NO_MORE_ENTRIES)
570 {
571 /* FIXME: Add current service to 'failed service' list */
572 DPRINT("Service '%S' failed\n", Service->lpServiceName);
573 break;
574 }
575
576 if (!NT_SUCCESS(Status))
577 break;
578
579 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);
580
581 if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
582 {
583 DPRINT("Found: '%S' '%wZ'\n",
584 Service->lpServiceName, &DirInfo->ObjectName);
585
586 /* Mark service as 'running' */
587 Service->Status.dwCurrentState = SERVICE_RUNNING;
588
589 /* Find the driver's group and mark it as 'running' */
590 if (Service->lpServiceGroup != NULL)
591 {
592 GroupEntry = GroupListHead.Flink;
593 while (GroupEntry != &GroupListHead)
594 {
595 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
596
597 DPRINT("Checking group '%wZ'\n", &CurrentGroup->GroupName);
598 if (Service->lpServiceGroup != NULL &&
599 _wcsicmp(Service->lpServiceGroup, CurrentGroup->GroupName.Buffer) == 0)
600 {
601 CurrentGroup->ServicesRunning = TRUE;
602 }
603
604 GroupEntry = GroupEntry->Flink;
605 }
606 }
607 break;
608 }
609 }
610
611 HeapFree(GetProcessHeap(),
612 0,
613 DirInfo);
614 NtClose(DirHandle);
615
616 return STATUS_SUCCESS;
617 }
618
619
620 VOID
621 ScmGetBootAndSystemDriverState(VOID)
622 {
623 PLIST_ENTRY ServiceEntry;
624 PSERVICE CurrentService;
625
626 DPRINT("ScmGetBootAndSystemDriverState() called\n");
627
628 ServiceEntry = ServiceListHead.Flink;
629 while (ServiceEntry != &ServiceListHead)
630 {
631 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
632
633 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
634 CurrentService->dwStartType == SERVICE_SYSTEM_START)
635 {
636 /* Check driver */
637 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
638
639 ScmCheckDriver(CurrentService);
640 }
641
642 ServiceEntry = ServiceEntry->Flink;
643 }
644
645 DPRINT("ScmGetBootAndSystemDriverState() done\n");
646 }
647
648
649 static NTSTATUS
650 ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
651 {
652 PSCM_START_PACKET StartPacket;
653 DWORD TotalLength;
654 #if 0
655 DWORD Length;
656 #endif
657 PWSTR Ptr;
658 DWORD Count;
659
660 DPRINT("ScmSendStartCommand() called\n");
661
662 /* Calculate the total length of the start command line */
663 TotalLength = wcslen(Service->lpServiceName) + 1;
664 #if 0
665 if (Arguments != NULL)
666 {
667 Ptr = Arguments;
668 while (*Ptr)
669 {
670 Length = wcslen(Ptr) + 1;
671 TotalLength += Length;
672 Ptr += Length;
673 }
674 }
675 #endif
676 TotalLength++;
677
678 /* Allocate start command packet */
679 StartPacket = HeapAlloc(GetProcessHeap(),
680 HEAP_ZERO_MEMORY,
681 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
682 if (StartPacket == NULL)
683 return STATUS_INSUFFICIENT_RESOURCES;
684
685 StartPacket->Command = SCM_START_COMMAND;
686 StartPacket->Size = TotalLength;
687 Ptr = &StartPacket->Arguments[0];
688 wcscpy(Ptr, Service->lpServiceName);
689 Ptr += (wcslen(Service->lpServiceName) + 1);
690
691 /* FIXME: Copy argument list */
692
693 *Ptr = 0;
694
695 /* Send the start command */
696 WriteFile(Service->ControlPipeHandle,
697 StartPacket,
698 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
699 &Count,
700 NULL);
701
702 /* FIXME: Read the reply */
703
704 HeapFree(GetProcessHeap(),
705 0,
706 StartPacket);
707
708 DPRINT("ScmSendStartCommand() done\n");
709
710 return STATUS_SUCCESS;
711 }
712
713
714 static NTSTATUS
715 ScmStartUserModeService(PSERVICE Service)
716 {
717 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
718 PROCESS_INFORMATION ProcessInformation;
719 STARTUPINFOW StartupInfo;
720 UNICODE_STRING ImagePath;
721 ULONG Type;
722 BOOL Result;
723 NTSTATUS Status;
724
725 RtlInitUnicodeString(&ImagePath, NULL);
726
727 /* Get service data */
728 RtlZeroMemory(&QueryTable,
729 sizeof(QueryTable));
730
731 QueryTable[0].Name = L"Type";
732 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
733 QueryTable[0].EntryContext = &Type;
734
735 QueryTable[1].Name = L"ImagePath";
736 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
737 QueryTable[1].EntryContext = &ImagePath;
738
739 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
740 Service->lpServiceName,
741 QueryTable,
742 NULL,
743 NULL);
744 if (!NT_SUCCESS(Status))
745 {
746 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
747 return Status;
748 }
749 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
750 DPRINT("Type: %lx\n", Type);
751
752 /* Create '\\.\pipe\net\NtControlPipe' instance */
753 Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
754 PIPE_ACCESS_DUPLEX,
755 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
756 100,
757 8000,
758 4,
759 30000,
760 NULL);
761 DPRINT("CreateNamedPipeW() done\n");
762 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
763 {
764 DPRINT1("Failed to create control pipe!\n");
765 return STATUS_UNSUCCESSFUL;
766 }
767
768 StartupInfo.cb = sizeof(StartupInfo);
769 StartupInfo.lpReserved = NULL;
770 StartupInfo.lpDesktop = NULL;
771 StartupInfo.lpTitle = NULL;
772 StartupInfo.dwFlags = 0;
773 StartupInfo.cbReserved2 = 0;
774 StartupInfo.lpReserved2 = 0;
775
776 Result = CreateProcessW(ImagePath.Buffer,
777 NULL,
778 NULL,
779 NULL,
780 FALSE,
781 DETACHED_PROCESS | CREATE_SUSPENDED,
782 NULL,
783 NULL,
784 &StartupInfo,
785 &ProcessInformation);
786 RtlFreeUnicodeString(&ImagePath);
787
788 if (!Result)
789 {
790 /* Close control pipe */
791 CloseHandle(Service->ControlPipeHandle);
792 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
793
794 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
795 return STATUS_UNSUCCESSFUL;
796 }
797
798 DPRINT("Process Id: %lu Handle %lx\n",
799 ProcessInformation.dwProcessId,
800 ProcessInformation.hProcess);
801 DPRINT("Thread Id: %lu Handle %lx\n",
802 ProcessInformation.dwThreadId,
803 ProcessInformation.hThread);
804
805 /* Get process and thread ids */
806 Service->ProcessId = ProcessInformation.dwProcessId;
807 Service->ThreadId = ProcessInformation.dwThreadId;
808
809 /* Resume Thread */
810 ResumeThread(ProcessInformation.hThread);
811
812 /* Connect control pipe */
813 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
814 {
815 DWORD dwProcessId = 0;
816 DWORD dwRead = 0;
817
818 DPRINT("Control pipe connected!\n");
819
820 /* Read thread id from pipe */
821 if (!ReadFile(Service->ControlPipeHandle,
822 (LPVOID)&dwProcessId,
823 sizeof(DWORD),
824 &dwRead,
825 NULL))
826 {
827 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
828 GetLastError());
829 Status = STATUS_UNSUCCESSFUL;
830 }
831 else
832 {
833 DPRINT("Received process id %lu\n", dwProcessId);
834
835 /* FIXME: Send start command */
836
837 Status = STATUS_SUCCESS;
838 }
839 }
840 else
841 {
842 DPRINT("Connecting control pipe failed!\n");
843
844 /* Close control pipe */
845 CloseHandle(Service->ControlPipeHandle);
846 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
847 Service->ProcessId = 0;
848 Service->ThreadId = 0;
849 Status = STATUS_UNSUCCESSFUL;
850 }
851
852 ScmSendStartCommand(Service, NULL);
853
854 /* Close process and thread handle */
855 CloseHandle(ProcessInformation.hThread);
856 CloseHandle(ProcessInformation.hProcess);
857
858 return Status;
859 }
860
861
862 static NTSTATUS
863 ScmStartService(PSERVICE Service,
864 PSERVICE_GROUP Group)
865 {
866 NTSTATUS Status;
867
868 DPRINT("ScmStartService() called\n");
869
870 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
871 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
872
873 if (Service->Status.dwServiceType & SERVICE_DRIVER)
874 {
875 /* Load driver */
876 Status = ScmLoadDriver(Service);
877 if (Status == STATUS_SUCCESS)
878 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
879 }
880 else
881 {
882 /* Start user-mode service */
883 Status = ScmStartUserModeService(Service);
884 }
885
886 DPRINT("ScmStartService() done (Status %lx)\n", Status);
887
888 if (NT_SUCCESS(Status))
889 {
890 if (Group != NULL)
891 {
892 Group->ServicesRunning = TRUE;
893 }
894 Service->Status.dwCurrentState = SERVICE_RUNNING;
895 }
896 #if 0
897 else
898 {
899 switch (Service->ErrorControl)
900 {
901 case SERVICE_ERROR_NORMAL:
902 /* FIXME: Log error */
903 break;
904
905 case SERVICE_ERROR_SEVERE:
906 if (IsLastKnownGood == FALSE)
907 {
908 /* FIXME: Boot last known good configuration */
909 }
910 break;
911
912 case SERVICE_ERROR_CRITICAL:
913 if (IsLastKnownGood == FALSE)
914 {
915 /* FIXME: Boot last known good configuration */
916 }
917 else
918 {
919 /* FIXME: BSOD! */
920 }
921 break;
922 }
923 }
924 #endif
925
926 return Status;
927 }
928
929
930 VOID
931 ScmAutoStartServices(VOID)
932 {
933 PLIST_ENTRY GroupEntry;
934 PLIST_ENTRY ServiceEntry;
935 PSERVICE_GROUP CurrentGroup;
936 PSERVICE CurrentService;
937 ULONG i;
938
939 /* Clear 'ServiceVisited' flag */
940 ServiceEntry = ServiceListHead.Flink;
941 while (ServiceEntry != &ServiceListHead)
942 {
943 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
944 CurrentService->ServiceVisited = FALSE;
945 ServiceEntry = ServiceEntry->Flink;
946 }
947
948 /* Start all services which are members of an existing group */
949 GroupEntry = GroupListHead.Flink;
950 while (GroupEntry != &GroupListHead)
951 {
952 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
953
954 DPRINT("Group '%wZ'\n", &CurrentGroup->GroupName);
955
956 /* Start all services witch have a valid tag */
957 for (i = 0; i < CurrentGroup->TagCount; i++)
958 {
959 ServiceEntry = ServiceListHead.Flink;
960 while (ServiceEntry != &ServiceListHead)
961 {
962 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
963
964 if ((CurrentService->lpServiceGroup != NULL) &&
965 (_wcsicmp(CurrentGroup->GroupName.Buffer, CurrentService->lpServiceGroup) == 0) &&
966 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
967 (CurrentService->ServiceVisited == FALSE) &&
968 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
969 {
970 CurrentService->ServiceVisited = TRUE;
971 ScmStartService(CurrentService,
972 CurrentGroup);
973 }
974
975 ServiceEntry = ServiceEntry->Flink;
976 }
977 }
978
979 /* Start all services which have an invalid tag or which do not have a tag */
980 ServiceEntry = ServiceListHead.Flink;
981 while (ServiceEntry != &ServiceListHead)
982 {
983 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
984
985 if ((CurrentService->lpServiceGroup != NULL) &&
986 (_wcsicmp(CurrentGroup->GroupName.Buffer, CurrentService->lpServiceGroup) == 0) &&
987 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
988 (CurrentService->ServiceVisited == FALSE))
989 {
990 CurrentService->ServiceVisited = TRUE;
991 ScmStartService(CurrentService,
992 CurrentGroup);
993 }
994
995 ServiceEntry = ServiceEntry->Flink;
996 }
997
998 GroupEntry = GroupEntry->Flink;
999 }
1000
1001 /* Start all services which are members of any non-existing group */
1002 ServiceEntry = ServiceListHead.Flink;
1003 while (ServiceEntry != &ServiceListHead)
1004 {
1005 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1006
1007 if ((CurrentService->lpServiceGroup != NULL) &&
1008 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1009 (CurrentService->ServiceVisited == FALSE))
1010 {
1011 CurrentService->ServiceVisited = TRUE;
1012 ScmStartService(CurrentService,
1013 NULL);
1014 }
1015
1016 ServiceEntry = ServiceEntry->Flink;
1017 }
1018
1019 /* Start all services which are not a member of any group */
1020 ServiceEntry = ServiceListHead.Flink;
1021 while (ServiceEntry != &ServiceListHead)
1022 {
1023 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1024
1025 if ((CurrentService->lpServiceGroup == NULL) &&
1026 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1027 (CurrentService->ServiceVisited == FALSE))
1028 {
1029 CurrentService->ServiceVisited = TRUE;
1030 ScmStartService(CurrentService,
1031 NULL);
1032 }
1033
1034 ServiceEntry = ServiceEntry->Flink;
1035 }
1036
1037 /* Clear 'ServiceVisited' flag again */
1038 ServiceEntry = ServiceListHead.Flink;
1039 while (ServiceEntry != &ServiceListHead)
1040 {
1041 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1042 CurrentService->ServiceVisited = FALSE;
1043 ServiceEntry = ServiceEntry->Flink;
1044 }
1045 }
1046
1047 /* EOF */