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