c5d8e2ca3e6bc3e9cb1911082d26622a0f9bd10a
[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 #include <services/services.h>
30
31 #define NDEBUG
32 #include <debug.h>
33
34
35 /* TYPES *********************************************************************/
36
37 typedef struct _SERVICE_GROUP
38 {
39 LIST_ENTRY GroupListEntry;
40 UNICODE_STRING GroupName;
41
42 BOOLEAN ServicesRunning;
43 ULONG TagCount;
44 PULONG TagArray;
45
46 } SERVICE_GROUP, *PSERVICE_GROUP;
47
48
49
50
51 /* GLOBALS *******************************************************************/
52
53 LIST_ENTRY GroupListHead;
54 LIST_ENTRY ServiceListHead;
55
56
57 /* FUNCTIONS *****************************************************************/
58
59 PSERVICE
60 ScmGetServiceEntryByName(PUNICODE_STRING ServiceName)
61 {
62 PLIST_ENTRY ServiceEntry;
63 PSERVICE CurrentService;
64
65 DPRINT("ScmGetServiceEntryByName() called\n");
66
67 ServiceEntry = ServiceListHead.Flink;
68 while (ServiceEntry != &ServiceListHead)
69 {
70 CurrentService = CONTAINING_RECORD(ServiceEntry,
71 SERVICE,
72 ServiceListEntry);
73 if (RtlEqualUnicodeString(&CurrentService->ServiceName, ServiceName, TRUE))
74 {
75 DPRINT("Found service: '%wZ'\n", &CurrentService->ServiceName);
76 return CurrentService;
77 }
78
79 ServiceEntry = ServiceEntry->Flink;
80 }
81
82 DPRINT("Couldn't find a matching service\n");
83
84 return NULL;
85 }
86
87
88 static NTSTATUS STDCALL
89 CreateGroupOrderListRoutine(PWSTR ValueName,
90 ULONG ValueType,
91 PVOID ValueData,
92 ULONG ValueLength,
93 PVOID Context,
94 PVOID EntryContext)
95 {
96 PSERVICE_GROUP Group;
97
98 DPRINT("IopGetGroupOrderList(%S, %x, %x, %x, %x, %x)\n",
99 ValueName, ValueType, ValueData, ValueLength, Context, EntryContext);
100
101 if (ValueType == REG_BINARY &&
102 ValueData != NULL &&
103 ValueLength >= sizeof(DWORD) &&
104 ValueLength >= (*(PULONG)ValueData + 1) * sizeof(DWORD))
105 {
106 Group = (PSERVICE_GROUP)Context;
107 Group->TagCount = ((PULONG)ValueData)[0];
108 if (Group->TagCount > 0)
109 {
110 if (ValueLength >= (Group->TagCount + 1) * sizeof(DWORD))
111 {
112 Group->TagArray = (PULONG)HeapAlloc(GetProcessHeap(),
113 HEAP_ZERO_MEMORY,
114 Group->TagCount * sizeof(DWORD));
115 if (Group->TagArray == NULL)
116 {
117 Group->TagCount = 0;
118 return STATUS_INSUFFICIENT_RESOURCES;
119 }
120 RtlCopyMemory(Group->TagArray,
121 (PULONG)ValueData + 1,
122 Group->TagCount * sizeof(DWORD));
123 }
124 else
125 {
126 Group->TagCount = 0;
127 return STATUS_UNSUCCESSFUL;
128 }
129 }
130 }
131 return STATUS_SUCCESS;
132 }
133
134
135 static NTSTATUS STDCALL
136 CreateGroupListRoutine(PWSTR ValueName,
137 ULONG ValueType,
138 PVOID ValueData,
139 ULONG ValueLength,
140 PVOID Context,
141 PVOID EntryContext)
142 {
143 PSERVICE_GROUP Group;
144 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
145 NTSTATUS Status;
146
147 if (ValueType == REG_SZ)
148 {
149 DPRINT("Data: '%S'\n", (PWCHAR)ValueData);
150
151 Group = (PSERVICE_GROUP)HeapAlloc(GetProcessHeap(),
152 HEAP_ZERO_MEMORY,
153 sizeof(SERVICE_GROUP));
154 if (Group == NULL)
155 {
156 return STATUS_INSUFFICIENT_RESOURCES;
157 }
158
159 if (!RtlCreateUnicodeString(&Group->GroupName,
160 (PWSTR)ValueData))
161 {
162 return STATUS_INSUFFICIENT_RESOURCES;
163 }
164
165 RtlZeroMemory(&QueryTable, sizeof(QueryTable));
166 QueryTable[0].Name = (PWSTR)ValueData;
167 QueryTable[0].QueryRoutine = CreateGroupOrderListRoutine;
168
169 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
170 L"GroupOrderList",
171 QueryTable,
172 (PVOID)Group,
173 NULL);
174 DPRINT("%x %d %S\n", Status, Group->TagCount, (PWSTR)ValueData);
175
176
177 InsertTailList(&GroupListHead,
178 &Group->GroupListEntry);
179 }
180
181 return STATUS_SUCCESS;
182 }
183
184
185 static NTSTATUS STDCALL
186 CreateServiceListEntry(PUNICODE_STRING ServiceName)
187 {
188 RTL_QUERY_REGISTRY_TABLE QueryTable[6];
189 PSERVICE Service = NULL;
190 NTSTATUS Status;
191
192 DPRINT("Service: '%wZ'\n", ServiceName);
193
194 /* Allocate service entry */
195 Service = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
196 sizeof(SERVICE));
197 if (Service == NULL)
198 {
199 return STATUS_INSUFFICIENT_RESOURCES;
200 }
201
202 /* Copy service name */
203 Service->ServiceName.Length = ServiceName->Length;
204 Service->ServiceName.MaximumLength = ServiceName->Length + sizeof(WCHAR);
205 Service->ServiceName.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
206 Service->ServiceName.MaximumLength);
207 if (Service->ServiceName.Buffer == NULL)
208 {
209 HeapFree(GetProcessHeap(), 0, Service);
210 return STATUS_INSUFFICIENT_RESOURCES;
211 }
212
213 RtlCopyMemory(Service->ServiceName.Buffer,
214 ServiceName->Buffer,
215 ServiceName->Length);
216 Service->ServiceName.Buffer[ServiceName->Length / sizeof(WCHAR)] = 0;
217
218 /* Build registry path */
219 Service->RegistryPath.MaximumLength = MAX_PATH * sizeof(WCHAR);
220 Service->RegistryPath.Buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
221 MAX_PATH * sizeof(WCHAR));
222 if (Service->ServiceName.Buffer == NULL)
223 {
224 HeapFree(GetProcessHeap(), 0, Service->ServiceName.Buffer);
225 HeapFree(GetProcessHeap(), 0, Service);
226 return STATUS_INSUFFICIENT_RESOURCES;
227 }
228
229 wcscpy(Service->RegistryPath.Buffer,
230 L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
231 wcscat(Service->RegistryPath.Buffer,
232 Service->ServiceName.Buffer);
233 Service->RegistryPath.Length = wcslen(Service->RegistryPath.Buffer) * sizeof(WCHAR);
234
235 /* Get service data */
236 RtlZeroMemory(&QueryTable,
237 sizeof(QueryTable));
238
239 QueryTable[0].Name = L"Start";
240 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
241 QueryTable[0].EntryContext = &Service->Start;
242
243 QueryTable[1].Name = L"Type";
244 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
245 QueryTable[1].EntryContext = &Service->Type;
246
247 QueryTable[2].Name = L"ErrorControl";
248 QueryTable[2].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
249 QueryTable[2].EntryContext = &Service->ErrorControl;
250
251 QueryTable[3].Name = L"Group";
252 QueryTable[3].Flags = RTL_QUERY_REGISTRY_DIRECT;
253 QueryTable[3].EntryContext = &Service->ServiceGroup;
254
255 QueryTable[4].Name = L"Tag";
256 QueryTable[4].Flags = RTL_QUERY_REGISTRY_DIRECT;
257 QueryTable[4].EntryContext = &Service->Tag;
258
259 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
260 ServiceName->Buffer,
261 QueryTable,
262 NULL,
263 NULL);
264 if (!NT_SUCCESS(Status))
265 {
266 PrintString("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
267 RtlFreeUnicodeString(&Service->RegistryPath);
268 RtlFreeUnicodeString(&Service->ServiceName);
269 HeapFree(GetProcessHeap(), 0, Service);
270 return Status;
271 }
272
273 DPRINT("ServiceName: '%wZ'\n", &Service->ServiceName);
274 DPRINT("RegistryPath: '%wZ'\n", &Service->RegistryPath);
275 DPRINT("ServiceGroup: '%wZ'\n", &Service->ServiceGroup);
276 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
277 Service->Start, Service->Type, Service->Tag, Service->ErrorControl);
278
279 /* Append service entry */
280 InsertTailList(&ServiceListHead,
281 &Service->ServiceListEntry);
282
283 Service->CurrentState = SERVICE_STOPPED;
284 Service->ControlsAccepted = 0;
285 Service->Win32ExitCode = 0;
286 Service->ServiceSpecificExitCode = 0;
287 Service->CheckPoint = 0;
288 Service->WaitHint = 2000; /* 2 seconds */
289
290 return STATUS_SUCCESS;
291 }
292
293
294 NTSTATUS
295 ScmCreateServiceDataBase(VOID)
296 {
297 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
298 OBJECT_ATTRIBUTES ObjectAttributes;
299 UNICODE_STRING ServicesKeyName =
300 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services");
301 UNICODE_STRING SubKeyName;
302 HKEY ServicesKey;
303 ULONG Index;
304 NTSTATUS Status;
305
306 PKEY_BASIC_INFORMATION KeyInfo = NULL;
307 ULONG KeyInfoLength = 0;
308 ULONG ReturnedLength;
309
310 DPRINT("ScmCreateServiceDataBase() called\n");
311
312 /* Initialize basic variables */
313 InitializeListHead(&GroupListHead);
314 InitializeListHead(&ServiceListHead);
315
316 /* Build group order list */
317 RtlZeroMemory(&QueryTable,
318 sizeof(QueryTable));
319
320 QueryTable[0].Name = L"List";
321 QueryTable[0].QueryRoutine = CreateGroupListRoutine;
322
323 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
324 L"ServiceGroupOrder",
325 QueryTable,
326 NULL,
327 NULL);
328 if (!NT_SUCCESS(Status))
329 return Status;
330
331 InitializeObjectAttributes(&ObjectAttributes,
332 &ServicesKeyName,
333 OBJ_CASE_INSENSITIVE,
334 NULL,
335 NULL);
336
337 Status = RtlpNtOpenKey(&ServicesKey,
338 KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS,
339 &ObjectAttributes,
340 0);
341 if (!NT_SUCCESS(Status))
342 return Status;
343
344 /* Allocate key info buffer */
345 KeyInfoLength = sizeof(KEY_BASIC_INFORMATION) + MAX_PATH * sizeof(WCHAR);
346 KeyInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, KeyInfoLength);
347 if (KeyInfo == NULL)
348 {
349 NtClose(ServicesKey);
350 return STATUS_INSUFFICIENT_RESOURCES;
351 }
352
353 Index = 0;
354 while (TRUE)
355 {
356 Status = NtEnumerateKey(ServicesKey,
357 Index,
358 KeyBasicInformation,
359 KeyInfo,
360 KeyInfoLength,
361 &ReturnedLength);
362 if (NT_SUCCESS(Status))
363 {
364 if (KeyInfo->NameLength < MAX_PATH * sizeof(WCHAR))
365 {
366
367 SubKeyName.Length = KeyInfo->NameLength;
368 SubKeyName.MaximumLength = KeyInfo->NameLength + sizeof(WCHAR);
369 SubKeyName.Buffer = KeyInfo->Name;
370 SubKeyName.Buffer[SubKeyName.Length / sizeof(WCHAR)] = 0;
371
372 DPRINT("KeyName: '%wZ'\n", &SubKeyName);
373 Status = CreateServiceListEntry(&SubKeyName);
374
375 /* Ignore services without proper registry. */
376 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
377 {
378 Status = STATUS_SUCCESS;
379 }
380 }
381 }
382
383 if (!NT_SUCCESS(Status))
384 break;
385
386 Index++;
387 }
388
389 HeapFree(GetProcessHeap(), 0, KeyInfo);
390 NtClose(ServicesKey);
391
392 DPRINT("ScmCreateServiceDataBase() done\n");
393
394 return STATUS_SUCCESS;
395 }
396
397
398 static NTSTATUS
399 ScmCheckDriver(PSERVICE Service)
400 {
401 OBJECT_ATTRIBUTES ObjectAttributes;
402 UNICODE_STRING DirName;
403 HANDLE DirHandle;
404 NTSTATUS Status;
405 POBJECT_DIRECTORY_INFORMATION DirInfo;
406 ULONG BufferLength;
407 ULONG DataLength;
408 ULONG Index;
409 PLIST_ENTRY GroupEntry;
410 PSERVICE_GROUP CurrentGroup;
411
412 DPRINT("ScmCheckDriver(%wZ) called\n", &Service->ServiceName);
413
414 if (Service->Type == SERVICE_KERNEL_DRIVER)
415 {
416 RtlInitUnicodeString(&DirName,
417 L"\\Driver");
418 }
419 else
420 {
421 RtlInitUnicodeString(&DirName,
422 L"\\FileSystem");
423 }
424
425 InitializeObjectAttributes(&ObjectAttributes,
426 &DirName,
427 0,
428 NULL,
429 NULL);
430
431 Status = NtOpenDirectoryObject(&DirHandle,
432 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
433 &ObjectAttributes);
434 if (!NT_SUCCESS(Status))
435 {
436 return Status;
437 }
438
439 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
440 2 * MAX_PATH * sizeof(WCHAR);
441 DirInfo = HeapAlloc(GetProcessHeap(),
442 HEAP_ZERO_MEMORY,
443 BufferLength);
444
445 Index = 0;
446 while (TRUE)
447 {
448 Status = NtQueryDirectoryObject(DirHandle,
449 DirInfo,
450 BufferLength,
451 TRUE,
452 FALSE,
453 &Index,
454 &DataLength);
455 if (Status == STATUS_NO_MORE_ENTRIES)
456 {
457 /* FIXME: Add current service to 'failed service' list */
458 DPRINT("Service '%wZ' failed\n", &Service->ServiceName);
459 break;
460 }
461
462 if (!NT_SUCCESS(Status))
463 break;
464
465 DPRINT("Comparing: '%wZ' '%wZ'\n", &Service->ServiceName, &DirInfo->ObjectName);
466
467 if (RtlEqualUnicodeString(&Service->ServiceName, &DirInfo->ObjectName, TRUE))
468 {
469 DPRINT("Found: '%wZ' '%wZ'\n", &Service->ServiceName, &DirInfo->ObjectName);
470
471 /* Mark service as 'running' */
472 Service->CurrentState = SERVICE_RUNNING;
473
474 /* Find the driver's group and mark it as 'running' */
475 if (Service->ServiceGroup.Buffer != NULL)
476 {
477 GroupEntry = GroupListHead.Flink;
478 while (GroupEntry != &GroupListHead)
479 {
480 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
481
482 DPRINT("Checking group '%wZ'\n", &CurrentGroup->GroupName);
483 if (RtlEqualUnicodeString(&Service->ServiceGroup, &CurrentGroup->GroupName, TRUE))
484 {
485 CurrentGroup->ServicesRunning = TRUE;
486 }
487
488 GroupEntry = GroupEntry->Flink;
489 }
490 }
491 break;
492 }
493 }
494
495 HeapFree(GetProcessHeap(),
496 0,
497 DirInfo);
498 NtClose(DirHandle);
499
500 return STATUS_SUCCESS;
501 }
502
503
504 VOID
505 ScmGetBootAndSystemDriverState(VOID)
506 {
507 PLIST_ENTRY ServiceEntry;
508 PSERVICE CurrentService;
509
510 DPRINT("ScmGetBootAndSystemDriverState() called\n");
511
512 ServiceEntry = ServiceListHead.Flink;
513 while (ServiceEntry != &ServiceListHead)
514 {
515 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
516
517 if (CurrentService->Start == SERVICE_BOOT_START ||
518 CurrentService->Start == SERVICE_SYSTEM_START)
519 {
520 /* Check driver */
521 DPRINT(" Checking service: %wZ\n", &CurrentService->ServiceName);
522
523 ScmCheckDriver(CurrentService);
524 }
525 ServiceEntry = ServiceEntry->Flink;
526 }
527
528 DPRINT("ScmGetBootAndSystemDriverState() done\n");
529 }
530
531
532 static NTSTATUS
533 ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
534 {
535 PSCM_START_PACKET StartPacket;
536 DWORD TotalLength;
537 #if 0
538 DWORD Length;
539 #endif
540 PWSTR Ptr;
541 DWORD Count;
542
543 DPRINT("ScmSendStartCommand() called\n");
544
545 /* Calculate the total length of the start command line */
546 TotalLength = wcslen(Service->ServiceName.Buffer) + 1;
547 #if 0
548 if (Arguments != NULL)
549 {
550 Ptr = Arguments;
551 while (*Ptr)
552 {
553 Length = wcslen(Ptr) + 1;
554 TotalLength += Length;
555 Ptr += Length;
556 }
557 }
558 #endif
559 TotalLength++;
560
561 /* Allocate start command packet */
562 StartPacket = HeapAlloc(GetProcessHeap(),
563 HEAP_ZERO_MEMORY,
564 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
565 if (StartPacket == NULL)
566 return STATUS_INSUFFICIENT_RESOURCES;
567
568 StartPacket->Command = SCM_START_COMMAND;
569 StartPacket->Size = TotalLength;
570 Ptr = &StartPacket->Arguments[0];
571 wcscpy(Ptr, Service->ServiceName.Buffer);
572 Ptr += (wcslen(Service->ServiceName.Buffer) + 1);
573
574 /* FIXME: Copy argument list */
575
576 *Ptr = 0;
577
578 /* Send the start command */
579 WriteFile(Service->ControlPipeHandle,
580 StartPacket,
581 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
582 &Count,
583 NULL);
584
585 /* FIXME: Read the reply */
586
587 HeapFree(GetProcessHeap(),
588 0,
589 StartPacket);
590
591 DPRINT("ScmSendStartCommand() done\n");
592
593 return STATUS_SUCCESS;
594 }
595
596
597 static NTSTATUS
598 ScmStartUserModeService(PSERVICE Service)
599 {
600 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
601 PROCESS_INFORMATION ProcessInformation;
602 STARTUPINFOW StartupInfo;
603 UNICODE_STRING ImagePath;
604 ULONG Type;
605 BOOL Result;
606 NTSTATUS Status;
607
608 RtlInitUnicodeString(&ImagePath, NULL);
609
610 /* Get service data */
611 RtlZeroMemory(&QueryTable,
612 sizeof(QueryTable));
613
614 QueryTable[0].Name = L"Type";
615 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
616 QueryTable[0].EntryContext = &Type;
617
618 QueryTable[1].Name = L"ImagePath";
619 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
620 QueryTable[1].EntryContext = &ImagePath;
621
622 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
623 Service->ServiceName.Buffer,
624 QueryTable,
625 NULL,
626 NULL);
627 if (!NT_SUCCESS(Status))
628 {
629 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
630 return Status;
631 }
632 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
633 DPRINT("Type: %lx\n", Type);
634
635 /* Create '\\.\pipe\net\NtControlPipe' instance */
636 Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
637 PIPE_ACCESS_DUPLEX,
638 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
639 100,
640 8000,
641 4,
642 30000,
643 NULL);
644 DPRINT("CreateNamedPipeW() done\n");
645 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
646 {
647 DPRINT1("Failed to create control pipe!\n");
648 return STATUS_UNSUCCESSFUL;
649 }
650
651 StartupInfo.cb = sizeof(StartupInfo);
652 StartupInfo.lpReserved = NULL;
653 StartupInfo.lpDesktop = NULL;
654 StartupInfo.lpTitle = NULL;
655 StartupInfo.dwFlags = 0;
656 StartupInfo.cbReserved2 = 0;
657 StartupInfo.lpReserved2 = 0;
658
659 Result = CreateProcessW(ImagePath.Buffer,
660 NULL,
661 NULL,
662 NULL,
663 FALSE,
664 DETACHED_PROCESS | CREATE_SUSPENDED,
665 NULL,
666 NULL,
667 &StartupInfo,
668 &ProcessInformation);
669 RtlFreeUnicodeString(&ImagePath);
670
671 if (!Result)
672 {
673 /* Close control pipe */
674 CloseHandle(Service->ControlPipeHandle);
675 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
676
677 DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
678 return STATUS_UNSUCCESSFUL;
679 }
680
681 DPRINT("Process Id: %lu Handle %lx\n",
682 ProcessInformation.dwProcessId,
683 ProcessInformation.hProcess);
684 DPRINT("Thread Id: %lu Handle %lx\n",
685 ProcessInformation.dwThreadId,
686 ProcessInformation.hThread);
687
688 /* Get process and thread ids */
689 Service->ProcessId = ProcessInformation.dwProcessId;
690 Service->ThreadId = ProcessInformation.dwThreadId;
691
692 /* Resume Thread */
693 ResumeThread(ProcessInformation.hThread);
694
695 /* Connect control pipe */
696 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
697 {
698 DWORD dwProcessId = 0;
699 DWORD dwRead = 0;
700
701 DPRINT("Control pipe connected!\n");
702
703 /* Read thread id from pipe */
704 if (!ReadFile(Service->ControlPipeHandle,
705 (LPVOID)&dwProcessId,
706 sizeof(DWORD),
707 &dwRead,
708 NULL))
709 {
710 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
711 GetLastError());
712 Status = STATUS_UNSUCCESSFUL;
713 }
714 else
715 {
716 DPRINT("Received process id %lu\n", dwProcessId);
717
718 /* FIXME: Send start command */
719
720 Status = STATUS_SUCCESS;
721 }
722 }
723 else
724 {
725 DPRINT("Connecting control pipe failed!\n");
726
727 /* Close control pipe */
728 CloseHandle(Service->ControlPipeHandle);
729 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
730 Service->ProcessId = 0;
731 Service->ThreadId = 0;
732 Status = STATUS_UNSUCCESSFUL;
733 }
734
735 ScmSendStartCommand(Service, NULL);
736
737 /* Close process and thread handle */
738 CloseHandle(ProcessInformation.hThread);
739 CloseHandle(ProcessInformation.hProcess);
740
741 return Status;
742 }
743
744
745 static NTSTATUS
746 ScmStartService(PSERVICE Service,
747 PSERVICE_GROUP Group)
748 {
749 NTSTATUS Status;
750
751 DPRINT("ScmStartService() called\n");
752
753 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
754 DPRINT("Service->Type: %u\n", Service->Type);
755
756 if (Service->Type == SERVICE_KERNEL_DRIVER ||
757 Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
758 Service->Type == SERVICE_RECOGNIZER_DRIVER)
759 {
760 /* Load driver */
761 DPRINT(" Path: %wZ\n", &Service->RegistryPath);
762 Status = NtLoadDriver(&Service->RegistryPath);
763 }
764 else
765 {
766 /* Start user-mode service */
767 Status = ScmStartUserModeService(Service);
768 }
769
770 DPRINT("ScmStartService() done (Status %lx)\n", Status);
771
772 if (NT_SUCCESS(Status))
773 {
774 if (Group != NULL)
775 {
776 Group->ServicesRunning = TRUE;
777 }
778 Service->CurrentState = SERVICE_RUNNING;
779 }
780 #if 0
781 else
782 {
783 switch (Service->ErrorControl)
784 {
785 case SERVICE_ERROR_NORMAL:
786 /* FIXME: Log error */
787 break;
788
789 case SERVICE_ERROR_SEVERE:
790 if (IsLastKnownGood == FALSE)
791 {
792 /* FIXME: Boot last known good configuration */
793 }
794 break;
795
796 case SERVICE_ERROR_CRITICAL:
797 if (IsLastKnownGood == FALSE)
798 {
799 /* FIXME: Boot last known good configuration */
800 }
801 else
802 {
803 /* FIXME: BSOD! */
804 }
805 break;
806 }
807 }
808 #endif
809
810 return Status;
811 }
812
813
814 VOID
815 ScmAutoStartServices(VOID)
816 {
817 PLIST_ENTRY GroupEntry;
818 PLIST_ENTRY ServiceEntry;
819 PSERVICE_GROUP CurrentGroup;
820 PSERVICE CurrentService;
821 ULONG i;
822
823 /* Clear 'ServiceVisited' flag */
824 ServiceEntry = ServiceListHead.Flink;
825 while (ServiceEntry != &ServiceListHead)
826 {
827 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
828 CurrentService->ServiceVisited = FALSE;
829 ServiceEntry = ServiceEntry->Flink;
830 }
831
832 /* Start all services which are members of an existing group */
833 GroupEntry = GroupListHead.Flink;
834 while (GroupEntry != &GroupListHead)
835 {
836 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
837
838 DPRINT("Group '%wZ'\n", &CurrentGroup->GroupName);
839
840 /* Start all services witch have a valid tag */
841 for (i = 0; i < CurrentGroup->TagCount; i++)
842 {
843 ServiceEntry = ServiceListHead.Flink;
844 while (ServiceEntry != &ServiceListHead)
845 {
846 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
847
848 if ((RtlEqualUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE)) &&
849 (CurrentService->Start == SERVICE_AUTO_START) &&
850 (CurrentService->ServiceVisited == FALSE) &&
851 (CurrentService->Tag == CurrentGroup->TagArray[i]))
852 {
853 CurrentService->ServiceVisited = TRUE;
854 ScmStartService(CurrentService,
855 CurrentGroup);
856 }
857
858 ServiceEntry = ServiceEntry->Flink;
859 }
860 }
861
862 /* Start all services which have an invalid tag or which do not have a tag */
863 ServiceEntry = ServiceListHead.Flink;
864 while (ServiceEntry != &ServiceListHead)
865 {
866 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
867
868 if ((RtlEqualUnicodeString(&CurrentGroup->GroupName, &CurrentService->ServiceGroup, TRUE)) &&
869 (CurrentService->Start == SERVICE_AUTO_START) &&
870 (CurrentService->ServiceVisited == FALSE))
871 {
872 CurrentService->ServiceVisited = TRUE;
873 ScmStartService(CurrentService,
874 CurrentGroup);
875 }
876
877 ServiceEntry = ServiceEntry->Flink;
878 }
879
880 GroupEntry = GroupEntry->Flink;
881 }
882
883 /* Start all services which are members of any non-existing group */
884 ServiceEntry = ServiceListHead.Flink;
885 while (ServiceEntry != &ServiceListHead)
886 {
887 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
888
889 if ((CurrentService->ServiceGroup.Length != 0) &&
890 (CurrentService->Start == SERVICE_AUTO_START) &&
891 (CurrentService->ServiceVisited == FALSE))
892 {
893 CurrentService->ServiceVisited = TRUE;
894 ScmStartService(CurrentService,
895 NULL);
896 }
897
898 ServiceEntry = ServiceEntry->Flink;
899 }
900
901 /* Start all services which are not a member of any group */
902 ServiceEntry = ServiceListHead.Flink;
903 while (ServiceEntry != &ServiceListHead)
904 {
905 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
906
907 if ((CurrentService->ServiceGroup.Length == 0) &&
908 (CurrentService->Start == SERVICE_AUTO_START) &&
909 (CurrentService->ServiceVisited == FALSE))
910 {
911 CurrentService->ServiceVisited = TRUE;
912 ScmStartService(CurrentService,
913 NULL);
914 }
915
916 ServiceEntry = ServiceEntry->Flink;
917 }
918
919 /* Clear 'ServiceVisited' flag again */
920 ServiceEntry = ServiceListHead.Flink;
921 while (ServiceEntry != &ServiceListHead)
922 {
923 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
924 CurrentService->ServiceVisited = FALSE;
925 ServiceEntry = ServiceEntry->Flink;
926 }
927 }
928
929 /* EOF */