Removed debug spamming from previous checkin
[reactos.git] / reactos / base / system / services / database.c
index 3a4ab91..8c4bac7 100644 (file)
@@ -1,25 +1,12 @@
 /*
- *
- * service control manager
- *
- * ReactOS Operating System
- *
- * --------------------------------------------------------------------
- *
- * This software is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of the
- * License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this software; see the file COPYING.LIB. If not, write
- * to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
- * MA 02139, USA.
+ * PROJECT:     ReactOS Service Control Manager
+ * LICENSE:     GPL - See COPYING in the top level directory
+ * FILE:        base/system/services/database.c
+ * PURPOSE:     Database control interface
+ * COPYRIGHT:   Copyright 2002-2006 Eric Kohl
+ *              Copyright 2006 HervĂ© Poussineau <hpoussin@reactos.org>
+ *              Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
+ *                             Gregor Brunmar <gregor.brunmar@home.se>
  *
  */
 
@@ -41,6 +28,7 @@ static DWORD dwResumeCount = 1;
 
 /* FUNCTIONS *****************************************************************/
 
+
 PSERVICE
 ScmGetServiceEntryByName(LPWSTR lpServiceName)
 {
@@ -128,6 +116,37 @@ ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
 }
 
 
+PSERVICE
+ScmGetServiceEntryByClientHandle(ULONG Handle)
+{
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+
+    DPRINT("ScmGetServiceEntryByClientHandle() called\n");
+    DPRINT("looking for %lu\n", Handle);
+
+    ServiceEntry = ServiceListHead.Flink;
+    while (ServiceEntry != &ServiceListHead)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry,
+                                           SERVICE,
+                                           ServiceListEntry);
+
+        if (CurrentService->hClient == Handle)
+        {
+            DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
+            return CurrentService;
+        }
+
+        ServiceEntry = ServiceEntry->Flink;
+    }
+
+    DPRINT("Couldn't find a matching service\n");
+
+    return NULL;
+}
+
+
 DWORD
 ScmCreateNewServiceRecord(LPWSTR lpServiceName,
                           PSERVICE *lpServiceRecord)
