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