/*
* Uncomment the line below to start services
- * using the SERVICE_START_PENDING state
+ * using the SERVICE_START_PENDING state.
*/
-// #define USE_SERVICE_START_PENDING
+#define USE_SERVICE_START_PENDING
+
+/*
+ * Uncomment the line below to use asynchronous IO operations
+ * on the service control pipes.
+ */
+// #define USE_ASYNCHRONOUS_IO
+
/* GLOBALS *******************************************************************/
+LIST_ENTRY ImageListHead;
LIST_ENTRY ServiceListHead;
static RTL_RESOURCE DatabaseLock;
-static DWORD dwResumeCount = 1;
+static DWORD ResumeCount = 1;
+
+/* The critical section synchronizes service control requests */
+static CRITICAL_SECTION ControlServiceCriticalSection;
+static DWORD PipeTimeout = 30000; /* 30 Seconds */
/* FUNCTIONS *****************************************************************/
+static DWORD
+ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage)
+{
+ WCHAR szControlPipeName[MAX_PATH + 1];
+ HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
+ DWORD ServiceCurrent = 0;
+ DWORD KeyDisposition;
+ DWORD dwKeySize;
+ DWORD dwError;
+
+ /* Get the service number */
+ /* TODO: Create registry entry with correct write access */
+ dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
+ REG_OPTION_VOLATILE,
+ KEY_WRITE | KEY_READ,
+ NULL,
+ &hServiceCurrentKey,
+ &KeyDisposition);
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError);
+ return dwError;
+ }
+
+ if (KeyDisposition == REG_OPENED_EXISTING_KEY)
+ {
+ dwKeySize = sizeof(DWORD);
+ dwError = RegQueryValueExW(hServiceCurrentKey,
+ L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize);
+
+ if (dwError != ERROR_SUCCESS)
+ {
+ RegCloseKey(hServiceCurrentKey);
+ DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError);
+ return dwError;
+ }
+
+ ServiceCurrent++;
+ }
+
+ dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
+
+ RegCloseKey(hServiceCurrentKey);
+
+ if (dwError != ERROR_SUCCESS)
+ {
+ DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError);
+ return dwError;
+ }
+
+ /* Create '\\.\pipe\net\NtControlPipeXXX' instance */
+ swprintf(szControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", ServiceCurrent);
+
+ DPRINT("PipeName: %S\n", szControlPipeName);
+
+ pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName,
+#ifdef USE_ASYNCHRONOUS_IO
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+#else
+ PIPE_ACCESS_DUPLEX,
+#endif
+ PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
+ 100,
+ 8000,
+ 4,
+ PipeTimeout,
+ NULL);
+ DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName);
+ if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE)
+ {
+ DPRINT1("Failed to create control pipe!\n");
+ return GetLastError();
+ }
+
+ return ERROR_SUCCESS;
+}
+
+
+static PSERVICE_IMAGE
+ScmGetServiceImageByImagePath(LPWSTR lpImagePath)
+{
+ PLIST_ENTRY ImageEntry;
+ PSERVICE_IMAGE CurrentImage;
+
+ DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath);
+
+ ImageEntry = ImageListHead.Flink;
+ while (ImageEntry != &ImageListHead)
+ {
+ CurrentImage = CONTAINING_RECORD(ImageEntry,
+ SERVICE_IMAGE,
+ ImageListEntry);
+ if (_wcsicmp(CurrentImage->szImagePath, lpImagePath) == 0)
+ {
+ DPRINT("Found image: '%S'\n", CurrentImage->szImagePath);
+ return CurrentImage;
+ }
+
+ ImageEntry = ImageEntry->Flink;
+ }
+
+ DPRINT("Couldn't find a matching image\n");
+
+ return NULL;
+
+}
+
+
+static DWORD
+ScmCreateOrReferenceServiceImage(PSERVICE pService)
+{
+ RTL_QUERY_REGISTRY_TABLE QueryTable[2];
+ UNICODE_STRING ImagePath;
+ PSERVICE_IMAGE pServiceImage = NULL;
+ NTSTATUS Status;
+ DWORD dwError = ERROR_SUCCESS;
+
+ DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService);
+
+ RtlInitUnicodeString(&ImagePath, NULL);
+
+ /* Get service data */
+ RtlZeroMemory(&QueryTable,
+ sizeof(QueryTable));
+
+ QueryTable[0].Name = L"ImagePath";
+ QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
+ QueryTable[0].EntryContext = &ImagePath;
+
+ Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
+ pService->lpServiceName,
+ QueryTable,
+ NULL,
+ NULL);
+ if (!NT_SUCCESS(Status))
+ {
+ DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
+ return RtlNtStatusToDosError(Status);
+ }
+
+ DPRINT("ImagePath: '%wZ'\n", &ImagePath);
+
+ pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer);
+ if (pServiceImage == NULL)
+ {
+ /* Create a new service image */
+ pServiceImage = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ FIELD_OFFSET(SERVICE_IMAGE, szImagePath[ImagePath.Length / sizeof(WCHAR) + 1]));
+ if (pServiceImage == NULL)
+ {
+ dwError = ERROR_NOT_ENOUGH_MEMORY;
+ goto done;
+ }
+
+ pServiceImage->dwImageRunCount = 1;
+ pServiceImage->hControlPipe = INVALID_HANDLE_VALUE;
+
+ /* Set the image path */
+ wcscpy(pServiceImage->szImagePath,
+ ImagePath.Buffer);
+
+ RtlFreeUnicodeString(&ImagePath);
+
+ /* Create the control pipe */
+ dwError = ScmCreateNewControlPipe(pServiceImage);
+ if (dwError != ERROR_SUCCESS)
+ {
+ HeapFree(GetProcessHeap(), 0, pServiceImage);
+ goto done;
+ }
+
+ /* FIXME: Add more initialization code here */
+
+
+ /* Append service record */
+ InsertTailList(&ImageListHead,
+ &pServiceImage->ImageListEntry);
+ }
+ else
+ {
+ /* Increment the run counter */
+ pServiceImage->dwImageRunCount++;
+ }
+
+ DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount);
+
+ /* Link the service image to the service */
+ pService->lpImage = pServiceImage;
+
+done:;
+ RtlFreeUnicodeString(&ImagePath);
+
+ DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError);
+
+ return dwError;
+}
+
+
+static VOID
+ScmDereferenceServiceImage(PSERVICE_IMAGE pServiceImage)
+{
+ DPRINT1("ScmDereferenceServiceImage() called\n");
+
+ pServiceImage->dwImageRunCount--;
+
+ if (pServiceImage->dwImageRunCount == 0)
+ {
+ DPRINT1("dwImageRunCount == 0\n");
+
+ /* FIXME: Terminate the process */
+
+ /* Remove the service image from the list */
+ RemoveEntryList(&pServiceImage->ImageListEntry);
+
+ /* Close the control pipe */
+ if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE)
+ CloseHandle(pServiceImage->hControlPipe);
+
+ /* Release the service image */
+ HeapFree(GetProcessHeap(), 0, pServiceImage);
+ }
+}
+
PSERVICE
ScmGetServiceEntryByName(LPCWSTR lpServiceName)
DWORD
ScmCreateNewServiceRecord(LPCWSTR lpServiceName,
- PSERVICE *lpServiceRecord)
+ PSERVICE* lpServiceRecord)
{
PSERVICE lpService = NULL;
DPRINT("Service: '%S'\n", lpServiceName);
/* Allocate service entry */
- lpService = (SERVICE*) HeapAlloc(GetProcessHeap(),
+ lpService = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
- sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
+ FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1]));
if (lpService == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
lpService->lpDisplayName = lpService->lpServiceName;
/* Set the resume count */
- lpService->dwResumeCount = dwResumeCount++;
+ lpService->dwResumeCount = ResumeCount++;
/* Append service record */
InsertTailList(&ServiceListHead,
lpService->lpDisplayName != lpService->lpServiceName)
HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
- /* Decrement the image reference counter */
+ /* Dereference the service image */
if (lpService->lpImage)
- lpService->lpImage->dwServiceRefCount--;
+ ScmDereferenceServiceImage(lpService->lpImage);
/* Decrement the group reference counter */
if (lpService->lpGroup)
/* FIXME: SecurityDescriptor */
- /* Close the control pipe */
- if (lpService->ControlPipeHandle != INVALID_HANDLE_VALUE)
- CloseHandle(lpService->ControlPipeHandle);
/* Remove the Service from the List */
RemoveEntryList(&lpService->ServiceListEntry);
if (lpDisplayName != NULL)
HeapFree(GetProcessHeap(), 0, lpDisplayName);
+ if (lpService != NULL)
+ {
+ if (lpService->lpImage != NULL)
+ ScmDereferenceServiceImage(lpService->lpImage);
+ }
+
return dwError;
}
{
/* 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);
+ &dwMaxSubkeyLen, NULL, NULL, NULL, NULL, NULL, NULL);
if (!dwRet)
{
dwMaxSubkeyLen++;
- if (dwMaxSubkeyLen > sizeof(szNameBuf)/sizeof(WCHAR))
+ if (dwMaxSubkeyLen > sizeof(szNameBuf) / sizeof(WCHAR))
+ {
/* Name too big: alloc a buffer for it */
- lpszName = HeapAlloc(GetProcessHeap(), 0, dwMaxSubkeyLen*sizeof(WCHAR));
+ lpszName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwMaxSubkeyLen * sizeof(WCHAR));
+ }
- if(!lpszName)
+ if (!lpszName)
dwRet = ERROR_NOT_ENOUGH_MEMORY;
else
{
HeapFree(GetProcessHeap(), 0, CurrentService);
}
}
-
+
if (dwError != ERROR_SUCCESS)
DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName);
}
}
-VOID
-WaitForLSA(VOID)
-{
- HANDLE hEvent;
- DWORD dwError;
-
- 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");
-}
-
-
DWORD
ScmCreateServiceDatabase(VOID)
{
return dwError;
/* Initialize basic variables */
+ InitializeListHead(&ImageListHead);
InitializeListHead(&ServiceListHead);
/* Initialize the database lock */
RegCloseKey(hServicesKey);
- /* Wait for LSA */
- WaitForLSA();
+ /* Wait for the LSA server */
+ ScmWaitForLsa();
/* Delete services that are marked for delete */
ScmDeleteMarkedServices();
if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
{
- RtlInitUnicodeString(&DirName,
- L"\\Driver");
+ RtlInitUnicodeString(&DirName, L"\\Driver");
}
- else
+ else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER)
{
- RtlInitUnicodeString(&DirName,
- L"\\FileSystem");
+ ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER);
+ RtlInitUnicodeString(&DirName, L"\\FileSystem");
}
InitializeObjectAttributes(&ObjectAttributes,
}
BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
- 2 * MAX_PATH * sizeof(WCHAR);
- DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
+ 2 * MAX_PATH * sizeof(WCHAR);
+ DirInfo = HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
BufferLength);
DWORD dwWriteCount = 0;
DWORD dwReadCount = 0;
- DWORD TotalLength;
+ DWORD PacketSize;
+ PWSTR Ptr;
DWORD dwError = ERROR_SUCCESS;
+ BOOL bResult;
+#ifdef USE_ASYNCHRONOUS_IO
+ OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+#endif
DPRINT("ScmControlService() called\n");
- TotalLength = wcslen(Service->lpServiceName) + 1;
+ /* Acquire the service control critical section, to synchronize requests */
+ EnterCriticalSection(&ControlServiceCriticalSection);
+
+ /* Calculate the total length of the start command line */
+ PacketSize = sizeof(SCM_CONTROL_PACKET);
+ PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
- ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)));
+ ControlPacket = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ PacketSize);
if (ControlPacket == NULL)
+ {
+ LeaveCriticalSection(&ControlServiceCriticalSection);
return ERROR_NOT_ENOUGH_MEMORY;
+ }
+ ControlPacket->dwSize = PacketSize;
ControlPacket->dwControl = dwControl;
- ControlPacket->dwSize = TotalLength;
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
- wcscpy(&ControlPacket->szArguments[0], Service->lpServiceName);
+ ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
+
+ Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
+ wcscpy(Ptr, Service->lpServiceName);
+
+ ControlPacket->dwArgumentsCount = 0;
+ ControlPacket->dwArgumentsOffset = 0;
+
+#ifdef USE_ASYNCHRONOUS_IO
+ bResult = WriteFile(Service->lpImage->hControlPipe,
+ ControlPacket,
+ PacketSize,
+ &dwWriteCount,
+ &Overlapped);
+ if (bResult == FALSE)
+ {
+ DPRINT1("WriteFile() returned FALSE\n");
+
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
+ {
+ DPRINT1("dwError: ERROR_IO_PENDING\n");
+
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+
+ if (dwError == WAIT_TIMEOUT)
+ {
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
+
+ dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto Done;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwWriteCount,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
+
+ goto Done;
+ }
+ }
+ }
+ else
+ {
+ DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
+ goto Done;
+ }
+ }
+
+ /* Read the reply */
+ Overlapped.hEvent = (HANDLE) NULL;
+
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ &ReplyPacket,
+ sizeof(SCM_REPLY_PACKET),
+ &dwReadCount,
+ &Overlapped);
+ if (bResult == FALSE)
+ {
+ DPRINT1("ReadFile() returned FALSE\n");
+
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
+ {
+ DPRINT1("dwError: ERROR_IO_PENDING\n");
+
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+
+ if (dwError == WAIT_TIMEOUT)
+ {
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
+
+ dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto Done;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwReadCount,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
+
+ goto Done;
+ }
+ }
+ }
+ else
+ {
+ DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
+ goto Done;
+ }
+ }
+
+#else
/* Send the control packet */
- WriteFile(Service->ControlPipeHandle,
- ControlPacket,
- sizeof(SCM_CONTROL_PACKET) + (TotalLength * sizeof(WCHAR)),
- &dwWriteCount,
- NULL);
+ bResult = WriteFile(Service->lpImage->hControlPipe,
+ ControlPacket,
+ PacketSize,
+ &dwWriteCount,
+ NULL);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT("WriteFile() failed (Error %lu)\n", dwError);
+
+ if ((dwError == ERROR_GEN_FAILURE) &&
+ (dwControl == SERVICE_CONTROL_STOP))
+ {
+ /* Service is already terminated */
+ Service->Status.dwCurrentState = SERVICE_STOPPED;
+ Service->Status.dwControlsAccepted = 0;
+ Service->Status.dwWin32ExitCode = ERROR_SERVICE_NOT_ACTIVE;
+ dwError = ERROR_SUCCESS;
+ }
+ goto Done;
+ }
/* Read the reply */
- ReadFile(Service->ControlPipeHandle,
- &ReplyPacket,
- sizeof(SCM_REPLY_PACKET),
- &dwReadCount,
- NULL);
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ &ReplyPacket,
+ sizeof(SCM_REPLY_PACKET),
+ &dwReadCount,
+ NULL);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT("ReadFile() failed (Error %lu)\n", dwError);
+ }
+#endif
+Done:
/* Release the contol packet */
HeapFree(GetProcessHeap(),
0,
dwError = ReplyPacket.dwError;
}
+ if (dwError == ERROR_SUCCESS &&
+ dwControl == SERVICE_CONTROL_STOP)
+ {
+ ScmDereferenceServiceImage(Service->lpImage);
+ }
+
+ LeaveCriticalSection(&ControlServiceCriticalSection);
+
DPRINT("ScmControlService() done\n");
return dwError;
static DWORD
ScmSendStartCommand(PSERVICE Service,
DWORD argc,
- LPWSTR *argv)
+ LPWSTR* argv)
{
PSCM_CONTROL_PACKET ControlPacket;
SCM_REPLY_PACKET ReplyPacket;
- DWORD TotalLength;
- DWORD ArgsLength = 0;
- DWORD Length;
+ DWORD PacketSize;
PWSTR Ptr;
DWORD dwWriteCount = 0;
DWORD dwReadCount = 0;
DWORD dwError = ERROR_SUCCESS;
DWORD i;
+ PWSTR *pOffPtr;
+ PWSTR pArgPtr;
+ BOOL bResult;
+#ifdef USE_ASYNCHRONOUS_IO
+ OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+#endif
DPRINT("ScmSendStartCommand() called\n");
/* Calculate the total length of the start command line */
- TotalLength = wcslen(Service->lpServiceName) + 1;
- if (argc > 0)
+ PacketSize = sizeof(SCM_CONTROL_PACKET) +
+ (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR));
+
+ /* Calculate the required packet size for the start arguments */
+ if (argc > 0 && argv != NULL)
{
+ PacketSize = ALIGN_UP(PacketSize, LPWSTR);
+
+ DPRINT("Argc: %lu\n", argc);
for (i = 0; i < argc; i++)
{
- DPRINT("Arg: %S\n", argv[i]);
- Length = wcslen(argv[i]) + 1;
- TotalLength += Length;
- ArgsLength += Length;
+ DPRINT("Argv[%lu]: %S\n", i, argv[i]);
+ PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR) + sizeof(PWSTR));
}
}
- TotalLength++;
- DPRINT("ArgsLength: %ld TotalLength: %ld\n", ArgsLength, TotalLength);
/* Allocate a control packet */
- ControlPacket = (SCM_CONTROL_PACKET*)HeapAlloc(GetProcessHeap(),
- HEAP_ZERO_MEMORY,
- sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR));
+ ControlPacket = HeapAlloc(GetProcessHeap(),
+ HEAP_ZERO_MEMORY,
+ PacketSize);
if (ControlPacket == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
- ControlPacket->dwControl = SERVICE_CONTROL_START;
+ ControlPacket->dwSize = PacketSize;
+ ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS)
+ ? SERVICE_CONTROL_START_OWN
+ : SERVICE_CONTROL_START_SHARE;
ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service;
- ControlPacket->dwSize = TotalLength;
- Ptr = &ControlPacket->szArguments[0];
+ ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET);
+
+ Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset);
wcscpy(Ptr, Service->lpServiceName);
- Ptr += (wcslen(Service->lpServiceName) + 1);
+
+ ControlPacket->dwArgumentsCount = 0;
+ ControlPacket->dwArgumentsOffset = 0;
/* Copy argument list */
- if (argc > 0)
+ if (argc > 0 && argv != NULL)
{
- UNIMPLEMENTED;
- DPRINT1("Arguments sent to service ignored!\n");
-#if 0
- memcpy(Ptr, Arguments, ArgsLength);
- Ptr += ArgsLength;
-#endif
- }
-
- /* Terminate the argument list */
- *Ptr = 0;
+ Ptr += wcslen(Service->lpServiceName) + 1;
+ pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR);
+ pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR));
- /* Send the start command */
- WriteFile(Service->ControlPipeHandle,
- ControlPacket,
- sizeof(SCM_CONTROL_PACKET) + (TotalLength - 1) * sizeof(WCHAR),
- &dwWriteCount,
- NULL);
+ ControlPacket->dwArgumentsCount = argc;
+ ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket);
- /* Read the reply */
- ReadFile(Service->ControlPipeHandle,
- &ReplyPacket,
- sizeof(SCM_REPLY_PACKET),
- &dwReadCount,
- NULL);
+ DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount);
+ DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset);
- /* Release the contol packet */
- HeapFree(GetProcessHeap(),
- 0,
- ControlPacket);
+ for (i = 0; i < argc; i++)
+ {
+ wcscpy(pArgPtr, argv[i]);
+ *pOffPtr = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr);
+ DPRINT("offset: %p\n", *pOffPtr);
- if (dwReadCount == sizeof(SCM_REPLY_PACKET))
- {
- dwError = ReplyPacket.dwError;
+ pArgPtr += wcslen(argv[i]) + 1;
+ pOffPtr++;
+ }
}
- DPRINT("ScmSendStartCommand() done\n");
+#ifdef USE_ASYNCHRONOUS_IO
+ bResult = WriteFile(Service->lpImage->hControlPipe,
+ ControlPacket,
+ PacketSize,
+ &dwWriteCount,
+ &Overlapped);
+ if (bResult == FALSE)
+ {
+ DPRINT1("WriteFile() returned FALSE\n");
- return dwError;
-}
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
+ {
+ DPRINT1("dwError: ERROR_IO_PENDING\n");
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
-static DWORD
-ScmStartUserModeService(PSERVICE Service,
- DWORD argc,
- LPWSTR *argv)
-{
- 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];
- HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE;
- DWORD KeyDisposition;
- DWORD dwProcessId;
+ if (dwError == WAIT_TIMEOUT)
+ {
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
- RtlInitUnicodeString(&ImagePath, NULL);
+ dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto Done;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwWriteCount,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
- /* Get service data */
- RtlZeroMemory(&QueryTable,
- sizeof(QueryTable));
+ goto Done;
+ }
+ }
+ }
+ else
+ {
+ DPRINT1("WriteFile() failed (Error %lu)\n", dwError);
+ goto Done;
+ }
+ }
- QueryTable[0].Name = L"Type";
- QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[0].EntryContext = &Type;
+ /* Read the reply */
+ Overlapped.hEvent = (HANDLE) NULL;
+
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ &ReplyPacket,
+ sizeof(SCM_REPLY_PACKET),
+ &dwReadCount,
+ &Overlapped);
+ if (bResult == FALSE)
+ {
+ DPRINT1("ReadFile() returned FALSE\n");
- QueryTable[1].Name = L"ImagePath";
- QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED;
- QueryTable[1].EntryContext = &ImagePath;
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
+ {
+ DPRINT1("dwError: ERROR_IO_PENDING\n");
- Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES,
- Service->lpServiceName,
- QueryTable,
- NULL,
- NULL);
- if (!NT_SUCCESS(Status))
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+
+ if (dwError == WAIT_TIMEOUT)
+ {
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
+
+ dwError = ERROR_SERVICE_REQUEST_TIMEOUT;
+ goto Done;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwReadCount,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
+
+ goto Done;
+ }
+ }
+ }
+ else
+ {
+ DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
+ goto Done;
+ }
+ }
+
+#else
+ /* Send the start command */
+ bResult = WriteFile(Service->lpImage->hControlPipe,
+ ControlPacket,
+ PacketSize,
+ &dwWriteCount,
+ NULL);
+ if (bResult == FALSE)
{
- DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
- return RtlNtStatusToDosError(Status);
+ dwError = GetLastError();
+ DPRINT("WriteFile() failed (Error %lu)\n", dwError);
+ goto Done;
}
- DPRINT("ImagePath: '%S'\n", ImagePath.Buffer);
- DPRINT("Type: %lx\n", Type);
- /* Get the service number */
- /* TODO: Create registry entry with correct write access */
- Status = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
- L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL,
- REG_OPTION_VOLATILE,
- KEY_WRITE | KEY_READ,
- NULL,
- &hServiceCurrentKey,
- &KeyDisposition);
+ /* Read the reply */
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ &ReplyPacket,
+ sizeof(SCM_REPLY_PACKET),
+ &dwReadCount,
+ NULL);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT("ReadFile() failed (Error %lu)\n", dwError);
+ }
+#endif
+
+Done:
+ /* Release the contol packet */
+ HeapFree(GetProcessHeap(),
+ 0,
+ ControlPacket);
- if (ERROR_SUCCESS != Status)
+ if (dwReadCount == sizeof(SCM_REPLY_PACKET))
{
- DPRINT1("RegCreateKeyEx() failed with status %u\n", Status);
- return Status;
+ dwError = ReplyPacket.dwError;
}
- if (REG_OPENED_EXISTING_KEY == KeyDisposition)
+ DPRINT("ScmSendStartCommand() done\n");
+
+ return dwError;
+}
+
+
+static DWORD
+ScmWaitForServiceConnect(PSERVICE Service)
+{
+ DWORD dwRead = 0;
+ DWORD dwProcessId = 0;
+ DWORD dwError = ERROR_SUCCESS;
+ BOOL bResult;
+#ifdef USE_ASYNCHRONOUS_IO
+ OVERLAPPED Overlapped = {0, 0, 0, 0, 0};
+#endif
+
+ DPRINT("ScmWaitForServiceConnect()\n");
+
+#ifdef USE_ASYNCHRONOUS_IO
+ Overlapped.hEvent = (HANDLE)NULL;
+
+ bResult = ConnectNamedPipe(Service->lpImage->hControlPipe,
+ &Overlapped);
+ if (bResult == FALSE)
{
- DWORD KeySize = sizeof(ServiceCurrent);
- Status = RegQueryValueExW(hServiceCurrentKey, L"", 0, NULL, (BYTE*)&ServiceCurrent, &KeySize);
+ DPRINT("ConnectNamedPipe() returned FALSE\n");
- if (ERROR_SUCCESS != Status)
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
{
- RegCloseKey(hServiceCurrentKey);
- DPRINT1("RegQueryValueEx() failed with status %u\n", Status);
- return Status;
+ DPRINT("dwError: ERROR_IO_PENDING\n");
+
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ DPRINT("WaitForSingleObject() returned %lu\n", dwError);
+
+ if (dwError == WAIT_TIMEOUT)
+ {
+ DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
+
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
+
+ return ERROR_SERVICE_REQUEST_TIMEOUT;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwRead,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError);
+
+ return dwError;
+ }
+ }
+ }
+ else if (dwError != ERROR_PIPE_CONNECTED)
+ {
+ DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError);
+ return dwError;
}
+ }
- ServiceCurrent++;
+ DPRINT("Control pipe connected!\n");
+
+ Overlapped.hEvent = (HANDLE) NULL;
+
+ /* Read the process id from pipe */
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ (LPVOID)&dwProcessId,
+ sizeof(DWORD),
+ &dwRead,
+ &Overlapped);
+ if (bResult == FALSE)
+ {
+ DPRINT("ReadFile() returned FALSE\n");
+
+ dwError = GetLastError();
+ if (dwError == ERROR_IO_PENDING)
+ {
+ DPRINT("dwError: ERROR_IO_PENDING\n");
+
+ dwError = WaitForSingleObject(Service->lpImage->hControlPipe,
+ PipeTimeout);
+ if (dwError == WAIT_TIMEOUT)
+ {
+ DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n");
+
+ bResult = CancelIo(Service->lpImage->hControlPipe);
+ if (bResult == FALSE)
+ {
+ DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError());
+ }
+
+ return ERROR_SERVICE_REQUEST_TIMEOUT;
+ }
+ else if (dwError == WAIT_OBJECT_0)
+ {
+ DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n");
+
+ DPRINT("Process Id: %lu\n", dwProcessId);
+
+ bResult = GetOverlappedResult(Service->lpImage->hControlPipe,
+ &Overlapped,
+ &dwRead,
+ TRUE);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError);
+
+ return dwError;
+ }
+ }
+ else
+ {
+ DPRINT1("WaitForSingleObject() returned %lu\n", dwError);
+ }
+ }
+ else
+ {
+ DPRINT1("ReadFile() failed (Error %lu)\n", dwError);
+ return dwError;
+ }
}
- Status = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent));
+ DPRINT1("ScmWaitForServiceConnect() done\n");
- RegCloseKey(hServiceCurrentKey);
+ return ERROR_SUCCESS;
+#else
- if (ERROR_SUCCESS != Status)
+ /* Connect control pipe */
+ if (ConnectNamedPipe(Service->lpImage->hControlPipe, NULL) ?
+ TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
{
- DPRINT1("RegSetValueExW() failed (Status %lx)\n", Status);
- return Status;
+ DPRINT("Control pipe connected!\n");
+
+ /* Read SERVICE_STATUS_HANDLE from pipe */
+ bResult = ReadFile(Service->lpImage->hControlPipe,
+ (LPVOID)&dwProcessId,
+ sizeof(DWORD),
+ &dwRead,
+ NULL);
+ if (bResult == FALSE)
+ {
+ dwError = GetLastError();
+ DPRINT1("Reading the service control pipe failed (Error %lu)\n",
+ dwError);
+ }
+ else
+ {
+ dwError = ERROR_SUCCESS;
+ DPRINT("Read control pipe successfully\n");
+ }
+ }
+ else
+ {
+ DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError);
}
- /* 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,
- 8000,
- 4,
- 30000,
- NULL);
- DPRINT("CreateNamedPipeW(%S) done\n", NtControlPipeName);
- if (Service->ControlPipeHandle == INVALID_HANDLE_VALUE)
+ return dwError;
+#endif
+}
+
+
+static DWORD
+ScmStartUserModeService(PSERVICE Service,
+ DWORD argc,
+ LPWSTR* argv)
+{
+ PROCESS_INFORMATION ProcessInformation;
+ STARTUPINFOW StartupInfo;
+ BOOL Result;
+ DWORD dwError = ERROR_SUCCESS;
+
+ DPRINT("ScmStartUserModeService(%p)\n", Service);
+
+ /* If the image is already running ... */
+ if (Service->lpImage->dwImageRunCount > 1)
{
- DPRINT1("Failed to create control pipe!\n");
- return GetLastError();
+ /* ... just send a start command */
+ return ScmSendStartCommand(Service, argc, argv);
}
+ /* Otherwise start its process */
+ ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof(StartupInfo);
- StartupInfo.lpReserved = NULL;
- StartupInfo.lpDesktop = NULL;
- StartupInfo.lpTitle = NULL;
- StartupInfo.dwFlags = 0;
- StartupInfo.cbReserved2 = 0;
- StartupInfo.lpReserved2 = 0;
+ ZeroMemory(&ProcessInformation, sizeof(ProcessInformation));
Result = CreateProcessW(NULL,
- ImagePath.Buffer,
+ Service->lpImage->szImagePath,
NULL,
NULL,
FALSE,
NULL,
&StartupInfo,
&ProcessInformation);
- RtlFreeUnicodeString(&ImagePath);
-
if (!Result)
{
dwError = GetLastError();
- /* Close control pipe */
- CloseHandle(Service->ControlPipeHandle);
- Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
-
DPRINT1("Starting '%S' failed!\n", Service->lpServiceName);
return dwError;
}
- DPRINT("Process Id: %lu Handle %lx\n",
+ DPRINT("Process Id: %lu Handle %p\n",
ProcessInformation.dwProcessId,
ProcessInformation.hProcess);
- DPRINT("Thread Id: %lu Handle %lx\n",
+ DPRINT("Thread Id: %lu Handle %p\n",
ProcessInformation.dwThreadId,
ProcessInformation.hThread);
- /* Get process and thread ids */
- Service->ProcessId = ProcessInformation.dwProcessId;
- Service->ThreadId = ProcessInformation.dwThreadId;
+ /* Get process handle and id */
+ Service->lpImage->dwProcessId = ProcessInformation.dwProcessId;
/* Resume Thread */
ResumeThread(ProcessInformation.hThread);
/* Connect control pipe */
- if (ConnectNamedPipe(Service->ControlPipeHandle, NULL) ?
- TRUE : (dwError = GetLastError()) == ERROR_PIPE_CONNECTED)
+ dwError = ScmWaitForServiceConnect(Service);
+ if (dwError == ERROR_SUCCESS)
{
- DWORD dwRead = 0;
-
- DPRINT("Control pipe connected!\n");
-
- /* Read SERVICE_STATUS_HANDLE from pipe */
- if (!ReadFile(Service->ControlPipeHandle,
- (LPVOID)&dwProcessId,
- sizeof(DWORD),
- &dwRead,
- NULL))
- {
- dwError = GetLastError();
- DPRINT1("Reading the service control pipe failed (Error %lu)\n",
- dwError);
- }
- else
- {
- DPRINT("Received service process ID %lu\n", dwProcessId);
-
- /* Send start command */
- dwError = ScmSendStartCommand(Service, argc, argv);
- }
+ /* Send start command */
+ dwError = ScmSendStartCommand(Service, argc, argv);
}
else
{
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;
+ Service->lpImage->dwProcessId = 0;
}
- /* Close process and thread handle */
+ /* Close thread and process handle */
CloseHandle(ProcessInformation.hThread);
CloseHandle(ProcessInformation.hProcess);
}
-DWORD
-ScmStartService(PSERVICE Service, DWORD argc, LPWSTR *argv)
+static DWORD
+ScmLoadService(PSERVICE Service,
+ DWORD argc,
+ LPWSTR* argv)
{
PSERVICE_GROUP Group = Service->lpGroup;
DWORD dwError = ERROR_SUCCESS;
+ LPCWSTR ErrorLogStrings[2];
+ WCHAR szErrorBuffer[32];
- DPRINT("ScmStartService() called\n");
+ DPRINT("ScmLoadService() called\n");
+ DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
+
+ if (Service->Status.dwCurrentState != SERVICE_STOPPED)
+ {
+ DPRINT("Service %S is already running!\n", Service->lpServiceName);
+ return ERROR_SERVICE_ALREADY_RUNNING;
+ }
- Service->ControlPipeHandle = INVALID_HANDLE_VALUE;
DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType);
if (Service->Status.dwServiceType & SERVICE_DRIVER)
Service->Status.dwCurrentState = SERVICE_RUNNING;
}
}
- else
+ else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS))
{
/* Start user-mode service */
- dwError = ScmStartUserModeService(Service, argc, argv);
+ dwError = ScmCreateOrReferenceServiceImage(Service);
if (dwError == ERROR_SUCCESS)
{
+ dwError = ScmStartUserModeService(Service, argc, argv);
+ if (dwError == ERROR_SUCCESS)
+ {
#ifdef USE_SERVICE_START_PENDING
- Service->Status.dwCurrentState = SERVICE_START_PENDING;
+ Service->Status.dwCurrentState = SERVICE_START_PENDING;
#else
- Service->Status.dwCurrentState = SERVICE_RUNNING;
+ Service->Status.dwCurrentState = SERVICE_RUNNING;
#endif
+ }
+ else
+ {
+ ScmDereferenceServiceImage(Service->lpImage);
+ Service->lpImage = NULL;
+ }
}
}
- DPRINT("ScmStartService() done (Error %lu)\n", dwError);
+ DPRINT("ScmLoadService() done (Error %lu)\n", dwError);
if (dwError == ERROR_SUCCESS)
{
Group->ServicesRunning = TRUE;
}
}
-#if 0
else
{
- switch (Service->ErrorControl)
+ if (Service->dwErrorControl != SERVICE_ERROR_IGNORE)
{
- case SERVICE_ERROR_NORMAL:
- /* FIXME: Log error */
- break;
+ /* Log a failed service start */
+ swprintf(szErrorBuffer, L"%lu", dwError);
+ ErrorLogStrings[0] = Service->lpServiceName;
+ ErrorLogStrings[1] = szErrorBuffer;
+ ScmLogError(EVENT_SERVICE_START_FAILED,
+ 2,
+ ErrorLogStrings);
+ }
+#if 0
+ switch (Service->dwErrorControl)
+ {
case SERVICE_ERROR_SEVERE:
if (IsLastKnownGood == FALSE)
{
}
break;
}
- }
#endif
+ }
+
+ return dwError;
+}
+
+
+DWORD
+ScmStartService(PSERVICE Service,
+ DWORD argc,
+ LPWSTR* argv)
+{
+ DWORD dwError = ERROR_SUCCESS;
+ SC_RPC_LOCK Lock = NULL;
+
+ DPRINT("ScmStartService() called\n");
+ DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName);
+
+ /* Acquire the service control critical section, to synchronize starts */
+ EnterCriticalSection(&ControlServiceCriticalSection);
+
+ /*
+ * Acquire the user service start lock while the service is starting, if
+ * needed (i.e. if we are not starting it during the initialization phase).
+ * If we don't success, bail out.
+ */
+ if (!ScmInitialize)
+ {
+ dwError = ScmAcquireServiceStartLock(TRUE, &Lock);
+ if (dwError != ERROR_SUCCESS) goto done;
+ }
+
+ /* Really start the service */
+ dwError = ScmLoadService(Service, argc, argv);
+
+ /* Release the service start lock, if needed, and the critical section */
+ if (Lock) ScmReleaseServiceStartLock(&Lock);
+
+done:
+ LeaveCriticalSection(&ControlServiceCriticalSection);
+
+ DPRINT("ScmStartService() done (Error %lu)\n", dwError);
return dwError;
}
VOID
ScmAutoStartServices(VOID)
{
+ DWORD dwError = ERROR_SUCCESS;
PLIST_ENTRY GroupEntry;
PLIST_ENTRY ServiceEntry;
PSERVICE_GROUP CurrentGroup;
PSERVICE CurrentService;
+ WCHAR szSafeBootServicePath[MAX_PATH];
+ HKEY hKey;
ULONG i;
- /* Clear 'ServiceVisited' flag */
+ /*
+ * This function MUST be called ONLY at initialization time.
+ * Therefore, no need to acquire the user service start lock.
+ */
+ ASSERT(ScmInitialize);
+
+ /* Acquire the service control critical section, to synchronize starts */
+ EnterCriticalSection(&ControlServiceCriticalSection);
+
+ /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
- CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
- CurrentService->ServiceVisited = FALSE;
- ServiceEntry = ServiceEntry->Flink;
+ CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
+
+ /* Build the safe boot path */
+ wcscpy(szSafeBootServicePath,
+ L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot");
+
+ switch (GetSystemMetrics(SM_CLEANBOOT))
+ {
+ /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */
+ case 1:
+ case 3:
+ wcscat(szSafeBootServicePath, L"\\Minimal\\");
+ break;
+
+ case 2:
+ wcscat(szSafeBootServicePath, L"\\Network\\");
+ break;
+ }
+
+ if (GetSystemMetrics(SM_CLEANBOOT))
+ {
+ /* If key does not exist then do not assume safe mode */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ szSafeBootServicePath,
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError == ERROR_SUCCESS)
+ {
+ RegCloseKey(hKey);
+
+ /* Finish Safe Boot path off */
+ wcsncat(szSafeBootServicePath,
+ CurrentService->lpServiceName,
+ MAX_PATH - wcslen(szSafeBootServicePath));
+
+ /* Check that the key is in the Safe Boot path */
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ szSafeBootServicePath,
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError != ERROR_SUCCESS)
+ {
+ /* Mark service as visited so it is not auto-started */
+ CurrentService->ServiceVisited = TRUE;
+ }
+ else
+ {
+ /* Must be auto-started in safe mode - mark as unvisited */
+ RegCloseKey(hKey);
+ CurrentService->ServiceVisited = FALSE;
+ }
+ }
+ else
+ {
+ DPRINT1("WARNING: Could not open the associated Safe Boot key!");
+ CurrentService->ServiceVisited = FALSE;
+ }
+ }
+
+ ServiceEntry = ServiceEntry->Flink;
}
/* Start all services which are members of an existing group */
(CurrentService->dwTag == CurrentGroup->TagArray[i]))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService, 0, NULL);
+ ScmLoadService(CurrentService, 0, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService, 0, NULL);
+ ScmLoadService(CurrentService, 0, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService, 0, NULL);
+ ScmLoadService(CurrentService, 0, NULL);
}
ServiceEntry = ServiceEntry->Flink;
(CurrentService->ServiceVisited == FALSE))
{
CurrentService->ServiceVisited = TRUE;
- ScmStartService(CurrentService, 0, NULL);
+ ScmLoadService(CurrentService, 0, NULL);
}
ServiceEntry = ServiceEntry->Flink;
CurrentService->ServiceVisited = FALSE;
ServiceEntry = ServiceEntry->Flink;
}
+
+ /* Release the critical section */
+ LeaveCriticalSection(&ControlServiceCriticalSection);
}
DPRINT("ScmAutoShutdownServices() called\n");
+ /* Lock the service database exclusively */
+ ScmLockDatabaseExclusive();
+
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)
{
/* shutdown service */
- ScmControlService(CurrentService, SERVICE_CONTROL_STOP);
+ DPRINT("Shutdown service: %S\n", CurrentService->szServiceName);
+ ScmControlService(CurrentService, SERVICE_CONTROL_SHUTDOWN);
}
ServiceEntry = ServiceEntry->Flink;
}
- DPRINT("ScmGetBootAndSystemDriverState() done\n");
+ /* Unlock the service database */
+ ScmUnlockDatabase();
+
+ DPRINT("ScmAutoShutdownServices() done\n");
}
RtlReleaseResource(&DatabaseLock);
}
+
+VOID
+ScmInitNamedPipeCriticalSection(VOID)
+{
+ HKEY hKey;
+ DWORD dwKeySize;
+ DWORD dwError;
+
+ InitializeCriticalSection(&ControlServiceCriticalSection);
+
+ dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
+ L"SYSTEM\\CurrentControlSet\\Control",
+ 0,
+ KEY_READ,
+ &hKey);
+ if (dwError == ERROR_SUCCESS)
+ {
+ dwKeySize = sizeof(DWORD);
+ RegQueryValueExW(hKey,
+ L"ServicesPipeTimeout",
+ 0,
+ NULL,
+ (LPBYTE)&PipeTimeout,
+ &dwKeySize);
+
+ RegCloseKey(hKey);
+ }
+}
+
+
+VOID
+ScmDeleteNamedPipeCriticalSection(VOID)
+{
+ DeleteCriticalSection(&ControlServiceCriticalSection);
+}
+
/* EOF */