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