1c5dd29fa556211f62934970935098aadafbfa6f
[reactos.git] / 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 TotalLength;
922 DWORD dwError = ERROR_SUCCESS;
923
924 DPRINT("ScmControlService() called\n");
925
926 EnterCriticalSection(&ControlServiceCriticalSection);
927
928 TotalLength = wcslen(Service->lpServiceName) + 1;
929
930 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
931 HEAP_ZERO_MEMORY,
932 sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)));
933 if (ControlPacket == NULL)
934 {
935 LeaveCriticalSection(&ControlServiceCriticalSection);
936 return ERROR_NOT_ENOUGH_MEMORY;
937 }
938
939 ControlPacket->dwControl = dwControl;
940 ControlPacket->dwSize = TotalLength;
941 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
942 wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
943
944 /* Send the control packet */
945 WriteFile(Service->lpImage->hControlPipe,
946 ControlPacket,
947 sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)),
948 &dwWriteCount,
949 NULL);
950
951 /* Read the reply */
952 ReadFile(Service->lpImage->hControlPipe,
953 &ReplyPacket,
954 sizeof(SCM_REPLY_PACKET),
955 &dwReadCount,
956 NULL);
957
958 /* Release the contol packet */
959 HeapFree(GetProcessHeap(),
960 0,
961 ControlPacket);
962
963 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
964 {
965 dwError = ReplyPacket.dwError;
966 }
967
968 if (dwError == ERROR_SUCCESS &&
969 dwControl == SERVICE_CONTROL_STOP)
970 {
971 ScmDereferenceServiceImage(Service->lpImage);
972 }
973
974 LeaveCriticalSection(&ControlServiceCriticalSection);
975
976 DPRINT("ScmControlService() done\n");
977
978 return dwError;
979 }
980
981
982 static DWORD
983 ScmSendStartCommand(PSERVICE Service,
984 DWORD argc,
985 LPWSTR *argv)
986 {
987 PSCM_CONTROL_PACKET ControlPacket;
988 SCM_REPLY_PACKET ReplyPacket;
989 DWORD TotalLength;
990 DWORD ArgsLength = 0;
991 DWORD Length;
992 PWSTR Ptr;
993 DWORD dwWriteCount = 0;
994 DWORD dwReadCount = 0;
995 DWORD dwError = ERROR_SUCCESS;
996 DWORD i;
997
998 DPRINT("ScmSendStartCommand() called\n");
999
1000 /* Calculate the total length of the start command line */
1001 TotalLength = wcslen(Service->lpServiceName) + 1;
1002 if (argc > 0)
1003 {
1004 for (i = 0; i < argc; i++)
1005 {
1006 DPRINT("Arg: %S\n", argv[i]);
1007 Length = wcslen(argv[i]) + 1;
1008 TotalLength += Length;
1009 ArgsLength += Length;
1010 }
1011 }
1012 TotalLength++;
1013 DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength, TotalLength);
1014
1015 /* Allocate a control packet */
1016 ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
1017 HEAP_ZERO_MEMORY,
1018 sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
1019 if (ControlPacket == NULL)
1020 return ERROR_NOT_ENOUGH_MEMORY;
1021
1022 ControlPacket->dwControl = SERVICE_CONTROL_START;
1023 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
1024 ControlPacket->dwSize = TotalLength;
1025 Ptr = &ControlPacket->szArguments[0];
1026 wcscpy(Ptr, Service->lpServiceName);
1027 Ptr += (wcslen(Service->lpServiceName) + 1);
1028
1029 /* Copy argument list */
1030 if (argc > 0)
1031 {
1032 UNIMPLEMENTED;
1033 DPRINT1("Arguments sent to service ignored!\n");
1034 #if 0
1035 memcpy(Ptr, Arguments, ArgsLength);
1036 Ptr += ArgsLength;
1037 #endif
1038 }
1039
1040 /* Terminate the argument list */
1041 *Ptr = 0;
1042
1043 /* Send the start command */
1044 WriteFile(Service->lpImage->hControlPipe,
1045 ControlPacket,
1046 sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
1047 &dwWriteCount,
1048 NULL);
1049
1050 /* Read the reply */
1051 ReadFile(Service->lpImage->hControlPipe,
1052 &ReplyPacket,
1053 sizeof(SCM_REPLY_PACKET),
1054 &dwReadCount,
1055 NULL);
1056
1057 /* Release the contol packet */
1058 HeapFree(GetProcessHeap(),
1059 0,
1060 ControlPacket);
1061
1062 if (dwReadCount == sizeof(SCM_REPLY_PACKET))
1063 {
1064 dwError = ReplyPacket.dwError;
1065 }
1066
1067 DPRINT("ScmSendStartCommand() done\n");
1068
1069 return dwError;
1070 }
1071
1072
1073 static DWORD
1074 ScmStartUserModeService(PSERVICE Service,
1075 DWORD argc,
1076 LPWSTR *argv)
1077 {
1078 PROCESS_INFORMATION ProcessInformation;
1079 STARTUPINFOW StartupInfo;
1080 BOOL Result;
1081 DWORD dwError = ERROR_SUCCESS;
1082 DWORD dwProcessId;
1083
1084 DPRINT("ScmStartUserModeService(%p)\n", Service);
1085
1086 /* If the image is already running ... */
1087 if (Service->lpImage->dwImageRunCount > 1)
1088 {
1089 /* ... just send a start command */
1090 return ScmSendStartCommand(Service, argc, argv);
1091 }
1092
1093 StartupInfo.cb = sizeof(StartupInfo);
1094 StartupInfo.lpReserved = NULL;
1095 StartupInfo.lpDesktop = NULL;
1096 StartupInfo.lpTitle = NULL;
1097 StartupInfo.dwFlags = 0;
1098 StartupInfo.cbReserved2 = 0;
1099 StartupInfo.lpReserved2 = 0;
1100
1101 Result = CreateProcessW(NULL,
1102 Service->lpImage->szImagePath,
1103 NULL,
1104 NULL,
1105 FALSE,
1106 DETACHED_PROCESS | CREATE_SUSPENDED,
1107 NULL,
1108 NULL,
1109 &StartupInfo,
1110 &ProcessInformation);
1111 if (!Result)
1112 {
1113 dwError = GetLastError();
1114 DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
1115 return dwError;
1116 }
1117
1118 DPRINT("Process Id: %lu Handle %lx\n",
1119 ProcessInformation.dwProcessId,
1120 ProcessInformation.hProcess);
1121 DPRINT("Thread Id: %lu Handle %lx\n",
1122 ProcessInformation.dwThreadId,
1123 ProcessInformation.hThread);
1124
1125 /* Get process handle and id */
1126 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
1127 Service->lpImage->hProcess = ProcessInformation.hProcess;
1128
1129 /* Resume Thread */
1130 ResumeThread(ProcessInformation.hThread);
1131
1132 /* Connect control pipe */
1133 if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
1134 TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
1135 {
1136 DWORD dwRead = 0;
1137
1138 DPRINT("Control pipe connected!\n");
1139
1140 /* Read SERVICE_STATUS_HANDLE from pipe */
1141 if (!ReadFile(Service->lpImage->hControlPipe,
1142 (LPVOID)&dwProcessId,
1143 sizeof(DWORD),
1144 &dwRead,
1145 NULL))
1146 {
1147 dwError = GetLastError();
1148 DPRINT1("Reading the service control pipe failed (Error %lu)\n",
1149 dwError);
1150 }
1151 else
1152 {
1153 DPRINT("Received service process ID %lu\n", dwProcessId);
1154
1155 /* Send start command */
1156 dwError = ScmSendStartCommand(Service, argc, argv);
1157 }
1158 }
1159 else
1160 {
1161 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
1162 }
1163
1164 /* Close thread handle */
1165 CloseHandle(ProcessInformation.hThread);
1166
1167 return dwError;
1168 }
1169
1170
1171 DWORD
1172 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
1173 {
1174 PSERVICE_GROUP Group = Service->lpGroup;
1175 DWORD dwError = ERROR_SUCCESS;
1176 LPCWSTR ErrorLogStrings[2];
1177
1178 DPRINT("ScmStartService() called\n");
1179
1180 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
1181
1182 EnterCriticalSection(&ControlServiceCriticalSection);
1183
1184 if (Service->Status.dwCurrentState != SERVICE_STOPPED)
1185 {
1186 DPRINT("Service %S is already running!\n", Service->lpServiceName);
1187 LeaveCriticalSection(&ControlServiceCriticalSection);
1188 return ERROR_SERVICE_ALREADY_RUNNING;
1189 }
1190
1191 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
1192
1193 if (Service->Status.dwServiceType & SERVICE_DRIVER)
1194 {
1195 /* Load driver */
1196 dwError = ScmLoadDriver(Service);
1197 if (dwError == ERROR_SUCCESS)
1198 {
1199 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
1200 Service->Status.dwCurrentState = SERVICE_RUNNING;
1201 }
1202 }
1203 else
1204 {
1205 /* Start user-mode service */
1206 dwError = ScmCreateOrReferenceServiceImage(Service);
1207 if (dwError == ERROR_SUCCESS)
1208 {
1209 dwError = ScmStartUserModeService(Service, argc, argv);
1210 if (dwError == ERROR_SUCCESS)
1211 {
1212 #ifdef USE_SERVICE_START_PENDING
1213 Service->Status.dwCurrentState = SERVICE_START_PENDING;
1214 #else
1215 Service->Status.dwCurrentState = SERVICE_RUNNING;
1216 #endif
1217 }
1218 else
1219 {
1220 ScmDereferenceServiceImage(Service->lpImage);
1221 Service->lpImage = NULL;
1222 }
1223 }
1224 }
1225
1226 LeaveCriticalSection(&ControlServiceCriticalSection);
1227
1228 DPRINT("ScmStartService() done (Error %lu)\n", dwError);
1229
1230 if (dwError == ERROR_SUCCESS)
1231 {
1232 if (Group != NULL)
1233 {
1234 Group->ServicesRunning = TRUE;
1235 }
1236 }
1237 else
1238 {
1239 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
1240 {
1241 ErrorLogStrings[0] = Service->lpServiceName;
1242 ErrorLogStrings[1] = L"Test";
1243 ScmLogError(EVENT_SERVICE_START_FAILED,
1244 2,
1245 ErrorLogStrings);
1246 }
1247
1248 #if 0
1249 switch (Service->dwErrorControl)
1250 {
1251 case SERVICE_ERROR_SEVERE:
1252 if (IsLastKnownGood == FALSE)
1253 {
1254 /* FIXME: Boot last known good configuration */
1255 }
1256 break;
1257
1258 case SERVICE_ERROR_CRITICAL:
1259 if (IsLastKnownGood == FALSE)
1260 {
1261 /* FIXME: Boot last known good configuration */
1262 }
1263 else
1264 {
1265 /* FIXME: BSOD! */
1266 }
1267 break;
1268 }
1269 #endif
1270 }
1271
1272 return dwError;
1273 }
1274
1275
1276 VOID
1277 ScmAutoStartServices(VOID)
1278 {
1279 PLIST_ENTRY GroupEntry;
1280 PLIST_ENTRY ServiceEntry;
1281 PSERVICE_GROUP CurrentGroup;
1282 PSERVICE CurrentService;
1283 WCHAR szSafeBootServicePath[MAX_PATH];
1284 DWORD dwError;
1285 HKEY hKey;
1286 ULONG i;
1287
1288 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
1289 ServiceEntry = ServiceListHead.Flink;
1290 while (ServiceEntry != &ServiceListHead)
1291 {
1292 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1293 /* Build the safe boot path */
1294 wcscpy(szSafeBootServicePath,
1295 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
1296 switch(GetSystemMetrics(SM_CLEANBOOT))
1297 {
1298 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
1299 case 1:
1300 case 3: wcscat(szSafeBootServicePath, L"\\Minimal\\"); break;
1301 case 2: wcscat(szSafeBootServicePath, L"\\Network\\"); break;
1302 }
1303 if(GetSystemMetrics(SM_CLEANBOOT))
1304 {
1305 /* If key does not exist then do not assume safe mode */
1306 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1307 szSafeBootServicePath,
1308 0,
1309 KEY_READ,
1310 &hKey);
1311 if(dwError == ERROR_SUCCESS)
1312 {
1313 RegCloseKey(hKey);
1314 /* Finish Safe Boot path off */
1315 wcsncat(szSafeBootServicePath,
1316 CurrentService->lpServiceName,
1317 MAX_PATH - wcslen(szSafeBootServicePath));
1318 /* Check that the key is in the Safe Boot path */
1319 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1320 szSafeBootServicePath,
1321 0,
1322 KEY_READ,
1323 &hKey);
1324 if(dwError != ERROR_SUCCESS)
1325 {
1326 /* Mark service as visited so it is not auto-started */
1327 CurrentService->ServiceVisited = TRUE;
1328 }
1329 else
1330 {
1331 /* Must be auto-started in safe mode - mark as unvisited */
1332 RegCloseKey(hKey);
1333 CurrentService->ServiceVisited = FALSE;
1334 }
1335 }
1336 else
1337 {
1338 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
1339 CurrentService->ServiceVisited = FALSE;
1340 }
1341 }
1342 ServiceEntry = ServiceEntry->Flink;
1343 }
1344
1345 /* Start all services which are members of an existing group */
1346 GroupEntry = GroupListHead.Flink;
1347 while (GroupEntry != &GroupListHead)
1348 {
1349 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
1350
1351 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
1352
1353 /* Start all services witch have a valid tag */
1354 for (i = 0; i < CurrentGroup->TagCount; i++)
1355 {
1356 ServiceEntry = ServiceListHead.Flink;
1357 while (ServiceEntry != &ServiceListHead)
1358 {
1359 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1360
1361 if ((CurrentService->lpGroup == CurrentGroup) &&
1362 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1363 (CurrentService->ServiceVisited == FALSE) &&
1364 (CurrentService->dwTag == CurrentGroup->TagArray[i]))
1365 {
1366 CurrentService->ServiceVisited = TRUE;
1367 ScmStartService(CurrentService, 0, NULL);
1368 }
1369
1370 ServiceEntry = ServiceEntry->Flink;
1371 }
1372 }
1373
1374 /* Start all services which have an invalid tag or which do not have a tag */
1375 ServiceEntry = ServiceListHead.Flink;
1376 while (ServiceEntry != &ServiceListHead)
1377 {
1378 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1379
1380 if ((CurrentService->lpGroup == CurrentGroup) &&
1381 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1382 (CurrentService->ServiceVisited == FALSE))
1383 {
1384 CurrentService->ServiceVisited = TRUE;
1385 ScmStartService(CurrentService, 0, NULL);
1386 }
1387
1388 ServiceEntry = ServiceEntry->Flink;
1389 }
1390
1391 GroupEntry = GroupEntry->Flink;
1392 }
1393
1394 /* Start all services which are members of any non-existing group */
1395 ServiceEntry = ServiceListHead.Flink;
1396 while (ServiceEntry != &ServiceListHead)
1397 {
1398 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1399
1400 if ((CurrentService->lpGroup != NULL) &&
1401 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
1402 (CurrentService->ServiceVisited == FALSE))
1403 {
1404 CurrentService->ServiceVisited = TRUE;
1405 ScmStartService(CurrentService, 0, NULL);
1406 }
1407
1408 ServiceEntry = ServiceEntry->Flink;
1409 }
1410
1411 /* Start all services which are not a member of any group */
1412 ServiceEntry = ServiceListHead.Flink;
1413 while (ServiceEntry != &ServiceListHead)
1414 {
1415 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1416
1417 if ((CurrentService->lpGroup == NULL) &&
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 /* Clear 'ServiceVisited' flag again */
1429 ServiceEntry = ServiceListHead.Flink;
1430 while (ServiceEntry != &ServiceListHead)
1431 {
1432 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1433 CurrentService->ServiceVisited = FALSE;
1434 ServiceEntry = ServiceEntry->Flink;
1435 }
1436 }
1437
1438
1439 VOID
1440 ScmAutoShutdownServices(VOID)
1441 {
1442 PLIST_ENTRY ServiceEntry;
1443 PSERVICE CurrentService;
1444
1445 DPRINT("ScmAutoShutdownServices() called\n");
1446
1447 /* Lock the service database exclusively */
1448 ScmLockDatabaseExclusive();
1449
1450 ServiceEntry = ServiceListHead.Flink;
1451 while (ServiceEntry != &ServiceListHead)
1452 {
1453 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
1454
1455 if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
1456 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
1457 {
1458 /* shutdown service */
1459 DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
1460 ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
1461 }
1462
1463 ServiceEntry = ServiceEntry->Flink;
1464 }
1465
1466 /* Unlock the service database */
1467 ScmUnlockDatabase();
1468
1469 DPRINT("ScmAutoShutdownServices() done\n");
1470 }
1471
1472
1473 BOOL
1474 ScmLockDatabaseExclusive(VOID)
1475 {
1476 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
1477 }
1478
1479
1480 BOOL
1481 ScmLockDatabaseShared(VOID)
1482 {
1483 return RtlAcquireResourceShared(&DatabaseLock, TRUE);
1484 }
1485
1486
1487 VOID
1488 ScmUnlockDatabase(VOID)
1489 {
1490 RtlReleaseResource(&DatabaseLock);
1491 }
1492
1493
1494 VOID
1495 ScmInitNamedPipeCriticalSection(VOID)
1496 {
1497 InitializeCriticalSection(&ControlServiceCriticalSection);
1498 }
1499
1500
1501 VOID
1502 ScmDeleteNamedPipeCriticalSection(VOID)
1503 {
1504 DeleteCriticalSection(&ControlServiceCriticalSection);
1505 }
1506
1507 /* EOF */