[KMTESTS]

- rework the kmtest loader application to follow everything else's coding style and to allow user-mode test parts

svn path=/branches/GSoC_2011/KMTestSuite/; revision=52519
This commit is contained in:
Thomas Faber 2011-07-03 18:53:26 +00:00
parent 991bc0e366
commit 459f4ac630
8 changed files with 803 additions and 238 deletions

View file

@ -48,6 +48,8 @@ set_rc_compiler()
list(APPEND KMTEST_SOURCE
kmtest/kmtest.c
kmtest/service.c
kmtest/support.c
kmtest/testlist.c
kmtest/kmtest.rc)
add_executable(kmtest ${KMTEST_SOURCE})

View file

@ -16,6 +16,7 @@
#include <stdarg.h>
typedef VOID KMT_TESTFUNC(VOID);
typedef KMT_TESTFUNC *PKMT_TESTFUNC;
typedef struct
{
@ -37,6 +38,17 @@ typedef struct
CHAR LogBuffer[ANYSIZE_ARRAY];
} KMT_RESULTBUFFER, *PKMT_RESULTBUFFER;
#if defined KMT_USER_MODE
VOID KmtLoadDriver(IN PCWSTR ServiceName, IN BOOLEAN RestartIfRunning);
VOID KmtUnloadDriver(VOID);
VOID KmtOpenDriver(VOID);
VOID KmtCloseDriver(VOID);
DWORD KmtSendToDriver(IN DWORD ControlCode);
DWORD KmtSendStringToDriver(IN DWORD ControlCode, IN PCSTR String);
DWORD KmtSendBufferToDriver(IN DWORD ControlCode, IN OUT PVOID Buffer, IN DWORD Length);
#endif /* defined KMT_USER_MODE */
extern PKMT_RESULTBUFFER ResultBuffer;
#ifdef __GNUC__
@ -47,13 +59,15 @@ extern PKMT_RESULTBUFFER ResultBuffer;
#define START_TEST(name) VOID Test_##name(VOID)
#ifndef KMT_STRINGIZE
#define KMT_STRINGIZE(x) #x
#define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
#define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
#endif /* !defined KMT_STRINGIZE */
#define ok(test, ...) ok_(test, __FILE__, __LINE__, __VA_ARGS__)
#define trace(...) trace_( __FILE__, __LINE__, __VA_ARGS__)
#define skip(test, ...) skip_(test, __FILE__, __LINE__, __VA_ARGS__)
#define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
#define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
#define ok_(test, file, line, ...) KmtOk(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
#define trace_(file, line, ...) KmtTrace( file ":" KMT_STRINGIZE(line), __VA_ARGS__)
#define skip_(test, file, line, ...) KmtSkip(test, file ":" KMT_STRINGIZE(line), __VA_ARGS__)
VOID KmtVOk(INT Condition, PCSTR FileAndLine, PCSTR Format, va_list Arguments) KMT_FORMAT(ms_printf, 3, 0);
@ -75,7 +89,9 @@ BOOLEAN KmtSkip(INT Condition, PCSTR FileAndLine, PCSTR Format, ...)
#define ok_eq_hex(value, expected) ok_eq_print(value, expected, "0x%08lx")
#define ok_bool_true(value, desc) ok((value) == TRUE, desc " FALSE, expected TRUE\n")
#define ok_bool_false(value, desc) ok((value) == FALSE, desc " TRUE, expected FALSE\n")
#define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", (value) ? "TRUE" : "FALSE", (expected) ? "TRUE" : "FALSE")
#define ok_eq_bool(value, expected) ok((value) == (expected), #value " = %s, expected %s\n", \
(value) ? "TRUE" : "FALSE", \
(expected) ? "TRUE" : "FALSE")
#define ok_eq_str(value, expected) ok(!strcmp(value, expected), #value " = \"%s\", expected \"%s\"\n", value, expected)
#define ok_eq_wstr(value, expected) ok(!wcscmp(value, expected), #value " = \"%ls\", expected \"%ls\"\n", value, expected)

