Use the service contol pipe to send a start command in order to start a service thread.
authorEric Kohl <eric.kohl@reactos.org>
Fri, 28 Jan 2005 13:28:56 +0000 (13:28 +0000)
committerEric Kohl <eric.kohl@reactos.org>
Fri, 28 Jan 2005 13:28:56 +0000 (13:28 +0000)
svn path=/trunk/; revision=13350

reactos/include/services/services.h [new file with mode: 0644]
reactos/lib/advapi32/service/sctrl.c
reactos/subsys/system/services/database.c

diff --git a/reactos/include/services/services.h b/reactos/include/services/services.h
new file mode 100644 (file)
index 0000000..95818c0
--- /dev/null
@@ -0,0 +1,24 @@
+/* $Id$\r
+ *\r
+ * COPYRIGHT:   See COPYING in the top level directory\r
+ * PROJECT:     ReactOS kernel\r
+ * FILE:        include/services/services.h\r
+ * PURPOSE:     Private interface between SERVICES.EXE and ADVAPI32.DLL\r
+ * PROGRAMMER:  Eric Kohl\r
+ */\r
+\r
+#ifndef __SERVICES_SERVICES_H__\r
+#define __SERVICES_SERVICES_H__\r
+\r
+#define SCM_START_COMMAND 1\r
+\r
+typedef struct _SCM_START_PACKET\r
+{\r
+  ULONG Command;\r
+  ULONG Size;\r
+  WCHAR Arguments[1];\r
+} SCM_START_PACKET, *PSCM_START_PACKET;\r
+\r
+#endif /* __SERVICES_SERVICES_H__ */\r
+\r
+/* EOF */\r
index 7b033a5..defa64c 100644 (file)
@@ -13,6 +13,8 @@
 /* INCLUDES ******************************************************************/
 
 #include "advapi32.h"
+#include <services/services.h>
+
 #define NDEBUG
 #include <debug.h>
 
@@ -23,9 +25,15 @@ typedef struct _ACTIVE_SERVICE
 {
   DWORD ThreadId;
   UNICODE_STRING ServiceName;
-  LPSERVICE_MAIN_FUNCTIONW MainFunction;
+  union
+  {
+    LPSERVICE_MAIN_FUNCTIONA lpFuncA;
+    LPSERVICE_MAIN_FUNCTIONW lpFuncW;
+  } Main;
   LPHANDLER_FUNCTION HandlerFunction;
   SERVICE_STATUS ServiceStatus;
+  BOOL bUnicode;
+  LPWSTR Arguments;
 } ACTIVE_SERVICE, *PACTIVE_SERVICE;
 
 
@@ -33,7 +41,6 @@ typedef struct _ACTIVE_SERVICE
 
 static DWORD dwActiveServiceCount = 0;
 static PACTIVE_SERVICE lpActiveServices = NULL;
-/* static PHANDLE ActiveServicesThreadHandles; */ /* uncomment when in use */
 
 
 /* FUNCTIONS *****************************************************************/
@@ -80,15 +87,53 @@ static DWORD WINAPI
 ScServiceMainStub(LPVOID Context)
 {
   PACTIVE_SERVICE lpService;
+  DWORD dwArgCount = 0;
+  DWORD dwLength = 0;
 
   lpService = (PACTIVE_SERVICE)Context;
 
   DPRINT("ScServiceMainStub() called\n");
 
-  /* FIXME: Send argc and argv (from command line) as arguments */
+  /* Count arguments */
+  while (lpService->Arguments[dwLength])
+    {
+      dwLength += wcslen(&lpService->Arguments[dwLength]) + 1;
+      dwArgCount++;
+    }
+
+  /* Build the argument vector and call the main service routine */
+  if (lpService->bUnicode)
+    {
+      LPWSTR *lpArgVector;
+      LPWSTR Ptr;
+
+      lpArgVector = HeapAlloc(GetProcessHeap(),
+                             HEAP_ZERO_MEMORY,
+                             (dwArgCount + 1) * sizeof(LPWSTR));
+      if (lpArgVector == NULL)
+        return ERROR_OUTOFMEMORY;
+
+      dwArgCount = 0;
+      Ptr = lpService->Arguments;
+      while (*Ptr)
+       {
+         lpArgVector[dwArgCount] = Ptr;
 
+         dwArgCount++;
+         Ptr += (wcslen(Ptr) + 1);
+       }
+      lpArgVector[dwArgCount] = NULL;
 
-  (lpService->MainFunction)(0, NULL);
+      (lpService->Main.lpFuncW)(dwArgCount, lpArgVector);
+
+      HeapFree(GetProcessHeap(),
+              0,
+              lpArgVector);
+    }
+  else
+    {
+      (lpService->Main.lpFuncA)(0, NULL);
+    }
 
   return ERROR_SUCCESS;
 }
