360 lines
11 KiB
C
360 lines
11 KiB
C
|
/*++
|
||
|
|
||
|
Copyright (c) Microsoft Corporation. All rights reserved.
|
||
|
|
||
|
Module Name:
|
||
|
|
||
|
cntxtlog.h
|
||
|
|
||
|
Abstract:
|
||
|
|
||
|
This module implements more logging for setupapi
|
||
|
|
||
|
Author:
|
||
|
|
||
|
Gabe Schaffer (t-gabes) 7-Jul-1998
|
||
|
|
||
|
Revision History:
|
||
|
|
||
|
Jamie Hunter (jamiehun) 26-Aug-1998
|
||
|
|
||
|
--*/
|
||
|
|
||
|
/*
|
||
|
There are two log levels. One is set in the registry, which determines
|
||
|
what is logged and how. The other is passed as a parameter, and indicates
|
||
|
under what conditions the entry should be logged. For example, the registry
|
||
|
would say that all errors and warnings should be logged, while the call to
|
||
|
WriteLogEntry would specify in the LogLevel parameter that some string
|
||
|
should be logged as a warning.
|
||
|
|
||
|
The 24 least-significant bits specify flags which indicate the type of
|
||
|
message when passed as a parameter, or the type of messages to logged
|
||
|
when set in the registry.
|
||
|
|
||
|
The 4 most-significant bits are flags:
|
||
|
|
||
|
SETUP_LOG_DEBUGOUT - when specified in the registry, indicates that all
|
||
|
log output should be sent to the debugger as well as the logfile.
|
||
|
This flag is currently not supported as a parameter to WriteLogEntry.
|
||
|
|
||
|
SETUP_LOG_SIMPLE - when specified in the registry, indicates that all
|
||
|
logfile entries should be appended to the logfile in chronological
|
||
|
order, rather than grouped by section name. This flag is not
|
||
|
currently supported as a parameter.
|
||
|
|
||
|
SETUP_LOG_BUFFER - when specified as a parameter, indicates that the
|
||
|
message to be logged will be buffered until such time as a call to
|
||
|
WriteLogEntry with the same LogContext but this flag is not specified.
|
||
|
When an entry is to be logged without this flag set, the latest
|
||
|
message will be added to the buffer, and the buffer will be flushed to
|
||
|
the logfile.
|
||
|
|
||
|
This allows you to build up a string to log without having to do
|
||
|
buffer management everywhere.
|
||
|
|
||
|
This flag does not make sense in the registry.
|
||
|
|
||
|
NOTE: for proper functioning, do not mix log levels while buffering
|
||
|
output.
|
||
|
|
||
|
NOTE: if this flag is NOT specified, the string to be logged MUST
|
||
|
end in a newline, otherwise bad stuff will happen if another log
|
||
|
context writes to the logfile immediately afterward.
|
||
|
|
||
|
SETUP_LOG_IS_CONTEXT - when specified in the registry, indicates that
|
||
|
all context messages should be immediately logged to the logfile,
|
||
|
rather than buffered in the LogContext.
|
||
|
|
||
|
This flag should never appear in a file other than cntxtlog.*;
|
||
|
that is, as a parameter it only makes sense if added to a multiple
|
||
|
of SETUP_FIRST_LOG_CONTEXT.
|
||
|
|
||
|
NOTE: the context buffering mechanism is explained below where
|
||
|
ContextInfo is defined in SETUP_LOG_CONTEXT.
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// These registry/filename strings should probably belong elsewhere
|
||
|
//
|
||
|
#define SP_REGKEY_LOGLEVEL TEXT("LogLevel")
|
||
|
#define SP_REGKEY_LOGPATH TEXT("LogPath")
|
||
|
#define SP_REGKEY_APPLOGLEVEL TEXT("AppLogLevels")
|
||
|
#define SP_LOG_FILENAME TEXT("setupapi.log")
|
||
|
|
||
|
|
||
|
//
|
||
|
// these are for general setup log entries
|
||
|
//
|
||
|
#define SETUP_LOG_SHIFT (0)
|
||
|
#define SETUP_LOG_LEVELMASK 0x000000FF
|
||
|
#define SETUP_LOG_NOLOG 0x00000001 // indicates no-logging (remember 0 is default)
|
||
|
#define SETUP_LOG_ERROR 0x00000010 // 10-1f is varying levels of errors
|
||
|
#define SETUP_LOG_WARNING 0x00000020 // 20-2f is varying levels of warnings
|
||
|
#define SETUP_LOG_INFO 0x00000030 // 30-3f is varying levels of info
|
||
|
#define SETUP_LOG_VERBOSE 0x00000040 // 40-4f is varying levels of verbose
|
||
|
#define SETUP_LOG_TIME 0x00000050 // 50+ allow logging of time-stamped enties
|
||
|
#define SETUP_LOG_TIMEALL 0x00000060 // 60+ turns on time-stamping of all entries
|
||
|
#define SETUP_LOG_VVERBOSE 0x00000070 // 70-7f is very-verbose - reserved for stuff that logging really slows down
|
||
|
#define SETUP_LOG_DEFAULT 0x00000020
|
||
|
|
||
|
//
|
||
|
// these are for driver-only log entries
|
||
|
//
|
||
|
#define DRIVER_LOG_SHIFT (8)
|
||
|
#define DRIVER_LOG_LEVELMASK 0x0000FF00
|
||
|
#define DRIVER_LOG_NOLOG 0x00000100 // indicates no-logging (remember 0 is default)
|
||
|
#define DRIVER_LOG_ERROR 0x00001000
|
||
|
#define DRIVER_LOG_WARNING 0x00002000
|
||
|
#define DRIVER_LOG_INFO 0x00003000
|
||
|
#define DRIVER_LOG_INFO1 0x00003100
|
||
|
#define DRIVER_LOG_VERBOSE 0x00004000
|
||
|
#define DRIVER_LOG_VERBOSE1 0x00004100
|
||
|
#define DRIVER_LOG_TIME 0x00005000
|
||
|
#define DRIVER_LOG_TIMEALL 0x00006000
|
||
|
#define DRIVER_LOG_VVERBOSE 0x00007000 // 70-7f is very-verbose - reserved for stuff that logging really slows down
|
||
|
#define DRIVER_LOG_DEFAULT 0x00003000
|
||
|
|
||
|
//
|
||
|
// Calling AllocLogInfoSlot will return an index with SETUP_LOG_IS_CONTEXT set
|
||
|
// this index represents a nested stack entry for logging information
|
||
|
// that will get dumped if an actual log entry is dumped
|
||
|
// thus providing more information
|
||
|
// note that lower 16 bits are used for index, re-using above Log level bits
|
||
|
//
|
||
|
#define SETUP_LOG_IS_CONTEXT 0x10000000
|
||
|
#define SETUP_LOG_CONTEXTMASK 0x0000ffff
|
||
|
|
||
|
//
|
||
|
// pass this flag to WriteLogEntry to have the entry stored in a buffer,
|
||
|
// to be spit out the next time the flag is *not* specified
|
||
|
//
|
||
|
#define SETUP_LOG_BUFFER 0x20000000
|
||
|
|
||
|
//
|
||
|
// pass this flag to registry to have output sent to debugger
|
||
|
//
|
||
|
#define SETUP_LOG_DEBUGOUT 0x80000000
|
||
|
//
|
||
|
// pass this flag to registry to have entries simply appended to the log
|
||
|
//
|
||
|
#define SETUP_LOG_SIMPLE 0x40000000
|
||
|
//
|
||
|
// pass this flag to registry to speed up logging
|
||
|
//
|
||
|
#define SETUP_LOG_NOFLUSH 0x20000000
|
||
|
//
|
||
|
// pass this flag to registry to indicate we want to always log SETUP_LOG_ISCONTEXT
|
||
|
//
|
||
|
#define SETUP_LOG_ALL_CONTEXT 0x10000000
|
||
|
//
|
||
|
// pass this flag to registry to indicate we always want to log timestamp
|
||
|
//
|
||
|
#define SETUP_LOG_TIMESTAMP 0x08000000
|
||
|
//
|
||
|
// for validating registry log value
|
||
|
//
|
||
|
#define SETUP_LOG_VALIDREGBITS (SETUP_LOG_DEBUGOUT|SETUP_LOG_SIMPLE|SETUP_LOG_NOFLUSH|SETUP_LOG_ALL_CONTEXT|SETUP_LOG_TIMESTAMP|DRIVER_LOG_LEVELMASK|SETUP_LOG_LEVELMASK)
|
||
|
//
|
||
|
// for validating non-context log value
|
||
|
//
|
||
|
#define SETUP_LOG_VALIDLOGBITS (SETUP_LOG_DEBUGOUT|SETUP_LOG_BUFFER|DRIVER_LOG_LEVELMASK|SETUP_LOG_LEVELMASK)
|
||
|
//
|
||
|
// for validating context log value
|
||
|
//
|
||
|
#define SETUP_LOG_VALIDCONTEXTBITS (SETUP_LOG_IS_CONTEXT | SETUP_LOG_CONTEXTMASK)
|
||
|
|
||
|
|
||
|
//
|
||
|
// timeouts when waiting for log acquired by another process
|
||
|
//
|
||
|
#define MAX_LOG_INTERVAL (1000) // 1s
|
||
|
#define MAX_LOG_WAIT (10 * MAX_LOG_INTERVAL)
|
||
|
|
||
|
|
||
|
//
|
||
|
// This is the structure that holds all of the data required to persist logging
|
||
|
// information. It is not to be confused with the SETUPLOG_CONTEXT struct that
|
||
|
// is used elsewhere in setup.
|
||
|
//
|
||
|
typedef struct _SETUP_LOG_CONTEXT {
|
||
|
//
|
||
|
// Pointer to allocated name of section to be used.
|
||
|
// If NULL, a section name will be generated on first use.
|
||
|
//
|
||
|
PTSTR SectionName;
|
||
|
|
||
|
//
|
||
|
// Multiple structures may simultaneously have pointers to
|
||
|
// this struct, so a ref count is needed. CreateLogContext()
|
||
|
// will set this to 1, and DeleteLogContext() will decrement
|
||
|
// this until it reaches 0 (at which point the structure is
|
||
|
// actually freed).
|
||
|
//
|
||
|
UINT RefCount;
|
||
|
|
||
|
//
|
||
|
// This is the number of entries that have been logged in this
|
||
|
// context. If timestamp is used for the section name, this will
|
||
|
// allow us to use the time of the first error, rather than the
|
||
|
// time the log context was created.
|
||
|
//
|
||
|
UINT LoggedEntries;
|
||
|
|
||
|
//
|
||
|
// These fields are for implementation of
|
||
|
// AllocLogSlot and ReleaseLogSlot functions
|
||
|
// ContextInfo is a list of strings indexable via SETUP_LOG_CONTEXTMASK
|
||
|
// bits of a context slot returned by AllocLogSlot (ie, the slot)
|
||
|
// it is also enumeratable via the link list headed by ContextFirstUsed
|
||
|
// ContextFirstUsed points to first slot currently in use (bottom of stack)
|
||
|
// ContextIndexes[ContextFirstUsed] points to next and so on
|
||
|
// ContextLastUnused points to last slot that was released
|
||
|
// -1 is used as end of list value
|
||
|
// An entry may disappear in the middle of the stack if the context is used in
|
||
|
// more than one thread
|
||
|
//
|
||
|
PTSTR *ContextInfo; // pointer to array of strings
|
||
|
int *ContextIndexes; // by mark, is either index to ContextInfo, or to next unused mark
|
||
|
int ContextLastUnused; // LIFO linked list of unused marks
|
||
|
int ContextBufferSize; // items allocated for
|
||
|
int ContextFirstUsed; // FIFO linked list of used marks
|
||
|
int ContextFirstAuto; // FIFO linked list of auto-release used marks
|
||
|
|
||
|
//
|
||
|
// Sometimes multiple strings need to be logged as one entry, which
|
||
|
// requires making multiple calls to WriteLogEntry. If SETUP_LOG_BUFFER
|
||
|
// is specified, the text will be accumulated in the buffer until such
|
||
|
// time as SETUP_LOG_BUFFER is not specified, in which case the
|
||
|
// contents of Buffer is output together with the current string.
|
||
|
//
|
||
|
PTSTR Buffer;
|
||
|
|
||
|
//
|
||
|
// In case multiple threads access this struct simultaneously,
|
||
|
// access to ContextInfo must be serialized. Also, we
|
||
|
// don't want this to be deleted while another thread is using it.
|
||
|
//
|
||
|
|
||
|
} SETUP_LOG_CONTEXT, *PSETUP_LOG_CONTEXT;
|
||
|
|
||
|
//
|
||
|
// TLS data used by logging
|
||
|
//
|
||
|
typedef struct _SETUP_LOG_TLS {
|
||
|
//
|
||
|
// stack of context's
|
||
|
//
|
||
|
PSETUP_LOG_CONTEXT ThreadLogContext;
|
||
|
|
||
|
} SETUP_LOG_TLS, *PSETUP_LOG_TLS;
|
||
|
|
||
|
//
|
||
|
// Convenient macro for determining whether a deletion failure should be
|
||
|
// considered an error or a verbose entry.
|
||
|
//
|
||
|
#define DEL_ERR_LOG_LEVEL(Err) ((((Err) == ERROR_FILE_NOT_FOUND) || ((Err) == ERROR_PATH_NOT_FOUND)) \
|
||
|
? SETUP_LOG_VERBOSE : SETUP_LOG_ERROR)
|
||
|
|
||
|
DWORD
|
||
|
CreateLogContext(
|
||
|
IN PCTSTR SectionName, OPTIONAL
|
||
|
IN BOOL UseDefault,
|
||
|
OUT PSETUP_LOG_CONTEXT *LogContext
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
DeleteLogContext(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
RefLogContext( // increment reference count
|
||
|
IN PSETUP_LOG_CONTEXT LogContext
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
SetLogSectionName(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext,
|
||
|
IN PCTSTR SectionName
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
InheritLogContext(
|
||
|
IN TRACK_ARG_DECLARE TRACK_ARG_COMMA
|
||
|
IN PSETUP_LOG_CONTEXT Source,
|
||
|
OUT PSETUP_LOG_CONTEXT *Dest
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
ShareLogContext(
|
||
|
IN OUT PSETUP_LOG_CONTEXT *Primary,
|
||
|
IN OUT PSETUP_LOG_CONTEXT *Secondary
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
pSetupWriteLogEntry(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
|
||
|
IN DWORD Level,
|
||
|
IN DWORD MessageId,
|
||
|
IN PCTSTR MessageStr, OPTIONAL
|
||
|
... OPTIONAL
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
pSetupWriteLogError(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext, OPTIONAL
|
||
|
IN DWORD Level,
|
||
|
IN DWORD Error
|
||
|
);
|
||
|
|
||
|
#define WriteLogEntry pSetupWriteLogEntry
|
||
|
#define WriteLogError pSetupWriteLogError
|
||
|
|
||
|
DWORD
|
||
|
MakeUniqueName(
|
||
|
IN PCTSTR Component, OPTIONAL
|
||
|
OUT PTSTR * UniqueString
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
AllocLogInfoSlot(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext,
|
||
|
IN BOOL AutoRelease
|
||
|
);
|
||
|
|
||
|
DWORD
|
||
|
AllocLogInfoSlotOrLevel(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext,
|
||
|
IN DWORD Level,
|
||
|
IN BOOL AutoRelease
|
||
|
);
|
||
|
|
||
|
VOID
|
||
|
ReleaseLogInfoSlot(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext,
|
||
|
DWORD Slot
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
InitializeContextLogging(
|
||
|
IN BOOL Attach
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
ContextLoggingTlsInit(
|
||
|
IN BOOL Init
|
||
|
);
|
||
|
|
||
|
BOOL
|
||
|
SetThreadLogContext(
|
||
|
IN PSETUP_LOG_CONTEXT LogContext,
|
||
|
OUT PSETUP_LOG_CONTEXT *PrevContext OPTIONAL
|
||
|
);
|
||
|
|
||
|
PSETUP_LOG_CONTEXT
|
||
|
GetThreadLogContext(
|
||
|
);
|
||
|
|
||
|
|