View file

@ -5,5 +5,7 @@
<directory name="kmtest">
<file>kmtest.c</file>
<file>service.c</file>
<file>support.c</file>
<file>testlist.c</file>
</directory>
</module>

View file

@ -6,6 +6,7 @@
*/
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <strsafe.h>
@ -19,186 +20,288 @@
#define KMT_DEFINE_TEST_FUNCTIONS
#include <kmt_test.h>
#define LOGBUFFER_SIZE 65000
#define SERVICE_NAME L"Kmtest"
#define SERVICE_PATH L"kmtest_drv.sys"
static void OutputError(FILE *fp, DWORD error);
static DWORD RunTest(char *testName);
static DWORD ListTests(PSTR *testList);
int __cdecl main(int argc, char **argv);
#define LOGBUFFER_SIZE 65000
#define RESULTBUFFER_SIZE FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer[LOGBUFFER_SIZE])
static void OutputError(FILE *fp, DWORD error)
static HANDLE KmtestHandle;
PCSTR ErrorFileAndLine = "No error";
static void OutputError(DWORD Error);
static DWORD ListTests(VOID);
static PKMT_TESTFUNC FindTest(PCSTR TestName);
static DWORD OutputResult(PCSTR TestName);
static DWORD RunTest(PCSTR TestName);
int __cdecl main(int ArgCount, char **Arguments);
/**
* @name OutputError
*
* Output an error message to the console.
*
* @param Error
* Win32 error code
*/
static
void
OutputError(
DWORD Error)
{
char *message;
PSTR Message;
if (!FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_ALLOCATE_BUFFER,
NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&message, 0, NULL))
NULL, Error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&Message, 0, NULL))
{
fprintf(fp, "Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n", GetLastError(), error);
fprintf(stderr, "%s: Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n",
ErrorFileAndLine, GetLastError(), Error);
return;
}
fprintf(fp, "%s\n", message);
fprintf(stderr, "%s: error 0x%08lx: %s\n", ErrorFileAndLine, Error, Message);
LocalFree(message);
LocalFree(Message);
}
static DWORD RunTest(char *testName)
/**
* @name ListTests
*
* Output the list of tests to the console.
* The list will comprise tests as listed by the driver
* in addition to user-mode tests in TestList.
*
* @return Win32 error code
*/
static
DWORD
ListTests(VOID)
{
DWORD error = ERROR_SUCCESS;
HANDLE hDevice = INVALID_HANDLE_VALUE;
DWORD bytesRead, bytesWritten;
DWORD Error = ERROR_SUCCESS;
CHAR Buffer[1024];
DWORD BytesRead;
PCSTR TestName = Buffer;
PCKMT_TEST TestEntry = TestList;
PCSTR NextTestName;
puts("Valid test names:");
// get test list from driver
if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_GET_TESTS, NULL, 0, Buffer, sizeof Buffer, &BytesRead, NULL))
error_goto(Error, cleanup);
// output test list plus user-mode tests
while (TestEntry->TestName || *TestName)
{
// tests starting with a '-' should not be listed
while (TestEntry->TestName && *TestEntry->TestName == '-')
++TestEntry;
if (!TestEntry->TestName)
{
NextTestName = TestName;
TestName += strlen(TestName) + 1;
}
else if (!*TestName)
{
NextTestName = TestEntry->TestName;
++TestEntry;
}
else
{
int Result = strcmp(TestEntry->TestName, TestName);
if (Result == 0)
{
NextTestName = TestEntry->TestName;
TestName += strlen(TestName) + 1;
++TestEntry;
}
else if (Result < 0)
{
NextTestName = TestEntry->TestName;
++TestEntry;
}
else
{
NextTestName = TestName;
TestName += strlen(TestName) + 1;
}
}
printf(" %s\n", NextTestName);
}
cleanup:
return Error;
}
/**
* @name FindTest
*
* Find a test in TestList by name.
*
* @param TestName
* Name of the test to look for. Case sensitive
*
* @return pointer to test function, or NULL if not found
*/
static
PKMT_TESTFUNC
FindTest(
PCSTR TestName)
{
PCKMT_TEST TestEntry = TestList;
for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
{
PCSTR TestEntryName = TestEntry->TestName;
// skip leading '-' if present
if (*TestEntryName == '-')
++TestEntryName;
if (!lstrcmpA(TestEntryName, TestName))
break;
}
return TestEntry->TestFunction;
}
/**
* @name OutputResult
*
* Output the test results in ResultBuffer to the console.
*
* @param TestName
* Name of the test whose result is to be printed
*
* @return Win32 error code
*/
static
DWORD
OutputResult(
PCSTR TestName)
{
DWORD Error = ERROR_SUCCESS;
DWORD BytesWritten;
KmtFinishTest(TestName);
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ResultBuffer->LogBuffer, ResultBuffer->LogBufferLength, &BytesWritten, NULL))
Error = GetLastError();
return Error;
}
/**
* @name RunTest
*
* Run the named test and output its results.
*
* @param TestName
* Name of the test to run. Case sensitive
*
* @return Win32 error code
*/
static
DWORD
RunTest(
PCSTR TestName)
{
DWORD Error = ERROR_SUCCESS;
PKMT_TESTFUNC TestFunction;
DWORD BytesRead;
ResultBuffer = KmtAllocateResultBuffer(LOGBUFFER_SIZE);
if (!ResultBuffer)
if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_SET_RESULTBUFFER, ResultBuffer, RESULTBUFFER_SIZE, NULL, 0, &BytesRead, NULL))
error_goto(Error, cleanup);
// check test list
TestFunction = FindTest(TestName);
if (TestFunction)
{
error = GetLastError();
goto cleanup;
}
hDevice = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
error = GetLastError();
goto cleanup;
}
if (!DeviceIoControl(hDevice, IOCTL_KMTEST_SET_RESULTBUFFER, ResultBuffer, FIELD_OFFSET(KMT_RESULTBUFFER, LogBuffer[LOGBUFFER_SIZE]), NULL, 0, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
if (!DeviceIoControl(hDevice, IOCTL_KMTEST_RUN_TEST, testName, strlen(testName), NULL, 0, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
KmtFinishTest(testName);
if (!WriteConsoleA(GetStdHandle(STD_OUTPUT_HANDLE), ResultBuffer->LogBuffer, ResultBuffer->LogBufferLength, &bytesWritten, NULL))
{
error = GetLastError();
TestFunction();
goto cleanup;
}
// not found in user-mode test list, call driver
if (!DeviceIoControl(KmtestHandle, IOCTL_KMTEST_RUN_TEST, (PVOID)TestName, strlen(TestName), NULL, 0, &BytesRead, NULL))
error_goto(Error, cleanup);
cleanup:
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
OutputResult(TestName);
KmtFreeResultBuffer(ResultBuffer);
if (ResultBuffer)
KmtFreeResultBuffer(ResultBuffer);
return error;
return Error;
}
static DWORD ListTests(PSTR *testList)
/**
* @name main
*
* Program entry point
*
* @param ArgCount
* @param Arguments
*
* @return EXIT_SUCCESS on success, EXIT_FAILURE on failure
*/
int
main(
int ArgCount,
char **Arguments)
{
DWORD error = ERROR_SUCCESS;
HANDLE hDevice = INVALID_HANDLE_VALUE;
DWORD bytesRead;
PSTR buffer = NULL;
DWORD bufferSize;
INT Status = EXIT_SUCCESS;
DWORD Error = ERROR_SUCCESS;
SC_HANDLE ServiceHandle;
PCSTR AppName = "kmtest.exe";
PCSTR TestName;
if (!testList)
{
error = ERROR_INVALID_PARAMETER;
Error = KmtServiceInit();
if (Error)
goto cleanup;
}
hDevice = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, 0, NULL);
if (hDevice == INVALID_HANDLE_VALUE)
{
error = GetLastError();
Error = KmtCreateAndStartService(SERVICE_NAME, SERVICE_PATH, L"ReactOS Kernel-Mode Test Suite Driver", &ServiceHandle, FALSE);
if (Error)
goto cleanup;
}
bufferSize = 1024;
buffer = HeapAlloc(GetProcessHeap(), 0, bufferSize);
if (!buffer)
KmtestHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (KmtestHandle == INVALID_HANDLE_VALUE)
error_goto(Error, cleanup);
if (ArgCount >= 1)
AppName = Arguments[0];
if (ArgCount <= 1)
{
error = GetLastError();
goto cleanup;
}
if (!DeviceIoControl(hDevice, IOCTL_KMTEST_GET_TESTS, NULL, 0, buffer, bufferSize, &bytesRead, NULL))
{
error = GetLastError();
goto cleanup;
}
cleanup:
if (buffer && error)
{
HeapFree(GetProcessHeap(), 0, buffer);
buffer = NULL;
}
if (hDevice != INVALID_HANDLE_VALUE)
CloseHandle(hDevice);
if (testList)
*testList = buffer;
return error;
}
int __cdecl main(int argc, char **argv)
{
int status = EXIT_SUCCESS;
DWORD error;
if (argc <= 1)
{
/* no arguments: show usage and list tests */
char *programName = argc == 0 ? "kmtest" : argv[0];
char *testNames, *testName;
size_t len;
printf("Usage: %s test_name\n", programName);
printf(" %s <Create|Start|Stop|Delete>\n", programName);
puts("\nValid test names:");
error = ListTests(&testNames);
testName = testNames;
while ((len = strlen(testName)) != 0)
{
printf(" %s\n", testName);
testName += len + 1;
}
/* TODO: user-mode test parts */
if (error)
OutputError(stdout, error);
printf("Usage: %s <test_name> - run the specified test\n", AppName);
printf(" %s --list - list available tests\n", AppName);
printf(" %s <create|delete|start|stop> - manage the kmtest driver\n\n", AppName);
Error = ListTests();
}
else
{
char *testName = argv[1];
if (argc > 2)
fputs("Excess arguments ignored\n", stderr);
if (!lstrcmpiA(testName, "create"))
error = Service_Control(Service_Create);
else if (!lstrcmpiA(testName, "delete"))
error = Service_Control(Service_Delete);
else if (!lstrcmpiA(testName, "start"))
error = Service_Control(Service_Start);
else if (!lstrcmpiA(testName, "stop"))
error = Service_Control(Service_Stop);
TestName = Arguments[1];
if (!lstrcmpA(Arguments[1], "--list"))
Error = ListTests();
else
/* TODO: user-mode test parts */
error = RunTest(testName);
OutputError(stdout, error);
Error = RunTest(TestName);
}
if (error)
status = EXIT_FAILURE;
cleanup:
if (KmtestHandle)
CloseHandle(KmtestHandle);
return status;
if (Error)
KmtServiceCleanup(TRUE);
else
Error = KmtServiceCleanup(FALSE);
if (Error)
OutputError(Error);
if (Error)
Status = EXIT_FAILURE;
return Status;
}

View file

@ -8,16 +8,57 @@
#ifndef _KMTESTS_H_
#define _KMTESTS_H_
#include <windows.h>
extern PCSTR ErrorFileAndLine;
/* service control functions */
typedef DWORD SERVICE_FUNC(SC_HANDLE hManager);
#ifndef KMT_STRINGIZE
#define KMT_STRINGIZE(x) #x
#endif /* !defined KMT_STRINGIZE */
SERVICE_FUNC Service_Create;
SERVICE_FUNC Service_Delete;
SERVICE_FUNC Service_Start;
SERVICE_FUNC Service_Stop;
#define location(file, line) do { ErrorFileAndLine = file ":" KMT_STRINGIZE(line); } while (0)
#define error_value(Error, value) do { location(__FILE__, __LINE__); Error = value; } while (0)
#define error(Error) error_value(Error, GetLastError())
#define error_goto(Error, label) do { error(Error); goto label; } while (0)
#define error_value_goto(Error, value, label) do { error_value(Error, value); goto label; } while (0)
DWORD Service_Control(SERVICE_FUNC *Service_Func);
/* service management functions */
DWORD
KmtServiceInit(VOID);
DWORD
KmtServiceCleanup(
BOOLEAN IgnoreErrors);
DWORD
KmtCreateService(
IN PCWSTR ServiceName,
IN PCWSTR ServicePath,
IN PCWSTR DisplayName OPTIONAL,
OUT SC_HANDLE *ServiceHandle);
DWORD
KmtStartService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle);
DWORD
KmtCreateAndStartService(
IN PCWSTR ServiceName,
IN PCWSTR ServicePath,
IN PCWSTR DisplayName OPTIONAL,
OUT SC_HANDLE *ServiceHandle,
IN BOOLEAN RestartIfRunning);
DWORD
KmtStopService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle);
DWORD
KmtDeleteService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle);
DWORD KmtCloseService(
IN OUT SC_HANDLE *ServiceHandle);
#endif /* !defined _KMTESTS_H_ */

