Use the service contol pipe to send a start command in order to start a service thread.
[reactos.git] / reactos / subsys / system / services / database.c
index 6348f3d..033e019 100644 (file)
@@ -32,6 +32,7 @@
 #include <windows.h>
 #include <tchar.h>
 
+#include <services/services.h>
 #include "services.h"
 
 #define NDEBUG
@@ -521,8 +522,72 @@ ScmGetBootAndSystemDriverState(VOID)
 
 
 static NTSTATUS
-ScmStartService(PSERVICE Service,
-               PSERVICE_GROUP Group)
+ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
+{
+  PSCM_START_PACKET StartPacket;
+  DWORD TotalLength;
+#if 0
+  DWORD Length;
+#endif
+  PWSTR Ptr;
+  DWORD Count;
+
+  DPRINT("ScmSendStartCommand() called\n");
+
+  /* Calculate the total length of the start command line */
+  TotalLength = wcslen(Service->ServiceName.Buffer) + 1;
+#if 0
+  if (Arguments != NULL)
+  {
+    Ptr = Arguments;
+    while (*Ptr)
+    {
+      Length = wcslen(Ptr) + 1;
+      TotalLength += Length;
+      Ptr += Length;
+    }
+  }
+#endif
+  TotalLength++;
+
+  /* Allocate start command packet */
+  StartPacket = HeapAlloc(GetProcessHeap(),
+                         HEAP_ZERO_MEMORY,
+                         sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
+  if (StartPacket == NULL)
+    return STATUS_INSUFFICIENT_RESOURCES;
+
+  StartPacket->Command = SCM_START_COMMAND;
+  StartPacket->Size = TotalLength;
+  Ptr = &StartPacket->Arguments[0];
+  wcscpy(Ptr, Service->ServiceName.Buffer);
+  Ptr += (wcslen(Service->ServiceName.Buffer) + 1);
+
+  /* FIXME: Copy argument list */
+
+  *Ptr = 0;
+
+  /* Send the start command */
+  WriteFile(Service->ControlPipeHandle,
+           StartPacket,
+           sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
+           &Count,
+           NULL);
+
+  /* FIXME: Read the reply */
+
+  HeapFree(GetProcessHeap(),
+           0,
+           StartPacket);
+
+  DPRINT("ScmSendStartCommand() done\n");
+
+  return STATUS_SUCCESS;
+}
+
+
+static NTSTATUS
+ScmStartUserModeService(PSERVICE Service)
 {
   RTL_QUERY_REGISTRY_TABLE QueryTable[3];
   PROCESS_INFORMATION ProcessInformation;
@@ -532,153 +597,168 @@ ScmStartService(PSERVICE Service,
   BOOL Result;
   NTSTATUS Status;
 
-  DPRINT("ScmStartService() called\n");
+  RtlInitUnicodeString(&ImagePath, NULL);
 
-  Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
-  DPRINT("Service->Type: %u\n", Service->Type);
+  /* Get service data */
+  RtlZeroMemory(&QueryTable,
+               sizeof(QueryTable));
 
-  if (Service->Type == SERVICE_KERNEL_DRIVER ||
-      Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
-      Service->Type == SERVICE_RECOGNIZER_DRIVER)
+  QueryTable[0].Name = L"Type";
+  QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+  QueryTable[0].EntryContext = &Type;
+
+  QueryTable[1].Name = L"ImagePath";
+  QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+  QueryTable[1].EntryContext = &ImagePath;
+
+  Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+                                 Service->ServiceName.Buffer,
+                                 QueryTable,
+                                 NULL,
+                                 NULL);
+  if (!NT_SUCCESS(Status))
     {
-      /* Load driver */
-      DPRINT("  Path: %wZ\n", &Service->RegistryPath);
-      Status = NtLoadDriver(&Service->RegistryPath);
+      DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+      return Status;
     }
-  else
+  DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
+  DPRINT("Type: %lx\n", Type);
+
+  /* Create '\\.\pipe\net\NtControlPipe' instance */
+  Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
+                                               PIPE_ACCESS_DUPLEX,
+                                               PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+                                               100,
+                                               8000,
+                                               4,
+                                               30000,
+                                               NULL);
+  DPRINT("CreateNamedPipeW() done\n");
+  if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
     {
-      RtlInitUnicodeString(&ImagePath, NULL);
+      DPRINT1("Failed to create control pipe!\n");
+      return STATUS_UNSUCCESSFUL;
+    }
 
-      /* Get service data */
-      RtlZeroMemory(&QueryTable,
-                   sizeof(QueryTable));
+  StartupInfo.cb = sizeof(StartupInfo);
+  StartupInfo.lpReserved = NULL;
+  StartupInfo.lpDesktop = NULL;
+  StartupInfo.lpTitle = NULL;
+  StartupInfo.dwFlags = 0;
+  StartupInfo.cbReserved2 = 0;
+  StartupInfo.lpReserved2 = 0;
+
+  Result = CreateProcessW(ImagePath.Buffer,
+                         NULL,
+                         NULL,
+                         NULL,
+                         FALSE,
+                         DETACHED_PROCESS | CREATE_SUSPENDED,
+                         NULL,
+                         NULL,
+                         &StartupInfo,
+                         &ProcessInformation);
+  RtlFreeUnicodeString(&ImagePath);
+
+  if (!Result)
+    {
+      /* Close control pipe */
+      CloseHandle(Service->ControlPipeHandle);
+      Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
 
-      QueryTable[0].Name = L"Type";
-      QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
-      QueryTable[0].EntryContext = &Type;
+      DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
+      return STATUS_UNSUCCESSFUL;
+    }
 
-      QueryTable[1].Name = L"ImagePath";
-      QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
-      QueryTable[1].EntryContext = &ImagePath;
+  DPRINT("Process Id: %lu  Handle %lx\n",
+        ProcessInformation.dwProcessId,
+        ProcessInformation.hProcess);
+  DPRINT("Thread Id: %lu  Handle %lx\n",
+        ProcessInformation.dwThreadId,
+        ProcessInformation.hThread);
 
-      Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
-                                     Service->ServiceName.Buffer,
-                                     QueryTable,
-                                     NULL,
-                                     NULL);
-      if (NT_SUCCESS(Status))
+  /* Get process and thread ids */
+  Service->ProcessId = ProcessInformation.dwProcessId;
+  Service->ThreadId = ProcessInformation.dwThreadId;
+
+  /* Resume Thread */
+  ResumeThread(ProcessInformation.hThread);
+
+  /* Connect control pipe */
+  if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
+    {
+      DWORD dwProcessId = 0;
+      DWORD dwRead = 0;
+
+      DPRINT("Control pipe connected!\n");
+
+      /* Read thread id from pipe */
+      if (!ReadFile(Service->ControlPipeHandle,
+                   (LPVOID)&dwProcessId,
+                   sizeof(DWORD),
+                   &dwRead,
+                   NULL))
        {
-         DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
-         DPRINT("Type: %lx\n", Type);
-
-         /* FIXME: create '\\.\pipe\net\NtControlPipe' instance */
-         Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
-                                                       PIPE_ACCESS_DUPLEX,
-                                                       PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
-                                                       100,
-                                                       8000,
-                                                       4,
-                                                       30000,
-                                                       NULL);
-         DPRINT("CreateNamedPipeW() done\n");
-         if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
-           {
-             DPRINT1("Failed to create control pipe!\n");
-             Status = STATUS_UNSUCCESSFUL;
-             goto Done;
-           }
+         DPRINT1("Reading the service control pipe failed (Error %lu)\n",
+                 GetLastError());
+         Status = STATUS_UNSUCCESSFUL;
+       }
+      else
+       {
+         DPRINT("Received process id %lu\n", dwProcessId);
 
-         StartupInfo.cb = sizeof(StartupInfo);
-         StartupInfo.lpReserved = NULL;
-         StartupInfo.lpDesktop = NULL;
-         StartupInfo.lpTitle = NULL;
-         StartupInfo.dwFlags = 0;
-         StartupInfo.cbReserved2 = 0;
-         StartupInfo.lpReserved2 = 0;
+         /* FIXME: Send start command */
 
-         Result = CreateProcessW(ImagePath.Buffer,
-                                 NULL,
-                                 NULL,
-                                 NULL,
-                                 FALSE,
-                                 DETACHED_PROCESS | CREATE_SUSPENDED,
-                                 NULL,
-                                 NULL,
-                                 &StartupInfo,
-                                 &ProcessInformation);
-         RtlFreeUnicodeString(&ImagePath);
+         Status = STATUS_SUCCESS;
+       }
+    }
+  else
+    {
+      DPRINT("Connecting control pipe failed!\n");
+
+      /* Close control pipe */
+      CloseHandle(Service->ControlPipeHandle);
+      Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+      Service->ProcessId = 0;
+      Service->ThreadId = 0;
+      Status = STATUS_UNSUCCESSFUL;
+    }
 
