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.
 
 
 
 
 
 

698 lines
17 KiB

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
debug.c
Abstract:
This file implements the debug code for the
fax project. All components that require
debug prints, asserts, etc.
Author:
Wesley Witt (wesw) 22-Dec-1995
History:
1-Sep-1999 yossg add ArielK additions, activate DebugLogPrint
only while Setup g_fIsSetupLogFileMode
.
.
Environment:
User Mode
--*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>
#include <time.h>
#include "faxreg.h"
#include "faxutil.h"
BOOL ConsoleDebugOutput = FALSE;
INT FaxDebugLevel = -1;
DWORD FaxDebugLevelEx = -1;
DWORD FaxFormatLevelEx = -1;
DWORD FaxContextLevelEx = -1;
TCHAR g_szPathToFile[MAX_PATH] = {0};
DWORD g_dwMaxSize = -1; // max log file size, -1 = no max size
FILE * g_pLogFile = NULL;
static BOOL g_fIsSetupLogFileMode = FALSE;
HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
LONG g_iLogFileRefCount = 0;
BOOL debugOutputFileString(LPCTSTR szMsg);
BOOL debugCheckFileSize();
VOID
StartDebugLog(LPTSTR lpszSetupLogFile)
{
g_fIsSetupLogFileMode = TRUE;
if (!g_pLogFile)
{
g_pLogFile = _tfopen(lpszSetupLogFile, TEXT("w"));
}
}
VOID
CloseDebugLog()
{
g_fIsSetupLogFileMode = FALSE;
if (!g_pLogFile)
{
fclose(g_pLogFile);
}
}
VOID
DebugLogPrint(
LPCTSTR buf
)
{
if (g_pLogFile)
{
_fputts(TEXT("FAX Server Setup Log: "), g_pLogFile);
_fputts( buf, g_pLogFile);
fflush(g_pLogFile);
}
}
//*****************************************************************************
//* Name: debugOpenLogFile
//* Author: Mooly Beery (MoolyB), May, 2000
//*****************************************************************************
//* DESCRIPTION:
//* Creates a log file which accepts the debug output
//* FormatLevelEx should be set in the registry to include DBG_PRNT_TO_FILE
//*
//* PARAMETERS:
//* [IN] LPCTSTR lpctstrFilename:
//* the filename which will be created in the temporary folder
//* [IN] DWORD dwMaxSize
//* Maximum allowed log file size in bytes. -1 means no max size.
//*
//* RETURN VALUE:
//* FALSE if the operation failed.
//* TRUE is succeeded.
//* Comments:
//* this function should be used together with CloseLogFile()
//*****************************************************************************
BOOL debugOpenLogFile(LPCTSTR lpctstrFilename, DWORD dwMaxSize)
{
TCHAR szFilename[MAX_PATH] = {0};
TCHAR szTempFolder[MAX_PATH] = {0};
if (g_hLogFile!=INVALID_HANDLE_VALUE)
{
InterlockedIncrement(&g_iLogFileRefCount);
return TRUE;
}
if (!lpctstrFilename)
{
return FALSE;
}
// first expand the filename
if (ExpandEnvironmentStrings(lpctstrFilename,szFilename,MAX_PATH)==0)
{
return FALSE;
}
// is this is a file description or a complete path to file
if (_tcschr(szFilename,_T('\\'))==NULL)
{
// this is just the file's name, need to add the temp folder to it.
if (GetTempPath(MAX_PATH,szTempFolder)==0)
{
return FALSE;
}
_tcsncpy(g_szPathToFile,szTempFolder,MAX_PATH-1);
_tcsncat(g_szPathToFile,szFilename,MAX_PATH-_tcslen(g_szPathToFile)-1);
}
else
{
// this is the full path to the log file, use it.
_tcsncpy(g_szPathToFile,szFilename,MAX_PATH-1);
}
g_dwMaxSize = dwMaxSize;
g_hLogFile = ::SafeCreateFile(
g_szPathToFile,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
OPEN_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
NULL);
if (g_hLogFile==INVALID_HANDLE_VALUE)
{
return FALSE;
}
DWORD dwFilePointer = ::SetFilePointer(g_hLogFile,0,NULL,FILE_END);
if (dwFilePointer==INVALID_SET_FILE_POINTER)
{
::CloseHandle(g_hLogFile);
g_hLogFile = INVALID_HANDLE_VALUE;
return FALSE;
}
InterlockedExchange(&g_iLogFileRefCount,1);
return TRUE;
}
//*****************************************************************************
//* Name: CloseLogFile
//* Author: Mooly Beery (MoolyB), May, 2000
//*****************************************************************************
//* DESCRIPTION:
//* Closes the log file which accepts the debug output
//*
//* PARAMETERS:
//*
//* RETURN VALUE:
//*
//* Comments:
//* this function should be used together with OpenLogFile()
//*****************************************************************************
void debugCloseLogFile()
{
InterlockedDecrement(&g_iLogFileRefCount);
if (g_iLogFileRefCount==0)
{
if (g_hLogFile!=INVALID_HANDLE_VALUE)
{
::CloseHandle(g_hLogFile);
g_hLogFile = INVALID_HANDLE_VALUE;
}
}
}
DWORD
GetDebugLevel(
VOID
)
{
DWORD rc;
DWORD err;
DWORD size;
DWORD type;
HKEY hkey;
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGKEY_FAX_CLIENT,
0,
KEY_READ,
&hkey);
if (err != ERROR_SUCCESS)
return 0;
size = sizeof(DWORD);
err = RegQueryValueEx(hkey,
REGVAL_DBGLEVEL,
0,
&type,
(LPBYTE)&rc,
&size);
if (err != ERROR_SUCCESS || type != REG_DWORD)
rc = 0;
RegCloseKey(hkey);
return rc;
}
DWORD
GetDebugLevelEx(
VOID
)
{
DWORD RetVal = 0;
DWORD err;
DWORD size;
DWORD type;
HKEY hkey;
// first let's set the defaults
FaxDebugLevelEx = 0; // Default get no debug output
FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
FaxContextLevelEx = DEBUG_CONTEXT_ALL;
err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
REGKEY_FAX_CLIENT,
0,
KEY_READ,
&hkey);
if (err != ERROR_SUCCESS)
return RetVal;
size = sizeof(DWORD);
err = RegQueryValueEx(hkey,
REGVAL_DBGLEVEL_EX,
0,
&type,
(LPBYTE)&RetVal,
&size);
if (err != ERROR_SUCCESS || type != REG_DWORD)
{
RetVal = 0;
}
size = sizeof(DWORD);
err = RegQueryValueEx(hkey,
REGVAL_DBGFORMAT_EX,
0,
&type,
(LPBYTE)&FaxFormatLevelEx,
&size);
if (err != ERROR_SUCCESS || type != REG_DWORD)
{
FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
}
err = RegQueryValueEx(hkey,
REGVAL_DBGCONTEXT_EX,
0,
&type,
(LPBYTE)&FaxContextLevelEx,
&size);
if (err != ERROR_SUCCESS || type != REG_DWORD)
{
FaxContextLevelEx = DEBUG_CONTEXT_ALL;
}
RegCloseKey(hkey);
return RetVal;
}
void dprintfex
(
DEBUG_MESSAGE_CONTEXT nMessageContext,
DEBUG_MESSAGE_TYPE nMessageType,
LPCTSTR lpctstrDbgFunctionName,
LPCTSTR lpctstrFile,
DWORD dwLine,
LPCTSTR lpctstrFormat,
...
)
{
TCHAR buf[2048] = {0};
DWORD len;
va_list arg_ptr;
TCHAR szExtFormat[2048] = {0};
LPTSTR lptstrMsgPrefix;
TCHAR szTimeBuff[10];
TCHAR szDateBuff[10];
DWORD dwInd = 0;
TCHAR bufLocalFile[MAX_PATH] = {0};
LPTSTR lptstrShortFile = NULL;
LPTSTR lptstrProject = NULL;
DWORD dwLastError = GetLastError();
static BOOL bChecked = FALSE;
if (!bChecked)
{
if (FaxDebugLevelEx==-1)
FaxDebugLevelEx = GetDebugLevelEx();
bChecked = TRUE;
}
if (FaxDebugLevelEx == 0)
{
goto exit;
}
if (!(nMessageType & FaxDebugLevelEx))
{
goto exit;
}
if (!(nMessageContext & FaxContextLevelEx))
{
goto exit;
}
switch (nMessageType)
{
case DEBUG_VER_MSG:
lptstrMsgPrefix=TEXT(" ");
break;
case DEBUG_WRN_MSG:
lptstrMsgPrefix=TEXT("WRN");
break;
case DEBUG_ERR_MSG:
lptstrMsgPrefix=TEXT("ERR");
break;
case DEBUG_FAX_TAPI_MSG:
lptstrMsgPrefix=TEXT("TAP");
break;
default:
_ASSERT(FALSE);
lptstrMsgPrefix=TEXT(" ");
break;
}
// Date & Time stamps
if( FaxFormatLevelEx & DBG_PRNT_TIME_STAMP )
{
dwInd += _stprintf(&szExtFormat[dwInd],
TEXT("[%-8s %-8s]"),
_tstrdate(szDateBuff),
_tstrtime(szTimeBuff));
}
// Tick Count
if( FaxFormatLevelEx & DBG_PRNT_TICK_COUNT )
{
dwInd += _stprintf(&szExtFormat[dwInd],
TEXT("[%09d]"),
GetTickCount());
}
// Thread ID
if( FaxFormatLevelEx & DBG_PRNT_THREAD_ID )
{
dwInd += _stprintf(&szExtFormat[dwInd],
TEXT("[0x%05x]"),
GetCurrentThreadId());
}
// Message type
if( FaxFormatLevelEx & DBG_PRNT_MSG_TYPE )
{
dwInd += _stprintf(&szExtFormat[dwInd],
TEXT("[%s]"),
lptstrMsgPrefix);
}
// filename & line number
if( FaxFormatLevelEx & DBG_PRNT_FILE_LINE )
{
_tcsncpy(bufLocalFile,lpctstrFile,MAX_PATH-1);
lptstrShortFile = _tcsrchr(bufLocalFile,_T('\\'));
if (lptstrShortFile)
{
(*lptstrShortFile) = _T('\0');
lptstrProject = _tcsrchr(bufLocalFile,_T('\\'));
(*lptstrShortFile) = _T('\\');
if (lptstrProject)
lptstrProject = _tcsinc(lptstrProject);
}
dwInd += _stprintf( &szExtFormat[dwInd],
TEXT("[%-20s][%-4ld]"),
lptstrProject,
dwLine);
}
// Module name
if( FaxFormatLevelEx & DBG_PRNT_MOD_NAME )
{
dwInd += _stprintf(&szExtFormat[dwInd],
TEXT("[%-20s]"),
lpctstrDbgFunctionName);
}
// Now comes the actual message
va_start(arg_ptr, lpctstrFormat);
_vsntprintf(buf, ARR_SIZE(buf) - 1, lpctstrFormat, arg_ptr);
len = _tcslen(buf);
_tcsncpy (&szExtFormat[dwInd], buf, ARR_SIZE(szExtFormat) - dwInd - 1);
dwInd += len;
//
// Limit index to szExtFormat size
//
if (dwInd > ARR_SIZE(szExtFormat)-3)
{
dwInd = ARR_SIZE(szExtFormat)-3;
}
_stprintf( &szExtFormat[dwInd],TEXT("\r\n"));
if( FaxFormatLevelEx & DBG_PRNT_TO_STD )
{
OutputDebugString( szExtFormat);
}
if ( FaxFormatLevelEx & DBG_PRNT_TO_FILE )
{
if (g_hLogFile!=INVALID_HANDLE_VALUE)
{
debugOutputFileString(szExtFormat);
}
}
exit:
SetLastError (dwLastError); // dprintfex will not change LastError
return;
}
BOOL debugOutputFileString(LPCTSTR szMsg)
{
BOOL bRes = FALSE;
//
// Attempt to add the line to a log file
//
#ifdef UNICODE
char sFileMsg[2000];
int Count = WideCharToMultiByte(
CP_ACP,
0,
szMsg,
-1,
sFileMsg,
sizeof(sFileMsg)/sizeof(sFileMsg[0]),
NULL,
NULL
);
if (Count==0)
{
return bRes;
}
#else
const char* sFileMsg = szMsg;
#endif
DWORD dwNumBytesWritten = 0;
DWORD dwNumOfBytesToWrite = strlen(sFileMsg);
if (!::WriteFile(g_hLogFile,sFileMsg,dwNumOfBytesToWrite,&dwNumBytesWritten,NULL))
{
return bRes;
}
if (dwNumBytesWritten!=dwNumOfBytesToWrite)
{
return bRes;
}
// ::FlushFileBuffers(g_hLogFile);
if (g_dwMaxSize != -1)
{ // There's a file size limitation, let's see if we exceeded it
debugCheckFileSize();
// Ignore return value - there's nothing we can do about it anyway
}
bRes = TRUE;
return bRes;
}
//*****************************************************************************
//* Name: debugCheckFileSize
//* Author: Jonathan Barner (t-jonb), August 2001
//*****************************************************************************
//* DESCRIPTION:
//* Checks whether the log file exceeded the maximum size specified
//* in debugOpenLogFile. If so, renames the file (overwriting the last
//* renamed file, if exists), and creates a new log file.
//*
//* PARAMETERS: none
//* RETURN VALUE: TRUE - success, FALSE - failure
//*
//*****************************************************************************
BOOL debugCheckFileSize()
{
DWORD dwSizeHigh=0, dwSizeLow=0;
dwSizeLow = GetFileSize(g_hLogFile, &dwSizeHigh);
if (dwSizeLow==INVALID_FILE_SIZE && (GetLastError()!=NO_ERROR))
{
return FALSE;
}
if (dwSizeHigh>0 || dwSizeLow>g_dwMaxSize)
{
TCHAR szPathToFileOld[MAX_PATH] = {0};
PTCHAR lpszDot = NULL;
_tcsncpy(szPathToFileOld, g_szPathToFile, MAX_PATH - 1);
// Change File.txt into FileOld.txt
lpszDot = _tcsrchr(szPathToFileOld, _T('.'));
if (lpszDot != NULL)
{
*lpszDot = _T('\0');
}
if (_tcslen(szPathToFileOld)+7 > MAX_PATH) // strlen("Old.txt") = 7
{
return FALSE;
}
_tcscat(szPathToFileOld, _T("Old.txt"));
if (! ::CloseHandle(g_hLogFile))
{
return FALSE;
}
g_hLogFile = INVALID_HANDLE_VALUE;
::MoveFileEx(g_szPathToFile, szPathToFileOld, MOVEFILE_REPLACE_EXISTING);
// MoveFileEx could fail if the old file is open. In this case, do nothing
g_hLogFile = ::SafeCreateFile(
g_szPathToFile,
GENERIC_WRITE,
FILE_SHARE_WRITE | FILE_SHARE_READ,
NULL,
CREATE_ALWAYS, // overwrite old file
FILE_ATTRIBUTE_NORMAL,
NULL);
if (g_hLogFile==INVALID_HANDLE_VALUE)
{
// We closed the file and never opened it again - so we
// need to decrement reference count
InterlockedDecrement(&g_iLogFileRefCount);
return FALSE;
}
}
return TRUE;
}
void
fax_dprintf(
LPCTSTR Format,
...
)
/*++
Routine Description:
Prints a debug string
Arguments:
format - printf() format string
... - Variable data
Return Value:
None.
--*/
{
TCHAR buf[1024] = {0};
DWORD len;
va_list arg_ptr;
static BOOL bChecked = FALSE;
if (!bChecked) {
FaxDebugLevel = (INT) GetDebugLevel();
bChecked = TRUE;
}
if (!g_fIsSetupLogFileMode)
{
if (FaxDebugLevel <= 0)
{
return;
}
}
va_start(arg_ptr, Format);
_vsntprintf(buf, ARR_SIZE(buf) - 1, Format, arg_ptr);
len = min(_tcslen( buf ), ARR_SIZE(buf)-3);
if (buf[len-1] != TEXT('\n'))
{
buf[len] = TEXT('\r');
buf[len+1] = TEXT('\n');
buf[len+2] = 0;
}
OutputDebugString( buf );
if (g_fIsSetupLogFileMode)
{
DebugLogPrint(buf);
}
} // fax_dprintf
VOID
AssertError(
LPCTSTR Expression,
LPCTSTR File,
ULONG LineNumber
)
/*++
Routine Description:
Thie function is use together with the Assert MACRO.
It checks to see if an expression is FALSE. if the
expression is FALSE, then you end up here.
Arguments:
Expression - The text of the 'C' expression
File - The file that caused the assertion
LineNumber - The line number in the file.
Return Value:
None.
--*/
{
fax_dprintf(
TEXT("Assertion error: [%s] %s @ %d\n"),
Expression,
File,
LineNumber
);
#ifdef DEBUG
__try {
DebugBreak();
} __except (UnhandledExceptionFilter(GetExceptionInformation())) {
// Nothing to do in here.
}
#endif // DEBUG
}
void debugSetProperties(DWORD dwLevel,DWORD dwFormat,DWORD dwContext)
{
FaxDebugLevelEx = dwLevel;
FaxFormatLevelEx = dwFormat;
FaxContextLevelEx = dwContext;
}