@@ -137,7 +156,7 @@ ScmCreateNewServiceRecord(LPWSTR lpServiceName,
     DPRINT("Service: '%S'\n", lpServiceName);
 
     /* Allocate service entry */
-    lpService = HeapAlloc(GetProcessHeap(),
+    lpService = (SERVICE*) HeapAlloc(GetProcessHeap(),
                           HEAP_ZERO_MEMORY,
                           sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
     if (lpService == NULL)
@@ -279,7 +298,10 @@ CreateServiceListEntry(LPWSTR lpServiceName,
     }
 
     DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
-    DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
+    if (lpService->lpGroup != NULL)
+    {
+        DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
+    }
     DPRINT("Start %lx  Type %lx  Tag %lx  ErrorControl %lx\n",
            lpService->dwStartType,
            lpService->Status.dwServiceType,
@@ -405,6 +427,18 @@ ScmCreateServiceDatabase(VOID)
 }
 
 
+VOID
+ScmShutdownServiceDatabase(VOID)
+{
+    DPRINT("ScmShutdownServiceDatabase() called\n");
+
+    ScmDeleteMarkedServices();
+    RtlDeleteResource(&DatabaseLock);
+
+    DPRINT("ScmShutdownServiceDatabase() done\n");
+}
+
+
 static NTSTATUS
 ScmCheckDriver(PSERVICE Service)
 {
@@ -446,7 +480,7 @@ ScmCheckDriver(PSERVICE Service)
 
     BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
                    2 * MAX_PATH * sizeof(WCHAR);
-    DirInfo = HeapAlloc(GetProcessHeap(),
+    DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
                         HEAP_ZERO_MEMORY,
                         BufferLength);
 
@@ -470,12 +504,12 @@ ScmCheckDriver(PSERVICE Service)
         if (!NT_SUCCESS(Status))
             break;
 
-        DPRINT("Comparing: '%S'  '%wZ'\n", Service->lpServiceName, &DirInfo->ObjectName);
+        DPRINT("Comparing: '%S'  '%wZ'\n", Service->lpServiceName, &DirInfo->Name);
 
-        if (_wcsicmp(Service->lpServiceName, DirInfo->ObjectName.Buffer) == 0)
+        if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0)
         {
             DPRINT("Found: '%S'  '%wZ'\n",
-                   Service->lpServiceName, &DirInfo->ObjectName);
+                   Service->lpServiceName, &DirInfo->Name);
 
             /* Mark service as 'running' */
             Service->Status.dwCurrentState = SERVICE_RUNNING;
@@ -528,14 +562,62 @@ ScmGetBootAndSystemDriverState(VOID)
 }
 
 
-static NTSTATUS
-ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
+DWORD
+ScmControlService(PSERVICE Service,
+                  DWORD dwControl,
+                  LPSERVICE_STATUS lpServiceStatus)
 {
-    PSCM_START_PACKET StartPacket;
+    PSCM_CONTROL_PACKET ControlPacket;
+    DWORD Count;
     DWORD TotalLength;
-#if 0
+
+    DPRINT("ScmControlService() called\n");
+
+    TotalLength = wcslen(Service->lpServiceName) + 1;
+
+    ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
+                                                   HEAP_ZERO_MEMORY,
+                                                   sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)));
+    if (ControlPacket == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
+
+    ControlPacket->dwControl = dwControl;
+    ControlPacket->hClient = Service->hClient;
+    ControlPacket->dwSize = TotalLength;
+    wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
+
+    /* Send the start command */
+    WriteFile(Service->ControlPipeHandle,
+              ControlPacket,
+              sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)),
+              &Count,
+              NULL);
+
+    /* FIXME: Read the reply */
+
+    /* Release the contol packet */
+    HeapFree(GetProcessHeap(),
+             0,
+             ControlPacket);
+
+    RtlCopyMemory(lpServiceStatus,
+                  &Service->Status,
+                  sizeof(SERVICE_STATUS));
+
+    DPRINT("ScmControlService) done\n");
+
+    return ERROR_SUCCESS;
+}
+
+
+static DWORD
+ScmSendStartCommand(PSERVICE Service,
+                    LPWSTR Arguments)
+{
+    PSCM_CONTROL_PACKET ControlPacket;
+    DWORD TotalLength;
+    DWORD ArgsLength = 0;
     DWORD Length;
-#endif
     PWSTR Ptr;
     DWORD Count;
 
@@ -543,7 +625,6 @@ ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
 
     /* Calculate the total length of the start command line */
     TotalLength = wcslen(Service->lpServiceName) + 1;
-#if 0
     if (Arguments != NULL)
     {
         Ptr = Arguments;
@@ -551,58 +632,72 @@ ScmSendStartCommand(PSERVICE Service, LPWSTR Arguments)
         {
             Length = wcslen(Ptr) + 1;
             TotalLength += Length;
+            ArgsLength += Length;
             Ptr += Length;
+            DPRINT("Arg: %S\n", Ptr);
         }
     }
-#endif
     TotalLength++;
+    DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength, 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;
+    /* Allocate a control packet */
+    ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
+                                                   HEAP_ZERO_MEMORY,
+                                                   sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
+    if (ControlPacket == NULL)
+        return ERROR_NOT_ENOUGH_MEMORY;
 
-    StartPacket->Command = SCM_START_COMMAND;
-    StartPacket->Size = TotalLength;
-    Ptr = &StartPacket->Arguments[0];
+    ControlPacket->dwControl = SERVICE_CONTROL_START;
+    ControlPacket->hClient = Service->hClient;
+    ControlPacket->dwSize = TotalLength;
+    Ptr = &ControlPacket->szArguments[0];
     wcscpy(Ptr, Service->lpServiceName);
     Ptr += (wcslen(Service->lpServiceName) + 1);
 
-    /* FIXME: Copy argument list */
+    /* Copy argument list */
+    if (Arguments != NULL)
+    {
+        memcpy(Ptr, Arguments, ArgsLength);
+        Ptr += ArgsLength;
+    }
 
+    /* Terminate the argument list */
     *Ptr = 0;
 
     /* Send the start command */
     WriteFile(Service->ControlPipeHandle,
-              StartPacket,
-              sizeof(SCM_START_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
+              ControlPacket,
+              sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
               &Count,
               NULL);
 
     /* FIXME: Read the reply */
 
+    /* Release the contol packet */
     HeapFree(GetProcessHeap(),
              0,
-             StartPacket);
+             ControlPacket);
 
     DPRINT("ScmSendStartCommand() done\n");
 
-    return STATUS_SUCCESS;
+    return ERROR_SUCCESS;
 }
 
 
