Leaked source code of windows server 2003
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.
 
 
 
 
 
 

702 lines
22 KiB

/*++
Copyright (c) Microsoft Corporation. All rights reserved.
Module Name:
tracelog.c
Abstract:
Sample trace control program. Allows user to start, update, query, stop
event tracing, etc.
--*/
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <shellapi.h>
#include <tchar.h>
#include <wmistr.h>
#include <initguid.h>
#include <guiddef.h>
#include <evntrace.h>
#define MAXSTR 1024
// Default trace file name.
#define DEFAULT_LOGFILE_NAME _T("C:\\LogFile.Etl")
// On Windows 2000, we support up to 32 loggers at once.
// On Windows XP and .NET server, we support up to 64 loggers.
#define MAXIMUM_LOGGERS 32
// In this sample, we support the following actions.
// Additional actions that we do not use in this sample include
// Flush and Enumerate Guids functionalities. They are supported
// only on XP or higher version.
#define ACTION_QUERY 0
#define ACTION_START 1
#define ACTION_STOP 2
#define ACTION_UPDATE 3
#define ACTION_LIST 4
#define ACTION_ENABLE 5
#define ACTION_HELP 6
#define ACTION_UNDEFINED 10
void
PrintLoggerStatus(
IN PEVENT_TRACE_PROPERTIES LoggerInfo,
IN ULONG Status
);
ULONG
ahextoi(
IN TCHAR *s
);
void
StringToGuid(
IN TCHAR *str,
OUT LPGUID guid
);
void
PrintHelpMessage();
//
// main function
//
__cdecl main(argc, argv)
int argc;
char **argv;
/*++
Routine Description:
It is the main function.
Arguments:
Return Value:
Error Code defined in winerror.h : If the function succeeds,
it returns ERROR_SUCCESS (== 0).
--*/{
ULONG i, j;
ULONG Status = ERROR_SUCCESS;
LPTSTR *targv, *utargv = NULL;
// Action to be taken
USHORT Action = ACTION_UNDEFINED;
LPTSTR LoggerName;
LPTSTR LogFileName;
PEVENT_TRACE_PROPERTIES pLoggerInfo;
TRACEHANDLE LoggerHandle = 0;
// Target GUID, level and flags for enable/disable
GUID TargetGuid;
ULONG bEnable = TRUE;
ULONG SizeNeeded = 0;
// We will enable Process, Thread, Disk, and Network events
// if the Kernel Logger is requested.
BOOL bKernelLogger = FALSE;
// Allocate and initialize EVENT_TRACE_PROPERTIES structure first
SizeNeeded = sizeof(EVENT_TRACE_PROPERTIES) + 2 * MAXSTR * sizeof(TCHAR);
pLoggerInfo = (PEVENT_TRACE_PROPERTIES) malloc(SizeNeeded);
if (pLoggerInfo == NULL) {
return (ERROR_OUTOFMEMORY);
}
RtlZeroMemory(pLoggerInfo, SizeNeeded);
pLoggerInfo->Wnode.BufferSize = SizeNeeded;
pLoggerInfo->Wnode.Flags = WNODE_FLAG_TRACED_GUID;
pLoggerInfo->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pLoggerInfo->LogFileNameOffset = pLoggerInfo->LoggerNameOffset + MAXSTR * sizeof(TCHAR);
LoggerName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LoggerNameOffset);
LogFileName = (LPTSTR)((char*)pLoggerInfo + pLoggerInfo->LogFileNameOffset);
// If the logger name is not given, we will assume the kernel logger.
_tcscpy(LoggerName, KERNEL_LOGGER_NAME);
#ifdef UNICODE
if ((targv = CommandLineToArgvW(
GetCommandLineW(), // pointer to a command-line string
&argc // receives the argument count
)) == NULL) {
free(pLoggerInfo);
return (GetLastError());
};
utargv = targv;
#else
targv = argv;
#endif
//
// Parse the command line options to determine actions and parameters.
//
while (--argc > 0) {
++targv;
if (**targv == '-' || **targv == '/') { // argument found
if (targv[0][0] == '/' ) {
targv[0][0] = '-';
}
// Deterine actions.
if (!_tcsicmp(targv[0], _T("-start"))) {
Action = ACTION_START;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-enable"))) {
Action = ACTION_ENABLE;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-disable"))) {
Action = ACTION_ENABLE;
bEnable = FALSE;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-stop"))) {
Action = ACTION_STOP;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-update"))) {
Action = ACTION_UPDATE;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-query"))) {
Action = ACTION_QUERY;
if (argc > 1) {
if (targv[1][0] != '-' && targv[1][0] != '/') {
++targv; --argc;
_tcscpy(LoggerName, targv[0]);
}
}
}
else if (!_tcsicmp(targv[0], _T("-list"))) {
Action = ACTION_LIST;
}
// Get other parameters.
// Users can customize logger settings further by adding/changing
// values to pLoggerInfo. Refer to EVENT_TRACE_PROPERTIES documentation
// for available options.
// In this sample, we allow changing maximum number of buffers and
// specifying user mode (private) logger.
// We also take trace file name and guid for enable/disable.
else if (!_tcsicmp(targv[0], _T("-f"))) {
if (argc > 1) {
_tfullpath(LogFileName, targv[1], MAXSTR);
++targv; --argc;
}
}
else if (!_tcsicmp(targv[0], _T("-guid"))) {
if (argc > 1) {
// -guid #00000000-0000-0000-0000-000000000000
if (targv[1][0] == _T('#')) {
StringToGuid(&targv[1][1], &TargetGuid);
++targv; --argc;
}
}
}
else if (!_tcsicmp(targv[0], _T("-max"))) {
if (argc > 1) {
pLoggerInfo->MaximumBuffers = _ttoi(targv[1]);
++targv; --argc;
}
}
else if (!_tcsicmp(targv[0], _T("-um"))) {
pLoggerInfo->LogFileMode |= EVENT_TRACE_PRIVATE_LOGGER_MODE;
}
else if ( targv[0][1] == 'h' || targv[0][1] == 'H' || targv[0][1] == '?'){
Action = ACTION_HELP;
PrintHelpMessage();
if (utargv != NULL) {
GlobalFree(utargv);
}
free(pLoggerInfo);
return (ERROR_SUCCESS);
}
else Action = ACTION_UNDEFINED;
}
else {
_tprintf(_T("Invalid option given: %s\n"), targv[0]);
Status = ERROR_INVALID_PARAMETER;
SetLastError(Status);
if (utargv != NULL) {
GlobalFree(utargv);
}
free(pLoggerInfo);
return (Status);
}
}
// Set the kernel logger parameters.
if (!_tcscmp(LoggerName, KERNEL_LOGGER_NAME)) {
// Set enable flags. Users can add options to add additional kernel events
// or remove some of these events.
pLoggerInfo->EnableFlags |= EVENT_TRACE_FLAG_PROCESS;
pLoggerInfo->EnableFlags |= EVENT_TRACE_FLAG_THREAD;
pLoggerInfo->EnableFlags |= EVENT_TRACE_FLAG_DISK_IO;
pLoggerInfo->EnableFlags |= EVENT_TRACE_FLAG_NETWORK_TCPIP;
pLoggerInfo->Wnode.Guid = SystemTraceControlGuid;
bKernelLogger = TRUE;
}
else if (pLoggerInfo->LogFileMode & EVENT_TRACE_PRIVATE_LOGGER_MODE) {
// We must provide a control GUID for a private logger.
pLoggerInfo->Wnode.Guid = TargetGuid;
}
// Process the request.
switch (Action) {
case ACTION_START:
{
// Use default file name if not given
if (_tcslen(LogFileName) == 0) {
_tcscpy(LogFileName, DEFAULT_LOGFILE_NAME);
}
Status = StartTrace(&LoggerHandle, LoggerName, pLoggerInfo);
if (Status != ERROR_SUCCESS) {
_tprintf(_T("Could not start logger: %s\n")
_T("Operation Status: %uL\n"),
LoggerName,
Status);
break;
}
_tprintf(_T("Logger Started...\n"));
}
case ACTION_ENABLE:
{
// We can allow enabling a GUID during START operation (Note no break in case ACTION_START).
// In that case, we do not need to get LoggerHandle separately.
if (Action == ACTION_ENABLE ){
// Get Logger Handle though Query.
Status = ControlTrace((TRACEHANDLE) 0, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY);
if( Status != ERROR_SUCCESS ){
_tprintf( _T("ERROR: Logger not started\n")
_T("Operation Status: %uL\n"),
Status);
break;
}
LoggerHandle = pLoggerInfo->Wnode.HistoricalContext;
}
// We do not allow EnableTrace on the Kernel Logger in this sample,
// users can use EnableFlags to enable/disable certain kernel events.
if (!bKernelLogger) {
_tprintf(_T("Enabling trace to logger %d\n"), LoggerHandle);
// In this sample, we use EnableFlag = EnableLebel = 0
Status = EnableTrace (
bEnable,
0,
0,
&TargetGuid,
LoggerHandle);
if (Status != ERROR_SUCCESS) {
_tprintf(_T("ERROR: Failed to enable Guid...\n"));
_tprintf(_T("Operation Status: %uL\n"), Status);
break;
}
}
break;
}
case ACTION_STOP :
{
LoggerHandle = (TRACEHANDLE) 0;
Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_STOP);
break;
}
case ACTION_LIST :
{
ULONG returnCount;
PEVENT_TRACE_PROPERTIES pLoggerInfo[MAXIMUM_LOGGERS];
PEVENT_TRACE_PROPERTIES pStorage, pTempStorage;
ULONG SizeForOneProperty = sizeof(EVENT_TRACE_PROPERTIES) +
2 * MAXSTR * sizeof(TCHAR);
// We need to prepare space to receieve the inforamtion on loggers.
SizeNeeded = MAXIMUM_LOGGERS * SizeForOneProperty;
pStorage = (PEVENT_TRACE_PROPERTIES)malloc(SizeNeeded);
if (pStorage == NULL) {
Status = ERROR_OUTOFMEMORY;
break;
}
RtlZeroMemory(pStorage, SizeNeeded);
// Save the pointer for free() later.
pTempStorage = pStorage;
for (i = 0; i < MAXIMUM_LOGGERS; i++) {
pStorage->Wnode.BufferSize = SizeForOneProperty;
pStorage->LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES);
pStorage->LogFileNameOffset = sizeof(EVENT_TRACE_PROPERTIES)
+ MAXSTR * sizeof(TCHAR);
pLoggerInfo[i] = pStorage;
pStorage = (PEVENT_TRACE_PROPERTIES) (
(PUCHAR)pStorage +
pStorage->Wnode.BufferSize);
}
Status = QueryAllTraces(pLoggerInfo,
MAXIMUM_LOGGERS,
&returnCount);
if (Status == ERROR_SUCCESS)
{
for (j= 0; j < returnCount; j++)
{
PrintLoggerStatus(pLoggerInfo[j],
Status);
_tprintf(_T("\n"));
}
}
free(pTempStorage);
break;
}
case ACTION_UPDATE :
{
// In this sample, users can only update MaximumBuffers and log file name.
// User can add more options for other parameters as needed.
Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_UPDATE);
break;
}
case ACTION_QUERY :
{
Status = ControlTrace(LoggerHandle, LoggerName, pLoggerInfo, EVENT_TRACE_CONTROL_QUERY);
break;
}
case ACTION_HELP:
{
PrintHelpMessage();
break;
}
default :
{
_tprintf(_T("Error: no action specified\n"));
PrintHelpMessage();
break;
}
}
if ((Action != ACTION_HELP) &&
(Action != ACTION_UNDEFINED) &&
(Action != ACTION_LIST)) {
PrintLoggerStatus(pLoggerInfo,
Status);
}
if (Status != ERROR_SUCCESS) {
SetLastError(Status);
}
if (utargv != NULL) {
GlobalFree(utargv);
}
free(pLoggerInfo);
return (Status);
}
void
PrintLoggerStatus(
IN PEVENT_TRACE_PROPERTIES LoggerInfo,
IN ULONG Status
)
/*++
Routine Description:
Prints out the status of the specified logger.
Arguments:
LoggerInfo - The pointer to the resident EVENT_TRACE_PROPERTIES that has
the information about the current logger.
Status - The operation status of the current logger.
Return Value:
None
--*/
{
LPTSTR LoggerName, LogFileName;
if ((LoggerInfo->LoggerNameOffset > 0) &&
(LoggerInfo->LoggerNameOffset < LoggerInfo->Wnode.BufferSize)) {
LoggerName = (LPTSTR) ((PUCHAR)LoggerInfo +
LoggerInfo->LoggerNameOffset);
}
else LoggerName = NULL;
if ((LoggerInfo->LogFileNameOffset > 0) &&
(LoggerInfo->LogFileNameOffset < LoggerInfo->Wnode.BufferSize)) {
LogFileName = (LPTSTR) ((PUCHAR)LoggerInfo +
LoggerInfo->LogFileNameOffset);
}
else LogFileName = NULL;
_tprintf(_T("Operation Status: %uL\n"), Status);
_tprintf(_T("Logger Name: %s\n"),
(LoggerName == NULL) ?
_T(" ") : LoggerName);
_tprintf(_T("Logger Id: %I64x\n"), LoggerInfo->Wnode.HistoricalContext);
_tprintf(_T("Logger Thread Id: %d\n"), LoggerInfo->LoggerThreadId);
if (Status != 0)
return;
_tprintf(_T("Buffer Size: %d Kb"), LoggerInfo->BufferSize);
if (LoggerInfo->LogFileMode & EVENT_TRACE_USE_PAGED_MEMORY) {
_tprintf(_T(" using paged memory\n"));
}
else {
_tprintf(_T("\n"));
}
_tprintf(_T("Maximum Buffers: %d\n"), LoggerInfo->MaximumBuffers);
_tprintf(_T("Minimum Buffers: %d\n"), LoggerInfo->MinimumBuffers);
_tprintf(_T("Number of Buffers: %d\n"), LoggerInfo->NumberOfBuffers);
_tprintf(_T("Free Buffers: %d\n"), LoggerInfo->FreeBuffers);
_tprintf(_T("Buffers Written: %d\n"), LoggerInfo->BuffersWritten);
_tprintf(_T("Events Lost: %d\n"), LoggerInfo->EventsLost);
_tprintf(_T("Log Buffers Lost: %d\n"), LoggerInfo->LogBuffersLost);
_tprintf(_T("Real Time Buffers Lost: %d\n"), LoggerInfo->RealTimeBuffersLost);
_tprintf(_T("AgeLimit: %d\n"), LoggerInfo->AgeLimit);
if (LogFileName == NULL) {
_tprintf(_T("Buffering Mode: "));
}
else {
_tprintf(_T("Log File Mode: "));
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_APPEND) {
_tprintf(_T("Append "));
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_CIRCULAR) {
_tprintf(_T("Circular\n"));
}
else if (LoggerInfo->LogFileMode & EVENT_TRACE_FILE_MODE_SEQUENTIAL) {
_tprintf(_T("Sequential\n"));
}
else {
_tprintf(_T("Sequential\n"));
}
if (LoggerInfo->LogFileMode & EVENT_TRACE_REAL_TIME_MODE) {
_tprintf(_T("Real Time mode enabled"));
_tprintf(_T("\n"));
}
if (LoggerInfo->MaximumFileSize > 0)
_tprintf(_T("Maximum File Size: %d Mb\n"), LoggerInfo->MaximumFileSize);
if (LoggerInfo->FlushTimer > 0)
_tprintf(_T("Buffer Flush Timer: %d secs\n"), LoggerInfo->FlushTimer);
if (LoggerInfo->EnableFlags != 0) {
_tprintf(_T("Enabled tracing: "));
if ((LoggerName != NULL) && (!_tcscmp(LoggerName, KERNEL_LOGGER_NAME))) {
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_PROCESS)
_tprintf(_T("Process "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_THREAD)
_tprintf(_T("Thread "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_IO)
_tprintf(_T("Disk "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_DISK_FILE_IO)
_tprintf(_T("File "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_PAGE_FAULTS)
_tprintf(_T("PageFaults "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_MEMORY_HARD_FAULTS)
_tprintf(_T("HardFaults "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_IMAGE_LOAD)
_tprintf(_T("ImageLoad "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_NETWORK_TCPIP)
_tprintf(_T("TcpIp "));
if (LoggerInfo->EnableFlags & EVENT_TRACE_FLAG_REGISTRY)
_tprintf(_T("Registry "));
}else{
_tprintf(_T("0x%08x"), LoggerInfo->EnableFlags );
}
_tprintf(_T("\n"));
}
if (LogFileName != NULL) {
_tprintf(_T("Log Filename: %s\n"), LogFileName);
}
}
ULONG
ahextoi(
IN TCHAR *s
)
/*++
Routine Description:
Converts a hex string into a number.
Arguments:
s - A hex string in TCHAR.
Return Value:
ULONG - The number in the string.
--*/
{
int len;
ULONG num, base, hex;
len = _tcslen(s);
hex = 0; base = 1; num = 0;
while (--len >= 0) {
if ( (s[len] == 'x' || s[len] == 'X') &&
(s[len-1] == '0') )
break;
if (s[len] >= '0' && s[len] <= '9')
num = s[len] - '0';
else if (s[len] >= 'a' && s[len] <= 'f')
num = (s[len] - 'a') + 10;
else if (s[len] >= 'A' && s[len] <= 'F')
num = (s[len] - 'A') + 10;
else
continue;
hex += num * base;
base = base * 16;
}
return hex;
}
void
StringToGuid(
IN TCHAR *str,
IN OUT LPGUID guid
)
/*++
Routine Description:
Converts a string into a GUID.
Arguments:
str - A string in TCHAR.
guid - The pointer to a GUID that will have the converted GUID.
Return Value:
None.
--*/
{
TCHAR temp[10];
int i;
_tcsncpy(temp, str, 8);
temp[8] = 0;
guid->Data1 = ahextoi(temp);
_tcsncpy(temp, &str[9], 4);
temp[4] = 0;
guid->Data2 = (USHORT) ahextoi(temp);
_tcsncpy(temp, &str[14], 4);
temp[4] = 0;
guid->Data3 = (USHORT) ahextoi(temp);
for (i=0; i<2; i++) {
_tcsncpy(temp, &str[19 + (i*2)], 2);
temp[2] = 0;
guid->Data4[i] = (UCHAR) ahextoi(temp);
}
for (i=2; i<8; i++) {
_tcsncpy(temp, &str[20 + (i*2)], 2);
temp[2] = 0;
guid->Data4[i] = (UCHAR) ahextoi(temp);
}
}
void PrintHelpMessage()
/*++
Routine Description:
prints out a help message.
Arguments:
None.
Return Value:
None.
--*/
{
_tprintf(_T("Usage: tracelog [actions] [options] | [-h | -help | -?]\n"));
_tprintf(_T("\n actions:\n"));
_tprintf(_T("\t-start [LoggerName] Starts up the [LoggerName] trace session\n"));
_tprintf(_T("\t-stop [LoggerName] Stops the [LoggerName] trace session\n"));
_tprintf(_T("\t-update [LoggerName] Updates the [LoggerName] trace session\n"));
_tprintf(_T("\t-enable [LoggerName] Enables providers for the [LoggerName] session\n"));
_tprintf(_T("\t-disable [LoggerName] Disables providers for the [LoggerName] session\n"));
_tprintf(_T("\t-query [LoggerName] Query status of [LoggerName] trace session\n"));
_tprintf(_T("\t-list List all trace sessions\n"));
_tprintf(_T("\n options:\n"));
_tprintf(_T("\t-um Use Process Private tracing\n"));
_tprintf(_T("\t-max <n> Sets maximum buffers\n"));
_tprintf(_T("\t-f <name> Log to file <name>\n"));
_tprintf(_T("\t-guid #<guid> Provider GUID to enable/disable\n"));
_tprintf(_T("\n"));
_tprintf(_T("\t-h\n"));
_tprintf(_T("\t-help\n"));
_tprintf(_T("\t-? Display usage information\n"));
}