View file

@ -6,130 +6,308 @@
*/
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <strsafe.h>
#include <assert.h>
#include "kmtest.h"
#define SERVICE_NAME L"Kmtest"
#define SERVICE_PATH L"\\kmtest_drv.sys"
#define SERVICE_ACCESS (SERVICE_START | SERVICE_STOP | DELETE)
DWORD Service_Create(SC_HANDLE hScm)
static SC_HANDLE ScmHandle;
/**
* @name KmtServiceInit
*
* Initialize service management routines (by opening the service control manager)
*
* @return Win32 error code
*/
DWORD
KmtServiceInit(VOID)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
wchar_t driverPath[MAX_PATH];
DWORD Error = ERROR_SUCCESS;
assert(!ScmHandle);
ScmHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
if (!ScmHandle)
error(Error);
return Error;
}
/**
* @name KmtServiceCleanup
*
* Clean up resources used by service management routines.
*
* @param IgnoreErrors
* If TRUE, the function will never set ErrorLineAndFile, and always return ERROR_SUCCESS
*
* @return Win32 error code
*/
DWORD
KmtServiceCleanup(
BOOLEAN IgnoreErrors)
{
DWORD Error = ERROR_SUCCESS;
if (ScmHandle && !CloseServiceHandle(ScmHandle) && !IgnoreErrors)
error(Error);
return Error;
}
/**
* @name KmtCreateService
*
* Create the specified driver service and return a handle to it
*
* @param ServiceName
* Name of the service to create
* @param ServicePath
* File name of the driver, relative to the current directory
* @param DisplayName
* Service display name
* @param ServiceHandle
* Pointer to a variable to receive the handle to the service
*
* @return Win32 error code
*/
DWORD
KmtCreateService(
IN PCWSTR ServiceName,
IN PCWSTR ServicePath,
IN PCWSTR DisplayName OPTIONAL,
OUT SC_HANDLE *ServiceHandle)
{
DWORD Error = ERROR_SUCCESS;
WCHAR DriverPath[MAX_PATH];
HRESULT result = S_OK;
if (!GetCurrentDirectory(sizeof driverPath / sizeof driverPath[0], driverPath)
|| FAILED(result = StringCbCat(driverPath, sizeof driverPath, SERVICE_PATH)))
assert(ServiceHandle);
assert(ServiceName && ServicePath);
if (!GetCurrentDirectory(sizeof DriverPath / sizeof DriverPath[0], DriverPath))
error_goto(Error, cleanup);
if (DriverPath[wcslen(DriverPath) - 1] != L'\\')
{
if (FAILED(result))
error = result;
else
error = GetLastError();
goto cleanup;
DriverPath[wcslen(DriverPath) + 1] = L'\0';
DriverPath[wcslen(DriverPath)] = L'\\';
}
hService = CreateService(hScm, SERVICE_NAME, L"ReactOS Kernel-Mode Test Suite Driver",
SERVICE_START, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL, driverPath, NULL, NULL, NULL, NULL, NULL);
result = StringCbCat(DriverPath, sizeof DriverPath, ServicePath);
if (FAILED(result))
error_value_goto(Error, result, cleanup);
if (!hService)
error = GetLastError();
*ServiceHandle = CreateService(ScmHandle, ServiceName, DisplayName,
SERVICE_ACCESS, SERVICE_KERNEL_DRIVER, SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL, DriverPath, NULL, NULL, NULL, NULL, NULL);
if (!*ServiceHandle)
error_goto(Error, cleanup);
cleanup:
return error;
return Error;
}
DWORD Service_Delete(SC_HANDLE hScm)
/**
* @name KmtStartService
*
* Start the specified driver service by handle or name (and return a handle to it)
*
* @param ServiceName
* If *ServiceHandle is NULL, name of the service to start
* @param ServiceHandle
* Pointer to a variable containing the service handle,
* or NULL (in which case it will be filled with a handle to the service)
*
* @return Win32 error code
*/
DWORD
KmtStartService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
DWORD Error = ERROR_SUCCESS;
hService = OpenService(hScm, SERVICE_NAME, DELETE);
assert(ServiceHandle);
assert(ServiceName || *ServiceHandle);
if (!hService)
{
error = GetLastError();
goto cleanup;
}
if (!*ServiceHandle)
*ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
if (!DeleteService(hService))
error = GetLastError();
if (!*ServiceHandle)
error_goto(Error, cleanup);
if (!StartService(*ServiceHandle, 0, NULL))
error_goto(Error, cleanup);
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
return Error;
}
DWORD Service_Start(SC_HANDLE hScm)
/**
* @name KmtCreateAndStartService
*
* Create and start the specified driver service and return a handle to it
*
* @param ServiceName
* Name of the service to create
* @param ServicePath
* File name of the driver, relative to the current directory
* @param DisplayName
* Service display name
* @param ServiceHandle
* Pointer to a variable to receive the handle to the service
* @param RestartIfRunning
* TRUE to stop and restart the service if it is already running
*
* @return Win32 error code
*/
DWORD
KmtCreateAndStartService(
IN PCWSTR ServiceName,
IN PCWSTR ServicePath,
IN PCWSTR DisplayName OPTIONAL,
OUT SC_HANDLE *ServiceHandle,
IN BOOLEAN RestartIfRunning)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
DWORD Error = ERROR_SUCCESS;
hService = OpenService(hScm, SERVICE_NAME, SERVICE_START);
assert(ServiceHandle);
if (!hService)
{
error = GetLastError();
Error = KmtCreateService(ServiceName, ServicePath, DisplayName, ServiceHandle);
if (Error && Error != ERROR_SERVICE_EXISTS)
goto cleanup;
}
if (!StartService(hService, 0, NULL))
error = GetLastError();
Error = KmtStartService(ServiceName, ServiceHandle);
if (Error != ERROR_SERVICE_ALREADY_RUNNING)
goto cleanup;
Error = ERROR_SUCCESS;
if (!RestartIfRunning)
goto cleanup;
Error = KmtStopService(ServiceName, ServiceHandle);
if (Error)
goto cleanup;
Error = KmtStartService(ServiceName, ServiceHandle);
if (Error)
goto cleanup;
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
assert(Error || *ServiceHandle);
return Error;
}
DWORD Service_Stop(SC_HANDLE hScm)
/**
* @name KmtStopService
*
* Stop the specified driver service by handle or name (and return a handle to it)
*
* @param ServiceName
* If *ServiceHandle is NULL, name of the service to stop
* @param ServiceHandle
* Pointer to a variable containing the service handle,
* or NULL (in which case it will be filled with a handle to the service)
*
* @return Win32 error code
*/
DWORD
KmtStopService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hService = NULL;
SERVICE_STATUS serviceStatus;
DWORD Error = ERROR_SUCCESS;
SERVICE_STATUS ServiceStatus;
hService = OpenService(hScm, SERVICE_NAME, SERVICE_STOP);
assert(ServiceHandle);
assert(ServiceName || *ServiceHandle);
if (!hService)
{
error = GetLastError();
goto cleanup;
}
if (!*ServiceHandle)
*ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
if (!ControlService(hService, SERVICE_CONTROL_STOP, &serviceStatus))
error = GetLastError();
if (!*ServiceHandle)
error_goto(Error, cleanup);
if (!ControlService(*ServiceHandle, SERVICE_CONTROL_STOP, &ServiceStatus))
error_goto(Error, cleanup);
cleanup:
if (hService)
CloseServiceHandle(hService);
return error;
return Error;
}
DWORD Service_Control(SERVICE_FUNC *Service_Func)
/**
* @name KmtDeleteService
*
* Delete the specified driver service by handle or name (and return a handle to it)
*
* @param ServiceName
* If *ServiceHandle is NULL, name of the service to delete
* @param ServiceHandle
* Pointer to a variable containing the service handle.
* Will be set to NULL on success
*
* @return Win32 error code
*/
DWORD
KmtDeleteService(
IN PCWSTR ServiceName OPTIONAL,
IN OUT SC_HANDLE *ServiceHandle)
{
DWORD error = ERROR_SUCCESS;
SC_HANDLE hScm = NULL;
DWORD Error = ERROR_SUCCESS;
hScm = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);
assert(ServiceHandle);
assert(ServiceName || *ServiceHandle);
if (!hScm)
{
error = GetLastError();
goto cleanup;
}
if (!*ServiceHandle)
*ServiceHandle = OpenService(ScmHandle, ServiceName, SERVICE_ACCESS);
error = Service_Func(hScm);
if (!*ServiceHandle)
error_goto(Error, cleanup);
if (!DeleteService(*ServiceHandle))
error_goto(Error, cleanup);
if (*ServiceHandle)
CloseServiceHandle(*ServiceHandle);
cleanup:
if (hScm)
CloseServiceHandle(hScm);
return error;
return Error;
}
/**
* @name KmtCloseService
*
* Close the specified driver service handle
*
* @param ServiceHandle
* Pointer to a variable containing the service handle.
* Will be set to NULL on success
*
* @return Win32 error code
*/
DWORD KmtCloseService(
IN OUT SC_HANDLE *ServiceHandle)
{
DWORD Error = ERROR_SUCCESS;
assert(ServiceHandle);
if (*ServiceHandle && !CloseServiceHandle(*ServiceHandle))
error_goto(Error, cleanup);
*ServiceHandle = NULL;
cleanup:
return Error;
}

