Synchronize with trunk revision 59781.
[reactos.git] / base / system / services / database.c
index 93ea322..a5c24d2 100644 (file)
@@ -19,9 +19,9 @@
 
 /*
  * Uncomment the line below to start services
- *  using the SERVICE_START_PENDING state
+ * using the SERVICE_START_PENDING state.
  */
-// #define USE_SERVICE_START_PENDING
+#define USE_SERVICE_START_PENDING
 
 /*
  * Uncomment the line below to use asynchronous IO operations
@@ -36,10 +36,11 @@ LIST_ENTRY ImageListHead;
 LIST_ENTRY ServiceListHead;
 
 static RTL_RESOURCE DatabaseLock;
-static DWORD dwResumeCount = 1;
+static DWORD ResumeCount = 1;
 
+/* The critical section synchronizes service control requests */
 static CRITICAL_SECTION ControlServiceCriticalSection;
-static DWORD dwPipeTimeout = 30000; /* 30 Seconds */
+static DWORD PipeTimeout = 30000; /* 30 Seconds */
 
 
 /* FUNCTIONS *****************************************************************/
@@ -110,7 +111,7 @@ ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
                                                    100,
                                                    8000,
                                                    4,
-                                                   dwPipeTimeout,
+                                                   PipeTimeout,
                                                    NULL);
     DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
     if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
@@ -359,7 +360,7 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 
 DWORD
 ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
-                          PSERVICE *lpServiceRecord)
+                          PSERVICElpServiceRecord)
 {
     PSERVICE lpService = NULL;
 
@@ -380,7 +381,7 @@ ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
     lpService->lpDisplayName = lpService->lpServiceName;
 
     /* Set the resume count */
-    lpService->dwResumeCount = dwResumeCount++;
+    lpService->dwResumeCount = ResumeCount++;
 
     /* Append service record */
     InsertTailList(&ServiceListHead,
@@ -591,7 +592,7 @@ ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
             if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR))
             {
                 /* Name too big: alloc a buffer for it */
-                lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen * sizeof(WCHAR));
+                lpszName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSubkeyLen * sizeof(WCHAR));
             }
 
             if (!lpszName)
@@ -661,46 +662,6 @@ ScmDeleteMarkedServices(VOID)
 }
 
 
-VOID
-WaitForLSA(VOID)
-{
-    HANDLE hEvent;
-    DWORD dwError;
-
-    DPRINT("WaitForLSA() called\n");
-
-    hEvent = CreateEventW(NULL,
-                          TRUE,
-                          FALSE,
-                          L"LSA_RPC_SERVER_ACTIVE");
-    if (hEvent == NULL)
-    {
-        dwError = GetLastError();
-        DPRINT1("Failed to create the notication event (Error %lu)\n", dwError);
-
-        if (dwError == ERROR_ALREADY_EXISTS)
-        {
-            hEvent = OpenEventW(SYNCHRONIZE,
-                                FALSE,
-                                L"LSA_RPC_SERVER_ACTIVE");
-            if (hEvent != NULL)
-            {
-               DPRINT1("Could not open the notification event!\n");
-               return;
-            }
-        }
-    }
-
-    DPRINT("Wait for LSA!\n");
-    WaitForSingleObject(hEvent, INFINITE);
-    DPRINT("LSA is available!\n");
-
-    CloseHandle(hEvent);
-
-    DPRINT("WaitForLSA() done\n");
-}
-
-
 DWORD
 ScmCreateServiceDatabase(VOID)
 {
@@ -772,8 +733,8 @@ ScmCreateServiceDatabase(VOID)
 
     RegCloseKey(hServicesKey);
 
-    /* Wait for LSA */
-    WaitForLSA();
+    /* Wait for the LSA server */
+    ScmWaitForLsa();
 
     /* Delete services that are marked for delete */
     ScmDeleteMarkedServices();
@@ -812,13 +773,12 @@ ScmCheckDriver(PSERVICE Service)
 
     if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\Driver");
+        RtlInitUnicodeString(&DirName, L"\\Driver");
     }
-    else
+    else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
     {
-        RtlInitUnicodeString(&DirName,
-                             L"\\FileSystem");
+        ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
+        RtlInitUnicodeString(&DirName, L"\\FileSystem");
     }
 
     InitializeObjectAttributes(&ObjectAttributes,
@@ -836,7 +796,7 @@ ScmCheckDriver(PSERVICE Service)
     }
 
     BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
-                   2 * MAX_PATH * sizeof(WCHAR);
+                       2 * MAX_PATH * sizeof(WCHAR);
     DirInfo = HeapAlloc(GetProcessHeap(),
                         HEAP_ZERO_MEMORY,
                         BufferLength);
