You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1487 lines
40 KiB
1487 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
TEST.C
|
|
|
|
Abstract:
|
|
|
|
Test program for the eventlog service. This program calls the Elf
|
|
APIs to test out the operation of the service.
|
|
|
|
Author:
|
|
|
|
Rajen Shah (rajens) 05-Aug-1991
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
/*----------------------*/
|
|
/* INCLUDES */
|
|
/*----------------------*/
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h> // printf
|
|
#include <string.h> // stricmp
|
|
#include <stdlib.h>
|
|
#include <process.h> // exit
|
|
#include <elfcommn.h>
|
|
#include <windows.h>
|
|
#include <ntiolog.h>
|
|
#include <malloc.h>
|
|
|
|
#define READ_BUFFER_SIZE 1024*2 // Use 2K buffer
|
|
|
|
#define SIZE_DATA_ARRAY 22
|
|
|
|
#define SET_OPERATION(x) \
|
|
if (Operation != Invalid) { \
|
|
printf("Only one operation at a time\n"); \
|
|
Usage(); \
|
|
} \
|
|
Operation = x;
|
|
|
|
//
|
|
// Global buffer used to emulate "binary data" when writing an event
|
|
// record.
|
|
//
|
|
ULONG Data[SIZE_DATA_ARRAY];
|
|
enum _OPERATION_TYPE {
|
|
Invalid,
|
|
Clear,
|
|
Backup,
|
|
Read,
|
|
Write,
|
|
Notify,
|
|
TestFull,
|
|
LPC
|
|
} Operation = Invalid;
|
|
ULONG ReadFlags;
|
|
BOOL Verbose = FALSE;
|
|
ULONG NumberofRecords = 1;
|
|
ULONG DelayInMilliseconds = 0;
|
|
CHAR DefaultModuleName[] = "TESTAPP";
|
|
PCHAR pModuleName = DefaultModuleName;
|
|
PCHAR pBackupFileName;
|
|
ANSI_STRING AnsiString;
|
|
UNICODE_STRING ServerName;
|
|
BOOL ReadingBackupFile = FALSE;
|
|
BOOL ReadingModule = FALSE;
|
|
BOOL WriteInvalidRecords = FALSE;
|
|
BOOL InvalidUser = FALSE;
|
|
|
|
// Function prototypes
|
|
|
|
VOID ParseParms(ULONG argc, PCHAR *argv);
|
|
|
|
VOID
|
|
Initialize (
|
|
VOID
|
|
)
|
|
{
|
|
ULONG i;
|
|
|
|
// Initialize the values in the data buffer.
|
|
//
|
|
for (i=0; i< SIZE_DATA_ARRAY; i++)
|
|
Data[i] = i;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
Usage (
|
|
VOID
|
|
)
|
|
{
|
|
printf( "usage: \n" );
|
|
printf( "-c Clears the specified log\n");
|
|
printf( "-b <filename> Backs up the log to file <filename>\n");
|
|
printf( "-f <filename> Filename of backup log to use for read\n");
|
|
printf( "-i Generate invalid SID\n");
|
|
printf( "-l[i] nn Writes nn records thru LPC port [i ==> bad records]\n");
|
|
printf( "-m <modulename> Module name to use for read/clear\n");
|
|
printf( "-n Test out change notify\n");
|
|
printf( "-rsb Reads nn event log records sequentially backwards\n");
|
|
printf( "-rsf nn Reads nn event log records sequentially forwards\n");
|
|
printf( "-rrb <record> Reads event log from <record> backwards\n");
|
|
printf( "-rrf <record> Reads event log from <record> forwards\n");
|
|
printf( "-s <servername> Name of server to remote calls to\n");
|
|
printf( "-t nn Number of milliseconds to delay between read/write"
|
|
" (default 0)\n\tOnly used with -l switch\n");
|
|
printf( "-w <count> Writes <count> records\n");
|
|
printf( "-z Test to see if the logs are full\n");
|
|
exit(0);
|
|
|
|
} // Usage
|
|
|
|
|
|
NTSTATUS
|
|
WriteLogEntry (
|
|
HANDLE LogHandle,
|
|
ULONG EventID
|
|
)
|
|
{
|
|
#define NUM_STRINGS 2
|
|
#define SIZE_TOKEN_BUFFER 512
|
|
|
|
SYSTEMTIME systime;
|
|
NTSTATUS Status;
|
|
USHORT EventType, i;
|
|
ULONG DataSize;
|
|
PSID pUserSid = NULL;
|
|
PWSTR Strings[NUM_STRINGS] = {L"StringOne", L"StringTwo"};
|
|
PUNICODE_STRING UStrings[NUM_STRINGS];
|
|
HANDLE hProcess;
|
|
HANDLE hToken;
|
|
PTOKEN_USER pTokenUser;
|
|
DWORD SizeRequired;
|
|
|
|
EventType = EVENTLOG_INFORMATION_TYPE;
|
|
DataSize = sizeof(ULONG) * SIZE_DATA_ARRAY;
|
|
|
|
//
|
|
// Get the SID of the current user (process)
|
|
//
|
|
|
|
pTokenUser = malloc(SIZE_TOKEN_BUFFER);
|
|
|
|
if (!InvalidUser) {
|
|
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE,
|
|
GetCurrentProcessId());
|
|
if (!hProcess) {
|
|
printf("Couldn't open the process, rc = %d\n", GetLastError());
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) {
|
|
printf("Couldn't open the token, rc = %d\n", GetLastError());
|
|
CloseHandle(hProcess);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
if (!pTokenUser) {
|
|
printf("Couldn't allocate buffer for TokenUser\n");
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
if (!GetTokenInformation(hToken, TokenUser, pTokenUser, SIZE_TOKEN_BUFFER,
|
|
&SizeRequired)) {
|
|
printf("Couldn't get TokenUser information, rc = %d\n",
|
|
GetLastError());
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
free(pTokenUser);
|
|
return(STATUS_UNSUCCESSFUL);
|
|
}
|
|
|
|
CloseHandle(hToken);
|
|
CloseHandle(hProcess);
|
|
}
|
|
else {
|
|
memset(pTokenUser, 0xFADE, SIZE_TOKEN_BUFFER);
|
|
pTokenUser->User.Sid = (PSID)pUserSid;
|
|
}
|
|
|
|
pUserSid = pTokenUser->User.Sid;
|
|
|
|
for (i=0; i< SIZE_DATA_ARRAY; i++)
|
|
Data[i] += i;
|
|
|
|
// Allocate space for the unicode strings in the array, and
|
|
// copy over the strings from Strings[] to that array.
|
|
//
|
|
for (i=0; i<NUM_STRINGS; i++) {
|
|
|
|
UStrings[i] = malloc(sizeof(UNICODE_STRING));
|
|
RtlInitUnicodeString (UStrings[i], Strings[i]);
|
|
UStrings[i]->MaximumLength = UStrings[i]->Length + sizeof(WCHAR);
|
|
}
|
|
|
|
//
|
|
// Vary the data sizes.
|
|
//
|
|
|
|
GetLocalTime(&systime);
|
|
|
|
DataSize = systime.wMilliseconds % sizeof(Data);
|
|
printf("\nData Size = %lu\n", DataSize);
|
|
|
|
Status = ElfReportEventW (
|
|
LogHandle,
|
|
EventType,
|
|
0, // category
|
|
EventID,
|
|
pUserSid,
|
|
NUM_STRINGS,
|
|
DataSize,
|
|
UStrings,
|
|
(PVOID)Data,
|
|
0, // Flags - paired event support
|
|
NULL, // RecordNumber | not in product 1
|
|
NULL // TimeWritten -
|
|
);
|
|
|
|
for (i=0; i<NUM_STRINGS; i++)
|
|
free(UStrings[i]);
|
|
|
|
free(pTokenUser);
|
|
return (Status);
|
|
}
|
|
|
|
|
|
VOID
|
|
DisplayEventRecords( PVOID Buffer,
|
|
ULONG BufSize,
|
|
PULONG NumRecords)
|
|
|
|
{
|
|
PEVENTLOGRECORD pLogRecord;
|
|
LPWSTR pwString;
|
|
ULONG Count = 0;
|
|
ULONG Offset = 0;
|
|
ULONG i;
|
|
|
|
pLogRecord = (PEVENTLOGRECORD) Buffer;
|
|
|
|
while (Offset < BufSize && Count < *NumRecords) {
|
|
|
|
printf("\nRecord # %lu\n", pLogRecord->RecordNumber);
|
|
|
|
printf("Length: 0x%lx TimeGenerated: 0x%lx EventID: 0x%lx EventType: 0x%x\n",
|
|
pLogRecord->Length, pLogRecord->TimeGenerated, pLogRecord->EventID,
|
|
pLogRecord->EventType);
|
|
|
|
printf("NumStrings: 0x%x StringOffset: 0x%lx UserSidLength: 0x%lx TimeWritten: 0x%lx\n",
|
|
pLogRecord->NumStrings, pLogRecord->StringOffset,
|
|
pLogRecord->UserSidLength, pLogRecord->TimeWritten);
|
|
|
|
printf("UserSidOffset: 0x%lx DataLength: 0x%lx DataOffset: 0x%lx Category: 0x%lx\n",
|
|
pLogRecord->UserSidOffset, pLogRecord->DataLength,
|
|
pLogRecord->DataOffset, pLogRecord->EventCategory);
|
|
|
|
//
|
|
// Print out module name
|
|
//
|
|
|
|
pwString = (PWSTR)((LPBYTE) pLogRecord + sizeof(EVENTLOGRECORD));
|
|
printf("ModuleName: %ws\n", pwString);
|
|
|
|
//
|
|
// Display ComputerName
|
|
//
|
|
pwString += wcslen(pwString) + 1;
|
|
printf("ComputerName: %ws\n", pwString);
|
|
|
|
//
|
|
// Display strings
|
|
//
|
|
|
|
pwString = (PWSTR)((LPBYTE)pLogRecord + pLogRecord->StringOffset);
|
|
|
|
printf("Strings: ");
|
|
for (i=0; i<pLogRecord->NumStrings; i++) {
|
|
|
|
printf(" %ws ", pwString);
|
|
pwString += wcslen(pwString) + 1;
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
//
|
|
// If verbose mode, display binary data (up to 256 bytes)
|
|
//
|
|
|
|
if (Verbose) {
|
|
PULONG pData;
|
|
PULONG pEnd;
|
|
|
|
if (pLogRecord->DataLength < 80) {
|
|
pEnd = (PULONG)((PBYTE) pLogRecord + pLogRecord->DataOffset +
|
|
pLogRecord->DataLength);
|
|
}
|
|
else {
|
|
pEnd = (PULONG)((PBYTE) pLogRecord + pLogRecord->DataOffset +
|
|
256);
|
|
}
|
|
|
|
printf("Data: \n\n");
|
|
for (pData = (PULONG)((PBYTE) pLogRecord + pLogRecord->DataOffset);
|
|
pData < pEnd; (PBYTE) pData += 32) {
|
|
|
|
printf("\t%08x %08x %08x %08x\n", pData[0], pData[1], pData[2],
|
|
pData[3]);
|
|
}
|
|
}
|
|
|
|
// Get next record
|
|
//
|
|
Offset += pLogRecord->Length;
|
|
|
|
// pLogRecord = (PEVENTLOGRECORD)((ULONG)Buffer + Offset);
|
|
pLogRecord = (PEVENTLOGRECORD)((BYTE *)Buffer + Offset);
|
|
|
|
Count++;
|
|
|
|
}
|
|
|
|
*NumRecords = Count;
|
|
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
ReadFromLog ( HANDLE LogHandle,
|
|
PVOID Buffer,
|
|
PULONG pBytesRead,
|
|
ULONG ReadFlag,
|
|
ULONG Record
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
ULONG MinBytesNeeded;
|
|
|
|
Status = ElfReadEventLogW (
|
|
LogHandle,
|
|
ReadFlag,
|
|
Record,
|
|
Buffer,
|
|
READ_BUFFER_SIZE,
|
|
pBytesRead,
|
|
&MinBytesNeeded
|
|
);
|
|
|
|
|
|
if (Status == STATUS_BUFFER_TOO_SMALL)
|
|
printf("Buffer too small. Need %lu bytes min\n", MinBytesNeeded);
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TestReadEventLog (
|
|
ULONG Count,
|
|
ULONG ReadFlag,
|
|
ULONG Record
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status, IStatus;
|
|
|
|
HANDLE LogHandle;
|
|
UNICODE_STRING ModuleNameU;
|
|
ANSI_STRING ModuleNameA;
|
|
ULONG NumRecords, BytesReturned;
|
|
PVOID Buffer;
|
|
ULONG RecordOffset;
|
|
ULONG NumberOfRecords;
|
|
ULONG OldestRecord;
|
|
|
|
printf("Testing ElfReadEventLog API to read %lu entries\n",Count);
|
|
|
|
Buffer = malloc (READ_BUFFER_SIZE);
|
|
|
|
//
|
|
// Initialize the strings
|
|
//
|
|
NumRecords = Count;
|
|
RtlInitAnsiString(&ModuleNameA, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &ModuleNameA, TRUE);
|
|
ModuleNameU.MaximumLength = ModuleNameU.Length + sizeof(WCHAR);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
|
|
if (ReadingBackupFile) {
|
|
printf("ElfOpenBackupEventLog - ");
|
|
Status = ElfOpenBackupEventLogW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
}
|
|
else {
|
|
printf("ElfOpenEventLog - ");
|
|
Status = ElfOpenEventLogW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Error - 0x%lx\n", Status);
|
|
|
|
} else {
|
|
printf("SUCCESS\n");
|
|
|
|
//
|
|
// Get and print record information
|
|
//
|
|
|
|
Status = ElfNumberOfRecords(LogHandle, & NumberOfRecords);
|
|
if (NT_SUCCESS(Status)) {
|
|
Status = ElfOldestRecord(LogHandle, & OldestRecord);
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Query of record information failed with %X", Status);
|
|
return(Status);
|
|
}
|
|
|
|
printf("\nThere are %d records in the file, %d is the oldest"
|
|
" record number\n", NumberOfRecords, OldestRecord);
|
|
|
|
RecordOffset = Record;
|
|
|
|
while (Count && NT_SUCCESS(Status)) {
|
|
|
|
printf("Read %u records\n", NumRecords);
|
|
//
|
|
// Read from the log
|
|
//
|
|
Status = ReadFromLog ( LogHandle,
|
|
Buffer,
|
|
&BytesReturned,
|
|
ReadFlag,
|
|
RecordOffset
|
|
);
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
printf("Bytes read = 0x%lx\n", BytesReturned);
|
|
NumRecords = Count;
|
|
DisplayEventRecords(Buffer, BytesReturned, &NumRecords);
|
|
Count -= NumRecords;
|
|
}
|
|
|
|
}
|
|
printf("\n");
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (Status == STATUS_END_OF_FILE) {
|
|
printf("Tried to read more records than in log file\n");
|
|
}
|
|
else {
|
|
printf ("Error - 0x%lx. Remaining count %lu\n", Status, Count);
|
|
}
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
printf("Calling ElfCloseEventLog\n");
|
|
IStatus = ElfCloseEventLog (LogHandle);
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TestReportEvent (
|
|
ULONG Count
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status, IStatus;
|
|
HANDLE LogHandle;
|
|
UNICODE_STRING ModuleNameU;
|
|
ANSI_STRING ModuleNameA;
|
|
ULONG EventID = 99;
|
|
|
|
printf("Testing ElfReportEvent API\n");
|
|
|
|
//
|
|
// Initialize the strings
|
|
//
|
|
|
|
RtlInitAnsiString(&ModuleNameA, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &ModuleNameA, TRUE);
|
|
ModuleNameU.MaximumLength = ModuleNameU.Length + sizeof(WCHAR);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
printf("Calling ElfRegisterEventSource for WRITE %lu times - ", Count);
|
|
Status = ElfRegisterEventSourceW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Error - 0x%lx\n", Status);
|
|
|
|
} else {
|
|
printf("SUCCESS\n");
|
|
|
|
while (Count && NT_SUCCESS(Status)) {
|
|
|
|
printf("Record # %u \n", Count);
|
|
|
|
//
|
|
// Write an entry into the log
|
|
//
|
|
Data[0] = Count; // Make data "unique"
|
|
EventID = (EventID + Count) % 100; // Vary the eventids
|
|
Status = WriteLogEntry ( LogHandle, EventID );
|
|
Count--;
|
|
}
|
|
printf("\n");
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
if (Status == STATUS_LOG_FILE_FULL) {
|
|
printf("Log Full\n");
|
|
}
|
|
else {
|
|
printf ("Error - 0x%lx. Remaining count %lu\n", Status, Count);
|
|
}
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
printf("Calling ElfDeregisterEventSource\n");
|
|
IStatus = ElfDeregisterEventSource (LogHandle);
|
|
}
|
|
|
|
return (Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TestElfClearLogFile(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status, IStatus;
|
|
HANDLE LogHandle;
|
|
UNICODE_STRING BackupU, ModuleNameU;
|
|
ANSI_STRING ModuleNameA;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
HANDLE ClearHandle;
|
|
FILE_DISPOSITION_INFORMATION DeleteInfo = {TRUE};
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
BOOLEAN DontRetry = FALSE;
|
|
|
|
printf("Testing ElfClearLogFile API\n");
|
|
//
|
|
// Initialize the strings
|
|
//
|
|
RtlInitAnsiString( &ModuleNameA, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &ModuleNameA, TRUE);
|
|
ModuleNameU.MaximumLength = ModuleNameU.Length + sizeof(WCHAR);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
printf("Calling ElfOpenEventLog for CLEAR - ");
|
|
Status = ElfOpenEventLogW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Error - 0x%lx\n", Status);
|
|
|
|
} else {
|
|
printf("SUCCESS\n");
|
|
|
|
//
|
|
// Clear the log file and back it up to "view.evt"
|
|
//
|
|
|
|
RtlInitUnicodeString( &BackupU,
|
|
L"\\SystemRoot\\System32\\Config\\view.evt" );
|
|
BackupU.MaximumLength = BackupU.Length + sizeof(WCHAR);
|
|
retry:
|
|
printf("Calling ElfClearEventLogFile backing up to view.evt ");
|
|
Status = ElfClearEventLogFileW (
|
|
LogHandle,
|
|
&BackupU
|
|
);
|
|
|
|
if (Status == STATUS_OBJECT_NAME_COLLISION) {
|
|
if (DontRetry) {
|
|
printf("Still can't backup to View.Evt\n");
|
|
}
|
|
else {
|
|
printf("Failed.\nView.Evt already exists, deleting ...\n");
|
|
|
|
//
|
|
// Open the file with delete access
|
|
//
|
|
|
|
InitializeObjectAttributes(
|
|
&ObjectAttributes,
|
|
&BackupU,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
Status = NtOpenFile(&ClearHandle,
|
|
GENERIC_READ | DELETE | SYNCHRONIZE,
|
|
&ObjectAttributes,
|
|
&IoStatusBlock,
|
|
FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT
|
|
);
|
|
|
|
Status = NtSetInformationFile(
|
|
ClearHandle,
|
|
&IoStatusBlock,
|
|
&DeleteInfo,
|
|
sizeof(DeleteInfo),
|
|
FileDispositionInformation
|
|
);
|
|
|
|
if (NT_SUCCESS (Status) ) {
|
|
Status = NtClose (ClearHandle); // Discard status
|
|
goto retry;
|
|
}
|
|
|
|
printf("Delete failed 0x%lx\n",Status);
|
|
Status = NtClose (ClearHandle); // Discard status
|
|
goto JustClear;
|
|
}
|
|
}
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf ("Error - 0x%lx\n", Status);
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
JustClear:
|
|
|
|
//
|
|
// Now just clear the file without backing it up
|
|
//
|
|
printf("Calling ElfClearEventLogFile with no backup ");
|
|
Status = ElfClearEventLogFileW (
|
|
LogHandle,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf ("Error - 0x%lx\n", Status);
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
printf("Calling ElfCloseEventLog\n");
|
|
IStatus = ElfCloseEventLog (LogHandle);
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
TestElfBackupLogFile(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status, IStatus;
|
|
HANDLE LogHandle;
|
|
UNICODE_STRING BackupU, ModuleNameU;
|
|
ANSI_STRING AnsiString;
|
|
|
|
printf("Testing ElfBackupLogFile API\n");
|
|
|
|
//
|
|
// Initialize the strings
|
|
//
|
|
|
|
RtlInitAnsiString( &AnsiString, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &AnsiString, TRUE);
|
|
ModuleNameU.MaximumLength = ModuleNameU.Length + sizeof(WCHAR);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
|
|
printf("Calling ElfOpenEventLog for BACKUP - ");
|
|
Status = ElfOpenEventLogW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Error - 0x%lx\n", Status);
|
|
|
|
} else {
|
|
printf("SUCCESS\n");
|
|
|
|
//
|
|
// Backup the log file
|
|
//
|
|
|
|
printf("Calling ElfBackupEventLogFile backing up to %s ",
|
|
pBackupFileName);
|
|
|
|
RtlInitAnsiString( &AnsiString, pBackupFileName);
|
|
RtlAnsiStringToUnicodeString(&BackupU, &AnsiString, TRUE);
|
|
BackupU.MaximumLength = BackupU.Length + sizeof(WCHAR);
|
|
|
|
Status = ElfBackupEventLogFileW (
|
|
LogHandle,
|
|
&BackupU
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf ("Error - 0x%lx\n", Status);
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
|
|
printf("Calling ElfCloseEventLog - ");
|
|
IStatus = ElfCloseEventLog (LogHandle);
|
|
if (NT_SUCCESS(IStatus)) {
|
|
printf("Success\n");
|
|
}
|
|
else {
|
|
printf("Failed with code %X\n", IStatus);
|
|
}
|
|
}
|
|
|
|
return(Status);
|
|
}
|
|
|
|
#define DRIVER_NAME L"FLOPPY"
|
|
#define DEVICE_NAME L"A:"
|
|
#define STRING L"Test String"
|
|
|
|
// These include the NULL terminator, but is length in chars, not bytes
|
|
#define DRIVER_NAME_LENGTH 7
|
|
#define DEVICE_NAME_LENGTH 3
|
|
#define STRING_LENGTH 12
|
|
|
|
#define NUMBER_OF_DATA_BYTES 8
|
|
|
|
VOID
|
|
TestLPCWrite(
|
|
DWORD NumberOfRecords,
|
|
DWORD MillisecondsToDelay
|
|
)
|
|
{
|
|
|
|
HANDLE PortHandle;
|
|
UNICODE_STRING PortName;
|
|
NTSTATUS Status;
|
|
SECURITY_QUALITY_OF_SERVICE Qos;
|
|
PIO_ERROR_LOG_MESSAGE pIoErrorLogMessage;
|
|
DWORD i;
|
|
LPWSTR pDestinationString;
|
|
PPORT_MESSAGE RequestMessage;
|
|
PORT_MESSAGE ReplyMessage;
|
|
WORD DataLength;
|
|
WORD TotalLength;
|
|
INT YorN;
|
|
CHAR NumberString[8];
|
|
ULONG MessageId = 1;
|
|
DWORD BadType = 0;
|
|
|
|
//
|
|
// Warn the user about how this test works
|
|
//
|
|
|
|
printf("\nThis test doesn't end! It will write a number of\n"
|
|
"records, then prompt you to write more. This is \n"
|
|
"required since it is simulating the system thread\n"
|
|
"which never shuts down it's connection\n\n"
|
|
"Do you wish to continue with this test (y or n)? ");
|
|
|
|
YorN = getc(stdin);
|
|
|
|
if (YorN == 'n' || YorN == 'N') {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Initialize the SecurityQualityofService structure
|
|
//
|
|
|
|
Qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
|
Qos.ImpersonationLevel = SecurityImpersonation;
|
|
Qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
|
Qos.EffectiveOnly = TRUE;
|
|
|
|
//
|
|
// Connect to the LPC Port
|
|
//
|
|
|
|
RtlInitUnicodeString( &PortName, L"\\ErrorLogPort" );
|
|
|
|
Status = NtConnectPort(& PortHandle,
|
|
& PortName,
|
|
& Qos,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Connect to the LPC port failed with RC %X\n", Status);
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Allocate the memory for the Message to send to the LPC port. It
|
|
// will contain a PORT_MESSAGE followed by an IO_ERROR_LOG_MESSAGE
|
|
// followed by Drivername and Devicename UNICODE strings
|
|
//
|
|
|
|
DataLength = PORT_MAXIMUM_MESSAGE_LENGTH -
|
|
(sizeof(IO_ERROR_LOG_MESSAGE)
|
|
+ DRIVER_NAME_LENGTH * sizeof(WCHAR)
|
|
+ DEVICE_NAME_LENGTH * sizeof(WCHAR)
|
|
+ STRING_LENGTH * sizeof(WCHAR));
|
|
TotalLength = PORT_MAXIMUM_MESSAGE_LENGTH + (WORD) sizeof(PORT_MESSAGE);
|
|
|
|
RequestMessage = (PPORT_MESSAGE) malloc(TotalLength);
|
|
if (RequestMessage == NULL) {
|
|
printf("Couldn't alloc %d bytes of memory for message\n", TotalLength);
|
|
NtClose(PortHandle);
|
|
return;
|
|
}
|
|
|
|
pIoErrorLogMessage = (PIO_ERROR_LOG_MESSAGE) ((LPBYTE) RequestMessage +
|
|
sizeof(PORT_MESSAGE));
|
|
|
|
//
|
|
// Initialize the PORT_MESSAGE
|
|
//
|
|
|
|
RequestMessage->u1.s1.DataLength = PORT_MAXIMUM_MESSAGE_LENGTH;
|
|
RequestMessage->u1.s1.TotalLength = TotalLength;
|
|
RequestMessage->u2.s2.Type = 0;
|
|
RequestMessage->u2.ZeroInit = 0;
|
|
RequestMessage->ClientId.UniqueProcess = GetCurrentProcess();
|
|
RequestMessage->ClientId.UniqueThread = GetCurrentThread();
|
|
RequestMessage->MessageId = 0x1234;
|
|
|
|
//
|
|
// Initialize the IO_ERROR_LOG_MESSAGE
|
|
//
|
|
|
|
pIoErrorLogMessage->Type = IO_TYPE_ERROR_MESSAGE;
|
|
pIoErrorLogMessage->Size = PORT_MAXIMUM_MESSAGE_LENGTH;
|
|
pIoErrorLogMessage->DriverNameLength = DRIVER_NAME_LENGTH * sizeof(WCHAR);
|
|
NtQuerySystemTime((PTIME) &pIoErrorLogMessage->TimeStamp);
|
|
pIoErrorLogMessage->DriverNameOffset = sizeof(IO_ERROR_LOG_MESSAGE) +
|
|
DataLength - sizeof(DWORD);
|
|
|
|
pIoErrorLogMessage->EntryData.MajorFunctionCode = 1;
|
|
pIoErrorLogMessage->EntryData.RetryCount = 5;
|
|
pIoErrorLogMessage->EntryData.DumpDataSize = DataLength;
|
|
pIoErrorLogMessage->EntryData.NumberOfStrings = 2;
|
|
pIoErrorLogMessage->EntryData.StringOffset = sizeof(IO_ERROR_LOG_MESSAGE)
|
|
- sizeof(DWORD) + DataLength +
|
|
DRIVER_NAME_LENGTH * sizeof(WCHAR);
|
|
pIoErrorLogMessage->EntryData.EventCategory = 0;
|
|
pIoErrorLogMessage->EntryData.ErrorCode = 0xC0020008;
|
|
pIoErrorLogMessage->EntryData.UniqueErrorValue = 0x20008;
|
|
pIoErrorLogMessage->EntryData.FinalStatus = 0x1111;
|
|
pIoErrorLogMessage->EntryData.SequenceNumber = 1;
|
|
pIoErrorLogMessage->EntryData.IoControlCode = 0xFF;
|
|
pIoErrorLogMessage->EntryData.DeviceOffset =
|
|
RtlConvertUlongToLargeInteger(1);
|
|
|
|
for (i = 0; i < DataLength ; i++ ) {
|
|
pIoErrorLogMessage->EntryData.DumpData[i] = i;
|
|
}
|
|
|
|
//
|
|
// Copy the strings
|
|
//
|
|
|
|
pDestinationString = (LPWSTR) ((LPBYTE) pIoErrorLogMessage
|
|
+ sizeof(IO_ERROR_LOG_MESSAGE)
|
|
- sizeof(DWORD) + pIoErrorLogMessage->EntryData.DumpDataSize);
|
|
wcscpy(pDestinationString, DRIVER_NAME);
|
|
|
|
pDestinationString += DRIVER_NAME_LENGTH;
|
|
wcscpy(pDestinationString, DEVICE_NAME);
|
|
|
|
pDestinationString += DEVICE_NAME_LENGTH;
|
|
wcscpy(pDestinationString, STRING);
|
|
|
|
//
|
|
// Write the packet as many times as requested, with delay, then ask
|
|
// if they want to write more
|
|
//
|
|
while (NumberOfRecords) {
|
|
|
|
printf("\n\nWriting %d records\n", NumberOfRecords);
|
|
|
|
while(NumberOfRecords--) {
|
|
printf(".");
|
|
|
|
//
|
|
// Put in a unique message number
|
|
//
|
|
|
|
RequestMessage->MessageId = MessageId++;
|
|
|
|
//
|
|
// If they want invalid records, give them invalid records
|
|
//
|
|
|
|
if (WriteInvalidRecords) {
|
|
switch (BadType++) {
|
|
case 0:
|
|
pIoErrorLogMessage->EntryData.DumpDataSize++;
|
|
break;
|
|
|
|
case 1:
|
|
pIoErrorLogMessage->EntryData.NumberOfStrings++;
|
|
break;
|
|
|
|
case 2:
|
|
pIoErrorLogMessage->EntryData.StringOffset++;
|
|
break;
|
|
|
|
default:
|
|
BadType = 0;
|
|
}
|
|
}
|
|
|
|
Status = NtRequestWaitReplyPort(PortHandle,
|
|
RequestMessage,
|
|
& ReplyMessage);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Request to LPC port failed with RC %X\n", Status);
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Delay a little bit, if requested
|
|
//
|
|
|
|
if (MillisecondsToDelay) {
|
|
Sleep(MillisecondsToDelay);
|
|
}
|
|
}
|
|
printf("\nEnter the number of records to write ");
|
|
|
|
while (!gets(NumberString) || !(NumberOfRecords = atoi(NumberString))) {
|
|
printf("Enter the number of records to write ");
|
|
}
|
|
}
|
|
|
|
//
|
|
// Clean up and exit
|
|
//
|
|
|
|
Status = NtClose(PortHandle);
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Close of Port failed with RC %X\n", Status);
|
|
}
|
|
|
|
free(RequestMessage);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
TestChangeNotify(
|
|
VOID
|
|
)
|
|
{
|
|
|
|
HANDLE Event;
|
|
UNICODE_STRING ModuleNameU;
|
|
ANSI_STRING ModuleNameA;
|
|
NTSTATUS Status;
|
|
HANDLE LogHandle;
|
|
OBJECT_ATTRIBUTES obja;
|
|
ULONG NumRecords;
|
|
ULONG BytesRead;
|
|
ULONG MinBytesNeeded;
|
|
PVOID Buffer;
|
|
ULONG OldestRecord;
|
|
ULONG NumberOfRecords;
|
|
|
|
RtlInitAnsiString(&ModuleNameA, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &ModuleNameA, TRUE);
|
|
ModuleNameU.MaximumLength = ModuleNameU.Length + sizeof(WCHAR);
|
|
|
|
Buffer = malloc (READ_BUFFER_SIZE);
|
|
ASSERT(Buffer);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
|
|
printf("ElfOpenEventLog - ");
|
|
Status = ElfOpenEventLogW (
|
|
&ServerName,
|
|
&ModuleNameU,
|
|
&LogHandle
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf("Error - 0x%lx\n", Status);
|
|
return;
|
|
}
|
|
|
|
printf("SUCCESS\n");
|
|
|
|
//
|
|
// Create the Event
|
|
//
|
|
|
|
InitializeObjectAttributes( &obja, NULL, 0, NULL, NULL);
|
|
|
|
Status = NtCreateEvent(
|
|
&Event,
|
|
SYNCHRONIZE | EVENT_QUERY_STATE | EVENT_MODIFY_STATE,
|
|
&obja,
|
|
SynchronizationEvent,
|
|
FALSE
|
|
);
|
|
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Get the read pointer to the end of the log
|
|
//
|
|
|
|
Status = ElfOldestRecord(LogHandle, & OldestRecord);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
Status = ElfNumberOfRecords(LogHandle, & NumberOfRecords);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
OldestRecord += NumberOfRecords - 1;
|
|
|
|
Status = ElfReadEventLogW (
|
|
LogHandle,
|
|
EVENTLOG_SEEK_READ | EVENTLOG_FORWARDS_READ,
|
|
OldestRecord,
|
|
Buffer,
|
|
READ_BUFFER_SIZE,
|
|
&BytesRead,
|
|
&MinBytesNeeded
|
|
);
|
|
|
|
|
|
//
|
|
// This one should hit end of file
|
|
//
|
|
|
|
Status = ElfReadEventLogW (
|
|
LogHandle,
|
|
EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
|
|
0,
|
|
Buffer,
|
|
READ_BUFFER_SIZE,
|
|
&BytesRead,
|
|
&MinBytesNeeded
|
|
);
|
|
|
|
if (Status != STATUS_END_OF_FILE) {
|
|
printf("Hmmm, should have hit EOF (unless there are writes going"
|
|
" on elsewhere- %X\n", Status);
|
|
}
|
|
|
|
//
|
|
// Call ElfChangeNotify
|
|
//
|
|
|
|
Status = ElfChangeNotify(LogHandle, Event);
|
|
ASSERT(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Now loop waiting for the event to get toggled
|
|
//
|
|
|
|
while (1) {
|
|
|
|
Status = NtWaitForSingleObject(Event, FALSE, 0);
|
|
printf("The change notify event just got kicked\n");
|
|
|
|
//
|
|
// Now read the new records
|
|
//
|
|
|
|
while(1) {
|
|
|
|
Status = ElfReadEventLogW (
|
|
LogHandle,
|
|
EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ,
|
|
0,
|
|
Buffer,
|
|
READ_BUFFER_SIZE,
|
|
&BytesRead,
|
|
&MinBytesNeeded
|
|
);
|
|
|
|
if (Status == STATUS_END_OF_FILE) {
|
|
break;
|
|
}
|
|
|
|
NumRecords = 0xffff; // should be plenty
|
|
DisplayEventRecords (Buffer, BytesRead, &NumRecords);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
TestLogFull(
|
|
VOID
|
|
)
|
|
{
|
|
HANDLE hLogFile;
|
|
BOOL fIsFull;
|
|
BOOLEAN fPrevious = FALSE;
|
|
DWORD i;
|
|
DWORD dwBytesNeeded;
|
|
BOOL fIsSecLog;
|
|
|
|
LPWSTR szLogNames[] = { L"Application", L"Security", L"System" };
|
|
|
|
for (i = 0; i < sizeof(szLogNames) / sizeof(LPWSTR); i++) {
|
|
|
|
fIsSecLog = (wcscmp(szLogNames[i], L"Security") == 0);
|
|
|
|
if (fIsSecLog) {
|
|
|
|
if (!NT_SUCCESS(RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE,
|
|
TRUE,
|
|
FALSE,
|
|
&fPrevious))) {
|
|
|
|
printf("RtlAdjustPrivilege FAILED %d\n",
|
|
RtlNtStatusToDosError(GetLastError()));
|
|
}
|
|
}
|
|
|
|
hLogFile = OpenEventLogW(NULL, szLogNames[i]);
|
|
|
|
if (hLogFile != NULL) {
|
|
|
|
if (GetEventLogInformation(hLogFile,
|
|
0, // Log full infolevel
|
|
(LPBYTE)&fIsFull,
|
|
sizeof(fIsFull),
|
|
&dwBytesNeeded)) {
|
|
|
|
printf("The %ws Log is%sfull\n",
|
|
szLogNames[i],
|
|
fIsFull ? " " : " not ");
|
|
}
|
|
else {
|
|
|
|
printf("GetEventLogInformation FAILED %d for the %ws Log\n",
|
|
GetLastError(),
|
|
szLogNames[i]);
|
|
}
|
|
}
|
|
else {
|
|
|
|
printf("OpenEventLog FAILED %d for the %ws Log\n",
|
|
GetLastError(),
|
|
szLogNames[i]);
|
|
}
|
|
|
|
if (fIsSecLog) {
|
|
RtlAdjustPrivilege(SE_SECURITY_PRIVILEGE, fPrevious, FALSE, &fPrevious);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
__cdecl
|
|
main (
|
|
IN SHORT argc,
|
|
IN PSZ argv[]
|
|
)
|
|
{
|
|
|
|
Initialize(); // Init any data
|
|
|
|
//
|
|
// Parse the command line
|
|
//
|
|
|
|
ParseParms(argc, argv);
|
|
|
|
switch (Operation) {
|
|
case Clear:
|
|
|
|
TestElfClearLogFile();
|
|
break;
|
|
|
|
case Backup:
|
|
|
|
TestElfBackupLogFile();
|
|
break;
|
|
|
|
case Read:
|
|
|
|
if (ReadFlags & EVENTLOG_SEEK_READ) {
|
|
TestReadEventLog(1, ReadFlags, NumberofRecords) ;
|
|
}
|
|
else {
|
|
TestReadEventLog(NumberofRecords, ReadFlags, 0) ;
|
|
}
|
|
break;
|
|
|
|
case Write:
|
|
|
|
TestReportEvent (NumberofRecords);
|
|
break;
|
|
|
|
case LPC:
|
|
TestLPCWrite(NumberofRecords, DelayInMilliseconds);
|
|
break;
|
|
|
|
case Notify:
|
|
TestChangeNotify();
|
|
break;
|
|
|
|
case TestFull:
|
|
TestLogFull();
|
|
break;
|
|
|
|
default:
|
|
printf("Invalid switch from ParseParms %d\n", Operation);
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
ParseParms(
|
|
ULONG argc,
|
|
PCHAR *argv
|
|
)
|
|
{
|
|
|
|
ULONG i;
|
|
PCHAR pch;
|
|
|
|
for (i = 1; i < argc; i++) { /* for each argument */
|
|
if (*(pch = argv[i]) == '-') {
|
|
while (*++pch) {
|
|
switch (*pch) {
|
|
case 'b':
|
|
|
|
SET_OPERATION(Backup)
|
|
|
|
//
|
|
// Get the file name for backup
|
|
//
|
|
|
|
if (i+1 < argc) {
|
|
pBackupFileName = argv[++i];
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'c':
|
|
|
|
SET_OPERATION(Clear)
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
if (i+1 < argc) {
|
|
pModuleName = argv[++i];
|
|
ReadingBackupFile = TRUE;
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
case 'h':
|
|
case 'H':
|
|
Usage();
|
|
break;
|
|
|
|
case 'i':
|
|
InvalidUser = TRUE;
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
SET_OPERATION(LPC);
|
|
|
|
//
|
|
// See if they want invalid records
|
|
//
|
|
|
|
if (*++pch == 'i') {
|
|
WriteInvalidRecords = TRUE;
|
|
}
|
|
|
|
//
|
|
// See if they specified a number of records
|
|
//
|
|
|
|
if (i + 1 < argc && argv[i+1][0] != '-') {
|
|
NumberofRecords = atoi(argv[++i]);
|
|
if (NumberofRecords == 0) {
|
|
Usage();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
if (i+1 < argc) {
|
|
pModuleName = argv[++i];
|
|
ReadingModule = TRUE;
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case 'n':
|
|
SET_OPERATION(Notify)
|
|
break;
|
|
|
|
case 'r':
|
|
|
|
SET_OPERATION(Read)
|
|
|
|
//
|
|
// Different Read options
|
|
//
|
|
|
|
if (*++pch == 's') {
|
|
ReadFlags |= EVENTLOG_SEQUENTIAL_READ;
|
|
}
|
|
else if (*pch == 'r') {
|
|
ReadFlags |= EVENTLOG_SEEK_READ;
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
|
|
if (*++pch == 'f') {
|
|
ReadFlags |= EVENTLOG_FORWARDS_READ;
|
|
}
|
|
else if (*pch == 'b') {
|
|
ReadFlags |= EVENTLOG_BACKWARDS_READ;
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
|
|
//
|
|
// See if they specified a number of records
|
|
//
|
|
|
|
if (i + 1 < argc && argv[i+1][0] != '-') {
|
|
NumberofRecords = atoi(argv[++i]);
|
|
if (NumberofRecords == 0) {
|
|
Usage();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 's':
|
|
if (i+1 >= argc) {
|
|
printf("Must supply a server name with -s\n");
|
|
Usage();
|
|
}
|
|
RtlInitAnsiString(&AnsiString, argv[++i]);
|
|
RtlAnsiStringToUnicodeString(&ServerName, &AnsiString,
|
|
TRUE);
|
|
break;
|
|
|
|
case 't':
|
|
DelayInMilliseconds = atoi(argv[++i]);
|
|
break;
|
|
|
|
case 'v':
|
|
Verbose = TRUE;
|
|
break;
|
|
|
|
case 'w':
|
|
|
|
SET_OPERATION(Write)
|
|
|
|
//
|
|
// See if they specified a number of records
|
|
//
|
|
|
|
if (i + 1 < argc && argv[i+1][0] != '-') {
|
|
NumberofRecords = atoi(argv[++i]);
|
|
if (NumberofRecords == 0) {
|
|
Usage();
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case 'z':
|
|
|
|
SET_OPERATION(TestFull)
|
|
break;
|
|
|
|
default: /* Invalid options */
|
|
printf("Invalid option %c\n\n", *pch);
|
|
Usage();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// There aren't any non switch parms
|
|
//
|
|
|
|
else {
|
|
Usage();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Verify parms are correct
|
|
//
|
|
|
|
|
|
if ( Operation == Invalid) {
|
|
printf( "Must specify an operation\n");
|
|
Usage( );
|
|
}
|
|
|
|
if (ReadingBackupFile && ReadingModule) {
|
|
printf("-m and -f are mutually exclusive\n");
|
|
Usage();
|
|
}
|
|
|
|
if (ReadingBackupFile && Operation == Write) {
|
|
printf("You cannot write to a backup log file\n");
|
|
Usage();
|
|
}
|
|
if (DelayInMilliseconds && Operation != LPC) {
|
|
printf("\n\n-t switch is only used with -l\n\n");
|
|
}
|
|
}
|
|
|