197
kmtests/kmtest/support.c Normal file
View file

@ -0,0 +1,197 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite Driver
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#define UNICODE
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <strsafe.h>
#include "kmtest.h"
#include <kmt_test.h>
#include <kmt_public.h>
/* pseudo-tests */
START_TEST(Create)
{
// nothing to do here. All tests start the service if needed
}
START_TEST(Delete)
{
// TODO: delete kmtest service
}
START_TEST(Start)
{
// nothing to do here. All tests start the service
}
START_TEST(Stop)
{
// TODO: stop kmtest service
}
/* test support functions for special-purpose drivers */
static WCHAR TestServiceName[MAX_PATH];
static SC_HANDLE TestServiceHandle;
static HANDLE TestDeviceHandle;
/**
* @name KmtLoadDriver
*
* Load the specified special-purpose driver (create/start the service)
*
* @param ServiceName
* Name of the driver service (Kmtest- prefix will be added automatically)
* @param RestartIfRunning
* TRUE to stop and restart the service if it is already running
*/
VOID
KmtLoadDriver(
IN PCWSTR ServiceName,
IN BOOLEAN RestartIfRunning)
{
DWORD Error = ERROR_SUCCESS;
WCHAR ServicePath[MAX_PATH];
StringCbCopy(ServicePath, sizeof ServicePath, ServiceName);
StringCbCat(ServicePath, sizeof ServicePath, L"_drv.sys");
StringCbCopy(TestServiceName, sizeof TestServiceName, L"Kmtest-");
StringCbCat(TestServiceName, sizeof TestServiceName, ServiceName);
Error = KmtCreateAndStartService(TestServiceName, ServicePath, NULL, &TestServiceHandle, RestartIfRunning);
if (Error)
{
// TODO
__debugbreak();
}
}
/**
* @name KmtUnloadDriver
*
* Unload special-purpose driver (stop the service)
*/
VOID
KmtUnloadDriver(VOID)
{
DWORD Error = ERROR_SUCCESS;
Error = KmtStopService(TestServiceName, &TestServiceHandle);
if (Error)
{
// TODO
__debugbreak();
}
}
/**
* @name KmtOpenDriver
*
* Open special-purpose driver (acquire a device handle)
*/
VOID
KmtOpenDriver(VOID)
{
DWORD Error = ERROR_SUCCESS;
WCHAR DevicePath[MAX_PATH];
StringCbCopy(DevicePath, sizeof DevicePath, L"\\\\.\\Global\\GLOBALROOT\\Device\\");
StringCbCat(DevicePath, sizeof DevicePath, TestServiceName);
TestDeviceHandle = CreateFile(KMTEST_DEVICE_PATH, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
if (TestDeviceHandle == INVALID_HANDLE_VALUE)
error(Error);
if (Error)
{
// TODO
__debugbreak();
}
}
/**
* @name KmtCloseDriver
*
* Close special-purpose driver (close device handle)
*/
VOID
KmtCloseDriver(VOID)
{
DWORD Error = ERROR_SUCCESS;
if (TestDeviceHandle && !CloseHandle(TestDeviceHandle))
error(Error);
if (Error)
{
// TODO
__debugbreak();
}
}
/* TODO: check if these will be useful */
/**
* @name KmtSendToDriver
*
* Unload special-purpose driver (stop the service)
*
* @param ControlCode
*
* @return Win32 error code as returned by DeviceIoControl
*/
DWORD
KmtSendToDriver(
IN DWORD ControlCode)
{
// TODO
return ERROR_CALL_NOT_IMPLEMENTED;
}
/**
* @name KmtSendStringToDriver
*
* Unload special-purpose driver (stop the service)
*
* @param ControlCode
* @param String
*
* @return Win32 error code as returned by DeviceIoControl
*/
DWORD
KmtSendStringToDriver(
IN DWORD ControlCode,
IN PCSTR String)
{
// TODO
return ERROR_CALL_NOT_IMPLEMENTED;
}
/**
* @name KmtSendBufferToDriver
*
* @param ControlCode
* @param Buffer
* @param Length
*
* @return Win32 error code as returned by DeviceIoControl
*/
DWORD
KmtSendBufferToDriver(
IN DWORD ControlCode,
IN OUT PVOID Buffer,
IN DWORD Length)
{
// TODO
return ERROR_CALL_NOT_IMPLEMENTED;
}

26
kmtests/kmtest/testlist.c Normal file
View file

@ -0,0 +1,26 @@
/*
* PROJECT: ReactOS kernel-mode tests
* LICENSE: GPLv2+ - See COPYING in the top level directory
* PURPOSE: Kernel-Mode Test Suite user-mode test list
* PROGRAMMER: Thomas Faber <thfabba@gmx.de>
*/
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#include <windows.h>
#include <kmt_test.h>
VOID Test_Create(VOID);
VOID Test_Delete(VOID);
VOID Test_Start(VOID);
VOID Test_Stop(VOID);
/* tests with a leading '-' will not be listed */
const KMT_TEST TestList[] =
{
{ "-create", Test_Create },
{ "-delete", Test_Delete },
{ "-start", Test_Start },
{ "-stop", Test_Stop, },
{ NULL, NULL },
};