Move some xml around and back off one change in ReactOS.rbuild for now.
[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 dwError = ScmSetServiceGroup(lpService, lpGroup);
271 if (dwError != ERROR_SUCCESS)
272 goto done;
273 }
274
275 if (lpDisplayName != NULL)
276 {
277 lpService->lpDisplayName = lpDisplayName;
278 lpDisplayName = NULL;
279 }
280
281 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
282 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
283 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
284 lpService->dwStartType,
285 lpService->Status.dwServiceType,
286 lpService->dwTag,
287 lpService->dwErrorControl);
288
289 if (ScmIsDeleteFlagSet(hServiceKey))
290 lpService->bDeleted = TRUE;
291
292 done:;
293 if (lpGroup != NULL)
294 HeapFree(GetProcessHeap(), 0, lpGroup);
295
296 if (lpDisplayName != NULL)
297 HeapFree(GetProcessHeap(), 0, lpDisplayName);
298
299 return dwError;
300 }
301
302
303 VOID
304 ScmDeleteMarkedServices(VOID)
305 {
306 PLIST_ENTRY ServiceEntry;
307 PSERVICE CurrentService;
308
309 ServiceEntry = ServiceListHead.Flink;
310 while (ServiceEntry != &ServiceListHead)
311 {
312 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
313
314 ServiceEntry = ServiceEntry->Flink;
315
316 if (CurrentService->bDeleted == TRUE)
317 {
318 DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
319
320 /* FIXME: Delete the registry keys */
321
322 /* FIXME: Delete the service record from the list */
323
324 }
325 }
326 }
327
328
329 DWORD
330 ScmCreateServiceDatabase(VOID)
331 {
332 WCHAR szSubKey[MAX_PATH];
333 HKEY hServicesKey;
334 HKEY hServiceKey;
335 DWORD dwSubKey;
336 DWORD dwSubKeyLength;
337 FILETIME ftLastChanged;
338 DWORD dwError;
339
340 DPRINT("ScmCreateServiceDatabase() called\n");
341
342 dwError = ScmCreateGroupList();
343 if (dwError != ERROR_SUCCESS)
344 return dwError;
345
346 /* Initialize basic variables */
347 InitializeListHead(&ServiceListHead);
348
349 /* Initialize the database lock */
350 RtlInitializeResource(&DatabaseLock);
351
352 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
353 L"System\\CurrentControlSet\\Services",
354 0,
355 KEY_READ,
356 &hServicesKey);
357 if (dwError != ERROR_SUCCESS)
358 return dwError;
359
360 dwSubKey = 0;
361 for (;;)
362 {
363 dwSubKeyLength = MAX_PATH;
364 dwError = RegEnumKeyExW(hServicesKey,
365 dwSubKey,
366 szSubKey,
367 &dwSubKeyLength,
368 NULL,
369 NULL,
370 NULL,
371 &ftLastChanged);
372 if (dwError == ERROR_SUCCESS &&
373 szSubKey[0] != L'{')
374 {
375 DPRINT("SubKeyName: '%S'\n", szSubKey);
376
377 dwError = RegOpenKeyExW(hServicesKey,
378 szSubKey,
379 0,
380 KEY_READ,
381 &hServiceKey);
382 if (dwError == ERROR_SUCCESS)
383 {
384 dwError = CreateServiceListEntry(szSubKey,
385 hServiceKey);
386
387 RegCloseKey(hServiceKey);
388 }
389 }
390
391 if (dwError != ERROR_SUCCESS)
392 break;
393
394 dwSubKey++;
395 }
396
397 RegCloseKey(hServicesKey);
398
399 /* Delete services that are marked for delete */
400 ScmDeleteMarkedServices();
401
402 DPRINT("ScmCreateServiceDatabase() done\n");
403
404 return ERROR_SUCCESS;
405 }
406
407
408 static NTSTATUS
409 ScmCheckDriver(PSERVICE Service)
410 {
411 OBJECT_ATTRIBUTES ObjectAttributes;
412 UNICODE_STRING DirName;
413 HANDLE DirHandle;
414 NTSTATUS Status;
415 POBJECT_DIRECTORY_INFORMATION DirInfo;
416 ULONG BufferLength;
417 ULONG DataLength;
418 ULONG Index;
419
420 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
421
422 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
423 {
424 RtlInitUnicodeString(&DirName,
425 L"\\Driver");
426 }
427 else
428 {
429 RtlInitUnicodeString(&DirName,
430 L"\\FileSystem");
431 }
432
433 InitializeObjectAttributes(&ObjectAttributes,
434 &DirName,
435 0,
436 NULL,
437 NULL);
438
439 Status = NtOpenDirectoryObject(&DirHandle,
440 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
441 &ObjectAttributes);
442 if (!NT_SUCCESS(Status))
443 {
444 return Status;
445 }
446
447 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
448 2 * MAX_PATH * sizeof(WCHAR);
449 DirInfo = HeapAlloc(GetProcessHeap(),
450 HEAP_ZERO_MEMORY,
451 BufferLength);
452
453 Index = 0;
454 while (TRUE)
455 {
456 Status = NtQueryDirectoryObject(DirHandle,
457 DirInfo,
458 BufferLength,
459 TRUE,
460 FALSE,
461 &Index,
462 &DataLength);
463 if (Status == STATUS_NO_MORE_ENTRIES)
464 {
465 /* FIXME: Add current service to 'failed service' list */
466 DPRINT("Service '%S' failed\n", Service->lpServiceName);
467 break;
468 }
469
470 if (!NT_SUCCESS(Status))
471 break;
472
473 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);
474
475 if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
476 {
477 DPRINT("Found: '%S' '%wZ'\n",
478 Service->lpServiceName, &DirInfo->ObjectName);
479
480 /* Mark service as 'running' */
481 Service->Status.dwCurrentState = SERVICE_RUNNING;
482
483 /* Mark the service group as 'running' */
484 if (Service->lpGroup != NULL)
485 {
486 Service->lpGroup->ServicesRunning = TRUE;
487 }
488
489 break;
490 }
491 }
492
493 HeapFree(GetProcessHeap(),
494 0,
495 DirInfo);
496 NtClose(DirHandle);
497
498 return STATUS_SUCCESS;
499 }
500
501
502 VOID
503 ScmGetBootAndSystemDriverState(VOID)
504 {
505 PLIST_ENTRY ServiceEntry;
506 PSERVICE CurrentService;
507
508 DPRINT("ScmGetBootAndSystemDriverState() called\n");
509
510 ServiceEntry = ServiceListHead.Flink;
511 while (ServiceEntry != &ServiceListHead)
512 {
513 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
514
515 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
516 CurrentService->dwStartType == SERVICE_SYSTEM_START)
517 {
518 /* Check driver */
519 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
520
521 ScmCheckDriver(CurrentService);
522 }
523
524 ServiceEntry = ServiceEntry->Flink;
525 }
526
527 DPRINT("ScmGetBootAndSystemDriverState() done\n");
528 }
529
530
531 static NTSTATUS
532 ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
533 {
534 PSCM_START_PACKET StartPacket;
535 DWORD TotalLength;
536 #if 0
537 DWORD Length;
538 #endif
539 PWSTR Ptr;
540 DWORD Count;
541
542 DPRINT("ScmSendStartCommand() called\n");
543
544 /* Calculate the total length of the start command line */
545 TotalLength = wcslen(Service->lpServiceName) + 1;
546 #if 0
547 if (Arguments != NULL)
548 {
549 Ptr = Arguments;
550 while (*Ptr)
551 {
552 Length = wcslen(Ptr) + 1;
553 TotalLength += Length;
554 Ptr += Length;
555 }
556 }
557 #endif
558 TotalLength++;
559
560 /* Allocate start command packet */
561 StartPacket = HeapAlloc(GetProcessHeap(),
562 HEAP_ZERO_MEMORY,
563 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
564 if (StartPacket == NULL)
565 return STATUS_INSUFFICIENT_RESOURCES;
566
567 StartPacket->Command = SCM_START_COMMAND;
568 StartPacket->Size = TotalLength;
569 Ptr = &StartPacket->Arguments[0];
570 wcscpy(Ptr, Service->lpServiceName);
571 Ptr += (wcslen(Service->lpServiceName) + 1);
572
573 /* FIXME: Copy argument list */
574
575 *Ptr = 0;
576
577 /* Send the start command */
578 WriteFile(Service->ControlPipeHandle,
579 StartPacket,
580 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
581 &Count,
582 NULL);
583
584 /* FIXME: Read the reply */
585
586 HeapFree(GetProcessHeap(),
587 0,
588 StartPacket);
589
590 DPRINT("ScmSendStartCommand() done\n");
591
592 return STATUS_SUCCESS;
593 }
594
595
596 static NTSTATUS
597 ScmStartUserModeService(PSERVICE Service)
598 {
599 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
600 PROCESS_INFORMATION ProcessInformation;
601 STARTUPINFOW StartupInfo;
602 UNICODE_STRING ImagePath;
603 ULONG Type;
604 BOOL Result;
605 NTSTATUS Status;
606
607 RtlInitUnicodeString(&ImagePath, NULL);
608
609 /* Get service data */
610 RtlZeroMemory(&QueryTable,
611 sizeof(QueryTable));
612
613 QueryTable[0].Name = L"Type";
614 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
615 QueryTable[0].EntryContext = &Type;
616
617 QueryTable[1].Name = L"ImagePath";
618 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
619 QueryTable[1].EntryContext = &ImagePath;
620
621 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
622 Service->lpServiceName,
623 QueryTable,
624 NULL,
625 NULL);
626 if (!NT_SUCCESS(Status))
627 {
628 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
629 return Status;
630 }
631 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
632 DPRINT("Type: %lx\n", Type);
633
634 /* Create '\\.\pipe\net\NtControlPipe' instance */
635 Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
636 PIPE_ACCESS_DUPLEX,
637 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
638 100,
639 8000,
640 4,
641 30000,
642 NULL);
643 DPRINT("CreateNamedPipeW() done\n");
644 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
645 {
646 DPRINT1("Failed to create control pipe!\n");
647 return STATUS_UNSUCCESSFUL;
648 }
649
650 StartupInfo.cb = sizeof(StartupInfo);
651 StartupInfo.lpReserved = NULL;
652 StartupInfo.lpDesktop = NULL;
653 StartupInfo.lpTitle = NULL;
654 StartupInfo.dwFlags = 0;
655 StartupInfo.cbReserved2 = 0;
656 StartupInfo.lpReserved2 = 0;
657
658 Result = CreateProcessW(ImagePath.Buffer,
659 NULL,
660 NULL,
661 NULL,
662 FALSE,
663 DETACHED_PROCESS | CREATE_SUSPENDED,
664 NULL,
665 NULL,
666 &StartupInfo,
667 &ProcessInformation);
668 RtlFreeUnicodeString(&ImagePath);
669
670 if (!Result)
671 {
672 /* Close control pipe */
673 CloseHandle(Service->ControlPipeHandle);
674 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
675
676 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
677 return STATUS_UNSUCCESSFUL;
678 }
679
680 DPRINT("Process Id: %lu Handle %lx\n",
681 ProcessInformation.dwProcessId,
682 ProcessInformation.hProcess);
683 DPRINT("Thread Id: %lu Handle %lx\n",
684 ProcessInformation.dwThreadId,
685 ProcessInformation.hThread);
686
687 /* Get process and thread ids */
688 Service->ProcessId = ProcessInformation.dwProcessId;
689 Service->ThreadId = ProcessInformation.dwThreadId;
690
691 /* Resume Thread */
692 ResumeThread(ProcessInformation.hThread);
693
694 /* Connect control pipe */
695 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
696 {
697 DWORD dwProcessId = 0;
698 DWORD dwRead = 0;
699
700 DPRINT("Control pipe connected!\n");
701
702 /* Read thread id from pipe */
703 if (!ReadFile(Service->ControlPipeHandle,
704 (LPVOID)&dwProcessId,
705 sizeof(DWORD),
706 &dwRead,
707 NULL))
708 {
709 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
710 GetLastError());
711 Status = STATUS_UNSUCCESSFUL;
712 }
713 else
714 {
715 DPRINT("Received process id %lu\n", dwProcessId);
716
717 /* FIXME: Send start command */
718
719 Status = STATUS_SUCCESS;
720 }
721 }
722 else
723 {
724 DPRINT("Connecting control pipe failed!\n");
725
726 /* Close control pipe */
727 CloseHandle(Service->ControlPipeHandle);
728 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
729 Service->ProcessId = 0;
730 Service->ThreadId = 0;
731 Status = STATUS_UNSUCCESSFUL;
732 }
733
734 ScmSendStartCommand(Service, NULL);
735
736 /* Close process and thread handle */
737 CloseHandle(ProcessInformation.hThread);
738 CloseHandle(ProcessInformation.hProcess);
739
740 return Status;
741 }
742
743
744 static NTSTATUS
745 ScmStartService(PSERVICE Service,
746 PSERVICE_GROUP Group)
747 {
748 NTSTATUS Status;
749
750 DPRINT("ScmStartService() called\n");
751
752 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
753 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
754
755 if (Service->Status.dwServiceType & SERVICE_DRIVER)
756 {
757 /* Load driver */
758 Status = ScmLoadDriver(Service);
759 if (Status == STATUS_SUCCESS)
760 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
761 }
762 else
763 {
764 /* Start user-mode service */
765 Status = ScmStartUserModeService(Service);
766 }
767
768 DPRINT("ScmStartService() done (Status %lx)\n", Status);
769
770 if (NT_SUCCESS(Status))
771 {
772 if (Group != NULL)
773 {
774 Group->ServicesRunning = TRUE;
775 }
776 Service->Status.dwCurrentState = SERVICE_RUNNING;
777 }
778 #if 0
779 else
780 {
781 switch (Service->ErrorControl)
782 {
783 case SERVICE_ERROR_NORMAL:
784 /* FIXME: Log error */
785 break;
786
787 case SERVICE_ERROR_SEVERE:
788 if (IsLastKnownGood == FALSE)
789 {
790 /* FIXME: Boot last known good configuration */
791 }
792 break;
793
794 case SERVICE_ERROR_CRITICAL:
795 if (IsLastKnownGood == FALSE)
796 {
797 /* FIXME: Boot last known good configuration */
798 }
799 else
800 {
801 /* FIXME: BSOD! */
802 }
803 break;
804 }
805 }
806 #endif
807
808 return Status;
809 }
810
811
812 VOID
813 ScmAutoStartServices(VOID)
814 {
815 PLIST_ENTRY GroupEntry;
816 PLIST_ENTRY ServiceEntry;
817 PSERVICE_GROUP CurrentGroup;
818 PSERVICE CurrentService;
819 ULONG i;
820
821 /* Clear 'ServiceVisited' flag */
822 ServiceEntry = ServiceListHead.Flink;
823 while (ServiceEntry != &ServiceListHead)
824 {
825 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
826 CurrentService->ServiceVisited = FALSE;
827 ServiceEntry = ServiceEntry->Flink;
828 }
829
830 /* Start all services which are members of an existing group */
831 GroupEntry = GroupListHead.Flink;
832 while (GroupEntry != &GroupListHead)
833 {
834 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
835
836 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
837
838 /* Start all services witch have a valid tag */
839 for (i = 0; i < CurrentGroup->TagCount; i++)
840 {
841 ServiceEntry = ServiceListHead.Flink;
842 while (ServiceEntry != &ServiceListHead)
843 {
844 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
845
846 if ((CurrentService->lpGroup == CurrentGroup) &&
847 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
848 (CurrentService->ServiceVisited == FALSE) &&
849 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
850 {
851 CurrentService->ServiceVisited = TRUE;
852 ScmStartService(CurrentService,
853 CurrentGroup);
854 }
855
856 ServiceEntry = ServiceEntry->Flink;
857 }
858 }
859
860 /* Start all services which have an invalid tag or which do not have a tag */
861 ServiceEntry = ServiceListHead.Flink;
862 while (ServiceEntry != &ServiceListHead)
863 {
864 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
865
866 if ((CurrentService->lpGroup == CurrentGroup) &&
867 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
868 (CurrentService->ServiceVisited == FALSE))
869 {
870 CurrentService->ServiceVisited = TRUE;
871 ScmStartService(CurrentService,
872 CurrentGroup);
873 }
874
875 ServiceEntry = ServiceEntry->Flink;
876 }
877
878 GroupEntry = GroupEntry->Flink;
879 }
880
881 /* Start all services which are members of any non-existing group */
882 ServiceEntry = ServiceListHead.Flink;
883 while (ServiceEntry != &ServiceListHead)
884 {
885 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
886
887 if ((CurrentService->lpGroup != NULL) &&
888 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
889 (CurrentService->ServiceVisited == FALSE))
890 {
891 CurrentService->ServiceVisited = TRUE;
892 ScmStartService(CurrentService,
893 NULL);
894 }
895
896 ServiceEntry = ServiceEntry->Flink;
897 }
898
899 /* Start all services which are not a member of any group */
900 ServiceEntry = ServiceListHead.Flink;
901 while (ServiceEntry != &ServiceListHead)
902 {
903 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
904
905 if ((CurrentService->lpGroup == NULL) &&
906 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
907 (CurrentService->ServiceVisited == FALSE))
908 {
909 CurrentService->ServiceVisited = TRUE;
910 ScmStartService(CurrentService,
911 NULL);
912 }
913
914 ServiceEntry = ServiceEntry->Flink;
915 }
916
917 /* Clear 'ServiceVisited' flag again */
918 ServiceEntry = ServiceListHead.Flink;
919 while (ServiceEntry != &ServiceListHead)
920 {
921 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
922 CurrentService->ServiceVisited = FALSE;
923 ServiceEntry = ServiceEntry->Flink;
924 }
925 }
926
927 /* EOF */