[SERVICES/ADVAPI32]
[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 * Uncomment the line below to start services
22 * using the SERVICE_START_PENDING state
23 */
24 // #define USE_SERVICE_START_PENDING
25
26 /* GLOBALS *******************************************************************/
27
28 LIST_ENTRY ImageListHead;
29 LIST_ENTRY ServiceListHead;
30
31 static RTL_RESOURCE DatabaseLock;
32 static DWORD dwResumeCount = 1;
33
34 static CRITICAL_SECTION ControlServiceCriticalSection;
35
36 /* FUNCTIONS *****************************************************************/
37
38 static DWORD
39 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
40 {
41 WCHAR szControlPipeName[MAX_PATH + 1];
42 HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
43 DWORD ServiceCurrent = 0;
44 DWORD KeyDisposition;
45 DWORD dwKeySize;
46 DWORD dwError;
47
48 /* Get the service number */
49 /* TODO: Create registry entry with correct write access */
50 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
51 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
52 REG_OPTION_VOLATILE,
53 KEY_WRITE | KEY_READ,
54 NULL,
55 &hServiceCurrentKey,
56 &KeyDisposition);
57 if (dwError != ERROR_SUCCESS)
58 {
59 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
60 return dwError;
61 }
62
63 if (KeyDisposition == REG_OPENED_EXISTING_KEY)
64 {
65 dwKeySize = sizeof(DWORD);
66 dwError = RegQueryValueExW(hServiceCurrentKey,
67 L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
68
69 if (dwError != ERROR_SUCCESS)
70 {
71 RegCloseKey(hServiceCurrentKey);
72 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
73 return dwError;
74 }
75
76 ServiceCurrent++;
77 }
78
79 dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
80
81 RegCloseKey(hServiceCurrentKey);
82
83 if (dwError != ERROR_SUCCESS)
84 {
85 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
86 return dwError;
87 }
88
89 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
90 swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
91
92 DPRINT("PipeName: %S\n", szControlPipeName);
93
94 pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
95 PIPE_ACCESS_DUPLEX,
96 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
97 100,
98 8000,
99 4,
100 30000,
101 NULL);
102 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
103 if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
104 {
105 DPRINT1("Failed to create control pipe!\n");
106 return GetLastError();
107 }
108
109 return ERROR_SUCCESS;
110 }
111
112
113 static PSERVICE_IMAGE
114 ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
115 {
116 PLIST_ENTRY ImageEntry;
117 PSERVICE_IMAGE CurrentImage;
118
119 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath);
120
121 ImageEntry = ImageListHead.Flink;
122 while (ImageEntry != &ImageListHead)
123 {
124 CurrentImage = CONTAINING_RECORD(ImageEntry,
125 SERVICE_IMAGE,
126 ImageListEntry);
127 if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0)
128 {
129 DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
130 return CurrentImage;
131 }
132
133 ImageEntry = ImageEntry->Flink;
134 }
135
136 DPRINT1("Couldn't find a matching image\n");
137
138 return NULL;
139
140 }
141
142
143 static DWORD
144 ScmCreateOrReferenceServiceImage(PSERVICE pService)
145 {
146 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
147 UNICODE_STRING ImagePath;
148 PSERVICE_IMAGE pServiceImage = NULL;
149 NTSTATUS Status;
150 DWORD dwError = ERROR_SUCCESS;
151
152 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
153
154 RtlInitUnicodeString(&ImagePath, NULL);
155
156 /* Get service data */
157 RtlZeroMemory(&QueryTable,
158 sizeof(QueryTable));
159
160 QueryTable[0].Name = L"ImagePath";
161 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
162 QueryTable[0].EntryContext = &ImagePath;
163
164 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
165 pService->lpServiceName,
166 QueryTable,
167 NULL,
168 NULL);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
172 return RtlNtStatusToDosError(Status);
173 }
174
175 DPRINT("ImagePath: '%wZ'\n", &ImagePath);
176
177 pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
178 if (pServiceImage == NULL)
179 {
180 /* Create a new service image */
181 pServiceImage = (PSERVICE_IMAGE)HeapAlloc(GetProcessHeap(),
182 HEAP_ZERO_MEMORY,
183 sizeof(SERVICE_IMAGE) + ((wcslen(ImagePath.Buffer) + 1) * sizeof(WCHAR)));
184 if (pServiceImage == NULL)
185 {
186 dwError = ERROR_NOT_ENOUGH_MEMORY;
187 goto done;
188 }
189
190 pServiceImage->dwImageRunCount = 1;
191 pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
192 pServiceImage->hProcess = INVALID_HANDLE_VALUE;
193
194 /* Set the image path */
195 wcscpy(pServiceImage->szImagePath,
196 ImagePath.Buffer);
197
198 RtlFreeUnicodeString(&ImagePath);
199
200 /* Create the control pipe */
201 dwError = ScmCreateNewControlPipe(pServiceImage);
202 if (dwError != ERROR_SUCCESS)
203 {
204 HeapFree(GetProcessHeap(), 0, pServiceImage);
205 goto done;
206 }
207
208 /* FIXME: Add more initialization code here */
209
210
211 /* Append service record */
212 InsertTailList(&ImageListHead,
213 &pServiceImage->ImageListEntry);
214 }
215 else
216 {
217 /* Increment the run counter */
218 pServiceImage->dwImageRunCount++;
219 }
220
221 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
222
223 /* Link the service image to the service */
224 pService->lpImage = pServiceImage;
225
226 done:;
227 RtlFreeUnicodeString(&ImagePath);
228
229 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
230
231 return dwError;
232 }
233
234
235 static VOID
236 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
237 {
238 DPRINT1("ScmDereferenceServiceImage() called\n");
239
240 pServiceImage->dwImageRunCount--;
241
242 if (pServiceImage->dwImageRunCount == 0)
243 {
244 DPRINT1("dwImageRunCount == 0\n");
245
246 /* FIXME: Terminate the process */
247
248 /* Remove the service image from the list */
249 RemoveEntryList(&pServiceImage->ImageListEntry);
250
251 /* Close the control pipe */
252 if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
253 CloseHandle(pServiceImage->hControlPipe);
254
255 /* Close the process handle */
256 if (pServiceImage->hProcess != INVALID_HANDLE_VALUE)
257 CloseHandle(pServiceImage->hProcess);
258
259 /* Release the service image */
260 HeapFree(GetProcessHeap(), 0, pServiceImage);
261 }
262 }
263
264
265 PSERVICE
266 ScmGetServiceEntryByName(LPCWSTR lpServiceName)
267 {
268 PLIST_ENTRY ServiceEntry;
269 PSERVICE CurrentService;
270
271 DPRINT("ScmGetServiceEntryByName() called\n");
272
273 ServiceEntry = ServiceListHead.Flink;
274 while (ServiceEntry != &ServiceListHead)
275 {
276 CurrentService = CONTAINING_RECORD(ServiceEntry,
277 SERVICE,
278 ServiceListEntry);
279 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
280 {
281 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
282 return CurrentService;
283 }
284
285 ServiceEntry = ServiceEntry->Flink;
286 }
287
288 DPRINT("Couldn't find a matching service\n");
289
290 return NULL;
291 }
292
293
294 PSERVICE
295 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName)
296 {
297 PLIST_ENTRY ServiceEntry;
298 PSERVICE CurrentService;
299
300 DPRINT("ScmGetServiceEntryByDisplayName() called\n");
301
302 ServiceEntry = ServiceListHead.Flink;
303 while (ServiceEntry != &ServiceListHead)
304 {
305 CurrentService = CONTAINING_RECORD(ServiceEntry,
306 SERVICE,
307 ServiceListEntry);
308 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
309 {
310 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
311 return CurrentService;
312 }
313
314 ServiceEntry = ServiceEntry->Flink;
315 }
316
317 DPRINT("Couldn't find a matching service\n");
318
319 return NULL;
320 }
321
322
323 PSERVICE
324 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
325 {
326 PLIST_ENTRY ServiceEntry;
327 PSERVICE CurrentService;
328
329 DPRINT("ScmGetServiceEntryByResumeCount() called\n");
330
331 ServiceEntry = ServiceListHead.Flink;
332 while (ServiceEntry != &ServiceListHead)
333 {
334 CurrentService = CONTAINING_RECORD(ServiceEntry,
335 SERVICE,
336 ServiceListEntry);
337 if (CurrentService->dwResumeCount > dwResumeCount)
338 {
339 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
340 return CurrentService;
341 }
342
343 ServiceEntry = ServiceEntry->Flink;
344 }
345
346 DPRINT("Couldn't find a matching service\n");
347
348 return NULL;
349 }
350
351
352 DWORD
353 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
354 PSERVICE *lpServiceRecord)
355 {
356 PSERVICE lpService = NULL;
357
358 DPRINT("Service: '%S'\n", lpServiceName);
359
360 /* Allocate service entry */
361 lpService = (SERVICE*)HeapAlloc(GetProcessHeap(),
362 HEAP_ZERO_MEMORY,
363 sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
364 if (lpService == NULL)
365 return ERROR_NOT_ENOUGH_MEMORY;
366
367 *lpServiceRecord = lpService;
368
369 /* Copy service name */
370 wcscpy(lpService->szServiceName, lpServiceName);
371 lpService->lpServiceName = lpService->szServiceName;
372 lpService->lpDisplayName = lpService->lpServiceName;
373
374 /* Set the resume count */
375 lpService->dwResumeCount = dwResumeCount++;
376
377 /* Append service record */
378 InsertTailList(&ServiceListHead,
379 &lpService->ServiceListEntry);
380
381 /* Initialize the service status */
382 lpService->Status.dwCurrentState = SERVICE_STOPPED;
383 lpService->Status.dwControlsAccepted = 0;
384 lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
385 lpService->Status.dwServiceSpecificExitCode = 0;
386 lpService->Status.dwCheckPoint = 0;
387 lpService->Status.dwWaitHint = 2000; /* 2 seconds */
388
389 return ERROR_SUCCESS;
390 }
391
392
393 VOID
394 ScmDeleteServiceRecord(PSERVICE lpService)
395 {
396 DPRINT("Deleting Service %S\n", lpService->lpServiceName);
397
398 /* Delete the display name */
399 if (lpService->lpDisplayName != NULL &&
400 lpService->lpDisplayName != lpService->lpServiceName)
401 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
402
403 /* Dereference the service image */
404 if (lpService->lpImage)
405 ScmDereferenceServiceImage(lpService->lpImage);
406
407 /* Decrement the group reference counter */
408 if (lpService->lpGroup)
409 lpService->lpGroup->dwRefCount--;
410
411 /* FIXME: SecurityDescriptor */
412
413
414 /* Remove the Service from the List */
415 RemoveEntryList(&lpService->ServiceListEntry);
416
417 DPRINT("Deleted Service %S\n", lpService->lpServiceName);
418
419 /* Delete the service record */
420 HeapFree(GetProcessHeap(), 0, lpService);
421
422 DPRINT("Done\n");
423 }
424
425
426 static DWORD
427 CreateServiceListEntry(LPCWSTR lpServiceName,
428 HKEY hServiceKey)
429 {
430 PSERVICE lpService = NULL;
431 LPWSTR lpDisplayName = NULL;
432 LPWSTR lpGroup = NULL;
433 DWORD dwSize;
434 DWORD dwError;
435 DWORD dwServiceType;
436 DWORD dwStartType;
437 DWORD dwErrorControl;
438 DWORD dwTagId;
439
440 DPRINT("Service: '%S'\n", lpServiceName);
441 if (*lpServiceName == L'{')
442 return ERROR_SUCCESS;
443
444 dwSize = sizeof(DWORD);
445 dwError = RegQueryValueExW(hServiceKey,
446 L"Type",
447 NULL,
448 NULL,
449 (LPBYTE)&dwServiceType,
450 &dwSize);
451 if (dwError != ERROR_SUCCESS)
452 return ERROR_SUCCESS;
453
454 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
455 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
456 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
457 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
458 return ERROR_SUCCESS;
459
460 DPRINT("Service type: %lx\n", dwServiceType);
461
462 dwSize = sizeof(DWORD);
463 dwError = RegQueryValueExW(hServiceKey,
464 L"Start",
465 NULL,
466 NULL,
467 (LPBYTE)&dwStartType,
468 &dwSize);
469 if (dwError != ERROR_SUCCESS)
470 return ERROR_SUCCESS;
471
472 DPRINT("Start type: %lx\n", dwStartType);
473
474 dwSize = sizeof(DWORD);
475 dwError = RegQueryValueExW(hServiceKey,
476 L"ErrorControl",
477 NULL,
478 NULL,
479 (LPBYTE)&dwErrorControl,
480 &dwSize);
481 if (dwError != ERROR_SUCCESS)
482 return ERROR_SUCCESS;
483
484 DPRINT("Error control: %lx\n", dwErrorControl);
485
486 dwError = RegQueryValueExW(hServiceKey,
487 L"Tag",
488 NULL,
489 NULL,
490 (LPBYTE)&dwTagId,
491 &dwSize);
492 if (dwError != ERROR_SUCCESS)
493 dwTagId = 0;
494
495 DPRINT("Tag: %lx\n", dwTagId);
496
497 dwError = ScmReadString(hServiceKey,
498 L"Group",
499 &lpGroup);
500 if (dwError != ERROR_SUCCESS)
501 lpGroup = NULL;
502
503 DPRINT("Group: %S\n", lpGroup);
504
505 dwError = ScmReadString(hServiceKey,
506 L"DisplayName",
507 &lpDisplayName);
508 if (dwError != ERROR_SUCCESS)
509 lpDisplayName = NULL;
510
511 DPRINT("Display name: %S\n", lpDisplayName);
512
513 dwError = ScmCreateNewServiceRecord(lpServiceName,
514 &lpService);
515 if (dwError != ERROR_SUCCESS)
516 goto done;
517
518 lpService->Status.dwServiceType = dwServiceType;
519 lpService->dwStartType = dwStartType;
520 lpService->dwErrorControl = dwErrorControl;
521 lpService->dwTag = dwTagId;
522
523 if (lpGroup != NULL)
524 {
525 dwError = ScmSetServiceGroup(lpService, lpGroup);
526 if (dwError != ERROR_SUCCESS)
527 goto done;
528 }
529
530 if (lpDisplayName != NULL)
531 {
532 lpService->lpDisplayName = lpDisplayName;
533 lpDisplayName = NULL;
534 }
535
536 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
537 if (lpService->lpGroup != NULL)
538 {
539 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
540 }
541 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
542 lpService->dwStartType,
543 lpService->Status.dwServiceType,
544 lpService->dwTag,
545 lpService->dwErrorControl);
546
547 if (ScmIsDeleteFlagSet(hServiceKey))
548 lpService->bDeleted = TRUE;
549
550 done:;
551 if (lpGroup != NULL)
552 HeapFree(GetProcessHeap(), 0, lpGroup);
553
554 if (lpDisplayName != NULL)
555 HeapFree(GetProcessHeap(), 0, lpDisplayName);
556
557 if (lpService != NULL)
558 {
559 if (lpService->lpImage != NULL)
560 ScmDereferenceServiceImage(lpService->lpImage);
561 }
562
563 return dwError;
564 }
565
566
567 DWORD
568 ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
569 {
570 DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
571 WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
572 HKEY hSubKey = 0;
573
574 dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
575 if (!dwRet)
576 {
577 /* Find the maximum subkey length so that we can allocate a buffer */
578 dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
579 &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
580 if (!dwRet)
581 {
582 dwMaxSubkeyLen++;
583 if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
584 /* Name too big: alloc a buffer for it */
585 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
586
587 if(!lpszName)
588 dwRet = ERROR_NOT_ENOUGH_MEMORY;
589 else
590 {
591 while (dwRet == ERROR_SUCCESS)
592 {
593 dwSize = dwMaxSubkeyLen;
594 dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
595 if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
596 dwRet = ScmDeleteRegKey(hSubKey, lpszName);
597 }
598 if (dwRet == ERROR_NO_MORE_ITEMS)
599 dwRet = ERROR_SUCCESS;
600
601 if (lpszName != szNameBuf)
602 HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
603 }
604 }
605
606 RegCloseKey(hSubKey);
607 if (!dwRet)
608 dwRet = RegDeleteKeyW(hKey, lpszSubKey);
609 }
610 return dwRet;
611 }
612
613
614 VOID
615 ScmDeleteMarkedServices(VOID)
616 {
617 PLIST_ENTRY ServiceEntry;
618 PSERVICE CurrentService;
619 HKEY hServicesKey;
620 DWORD dwError;
621
622 ServiceEntry = ServiceListHead.Flink;
623 while (ServiceEntry != &ServiceListHead)
624 {
625 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
626
627 ServiceEntry = ServiceEntry->Flink;
628
629 if (CurrentService->bDeleted == TRUE)
630 {
631 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
632 L"System\\CurrentControlSet\\Services",
633 0,
634 DELETE,
635 &hServicesKey);
636 if (dwError == ERROR_SUCCESS)
637 {
638 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
639 RegCloseKey(hServicesKey);
640 if (dwError == ERROR_SUCCESS)
641 {
642 RemoveEntryList(&CurrentService->ServiceListEntry);
643 HeapFree(GetProcessHeap(), 0, CurrentService);
644 }
645 }
646
647 if (dwError != ERROR_SUCCESS)
648 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
649 }
650 }
651 }
652
653
654 VOID
655 WaitForLSA(VOID)
656 {
657 HANDLE hEvent;
658 DWORD dwError;
659
660 DPRINT("WaitForLSA() called\n");
661
662 hEvent = CreateEventW(NULL,
663 TRUE,
664 FALSE,
665 L"LSA_RPC_SERVER_ACTIVE");
666 if (hEvent == NULL)
667 {
668 dwError = GetLastError();
669 DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
670
671 if (dwError == ERROR_ALREADY_EXISTS)
672 {
673 hEvent = OpenEventW(SYNCHRONIZE,
674 FALSE,
675 L"LSA_RPC_SERVER_ACTIVE");
676 if (hEvent != NULL)
677 {
678 DPRINT1("Could not open the notification event!\n");
679 return;
680 }
681 }
682 }
683
684 DPRINT("Wait for LSA!\n");
685 WaitForSingleObject(hEvent, INFINITE);
686 DPRINT("LSA is available!\n");
687
688 CloseHandle(hEvent);
689
690 DPRINT("WaitForLSA() done\n");
691 }
692
693
694 DWORD
695 ScmCreateServiceDatabase(VOID)
696 {
697 WCHAR szSubKey[MAX_PATH];
698 HKEY hServicesKey;
699 HKEY hServiceKey;
700 DWORD dwSubKey;
701 DWORD dwSubKeyLength;
702 FILETIME ftLastChanged;
703 DWORD dwError;
704
705 DPRINT("ScmCreateServiceDatabase() called\n");
706
707 dwError = ScmCreateGroupList();
708 if (dwError != ERROR_SUCCESS)
709 return dwError;
710
711 /* Initialize basic variables */
712 InitializeListHead(&ImageListHead);
713 InitializeListHead(&ServiceListHead);
714
715 /* Initialize the database lock */
716 RtlInitializeResource(&DatabaseLock);
717
718 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
719 L"System\\CurrentControlSet\\Services",
720 0,
721 KEY_READ,
722 &hServicesKey);
723 if (dwError != ERROR_SUCCESS)
724 return dwError;
725
726 dwSubKey = 0;
727 for (;;)
728 {
729 dwSubKeyLength = MAX_PATH;
730 dwError = RegEnumKeyExW(hServicesKey,
731 dwSubKey,
732 szSubKey,
733 &dwSubKeyLength,
734 NULL,
735 NULL,
736 NULL,
737 &ftLastChanged);
738 if (dwError == ERROR_SUCCESS &&
739 szSubKey[0] != L'{')
740 {
741 DPRINT("SubKeyName: '%S'\n", szSubKey);
742
743 dwError = RegOpenKeyExW(hServicesKey,
744 szSubKey,
745 0,
746 KEY_READ,
747 &hServiceKey);
748 if (dwError == ERROR_SUCCESS)
749 {
750 dwError = CreateServiceListEntry(szSubKey,
751 hServiceKey);
752
753 RegCloseKey(hServiceKey);
754 }
755 }
756
757 if (dwError != ERROR_SUCCESS)
758 break;
759
760 dwSubKey++;
761 }
762
763 RegCloseKey(hServicesKey);
764
765 /* Wait for LSA */
766 WaitForLSA();
767
768 /* Delete services that are marked for delete */
769 ScmDeleteMarkedServices();
770
771 DPRINT("ScmCreateServiceDatabase() done\n");
772
773 return ERROR_SUCCESS;
774 }
775
776
777 VOID
778 ScmShutdownServiceDatabase(VOID)
779 {
780 DPRINT("ScmShutdownServiceDatabase() called\n");
781
782 ScmDeleteMarkedServices();
783 RtlDeleteResource(&DatabaseLock);
784
785 DPRINT("ScmShutdownServiceDatabase() done\n");
786 }
787
788
789 static NTSTATUS
790 ScmCheckDriver(PSERVICE Service)
791 {
792 OBJECT_ATTRIBUTES ObjectAttributes;
793 UNICODE_STRING DirName;
794 HANDLE DirHandle;
795 NTSTATUS Status;
796 POBJECT_DIRECTORY_INFORMATION DirInfo;
797 ULONG BufferLength;
798 ULONG DataLength;
799 ULONG Index;
800
801 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
802
803 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
804 {
805 RtlInitUnicodeString(&DirName,
806 L"\\Driver");
807 }
808 else
809 {
810 RtlInitUnicodeString(&DirName,
811 L"\\FileSystem");
812 }
813
814 InitializeObjectAttributes(&ObjectAttributes,
815 &DirName,
816 0,
817 NULL,
818 NULL);
819
820 Status = NtOpenDirectoryObject(&DirHandle,
821 DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
822 &ObjectAttributes);
823 if (!NT_SUCCESS(Status))
824 {
825 return Status;
826 }
827
828 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
829 2 * MAX_PATH * sizeof(WCHAR);
830 DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
831 HEAP_ZERO_MEMORY,
832 BufferLength);
833
834 Index = 0;
835 while (TRUE)
836 {
837 Status = NtQueryDirectoryObject(DirHandle,
838 DirInfo,
839 BufferLength,
840 TRUE,
841 FALSE,
842 &Index,
843 &DataLength);
844 if (Status == STATUS_NO_MORE_ENTRIES)
845 {
846 /* FIXME: Add current service to 'failed service' list */
847 DPRINT("Service '%S' failed\n", Service->lpServiceName);
848 break;
849 }
850
851 if (!NT_SUCCESS(Status))
852 break;
853
854 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
855
856 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
857 {
858 DPRINT("Found: '%S' '%wZ'\n",
859 Service->lpServiceName, &DirInfo->Name);
860
861 /* Mark service as 'running' */
862 Service->Status.dwCurrentState = SERVICE_RUNNING;
863
864 /* Mark the service group as 'running' */
865 if (Service->lpGroup != NULL)
866 {
867 Service->lpGroup->ServicesRunning = TRUE;
868 }
869
870 break;
871 }
872 }
873
874 HeapFree(GetProcessHeap(),
875 0,
876 DirInfo);
877 NtClose(DirHandle);
878
879 return STATUS_SUCCESS;
880 }
881
882
883 VOID
884 ScmGetBootAndSystemDriverState(VOID)
885 {
886 PLIST_ENTRY ServiceEntry;
887 PSERVICE CurrentService;
888
889 DPRINT("ScmGetBootAndSystemDriverState() called\n");
890
891 ServiceEntry = ServiceListHead.Flink;
892 while (ServiceEntry != &ServiceListHead)
893 {
894 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
895
896 if (CurrentService->dwStartType == SERVICE_BOOT_START ||
897 CurrentService->dwStartType == SERVICE_SYSTEM_START)
898 {
899 /* Check driver */
900 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName);
901
902 ScmCheckDriver(CurrentService);
903 }
904
905 ServiceEntry = ServiceEntry->Flink;
906 }
907
908 DPRINT("ScmGetBootAndSystemDriverState() done\n");
909 }
910
911
912 DWORD
913 ScmControlService(PSERVICE Service,
914 DWORD dwControl)
915 {
916 PSCM_CONTROL_PACKET ControlPacket;
917 SCM_REPLY_PACKET ReplyPacket;
918
919 DWORD dwWriteCount = 0;
920 DWORD dwReadCount = 0;
921 DWORD PacketSize;
922 PWSTR Ptr;
923 DWORD dwError = ERROR_SUCCESS;
924
925 DPRINT("ScmControlService() called\n");
926
927 EnterCriticalSection(&ControlServiceCriticalSection);
928
929 /* Calculate the total length of the start command line */
930 PacketSize = sizeof(SCM_CONTROL_PACKET);
931 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
932
933 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
934 HEAP_ZERO_MEMORY,
935 PacketSize);
936 if (ControlPacket == NULL)
937 {
938 LeaveCriticalSection(&ControlServiceCriticalSection);
939 return ERROR_NOT_ENOUGH_MEMORY;
940 }
941
942 ControlPacket->dwSize = PacketSize;
943 ControlPacket->dwControl = dwControl;
944 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
945
946 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
947
948 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
949 wcscpy(Ptr, Service->lpServiceName);
950
951 ControlPacket->dwArgumentsCount = 0;
952 ControlPacket->dwArgumentsOffset = 0;
953
954 /* Send the control packet */
955 WriteFile(Service->lpImage->hControlPipe,
956 ControlPacket,
957 PacketSize,
958 &dwWriteCount,
959 NULL);
960
961 /* Read the reply */
962 ReadFile(Service->lpImage->hControlPipe,
963 &ReplyPacket,
964 sizeof(SCM_REPLY_PACKET),
965 &dwReadCount,
966 NULL);
967
968 /* Release the contol packet */
969 HeapFree(GetProcessHeap(),
970 0,
971 ControlPacket);
972
973 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
974 {
975 dwError = ReplyPacket.dwError;
976 }
977
978 if (dwError == ERROR_SUCCESS &&
979 dwControl == SERVICE_CONTROL_STOP)
980 {
981 ScmDereferenceServiceImage(Service->lpImage);
982 }
983
984 LeaveCriticalSection(&ControlServiceCriticalSection);
985
986 DPRINT("ScmControlService() done\n");
987
988 return dwError;
989 }
990
991
992 static DWORD
993 ScmSendStartCommand(PSERVICE Service,
994 DWORD argc,
995 LPWSTR *argv)
996 {
997 PSCM_CONTROL_PACKET ControlPacket;
998 SCM_REPLY_PACKET ReplyPacket;
999 DWORD PacketSize;
1000 PWSTR Ptr;
1001 DWORD dwWriteCount = 0;
1002 DWORD dwReadCount = 0;
1003 DWORD dwError = ERROR_SUCCESS;
1004 DWORD i;
1005 PWSTR *pOffPtr;
1006 PWSTR pArgPtr;
1007
1008 DPRINT("ScmSendStartCommand() called\n");
1009
1010 /* Calculate the total length of the start command line */
1011 PacketSize = sizeof(SCM_CONTROL_PACKET);
1012 PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
1013
1014 /* Calculate the required packet size for the start arguments */
1015 if (argc > 0 && argv != NULL)
1016 {
1017 PacketSize = ALIGN_UP(PacketSize, LPWSTR);
1018
1019 DPRINT("Argc: %lu\n", argc);
1020 for (i = 0; i < argc; i++)
1021 {
1022 DPRINT("Argv[%lu]: %S\n", i, argv[i]);
1023 PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR);
1024 }
1025 }
1026
1027 /* Allocate a control packet */
1028 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
1029 HEAP_ZERO_MEMORY,
1030 PacketSize);
1031 if (ControlPacket == NULL)
1032 return ERROR_NOT_ENOUGH_MEMORY;
1033
1034 ControlPacket->dwSize = PacketSize;
1035 ControlPacket->dwControl = SERVICE_CONTROL_START;
1036 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1037 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
1038
1039 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
1040 wcscpy(Ptr, Service->lpServiceName);
1041
1042 ControlPacket->dwArgumentsCount = 0;
1043 ControlPacket->dwArgumentsOffset = 0;
1044
1045 /* Copy argument list */
1046 if (argc > 0 && argv != NULL)
1047 {
1048 Ptr += wcslen(Service->lpServiceName) + 1;
1049 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
1050 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
1051
1052 ControlPacket->dwArgumentsCount = argc;
1053 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
1054
1055 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
1056 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
1057
1058 for (i = 0; i < argc; i++)
1059 {
1060 wcscpy(pArgPtr, argv[i]);
1061 *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
1062 DPRINT("offset: %p\n", *pOffPtr);
1063
1064 pArgPtr += wcslen(argv[i]) + 1;
1065 pOffPtr++;
1066 }
1067 }
1068
1069 /* Send the start command */
1070 WriteFile(Service->lpImage->hControlPipe,
1071 ControlPacket,
1072 PacketSize,
1073 &dwWriteCount,
1074 NULL);
1075
1076 /* Read the reply */
1077 ReadFile(Service->lpImage->hControlPipe,
1078 &ReplyPacket,
1079 sizeof(SCM_REPLY_PACKET),
1080 &dwReadCount,
1081 NULL);
1082
1083 /* Release the contol packet */
1084 HeapFree(GetProcessHeap(),
1085 0,
1086 ControlPacket);
1087
1088 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1089 {
1090 dwError = ReplyPacket.dwError;
1091 }
1092
1093 DPRINT("ScmSendStartCommand() done\n");
1094
1095 return dwError;
1096 }
1097
1098
1099 static DWORD
1100 ScmStartUserModeService(PSERVICE Service,
1101 DWORD argc,
1102 LPWSTR *argv)
1103 {
1104 PROCESS_INFORMATION ProcessInformation;
1105 STARTUPINFOW StartupInfo;
1106 BOOL Result;
1107 DWORD dwError = ERROR_SUCCESS;
1108 DWORD dwProcessId;
1109
1110 DPRINT("ScmStartUserModeService(%p)\n", Service);
1111
1112 /* If the image is already running ... */
1113 if (Service->lpImage->dwImageRunCount > 1)
1114 {
1115 /* ... just send a start command */
1116 return ScmSendStartCommand(Service, argc, argv);
1117 }
1118
1119 StartupInfo.cb = sizeof(StartupInfo);
1120 StartupInfo.lpReserved = NULL;
1121 StartupInfo.lpDesktop = NULL;
1122 StartupInfo.lpTitle = NULL;
1123 StartupInfo.dwFlags = 0;
1124 StartupInfo.cbReserved2 = 0;
1125 StartupInfo.lpReserved2 = 0;
1126
1127 Result = CreateProcessW(NULL,
1128 Service->lpImage->szImagePath,
1129 NULL,
1130 NULL,
1131 FALSE,
1132 DETACHED_PROCESS | CREATE_SUSPENDED,
1133 NULL,
1134 NULL,
1135 &StartupInfo,
1136 &ProcessInformation);
1137 if (!Result)
1138 {
1139 dwError = GetLastError();
1140 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
1141 return dwError;
1142 }
1143
1144 DPRINT("Process Id: %lu Handle %lx\n",
1145 ProcessInformation.dwProcessId,
1146 ProcessInformation.hProcess);
1147 DPRINT("Thread Id: %lu Handle %lx\n",
1148 ProcessInformation.dwThreadId,
1149 ProcessInformation.hThread);
1150
1151 /* Get process handle and id */
1152 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1153 Service->lpImage->hProcess = ProcessInformation.hProcess;
1154
1155 /* Resume Thread */
1156 ResumeThread(ProcessInformation.hThread);
1157
1158 /* Connect control pipe */
1159 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
1160 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
1161 {
1162 DWORD dwRead = 0;
1163
1164 DPRINT("Control pipe connected!\n");
1165
1166 /* Read SERVICE_STATUS_HANDLE from pipe */
1167 if (!ReadFile(Service->lpImage->hControlPipe,
1168 (LPVOID)&dwProcessId,
1169 sizeof(DWORD),
1170 &dwRead,
1171 NULL))
1172 {
1173 dwError = GetLastError();
1174 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1175 dwError);
1176 }
1177 else
1178 {
1179 DPRINT("Received service process ID %lu\n", dwProcessId);
1180
1181 /* Send start command */
1182 dwError = ScmSendStartCommand(Service, argc, argv);
1183 }
1184 }
1185 else
1186 {
1187 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1188 }
1189
1190 /* Close thread handle */
1191 CloseHandle(ProcessInformation.hThread);
1192
1193 return dwError;
1194 }
1195
1196
1197 DWORD
1198 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
1199 {
1200 PSERVICE_GROUP Group = Service->lpGroup;
1201 DWORD dwError = ERROR_SUCCESS;
1202 LPCWSTR ErrorLogStrings[2];
1203
1204 DPRINT("ScmStartService() called\n");
1205
1206 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1207
1208 EnterCriticalSection(&ControlServiceCriticalSection);
1209
1210 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1211 {
1212 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1213 LeaveCriticalSection(&ControlServiceCriticalSection);
1214 return ERROR_SERVICE_ALREADY_RUNNING;
1215 }
1216
1217 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1218
1219 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1220 {
1221 /* Load driver */
1222 dwError = ScmLoadDriver(Service);
1223 if (dwError == ERROR_SUCCESS)
1224 {
1225 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1226 Service->Status.dwCurrentState = SERVICE_RUNNING;
1227 }
1228 }
1229 else
1230 {
1231 /* Start user-mode service */
1232 dwError = ScmCreateOrReferenceServiceImage(Service);
1233 if (dwError == ERROR_SUCCESS)
1234 {
1235 dwError = ScmStartUserModeService(Service, argc, argv);
1236 if (dwError == ERROR_SUCCESS)
1237 {
1238 #ifdef USE_SERVICE_START_PENDING
1239 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1240 #else
1241 Service->Status.dwCurrentState = SERVICE_RUNNING;
1242 #endif
1243 }
1244 else
1245 {
1246 ScmDereferenceServiceImage(Service->lpImage);
1247 Service->lpImage = NULL;
1248 }
1249 }
1250 }
1251
1252 LeaveCriticalSection(&ControlServiceCriticalSection);
1253
1254 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
1255
1256 if (dwError == ERROR_SUCCESS)
1257 {
1258 if (Group != NULL)
1259 {
1260 Group->ServicesRunning = TRUE;
1261 }
1262 }
1263 else
1264 {
1265 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1266 {
1267 ErrorLogStrings[0] = Service->lpServiceName;
1268 ErrorLogStrings[1] = L"Test";
1269 ScmLogError(EVENT_SERVICE_START_FAILED,
1270 2,
1271 ErrorLogStrings);
1272 }
1273
1274 #if 0
1275 switch (Service->dwErrorControl)
1276 {
1277 case SERVICE_ERROR_SEVERE:
1278 if (IsLastKnownGood == FALSE)
1279 {
1280 /* FIXME: Boot last known good configuration */
1281 }
1282 break;
1283
1284 case SERVICE_ERROR_CRITICAL:
1285 if (IsLastKnownGood == FALSE)
1286 {
1287 /* FIXME: Boot last known good configuration */
1288 }
1289 else
1290 {
1291 /* FIXME: BSOD! */
1292 }
1293 break;
1294 }
1295 #endif
1296 }
1297
1298 return dwError;
1299 }
1300
1301
1302 VOID
1303 ScmAutoStartServices(VOID)
1304 {
1305 PLIST_ENTRY GroupEntry;
1306 PLIST_ENTRY ServiceEntry;
1307 PSERVICE_GROUP CurrentGroup;
1308 PSERVICE CurrentService;
1309 WCHAR szSafeBootServicePath[MAX_PATH];
1310 DWORD dwError;
1311 HKEY hKey;
1312 ULONG i;
1313
1314 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1315 ServiceEntry = ServiceListHead.Flink;
1316 while (ServiceEntry != &ServiceListHead)
1317 {
1318 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1319
1320 /* Build the safe boot path */
1321 wcscpy(szSafeBootServicePath,
1322 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1323
1324 switch (GetSystemMetrics(SM_CLEANBOOT))
1325 {
1326 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1327 case 1:
1328 case 3:
1329 wcscat(szSafeBootServicePath, L"\\Minimal\\");
1330 break;
1331
1332 case 2:
1333 wcscat(szSafeBootServicePath, L"\\Network\\");
1334 break;
1335 }
1336
1337 if (GetSystemMetrics(SM_CLEANBOOT))
1338 {
1339 /* If key does not exist then do not assume safe mode */
1340 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1341 szSafeBootServicePath,
1342 0,
1343 KEY_READ,
1344 &hKey);
1345 if (dwError == ERROR_SUCCESS)
1346 {
1347 RegCloseKey(hKey);
1348
1349 /* Finish Safe Boot path off */
1350 wcsncat(szSafeBootServicePath,
1351 CurrentService->lpServiceName,
1352 MAX_PATH - wcslen(szSafeBootServicePath));
1353
1354 /* Check that the key is in the Safe Boot path */
1355 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1356 szSafeBootServicePath,
1357 0,
1358 KEY_READ,
1359 &hKey);
1360 if (dwError != ERROR_SUCCESS)
1361 {
1362 /* Mark service as visited so it is not auto-started */
1363 CurrentService->ServiceVisited = TRUE;
1364 }
1365 else
1366 {
1367 /* Must be auto-started in safe mode - mark as unvisited */
1368 RegCloseKey(hKey);
1369 CurrentService->ServiceVisited = FALSE;
1370 }
1371 }
1372 else
1373 {
1374 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1375 CurrentService->ServiceVisited = FALSE;
1376 }
1377 }
1378
1379 ServiceEntry = ServiceEntry->Flink;
1380 }
1381
1382 /* Start all services which are members of an existing group */
1383 GroupEntry = GroupListHead.Flink;
1384 while (GroupEntry != &GroupListHead)
1385 {
1386 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1387
1388 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
1389
1390 /* Start all services witch have a valid tag */
1391 for (i = 0; i < CurrentGroup->TagCount; i++)
1392 {
1393 ServiceEntry = ServiceListHead.Flink;
1394 while (ServiceEntry != &ServiceListHead)
1395 {
1396 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1397
1398 if ((CurrentService->lpGroup == CurrentGroup) &&
1399 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1400 (CurrentService->ServiceVisited == FALSE) &&
1401 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
1402 {
1403 CurrentService->ServiceVisited = TRUE;
1404 ScmStartService(CurrentService, 0, NULL);
1405 }
1406
1407 ServiceEntry = ServiceEntry->Flink;
1408 }
1409 }
1410
1411 /* Start all services which have an invalid tag or which do not have a tag */
1412 ServiceEntry = ServiceListHead.Flink;
1413 while (ServiceEntry != &ServiceListHead)
1414 {
1415 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1416
1417 if ((CurrentService->lpGroup == CurrentGroup) &&
1418 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1419 (CurrentService->ServiceVisited == FALSE))
1420 {
1421 CurrentService->ServiceVisited = TRUE;
1422 ScmStartService(CurrentService, 0, NULL);
1423 }
1424
1425 ServiceEntry = ServiceEntry->Flink;
1426 }
1427
1428 GroupEntry = GroupEntry->Flink;
1429 }
1430
1431 /* Start all services which are members of any non-existing group */
1432 ServiceEntry = ServiceListHead.Flink;
1433 while (ServiceEntry != &ServiceListHead)
1434 {
1435 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1436
1437 if ((CurrentService->lpGroup != NULL) &&
1438 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1439 (CurrentService->ServiceVisited == FALSE))
1440 {
1441 CurrentService->ServiceVisited = TRUE;
1442 ScmStartService(CurrentService, 0, NULL);
1443 }
1444
1445 ServiceEntry = ServiceEntry->Flink;
1446 }
1447
1448 /* Start all services which are not a member of any group */
1449 ServiceEntry = ServiceListHead.Flink;
1450 while (ServiceEntry != &ServiceListHead)
1451 {
1452 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1453
1454 if ((CurrentService->lpGroup == NULL) &&
1455 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1456 (CurrentService->ServiceVisited == FALSE))
1457 {
1458 CurrentService->ServiceVisited = TRUE;
1459 ScmStartService(CurrentService, 0, NULL);
1460 }
1461
1462 ServiceEntry = ServiceEntry->Flink;
1463 }
1464
1465 /* Clear 'ServiceVisited' flag again */
1466 ServiceEntry = ServiceListHead.Flink;
1467 while (ServiceEntry != &ServiceListHead)
1468 {
1469 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1470 CurrentService->ServiceVisited = FALSE;
1471 ServiceEntry = ServiceEntry->Flink;
1472 }
1473 }
1474
1475
1476 VOID
1477 ScmAutoShutdownServices(VOID)
1478 {
1479 PLIST_ENTRY ServiceEntry;
1480 PSERVICE CurrentService;
1481
1482 DPRINT("ScmAutoShutdownServices() called\n");
1483
1484 /* Lock the service database exclusively */
1485 ScmLockDatabaseExclusive();
1486
1487 ServiceEntry = ServiceListHead.Flink;
1488 while (ServiceEntry != &ServiceListHead)
1489 {
1490 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1491
1492 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1493 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1494 {
1495 /* shutdown service */
1496 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
1497 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
1498 }
1499
1500 ServiceEntry = ServiceEntry->Flink;
1501 }
1502
1503 /* Unlock the service database */
1504 ScmUnlockDatabase();
1505
1506 DPRINT("ScmAutoShutdownServices() done\n");
1507 }
1508
1509
1510 BOOL
1511 ScmLockDatabaseExclusive(VOID)
1512 {
1513 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
1514 }
1515
1516
1517 BOOL
1518 ScmLockDatabaseShared(VOID)
1519 {
1520 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
1521 }
1522
1523
1524 VOID
1525 ScmUnlockDatabase(VOID)
1526 {
1527 RtlReleaseResource(&DatabaseLock);
1528 }
1529
1530
1531 VOID
1532 ScmInitNamedPipeCriticalSection(VOID)
1533 {
1534 InitializeCriticalSection(&ControlServiceCriticalSection);
1535 }
1536
1537
1538 VOID
1539 ScmDeleteNamedPipeCriticalSection(VOID)
1540 {
1541 DeleteCriticalSection(&ControlServiceCriticalSection);
1542 }
1543
1544 /* EOF */