@@ -141,17 +186,29 @@ ScConnectControlPipe(HANDLE *hPipe)
 }
 
 
-static BOOL
-ScServiceDispatcher(HANDLE hPipe,
-                   PUCHAR lpBuffer,
-                   DWORD dwBufferSize)
+
+static DWORD
+ScStartService(PSCM_START_PACKET StartPacket)
 {
   PACTIVE_SERVICE lpService;
   HANDLE ThreadHandle;
 
-  DPRINT("ScDispatcherLoop() called\n");
+  DPRINT("Size: %lu\n", StartPacket->Size);
+  DPRINT("Service: %S\n", &StartPacket->Arguments[0]);
+
+  lpService = ScLookupServiceByServiceName(&StartPacket->Arguments[0]);
+  if (lpService == NULL)
+    return ERROR_SERVICE_DOES_NOT_EXIST;
 
-  lpService = &lpActiveServices[0];
+  lpService->Arguments = HeapAlloc(GetProcessHeap(),
+                                  HEAP_ZERO_MEMORY,
+                                  StartPacket->Size);
+  if (lpService->Arguments == NULL)
+    return ERROR_OUTOFMEMORY;
+
+  memcpy(lpService->Arguments,
+        StartPacket->Arguments,
+        StartPacket->Size * sizeof(WCHAR));
 
   ThreadHandle = CreateThread(NULL,
                              0,
@@ -160,21 +217,63 @@ ScServiceDispatcher(HANDLE hPipe,
                              CREATE_SUSPENDED,
                              &lpService->ThreadId);
   if (ThreadHandle == NULL)
-    return FALSE;
+    return ERROR_SERVICE_NO_THREAD;
 
   ResumeThread(ThreadHandle);
-
   CloseHandle(ThreadHandle);
 
-#if 0
+  return ERROR_SUCCESS;
+}
+
+
+static BOOL
+ScServiceDispatcher(HANDLE hPipe,
+                   PUCHAR lpBuffer,
+                   DWORD dwBufferSize)
+{
+  LPDWORD Buffer;
+  DWORD Count;
+  BOOL bResult;
+
+  DPRINT("ScDispatcherLoop() called\n");
+
+  Buffer = HeapAlloc(GetProcessHeap(),
+                     HEAP_ZERO_MEMORY,
+                     1024);
+  if (Buffer == NULL)
+    return FALSE;
+
   while (TRUE)
     {
       /* Read command from the control pipe */
+      bResult = ReadFile(hPipe,
+                        Buffer,
+                        1024,
+                        &Count,
+                        NULL);
+      if (bResult == FALSE)
+        {
+          DPRINT1("Pipe read failed\n");
+          return FALSE;
+        }
 
       /* Execute command */
-
+      switch (Buffer[0])
+        {
+          case SCM_START_COMMAND:
+            DPRINT("Start command\n");
+            ScStartService((PSCM_START_PACKET)Buffer);
+            break;
+
+          default:
+            DPRINT1("Unknown command %lu", Buffer[0]);
+            break;
+        }
     }
-#endif
+
+  HeapFree(GetProcessHeap(),
+           0,
+           Buffer);
 
   return TRUE;
 }
@@ -324,7 +423,8 @@ StartServiceCtrlDispatcherA(LPSERVICE_TABLE_ENTRYA lpServiceStartTable)
     {
       RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName,
                                       lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].MainFunction = (LPSERVICE_MAIN_FUNCTIONW)lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].Main.lpFuncA = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].bUnicode = FALSE;
     }
 
   dwError = ScConnectControlPipe(&hPipe);
@@ -400,7 +500,8 @@ StartServiceCtrlDispatcherW(LPSERVICE_TABLE_ENTRYW lpServiceStartTable)
     {
       RtlCreateUnicodeString(&lpActiveServices[i].ServiceName,
                             lpServiceStartTable[i].lpServiceName);
-      lpActiveServices[i].MainFunction = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].Main.lpFuncW = lpServiceStartTable[i].lpServiceProc;
+      lpActiveServices[i].bUnicode = TRUE;
     }
 
   dwError = ScConnectControlPipe(&hPipe);
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))