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