Move group-list related code to a separate file and keep the group name in the group...
[reactos.git] / reactos / subsys / system / services / database.c
1 /*
2 *
3 * service control manager
4 *
5 * ReactOS Operating System
6 *
7 * --------------------------------------------------------------------
8 *
9 * This software is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of the
12 * License, or (at your option) any later version.
13 *
14 * This software is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this software; see the file COPYING.LIB. If not, write
21 * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
22 * MA 02139, USA.
23 *
24 */
25
26 /* INCLUDES *****************************************************************/
27
28 #include "services.h"
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 /* GLOBALS *******************************************************************/
35
36 LIST_ENTRY ServiceListHead;
37
38 static RTL_RESOURCE DatabaseLock;
39 static DWORD dwResumeCount = 1;
40
41
42 /* FUNCTIONS *****************************************************************/
43
44 PSERVICE
45 ScmGetServiceEntryByName(LPWSTR lpServiceName)
46 {
47 PLIST_ENTRY ServiceEntry;
48 PSERVICE CurrentService;
49
50 DPRINT("ScmGetServiceEntryByName() called\n");
51
52 ServiceEntry = ServiceListHead.Flink;
53 while (ServiceEntry != &ServiceListHead)
54 {
55 CurrentService = CONTAINING_RECORD(ServiceEntry,
56 SERVICE,
57 ServiceListEntry);
58 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
59 {
60 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
61 return CurrentService;
62 }
63
64 ServiceEntry = ServiceEntry->Flink;
65 }
66
67 DPRINT("Couldn't find a matching service\n");
68
69 return NULL;
70 }
71
72
73 PSERVICE
74 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
75 {
76 PLIST_ENTRY ServiceEntry;
77 PSERVICE CurrentService;
78
79 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
80
81 ServiceEntry = ServiceListHead.Flink;
82 while (ServiceEntry != &ServiceListHead)
83 {
84 CurrentService = CONTAINING_RECORD(ServiceEntry,
85 SERVICE,
86 ServiceListEntry);
87 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
88 {
89 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
90 return CurrentService;
91 }
92
93 ServiceEntry = ServiceEntry->Flink;
94 }
95
96 DPRINT("Couldn't find a matching service\n");
97
98 return NULL;
99 }
100
101
102 PSERVICE
103 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
104 {
105 PLIST_ENTRY ServiceEntry;
106 PSERVICE CurrentService;
107
108 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
109
110 ServiceEntry = ServiceListHead.Flink;
111 while (ServiceEntry != &ServiceListHead)
112 {
113 CurrentService = CONTAINING_RECORD(ServiceEntry,
114 SERVICE,
115 ServiceListEntry);
116 if (CurrentService->dwResumeCount > dwResumeCount)
117 {
118 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
119 return CurrentService;
120 }
121
122 ServiceEntry = ServiceEntry->Flink;
123 }
124
125 DPRINT("Couldn't find a matching service\n");
126
127 return NULL;
128 }
129
130
131 DWORD
132 ScmCreateNewServiceRecord(LPWSTR lpServiceName,
133 PSERVICE *lpServiceRecord)
134 {
135 PSERVICE lpService = NULL;
136
137 DPRINT("Service: '%S'\n", lpServiceName);
138
139 /* Allocate service entry */
140 lpService = HeapAlloc(GetProcessHeap(),
141 HEAP_ZERO_MEMORY,
142 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
143 if (lpService == NULL)
144 return ERROR_NOT_ENOUGH_MEMORY;
145
146 *lpServiceRecord = lpService;
147
148 /* Copy service name */
149 wcscpy(lpService->szServiceName, lpServiceName);
150 lpService->lpServiceName = lpService->szServiceName;
151 lpService->lpDisplayName = lpService->lpServiceName;
152
153 /* Set the resume count */
154 lpService->dwResumeCount = dwResumeCount++;
155
156 /* Append service entry */
157 InsertTailList(&ServiceListHead,
158 &lpService->ServiceListEntry);
159
160 lpService->Status.dwCurrentState = SERVICE_STOPPED;
161 lpService->Status.dwControlsAccepted = 0;
162 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
163 lpService->Status.dwServiceSpecificExitCode = 0;
164 lpService->Status.dwCheckPoint = 0;
165 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
166
167 return ERROR_SUCCESS;
168 }
169
170
171 static DWORD
172 CreateServiceListEntry(LPWSTR lpServiceName,
173 HKEY hServiceKey)
174 {
175 PSERVICE lpService = NULL;
176 LPWSTR lpDisplayName = NULL;
177 LPWSTR lpGroup = NULL;
178 DWORD dwSize;
179 DWORD dwError;
180 DWORD dwServiceType;
181 DWORD dwStartType;
182 DWORD dwErrorControl;
183 DWORD dwTagId;
184
185 DPRINT("Service: '%S'\n", lpServiceName);
186 if (*lpServiceName == L'{')
187 return ERROR_SUCCESS;
188
189 dwSize = sizeof(DWORD);
190 dwError = RegQueryValueExW(hServiceKey,
191 L"Type",
192 NULL,
193 NULL,
194 (LPBYTE)&dwServiceType,
195 &dwSize);
196 if (dwError != ERROR_SUCCESS)
197 return ERROR_SUCCESS;
198
199 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
200 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
201 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
202 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
203 return ERROR_SUCCESS;
204
205 DPRINT("Service type: %lx\n", dwServiceType);
206
207 dwSize = sizeof(DWORD);
208 dwError = RegQueryValueExW(hServiceKey,
209 L"Start",
210 NULL,
211 NULL,
212 (LPBYTE)&dwStartType,
213 &dwSize);
214 if (dwError != ERROR_SUCCESS)
215 return ERROR_SUCCESS;
216
217 DPRINT("Start type: %lx\n", dwStartType);
218
219 dwSize = sizeof(DWORD);
220 dwError = RegQueryValueExW(hServiceKey,
221 L"ErrorControl",
222 NULL,
223 NULL,
224 (LPBYTE)&dwErrorControl,
225 &dwSize);
226 if (dwError != ERROR_SUCCESS)
227 return ERROR_SUCCESS;
228
229 DPRINT("Error control: %lx\n", dwErrorControl);
230
231 dwError = RegQueryValueExW(hServiceKey,
232 L"Tag",
233 NULL,
234 NULL,
235 (LPBYTE)&dwTagId,
236 &dwSize);
237 if (dwError != ERROR_SUCCESS)
238 dwTagId = 0;
239
240 DPRINT("Tag: %lx\n", dwTagId);
241
242 dwError = ScmReadString(hServiceKey,
243 L"Group",
244 &lpGroup);
245 if (dwError != ERROR_SUCCESS)
246 lpGroup = NULL;
247
248 DPRINT("Group: %S\n", lpGroup);
249
250 dwError = ScmReadString(hServiceKey,
251 L"DisplayName",
252 &lpDisplayName);
253 if (dwError != ERROR_SUCCESS)
254 lpDisplayName = NULL;
255
256 DPRINT("Display name: %S\n", lpDisplayName);
257
258 dwError = ScmCreateNewServiceRecord(lpServiceName,
259 &lpService);
260 if (dwError != ERROR_SUCCESS)
261 goto done;
262
263 lpService->Status.dwServiceType = dwServiceType;
264 lpService->dwStartType = dwStartType;
265 lpService->dwErrorControl = dwErrorControl;
266 lpService->dwTag = dwTagId;
267
268 if (lpGroup != NULL)
269 {
270 lpService->lpServiceGroup = lpGroup;
271 lpGroup = NULL;
272 }
273
274 if (lpDisplayName != NULL)
275 {
276 lpService->lpDisplayName = lpDisplayName;
277 lpDisplayName = NULL;
278 }
279
280 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
281 DPRINT("Group: '%S'\n", lpService->lpServiceGroup);
282 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
283 lpService->dwStartType,
284 lpService->Status.dwServiceType,
285 lpService->dwTag,
286 lpService->dwErrorControl);
287
288 if (ScmIsDeleteFlagSet(hServiceKey))
289 lpService->bDeleted = TRUE;
290
291 done:;
292 if (lpGroup != NULL)
293 HeapFree(GetProcessHeap(), 0, lpGroup);
294
295 if (lpDisplayName != NULL)
296 HeapFree(GetProcessHeap(), 0, lpDisplayName);
297
298 return dwError;
299 }
300
301
302 VOID
303 ScmDeleteMarkedServices(VOID)
304 {
305 PLIST_ENTRY ServiceEntry;
306 PSERVICE CurrentService;
307
308 ServiceEntry = ServiceListHead.Flink;
309 while (ServiceEntry != &ServiceListHead)
310 {
311 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
312
313 ServiceEntry = ServiceEntry->Flink;
314
315 if (CurrentService->bDeleted == TRUE)
316 {
317 DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
318
319 /* FIXME: Delete the registry keys */
320
321 /* FIXME: Delete the service record from the list */
322
323 }
324 }
325 }
326
327
328 DWORD
329 ScmCreateServiceDatabase(VOID)
330 {
331 WCHAR szSubKey[MAX_PATH];
332 HKEY hServicesKey;
333 HKEY hServiceKey;
334 DWORD dwSubKey;
335 DWORD dwSubKeyLength;
336 FILETIME ftLastChanged;
337 DWORD dwError;
338
339 DPRINT("ScmCreateServiceDatabase() called\n");
340
341 dwError = ScmCreateGroupList();
342 if (dwError != ERROR_SUCCESS)
343 return dwError;
344
345 /* Initialize basic variables */
346 InitializeListHead(&ServiceListHead);
347
348 /* Initialize the database lock */
349 RtlInitializeResource(&DatabaseLock);
350
351 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
352 L"System\\CurrentControlSet\\Services",
353 0,
354 KEY_READ,
355 &hServicesKey);
356 if (dwError != ERROR_SUCCESS)
357 return dwError;
358
359 dwSubKey = 0;
360 for (;;)
361 {
362 dwSubKeyLength = MAX_PATH;
363 dwError = RegEnumKeyExW(hServicesKey,
364 dwSubKey,
365 szSubKey,
366 &dwSubKeyLength,
367 NULL,
368 NULL,
369 NULL,
370 &ftLastChanged);
371 if (dwError == ERROR_SUCCESS &&
372 szSubKey[0] != L'{')
373 {
374 DPRINT("SubKeyName: '%S'\n", szSubKey);
375
376 dwError = RegOpenKeyExW(hServicesKey,
377 szSubKey,
378 0,
379 KEY_READ,
380 &hServiceKey);
381 if (dwError == ERROR_SUCCESS)
382 {
383 dwError = CreateServiceListEntry(szSubKey,
384 hServiceKey);
385
386 RegCloseKey(hServiceKey);
387 }
388 }
389
390 if (dwError != ERROR_SUCCESS)
391 break;
392
393 dwSubKey++;
394 }
395
396 RegCloseKey(hServicesKey);
397
398 /* Delete services that are marked for delete */
399 ScmDeleteMarkedServices();
400
401 DPRINT("ScmCreateServiceDatabase() done\n");
402
403 return ERROR_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(%S) called\n", Service->lpServiceName);
422
423 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
424 {
425 RtlInitUnicodeString(&DirName,
426 L"\\Driver");
427 }
428 else
429 {
430 RtlInitUnicodeString(&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 '%S' failed\n", Service->lpServiceName);
468 break;
469 }
470
471 if (!NT_SUCCESS(Status))
472 break;
473
474 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);
475
476 if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
477 {
478 DPRINT("Found: '%S' '%wZ'\n",
479 Service->lpServiceName, &DirInfo->ObjectName);
480
481 /* Mark service as 'running' */
482 Service->Status.dwCurrentState = SERVICE_RUNNING;
483
484 /* Find the driver's group and mark it as 'running' */
485 if (Service->lpServiceGroup != NULL)
486 {
487 GroupEntry = GroupListHead.Flink;
488 while (GroupEntry != &GroupListHead)
489 {
490 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
491
492 DPRINT("Checking group '%S'\n", &CurrentGroup->lpGroupName);
493 if (Service->lpServiceGroup != NULL &&
494 _wcsicmp(Service->lpServiceGroup, CurrentGroup->lpGroupName) == 0)
495 {
496 CurrentGroup->ServicesRunning = TRUE;
497 }
498
499 GroupEntry = GroupEntry->Flink;
500 }
501 }
502 break;
503 }
504 }
505
506 HeapFree(GetProcessHeap(),
507 0,
508 DirInfo);
509 NtClose(DirHandle);
510
511 return STATUS_SUCCESS;
512 }
513
514
515 VOID
516 ScmGetBootAndSystemDriverState(VOID)
517 {
518 PLIST_ENTRY ServiceEntry;
519 PSERVICE CurrentService;
520
521 DPRINT("ScmGetBootAndSystemDriverState() called\n");
522
523 ServiceEntry = ServiceListHead.Flink;
524 while (ServiceEntry != &ServiceListHead)
525 {
526 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
527
528 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
529 CurrentService->dwStartType == SERVICE_SYSTEM_START)
530 {
531 /* Check driver */
532 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
533
534 ScmCheckDriver(CurrentService);
535 }
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->lpServiceName) + 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->lpServiceName);
584 Ptr += (wcslen(Service->lpServiceName) + 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->lpServiceName,
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->lpServiceName);
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: %lu\n", Service->Status.dwServiceType);
767
768 if (Service->Status.dwServiceType & SERVICE_DRIVER)
769 {
770 /* Load driver */
771 Status = ScmLoadDriver(Service);
772 if (Status == STATUS_SUCCESS)
773 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
774 }
775 else
776 {
777 /* Start user-mode service */
778 Status = ScmStartUserModeService(Service);
779 }
780
781 DPRINT("ScmStartService() done (Status %lx)\n", Status);
782
783 if (NT_SUCCESS(Status))
784 {
785 if (Group != NULL)
786 {
787 Group->ServicesRunning = TRUE;
788 }
789 Service->Status.dwCurrentState = SERVICE_RUNNING;
790 }
791 #if 0
792 else
793 {
794 switch (Service->ErrorControl)
795 {
796 case SERVICE_ERROR_NORMAL:
797 /* FIXME: Log error */
798 break;
799
800 case SERVICE_ERROR_SEVERE:
801 if (IsLastKnownGood == FALSE)
802 {
803 /* FIXME: Boot last known good configuration */
804 }
805 break;
806
807 case SERVICE_ERROR_CRITICAL:
808 if (IsLastKnownGood == FALSE)
809 {
810 /* FIXME: Boot last known good configuration */
811 }
812 else
813 {
814 /* FIXME: BSOD! */
815 }
816 break;
817 }
818 }
819 #endif
820
821 return Status;
822 }
823
824
825 VOID
826 ScmAutoStartServices(VOID)
827 {
828 PLIST_ENTRY GroupEntry;
829 PLIST_ENTRY ServiceEntry;
830 PSERVICE_GROUP CurrentGroup;
831 PSERVICE CurrentService;
832 ULONG i;
833
834 /* Clear 'ServiceVisited' flag */
835 ServiceEntry = ServiceListHead.Flink;
836 while (ServiceEntry != &ServiceListHead)
837 {
838 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
839 CurrentService->ServiceVisited = FALSE;
840 ServiceEntry = ServiceEntry->Flink;
841 }
842
843 /* Start all services which are members of an existing group */
844 GroupEntry = GroupListHead.Flink;
845 while (GroupEntry != &GroupListHead)
846 {
847 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
848
849 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
850
851 /* Start all services witch have a valid tag */
852 for (i = 0; i < CurrentGroup->TagCount; i++)
853 {
854 ServiceEntry = ServiceListHead.Flink;
855 while (ServiceEntry != &ServiceListHead)
856 {
857 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
858
859 if ((CurrentService->lpServiceGroup != NULL) &&
860 (_wcsicmp(CurrentGroup->lpGroupName, CurrentService->lpServiceGroup) == 0) &&
861 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
862 (CurrentService->ServiceVisited == FALSE) &&
863 (CurrentService->dwTag == 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 ((CurrentService->lpServiceGroup != NULL) &&
881 (_wcsicmp(CurrentGroup->lpGroupName, CurrentService->lpServiceGroup) == 0) &&
882 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
883 (CurrentService->ServiceVisited == FALSE))
884 {
885 CurrentService->ServiceVisited = TRUE;
886 ScmStartService(CurrentService,
887 CurrentGroup);
888 }
889
890 ServiceEntry = ServiceEntry->Flink;
891 }
892
893 GroupEntry = GroupEntry->Flink;
894 }
895
896 /* Start all services which are members of any non-existing group */
897 ServiceEntry = ServiceListHead.Flink;
898 while (ServiceEntry != &ServiceListHead)
899 {
900 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
901
902 if ((CurrentService->lpServiceGroup != NULL) &&
903 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
904 (CurrentService->ServiceVisited == FALSE))
905 {
906 CurrentService->ServiceVisited = TRUE;
907 ScmStartService(CurrentService,
908 NULL);
909 }
910
911 ServiceEntry = ServiceEntry->Flink;
912 }
913
914 /* Start all services which are not a member of any group */
915 ServiceEntry = ServiceListHead.Flink;
916 while (ServiceEntry != &ServiceListHead)
917 {
918 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
919
920 if ((CurrentService->lpServiceGroup == NULL) &&
921 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
922 (CurrentService->ServiceVisited == FALSE))
923 {
924 CurrentService->ServiceVisited = TRUE;
925 ScmStartService(CurrentService,
926 NULL);
927 }
928
929 ServiceEntry = ServiceEntry->Flink;
930 }
931
932 /* Clear 'ServiceVisited' flag again */
933 ServiceEntry = ServiceListHead.Flink;
934 while (ServiceEntry != &ServiceListHead)
935 {
936 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
937 CurrentService->ServiceVisited = FALSE;
938 ServiceEntry = ServiceEntry->Flink;
939 }
940 }
941
942 /* EOF */