-         if (!Result)
-           {
-             /* Close control pipe */
-             CloseHandle(Service->ControlPipeHandle);
-             Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+  ScmSendStartCommand(Service, NULL);
 
-             DPRINT1("Starting '%S' failed!\n", Service->ServiceName.Buffer);
-             Status = STATUS_UNSUCCESSFUL;
-           }
-         else
-           {
-             DPRINT("Process Id: %lu  Handle %lx\n",
-                    ProcessInformation.dwProcessId,
-                    ProcessInformation.hProcess);
-             DPRINT("Thread Id: %lu  Handle %lx\n",
-                    ProcessInformation.dwThreadId,
-                    ProcessInformation.hThread);
-
-             /* Get process and thread ids */
-             Service->ProcessId = ProcessInformation.dwProcessId;
-             Service->ThreadId = ProcessInformation.dwThreadId;
-
-             /* Resume Thread */
-             ResumeThread(ProcessInformation.hThread);
-
-             /* Connect control pipe */
-             if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
-               {
-                 DWORD dwProcessId = 0;
-                 DWORD dwRead = 0;
+  /* Close process and thread handle */
+  CloseHandle(ProcessInformation.hThread);
+  CloseHandle(ProcessInformation.hProcess);
 
-                 DPRINT("Control pipe connected!\n");
+  return Status;
+}
 
-                 /* FIXME: Read thread id from pipe */
-                 if (!ReadFile(Service->ControlPipeHandle,
-                               (LPVOID)&dwProcessId,
-                               sizeof(DWORD),
-                               &dwRead,
-                               NULL))
-                   {
-                     DPRINT1("Reading the service control pipe failed (Error %lu)\n", GetLastError());
-                   }
-                 else
-                   {
-                     DPRINT("Received process id %lu\n", dwProcessId);
 
-                     /* FIXME: Send start command */
+static NTSTATUS
+ScmStartService(PSERVICE Service,
+               PSERVICE_GROUP Group)
+{
+  NTSTATUS Status;
 
-                     Status = STATUS_SUCCESS;
-                   }
-               }
-             else
-               {
-                 DPRINT("Connecting control pipe failed!\n");
-
-                 /* Close control pipe */
-                 CloseHandle(Service->ControlPipeHandle);
-                 Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
-                 Service->ProcessId = 0;
-                 Service->ThreadId = 0;
-                 Status = STATUS_UNSUCCESSFUL;
-               }
+  DPRINT("ScmStartService() called\n");
 
-             /* Close process and thread handle */
-             CloseHandle(ProcessInformation.hThread);
-             CloseHandle(ProcessInformation.hProcess);
-           }
-       }
+  Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
+  DPRINT("Service->Type: %u\n", Service->Type);
+
+  if (Service->Type == SERVICE_KERNEL_DRIVER ||
+      Service->Type == SERVICE_FILE_SYSTEM_DRIVER ||
+      Service->Type == SERVICE_RECOGNIZER_DRIVER)
+    {
+      /* Load driver */
+      DPRINT("  Path: %wZ\n", &Service->RegistryPath);
+      Status = NtLoadDriver(&Service->RegistryPath);
+    }
+  else
+    {
+      /* Start user-mode service */
+      Status = ScmStartUserModeService(Service);
     }
 
-Done:
   DPRINT("ScmStartService() done (Status %lx)\n", Status);
 
   if (NT_SUCCESS(Status))