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