@@ -938,11 +898,12 @@ ScmControlService(PSERVICE Service,
 
     DPRINT("ScmControlService() called\n");
 
+    /* Acquire the service control critical section, to synchronize requests */
     EnterCriticalSection(&ControlServiceCriticalSection);
 
     /* Calculate the total length of the start command line */
     PacketSize = sizeof(SCM_CONTROL_PACKET);
-    PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
+    PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
 
     ControlPacket = HeapAlloc(GetProcessHeap(),
                               HEAP_ZERO_MEMORY,
@@ -981,7 +942,7 @@ ScmControlService(PSERVICE Service,
             DPRINT1("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
@@ -995,7 +956,7 @@ ScmControlService(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1035,7 +996,7 @@ ScmControlService(PSERVICE Service,
             DPRINT1("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
@@ -1049,7 +1010,7 @@ ScmControlService(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1136,7 +1097,7 @@ Done:
 static DWORD
 ScmSendStartCommand(PSERVICE Service,
                     DWORD argc,
-                    LPWSTR *argv)
+                    LPWSTRargv)
 {
     PSCM_CONTROL_PACKET ControlPacket;
     SCM_REPLY_PACKET ReplyPacket;
@@ -1156,8 +1117,8 @@ ScmSendStartCommand(PSERVICE Service,
     DPRINT("ScmSendStartCommand() called\n");
 
     /* Calculate the total length of the start command line */
-    PacketSize = sizeof(SCM_CONTROL_PACKET);
-    PacketSize += (wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR);
+    PacketSize = sizeof(SCM_CONTROL_PACKET) +
+                 (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
 
     /* Calculate the required packet size for the start arguments */
     if (argc > 0 && argv != NULL)
@@ -1168,7 +1129,7 @@ ScmSendStartCommand(PSERVICE Service,
         for (i = 0; i < argc; i++)
         {
             DPRINT("Argv[%lu]: %S\n", i, argv[i]);
-            PacketSize += (wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR);
+            PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
         }
     }
 
@@ -1180,7 +1141,9 @@ ScmSendStartCommand(PSERVICE Service,
         return ERROR_NOT_ENOUGH_MEMORY;
 
     ControlPacket->dwSize = PacketSize;
-    ControlPacket->dwControl = SERVICE_CONTROL_START;
+    ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
+                               ? SERVICE_CONTROL_START_OWN
+                               : SERVICE_CONTROL_START_SHARE;
     ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
     ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
 
@@ -1230,7 +1193,7 @@ ScmSendStartCommand(PSERVICE Service,
             DPRINT1("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
@@ -1244,7 +1207,7 @@ ScmSendStartCommand(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1284,7 +1247,7 @@ ScmSendStartCommand(PSERVICE Service,
             DPRINT1("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
@@ -1298,7 +1261,7 @@ ScmSendStartCommand(PSERVICE Service,
                 dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
                 goto Done;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
                 bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
                                               &Overlapped,
@@ -1392,7 +1355,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
             DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             DPRINT("WaitForSingleObject() returned %lu\n", dwError);
 
             if (dwError == WAIT_TIMEOUT)
@@ -1449,7 +1412,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
             DPRINT("dwError: ERROR_IO_PENDING\n");
 
             dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
-                                          dwPipeTimeout);
+                                          PipeTimeout);
             if (dwError == WAIT_TIMEOUT)
             {
                 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
@@ -1462,9 +1425,9 @@ ScmWaitForServiceConnect(PSERVICE Service)
 
                 return ERROR_SERVICE_REQUEST_TIMEOUT;
             }
-            else if (dwError == ERROR_SUCCESS)
+            else if (dwError == WAIT_OBJECT_0)
             {
-                DPRINT("WaitForSingleObject() returned ERROR_SUCCESS\n");
+                DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
 
                 DPRINT("Process Id: %lu\n", dwProcessId);
 
@@ -1534,7 +1497,7 @@ ScmWaitForServiceConnect(PSERVICE Service)
 static DWORD
 ScmStartUserModeService(PSERVICE Service,
                         DWORD argc,
-                        LPWSTR *argv)
+                        LPWSTRargv)
 {
     PROCESS_INFORMATION ProcessInformation;
     STARTUPINFOW StartupInfo;
@@ -1550,13 +1513,10 @@ ScmStartUserModeService(PSERVICE Service,
         return ScmSendStartCommand(Service, argc, argv);
     }
 
+    /* Otherwise start its process */
+    ZeroMemory(&StartupInfo, sizeof(StartupInfo));
     StartupInfo.cb = sizeof(StartupInfo);
-    StartupInfo.lpReserved = NULL;
-    StartupInfo.lpDesktop = NULL;
-    StartupInfo.lpTitle = NULL;
-    StartupInfo.dwFlags = 0;
-    StartupInfo.cbReserved2 = 0;
-    StartupInfo.lpReserved2 = 0;
+    ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
 
     Result = CreateProcessW(NULL,
                             Service->lpImage->szImagePath,
@@ -1593,9 +1553,7 @@ ScmStartUserModeService(PSERVICE Service,
     if (dwError == ERROR_SUCCESS)
     {
         /* Send start command */
-        dwError = ScmSendStartCommand(Service,
-                                      argc,
-                                      argv);
+        dwError = ScmSendStartCommand(Service, argc, argv);
     }
     else
     {
@@ -1611,23 +1569,22 @@ ScmStartUserModeService(PSERVICE Service,
 }
 
 
-DWORD
-ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
+static DWORD
+ScmLoadService(PSERVICE Service,
+               DWORD argc,
+               LPWSTR* argv)
 {
     PSERVICE_GROUP Group = Service->lpGroup;
     DWORD dwError = ERROR_SUCCESS;
     LPCWSTR ErrorLogStrings[2];
+    WCHAR szErrorBuffer[32];
 
-    DPRINT("ScmStartService() called\n");
-
+    DPRINT("ScmLoadService() called\n");
     DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
 
-    EnterCriticalSection(&ControlServiceCriticalSection);
-
     if (Service->Status.dwCurrentState != SERVICE_STOPPED)
     {
         DPRINT("Service %S is already running!\n", Service->lpServiceName);
-        LeaveCriticalSection(&ControlServiceCriticalSection);
         return ERROR_SERVICE_ALREADY_RUNNING;
     }
 
@@ -1643,7 +1600,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
             Service->Status.dwCurrentState = SERVICE_RUNNING;
         }
     }
-    else
+    else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
     {
         /* Start user-mode service */
         dwError = ScmCreateOrReferenceServiceImage(Service);
@@ -1666,9 +1623,7 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
         }
     }
 
-    LeaveCriticalSection(&ControlServiceCriticalSection);
-
-    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+    DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
 
     if (dwError == ERROR_SUCCESS)
     {
@@ -1681,8 +1636,10 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
     {
         if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
         {
+            /* Log a failed service start */
+            swprintf(szErrorBuffer, L"%lu", dwError);
             ErrorLogStrings[0] = Service->lpServiceName;
-            ErrorLogStrings[1] = L"Test";
+            ErrorLogStrings[1] = szErrorBuffer;
             ScmLogError(EVENT_SERVICE_START_FAILED,
                         2,
                         ErrorLogStrings);
@@ -1716,18 +1673,67 @@ ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
 }
 
 
+DWORD
+ScmStartService(PSERVICE Service,
+                DWORD argc,
+                LPWSTR* argv)
+{
+    DWORD dwError = ERROR_SUCCESS;
+    SC_RPC_LOCK Lock = NULL;
+
+    DPRINT("ScmStartService() called\n");
+    DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
+
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
+    /*
+     * Acquire the user service start lock while the service is starting, if
+     * needed (i.e. if we are not starting it during the initialization phase).
+     * If we don't success, bail out.
+     */
+    if (!ScmInitialize)
+    {
+        dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
+        if (dwError != ERROR_SUCCESS) goto done;
+    }
+
+    /* Really start the service */
+    dwError = ScmLoadService(Service, argc, argv);
+
+    /* Release the service start lock, if needed, and the critical section */
+    if (Lock) ScmReleaseServiceStartLock(&Lock);
+
+done:
+    LeaveCriticalSection(&ControlServiceCriticalSection);
+
+    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+
+    return dwError;
+}
+
+
 VOID
 ScmAutoStartServices(VOID)
 {
+    DWORD dwError = ERROR_SUCCESS;
     PLIST_ENTRY GroupEntry;
     PLIST_ENTRY ServiceEntry;
     PSERVICE_GROUP CurrentGroup;
     PSERVICE CurrentService;
     WCHAR szSafeBootServicePath[MAX_PATH];
-    DWORD dwError;
     HKEY hKey;
     ULONG i;
 
+    /*
+     * This function MUST be called ONLY at initialization time.
+     * Therefore, no need to acquire the user service start lock.
+     */
+    ASSERT(ScmInitialize);
+
+    /* Acquire the service control critical section, to synchronize starts */
+    EnterCriticalSection(&ControlServiceCriticalSection);
+
     /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
     ServiceEntry = ServiceListHead.Flink;
     while (ServiceEntry != &ServiceListHead)
@@ -1818,7 +1824,7 @@ ScmAutoStartServices(VOID)
                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                 {
                     CurrentService->ServiceVisited = TRUE;
-                    ScmStartService(CurrentService, 0, NULL);
+                    ScmLoadService(CurrentService, 0, NULL);
                 }
 
                 ServiceEntry = ServiceEntry->Flink;
@@ -1836,7 +1842,7 @@ ScmAutoStartServices(VOID)
                 (CurrentService->ServiceVisited == FALSE))
             {
                 CurrentService->ServiceVisited = TRUE;
-                ScmStartService(CurrentService, 0, NULL);
+                ScmLoadService(CurrentService, 0, NULL);
             }
 
             ServiceEntry = ServiceEntry->Flink;
@@ -1856,7 +1862,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1873,7 +1879,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, 0, NULL);
+            ScmLoadService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1887,6 +1893,9 @@ ScmAutoStartServices(VOID)
         CurrentService->ServiceVisited = FALSE;
         ServiceEntry = ServiceEntry->Flink;
     }
+
+    /* Release the critical section */
+    LeaveCriticalSection(&ControlServiceCriticalSection);
 }
 
 
@@ -1966,7 +1975,7 @@ ScmInitNamedPipeCriticalSection(VOID)
                          L"ServicesPipeTimeout",
                          0,
                          NULL,
-                         (LPBYTE)&dwPipeTimeout,
+                         (LPBYTE)&PipeTimeout,
                          &dwKeySize);
 
        RegCloseKey(hKey);