Don't crash when starting a 2nd GUI application when booted in console mode
[reactos.git] / reactos / base / system / services / database.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/database.c
5 * PURPOSE: Database control interface
6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl
7 * Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 * Gregor Brunmar <gregor.brunmar@home.se>
10 *
11 */
12
13 /* INCLUDES *****************************************************************/
14
15 #include "services.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20
21 /* GLOBALS *******************************************************************/
22
23 LIST_ENTRY ServiceListHead;
24
25 static RTL_RESOURCE DatabaseLock;
26 static DWORD dwResumeCount = 1;
27
28
29 /* FUNCTIONS *****************************************************************/
30
31
32 PSERVICE
33 ScmGetServiceEntryByName(LPWSTR lpServiceName)
34 {
35 PLIST_ENTRY ServiceEntry;
36 PSERVICE CurrentService;
37
38 DPRINT("ScmGetServiceEntryByName() called\n");
39
40 ServiceEntry = ServiceListHead.Flink;
41 while (ServiceEntry != &ServiceListHead)
42 {
43 CurrentService = CONTAINING_RECORD(ServiceEntry,
44 SERVICE,
45 ServiceListEntry);
46 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
47 {
48 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
49 return CurrentService;
50 }
51
52 ServiceEntry = ServiceEntry->Flink;
53 }
54
55 DPRINT("Couldn't find a matching service\n");
56
57 return NULL;
58 }
59
60
61 PSERVICE
62 ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
63 {
64 PLIST_ENTRY ServiceEntry;
65 PSERVICE CurrentService;
66
67 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
68
69 ServiceEntry = ServiceListHead.Flink;
70 while (ServiceEntry != &ServiceListHead)
71 {
72 CurrentService = CONTAINING_RECORD(ServiceEntry,
73 SERVICE,
74 ServiceListEntry);
75 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
76 {
77 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
78 return CurrentService;
79 }
80
81 ServiceEntry = ServiceEntry->Flink;
82 }
83
84 DPRINT("Couldn't find a matching service\n");
85
86 return NULL;
87 }
88
89
90 PSERVICE
91 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
92 {
93 PLIST_ENTRY ServiceEntry;
94 PSERVICE CurrentService;
95
96 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
97
98 ServiceEntry = ServiceListHead.Flink;
99 while (ServiceEntry != &ServiceListHead)
100 {
101 CurrentService = CONTAINING_RECORD(ServiceEntry,
102 SERVICE,
103 ServiceListEntry);
104 if (CurrentService->dwResumeCount > dwResumeCount)
105 {
106 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
107 return CurrentService;
108 }
109
110 ServiceEntry = ServiceEntry->Flink;
111 }
112
113 DPRINT("Couldn't find a matching service\n");
114
115 return NULL;
116 }
117
118
119 PSERVICE
120 ScmGetServiceEntryByClientHandle(ULONG Handle)
121 {
122 PLIST_ENTRY ServiceEntry;
123 PSERVICE CurrentService;
124
125 DPRINT("ScmGetServiceEntryByClientHandle() called\n");
126 DPRINT("looking for %lu\n", Handle);
127
128 ServiceEntry = ServiceListHead.Flink;
129 while (ServiceEntry != &ServiceListHead)
130 {
131 CurrentService = CONTAINING_RECORD(ServiceEntry,
132 SERVICE,
133 ServiceListEntry);
134
135 if (CurrentService->hClient == Handle)
136 {
137 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
138 return CurrentService;
139 }
140
141 ServiceEntry = ServiceEntry->Flink;
142 }
143
144 DPRINT("Couldn't find a matching service\n");
145
146 return NULL;
147 }
148
149
150 DWORD
151 ScmCreateNewServiceRecord(LPWSTR lpServiceName,
152 PSERVICE *lpServiceRecord)
153 {
154 PSERVICE lpService = NULL;
155
156 DPRINT("Service: '%S'\n", lpServiceName);
157
158 /* Allocate service entry */
159 lpService = (SERVICE*) HeapAlloc(GetProcessHeap(),
160 HEAP_ZERO_MEMORY,
161 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
162 if (lpService == NULL)
163 return ERROR_NOT_ENOUGH_MEMORY;
164
165 *lpServiceRecord = lpService;
166
167 /* Copy service name */
168 wcscpy(lpService->szServiceName, lpServiceName);
169 lpService->lpServiceName = lpService->szServiceName;
170 lpService->lpDisplayName = lpService->lpServiceName;
171
172 /* Set the resume count */
173 lpService->dwResumeCount = dwResumeCount++;
174
175 /* Append service entry */
176 InsertTailList(&ServiceListHead,
177 &lpService->ServiceListEntry);
178
179 lpService->Status.dwCurrentState = SERVICE_STOPPED;
180 lpService->Status.dwControlsAccepted = 0;
181 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
182 lpService->Status.dwServiceSpecificExitCode = 0;
183 lpService->Status.dwCheckPoint = 0;
184 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
185
186 return ERROR_SUCCESS;
187 }
188
189
190 static DWORD
191 CreateServiceListEntry(LPWSTR lpServiceName,
192 HKEY hServiceKey)
193 {
194 PSERVICE lpService = NULL;
195 LPWSTR lpDisplayName = NULL;
196 LPWSTR lpGroup = NULL;
197 DWORD dwSize;
198 DWORD dwError;
199 DWORD dwServiceType;
200 DWORD dwStartType;
201 DWORD dwErrorControl;
202 DWORD dwTagId;
203
204 DPRINT("Service: '%S'\n", lpServiceName);
205 if (*lpServiceName == L'{')
206 return ERROR_SUCCESS;
207
208 dwSize = sizeof(DWORD);
209 dwError = RegQueryValueExW(hServiceKey,
210 L"Type",
211 NULL,
212 NULL,
213 (LPBYTE)&dwServiceType,
214 &dwSize);
215 if (dwError != ERROR_SUCCESS)
216 return ERROR_SUCCESS;
217
218 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
219 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
220 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
221 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
222 return ERROR_SUCCESS;
223
224 DPRINT("Service type: %lx\n", dwServiceType);
225
226 dwSize = sizeof(DWORD);
227 dwError = RegQueryValueExW(hServiceKey,
228 L"Start",
229 NULL,
230 NULL,
231 (LPBYTE)&dwStartType,
232 &dwSize);
233 if (dwError != ERROR_SUCCESS)
234 return ERROR_SUCCESS;
235
236 DPRINT("Start type: %lx\n", dwStartType);
237
238 dwSize = sizeof(DWORD);
239 dwError = RegQueryValueExW(hServiceKey,
240 L"ErrorControl",
241 NULL,
242 NULL,
243 (LPBYTE)&dwErrorControl,
244 &dwSize);
245 if (dwError != ERROR_SUCCESS)
246 return ERROR_SUCCESS;
247
248 DPRINT("Error control: %lx\n", dwErrorControl);
249
250 dwError = RegQueryValueExW(hServiceKey,
251 L"Tag",
252 NULL,
253 NULL,
254 (LPBYTE)&dwTagId,
255 &dwSize);
256 if (dwError != ERROR_SUCCESS)
257 dwTagId = 0;
258
259 DPRINT("Tag: %lx\n", dwTagId);
260
261 dwError = ScmReadString(hServiceKey,
262 L"Group",
263 &lpGroup);
264 if (dwError != ERROR_SUCCESS)
265 lpGroup = NULL;
266
267 DPRINT("Group: %S\n", lpGroup);
268
269 dwError = ScmReadString(hServiceKey,
270 L"DisplayName",
271 &lpDisplayName);
272 if (dwError != ERROR_SUCCESS)
273 lpDisplayName = NULL;
274
275 DPRINT("Display name: %S\n", lpDisplayName);
276
277 dwError = ScmCreateNewServiceRecord(lpServiceName,
278 &lpService);
279 if (dwError != ERROR_SUCCESS)
280 goto done;
281
282 lpService->Status.dwServiceType = dwServiceType;
283 lpService->dwStartType = dwStartType;
284 lpService->dwErrorControl = dwErrorControl;
285 lpService->dwTag = dwTagId;
286
287 if (lpGroup != NULL)
288 {
289 dwError = ScmSetServiceGroup(lpService, lpGroup);
290 if (dwError != ERROR_SUCCESS)
291 goto done;
292 }
293
294 if (lpDisplayName != NULL)
295 {
296 lpService->lpDisplayName = lpDisplayName;
297 lpDisplayName = NULL;
298 }
299
300 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
301 if (lpService->lpGroup != NULL)
302 {
303 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
304 }
305 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
306 lpService->dwStartType,
307 lpService->Status.dwServiceType,
308 lpService->dwTag,
309 lpService->dwErrorControl);
310
311 if (ScmIsDeleteFlagSet(hServiceKey))
312 lpService->bDeleted = TRUE;
313
314 done:;
315 if (lpGroup != NULL)
316 HeapFree(GetProcessHeap(), 0, lpGroup);
317
318 if (lpDisplayName != NULL)
319 HeapFree(GetProcessHeap(), 0, lpDisplayName);
320
321 return dwError;
322 }
323
324
325 VOID
326 ScmDeleteMarkedServices(VOID)
327 {
328 PLIST_ENTRY ServiceEntry;
329 PSERVICE CurrentService;
330
331 ServiceEntry = ServiceListHead.Flink;
332 while (ServiceEntry != &ServiceListHead)
333 {
334 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
335
336 ServiceEntry = ServiceEntry->Flink;
337
338 if (CurrentService->bDeleted == TRUE)
339 {
340 DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
341
342 /* FIXME: Delete the registry keys */
343
344 /* FIXME: Delete the service record from the list */
345
346 }
347 }
348 }
349
350
351 DWORD
352 ScmCreateServiceDatabase(VOID)
353 {
354 WCHAR szSubKey[MAX_PATH];
355 HKEY hServicesKey;
356 HKEY hServiceKey;
357 DWORD dwSubKey;
358 DWORD dwSubKeyLength;
359 FILETIME ftLastChanged;
360 DWORD dwError;
361
362 DPRINT("ScmCreateServiceDatabase() called\n");
363
364 dwError = ScmCreateGroupList();
365 if (dwError != ERROR_SUCCESS)
366 return dwError;
367
368 /* Initialize basic variables */
369 InitializeListHead(&ServiceListHead);
370
371 /* Initialize the database lock */
372 RtlInitializeResource(&DatabaseLock);
373
374 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
375 L"System\\CurrentControlSet\\Services",
376 0,
377 KEY_READ,
378 &hServicesKey);
379 if (dwError != ERROR_SUCCESS)
380 return dwError;
381
382 dwSubKey = 0;
383 for (;;)
384 {
385 dwSubKeyLength = MAX_PATH;
386 dwError = RegEnumKeyExW(hServicesKey,
387 dwSubKey,
388 szSubKey,
389 &dwSubKeyLength,
390 NULL,
391 NULL,
392 NULL,
393 &ftLastChanged);
394 if (dwError == ERROR_SUCCESS &&
395 szSubKey[0] != L'{')
396 {
397 DPRINT("SubKeyName: '%S'\n", szSubKey);
398
399 dwError = RegOpenKeyExW(hServicesKey,
400 szSubKey,
401 0,
402 KEY_READ,
403 &hServiceKey);
404 if (dwError == ERROR_SUCCESS)
405 {
406 dwError = CreateServiceListEntry(szSubKey,
407 hServiceKey);
408
409 RegCloseKey(hServiceKey);
410 }
411 }
412
413 if (dwError != ERROR_SUCCESS)
414 break;
415
416 dwSubKey++;
417 }
418
419 RegCloseKey(hServicesKey);
420
421 /* Delete services that are marked for delete */
422 ScmDeleteMarkedServices();
423
424 DPRINT("ScmCreateServiceDatabase() done\n");
425
426 return ERROR_SUCCESS;
427 }
428
429
430 VOID
431 ScmShutdownServiceDatabase(VOID)
432 {
433 DPRINT("ScmShutdownServiceDatabase() called\n");
434
435 ScmDeleteMarkedServices();
436 RtlDeleteResource(&DatabaseLock);
437
438 DPRINT("ScmShutdownServiceDatabase() done\n");
439 }
440
441
442 static NTSTATUS
443 ScmCheckDriver(PSERVICE Service)
444 {
445 OBJECT_ATTRIBUTES ObjectAttributes;
446 UNICODE_STRING DirName;
447 HANDLE DirHandle;
448 NTSTATUS Status;
449 POBJECT_DIRECTORY_INFORMATION DirInfo;
450 ULONG BufferLength;
451 ULONG DataLength;
452 ULONG Index;
453
454 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
455
456 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
457 {
458 RtlInitUnicodeString(&DirName,
459 L"\\Driver");
460 }
461 else
462 {
463 RtlInitUnicodeString(&DirName,
464 L"\\FileSystem");
465 }
466
467 InitializeObjectAttributes(&ObjectAttributes,
468 &DirName,
469 0,
470 NULL,
471 NULL);
472
473 Status = NtOpenDirectoryObject(&DirHandle,
474 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
475 &ObjectAttributes);
476 if (!NT_SUCCESS(Status))
477 {
478 return Status;
479 }
480
481 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
482 2 * MAX_PATH * sizeof(WCHAR);
483 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
484 HEAP_ZERO_MEMORY,
485 BufferLength);
486
487 Index = 0;
488 while (TRUE)
489 {
490 Status = NtQueryDirectoryObject(DirHandle,
491 DirInfo,
492 BufferLength,
493 TRUE,
494 FALSE,
495 &Index,
496 &DataLength);
497 if (Status == STATUS_NO_MORE_ENTRIES)
498 {
499 /* FIXME: Add current service to 'failed service' list */
500 DPRINT("Service '%S' failed\n", Service->lpServiceName);
501 break;
502 }
503
504 if (!NT_SUCCESS(Status))
505 break;
506
507 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
508
509 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
510 {
511 DPRINT("Found: '%S' '%wZ'\n",
512 Service->lpServiceName, &DirInfo->Name);
513
514 /* Mark service as 'running' */
515 Service->Status.dwCurrentState = SERVICE_RUNNING;
516
517 /* Mark the service group as 'running' */
518 if (Service->lpGroup != NULL)
519 {
520 Service->lpGroup->ServicesRunning = TRUE;
521 }
522
523 break;
524 }
525 }
526
527 HeapFree(GetProcessHeap(),
528 0,
529 DirInfo);
530 NtClose(DirHandle);
531
532 return STATUS_SUCCESS;
533 }
534
535
536 VOID
537 ScmGetBootAndSystemDriverState(VOID)
538 {
539 PLIST_ENTRY ServiceEntry;
540 PSERVICE CurrentService;
541
542 DPRINT("ScmGetBootAndSystemDriverState() called\n");
543
544 ServiceEntry = ServiceListHead.Flink;
545 while (ServiceEntry != &ServiceListHead)
546 {
547 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
548
549 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
550 CurrentService->dwStartType == SERVICE_SYSTEM_START)
551 {
552 /* Check driver */
553 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
554
555 ScmCheckDriver(CurrentService);
556 }
557
558 ServiceEntry = ServiceEntry->Flink;
559 }
560
561 DPRINT("ScmGetBootAndSystemDriverState() done\n");
562 }
563
564
565 DWORD
566 ScmControlService(PSERVICE Service,
567 DWORD dwControl,
568 LPSERVICE_STATUS lpServiceStatus)
569 {
570 PSCM_CONTROL_PACKET ControlPacket;
571 DWORD Count;
572 DWORD TotalLength;
573
574 DPRINT("ScmControlService() called\n");
575
576 TotalLength = wcslen(Service->lpServiceName) + 1;
577
578 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
579 HEAP_ZERO_MEMORY,
580 sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)));
581 if (ControlPacket == NULL)
582 return ERROR_NOT_ENOUGH_MEMORY;
583
584 ControlPacket->dwControl = dwControl;
585 ControlPacket->hClient = Service->hClient;
586 ControlPacket->dwSize = TotalLength;
587 wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
588
589 /* Send the start command */
590 WriteFile(Service->ControlPipeHandle,
591 ControlPacket,
592 sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)),
593 &Count,
594 NULL);
595
596 /* FIXME: Read the reply */
597
598 /* Release the contol packet */
599 HeapFree(GetProcessHeap(),
600 0,
601 ControlPacket);
602
603 RtlCopyMemory(lpServiceStatus,
604 &Service->Status,
605 sizeof(SERVICE_STATUS));
606
607 DPRINT("ScmControlService) done\n");
608
609 return ERROR_SUCCESS;
610 }
611
612
613 static DWORD
614 ScmSendStartCommand(PSERVICE Service,
615 LPWSTR Arguments)
616 {
617 PSCM_CONTROL_PACKET ControlPacket;
618 DWORD TotalLength;
619 DWORD ArgsLength = 0;
620 DWORD Length;
621 PWSTR Ptr;
622 DWORD Count;
623
624 DPRINT("ScmSendStartCommand() called\n");
625
626 /* Calculate the total length of the start command line */
627 TotalLength = wcslen(Service->lpServiceName) + 1;
628 if (Arguments != NULL)
629 {
630 Ptr = Arguments;
631 while (*Ptr)
632 {
633 Length = wcslen(Ptr) + 1;
634 TotalLength += Length;
635 ArgsLength += Length;
636 Ptr += Length;
637 DPRINT("Arg: %S\n", Ptr);
638 }
639 }
640 TotalLength++;
641 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength, TotalLength);
642
643 /* Allocate a control packet */
644 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
645 HEAP_ZERO_MEMORY,
646 sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
647 if (ControlPacket == NULL)
648 return ERROR_NOT_ENOUGH_MEMORY;
649
650 ControlPacket->dwControl = SERVICE_CONTROL_START;
651 ControlPacket->hClient = Service->hClient;
652 ControlPacket->dwSize = TotalLength;
653 Ptr = &ControlPacket->szArguments[0];
654 wcscpy(Ptr, Service->lpServiceName);
655 Ptr += (wcslen(Service->lpServiceName) + 1);
656
657 /* Copy argument list */
658 if (Arguments != NULL)
659 {
660 memcpy(Ptr, Arguments, ArgsLength);
661 Ptr += ArgsLength;
662 }
663
664 /* Terminate the argument list */
665 *Ptr = 0;
666
667 /* Send the start command */
668 WriteFile(Service->ControlPipeHandle,
669 ControlPacket,
670 sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
671 &Count,
672 NULL);
673
674 /* FIXME: Read the reply */
675
676 /* Release the contol packet */
677 HeapFree(GetProcessHeap(),
678 0,
679 ControlPacket);
680
681 DPRINT("ScmSendStartCommand() done\n");
682
683 return ERROR_SUCCESS;
684 }
685
686
687 static DWORD
688 ScmStartUserModeService(PSERVICE Service,
689 LPWSTR lpArgs)
690 {
691 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
692 PROCESS_INFORMATION ProcessInformation;
693 STARTUPINFOW StartupInfo;
694 UNICODE_STRING ImagePath;
695 ULONG Type;
696 DWORD ServiceCurrent = 0;
697 BOOL Result;
698 NTSTATUS Status;
699 DWORD dwError = ERROR_SUCCESS;
700 WCHAR NtControlPipeName[MAX_PATH + 1];
701
702 RtlInitUnicodeString(&ImagePath, NULL);
703
704 /* Get service data */
705 RtlZeroMemory(&QueryTable,
706 sizeof(QueryTable));
707
708 QueryTable[0].Name = L"Type";
709 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
710 QueryTable[0].EntryContext = &Type;
711
712 QueryTable[1].Name = L"ImagePath";
713 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
714 QueryTable[1].EntryContext = &ImagePath;
715
716 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
717 Service->lpServiceName,
718 QueryTable,
719 NULL,
720 NULL);
721 if (!NT_SUCCESS(Status))
722 {
723 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
724 return RtlNtStatusToDosError(Status);
725 }
726 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
727 DPRINT("Type: %lx\n", Type);
728
729 /* Get the service number */
730 RtlZeroMemory(&QueryTable,
731 sizeof(QueryTable));
732
733 QueryTable[0].Name = L"";
734 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
735 QueryTable[0].EntryContext = &ServiceCurrent;
736
737 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
738 L"ServiceCurrent",
739 QueryTable,
740 NULL,
741 NULL);
742
743 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
744 {
745 /* TODO: Create registry entry with correct write access */
746 }
747 else if (!NT_SUCCESS(Status))
748 {
749 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
750 return RtlNtStatusToDosError(Status);
751 }
752 else
753 {
754 ServiceCurrent++;
755 }
756
757 Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, L"ServiceCurrent", L"", REG_DWORD, &ServiceCurrent, sizeof(ServiceCurrent));
758
759 if (!NT_SUCCESS(Status))
760 {
761 DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
762 return RtlNtStatusToDosError(Status);
763 }
764
765 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
766 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
767 Service->ControlPipeHandle = CreateNamedPipeW(NtControlPipeName,
768 PIPE_ACCESS_DUPLEX,
769 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
770 100,
771 8000,
772 4,
773 30000,
774 NULL);
775 DPRINT1("CreateNamedPipeW(%S) done\n", NtControlPipeName);
776 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
777 {
778 DPRINT1("Failed to create control pipe!\n");
779 return GetLastError();
780 }
781
782 StartupInfo.cb = sizeof(StartupInfo);
783 StartupInfo.lpReserved = NULL;
784 StartupInfo.lpDesktop = NULL;
785 StartupInfo.lpTitle = NULL;
786 StartupInfo.dwFlags = 0;
787 StartupInfo.cbReserved2 = 0;
788 StartupInfo.lpReserved2 = 0;
789
790 Result = CreateProcessW(ImagePath.Buffer,
791 NULL,
792 NULL,
793 NULL,
794 FALSE,
795 DETACHED_PROCESS | CREATE_SUSPENDED,
796 NULL,
797 NULL,
798 &StartupInfo,
799 &ProcessInformation);
800 RtlFreeUnicodeString(&ImagePath);
801
802 if (!Result)
803 {
804 dwError = GetLastError();
805 /* Close control pipe */
806 CloseHandle(Service->ControlPipeHandle);
807 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
808
809 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
810 return dwError;
811 }
812
813 DPRINT("Process Id: %lu Handle %lx\n",
814 ProcessInformation.dwProcessId,
815 ProcessInformation.hProcess);
816 DPRINT("Thread Id: %lu Handle %lx\n",
817 ProcessInformation.dwThreadId,
818 ProcessInformation.hThread);
819
820 /* Get process and thread ids */
821 Service->ProcessId = ProcessInformation.dwProcessId;
822 Service->ThreadId = ProcessInformation.dwThreadId;
823
824 /* Resume Thread */
825 ResumeThread(ProcessInformation.hThread);
826
827 /* Connect control pipe */
828 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ?
829 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
830 {
831 DWORD dwRead = 0;
832
833 DPRINT("Control pipe connected!\n");
834
835 /* Read SERVICE_STATUS_HANDLE from pipe */
836 if (!ReadFile(Service->ControlPipeHandle,
837 (LPVOID)&Service->hClient,
838 sizeof(DWORD),
839 &dwRead,
840 NULL))
841 {
842 dwError = GetLastError();
843 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
844 dwError);
845 }
846 else
847 {
848 DPRINT("Received service status %lu\n", Service->hClient);
849
850 /* Send start command */
851 dwError = ScmSendStartCommand(Service, lpArgs);
852 }
853 }
854 else
855 {
856 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
857
858 /* Close control pipe */
859 CloseHandle(Service->ControlPipeHandle);
860 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
861 Service->ProcessId = 0;
862 Service->ThreadId = 0;
863 }
864
865 /* Close process and thread handle */
866 CloseHandle(ProcessInformation.hThread);
867 CloseHandle(ProcessInformation.hProcess);
868
869 return dwError;
870 }
871
872
873 DWORD
874 ScmStartService(PSERVICE Service, LPWSTR lpArgs)
875 {
876 PSERVICE_GROUP Group = Service->lpGroup;
877 DWORD dwError = ERROR_SUCCESS;
878
879 DPRINT("ScmStartService() called\n");
880
881 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
882 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
883
884 if (Service->Status.dwServiceType & SERVICE_DRIVER)
885 {
886 /* Load driver */
887 dwError = ScmLoadDriver(Service);
888 if (dwError == ERROR_SUCCESS)
889 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
890 }
891 else
892 {
893 /* Start user-mode service */
894 dwError = ScmStartUserModeService(Service, lpArgs);
895 }
896
897 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
898
899 if (dwError == ERROR_SUCCESS)
900 {
901 if (Group != NULL)
902 {
903 Group->ServicesRunning = TRUE;
904 }
905 Service->Status.dwCurrentState = SERVICE_RUNNING;
906 }
907 #if 0
908 else
909 {
910 switch (Service->ErrorControl)
911 {
912 case SERVICE_ERROR_NORMAL:
913 /* FIXME: Log error */
914 break;
915
916 case SERVICE_ERROR_SEVERE:
917 if (IsLastKnownGood == FALSE)
918 {
919 /* FIXME: Boot last known good configuration */
920 }
921 break;
922
923 case SERVICE_ERROR_CRITICAL:
924 if (IsLastKnownGood == FALSE)
925 {
926 /* FIXME: Boot last known good configuration */
927 }
928 else
929 {
930 /* FIXME: BSOD! */
931 }
932 break;
933 }
934 }
935 #endif
936
937 return dwError;
938 }
939
940
941 VOID
942 ScmAutoStartServices(VOID)
943 {
944 PLIST_ENTRY GroupEntry;
945 PLIST_ENTRY ServiceEntry;
946 PSERVICE_GROUP CurrentGroup;
947 PSERVICE CurrentService;
948 ULONG i;
949
950 /* Clear 'ServiceVisited' flag */
951 ServiceEntry = ServiceListHead.Flink;
952 while (ServiceEntry != &ServiceListHead)
953 {
954 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
955 CurrentService->ServiceVisited = FALSE;
956 ServiceEntry = ServiceEntry->Flink;
957 }
958
959 /* Start all services which are members of an existing group */
960 GroupEntry = GroupListHead.Flink;
961 while (GroupEntry != &GroupListHead)
962 {
963 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
964
965 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
966
967 /* Start all services witch have a valid tag */
968 for (i = 0; i < CurrentGroup->TagCount; i++)
969 {
970 ServiceEntry = ServiceListHead.Flink;
971 while (ServiceEntry != &ServiceListHead)
972 {
973 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
974
975 if ((CurrentService->lpGroup == CurrentGroup) &&
976 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
977 (CurrentService->ServiceVisited == FALSE) &&
978 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
979 {
980 CurrentService->ServiceVisited = TRUE;
981 ScmStartService(CurrentService, NULL);
982 }
983
984 ServiceEntry = ServiceEntry->Flink;
985 }
986 }
987
988 /* Start all services which have an invalid tag or which do not have a tag */
989 ServiceEntry = ServiceListHead.Flink;
990 while (ServiceEntry != &ServiceListHead)
991 {
992 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
993
994 if ((CurrentService->lpGroup == CurrentGroup) &&
995 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
996 (CurrentService->ServiceVisited == FALSE))
997 {
998 CurrentService->ServiceVisited = TRUE;
999 ScmStartService(CurrentService, NULL);
1000 }
1001
1002 ServiceEntry = ServiceEntry->Flink;
1003 }
1004
1005 GroupEntry = GroupEntry->Flink;
1006 }
1007
1008 /* Start all services which are members of any non-existing group */
1009 ServiceEntry = ServiceListHead.Flink;
1010 while (ServiceEntry != &ServiceListHead)
1011 {
1012 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1013
1014 if ((CurrentService->lpGroup != NULL) &&
1015 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1016 (CurrentService->ServiceVisited == FALSE))
1017 {
1018 CurrentService->ServiceVisited = TRUE;
1019 ScmStartService(CurrentService, NULL);
1020 }
1021
1022 ServiceEntry = ServiceEntry->Flink;
1023 }
1024
1025 /* Start all services which are not a member of any group */
1026 ServiceEntry = ServiceListHead.Flink;
1027 while (ServiceEntry != &ServiceListHead)
1028 {
1029 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1030
1031 if ((CurrentService->lpGroup == NULL) &&
1032 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1033 (CurrentService->ServiceVisited == FALSE))
1034 {
1035 CurrentService->ServiceVisited = TRUE;
1036 ScmStartService(CurrentService, NULL);
1037 }
1038
1039 ServiceEntry = ServiceEntry->Flink;
1040 }
1041
1042 /* Clear 'ServiceVisited' flag again */
1043 ServiceEntry = ServiceListHead.Flink;
1044 while (ServiceEntry != &ServiceListHead)
1045 {
1046 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1047 CurrentService->ServiceVisited = FALSE;
1048 ServiceEntry = ServiceEntry->Flink;
1049 }
1050 }
1051
1052
1053 VOID
1054 ScmAutoShutdownServices(VOID)
1055 {
1056 PLIST_ENTRY ServiceEntry;
1057 PSERVICE CurrentService;
1058 SERVICE_STATUS ServiceStatus;
1059
1060 DPRINT("ScmAutoShutdownServices() called\n");
1061
1062 ServiceEntry = ServiceListHead.Flink;
1063 while (ServiceEntry != &ServiceListHead)
1064 {
1065 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1066
1067 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1068 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1069 {
1070 /* shutdown service */
1071 ScmControlService(CurrentService, SERVICE_CONTROL_STOP, &ServiceStatus);
1072 }
1073
1074 ServiceEntry = ServiceEntry->Flink;
1075 }
1076
1077 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1078 }
1079
1080 /* EOF */