windows-nt/Source/XPSP1/NT/sdktools/idwlog/idw_dbg.cpp
2020-09-26 16:20:57 +08:00

840 lines
19 KiB
C++

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <stdarg.h>
#include <time.h>
#include "network.h"
#include "idw_dbg.h"
#include "server.h"
/*++
Filename : idw_dbg.cpp
Description: Contains the idwlog1.dbg idwlog2.dbg error logging functions.
Created by: Wally Ho
History: Created on 31/01/2000.
Modified to TCHAR from my implementation in the MPK test suite.
09.19.2001 Joe Holman fixes for idwlog bugs 409338, 399178, and 352810
10.03.2001 Joe Holman make the log file report a 'w' instead of a 'a' fopen call.
11.02.2001 Joe Holman Added code to make a connection to ntburnlab2 with particular user so we
can authenticate when a machine is not in the same domain thus allowing
the file copy of logs to succeed.
11.12.2001 Joe Holman Added language value to the output log.
Contains these functions:
1. VOID OpenIdwlogDebugFile(DWORD dwPart);
2. VOID CloseIdwlogDebugFile(VOID);
3. VOID RemoveIdwlogDebugFile(DWORD dwPart);
4. VOID Idwlog (LPTSTR szMessage,...);
--*/
// Global
FILE* fpIdwlogDebugFile;
CONST DWORD MAX_SIZE_OF_DEBUG_FILE = 4000000;
static CONST LPTSTR IDWLOG_LOG = TEXT("Idwlog.log");
static CONST LPTSTR IDWLOGSERVICE_LOG = TEXT("IdwlogService.log");
TCHAR szSuiteMask[MAX_PATH*2];
TCHAR szProductType[MAX_PATH*2];
#define CLEAR_LOG TRUE
#define APPEND_LOG FALSE
VOID
MyLogger ( TCHAR * String, DWORD dwBuild, BOOL bClearLog, DWORD dwDelta )
/*++
Routine Description:
This function does the following:
- get's the computer name
- tries to create the log directory for the build
- opens the log file in append mode or overwrites
- writes out the specified string
- closes the log file
Arguments:
String - this is the text that we want to copy over to the server
dwBuild - the build # for the machine
bClearLog - if TRUE, we fopen with "w" (zero out), if FALSE, we fopen with "a" (append)
Return Value:
NONE
Notes:
NONE
Author: Joe Holman (joehol) 09.20.2001
--*/
{
FILE * stream;
TCHAR szName[MAX_PATH];
TCHAR szComputerName [ MAX_COMPUTERNAME_LENGTH + MAX_PATH] = "DefCompName";
DWORD dwSize;
dwSize = sizeof ( szComputerName );
if ( GetComputerName ( szComputerName, &dwSize ) ) {
// Try to make the directory name. This will only be succussful on the first instance for
// for this build, but we need to do the operation always to make sure it gets created.
//
if ( dwBuild == 2600 ) { // For Service Pack builds we want to use minor and major build # also to differentiate.
// We are going to use the format of:
//
// 2600.1001 (for internal use, we don't need to worry about having the major and minor data.
//
_stprintf ( szName, TEXT("\\\\ntburnlab2\\joehol\\logs\\%ld.%ld"), dwBuild, dwDelta );
CreateDirectory ( szName, NULL );
_stprintf ( szName, TEXT("\\\\ntburnlab2\\joehol\\logs\\%ld.%ld\\%s"), dwBuild, dwDelta, szComputerName );
}
else {
_stprintf ( szName, TEXT("\\\\ntburnlab2\\joehol\\logs\\%ld"), dwBuild );
CreateDirectory ( szName, NULL );
_stprintf ( szName, TEXT("\\\\ntburnlab2\\joehol\\logs\\%ld\\%s"), dwBuild, szComputerName );
}
// Idwlog ( TEXT("MyLogger szName = %s.\n"), szName );
if ( (stream = _tfopen ( szName, (bClearLog?TEXT("w"):TEXT("a")) )) != NULL ) {
TCHAR szBuf[2*MAX_PATH];
_stprintf ( szBuf, TEXT("%s"), String );
if ( fwrite ( szBuf, 1, _tcsclen(szBuf), stream ) < 1 ) {
Idwlog ( TEXT("MyLogger ERROR fwrite had an error writing.\n") );
}
fclose ( stream );
}
else {
Idwlog ( TEXT("MyLogger ERROR fopen had a problem on (%s).\n"), szName );
}
}
else {
Idwlog ( TEXT("MyLogger ERROR GetComputerName gle = %ld\n"), GetLastError() );
}
}
TCHAR * ShowProductType ( DWORD dwProductType )
/*++
Routine Description:
This function does the following:
- determines what the product type is and returns it in string format
Arguments:
dwProductType - the bit mask to examine
Return Value:
Pointer to global string to display.
Notes:
NONE
Author: Joe Holman (joehol) 09.20.2001
--*/
{
switch ( dwProductType ) {
case VER_NT_WORKSTATION :
_tcscpy ( szProductType, TEXT("VER_NT_WORKSTATION") );
break;
case VER_NT_DOMAIN_CONTROLLER :
_tcscpy ( szProductType, TEXT("VER_NT_DOMAIN_CONTROLLER") );
break;
case VER_NT_SERVER :
_tcscpy ( szProductType, TEXT("VER_NT_SERVER") );
break;
default :
strcpy ( szProductType, "ERRORUNKNOWNPRODUCTTYPE" );
}
return ( szProductType );
}
TCHAR * ShowSuiteMask ( DWORD dwSuiteMask )
/*++
Routine Description:
This function does the following:
- examines the suite mask provided and appends each suite characteristic to the global string.
Arguments:
dwSuiteMask - suite mask to do bit compares against.
Return Value:
Pointer to global string to display.
Notes:
NONE
Author: Joe Holman (joehol) 09.20.2001
--*/
{
_tcscpy ( szSuiteMask, " " );
if ( dwSuiteMask & VER_SUITE_SMALLBUSINESS ) {
_tcscat( szSuiteMask, TEXT("Small Business, ") );
}
if ( dwSuiteMask & VER_SUITE_BACKOFFICE ) {
_tcscat( szSuiteMask, TEXT("BackOffice, ") );
}
if ( dwSuiteMask & VER_SUITE_COMMUNICATIONS ) {
_tcscat( szSuiteMask, TEXT("Communications, ") );
}
if ( dwSuiteMask & VER_SUITE_TERMINAL ) {
_tcscat( szSuiteMask, TEXT("Terminal, ") );
}
if ( dwSuiteMask & VER_SUITE_SMALLBUSINESS_RESTRICTED ) {
_tcscat( szSuiteMask, TEXT("Small Business Restricted, ") );
}
if ( dwSuiteMask & VER_SUITE_EMBEDDEDNT ) {
_tcscat( szSuiteMask, TEXT("Embedded NT, ") );
}
if ( dwSuiteMask & VER_SUITE_SINGLEUSERTS ) {
_tcscat( szSuiteMask, TEXT("Supports Single User Terminal Service, ") );
}
if ( dwSuiteMask & VER_SUITE_PERSONAL ) {
_tcscat( szSuiteMask, TEXT("Home Edition, ") );
}
if ( dwSuiteMask & VER_SUITE_DATACENTER ) {
_tcscat( szSuiteMask, TEXT("Data Center, ") );
}
if ( dwSuiteMask & VER_SUITE_ENTERPRISE ) {
_tcscat( szSuiteMask, TEXT("Enterprise(old Advanced Server), ") );
}
if ( dwSuiteMask & VER_SUITE_BLADE ) {
_tcscat( szSuiteMask, TEXT("Blade, ") );
}
return ( szSuiteMask );
}
typedef struct _tagLANGINFO {
LANGID LangID;
INT Count;
} LANGINFO,*PLANGINFO;
BOOL
CALLBACK
EnumLangProc(
HANDLE hModule, // resource-module handle
LPCTSTR lpszType, // pointer to resource type
LPCTSTR lpszName, // pointer to resource name
WORD wIDLanguage, // resource language identifier
LONG_PTR lParam // application-defined parameter
)
/*++
Routine Description:
Callback that counts versions stamps.
Arguments:
Details of version enumerated version stamp. (Ignore.)
Return Value:
Indirectly thru lParam: count, langID
--*/
{
PLANGINFO LangInfo;
LangInfo = (PLANGINFO) lParam;
LangInfo->Count++;
//
// for localized build contains multiple resource,
// it usually contains 0409 as backup lang.
//
// if LangInfo->LangID != 0 means we already assigned an ID to it
//
// so when wIDLanguage == 0x409, we keep the one we got from last time
//
if ((wIDLanguage == 0x409) && (LangInfo->LangID != 0)) {
return TRUE;
}
LangInfo->LangID = wIDLanguage;
return TRUE; // continue enumeration
}
VOID
CopySetupErrorLog ( LPINSTALL_DATA pID )
/*++
Routine Description:
This function copies the machines SetupError.log file
to one of our specified servers for later analysis.
It will copy it to the following directory:
\\ntburnlab2\joehol\logs\<build#>\<machinename>
Arguments:
NONE
Return Value:
NONE
Notes:
This function should silently fail gracefully if any error
is encountered.
Author: Joe Holman (joehol) 09.20.2001
--*/
{
TCHAR szLog[2*MAX_PATH];
TCHAR szWindowsDirectory[MAX_PATH];
TCHAR Line[2*MAX_PATH];
UINT ui;
FILE* fp;
OSVERSIONINFOEX osv;
BOOL b;
DWORD dwBuild = 0;
NETRESOURCE NetResource;
TCHAR szRemoteName [MAX_PATH];
TCHAR szPassWord [ MAX_PATH ];
TCHAR szUserId [ MAX_PATH ];
DWORD dwError=0;
LPCTSTR Type = (LPCTSTR) RT_VERSION;
LPCTSTR Name = (LPCTSTR) 1;
LANGINFO LangInfo;
Idwlog ( TEXT("Entering CopySetupErrorLog.\n") );
Idwlog ( TEXT("CopySetupErrorLog pID.szSystemBuildSourceLocation = %s\n"), pID->szSystemBuildSourceLocation );
Idwlog ( TEXT("CopySetupErrorLog pID.szInstallingBuildSourceLocation = %s\n"), pID->szInstallingBuildSourceLocation );
Idwlog ( TEXT("CopySetupErrorLog g_InstallData.dwInstallingBuildDelta = %ld\n"), g_InstallData.dwInstallingBuildDelta );
// Get the windows directory for the machine.
//
ui = GetWindowsDirectory ( szWindowsDirectory, MAX_PATH );
if ( ui == 0 ) {
Idwlog ( TEXT("CopySetupErrorLog ERROR - GetWindowsDirectory gle = %ld\n"), GetLastError());
return;
}
// Gain access to the machine via a user and password since a lot of machines are NOT
// setup on the same domain and thus cannot authenticate unless we specify this.
// We will log an error if this doesn't work, but we won't stop.
//
_stprintf(szRemoteName, TEXT("%s"), SETUPLOGS_MACH);
_stprintf(szPassWord, TEXT("%s"), SETUPLOGS_PW);
_stprintf(szUserId, TEXT("%s"), SETUPLOGS_USER);
// Setup the memory for the connection.
ZeroMemory( &NetResource, sizeof( NetResource ) );
NetResource.dwType = RESOURCETYPE_DISK ;
NetResource.lpLocalName = NULL;
NetResource.lpRemoteName = szRemoteName;
NetResource.lpProvider = NULL;
_stprintf(szUserId, TEXT("%s"), SETUPLOGS_USER );
dwError = WNetAddConnection2( &NetResource, szPassWord, szUserId, 0 );
//Idwlog(TEXT("WNetAddConnection2 %s [dwError=%ld] using: %s, %s, %s\n"), (dwError==NO_ERROR)?TEXT("OK"):TEXT("ERROR"), dwError, szRemoteName, szUserId, szPassWord );
Idwlog(TEXT("WNetAddConnection2 %s [dwError=%ld] using: %s\n"), (dwError==NO_ERROR)?TEXT("OK"):TEXT("ERROR"), dwError, szRemoteName );
// Write the header out to the log file.
//
// Note: the first writes clear the log file.
//
ZeroMemory (&osv, sizeof(osv) );
osv.dwOSVersionInfoSize = sizeof ( OSVERSIONINFOEX );
b = GetVersionEx ( (OSVERSIONINFO * ) &osv );
if ( !b ) {
Idwlog ( TEXT("CopySetupErrorLog ERROR GetVersionEx FAILed, gle = %ld\n"), GetLastError());
dwBuild = 0;
MyLogger ( TEXT("IdwLog Header (GetVersionEx ERROR.)\n"), dwBuild, CLEAR_LOG, g_InstallData.dwInstallingBuildDelta );
}
else {
dwBuild = osv.dwBuildNumber;
Idwlog ( TEXT("CopySetupErrorLog retreived os version info. dwBuild = %ld\n"), dwBuild );
_stprintf ( szLog, TEXT ("IdwLog\nosv.dwOSVersionInfoSize = %x\nosv.dwMajorVersion = %d\nosv.dwMinorVersion = %d\nosv.dwBuildNumber = %d\nosv.dwPlatformId = %x\nosv.szCSDVersion = %s\nosv.wServicePackMajor = %x\nosv.wServicePackMinor = %x\nosv.wSuiteMask = %x (%s)\nosv.wProductType = %x (%s)\nszSystemBuildSource = %s\nszInstallingBuildSource = %s\n"),
osv.dwOSVersionInfoSize,
osv.dwMajorVersion,
osv.dwMinorVersion,
osv.dwBuildNumber,
osv.dwPlatformId,
osv.szCSDVersion,
osv.wServicePackMajor,
osv.wServicePackMinor,
osv.wSuiteMask,
ShowSuiteMask (osv.wSuiteMask),
osv.wProductType,
ShowProductType (osv.wProductType),
pID->szSystemBuildSourceLocation,
pID->szInstallingBuildSourceLocation
);
MyLogger ( szLog, dwBuild, CLEAR_LOG, g_InstallData.dwInstallingBuildDelta) ;
}
// Write out the language information.
//
//
ZeroMemory(&LangInfo,sizeof(LangInfo));
EnumResourceLanguages(
GetModuleHandle(TEXT("ntdll.dll")),
Type,
Name,
(ENUMRESLANGPROC) EnumLangProc,
(LONG_PTR) &LangInfo );
_stprintf ( szLog, "LangInfo.LangID = %X\n\n", LangInfo.LangID );
MyLogger ( szLog, dwBuild, APPEND_LOG, g_InstallData.dwInstallingBuildDelta );
// Open the setup error log.
//
_stprintf ( szLog, TEXT("%s\\setuperr.log"), szWindowsDirectory );
fp = _tfopen ( szLog, TEXT("r") );
if ( fp == NULL ) {
Idwlog ( TEXT("CopySetupErrorLog ERROR Couldn't open log file: %s\n"), szLog );
return;
}
Idwlog ( TEXT("CopySetupErrorLog opened local setuperr.log file.\n") );
while ( _fgetts ( Line, MAX_PATH, fp ) ) {
// Prepend our tag text and write to the Server.
//
_stprintf ( szLog, TEXT("SetupErr.Log ERROR: %s"), Line );
MyLogger ( szLog, dwBuild, APPEND_LOG, g_InstallData.dwInstallingBuildDelta );
}
fclose ( fp );
Idwlog ( TEXT("CopySetupErrorLog finished.\n") );
}
VOID
OpenIdwlogDebugFile(DWORD dwPart)
/*++
Routine Description:
This will open a logfile for the dbg output for the idwlog
The parameter it takes will let it write a *.log file for either
Part1 or Part two of the tools execution.
Arguments:
1 for service otherwise its idwlog.log.
Return Value:
NONE
Author: Wally Ho (wallyho) Jan 31st, 2000
--*/
{
TCHAR sztimeClock[128];
TCHAR sztimeDate[128];
TCHAR szmsg[MAX_PATH];
TCHAR szIdwlogFile[30];
TCHAR szIdwlogFileAndPath[100];
TCHAR szSystemDrive[4];
BOOL bUseSysDrive;
HANDLE hTestExistence;
WIN32_FIND_DATA ffd;
UINT i;
TCHAR szLogDirectoryToCreate[100] = TEXT("c:\\idwlog");
fpIdwlogDebugFile = NULL;
// Determine which part is the one we want.
if (1 == dwPart){
_tcscpy(szIdwlogFile,IDWLOGSERVICE_LOG );
}
else {
_tcscpy(szIdwlogFile, IDWLOG_LOG );
}
// Do a look for where we wrote the file first.
// The case is this: we install with a system on C drive.
// We install to d: drive. D drive boots up; we write the dbg
// on system root d:. This splits it from the initial write.
// This will find it if its on C.
// if it doesn't find it then we default to system drive.
bUseSysDrive = TRUE;
for (i= TEXT('c'); i <= TEXT('z'); i++){
_stprintf ( szIdwlogFileAndPath,
TEXT("%c:\\idwlog\\Idwlo*.dbg"), i);
hTestExistence = FindFirstFile(szIdwlogFileAndPath, &ffd);
if (INVALID_HANDLE_VALUE != hTestExistence){
FindClose(hTestExistence);
// Delete Old DBG files.
//
_stprintf ( szIdwlogFileAndPath, TEXT("%c:\\idwlog\\%s"), i, IDWLOGSERVICE_LOG );
SetFileAttributes(szIdwlogFileAndPath,FILE_ATTRIBUTE_NORMAL);
DeleteFile( szIdwlogFileAndPath);
_stprintf ( szIdwlogFileAndPath, TEXT("%c:\\idwlog\\%s"), i, IDWLOG_LOG );
SetFileAttributes(szIdwlogFileAndPath,FILE_ATTRIBUTE_NORMAL);
DeleteFile( szIdwlogFileAndPath);
}
}
for (i= TEXT('c'); i <= TEXT('z'); i++){
_stprintf ( szIdwlogFileAndPath,
TEXT("%c:\\idwlog\\%s"), i,szIdwlogFile);
hTestExistence = FindFirstFile(szIdwlogFileAndPath, &ffd);
if (INVALID_HANDLE_VALUE != hTestExistence){
// We found a log file in this case here.
//
bUseSysDrive = FALSE;
FindClose(hTestExistence);
_stprintf ( szIdwlogFileAndPath,
TEXT("%c:\\idwlog\\%s"), i, szIdwlogFile);
// Check for FileSize if Greater that 500,000 bytes then delete it.
if (ffd.nFileSizeLow >= MAX_SIZE_OF_DEBUG_FILE ) {
SetFileAttributes(szIdwlogFileAndPath,FILE_ATTRIBUTE_NORMAL);
DeleteFile( szIdwlogFileAndPath);
}
break;
}
}
if (TRUE == bUseSysDrive){
// Get the system Drive
//
if ( 0 == GetEnvironmentVariable(TEXT("SystemDrive"),szSystemDrive, 4)) {
//
// Default to C: (we're probably running on Win9x where there is
// no SystemDrive envinronment variable)
//
_tcscpy(szSystemDrive, TEXT("C:"));
}
_stprintf(szIdwlogFileAndPath,TEXT("%s\\idwlog\\%s"),
szSystemDrive,szIdwlogFile);
_stprintf( szLogDirectoryToCreate, TEXT("%s\\idwlog"), szSystemDrive ); // new
}
else {
_stprintf( szLogDirectoryToCreate, TEXT("%c\\idwlog"), szIdwlogFileAndPath[0] ); // new, szIdwlogFileAndPath filled out above.
}
// We want to store the logs in the our idwlog directory from the root, in order to fix bug #352810 - on logon, non-admin can't write log.
CreateDirectory ( szLogDirectoryToCreate, NULL ); // don't check return code since it will fail in some cases if exist.
fpIdwlogDebugFile = _tfopen(szIdwlogFileAndPath,TEXT("a"));
if(NULL == fpIdwlogDebugFile) {
// nothing we can do if the logfile is not formed?
//_tprintf ( TEXT("ERROR - Could not open log file: %s\n"), szIdwlogFileAndPath );
ExitProcess(GetLastError());
}
_tstrtime(sztimeClock);
_tstrdate(sztimeDate);
_stprintf(szmsg,TEXT("[Started on %s %s]\n"), sztimeDate, sztimeClock);
_ftprintf( fpIdwlogDebugFile,TEXT("%s"), szmsg);
/*** This is too annoying to have it hidden, so I'm removing it. JoeHol 09.17.2001
if(FALSE == SetFileAttributes(szIdwlogFileAndPath, FILE_ATTRIBUTE_HIDDEN)) {
Idwlog(TEXT("OpenIdwlogDebugFile ERROR - Could not set the debug file to Hidden.\n"));
}
***/
return;
}
VOID
CloseIdwlogDebugFile(VOID)
/*++
Routine Description:
This will close the logfile for the dbg output for the idwlog
Arguments:
NONE
Return Value:
NONE
Author: Wally Ho (wallyho) Jan 31st, 2000
--*/
{
if ( NULL != fpIdwlogDebugFile){
fclose(fpIdwlogDebugFile);
fpIdwlogDebugFile = NULL;
}
}
VOID
RemoveIdwlogDebugFile(DWORD dwPart)
/*++
Routine Description:
This will remove the logfile for the dbg output for the idwlog
Arguments:
NONE
Return Value:
NONE
Author: Wally Ho (wallyho) Jan 31st, 2000
--*/
{
TCHAR szIdwlogFile[50];
TCHAR szIdwlogFileAndPath[100];
HANDLE hTestExistence;
WIN32_FIND_DATA ffd;
UINT i;
// Determine which part is the one we want.
if (1 == dwPart){
_tcscpy(szIdwlogFile, IDWLOGSERVICE_LOG );
}
else
_tcscpy(szIdwlogFile, IDWLOG_LOG );
// Search all drives and kill the idwlog.dbg file
for (i= TEXT('c'); i <= TEXT('z'); i++){
_stprintf ( szIdwlogFileAndPath,
TEXT("%c:\\idwlog\\%s"), i,szIdwlogFile);
hTestExistence = FindFirstFile(szIdwlogFileAndPath, &ffd);
if (INVALID_HANDLE_VALUE != hTestExistence){
FindClose(hTestExistence);
_stprintf ( szIdwlogFileAndPath,
TEXT("%c:\\idwlog\\%s"), i,szIdwlogFile);
// Make sure the file is removed so we have a fresh file everytime.
_tremove(szIdwlogFile);
break;
}
}
}
VOID
Idwlog (LPTSTR szMessage,...)
/*++
Routine Description:
This is the logging function for the idwlog.
It behaves much like printf.
Arguments:
same as printf.
Return Value:
NONE
Author: Wally Ho (wallyho) Jan 31st, 2000
--*/
{
va_list vaArgs;
time_t t;
TCHAR szTimeBuffer[30];
if ( NULL != fpIdwlogDebugFile) {
// Write the time to the log.
time(&t);
_stprintf ( szTimeBuffer, TEXT("%s"), ctime(&t) );
// ctime addes a new line to the buffer. Erase it here.
szTimeBuffer[_tcslen(szTimeBuffer) - 1] = TEXT('\0');
_ftprintf( fpIdwlogDebugFile, TEXT("[%s] "),szTimeBuffer);
// Write the formatted string to the log.
va_start( vaArgs, szMessage );
_vftprintf( fpIdwlogDebugFile, szMessage, vaArgs );
va_end ( vaArgs );
// Flush the stream
fflush(fpIdwlogDebugFile);
}
}