- Sync up Mm interface with WinLdr branch (introduce the concept of a memory type...
[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 HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
702 DWORD KeyDisposition;
703
704 RtlInitUnicodeString(&ImagePath, NULL);
705
706 /* Get service data */
707 RtlZeroMemory(&QueryTable,
708 sizeof(QueryTable));
709
710 QueryTable[0].Name = L"Type";
711 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
712 QueryTable[0].EntryContext = &Type;
713
714 QueryTable[1].Name = L"ImagePath";
715 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
716 QueryTable[1].EntryContext = &ImagePath;
717
718 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
719 Service->lpServiceName,
720 QueryTable,
721 NULL,
722 NULL);
723 if (!NT_SUCCESS(Status))
724 {
725 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
726 return RtlNtStatusToDosError(Status);
727 }
728 DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
729 DPRINT("Type: %lx\n", Type);
730
731 /* Get the service number */
732 /* TODO: Create registry entry with correct write access */
733 Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
734 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
735 REG_OPTION_VOLATILE,
736 KEY_WRITE | KEY_READ,
737 NULL,
738 &hServiceCurrentKey,
739 &KeyDisposition);
740
741 if (ERROR_SUCCESS != Status)
742 {
743 DPRINT1("RegCreateKeyEx() failed with status %u\n", Status);
744 return Status;
745 }
746
747 if (REG_OPENED_EXISTING_KEY == KeyDisposition)
748 {
749 DWORD KeySize = sizeof(ServiceCurrent);
750 Status = RegQueryValueExW(hServiceCurrentKey, L"", 0, NULL, (BYTE*)&ServiceCurrent, &KeySize);
751
752 if (ERROR_SUCCESS != Status)
753 {
754 RegCloseKey(hServiceCurrentKey);
755 DPRINT1("RegQueryValueEx() failed with status %u\n", Status);
756 return Status;
757 }
758
759 ServiceCurrent++;
760 }
761
762 Status = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
763
764 RegCloseKey(hServiceCurrentKey);
765
766 if (ERROR_SUCCESS != Status)
767 {
768 DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status);
769 return Status;
770 }
771
772 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
773 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
774 Service->ControlPipeHandle = CreateNamedPipeW(NtControlPipeName,
775 PIPE_ACCESS_DUPLEX,
776 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
777 100,
778 8000,
779 4,
780 30000,
781 NULL);
782 DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName);
783 if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
784 {
785 DPRINT1("Failed to create control pipe!\n");
786 return GetLastError();
787 }
788
789 StartupInfo.cb = sizeof(StartupInfo);
790 StartupInfo.lpReserved = NULL;
791 StartupInfo.lpDesktop = NULL;
792 StartupInfo.lpTitle = NULL;
793 StartupInfo.dwFlags = 0;
794 StartupInfo.cbReserved2 = 0;
795 StartupInfo.lpReserved2 = 0;
796
797 Result = CreateProcessW(ImagePath.Buffer,
798 NULL,
799 NULL,
800 NULL,
801 FALSE,
802 DETACHED_PROCESS | CREATE_SUSPENDED,
803 NULL,
804 NULL,
805 &StartupInfo,
806 &ProcessInformation);
807 RtlFreeUnicodeString(&ImagePath);
808
809 if (!Result)
810 {
811 dwError = GetLastError();
812 /* Close control pipe */
813 CloseHandle(Service->ControlPipeHandle);
814 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
815
816 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
817 return dwError;
818 }
819
820 DPRINT("Process Id: %lu Handle %lx\n",
821 ProcessInformation.dwProcessId,
822 ProcessInformation.hProcess);
823 DPRINT("Thread Id: %lu Handle %lx\n",
824 ProcessInformation.dwThreadId,
825 ProcessInformation.hThread);
826
827 /* Get process and thread ids */
828 Service->ProcessId = ProcessInformation.dwProcessId;
829 Service->ThreadId = ProcessInformation.dwThreadId;
830
831 /* Resume Thread */
832 ResumeThread(ProcessInformation.hThread);
833
834 /* Connect control pipe */
835 if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ?
836 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
837 {
838 DWORD dwRead = 0;
839
840 DPRINT("Control pipe connected!\n");
841
842 /* Read SERVICE_STATUS_HANDLE from pipe */
843 if (!ReadFile(Service->ControlPipeHandle,
844 (LPVOID)&Service->hClient,
845 sizeof(DWORD),
846 &dwRead,
847 NULL))
848 {
849 dwError = GetLastError();
850 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
851 dwError);
852 }
853 else
854 {
855 DPRINT("Received service status %lu\n", Service->hClient);
856
857 /* Send start command */
858 dwError = ScmSendStartCommand(Service, lpArgs);
859 }
860 }
861 else
862 {
863 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
864
865 /* Close control pipe */
866 CloseHandle(Service->ControlPipeHandle);
867 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
868 Service->ProcessId = 0;
869 Service->ThreadId = 0;
870 }
871
872 /* Close process and thread handle */
873 CloseHandle(ProcessInformation.hThread);
874 CloseHandle(ProcessInformation.hProcess);
875
876 return dwError;
877 }
878
879
880 DWORD
881 ScmStartService(PSERVICE Service, LPWSTR lpArgs)
882 {
883 PSERVICE_GROUP Group = Service->lpGroup;
884 DWORD dwError = ERROR_SUCCESS;
885
886 DPRINT("ScmStartService() called\n");
887
888 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
889 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
890
891 if (Service->Status.dwServiceType & SERVICE_DRIVER)
892 {
893 /* Load driver */
894 dwError = ScmLoadDriver(Service);
895 if (dwError == ERROR_SUCCESS)
896 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
897 }
898 else
899 {
900 /* Start user-mode service */
901 dwError = ScmStartUserModeService(Service, lpArgs);
902 }
903
904 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
905
906 if (dwError == ERROR_SUCCESS)
907 {
908 if (Group != NULL)
909 {
910 Group->ServicesRunning = TRUE;
911 }
912 Service->Status.dwCurrentState = SERVICE_RUNNING;
913 }
914 #if 0
915 else
916 {
917 switch (Service->ErrorControl)
918 {
919 case SERVICE_ERROR_NORMAL:
920 /* FIXME: Log error */
921 break;
922
923 case SERVICE_ERROR_SEVERE:
924 if (IsLastKnownGood == FALSE)
925 {
926 /* FIXME: Boot last known good configuration */
927 }
928 break;
929
930 case SERVICE_ERROR_CRITICAL:
931 if (IsLastKnownGood == FALSE)
932 {
933 /* FIXME: Boot last known good configuration */
934 }
935 else
936 {
937 /* FIXME: BSOD! */
938 }
939 break;
940 }
941 }
942 #endif
943
944 return dwError;
945 }
946
947
948 VOID
949 ScmAutoStartServices(VOID)
950 {
951 PLIST_ENTRY GroupEntry;
952 PLIST_ENTRY ServiceEntry;
953 PSERVICE_GROUP CurrentGroup;
954 PSERVICE CurrentService;
955 ULONG i;
956
957 /* Clear 'ServiceVisited' flag */
958 ServiceEntry = ServiceListHead.Flink;
959 while (ServiceEntry != &ServiceListHead)
960 {
961 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
962 CurrentService->ServiceVisited = FALSE;
963 ServiceEntry = ServiceEntry->Flink;
964 }
965
966 /* Start all services which are members of an existing group */
967 GroupEntry = GroupListHead.Flink;
968 while (GroupEntry != &GroupListHead)
969 {
970 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
971
972 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
973
974 /* Start all services witch have a valid tag */
975 for (i = 0; i < CurrentGroup->TagCount; i++)
976 {
977 ServiceEntry = ServiceListHead.Flink;
978 while (ServiceEntry != &ServiceListHead)
979 {
980 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
981
982 if ((CurrentService->lpGroup == CurrentGroup) &&
983 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
984 (CurrentService->ServiceVisited == FALSE) &&
985 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
986 {
987 CurrentService->ServiceVisited = TRUE;
988 ScmStartService(CurrentService, NULL);
989 }
990
991 ServiceEntry = ServiceEntry->Flink;
992 }
993 }
994
995 /* Start all services which have an invalid tag or which do not have a tag */
996 ServiceEntry = ServiceListHead.Flink;
997 while (ServiceEntry != &ServiceListHead)
998 {
999 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1000
1001 if ((CurrentService->lpGroup == CurrentGroup) &&
1002 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1003 (CurrentService->ServiceVisited == FALSE))
1004 {
1005 CurrentService->ServiceVisited = TRUE;
1006 ScmStartService(CurrentService, NULL);
1007 }
1008
1009 ServiceEntry = ServiceEntry->Flink;
1010 }
1011
1012 GroupEntry = GroupEntry->Flink;
1013 }
1014
1015 /* Start all services which are members of any non-existing group */
1016 ServiceEntry = ServiceListHead.Flink;
1017 while (ServiceEntry != &ServiceListHead)
1018 {
1019 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1020
1021 if ((CurrentService->lpGroup != NULL) &&
1022 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1023 (CurrentService->ServiceVisited == FALSE))
1024 {
1025 CurrentService->ServiceVisited = TRUE;
1026 ScmStartService(CurrentService, NULL);
1027 }
1028
1029 ServiceEntry = ServiceEntry->Flink;
1030 }
1031
1032 /* Start all services which are not a member of any group */
1033 ServiceEntry = ServiceListHead.Flink;
1034 while (ServiceEntry != &ServiceListHead)
1035 {
1036 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1037
1038 if ((CurrentService->lpGroup == NULL) &&
1039 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1040 (CurrentService->ServiceVisited == FALSE))
1041 {
1042 CurrentService->ServiceVisited = TRUE;
1043 ScmStartService(CurrentService, NULL);
1044 }
1045
1046 ServiceEntry = ServiceEntry->Flink;
1047 }
1048
1049 /* Clear 'ServiceVisited' flag again */
1050 ServiceEntry = ServiceListHead.Flink;
1051 while (ServiceEntry != &ServiceListHead)
1052 {
1053 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1054 CurrentService->ServiceVisited = FALSE;
1055 ServiceEntry = ServiceEntry->Flink;
1056 }
1057 }
1058
1059
1060 VOID
1061 ScmAutoShutdownServices(VOID)
1062 {
1063 PLIST_ENTRY ServiceEntry;
1064 PSERVICE CurrentService;
1065 SERVICE_STATUS ServiceStatus;
1066
1067 DPRINT("ScmAutoShutdownServices() called\n");
1068
1069 ServiceEntry = ServiceListHead.Flink;
1070 while (ServiceEntry != &ServiceListHead)
1071 {
1072 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1073
1074 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1075 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1076 {
1077 /* shutdown service */
1078 ScmControlService(CurrentService, SERVICE_CONTROL_STOP, &ServiceStatus);
1079 }
1080
1081 ServiceEntry = ServiceEntry->Flink;
1082 }
1083
1084 DPRINT("ScmGetBootAndSystemDriverState() done\n");
1085 }
1086
1087 /* EOF */