599 lines
15 KiB
C
599 lines
15 KiB
C
/*++
|
|
|
|
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>
|
|
#include <time.h>
|
|
|
|
#define READ_BUFFER_SIZE 1024*2 // Use 2K buffer
|
|
|
|
#define SIZE_DATA_ARRAY 65
|
|
|
|
//
|
|
// Global buffer used to emulate "binary data" when writing an event
|
|
// record.
|
|
//
|
|
ULONG Data[SIZE_DATA_ARRAY];
|
|
enum _OPERATION_TYPE {
|
|
Invalid,
|
|
Clear,
|
|
Read,
|
|
Write,
|
|
LPC
|
|
} Operation = Invalid;
|
|
ULONG ReadFlags;
|
|
ULONG NumberofRecords = 1;
|
|
ULONG DelayInMilliseconds = 0;
|
|
CHAR DefaultModuleName[] = "System";
|
|
PCHAR pModuleName = DefaultModuleName;
|
|
|
|
// 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( "-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( "-m <modulename> Module name to use for read/clear\n");
|
|
exit(0);
|
|
|
|
} // Usage
|
|
|
|
VOID
|
|
DisplayEventRecords( PVOID Buffer,
|
|
ULONG BufSize,
|
|
PULONG NumRecords)
|
|
|
|
{
|
|
PEVENTLOGRECORD pLogRecord;
|
|
IO_ERROR_LOG_PACKET UNALIGNED *errorPacket;
|
|
NTSTATUS Status;
|
|
ANSI_STRING StringA;
|
|
UNICODE_STRING StringU;
|
|
PWSTR pwString;
|
|
PCHAR paString;
|
|
ULONG Count = 0;
|
|
ULONG Offset = 0;
|
|
ULONG i;
|
|
UCHAR MessageBuffer[265];
|
|
BOOLEAN ioRecord;
|
|
|
|
pLogRecord = (PEVENTLOGRECORD) Buffer;
|
|
|
|
if (getenv("TZ") == NULL) {
|
|
_putenv("TZ=PDT");
|
|
}
|
|
|
|
while (Offset < BufSize && Count < *NumRecords) {
|
|
|
|
printf("\nRecord # %lu\n", pLogRecord->RecordNumber);
|
|
|
|
if (/* pLogRecord->EventType != IO_TYPE_ERROR_MESSAGE || */
|
|
pLogRecord->DataLength < sizeof(IO_ERROR_LOG_PACKET)) {
|
|
|
|
ioRecord = FALSE;
|
|
|
|
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 \n",
|
|
pLogRecord->UserSidOffset, pLogRecord->DataLength,
|
|
pLogRecord->DataOffset);
|
|
} else {
|
|
|
|
ioRecord = TRUE;
|
|
errorPacket = (PIO_ERROR_LOG_PACKET)
|
|
((PCHAR) pLogRecord + pLogRecord->DataOffset);
|
|
}
|
|
|
|
//
|
|
// Print out module name
|
|
//
|
|
|
|
pwString = (PWSTR)((LPBYTE) pLogRecord + sizeof(EVENTLOGRECORD));
|
|
RtlInitUnicodeString (&StringU, pwString);
|
|
RtlUnicodeStringToAnsiString (&StringA, &StringU, TRUE);
|
|
|
|
printf("ModuleName: %s \t", StringA.Buffer);
|
|
RtlFreeAnsiString (&StringA);
|
|
|
|
//
|
|
// Display ComputerName
|
|
//
|
|
pwString += wcslen(pwString) + 1;
|
|
|
|
RtlInitUnicodeString (&StringU, pwString);
|
|
RtlUnicodeStringToAnsiString (&StringA, &StringU, TRUE);
|
|
|
|
printf("ComputerName: %s\n",StringA.Buffer);
|
|
RtlFreeAnsiString (&StringA);
|
|
|
|
//
|
|
// Display strings
|
|
//
|
|
|
|
pwString = (PWSTR)((LPBYTE)pLogRecord + pLogRecord->StringOffset);
|
|
|
|
printf("Strings: ");
|
|
for (i=0; i<pLogRecord->NumStrings; i++) {
|
|
|
|
RtlInitUnicodeString (&StringU, pwString);
|
|
RtlUnicodeStringToAnsiString (&StringA, &StringU, TRUE);
|
|
|
|
printf(" %s ",StringA.Buffer);
|
|
|
|
RtlFreeAnsiString (&StringA);
|
|
|
|
pwString = (PWSTR)((LPBYTE)pwString + StringU.MaximumLength);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
if (ioRecord) {
|
|
|
|
MessageBuffer[0] = '\0';
|
|
FormatMessage(
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE | FORMAT_MESSAGE_IGNORE_INSERTS,
|
|
NULL,
|
|
errorPacket->ErrorCode,
|
|
0,
|
|
MessageBuffer,
|
|
256,
|
|
NULL
|
|
);
|
|
|
|
#if 0
|
|
printf("Event id: %8lx, => %s",
|
|
errorPacket->ErrorCode, MessageBuffer);
|
|
#endif
|
|
printf(MessageBuffer, errorPacket->DumpData[0], errorPacket->DumpData[1], errorPacket->DumpData[2]);
|
|
printf("Major Function code: %2x, IoControlCode: %8x\n",
|
|
errorPacket->MajorFunctionCode, errorPacket->IoControlCode);
|
|
paString = ctime((time_t *) &pLogRecord->TimeGenerated);
|
|
|
|
if (pwString != NULL) {
|
|
printf("Sequence number: %ld, Time of error: %s",
|
|
errorPacket->SequenceNumber, paString);
|
|
}
|
|
|
|
printf("Unique Error Value: %ld, Final Status: %8lx\n",
|
|
errorPacket->UniqueErrorValue, errorPacket->FinalStatus);
|
|
|
|
printf("Device Offset: %08lx%08lx\n",
|
|
errorPacket->DeviceOffset.HighPart, errorPacket->DeviceOffset.LowPart);
|
|
|
|
printf("Dump Data:");
|
|
|
|
for (i = 0; i < 1 + (errorPacket->DumpDataSize +3)/ 4; i++) {
|
|
|
|
if (!(i % 4)) {
|
|
printf("\n");
|
|
}
|
|
|
|
printf("%08lx ", errorPacket->DumpData[i]);
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
// Get next record
|
|
//
|
|
Offset += pLogRecord->Length;
|
|
|
|
pLogRecord = (PEVENTLOGRECORD)((ULONG)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_NO_MORE_FILES)
|
|
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);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
printf("ElfOpenEventLog - ");
|
|
Status = ElfOpenEventLogW (
|
|
NULL,
|
|
&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
|
|
TestElfClearLogFile(
|
|
VOID
|
|
)
|
|
|
|
{
|
|
NTSTATUS Status, IStatus;
|
|
HANDLE LogHandle;
|
|
UNICODE_STRING BackupU, ModuleNameU;
|
|
ANSI_STRING ModuleNameA;
|
|
|
|
printf("Testing ElfClearLogFile API\n");
|
|
//
|
|
// Initialize the strings
|
|
//
|
|
RtlInitAnsiString( &ModuleNameA, pModuleName);
|
|
RtlAnsiStringToUnicodeString(&ModuleNameU, &ModuleNameA, TRUE);
|
|
|
|
//
|
|
// Open the log handle
|
|
//
|
|
printf("Calling ElfOpenEventLog for CLEAR - ");
|
|
Status = ElfOpenEventLogW (
|
|
NULL,
|
|
&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.log"
|
|
//
|
|
|
|
printf("Calling ElfClearEventLogFile backing up to view.log ");
|
|
RtlInitUnicodeString( &BackupU, L"view.log" );
|
|
|
|
Status = ElfClearEventLogFileW (
|
|
LogHandle,
|
|
&BackupU
|
|
);
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
printf ("Error - 0x%lx\n", Status);
|
|
} else {
|
|
printf ("SUCCESS\n");
|
|
}
|
|
|
|
//
|
|
// 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);
|
|
}
|
|
|
|
|
|
VOID
|
|
main (
|
|
IN SHORT argc,
|
|
IN PSZ argv[]
|
|
)
|
|
{
|
|
|
|
Initialize(); // Init any data
|
|
|
|
//
|
|
// Parse the command line
|
|
//
|
|
|
|
ParseParms(argc, argv);
|
|
|
|
if ( Operation == Invalid) {
|
|
printf( "Must specify an operation\n");
|
|
Usage( );
|
|
}
|
|
|
|
switch (Operation) {
|
|
case Clear:
|
|
|
|
TestElfClearLogFile();
|
|
|
|
case Read:
|
|
|
|
if (ReadFlags & EVENTLOG_SEEK_READ) {
|
|
TestReadEventLog(1, ReadFlags, NumberofRecords) ;
|
|
}
|
|
else {
|
|
TestReadEventLog(NumberofRecords, ReadFlags, 0) ;
|
|
}
|
|
break;
|
|
|
|
}
|
|
}
|
|
|
|
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 'r':
|
|
//
|
|
// Different Read options
|
|
//
|
|
|
|
if (Operation != Invalid) {
|
|
printf("Only one operation at a time\n");
|
|
Usage();
|
|
}
|
|
|
|
Operation = Read;
|
|
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 'c':
|
|
|
|
if (Operation != Invalid) {
|
|
printf("Only one operation at a time\n");
|
|
Usage();
|
|
}
|
|
|
|
Operation = Clear;
|
|
break;
|
|
|
|
case 'm':
|
|
if (i+1 < argc) {
|
|
pModuleName = argv[++i];
|
|
}
|
|
else {
|
|
Usage();
|
|
}
|
|
break;
|
|
|
|
case '?':
|
|
case 'h':
|
|
case 'H':
|
|
Usage();
|
|
break;
|
|
|
|
default: /* Invalid options */
|
|
printf("Invalid option %c\n\n", *pch);
|
|
Usage();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//
|
|
// There aren't any non switch parms
|
|
else {
|
|
Usage();
|
|
}
|
|
}
|
|
}
|