/*
- *
- * 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>
*
*/
/* FUNCTIONS *****************************************************************/
+
PSERVICE
ScmGetServiceEntryByName(LPWSTR lpServiceName)
{
}
+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)
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)
}
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,
}
+VOID
+ScmShutdownServiceDatabase(VOID)
+{
+ DPRINT("ScmShutdownServiceDatabase() called\n");
+
+ ScmDeleteMarkedServices();
+ RtlDeleteResource(&DatabaseLock);
+
+ DPRINT("ScmShutdownServiceDatabase() done\n");
+}
+
+
static NTSTATUS
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);
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;
}
-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;
/* Calculate the total length of the start command line */
TotalLength = wcslen(Service->lpServiceName) + 1;
-#if 0
if (Arguments != NULL)
{
Ptr = 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);
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,
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);
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",
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");
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)
{
}
#endif
- return Status;
+ return dwError;
}
(CurrentService->dwTag == CurrentGroup->TagArray[i]))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService);
+ ScmStartService(CurrentService, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService);
+ ScmStartService(CurrentService, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService);
+ ScmStartService(CurrentService, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService);
+ ScmStartService(CurrentService, NULL);
}
ServiceEntry = ServiceEntry->Flink;
}
}
+
+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 */