4d75727f0cfff09e8fa994320501970f20d475e6
[reactos.git] / reactos / base / 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->Name);
474
475 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
476 {
477 DPRINT("Found: '%S' '%wZ'\n",
478 Service->lpServiceName, &DirInfo->Name);
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 DWORD
532 ScmSendStartCommand(PSERVICE Service,
533 LPWSTR Arguments)
534 {
535 PSCM_START_PACKET StartPacket;
536 DWORD TotalLength;
537 DWORD ArgsLength = 0;
538 DWORD Length;
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 (Arguments != NULL)
547 {
548 Ptr = Arguments;
549 while (*Ptr)
550 {
551 Length = wcslen(Ptr) + 1;
552 TotalLength += Length;
553 ArgsLength += Length;
554 Ptr += Length;
555 DPRINT("Arg: %S\n", Ptr);
556 }
557 }
558 TotalLength++;
559 DPRINT("ArgsLength: %ld\nTotalLength: %ld\n\n", ArgsLength, TotalLength);
560
561 /* Allocate start command packet */
562 StartPacket = HeapAlloc(GetProcessHeap(),
563 HEAP_ZERO_MEMORY,
564 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
565 if (StartPacket == NULL)
566 return ERROR_NOT_ENOUGH_MEMORY;
567
568 StartPacket->Command = SCM_START_COMMAND;
569 StartPacket->Size = TotalLength;
570 Ptr = &StartPacket->Arguments[0];
571 wcscpy(Ptr, Service->lpServiceName);
572 Ptr += (wcslen(Service->lpServiceName) + 1);
573
574 /* Copy argument list */
575 if (Arguments != NULL)
576 {
577 memcpy(Ptr, Arguments, ArgsLength);
578 Ptr += ArgsLength;
579 }
580
581 /* Terminate the argument list */
582 *Ptr = 0;
583
584 /* Send the start command */
585 WriteFile(Service->ControlPipeHandle,
586 StartPacket,
587 sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
588 &Count,
589 NULL);
590
591 /* FIXME: Read the reply */
592
593 /* Release the start command packet */
594 HeapFree(GetProcessHeap(),
595 0,
596 StartPacket);
597
598 DPRINT("ScmSendStartCommand() done\n");
599
600 return ERROR_SUCCESS;
601 }
602
603
604 static DWORD
605 ScmStartUserModeService(PSERVICE Service,
606 LPWSTR lpArgs)
607 {
608 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
609 PROCESS_INFORMATION ProcessInformation;
610 STARTUPINFOW StartupInfo;
611 UNICODE_STRING ImagePath;
612 ULONG Type;
613 BOOL Result;
614 NTSTATUS Status;
615 DWORD dwError = ERROR_SUCCESS;
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->lpServiceName,
633 QueryTable,
634 NULL,
635 NULL);
636 if (!NT_SUCCESS(Status))
637 {
638 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
639 return RtlNtStatusToDosError(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 GetLastError();
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 dwError = GetLastError();
683 /* Close control pipe */
684 CloseHandle(Service->ControlPipeHandle);
685 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
686
687 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
688 return dwError;
689 }
690
691 DPRINT("Process Id: %lu Handle %lx\n",
692 ProcessInformation.dwProcessId,
693 ProcessInformation.hProcess);
694 DPRINT("Thread Id: %lu Handle %lx\n",
695 ProcessInformation.dwThreadId,
696 ProcessInformation.hThread);
697
698 /* Get process and thread ids */
699 Service->ProcessId = ProcessInformation.dwProcessId;
700 Service->ThreadId = ProcessInformation.dwThreadId;
701
702 /* Resume Thread */
703 ResumeThread(ProcessInformation.hThread);
704
705 /* Connect control pipe */
706 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
707 {
708 DWORD dwProcessId = 0;
709 DWORD dwRead = 0;
710
711 DPRINT("Control pipe connected!\n");
712
713 /* Read thread id from pipe */
714 if (!ReadFile(Service->ControlPipeHandle,
715 (LPVOID)&dwProcessId,
716 sizeof(DWORD),
717 &dwRead,
718 NULL))
719 {
720 dwError = GetLastError();
721 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
722 dwError);
723 }
724 else
725 {
726 DPRINT("Received process id %lu\n", dwProcessId);
727
728 /* Send start command */
729 dwError = ScmSendStartCommand(Service, lpArgs);
730 }
731 }
732 else
733 {
734 dwError = GetLastError();
735 DPRINT("Connecting control pipe failed!\n");
736
737 /* Close control pipe */
738 CloseHandle(Service->ControlPipeHandle);
739 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
740 Service->ProcessId = 0;
741 Service->ThreadId = 0;
742 }
743
744 /* Close process and thread handle */
745 CloseHandle(ProcessInformation.hThread);
746 CloseHandle(ProcessInformation.hProcess);
747
748 return dwError;
749 }
750
751
752 DWORD
753 ScmStartService(PSERVICE Service, LPWSTR lpArgs)
754 {
755 PSERVICE_GROUP Group = Service->lpGroup;
756 DWORD dwError = ERROR_SUCCESS;
757
758 DPRINT("ScmStartService() called\n");
759
760 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
761 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
762
763 if (Service->Status.dwServiceType & SERVICE_DRIVER)
764 {
765 /* Load driver */
766 dwError = ScmLoadDriver(Service);
767 if (dwError == ERROR_SUCCESS)
768 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
769 }
770 else
771 {
772 /* Start user-mode service */
773 dwError = ScmStartUserModeService(Service, lpArgs);
774 }
775
776 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
777
778 if (dwError == ERROR_SUCCESS)
779 {
780 if (Group != NULL)
781 {
782 Group->ServicesRunning = TRUE;
783 }
784 Service->Status.dwCurrentState = SERVICE_RUNNING;
785 }
786 #if 0
787 else
788 {
789 switch (Service->ErrorControl)
790 {
791 case SERVICE_ERROR_NORMAL:
792 /* FIXME: Log error */
793 break;
794
795 case SERVICE_ERROR_SEVERE:
796 if (IsLastKnownGood == FALSE)
797 {
798 /* FIXME: Boot last known good configuration */
799 }
800 break;
801
802 case SERVICE_ERROR_CRITICAL:
803 if (IsLastKnownGood == FALSE)
804 {
805 /* FIXME: Boot last known good configuration */
806 }
807 else
808 {
809 /* FIXME: BSOD! */
810 }
811 break;
812 }
813 }
814 #endif
815
816 return dwError;
817 }
818
819
820 VOID
821 ScmAutoStartServices(VOID)
822 {
823 PLIST_ENTRY GroupEntry;
824 PLIST_ENTRY ServiceEntry;
825 PSERVICE_GROUP CurrentGroup;
826 PSERVICE CurrentService;
827 ULONG i;
828
829 /* Clear 'ServiceVisited' flag */
830 ServiceEntry = ServiceListHead.Flink;
831 while (ServiceEntry != &ServiceListHead)
832 {
833 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
834 CurrentService->ServiceVisited = FALSE;
835 ServiceEntry = ServiceEntry->Flink;
836 }
837
838 /* Start all services which are members of an existing group */
839 GroupEntry = GroupListHead.Flink;
840 while (GroupEntry != &GroupListHead)
841 {
842 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
843
844 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
845
846 /* Start all services witch have a valid tag */
847 for (i = 0; i < CurrentGroup->TagCount; i++)
848 {
849 ServiceEntry = ServiceListHead.Flink;
850 while (ServiceEntry != &ServiceListHead)
851 {
852 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
853
854 if ((CurrentService->lpGroup == CurrentGroup) &&
855 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
856 (CurrentService->ServiceVisited == FALSE) &&
857 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
858 {
859 CurrentService->ServiceVisited = TRUE;
860 ScmStartService(CurrentService, NULL);
861 }
862
863 ServiceEntry = ServiceEntry->Flink;
864 }
865 }
866
867 /* Start all services which have an invalid tag or which do not have a tag */
868 ServiceEntry = ServiceListHead.Flink;
869 while (ServiceEntry != &ServiceListHead)
870 {
871 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
872
873 if ((CurrentService->lpGroup == CurrentGroup) &&
874 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
875 (CurrentService->ServiceVisited == FALSE))
876 {
877 CurrentService->ServiceVisited = TRUE;
878 ScmStartService(CurrentService, NULL);
879 }
880
881 ServiceEntry = ServiceEntry->Flink;
882 }
883
884 GroupEntry = GroupEntry->Flink;
885 }
886
887 /* Start all services which are members of any non-existing group */
888 ServiceEntry = ServiceListHead.Flink;
889 while (ServiceEntry != &ServiceListHead)
890 {
891 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
892
893 if ((CurrentService->lpGroup != NULL) &&
894 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
895 (CurrentService->ServiceVisited == FALSE))
896 {
897 CurrentService->ServiceVisited = TRUE;
898 ScmStartService(CurrentService, NULL);
899 }
900
901 ServiceEntry = ServiceEntry->Flink;
902 }
903
904 /* Start all services which are not a member of any group */
905 ServiceEntry = ServiceListHead.Flink;
906 while (ServiceEntry != &ServiceListHead)
907 {
908 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
909
910 if ((CurrentService->lpGroup == NULL) &&
911 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
912 (CurrentService->ServiceVisited == FALSE))
913 {
914 CurrentService->ServiceVisited = TRUE;
915 ScmStartService(CurrentService, NULL);
916 }
917
918 ServiceEntry = ServiceEntry->Flink;
919 }
920
921 /* Clear 'ServiceVisited' flag again */
922 ServiceEntry = ServiceListHead.Flink;
923 while (ServiceEntry != &ServiceListHead)
924 {
925 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
926 CurrentService->ServiceVisited = FALSE;
927 ServiceEntry = ServiceEntry->Flink;
928 }
929 }
930
931 /* EOF */