-static NTSTATUS
-ScmStartUserModeService(PSERVICE Service)
+static DWORD
+ScmStartUserModeService(PSERVICE Service,
+                        LPWSTR lpArgs)
 {
     RTL_QUERY_REGISTRY_TABLE QueryTable[3];
     PROCESS_INFORMATION ProcessInformation;
     STARTUPINFOW StartupInfo;
     UNICODE_STRING ImagePath;
     ULONG Type;
+    DWORD ServiceCurrent = 0;
     BOOL Result;
     NTSTATUS Status;
+    DWORD dwError = ERROR_SUCCESS;
+    WCHAR NtControlPipeName[MAX_PATH + 1];
 
     RtlInitUnicodeString(&ImagePath, NULL);
 
@@ -626,13 +721,50 @@ ScmStartUserModeService(PSERVICE Service)
     if (!NT_SUCCESS(Status))
     {
         DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
-        return Status;
+        return RtlNtStatusToDosError(Status);
     }
     DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
     DPRINT("Type: %lx\n", Type);
 
-    /* Create '\\.\pipe\net\NtControlPipe' instance */
-    Service->ControlPipeHandle = CreateNamedPipeW(L"\\\\.\\pipe\\net\\NtControlPipe",
+    /* Get the service number */
+    RtlZeroMemory(&QueryTable,
+                  sizeof(QueryTable));
+
+    QueryTable[0].Name = L"";
+    QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+    QueryTable[0].EntryContext = &ServiceCurrent;
+
+    Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
+                                    L"ServiceCurrent",
+                                    QueryTable,
+                                    NULL,
+                                    NULL);
+
+    if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
+    {
+        /* TODO: Create registry entry with correct write access */
+    }
+    else if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+    else
+    {
+        ServiceCurrent++;
+    }
+
+    Status = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL, L"ServiceCurrent", L"", REG_DWORD, &ServiceCurrent, sizeof(ServiceCurrent));
+
+    if (!NT_SUCCESS(Status))
+    {
+        DPRINT1("RtlWriteRegistryValue() failed (Status %lx)\n", Status);
+        return RtlNtStatusToDosError(Status);
+    }
+
+    /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
+    swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
+    Service->ControlPipeHandle = CreateNamedPipeW(NtControlPipeName,
                                                   PIPE_ACCESS_DUPLEX,
                                                   PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
                                                   100,
@@ -640,11 +772,11 @@ ScmStartUserModeService(PSERVICE Service)
                                                   4,
                                                   30000,
                                                   NULL);
-    DPRINT("CreateNamedPipeW() done\n");
+    DPRINT1("CreateNamedPipeW(%S) done\n", NtControlPipeName);
     if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
     {
-        DPRINT1("Failed to create control pipe!\n");
-        return STATUS_UNSUCCESSFUL;
+        DPRINT("Failed to create control pipe!\n");
+        return GetLastError();
     }
 
     StartupInfo.cb = sizeof(StartupInfo);
@@ -669,12 +801,13 @@ ScmStartUserModeService(PSERVICE Service)
 
     if (!Result)
     {
+        dwError = GetLastError();
         /* Close control pipe */
         CloseHandle(Service->ControlPipeHandle);
         Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
 
         DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
-        return STATUS_UNSUCCESSFUL;
+        return dwError;
     }
 
     DPRINT("Process Id: %lu  Handle %lx\n",
@@ -692,60 +825,56 @@ ScmStartUserModeService(PSERVICE Service)
     ResumeThread(ProcessInformation.hThread);
 
     /* Connect control pipe */
-    if (ConnectNamedPipe(Service->ControlPipeHandle, NULL))
+    if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ?
+        TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
     {
-        DWORD dwProcessId = 0;
         DWORD dwRead = 0;
 
         DPRINT("Control pipe connected!\n");
 
-        /* Read thread id from pipe */
+        /* Read SERVICE_STATUS_HANDLE from pipe */
         if (!ReadFile(Service->ControlPipeHandle,
-                      (LPVOID)&dwProcessId,
+                      (LPVOID)&Service->hClient,
                       sizeof(DWORD),
                       &dwRead,
                       NULL))
         {
+            dwError = GetLastError();
             DPRINT1("Reading the service control pipe failed (Error %lu)\n",
-                    GetLastError());
-            Status = STATUS_UNSUCCESSFUL;
+                    dwError);
         }
         else
         {
-            DPRINT("Received process id %lu\n", dwProcessId);
+            DPRINT("Received service status %lu\n", Service->hClient);
 
-            /* FIXME: Send start command */
-
-            Status = STATUS_SUCCESS;
+            /* Send start command */
+            dwError = ScmSendStartCommand(Service, lpArgs);
         }
     }
     else
     {
-        DPRINT("Connecting control pipe failed!\n");
+        DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
 
         /* Close control pipe */
         CloseHandle(Service->ControlPipeHandle);
         Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
         Service->ProcessId = 0;
         Service->ThreadId = 0;
-        Status = STATUS_UNSUCCESSFUL;
     }
 
