[SERVICES] Set default status to SERVICE_START_PENDING when starting a service.
[reactos.git] / reactos / base / system / services / database.c
index 13471d2..93a99e5 100644 (file)
@@ -30,7 +30,7 @@ static DWORD dwResumeCount = 1;
 
 
 PSERVICE
-ScmGetServiceEntryByName(LPWSTR lpServiceName)
+ScmGetServiceEntryByName(LPCWSTR lpServiceName)
 {
     PLIST_ENTRY ServiceEntry;
     PSERVICE CurrentService;
@@ -59,7 +59,7 @@ ScmGetServiceEntryByName(LPWSTR lpServiceName)
 
 
 PSERVICE
-ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
+ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName)
 {
     PLIST_ENTRY ServiceEntry;
     PSERVICE CurrentService;
@@ -117,13 +117,13 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 
 
 PSERVICE
-ScmGetServiceEntryByClientHandle(ULONG Handle)
+ScmGetServiceEntryByClientHandle(HANDLE Handle)
 {
     PLIST_ENTRY ServiceEntry;
     PSERVICE CurrentService;
 
     DPRINT("ScmGetServiceEntryByClientHandle() called\n");
-    DPRINT("looking for %lu\n", Handle);
+    DPRINT("looking for %p\n", Handle);
 
     ServiceEntry = ServiceListHead.Flink;
     while (ServiceEntry != &ServiceListHead)
@@ -148,7 +148,7 @@ ScmGetServiceEntryByClientHandle(ULONG Handle)
 
 
 DWORD
-ScmCreateNewServiceRecord(LPWSTR lpServiceName,
+ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
                           PSERVICE *lpServiceRecord)
 {
     PSERVICE lpService = NULL;
@@ -172,10 +172,11 @@ ScmCreateNewServiceRecord(LPWSTR lpServiceName,
     /* Set the resume count */
     lpService->dwResumeCount = dwResumeCount++;
 
-    /* Append service entry */
+    /* Append service record */
     InsertTailList(&ServiceListHead,
                    &lpService->ServiceListEntry);
 
+    /* Initialize the service status */
     lpService->Status.dwCurrentState = SERVICE_STOPPED;
     lpService->Status.dwControlsAccepted = 0;
     lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
@@ -187,8 +188,44 @@ ScmCreateNewServiceRecord(LPWSTR lpServiceName,
 }
 
 
+VOID
+ScmDeleteServiceRecord(PSERVICE lpService)
+{
+    DPRINT1("Deleting Service %S\n", lpService->lpServiceName);
+
+    /* Delete the display name */
+    if (lpService->lpDisplayName != NULL &&
+        lpService->lpDisplayName != lpService->lpServiceName)
+        HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
+
+    /* Decrement the image reference counter */
+    if (lpService->lpImage)
+        lpService->lpImage->dwServiceRefCount--;
+
+    /* Decrement the group reference counter */
+    if (lpService->lpGroup)
+        lpService->lpGroup->dwRefCount--;
+
+    /* FIXME: SecurityDescriptor */
+
+    /* Close the control pipe */
+    if (lpService->ControlPipeHandle != INVALID_HANDLE_VALUE)
+        CloseHandle(lpService->ControlPipeHandle);
+
+    /* Remove the Service from the List */
+    RemoveEntryList(&lpService->ServiceListEntry);
+
+    DPRINT1("Deleted Service %S\n", lpService->lpServiceName);
+
+    /* Delete the service record */
+    HeapFree(GetProcessHeap(), 0, lpService);
+
+    DPRINT1("Done\n");
+}
+
+
 static DWORD
-CreateServiceListEntry(LPWSTR lpServiceName,
+CreateServiceListEntry(LPCWSTR lpServiceName,
                        HKEY hServiceKey)
 {
     PSERVICE lpService = NULL;
@@ -322,11 +359,60 @@ done:;
 }
 
 
+DWORD
+ScmDeleteRegKey(HKEY hKey, LPCWSTR lpszSubKey)
+{
+    DWORD dwRet, dwMaxSubkeyLen = 0, dwSize;
+    WCHAR szNameBuf[MAX_PATH], *lpszName = szNameBuf;
+    HKEY hSubKey = 0;
+
+    dwRet = RegOpenKeyExW(hKey, lpszSubKey, 0, KEY_READ, &hSubKey);
+    if (!dwRet)
+    {
+        /* Find the maximum subkey length so that we can allocate a buffer */
+        dwRet = RegQueryInfoKeyW(hSubKey, NULL, NULL, NULL, NULL,
+                                                         &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
+        if (!dwRet)
+        {
+            dwMaxSubkeyLen++;
+            if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
+                /* Name too big: alloc a buffer for it */
+                lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
+
+            if(!lpszName)
+                dwRet = ERROR_NOT_ENOUGH_MEMORY;
+            else
+            {
+                while (dwRet == ERROR_SUCCESS)
+                {
+                    dwSize = dwMaxSubkeyLen;
+                    dwRet = RegEnumKeyExW(hSubKey, 0, lpszName, &dwSize, NULL, NULL, NULL, NULL);
+                    if (dwRet == ERROR_SUCCESS || dwRet == ERROR_MORE_DATA)
+                        dwRet = ScmDeleteRegKey(hSubKey, lpszName);
+                }
+                if (dwRet == ERROR_NO_MORE_ITEMS)
+                    dwRet = ERROR_SUCCESS;
+
+                if (lpszName != szNameBuf)
+                    HeapFree(GetProcessHeap(), 0, lpszName); /* Free buffer if allocated */
+            }
+        }
+
+        RegCloseKey(hSubKey);
+        if (!dwRet)
+            dwRet = RegDeleteKeyW(hKey, lpszSubKey);
+    }
+    return dwRet;
+}
+
+
 VOID
 ScmDeleteMarkedServices(VOID)
 {
     PLIST_ENTRY ServiceEntry;
     PSERVICE CurrentService;
+    HKEY hServicesKey;
+    DWORD dwError;
 
     ServiceEntry = ServiceListHead.Flink;
     while (ServiceEntry != &ServiceListHead)
@@ -337,14 +423,66 @@ ScmDeleteMarkedServices(VOID)
 
         if (CurrentService->bDeleted == TRUE)
         {
-            DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
+            dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+                                    L"System\\CurrentControlSet\\Services",
+                                    0,
+                                    DELETE,
+                                    &hServicesKey);
+            if (dwError == ERROR_SUCCESS)
+            {
+                dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName);
+                RegCloseKey(hServicesKey);
+                if (dwError == ERROR_SUCCESS)
+                {
+                    RemoveEntryList(&CurrentService->ServiceListEntry);
+                    HeapFree(GetProcessHeap(), 0, CurrentService);
+                }
+            }
+            
+            if (dwError != ERROR_SUCCESS)
+                DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
+        }
+    }
+}
+
 
-            /* FIXME: Delete the registry keys */
+VOID
+WaitForLSA(VOID)
+{
+    HANDLE hEvent;
+    DWORD dwError;
 
-            /* FIXME: Delete the service record from the list */
+    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");
 }
 
 
@@ -418,6 +556,9 @@ ScmCreateServiceDatabase(VOID)
 
     RegCloseKey(hServicesKey);
 
+    /* Wait for LSA */
+    WaitForLSA();
+
     /* Delete services that are marked for delete */
     ScmDeleteMarkedServices();
 
@@ -586,7 +727,7 @@ ScmControlService(PSERVICE Service,
     ControlPacket->dwSize = TotalLength;
     wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
 
-    /* Send the start command */
+    /* Send the control packet */
     WriteFile(Service->ControlPipeHandle,
               ControlPacket,
               sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)),
@@ -612,7 +753,8 @@ ScmControlService(PSERVICE Service,
 
 static DWORD
 ScmSendStartCommand(PSERVICE Service,
-                    LPWSTR Arguments)
+                    DWORD argc,
+                    LPWSTR *argv)
 {
     PSCM_CONTROL_PACKET ControlPacket;
     DWORD TotalLength;
@@ -625,16 +767,14 @@ ScmSendStartCommand(PSERVICE Service,
 
     /* Calculate the total length of the start command line */
     TotalLength = wcslen(Service->lpServiceName) + 1;
-    if (Arguments != NULL)
+    if (argc > 0)
     {
-        Ptr = Arguments;
-        while (*Ptr)
+        for (Count = 0; Count < argc; Count++)
         {
-            Length = wcslen(Ptr) + 1;
+            DPRINT("Arg: %S\n", argv[Count]);
+            Length = wcslen(argv[Count]) + 1;
             TotalLength += Length;
             ArgsLength += Length;
-            Ptr += Length;
-            DPRINT("Arg: %S\n", Ptr);
         }
     }
     TotalLength++;
@@ -655,10 +795,14 @@ ScmSendStartCommand(PSERVICE Service,
     Ptr += (wcslen(Service->lpServiceName) + 1);
 
     /* Copy argument list */
-    if (Arguments != NULL)
+    if (argc > 0)
     {
+        UNIMPLEMENTED;
+        DPRINT1("Arguments sent to service ignored!\n");
+#if 0
         memcpy(Ptr, Arguments, ArgsLength);
         Ptr += ArgsLength;
+#endif
     }
 
     /* Terminate the argument list */
@@ -686,7 +830,8 @@ ScmSendStartCommand(PSERVICE Service,
 
 static DWORD
 ScmStartUserModeService(PSERVICE Service,
-                        LPWSTR lpArgs)
+                        DWORD argc,
+                        LPWSTR *argv)
 {
     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
     PROCESS_INFORMATION ProcessInformation;
@@ -794,8 +939,8 @@ ScmStartUserModeService(PSERVICE Service,
     StartupInfo.cbReserved2 = 0;
     StartupInfo.lpReserved2 = 0;
 
-    Result = CreateProcessW(ImagePath.Buffer,
-                            NULL,
+    Result = CreateProcessW(NULL,
+                            ImagePath.Buffer,
                             NULL,
                             NULL,
                             FALSE,
@@ -855,7 +1000,7 @@ ScmStartUserModeService(PSERVICE Service,
             DPRINT("Received service status %lu\n", Service->hClient);
 
             /* Send start command */
-            dwError = ScmSendStartCommand(Service, lpArgs);
+            dwError = ScmSendStartCommand(Service, argc, argv);
         }
     }
     else
@@ -878,7 +1023,7 @@ ScmStartUserModeService(PSERVICE Service,
 
 
 DWORD
-ScmStartService(PSERVICE Service, LPWSTR lpArgs)
+ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
 {
     PSERVICE_GROUP Group = Service->lpGroup;
     DWORD dwError = ERROR_SUCCESS;
@@ -898,7 +1043,7 @@ ScmStartService(PSERVICE Service, LPWSTR lpArgs)
     else
     {
         /* Start user-mode service */
-        dwError = ScmStartUserModeService(Service, lpArgs);
+        dwError = ScmStartUserModeService(Service, argc, argv);
     }
 
     DPRINT("ScmStartService() done (Error %lu)\n", dwError);
@@ -909,7 +1054,7 @@ ScmStartService(PSERVICE Service, LPWSTR lpArgs)
         {
             Group->ServicesRunning = TRUE;
         }
-        Service->Status.dwCurrentState = SERVICE_RUNNING;
+        Service->Status.dwCurrentState = SERVICE_START_PENDING;
     }
 #if 0
     else
@@ -985,7 +1130,7 @@ ScmAutoStartServices(VOID)
                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                 {
                     CurrentService->ServiceVisited = TRUE;
-                    ScmStartService(CurrentService, NULL);
+                    ScmStartService(CurrentService, 0, NULL);
                 }
 
                 ServiceEntry = ServiceEntry->Flink;
@@ -1003,7 +1148,7 @@ ScmAutoStartServices(VOID)
                 (CurrentService->ServiceVisited == FALSE))
             {
                 CurrentService->ServiceVisited = TRUE;
-                ScmStartService(CurrentService, NULL);
+                ScmStartService(CurrentService, 0, NULL);
             }
 
             ServiceEntry = ServiceEntry->Flink;
@@ -1023,7 +1168,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, NULL);
+            ScmStartService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -1040,7 +1185,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService, NULL);
+            ScmStartService(CurrentService, 0, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;