ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

database.c
Go to the documentation of this file.
00001 /*
00002  * PROJECT:     ReactOS Service Control Manager
00003  * LICENSE:     GPL - See COPYING in the top level directory
00004  * FILE:        base/system/services/database.c
00005  * PURPOSE:     Database control interface
00006  * COPYRIGHT:   Copyright 2002-2006 Eric Kohl
00007  *              Copyright 2006 Hervé Poussineau <hpoussin@reactos.org>
00008  *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
00009  *                             Gregor Brunmar <gregor.brunmar@home.se>
00010  *
00011  */
00012 
00013 /* INCLUDES *****************************************************************/
00014 
00015 #include "services.h"
00016 
00017 #define NDEBUG
00018 #include <debug.h>
00019 
00020 /*
00021  * Uncomment the line below to start services
00022  *  using the SERVICE_START_PENDING state
00023  */
00024 // #define USE_SERVICE_START_PENDING
00025 
00026 /*
00027  * Uncomment the line below to use asynchronous IO operations
00028  * on the service control pipes.
00029  */
00030 // #define USE_ASYNCHRONOUS_IO
00031 
00032 
00033 /* GLOBALS *******************************************************************/
00034 
00035 LIST_ENTRY ImageListHead;
00036 LIST_ENTRY ServiceListHead;
00037 
00038 static RTL_RESOURCE DatabaseLock;
00039 static DWORD dwResumeCount = 1;
00040 
00041 static CRITICAL_SECTION ControlServiceCriticalSection;
00042 static DWORD dwPipeTimeout = 30000; /* 30 Seconds */
00043 
00044 
00045 /* FUNCTIONS *****************************************************************/
00046 
00047 static DWORD
00048 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
00049 {
00050     WCHAR szControlPipeName[MAX_PATH + 1];
00051     HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
00052     DWORD ServiceCurrent = 0;
00053     DWORD KeyDisposition;
00054     DWORD dwKeySize;
00055     DWORD dwError;
00056 
00057     /* Get the service number */
00058     /* TODO: Create registry entry with correct write access */
00059     dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
00060                               L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
00061                               REG_OPTION_VOLATILE,
00062                               KEY_WRITE | KEY_READ,
00063                               NULL,
00064                               &hServiceCurrentKey,
00065                               &KeyDisposition);
00066     if (dwError != ERROR_SUCCESS)
00067     {
00068         DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
00069         return dwError;
00070     }
00071 
00072     if (KeyDisposition == REG_OPENED_EXISTING_KEY)
00073     {
00074         dwKeySize = sizeof(DWORD);
00075         dwError = RegQueryValueExW(hServiceCurrentKey,
00076                                    L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
00077 
00078         if (dwError != ERROR_SUCCESS)
00079         {
00080             RegCloseKey(hServiceCurrentKey);
00081             DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
00082             return dwError;
00083         }
00084 
00085         ServiceCurrent++;
00086     }
00087 
00088     dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
00089 
00090     RegCloseKey(hServiceCurrentKey);
00091 
00092     if (dwError != ERROR_SUCCESS)
00093     {
00094         DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
00095         return dwError;
00096     }
00097 
00098     /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
00099     swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
00100 
00101     DPRINT("PipeName: %S\n", szControlPipeName);
00102 
00103     pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
00104 #ifdef USE_ASYNCHRONOUS_IO
00105                                                    PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
00106 #else
00107                                                    PIPE_ACCESS_DUPLEX,
00108 #endif
00109                                                    PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
00110                                                    100,
00111                                                    8000,
00112                                                    4,
00113                                                    dwPipeTimeout,
00114                                                    NULL);
00115     DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
00116     if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
00117     {
00118         DPRINT1("Failed to create control pipe!\n");
00119         return GetLastError();
00120     }
00121 
00122     return ERROR_SUCCESS;
00123 }
00124 
00125 
00126 static PSERVICE_IMAGE
00127 ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
00128 {
00129     PLIST_ENTRY ImageEntry;
00130     PSERVICE_IMAGE CurrentImage;
00131 
00132     DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath);
00133 
00134     ImageEntry = ImageListHead.Flink;
00135     while (ImageEntry != &ImageListHead)
00136     {
00137         CurrentImage = CONTAINING_RECORD(ImageEntry,
00138                                          SERVICE_IMAGE,
00139                                          ImageListEntry);
00140         if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0)
00141         {
00142             DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
00143             return CurrentImage;
00144         }
00145 
00146         ImageEntry = ImageEntry->Flink;
00147     }
00148 
00149     DPRINT("Couldn't find a matching image\n");
00150 
00151     return NULL;
00152 
00153 }
00154 
00155 
00156 static DWORD
00157 ScmCreateOrReferenceServiceImage(PSERVICE pService)
00158 {
00159     RTL_QUERY_REGISTRY_TABLE QueryTable[2];
00160     UNICODE_STRING ImagePath;
00161     PSERVICE_IMAGE pServiceImage = NULL;
00162     NTSTATUS Status;
00163     DWORD dwError = ERROR_SUCCESS;
00164 
00165     DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
00166 
00167     RtlInitUnicodeString(&ImagePath, NULL);
00168 
00169     /* Get service data */
00170     RtlZeroMemory(&QueryTable,
00171                   sizeof(QueryTable));
00172 
00173     QueryTable[0].Name = L"ImagePath";
00174     QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
00175     QueryTable[0].EntryContext = &ImagePath;
00176 
00177     Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
00178                                     pService->lpServiceName,
00179                                     QueryTable,
00180                                     NULL,
00181                                     NULL);
00182     if (!NT_SUCCESS(Status))
00183     {
00184         DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
00185         return RtlNtStatusToDosError(Status);
00186     }
00187 
00188     DPRINT("ImagePath: '%wZ'\n", &ImagePath);
00189 
00190     pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
00191     if (pServiceImage == NULL)
00192     {
00193         /* Create a new service image */
00194         pServiceImage = HeapAlloc(GetProcessHeap(),
00195                                   HEAP_ZERO_MEMORY,
00196                                   FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1]));
00197         if (pServiceImage == NULL)
00198         {
00199             dwError = ERROR_NOT_ENOUGH_MEMORY;
00200             goto done;
00201         }
00202 
00203         pServiceImage->dwImageRunCount = 1;
00204         pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
00205 
00206         /* Set the image path */
00207         wcscpy(pServiceImage->szImagePath,
00208                ImagePath.Buffer);
00209 
00210         RtlFreeUnicodeString(&ImagePath);
00211 
00212         /* Create the control pipe */
00213         dwError = ScmCreateNewControlPipe(pServiceImage);
00214         if (dwError != ERROR_SUCCESS)
00215         {
00216             HeapFree(GetProcessHeap(), 0, pServiceImage);
00217             goto done;
00218         }
00219 
00220         /* FIXME: Add more initialization code here */
00221 
00222 
00223         /* Append service record */
00224         InsertTailList(&ImageListHead,
00225                        &pServiceImage->ImageListEntry);
00226     }
00227     else
00228     {
00229         /* Increment the run counter */
00230         pServiceImage->dwImageRunCount++;
00231     }
00232 
00233     DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
00234 
00235     /* Link the service image to the service */
00236     pService->lpImage = pServiceImage;
00237 
00238 done:;
00239     RtlFreeUnicodeString(&ImagePath);
00240 
00241     DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
00242 
00243     return dwError;
00244 }
00245 
00246 
00247 static VOID
00248 ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
00249 {
00250     DPRINT1("ScmDereferenceServiceImage() called\n");
00251 
00252     pServiceImage->dwImageRunCount--;
00253 
00254     if (pServiceImage->dwImageRunCount == 0)
00255     {
00256         DPRINT1("dwImageRunCount == 0\n");
00257 
00258         /* FIXME: Terminate the process */
00259 
00260         /* Remove the service image from the list */
00261         RemoveEntryList(&pServiceImage->ImageListEntry);
00262 
00263         /* Close the control pipe */
00264         if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
00265             CloseHandle(pServiceImage->hControlPipe);
00266 
00267         /* Release the service image */
00268         HeapFree(GetProcessHeap(), 0, pServiceImage);
00269     }
00270 }
00271 
00272 
00273 PSERVICE
00274 ScmGetServiceEntryByName(LPCWSTR lpServiceName)
00275 {
00276     PLIST_ENTRY ServiceEntry;
00277     PSERVICE CurrentService;
00278 
00279     DPRINT("ScmGetServiceEntryByName() called\n");
00280 
00281     ServiceEntry = ServiceListHead.Flink;
00282     while (ServiceEntry != &ServiceListHead)
00283     {
00284         CurrentService = CONTAINING_RECORD(ServiceEntry,
00285                                            SERVICE,
00286                                            ServiceListEntry);
00287         if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
00288         {
00289             DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
00290             return CurrentService;
00291         }
00292 
00293         ServiceEntry = ServiceEntry->Flink;
00294     }
00295 
00296     DPRINT("Couldn't find a matching service\n");
00297 
00298     return NULL;
00299 }
00300 
00301 
00302 PSERVICE
00303 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName)
00304 {
00305     PLIST_ENTRY ServiceEntry;
00306     PSERVICE CurrentService;
00307 
00308     DPRINT("ScmGetServiceEntryByDisplayName() called\n");
00309 
00310     ServiceEntry = ServiceListHead.Flink;
00311     while (ServiceEntry != &ServiceListHead)
00312     {
00313         CurrentService = CONTAINING_RECORD(ServiceEntry,
00314                                            SERVICE,
00315                                            ServiceListEntry);
00316         if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
00317         {
00318             DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
00319             return CurrentService;
00320         }
00321 
00322         ServiceEntry = ServiceEntry->Flink;
00323     }
00324 
00325     DPRINT("Couldn't find a matching service\n");
00326 
00327     return NULL;
00328 }
00329 
00330 
00331 PSERVICE
00332 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
00333 {
00334     PLIST_ENTRY ServiceEntry;
00335     PSERVICE CurrentService;
00336 
00337     DPRINT("ScmGetServiceEntryByResumeCount() called\n");
00338 
00339     ServiceEntry = ServiceListHead.Flink;
00340     while (ServiceEntry != &ServiceListHead)
00341     {
00342         CurrentService = CONTAINING_RECORD(ServiceEntry,
00343                                            SERVICE,
00344                                            ServiceListEntry);
00345         if (CurrentService->dwResumeCount > dwResumeCount)
00346         {
00347             DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
00348             return CurrentService;
00349         }
00350 
00351         ServiceEntry = ServiceEntry->Flink;
00352     }
00353 
00354     DPRINT("Couldn't find a matching service\n");
00355 
00356     return NULL;
00357 }
00358 
00359 
00360 DWORD
00361 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
00362                           PSERVICE *lpServiceRecord)
00363 {
00364     PSERVICE lpService = NULL;
00365 
00366     DPRINT("Service: '%S'\n", lpServiceName);
00367 
00368     /* Allocate service entry */
00369     lpService = HeapAlloc(GetProcessHeap(),
00370                           HEAP_ZERO_MEMORY,
00371                           FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1]));
00372     if (lpService == NULL)
00373         return ERROR_NOT_ENOUGH_MEMORY;
00374 
00375     *lpServiceRecord = lpService;
00376 
00377     /* Copy service name */
00378     wcscpy(lpService->szServiceName, lpServiceName);
00379     lpService->lpServiceName = lpService->szServiceName;
00380     lpService->lpDisplayName = lpService->lpServiceName;
00381 
00382     /* Set the resume count */
00383     lpService->dwResumeCount = dwResumeCount++;
00384 
00385     /* Append service record */
00386     InsertTailList(&ServiceListHead,
00387                    &lpService->ServiceListEntry);
00388 
00389     /* Initialize the service status */
00390     lpService->Status.dwCurrentState = SERVICE_STOPPED;
00391     lpService->Status.dwControlsAccepted = 0;
00392     lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
00393     lpService->Status.dwServiceSpecificExitCode = 0;
00394     lpService->Status.dwCheckPoint = 0;
00395     lpService->Status.dwWaitHint = 2000; /* 2 seconds */
00396 
00397     return ERROR_SUCCESS;
00398 }
00399 
00400 
00401 VOID
00402 ScmDeleteServiceRecord(PSERVICE lpService)
00403 {
00404     DPRINT("Deleting Service %S\n", lpService->lpServiceName);
00405 
00406     /* Delete the display name */
00407     if (lpService->lpDisplayName != NULL &&
00408         lpService->lpDisplayName != lpService->lpServiceName)
00409         HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
00410 
00411     /* Dereference the service image */
00412     if (lpService->lpImage)
00413         ScmDereferenceServiceImage(lpService->lpImage);
00414 
00415     /* Decrement the group reference counter */
00416     if (lpService->lpGroup)
00417         lpService->lpGroup->dwRefCount--;
00418 
00419     /* FIXME: SecurityDescriptor */
00420 
00421 
00422     /* Remove the Service from the List */
00423     RemoveEntryList(&lpService->ServiceListEntry);
00424 
00425     DPRINT("Deleted Service %S\n", lpService->lpServiceName);
00426 
00427     /* Delete the service record */
00428     HeapFree(GetProcessHeap(), 0, lpService);
00429 
00430     DPRINT("Done\n");
00431 }
00432 
00433 
00434 static DWORD
00435 CreateServiceListEntry(LPCWSTR lpServiceName,
00436                        HKEY hServiceKey)
00437 {
00438     PSERVICE lpService = NULL;
00439     LPWSTR lpDisplayName = NULL;
00440     LPWSTR lpGroup = NULL;
00441     DWORD dwSize;
00442     DWORD dwError;
00443     DWORD dwServiceType;
00444     DWORD dwStartType;
00445     DWORD dwErrorControl;
00446     DWORD dwTagId;
00447 
00448     DPRINT("Service: '%S'\n", lpServiceName);
00449     if (*lpServiceName == L'{')
00450         return ERROR_SUCCESS;
00451 
00452     dwSize = sizeof(DWORD);
00453     dwError = RegQueryValueExW(hServiceKey,
00454                                L"Type",
00455                                NULL,
00456                                NULL,
00457                                (LPBYTE)&dwServiceType,
00458                                &dwSize);
00459     if (dwError != ERROR_SUCCESS)
00460         return ERROR_SUCCESS;
00461 
00462     if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
00463         ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
00464         (dwServiceType != SERVICE_KERNEL_DRIVER) &&
00465         (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
00466         return ERROR_SUCCESS;
00467 
00468     DPRINT("Service type: %lx\n", dwServiceType);
00469 
00470     dwSize = sizeof(DWORD);
00471     dwError = RegQueryValueExW(hServiceKey,
00472                                L"Start",
00473                                NULL,
00474                                NULL,
00475                                (LPBYTE)&dwStartType,
00476                                &dwSize);
00477     if (dwError != ERROR_SUCCESS)
00478         return ERROR_SUCCESS;
00479 
00480     DPRINT("Start type: %lx\n", dwStartType);
00481 
00482     dwSize = sizeof(DWORD);
00483     dwError = RegQueryValueExW(hServiceKey,
00484                                L"ErrorControl",
00485                                NULL,
00486                                NULL,
00487                                (LPBYTE)&dwErrorControl,
00488                                &dwSize);
00489     if (dwError != ERROR_SUCCESS)
00490         return ERROR_SUCCESS;
00491 
00492     DPRINT("Error control: %lx\n", dwErrorControl);
00493 
00494     dwError = RegQueryValueExW(hServiceKey,
00495                                L"Tag",
00496                                NULL,
00497                                NULL,
00498                                (LPBYTE)&dwTagId,
00499                                &dwSize);
00500     if (dwError != ERROR_SUCCESS)
00501         dwTagId = 0;
00502 
00503     DPRINT("Tag: %lx\n", dwTagId);
00504 
00505     dwError = ScmReadString(hServiceKey,
00506                             L"Group",
00507                             &lpGroup);
00508     if (dwError != ERROR_SUCCESS)
00509         lpGroup = NULL;
00510 
00511     DPRINT("Group: %S\n", lpGroup);
00512 
00513     dwError = ScmReadString(hServiceKey,
00514                             L"DisplayName",
00515                             &lpDisplayName);
00516     if (dwError != ERROR_SUCCESS)
00517         lpDisplayName = NULL;
00518 
00519     DPRINT("Display name: %S\n", lpDisplayName);
00520 
00521     dwError = ScmCreateNewServiceRecord(lpServiceName,
00522                                         &lpService);
00523     if (dwError != ERROR_SUCCESS)
00524         goto done;
00525 
00526     lpService->Status.dwServiceType = dwServiceType;
00527     lpService->dwStartType = dwStartType;
00528     lpService->dwErrorControl = dwErrorControl;
00529     lpService->dwTag = dwTagId;
00530 
00531     if (lpGroup != NULL)
00532     {
00533         dwError = ScmSetServiceGroup(lpService, lpGroup);
00534         if (dwError != ERROR_SUCCESS)
00535             goto done;
00536     }
00537 
00538     if (lpDisplayName != NULL)
00539     {
00540         lpService->lpDisplayName = lpDisplayName;
00541         lpDisplayName = NULL;
00542     }
00543 
00544     DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
00545     if (lpService->lpGroup != NULL)
00546     {
00547         DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
00548     }
00549     DPRINT("Start %lx  Type %lx  Tag %lx  ErrorControl %lx\n",
00550            lpService->dwStartType,
00551            lpService->Status.dwServiceType,
00552            lpService->dwTag,
00553            lpService->dwErrorControl);
00554 
00555     if (ScmIsDeleteFlagSet(hServiceKey))
00556         lpService->bDeleted = TRUE;
00557 
00558 done:;
00559     if (lpGroup != NULL)
00560         HeapFree(GetProcessHeap(), 0, lpGroup);
00561 
00562     if (lpDisplayName != NULL)
00563         HeapFree(GetProcessHeap(), 0, lpDisplayName);
00564 
00565     if (lpService != NULL)
00566     {
00567         if (lpService->lpImage != NULL)
00568             ScmDereferenceServiceImage(lpService->lpImage);
00569     }
00570 
00571     return dwError;
00572 }
00573 
00574 
00575 DWORD
00576 ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
00577 {
00578     DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
00579     WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
00580     HKEY hSubKey = 0;
00581 
00582     dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
00583     if (!dwRet)
00584     {
00585         /* Find the maximum subkey length so that we can allocate a buffer */
00586         dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
00587                                  &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
00588         if (!dwRet)
00589         {
00590             dwMaxSubkeyLen++;
00591             if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR))
00592             {
00593                 /* Name too big: alloc a buffer for it */
00594                 lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen * sizeof(WCHAR));
00595             }
00596 
00597             if (!lpszName)
00598                 dwRet = ERROR_NOT_ENOUGH_MEMORY;
00599             else
00600             {
00601                 while (dwRet == ERROR_SUCCESS)
00602                 {
00603                     dwSize = dwMaxSubkeyLen;
00604                     dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
00605                     if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
00606                         dwRet = ScmDeleteRegKey(hSubKey, lpszName);
00607                 }
00608                 if (dwRet == ERROR_NO_MORE_ITEMS)
00609                     dwRet = ERROR_SUCCESS;
00610 
00611                 if (lpszName != szNameBuf)
00612                     HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
00613             }
00614         }
00615 
00616         RegCloseKey(hSubKey);
00617         if (!dwRet)
00618             dwRet = RegDeleteKeyW(hKey, lpszSubKey);
00619     }
00620     return dwRet;
00621 }
00622 
00623 
00624 VOID
00625 ScmDeleteMarkedServices(VOID)
00626 {
00627     PLIST_ENTRY ServiceEntry;
00628     PSERVICE CurrentService;
00629     HKEY hServicesKey;
00630     DWORD dwError;
00631 
00632     ServiceEntry = ServiceListHead.Flink;
00633     while (ServiceEntry != &ServiceListHead)
00634     {
00635         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
00636 
00637         ServiceEntry = ServiceEntry->Flink;
00638 
00639         if (CurrentService->bDeleted == TRUE)
00640         {
00641             dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
00642                                     L"System\\CurrentControlSet\\Services",
00643                                     0,
00644                                     DELETE,
00645                                     &hServicesKey);
00646             if (dwError == ERROR_SUCCESS)
00647             {
00648                 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
00649                 RegCloseKey(hServicesKey);
00650                 if (dwError == ERROR_SUCCESS)
00651                 {
00652                     RemoveEntryList(&CurrentService->ServiceListEntry);
00653                     HeapFree(GetProcessHeap(), 0, CurrentService);
00654                 }
00655             }
00656 
00657             if (dwError != ERROR_SUCCESS)
00658                 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
00659         }
00660     }
00661 }
00662 
00663 
00664 VOID
00665 WaitForLSA(VOID)
00666 {
00667     HANDLE hEvent;
00668     DWORD dwError;
00669 
00670     DPRINT("WaitForLSA() called\n");
00671 
00672     hEvent = CreateEventW(NULL,
00673                           TRUE,
00674                           FALSE,
00675                           L"LSA_RPC_SERVER_ACTIVE");
00676     if (hEvent == NULL)
00677     {
00678         dwError = GetLastError();
00679         DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
00680 
00681         if (dwError == ERROR_ALREADY_EXISTS)
00682         {
00683             hEvent = OpenEventW(SYNCHRONIZE,
00684                                 FALSE,
00685                                 L"LSA_RPC_SERVER_ACTIVE");
00686             if (hEvent != NULL)
00687             {
00688                DPRINT1("Could not open the notification event!\n");
00689                return;
00690             }
00691         }
00692     }
00693 
00694     DPRINT("Wait for LSA!\n");
00695     WaitForSingleObject(hEvent, INFINITE);
00696     DPRINT("LSA is available!\n");
00697 
00698     CloseHandle(hEvent);
00699 
00700     DPRINT("WaitForLSA() done\n");
00701 }
00702 
00703 
00704 DWORD
00705 ScmCreateServiceDatabase(VOID)
00706 {
00707     WCHAR szSubKey[MAX_PATH];
00708     HKEY hServicesKey;
00709     HKEY hServiceKey;
00710     DWORD dwSubKey;
00711     DWORD dwSubKeyLength;
00712     FILETIME ftLastChanged;
00713     DWORD dwError;
00714 
00715     DPRINT("ScmCreateServiceDatabase() called\n");
00716 
00717     dwError = ScmCreateGroupList();
00718     if (dwError != ERROR_SUCCESS)
00719         return dwError;
00720 
00721     /* Initialize basic variables */
00722     InitializeListHead(&ImageListHead);
00723     InitializeListHead(&ServiceListHead);
00724 
00725     /* Initialize the database lock */
00726     RtlInitializeResource(&DatabaseLock);
00727 
00728     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
00729                             L"System\\CurrentControlSet\\Services",
00730                             0,
00731                             KEY_READ,
00732                             &hServicesKey);
00733     if (dwError != ERROR_SUCCESS)
00734         return dwError;
00735 
00736     dwSubKey = 0;
00737     for (;;)
00738     {
00739         dwSubKeyLength = MAX_PATH;
00740         dwError = RegEnumKeyExW(hServicesKey,
00741                                 dwSubKey,
00742                                 szSubKey,
00743                                 &dwSubKeyLength,
00744                                 NULL,
00745                                 NULL,
00746                                 NULL,
00747                                 &ftLastChanged);
00748         if (dwError == ERROR_SUCCESS &&
00749             szSubKey[0] != L'{')
00750         {
00751             DPRINT("SubKeyName: '%S'\n", szSubKey);
00752 
00753             dwError = RegOpenKeyExW(hServicesKey,
00754                                     szSubKey,
00755                                     0,
00756                                     KEY_READ,
00757                                     &hServiceKey);
00758             if (dwError == ERROR_SUCCESS)
00759             {
00760                 dwError = CreateServiceListEntry(szSubKey,
00761                                                  hServiceKey);
00762 
00763                 RegCloseKey(hServiceKey);
00764             }
00765         }
00766 
00767         if (dwError != ERROR_SUCCESS)
00768             break;
00769 
00770         dwSubKey++;
00771     }
00772 
00773     RegCloseKey(hServicesKey);
00774 
00775     /* Wait for LSA */
00776     WaitForLSA();
00777 
00778     /* Delete services that are marked for delete */
00779     ScmDeleteMarkedServices();
00780 
00781     DPRINT("ScmCreateServiceDatabase() done\n");
00782 
00783     return ERROR_SUCCESS;
00784 }
00785 
00786 
00787 VOID
00788 ScmShutdownServiceDatabase(VOID)
00789 {
00790     DPRINT("ScmShutdownServiceDatabase() called\n");
00791 
00792     ScmDeleteMarkedServices();
00793     RtlDeleteResource(&DatabaseLock);
00794 
00795     DPRINT("ScmShutdownServiceDatabase() done\n");
00796 }
00797 
00798 
00799 static NTSTATUS
00800 ScmCheckDriver(PSERVICE Service)
00801 {
00802     OBJECT_ATTRIBUTES ObjectAttributes;
00803     UNICODE_STRING DirName;
00804     HANDLE DirHandle;
00805     NTSTATUS Status;
00806     POBJECT_DIRECTORY_INFORMATION DirInfo;
00807     ULONG BufferLength;
00808     ULONG DataLength;
00809     ULONG Index;
00810 
00811     DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
00812 
00813     if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
00814     {
00815         RtlInitUnicodeString(&DirName,
00816                              L"\\Driver");
00817     }
00818     else
00819     {
00820         RtlInitUnicodeString(&DirName,
00821                              L"\\FileSystem");
00822     }
00823 
00824     InitializeObjectAttributes(&ObjectAttributes,
00825                                &DirName,
00826                                0,
00827                                NULL,
00828                                NULL);
00829 
00830     Status = NtOpenDirectoryObject(&DirHandle,
00831                                    DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
00832                                    &ObjectAttributes);
00833     if (!NT_SUCCESS(Status))
00834     {
00835         return Status;
00836     }
00837 
00838     BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
00839                    2 * MAX_PATH * sizeof(WCHAR);
00840     DirInfo = HeapAlloc(GetProcessHeap(),
00841                         HEAP_ZERO_MEMORY,
00842                         BufferLength);
00843 
00844     Index = 0;
00845     while (TRUE)
00846     {
00847         Status = NtQueryDirectoryObject(DirHandle,
00848                                         DirInfo,
00849                                         BufferLength,
00850                                         TRUE,
00851                                         FALSE,
00852                                         &Index,
00853                                         &DataLength);
00854         if (Status == STATUS_NO_MORE_ENTRIES)
00855         {
00856             /* FIXME: Add current service to 'failed service' list */
00857             DPRINT("Service '%S' failed\n", Service->lpServiceName);
00858             break;
00859         }
00860 
00861         if (!NT_SUCCESS(Status))
00862             break;
00863 
00864         DPRINT("Comparing: '%S'  '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
00865 
00866         if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
00867         {
00868             DPRINT("Found: '%S'  '%wZ'\n",
00869                    Service->lpServiceName, &DirInfo->Name);
00870 
00871             /* Mark service as 'running' */
00872             Service->Status.dwCurrentState = SERVICE_RUNNING;
00873 
00874             /* Mark the service group as 'running' */
00875             if (Service->lpGroup != NULL)
00876             {
00877                 Service->lpGroup->ServicesRunning = TRUE;
00878             }
00879 
00880             break;
00881         }
00882     }
00883 
00884     HeapFree(GetProcessHeap(),
00885              0,
00886              DirInfo);
00887     NtClose(DirHandle);
00888 
00889     return STATUS_SUCCESS;
00890 }
00891 
00892 
00893 VOID
00894 ScmGetBootAndSystemDriverState(VOID)
00895 {
00896     PLIST_ENTRY ServiceEntry;
00897     PSERVICE CurrentService;
00898 
00899     DPRINT("ScmGetBootAndSystemDriverState() called\n");
00900 
00901     ServiceEntry = ServiceListHead.Flink;
00902     while (ServiceEntry != &ServiceListHead)
00903     {
00904         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
00905 
00906         if (CurrentService->dwStartType == SERVICE_BOOT_START ||
00907             CurrentService->dwStartType == SERVICE_SYSTEM_START)
00908         {
00909             /* Check driver */
00910             DPRINT("  Checking service: %S\n", CurrentService->lpServiceName);
00911 
00912             ScmCheckDriver(CurrentService);
00913         }
00914 
00915         ServiceEntry = ServiceEntry->Flink;
00916     }
00917 
00918     DPRINT("ScmGetBootAndSystemDriverState() done\n");
00919 }
00920 
00921 
00922 DWORD
00923 ScmControlService(PSERVICE Service,
00924                   DWORD dwControl)
00925 {
00926     PSCM_CONTROL_PACKET ControlPacket;
00927     SCM_REPLY_PACKET ReplyPacket;
00928 
00929     DWORD dwWriteCount = 0;
00930     DWORD dwReadCount = 0;
00931     DWORD PacketSize;
00932     PWSTR Ptr;
00933     DWORD dwError = ERROR_SUCCESS;
00934     BOOL bResult;
00935 #ifdef USE_ASYNCHRONOUS_IO
00936     OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
00937 #endif
00938 
00939     DPRINT("ScmControlService() called\n");
00940 
00941     EnterCriticalSection(&ControlServiceCriticalSection);
00942 
00943     /* Calculate the total length of the start command line */
00944     PacketSize = sizeof(SCM_CONTROL_PACKET);
00945     PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
00946 
00947     ControlPacket = HeapAlloc(GetProcessHeap(),
00948                               HEAP_ZERO_MEMORY,
00949                               PacketSize);
00950     if (ControlPacket == NULL)
00951     {
00952         LeaveCriticalSection(&ControlServiceCriticalSection);
00953         return ERROR_NOT_ENOUGH_MEMORY;
00954     }
00955 
00956     ControlPacket->dwSize = PacketSize;
00957     ControlPacket->dwControl = dwControl;
00958     ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
00959 
00960     ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
00961 
00962     Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
00963     wcscpy(Ptr, Service->lpServiceName);
00964 
00965     ControlPacket->dwArgumentsCount = 0;
00966     ControlPacket->dwArgumentsOffset = 0;
00967 
00968 #ifdef USE_ASYNCHRONOUS_IO
00969     bResult = WriteFile(Service->lpImage->hControlPipe,
00970                         ControlPacket,
00971                         PacketSize,
00972                         &dwWriteCount,
00973                         &Overlapped);
00974     if (bResult == FALSE)
00975     {
00976         DPRINT1("WriteFile() returned FALSE\n");
00977 
00978         dwError = GetLastError();
00979         if (dwError == ERROR_IO_PENDING)
00980         {
00981             DPRINT1("dwError: ERROR_IO_PENDING\n");
00982 
00983             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
00984                                           dwPipeTimeout);
00985             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
00986 
00987             if (dwError == WAIT_TIMEOUT)
00988             {
00989                 bResult = CancelIo(Service->lpImage->hControlPipe);
00990                 if (bResult == FALSE)
00991                 {
00992                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
00993                 }
00994 
00995                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
00996                 goto Done;
00997             }
00998             else if (dwError == ERROR_SUCCESS)
00999             {
01000                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01001                                               &Overlapped,
01002                                               &dwWriteCount,
01003                                               TRUE);
01004                 if (bResult == FALSE)
01005                 {
01006                     dwError = GetLastError();
01007                     DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
01008 
01009                     goto Done;
01010                 }
01011             }
01012         }
01013         else
01014         {
01015             DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
01016             goto Done;
01017         }
01018     }
01019 
01020     /* Read the reply */
01021     Overlapped.hEvent = (HANDLE) NULL;
01022 
01023     bResult = ReadFile(Service->lpImage->hControlPipe,
01024                        &ReplyPacket,
01025                        sizeof(SCM_REPLY_PACKET),
01026                        &dwReadCount,
01027                        &Overlapped);
01028     if (bResult == FALSE)
01029     {
01030         DPRINT1("ReadFile() returned FALSE\n");
01031 
01032         dwError = GetLastError();
01033         if (dwError == ERROR_IO_PENDING)
01034         {
01035             DPRINT1("dwError: ERROR_IO_PENDING\n");
01036 
01037             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
01038                                           dwPipeTimeout);
01039             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
01040 
01041             if (dwError == WAIT_TIMEOUT)
01042             {
01043                 bResult = CancelIo(Service->lpImage->hControlPipe);
01044                 if (bResult == FALSE)
01045                 {
01046                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
01047                 }
01048 
01049                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
01050                 goto Done;
01051             }
01052             else if (dwError == ERROR_SUCCESS)
01053             {
01054                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01055                                               &Overlapped,
01056                                               &dwReadCount,
01057                                               TRUE);
01058                 if (bResult == FALSE)
01059                 {
01060                     dwError = GetLastError();
01061                     DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
01062 
01063                     goto Done;
01064                 }
01065             }
01066         }
01067         else
01068         {
01069             DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
01070             goto Done;
01071         }
01072     }
01073 
01074 #else
01075     /* Send the control packet */
01076     bResult = WriteFile(Service->lpImage->hControlPipe,
01077                         ControlPacket,
01078                         PacketSize,
01079                         &dwWriteCount,
01080                         NULL);
01081     if (bResult == FALSE)
01082     {
01083         dwError = GetLastError();
01084         DPRINT("WriteFile() failed (Error %lu)\n", dwError);
01085 
01086         if ((dwError == ERROR_GEN_FAILURE) &&
01087             (dwControl == SERVICE_CONTROL_STOP))
01088         {
01089             /* Service is already terminated */
01090             Service->Status.dwCurrentState = SERVICE_STOPPED;
01091             Service->Status.dwControlsAccepted = 0;
01092             Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE;
01093             dwError = ERROR_SUCCESS;
01094         }
01095         goto Done;
01096     }
01097 
01098     /* Read the reply */
01099     bResult = ReadFile(Service->lpImage->hControlPipe,
01100                        &ReplyPacket,
01101                        sizeof(SCM_REPLY_PACKET),
01102                        &dwReadCount,
01103                        NULL);
01104     if (bResult == FALSE)
01105     {
01106         dwError = GetLastError();
01107         DPRINT("ReadFile() failed (Error %lu)\n", dwError);
01108     }
01109 #endif
01110 
01111 Done:
01112     /* Release the contol packet */
01113     HeapFree(GetProcessHeap(),
01114              0,
01115              ControlPacket);
01116 
01117     if (dwReadCount == sizeof(SCM_REPLY_PACKET))
01118     {
01119         dwError = ReplyPacket.dwError;
01120     }
01121 
01122     if (dwError == ERROR_SUCCESS &&
01123         dwControl == SERVICE_CONTROL_STOP)
01124     {
01125         ScmDereferenceServiceImage(Service->lpImage);
01126     }
01127 
01128     LeaveCriticalSection(&ControlServiceCriticalSection);
01129 
01130     DPRINT("ScmControlService() done\n");
01131 
01132     return dwError;
01133 }
01134 
01135 
01136 static DWORD
01137 ScmSendStartCommand(PSERVICE Service,
01138                     DWORD argc,
01139                     LPWSTR *argv)
01140 {
01141     PSCM_CONTROL_PACKET ControlPacket;
01142     SCM_REPLY_PACKET ReplyPacket;
01143     DWORD PacketSize;
01144     PWSTR Ptr;
01145     DWORD dwWriteCount = 0;
01146     DWORD dwReadCount = 0;
01147     DWORD dwError = ERROR_SUCCESS;
01148     DWORD i;
01149     PWSTR *pOffPtr;
01150     PWSTR pArgPtr;
01151     BOOL bResult;
01152 #ifdef USE_ASYNCHRONOUS_IO
01153     OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
01154 #endif
01155 
01156     DPRINT("ScmSendStartCommand() called\n");
01157 
01158     /* Calculate the total length of the start command line */
01159     PacketSize = sizeof(SCM_CONTROL_PACKET);
01160     PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
01161 
01162     /* Calculate the required packet size for the start arguments */
01163     if (argc > 0 && argv != NULL)
01164     {
01165         PacketSize = ALIGN_UP(PacketSize, LPWSTR);
01166 
01167         DPRINT("Argc: %lu\n", argc);
01168         for (i = 0; i < argc; i++)
01169         {
01170             DPRINT("Argv[%lu]: %S\n", i, argv[i]);
01171             PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR);
01172         }
01173     }
01174 
01175     /* Allocate a control packet */
01176     ControlPacket = HeapAlloc(GetProcessHeap(),
01177                               HEAP_ZERO_MEMORY,
01178                               PacketSize);
01179     if (ControlPacket == NULL)
01180         return ERROR_NOT_ENOUGH_MEMORY;
01181 
01182     ControlPacket->dwSize = PacketSize;
01183     ControlPacket->dwControl = SERVICE_CONTROL_START;
01184     ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
01185     ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
01186 
01187     Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
01188     wcscpy(Ptr, Service->lpServiceName);
01189 
01190     ControlPacket->dwArgumentsCount = 0;
01191     ControlPacket->dwArgumentsOffset = 0;
01192 
01193     /* Copy argument list */
01194     if (argc > 0 && argv != NULL)
01195     {
01196         Ptr += wcslen(Service->lpServiceName) + 1;
01197         pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
01198         pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
01199 
01200         ControlPacket->dwArgumentsCount = argc;
01201         ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
01202 
01203         DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
01204         DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
01205 
01206         for (i = 0; i < argc; i++)
01207         {
01208              wcscpy(pArgPtr, argv[i]);
01209              *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
01210              DPRINT("offset: %p\n", *pOffPtr);
01211 
01212              pArgPtr += wcslen(argv[i]) + 1;
01213              pOffPtr++;
01214         }
01215     }
01216 
01217 #ifdef USE_ASYNCHRONOUS_IO
01218     bResult = WriteFile(Service->lpImage->hControlPipe,
01219                         ControlPacket,
01220                         PacketSize,
01221                         &dwWriteCount,
01222                         &Overlapped);
01223     if (bResult == FALSE)
01224     {
01225         DPRINT1("WriteFile() returned FALSE\n");
01226 
01227         dwError = GetLastError();
01228         if (dwError == ERROR_IO_PENDING)
01229         {
01230             DPRINT1("dwError: ERROR_IO_PENDING\n");
01231 
01232             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
01233                                           dwPipeTimeout);
01234             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
01235 
01236             if (dwError == WAIT_TIMEOUT)
01237             {
01238                 bResult = CancelIo(Service->lpImage->hControlPipe);
01239                 if (bResult == FALSE)
01240                 {
01241                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
01242                 }
01243 
01244                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
01245                 goto Done;
01246             }
01247             else if (dwError == ERROR_SUCCESS)
01248             {
01249                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01250                                               &Overlapped,
01251                                               &dwWriteCount,
01252                                               TRUE);
01253                 if (bResult == FALSE)
01254                 {
01255                     dwError = GetLastError();
01256                     DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
01257 
01258                     goto Done;
01259                 }
01260             }
01261         }
01262         else
01263         {
01264             DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
01265             goto Done;
01266         }
01267     }
01268 
01269     /* Read the reply */
01270     Overlapped.hEvent = (HANDLE) NULL;
01271 
01272     bResult = ReadFile(Service->lpImage->hControlPipe,
01273                        &ReplyPacket,
01274                        sizeof(SCM_REPLY_PACKET),
01275                        &dwReadCount,
01276                        &Overlapped);
01277     if (bResult == FALSE)
01278     {
01279         DPRINT1("ReadFile() returned FALSE\n");
01280 
01281         dwError = GetLastError();
01282         if (dwError == ERROR_IO_PENDING)
01283         {
01284             DPRINT1("dwError: ERROR_IO_PENDING\n");
01285 
01286             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
01287                                           dwPipeTimeout);
01288             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
01289 
01290             if (dwError == WAIT_TIMEOUT)
01291             {
01292                 bResult = CancelIo(Service->lpImage->hControlPipe);
01293                 if (bResult == FALSE)
01294                 {
01295                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
01296                 }
01297 
01298                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
01299                 goto Done;
01300             }
01301             else if (dwError == ERROR_SUCCESS)
01302             {
01303                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01304                                               &Overlapped,
01305                                               &dwReadCount,
01306                                               TRUE);
01307                 if (bResult == FALSE)
01308                 {
01309                     dwError = GetLastError();
01310                     DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
01311 
01312                     goto Done;
01313                 }
01314             }
01315         }
01316         else
01317         {
01318             DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
01319             goto Done;
01320         }
01321     }
01322 
01323 #else
01324     /* Send the start command */
01325     bResult = WriteFile(Service->lpImage->hControlPipe,
01326                         ControlPacket,
01327                         PacketSize,
01328                         &dwWriteCount,
01329                         NULL);
01330     if (bResult == FALSE)
01331     {
01332         dwError = GetLastError();
01333         DPRINT("WriteFile() failed (Error %lu)\n", dwError);
01334         goto Done;
01335     }
01336 
01337     /* Read the reply */
01338     bResult = ReadFile(Service->lpImage->hControlPipe,
01339                        &ReplyPacket,
01340                        sizeof(SCM_REPLY_PACKET),
01341                        &dwReadCount,
01342                        NULL);
01343     if (bResult == FALSE)
01344     {
01345         dwError = GetLastError();
01346         DPRINT("ReadFile() failed (Error %lu)\n", dwError);
01347     }
01348 #endif
01349 
01350 Done:
01351     /* Release the contol packet */
01352     HeapFree(GetProcessHeap(),
01353              0,
01354              ControlPacket);
01355 
01356     if (dwReadCount == sizeof(SCM_REPLY_PACKET))
01357     {
01358         dwError = ReplyPacket.dwError;
01359     }
01360 
01361     DPRINT("ScmSendStartCommand() done\n");
01362 
01363     return dwError;
01364 }
01365 
01366 
01367 static DWORD
01368 ScmWaitForServiceConnect(PSERVICE Service)
01369 {
01370     DWORD dwRead = 0;
01371     DWORD dwProcessId = 0;
01372     DWORD dwError = ERROR_SUCCESS;
01373     BOOL bResult;
01374 #ifdef USE_ASYNCHRONOUS_IO
01375     OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
01376 #endif
01377 
01378     DPRINT("ScmWaitForServiceConnect()\n");
01379 
01380 #ifdef USE_ASYNCHRONOUS_IO
01381     Overlapped.hEvent = (HANDLE)NULL;
01382 
01383     bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
01384                                &Overlapped);
01385     if (bResult == FALSE)
01386     {
01387         DPRINT("ConnectNamedPipe() returned FALSE\n");
01388 
01389         dwError = GetLastError();
01390         if (dwError == ERROR_IO_PENDING)
01391         {
01392             DPRINT("dwError: ERROR_IO_PENDING\n");
01393 
01394             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
01395                                           dwPipeTimeout);
01396             DPRINT("WaitForSingleObject() returned %lu\n", dwError);
01397 
01398             if (dwError == WAIT_TIMEOUT)
01399             {
01400                 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
01401 
01402                 bResult = CancelIo(Service->lpImage->hControlPipe);
01403                 if (bResult == FALSE)
01404                 {
01405                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
01406                 }
01407 
01408                 return ERROR_SERVICE_REQUEST_TIMEOUT;
01409             }
01410             else if (dwError == WAIT_OBJECT_0)
01411             {
01412                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01413                                               &Overlapped,
01414                                               &dwRead,
01415                                               TRUE);
01416                 if (bResult == FALSE)
01417                 {
01418                     dwError = GetLastError();
01419                     DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
01420 
01421                     return dwError;
01422                 }
01423             }
01424         }
01425         else if (dwError != ERROR_PIPE_CONNECTED)
01426         {
01427             DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
01428             return dwError;
01429         }
01430     }
01431 
01432     DPRINT("Control pipe connected!\n");
01433 
01434     Overlapped.hEvent = (HANDLE) NULL;
01435 
01436     /* Read the process id from pipe */
01437     bResult = ReadFile(Service->lpImage->hControlPipe,
01438                        (LPVOID)&dwProcessId,
01439                        sizeof(DWORD),
01440                        &dwRead,
01441                        &Overlapped);
01442     if (bResult == FALSE)
01443     {
01444         DPRINT("ReadFile() returned FALSE\n");
01445 
01446         dwError = GetLastError();
01447         if (dwError == ERROR_IO_PENDING)
01448         {
01449             DPRINT("dwError: ERROR_IO_PENDING\n");
01450 
01451             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
01452                                           dwPipeTimeout);
01453             if (dwError == WAIT_TIMEOUT)
01454             {
01455                 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
01456 
01457                 bResult = CancelIo(Service->lpImage->hControlPipe);
01458                 if (bResult == FALSE)
01459                 {
01460                     DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
01461                 }
01462 
01463                 return ERROR_SERVICE_REQUEST_TIMEOUT;
01464             }
01465             else if (dwError == ERROR_SUCCESS)
01466             {
01467                 DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
01468 
01469                 DPRINT("Process Id: %lu\n", dwProcessId);
01470 
01471                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
01472                                               &Overlapped,
01473                                               &dwRead,
01474                                               TRUE);
01475                 if (bResult == FALSE)
01476                 {
01477                     dwError = GetLastError();
01478                     DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
01479 
01480                     return dwError;
01481                 }
01482             }
01483             else
01484             {
01485                 DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
01486             }
01487         }
01488         else
01489         {
01490             DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
01491             return dwError;
01492         }
01493     }
01494 
01495     DPRINT1("ScmWaitForServiceConnect() done\n");
01496 
01497     return ERROR_SUCCESS;
01498 #else
01499 
01500     /* Connect control pipe */
01501     if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
01502         TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
01503     {
01504         DPRINT("Control pipe connected!\n");
01505 
01506         /* Read SERVICE_STATUS_HANDLE from pipe */
01507         bResult = ReadFile(Service->lpImage->hControlPipe,
01508                            (LPVOID)&dwProcessId,
01509                            sizeof(DWORD),
01510                            &dwRead,
01511                            NULL);
01512         if (bResult == FALSE)
01513         {
01514             dwError = GetLastError();
01515             DPRINT1("Reading the service control pipe failed (Error %lu)\n",
01516                     dwError);
01517         }
01518         else
01519         {
01520             dwError = ERROR_SUCCESS;
01521             DPRINT("Read control pipe successfully\n");
01522         }
01523     }
01524     else
01525     {
01526         DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
01527     }
01528 
01529     return dwError;
01530 #endif
01531 }
01532 
01533 
01534 static DWORD
01535 ScmStartUserModeService(PSERVICE Service,
01536                         DWORD argc,
01537                         LPWSTR *argv)
01538 {
01539     PROCESS_INFORMATION ProcessInformation;
01540     STARTUPINFOW StartupInfo;
01541     BOOL Result;
01542     DWORD dwError = ERROR_SUCCESS;
01543 
01544     DPRINT("ScmStartUserModeService(%p)\n", Service);
01545 
01546     /* If the image is already running ... */
01547     if (Service->lpImage->dwImageRunCount > 1)
01548     {
01549         /* ... just send a start command */
01550         return ScmSendStartCommand(Service, argc, argv);
01551     }
01552 
01553     StartupInfo.cb = sizeof(StartupInfo);
01554     StartupInfo.lpReserved = NULL;
01555     StartupInfo.lpDesktop = NULL;
01556     StartupInfo.lpTitle = NULL;
01557     StartupInfo.dwFlags = 0;
01558     StartupInfo.cbReserved2 = 0;
01559     StartupInfo.lpReserved2 = 0;
01560 
01561     Result = CreateProcessW(NULL,
01562                             Service->lpImage->szImagePath,
01563                             NULL,
01564                             NULL,
01565                             FALSE,
01566                             DETACHED_PROCESS | CREATE_SUSPENDED,
01567                             NULL,
01568                             NULL,
01569                             &StartupInfo,
01570                             &ProcessInformation);
01571     if (!Result)
01572     {
01573         dwError = GetLastError();
01574         DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
01575         return dwError;
01576     }
01577 
01578     DPRINT("Process Id: %lu  Handle %p\n",
01579            ProcessInformation.dwProcessId,
01580            ProcessInformation.hProcess);
01581     DPRINT("Thread Id: %lu  Handle %p\n",
01582            ProcessInformation.dwThreadId,
01583            ProcessInformation.hThread);
01584 
01585     /* Get process handle and id */
01586     Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
01587 
01588     /* Resume Thread */
01589     ResumeThread(ProcessInformation.hThread);
01590 
01591     /* Connect control pipe */
01592     dwError = ScmWaitForServiceConnect(Service);
01593     if (dwError == ERROR_SUCCESS)
01594     {
01595         /* Send start command */
01596         dwError = ScmSendStartCommand(Service,
01597                                       argc,
01598                                       argv);
01599     }
01600     else
01601     {
01602         DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
01603         Service->lpImage->dwProcessId = 0;
01604     }
01605 
01606     /* Close thread and process handle */
01607     CloseHandle(ProcessInformation.hThread);
01608     CloseHandle(ProcessInformation.hProcess);
01609 
01610     return dwError;
01611 }
01612 
01613 
01614 DWORD
01615 ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
01616 {
01617     PSERVICE_GROUP Group = Service->lpGroup;
01618     DWORD dwError = ERROR_SUCCESS;
01619     LPCWSTR ErrorLogStrings[2];
01620     WCHAR szErrorBuffer[32];
01621 
01622     DPRINT("ScmStartService() called\n");
01623 
01624     DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
01625 
01626     EnterCriticalSection(&ControlServiceCriticalSection);
01627 
01628     if (Service->Status.dwCurrentState != SERVICE_STOPPED)
01629     {
01630         DPRINT("Service %S is already running!\n", Service->lpServiceName);
01631         LeaveCriticalSection(&ControlServiceCriticalSection);
01632         return ERROR_SERVICE_ALREADY_RUNNING;
01633     }
01634 
01635     DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
01636 
01637     if (Service->Status.dwServiceType & SERVICE_DRIVER)
01638     {
01639         /* Load driver */
01640         dwError = ScmLoadDriver(Service);
01641         if (dwError == ERROR_SUCCESS)
01642         {
01643             Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
01644             Service->Status.dwCurrentState = SERVICE_RUNNING;
01645         }
01646     }
01647     else
01648     {
01649         /* Start user-mode service */
01650         dwError = ScmCreateOrReferenceServiceImage(Service);
01651         if (dwError == ERROR_SUCCESS)
01652         {
01653             dwError = ScmStartUserModeService(Service, argc, argv);
01654             if (dwError == ERROR_SUCCESS)
01655             {
01656 #ifdef USE_SERVICE_START_PENDING
01657                 Service->Status.dwCurrentState = SERVICE_START_PENDING;
01658 #else
01659                 Service->Status.dwCurrentState = SERVICE_RUNNING;
01660 #endif
01661             }
01662             else
01663             {
01664                 ScmDereferenceServiceImage(Service->lpImage);
01665                 Service->lpImage = NULL;
01666             }
01667         }
01668     }
01669 
01670     LeaveCriticalSection(&ControlServiceCriticalSection);
01671 
01672     DPRINT("ScmStartService() done (Error %lu)\n", dwError);
01673 
01674     if (dwError == ERROR_SUCCESS)
01675     {
01676         if (Group != NULL)
01677         {
01678             Group->ServicesRunning = TRUE;
01679         }
01680     }
01681     else
01682     {
01683         if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
01684         {
01685             /* Log a failed service start */
01686             swprintf(szErrorBuffer, L"%lu", dwError);
01687             ErrorLogStrings[0] = Service->lpServiceName;
01688             ErrorLogStrings[1] = szErrorBuffer;
01689             ScmLogError(EVENT_SERVICE_START_FAILED,
01690                         2,
01691                         ErrorLogStrings);
01692         }
01693 
01694 #if 0
01695         switch (Service->dwErrorControl)
01696         {
01697             case SERVICE_ERROR_SEVERE:
01698                 if (IsLastKnownGood == FALSE)
01699                 {
01700                     /* FIXME: Boot last known good configuration */
01701                 }
01702                 break;
01703 
01704             case SERVICE_ERROR_CRITICAL:
01705                 if (IsLastKnownGood == FALSE)
01706                 {
01707                     /* FIXME: Boot last known good configuration */
01708                 }
01709                 else
01710                 {
01711                     /* FIXME: BSOD! */
01712                 }
01713                 break;
01714         }
01715 #endif
01716     }
01717 
01718     return dwError;
01719 }
01720 
01721 
01722 VOID
01723 ScmAutoStartServices(VOID)
01724 {
01725     PLIST_ENTRY GroupEntry;
01726     PLIST_ENTRY ServiceEntry;
01727     PSERVICE_GROUP CurrentGroup;
01728     PSERVICE CurrentService;
01729     WCHAR szSafeBootServicePath[MAX_PATH];
01730     DWORD dwError;
01731     HKEY hKey;
01732     ULONG i;
01733 
01734     /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
01735     ServiceEntry = ServiceListHead.Flink;
01736     while (ServiceEntry != &ServiceListHead)
01737     {
01738         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01739 
01740         /* Build the safe boot path */
01741         wcscpy(szSafeBootServicePath,
01742                L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
01743 
01744         switch (GetSystemMetrics(SM_CLEANBOOT))
01745         {
01746             /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
01747             case 1:
01748             case 3:
01749                 wcscat(szSafeBootServicePath, L"\\Minimal\\");
01750                 break;
01751 
01752             case 2:
01753                 wcscat(szSafeBootServicePath, L"\\Network\\");
01754                 break;
01755         }
01756 
01757         if (GetSystemMetrics(SM_CLEANBOOT))
01758         {
01759             /* If key does not exist then do not assume safe mode */
01760             dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
01761                                     szSafeBootServicePath,
01762                                     0,
01763                                     KEY_READ,
01764                                     &hKey);
01765             if (dwError == ERROR_SUCCESS)
01766             {
01767                 RegCloseKey(hKey);
01768 
01769                 /* Finish Safe Boot path off */
01770                 wcsncat(szSafeBootServicePath,
01771                         CurrentService->lpServiceName,
01772                         MAX_PATH - wcslen(szSafeBootServicePath));
01773 
01774                 /* Check that the key is in the Safe Boot path */
01775                 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
01776                                         szSafeBootServicePath,
01777                                         0,
01778                                         KEY_READ,
01779                                         &hKey);
01780                 if (dwError != ERROR_SUCCESS)
01781                 {
01782                     /* Mark service as visited so it is not auto-started */
01783                     CurrentService->ServiceVisited = TRUE;
01784                 }
01785                 else
01786                 {
01787                     /* Must be auto-started in safe mode - mark as unvisited */
01788                     RegCloseKey(hKey);
01789                     CurrentService->ServiceVisited = FALSE;
01790                 }
01791             }
01792             else
01793             {
01794                 DPRINT1("WARNING: Could not open the associated Safe Boot key!");
01795                 CurrentService->ServiceVisited = FALSE;
01796             }
01797         }
01798 
01799         ServiceEntry = ServiceEntry->Flink;
01800     }
01801 
01802     /* Start all services which are members of an existing group */
01803     GroupEntry = GroupListHead.Flink;
01804     while (GroupEntry != &GroupListHead)
01805     {
01806         CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry);
01807 
01808         DPRINT("Group '%S'\n", CurrentGroup->lpGroupName);
01809 
01810         /* Start all services witch have a valid tag */
01811         for (i = 0; i < CurrentGroup->TagCount; i++)
01812         {
01813             ServiceEntry = ServiceListHead.Flink;
01814             while (ServiceEntry != &ServiceListHead)
01815             {
01816                 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01817 
01818                 if ((CurrentService->lpGroup == CurrentGroup) &&
01819                     (CurrentService->dwStartType == SERVICE_AUTO_START) &&
01820                     (CurrentService->ServiceVisited == FALSE) &&
01821                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
01822                 {
01823                     CurrentService->ServiceVisited = TRUE;
01824                     ScmStartService(CurrentService, 0, NULL);
01825                 }
01826 
01827                 ServiceEntry = ServiceEntry->Flink;
01828              }
01829         }
01830 
01831         /* Start all services which have an invalid tag or which do not have a tag */
01832         ServiceEntry = ServiceListHead.Flink;
01833         while (ServiceEntry != &ServiceListHead)
01834         {
01835             CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01836 
01837             if ((CurrentService->lpGroup == CurrentGroup) &&
01838                 (CurrentService->dwStartType == SERVICE_AUTO_START) &&
01839                 (CurrentService->ServiceVisited == FALSE))
01840             {
01841                 CurrentService->ServiceVisited = TRUE;
01842                 ScmStartService(CurrentService, 0, NULL);
01843             }
01844 
01845             ServiceEntry = ServiceEntry->Flink;
01846         }
01847 
01848         GroupEntry = GroupEntry->Flink;
01849     }
01850 
01851     /* Start all services which are members of any non-existing group */
01852     ServiceEntry = ServiceListHead.Flink;
01853     while (ServiceEntry != &ServiceListHead)
01854     {
01855         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01856 
01857         if ((CurrentService->lpGroup != NULL) &&
01858             (CurrentService->dwStartType == SERVICE_AUTO_START) &&
01859             (CurrentService->ServiceVisited == FALSE))
01860         {
01861             CurrentService->ServiceVisited = TRUE;
01862             ScmStartService(CurrentService, 0, NULL);
01863         }
01864 
01865         ServiceEntry = ServiceEntry->Flink;
01866     }
01867 
01868     /* Start all services which are not a member of any group */
01869     ServiceEntry = ServiceListHead.Flink;
01870     while (ServiceEntry != &ServiceListHead)
01871     {
01872         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01873 
01874         if ((CurrentService->lpGroup == NULL) &&
01875             (CurrentService->dwStartType == SERVICE_AUTO_START) &&
01876             (CurrentService->ServiceVisited == FALSE))
01877         {
01878             CurrentService->ServiceVisited = TRUE;
01879             ScmStartService(CurrentService, 0, NULL);
01880         }
01881 
01882         ServiceEntry = ServiceEntry->Flink;
01883     }
01884 
01885     /* Clear 'ServiceVisited' flag again */
01886     ServiceEntry = ServiceListHead.Flink;
01887     while (ServiceEntry != &ServiceListHead)
01888     {
01889         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01890         CurrentService->ServiceVisited = FALSE;
01891         ServiceEntry = ServiceEntry->Flink;
01892     }
01893 }
01894 
01895 
01896 VOID
01897 ScmAutoShutdownServices(VOID)
01898 {
01899     PLIST_ENTRY ServiceEntry;
01900     PSERVICE CurrentService;
01901 
01902     DPRINT("ScmAutoShutdownServices() called\n");
01903 
01904     /* Lock the service database exclusively */
01905     ScmLockDatabaseExclusive();
01906 
01907     ServiceEntry = ServiceListHead.Flink;
01908     while (ServiceEntry != &ServiceListHead)
01909     {
01910         CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
01911 
01912         if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
01913             CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
01914         {
01915             /* shutdown service */
01916             DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
01917             ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
01918         }
01919 
01920         ServiceEntry = ServiceEntry->Flink;
01921     }
01922 
01923     /* Unlock the service database */
01924     ScmUnlockDatabase();
01925 
01926     DPRINT("ScmAutoShutdownServices() done\n");
01927 }
01928 
01929 
01930 BOOL
01931 ScmLockDatabaseExclusive(VOID)
01932 {
01933     return RtlAcquireResourceExclusive(&DatabaseLock, TRUE);
01934 }
01935 
01936 
01937 BOOL
01938 ScmLockDatabaseShared(VOID)
01939 {
01940     return RtlAcquireResourceShared(&DatabaseLock, TRUE);
01941 }
01942 
01943 
01944 VOID
01945 ScmUnlockDatabase(VOID)
01946 {
01947     RtlReleaseResource(&DatabaseLock);
01948 }
01949 
01950 
01951 VOID
01952 ScmInitNamedPipeCriticalSection(VOID)
01953 {
01954     HKEY hKey;
01955     DWORD dwKeySize;
01956     DWORD dwError;
01957 
01958     InitializeCriticalSection(&ControlServiceCriticalSection);
01959 
01960     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
01961                             L"SYSTEM\\CurrentControlSet\\Control",
01962                             0,
01963                             KEY_READ,
01964                             &hKey);
01965    if (dwError == ERROR_SUCCESS)
01966    {
01967         dwKeySize = sizeof(DWORD);
01968         RegQueryValueExW(hKey,
01969                          L"ServicesPipeTimeout",
01970                          0,
01971                          NULL,
01972                          (LPBYTE)&dwPipeTimeout,
01973                          &dwKeySize);
01974 
01975        RegCloseKey(hKey);
01976    }
01977 }
01978 
01979 
01980 VOID
01981 ScmDeleteNamedPipeCriticalSection(VOID)
01982 {
01983     DeleteCriticalSection(&ControlServiceCriticalSection);
01984 }
01985 
01986 /* EOF */

Generated on Thu May 24 2012 04:19:00 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.