-    ScmSendStartCommand(Service, NULL);
-
     /* Close process and thread handle */
     CloseHandle(ProcessInformation.hThread);
     CloseHandle(ProcessInformation.hProcess);
 
-    return Status;
+    return dwError;
 }
 
 
-NTSTATUS
-ScmStartService(PSERVICE Service)
+DWORD
+ScmStartService(PSERVICE Service, LPWSTR lpArgs)
 {
     PSERVICE_GROUP Group = Service->lpGroup;
-    NTSTATUS Status;
+    DWORD dwError = ERROR_SUCCESS;
 
     DPRINT("ScmStartService() called\n");
 
@@ -755,19 +884,19 @@ ScmStartService(PSERVICE Service)
     if (Service->Status.dwServiceType & SERVICE_DRIVER)
     {
         /* Load driver */
-        Status = ScmLoadDriver(Service);
-        if (Status == STATUS_SUCCESS)
+        dwError = ScmLoadDriver(Service);
+        if (dwError == ERROR_SUCCESS)
             Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
     }
     else
     {
         /* Start user-mode service */
-        Status = ScmStartUserModeService(Service);
+        dwError = ScmStartUserModeService(Service, lpArgs);
     }
 
-    DPRINT("ScmStartService() done (Status %lx)\n", Status);
+    DPRINT("ScmStartService() done (Error %lu)\n", dwError);
 
-    if (NT_SUCCESS(Status))
+    if (dwError == ERROR_SUCCESS)
     {
         if (Group != NULL)
         {
@@ -805,7 +934,7 @@ ScmStartService(PSERVICE Service)
     }
 #endif
 
-    return Status;
+    return dwError;
 }
 
 
@@ -849,7 +978,7 @@ ScmAutoStartServices(VOID)
                     (CurrentService->dwTag == CurrentGroup->TagArray[i]))
                 {
                     CurrentService->ServiceVisited = TRUE;
-                    ScmStartService(CurrentService);
+                    ScmStartService(CurrentService, NULL);
                 }
 
                 ServiceEntry = ServiceEntry->Flink;
@@ -867,7 +996,7 @@ ScmAutoStartServices(VOID)
                 (CurrentService->ServiceVisited == FALSE))
             {
                 CurrentService->ServiceVisited = TRUE;
-                ScmStartService(CurrentService);
+                ScmStartService(CurrentService, NULL);
             }
 
             ServiceEntry = ServiceEntry->Flink;
@@ -887,7 +1016,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService);
+            ScmStartService(CurrentService, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -904,7 +1033,7 @@ ScmAutoStartServices(VOID)
             (CurrentService->ServiceVisited == FALSE))
         {
             CurrentService->ServiceVisited = TRUE;
-            ScmStartService(CurrentService);
+            ScmStartService(CurrentService, NULL);
         }
 
         ServiceEntry = ServiceEntry->Flink;
@@ -920,4 +1049,32 @@ ScmAutoStartServices(VOID)
     }
 }
 
+
+VOID
+ScmAutoShutdownServices(VOID)
+{
+    PLIST_ENTRY ServiceEntry;
+    PSERVICE CurrentService;
+    SERVICE_STATUS ServiceStatus;
+
+    DPRINT("ScmAutoShutdownServices() called\n");
+
+    ServiceEntry = ServiceListHead.Flink;
+    while (ServiceEntry != &ServiceListHead)
+    {
+        CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
+
+        if (CurrentService->Status.dwCurrentState == SERVICE_RUNNING ||
+            CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
+        {
+            /* shutdown service */
+            ScmControlService(CurrentService, SERVICE_CONTROL_STOP, &ServiceStatus);
+        }
+
+        ServiceEntry = ServiceEntry->Flink;
+    }
+
+    DPRINT("ScmGetBootAndSystemDriverState() done\n");
+}
+
 /* EOF */