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