ReactOS  0.4.12-dev-432-g3463b2d
kmtest.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS kernel-mode tests
3  * LICENSE: LGPL-2.1+ (https://spdx.org/licenses/LGPL-2.1+)
4  * PURPOSE: Kernel-Mode Test Suite loader application
5  * COPYRIGHT: Copyright 2011-2018 Thomas Faber <thomas.faber@reactos.org>
6  */
7 
8 #define KMT_DEFINE_TEST_FUNCTIONS
9 #include <kmt_test.h>
10 
11 #include "kmtest.h"
12 #include <kmt_public.h>
13 
14 #include <assert.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17 
18 #define SERVICE_NAME L"Kmtest"
19 #define SERVICE_PATH L"kmtest_drv.sys"
20 #define SERVICE_DESCRIPTION L"ReactOS Kernel-Mode Test Suite Driver"
21 
22 #define RESULTBUFFER_SIZE (1024 * 1024)
23 
24 typedef enum
25 {
31 
34 PCSTR ErrorFileAndLine = "No error";
35 
36 static void OutputError(IN DWORD Error);
37 static DWORD ListTests(IN BOOLEAN IncludeHidden);
38 static PKMT_TESTFUNC FindTest(IN PCSTR TestName);
39 static DWORD OutputResult(IN PCSTR TestName);
40 static DWORD RunTest(IN PCSTR TestName);
41 int __cdecl main(int ArgCount, char **Arguments);
42 
51 static
52 void
54  IN DWORD Error)
55 {
56  PSTR Message;
59  {
60  fprintf(stderr, "%s: Could not retrieve error message (error 0x%08lx). Original error: 0x%08lx\n",
62  return;
63  }
64 
65  fprintf(stderr, "%s: error 0x%08lx: %s\n", ErrorFileAndLine, Error, Message);
66 
68 }
69 
79 static
80 INT
82  IN PCSTR Str1,
83  IN PCSTR Str2)
84 {
85  if (*Str1 == '-')
86  ++Str1;
87  if (*Str2 == '-')
88  ++Str2;
89  while (*Str1 && *Str1 == *Str2)
90  {
91  ++Str1;
92  ++Str2;
93  }
94  return *Str1 - *Str2;
95 }
96 
109 static
110 DWORD
112  IN BOOLEAN IncludeHidden)
113 {
115  CHAR Buffer[1024];
117  PCSTR TestName = Buffer;
119  PCSTR NextTestName;
120 
121  puts("Valid test names:");
122 
123  // get test list from driver
126 
127  // output test list plus user-mode tests
128  while (TestEntry->TestName || *TestName)
129  {
130  if (!TestEntry->TestName)
131  {
132  NextTestName = TestName;
133  TestName += strlen(TestName) + 1;
134  }
135  else if (!*TestName)
136  {
137  NextTestName = TestEntry->TestName;
138  ++TestEntry;
139  }
140  else
141  {
142  INT Result = CompareTestNames(TestEntry->TestName, TestName);
143 
144  if (Result == 0)
145  {
146  NextTestName = TestEntry->TestName;
147  TestName += strlen(TestName) + 1;
148  ++TestEntry;
149  }
150  else if (Result < 0)
151  {
152  NextTestName = TestEntry->TestName;
153  ++TestEntry;
154  }
155  else
156  {
157  NextTestName = TestName;
158  TestName += strlen(TestName) + 1;
159  }
160  }
161 
162  if (IncludeHidden && NextTestName[0] == '-')
163  ++NextTestName;
164 
165  if (NextTestName[0] != '-')
166  printf(" %s\n", NextTestName);
167  }
168 
169 cleanup:
170  return Error;
171 }
172 
183 static
186  IN PCSTR TestName)
187 {
189 
190  for (TestEntry = TestList; TestEntry->TestName; ++TestEntry)
191  {
192  PCSTR TestEntryName = TestEntry->TestName;
193 
194  // skip leading '-' if present
195  if (*TestEntryName == '-')
196  ++TestEntryName;
197 
198  if (!lstrcmpA(TestEntryName, TestName))
199  break;
200  }
201 
202  return TestEntry->TestFunction;
203 }
204 
215 static
216 DWORD
218  IN PCSTR TestName)
219 {
222  DWORD LogBufferLength;
223  DWORD Offset = 0;
224  /* A console window can't handle a single
225  * huge block of data, so split it up */
226  const DWORD BlockSize = 8 * 1024;
227 
228  KmtFinishTest(TestName);
229 
230  LogBufferLength = ResultBuffer->LogBufferLength;
231  for (Offset = 0; Offset < LogBufferLength; Offset += BlockSize)
232  {
233  DWORD Length = min(LogBufferLength - Offset, BlockSize);
235  error(Error);
236  }
237 
238  return Error;
239 }
240 
251 static
252 DWORD
254  IN PCSTR TestName)
255 {
257  PKMT_TESTFUNC TestFunction;
259 
260  assert(TestName != NULL);
261 
262  if (!ResultBuffer)
263  {
265  if (!ResultBuffer)
269  }
270 
271  // check test list
272  TestFunction = FindTest(TestName);
273 
274  if (TestFunction)
275  {
276  TestFunction();
277  goto cleanup;
278  }
279 
280  // not found in user-mode test list, call driver
281  Error = KmtRunKernelTest(TestName);
282 
283 cleanup:
284  if (!Error)
285  Error = OutputResult(TestName);
286 
287  return Error;
288 }
289 
300 int
302  int ArgCount,
303  char **Arguments)
304 {
307  PCSTR AppName = "kmtest.exe";
308  PCSTR TestName = NULL;
310  BOOLEAN ShowHidden = FALSE;
311 
312  Error = KmtServiceInit();
313  if (Error)
314  goto cleanup;
315 
316  if (ArgCount >= 1)
317  AppName = Arguments[0];
318 
319  if (ArgCount <= 1)
320  {
321  printf("Usage: %s <test_name> - run the specified test (creates/starts the driver(s) as appropriate)\n", AppName);
322  printf(" %s --list - list available tests\n", AppName);
323  printf(" %s --list-all - list available tests, including hidden\n", AppName);
324  printf(" %s <create|delete|start|stop> - manage the kmtest driver\n\n", AppName);
326  }
327  else
328  {
329  TestName = Arguments[1];
330  if (!lstrcmpA(TestName, "create"))
332  else if (!lstrcmpA(TestName, "delete"))
334  else if (!lstrcmpA(TestName, "start"))
336  else if (!lstrcmpA(TestName, "stop"))
338 
339  else if (!lstrcmpA(TestName, "--list"))
341  else if (!lstrcmpA(TestName, "--list-all"))
343  else
345  }
346 
347  if (Operation)
348  {
350  if (Error)
351  goto cleanup;
352 
356 
357  switch (Operation)
358  {
359  case KMT_LIST_ALL_TESTS:
360  ShowHidden = TRUE;
361  /* fall through */
362  case KMT_LIST_TESTS:
363  Error = ListTests(ShowHidden);
364  break;
365  case KMT_RUN_TEST:
366  Error = RunTest(TestName);
367  break;
368  default:
369  assert(FALSE);
370  }
371  }
372 
373 cleanup:
374  if (KmtestHandle)
376 
377  if (ResultBuffer)
379 
381 
382  if (Error)
384  else
386 
387  if (Error)
388  {
390 
392  }
393 
394  return Status;
395 }
BOOL WINAPI WriteFile(IN HANDLE hFile, IN LPCVOID lpBuffer, IN DWORD nNumberOfBytesToWrite OPTIONAL, OUT LPDWORD lpNumberOfBytesWritten, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: rw.c:24
#define IN
Definition: typedefs.h:38
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesWritten
Definition: fltkernel.h:1293
#define TRUE
Definition: types.h:120
#define CloseHandle
Definition: compat.h:398
#define ERROR_SUCCESS
Definition: deptool.c:10
#define error(str)
Definition: mkdosfs.c:1605
#define __cdecl
Definition: accygwin.h:79
DWORD KmtStopService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:315
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
#define error_goto(Error, label)
Definition: kmtest.h:21
#define LANG_NEUTRAL
Definition: nls.h:22
const char * PCSTR
Definition: typedefs.h:51
DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, __ms_va_list *args)
Definition: format_msg.c:483
char CHAR
Definition: xmlstorage.h:175
#define KMTEST_DEVICE_PATH
Definition: kmt_public.h:35
#define SUBLANG_DEFAULT
Definition: nls.h:168
static CHAR AppName[MAX_PATH]
Definition: dem.c:252
#define INVALID_HANDLE_VALUE
Definition: compat.h:391
int WINAPI lstrcmpA(LPCSTR lpString1, LPCSTR lpString2)
Definition: lstring.c:18
#define assert(x)
Definition: debug.h:53
DWORD WINAPI GetLastError(VOID)
Definition: except.c:1059
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
DWORD KmtCloseService(IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:392
char * LPSTR
Definition: xmlstorage.h:182
int32_t INT
Definition: typedefs.h:56
#define RESULTBUFFER_SIZE
Definition: kmtest.c:22
#define EXIT_SUCCESS
Definition: rdjpgcom.c:55
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
DWORD KmtCreateService(IN PCWSTR ServiceName, IN PCWSTR ServicePath, IN PCWSTR DisplayName OPTIONAL, OUT SC_HANDLE *ServiceHandle)
Definition: service.c:92
#define GENERIC_WRITE
Definition: nt_native.h:90
static INT CompareTestNames(IN PCSTR Str1, IN PCSTR Str2)
Definition: kmtest.c:81
static VOID KmtFreeResultBuffer(PKMT_RESULTBUFFER Buffer)
Definition: kmt_test_user.h:30
#define FORMAT_MESSAGE_ALLOCATE_BUFFER
Definition: winbase.h:400
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:426
int __cdecl main(int ArgCount, char **Arguments)
Definition: kmtest.c:301
Definition: bufpool.h:45
#define FORMAT_MESSAGE_FROM_SYSTEM
Definition: winbase.h:404
#define SERVICE_NAME
Definition: kmtest.c:18
#define OPEN_EXISTING
Definition: compat.h:426
EH_STD::__list__< TestClass, eh_allocator(TestClass) > TestList
Definition: test_list.cpp:31
DWORD KmtRunKernelTest(IN PCSTR TestName)
Definition: support.c:94
KMT_OPERATION
Definition: kmtest.c:24
NTSTATUS TestEntry(IN PDRIVER_OBJECT DriverObject, IN PCUNICODE_STRING RegistryPath, OUT PCWSTR *DeviceName, IN OUT INT *Flags)
Definition: Example_drv.c:48
static DWORD RunTest(IN PCSTR TestName)
Definition: kmtest.c:253
DWORD KmtDeleteService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:356
unsigned long DWORD
Definition: ntddk_ex.h:95
#define EXIT_FAILURE
Definition: jerror.c:33
BOOL Error
Definition: chkdsk.c:66
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
CHAR Message[80]
Definition: alive.c:5
static PKMT_TESTFUNC FindTest(IN PCSTR TestName)
Definition: kmtest.c:185
#define GENERIC_READ
Definition: compat.h:124
#define STD_OUTPUT_HANDLE
Definition: winbase.h:265
SC_HANDLE KmtestServiceHandle
Definition: kmtest.c:33
int puts(const char *string)
Definition: crtsupp.c:23
Status
Definition: gdiplustypes.h:24
#define FORMAT_MESSAGE_IGNORE_INSERTS
Definition: winbase.h:401
#define IOCTL_KMTEST_GET_TESTS
Definition: kmt_public.h:13
BOOL WINAPI DeviceIoControl(IN HANDLE hDevice, IN DWORD dwIoControlCode, IN LPVOID lpInBuffer OPTIONAL, IN DWORD nInBufferSize OPTIONAL, OUT LPVOID lpOutBuffer OPTIONAL, IN DWORD nOutBufferSize OPTIONAL, OUT LPDWORD lpBytesReturned OPTIONAL, IN LPOVERLAPPED lpOverlapped OPTIONAL)
Definition: deviceio.c:136
IN OUT PVCB OUT PDIRENT OUT PBCB IN BOOLEAN CreateFile
Definition: fatprocs.h:904
#define IOCTL_KMTEST_SET_RESULTBUFFER
Definition: kmt_public.h:19
HLOCAL NTAPI LocalFree(HLOCAL hMem)
Definition: heapmem.c:1577
signed char * PSTR
Definition: retypes.h:7
#define min(a, b)
Definition: monoChain.cc:55
static PKMT_RESULTBUFFER KmtAllocateResultBuffer(SIZE_T ResultBufferSize)
Definition: kmt_test_user.h:15
PCSTR ErrorFileAndLine
Definition: kmtest.c:34
volatile LONG LogBufferLength
Definition: kmt_test.h:39
static void OutputError(IN DWORD Error)
Definition: kmtest.c:53
DWORD KmtServiceCleanup(BOOLEAN IgnoreErrors)
Definition: service.c:64
DWORD KmtServiceInit(VOID)
Definition: service.c:40
FILE * stderr
#define MAKELANGID(p, s)
Definition: nls.h:15
_In_ FLT_SET_CONTEXT_OPERATION Operation
Definition: fltkernel.h:1468
char * cleanup(char *str)
Definition: wpickclick.c:99
#define SERVICE_PATH
Definition: kmtest.c:19
KMT_TESTFUNC * PKMT_TESTFUNC
Definition: kmt_test.h:22
DWORD KmtStartService(IN PCWSTR ServiceName OPTIONAL, IN OUT SC_HANDLE *ServiceHandle)
Definition: service.c:217
static DWORD ListTests(IN BOOLEAN IncludeHidden)
Definition: kmtest.c:111
DWORD KmtCreateAndStartService(IN PCWSTR ServiceName, IN PCWSTR ServicePath, IN PCWSTR DisplayName OPTIONAL, OUT SC_HANDLE *ServiceHandle, IN BOOLEAN RestartIfRunning)
Definition: service.c:262
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
PKMT_RESULTBUFFER ResultBuffer
CHAR LogBuffer[ANYSIZE_ARRAY]
Definition: kmt_test.h:41
HANDLE KmtestHandle
Definition: kmtest.c:32
_Must_inspect_result_ _In_ PFILE_OBJECT _In_opt_ PLARGE_INTEGER _In_ ULONG _In_ FLT_IO_OPERATION_FLAGS _Out_opt_ PULONG BytesRead
Definition: fltkernel.h:1255
static DWORD OutputResult(IN PCSTR TestName)
Definition: kmtest.c:217
#define printf
Definition: config.h:203