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

  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. debug.c
  5. Abstract:
  6. This file implements the debug code for the
  7. fax project. All components that require
  8. debug prints, asserts, etc.
  9. Author:
  10. Wesley Witt (wesw) 22-Dec-1995
  11. History:
  12. 1-Sep-1999 yossg add ArielK additions, activate DebugLogPrint
  13. only while Setup g_fIsSetupLogFileMode
  14. .
  15. .
  16. Environment:
  17. User Mode
  18. --*/
  19. #include <windows.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <tchar.h>
  23. #include <time.h>
  24. #include "faxreg.h"
  25. #include "faxutil.h"
  26. BOOL ConsoleDebugOutput = FALSE;
  27. INT FaxDebugLevel = -1;
  28. DWORD FaxDebugLevelEx = -1;
  29. DWORD FaxFormatLevelEx = -1;
  30. DWORD FaxContextLevelEx = -1;
  31. TCHAR g_szPathToFile[MAX_PATH] = {0};
  32. DWORD g_dwMaxSize = -1; // max log file size, -1 = no max size
  33. FILE * g_pLogFile = NULL;
  34. static BOOL g_fIsSetupLogFileMode = FALSE;
  35. HANDLE g_hLogFile = INVALID_HANDLE_VALUE;
  36. LONG g_iLogFileRefCount = 0;
  37. BOOL debugOutputFileString(LPCTSTR szMsg);
  38. BOOL debugCheckFileSize();
  39. VOID
  40. StartDebugLog(LPTSTR lpszSetupLogFile)
  41. {
  42. g_fIsSetupLogFileMode = TRUE;
  43. if (!g_pLogFile)
  44. {
  45. g_pLogFile = _tfopen(lpszSetupLogFile, TEXT("w"));
  46. }
  47. }
  48. VOID
  49. CloseDebugLog()
  50. {
  51. g_fIsSetupLogFileMode = FALSE;
  52. if (!g_pLogFile)
  53. {
  54. fclose(g_pLogFile);
  55. }
  56. }
  57. VOID
  58. DebugLogPrint(
  59. LPCTSTR buf
  60. )
  61. {
  62. if (g_pLogFile)
  63. {
  64. _fputts(TEXT("FAX Server Setup Log: "), g_pLogFile);
  65. _fputts( buf, g_pLogFile);
  66. fflush(g_pLogFile);
  67. }
  68. }
  69. //*****************************************************************************
  70. //* Name: debugOpenLogFile
  71. //* Author: Mooly Beery (MoolyB), May, 2000
  72. //*****************************************************************************
  73. //* DESCRIPTION:
  74. //* Creates a log file which accepts the debug output
  75. //* FormatLevelEx should be set in the registry to include DBG_PRNT_TO_FILE
  76. //*
  77. //* PARAMETERS:
  78. //* [IN] LPCTSTR lpctstrFilename:
  79. //* the filename which will be created in the temporary folder
  80. //* [IN] DWORD dwMaxSize
  81. //* Maximum allowed log file size in bytes. -1 means no max size.
  82. //*
  83. //* RETURN VALUE:
  84. //* FALSE if the operation failed.
  85. //* TRUE is succeeded.
  86. //* Comments:
  87. //* this function should be used together with CloseLogFile()
  88. //*****************************************************************************
  89. BOOL debugOpenLogFile(LPCTSTR lpctstrFilename, DWORD dwMaxSize)
  90. {
  91. TCHAR szFilename[MAX_PATH] = {0};
  92. TCHAR szTempFolder[MAX_PATH] = {0};
  93. if (g_hLogFile!=INVALID_HANDLE_VALUE)
  94. {
  95. InterlockedIncrement(&g_iLogFileRefCount);
  96. return TRUE;
  97. }
  98. if (!lpctstrFilename)
  99. {
  100. return FALSE;
  101. }
  102. // first expand the filename
  103. if (ExpandEnvironmentStrings(lpctstrFilename,szFilename,MAX_PATH)==0)
  104. {
  105. return FALSE;
  106. }
  107. // is this is a file description or a complete path to file
  108. if (_tcschr(szFilename,_T('\\'))==NULL)
  109. {
  110. // this is just the file's name, need to add the temp folder to it.
  111. if (GetTempPath(MAX_PATH,szTempFolder)==0)
  112. {
  113. return FALSE;
  114. }
  115. _tcsncpy(g_szPathToFile,szTempFolder,MAX_PATH-1);
  116. _tcsncat(g_szPathToFile,szFilename,MAX_PATH-_tcslen(g_szPathToFile)-1);
  117. }
  118. else
  119. {
  120. // this is the full path to the log file, use it.
  121. _tcsncpy(g_szPathToFile,szFilename,MAX_PATH-1);
  122. }
  123. g_dwMaxSize = dwMaxSize;
  124. g_hLogFile = ::SafeCreateFile(
  125. g_szPathToFile,
  126. GENERIC_WRITE,
  127. FILE_SHARE_WRITE | FILE_SHARE_READ,
  128. NULL,
  129. OPEN_ALWAYS,
  130. FILE_ATTRIBUTE_NORMAL,
  131. NULL);
  132. if (g_hLogFile==INVALID_HANDLE_VALUE)
  133. {
  134. return FALSE;
  135. }
  136. DWORD dwFilePointer = ::SetFilePointer(g_hLogFile,0,NULL,FILE_END);
  137. if (dwFilePointer==INVALID_SET_FILE_POINTER)
  138. {
  139. ::CloseHandle(g_hLogFile);
  140. g_hLogFile = INVALID_HANDLE_VALUE;
  141. return FALSE;
  142. }
  143. InterlockedExchange(&g_iLogFileRefCount,1);
  144. return TRUE;
  145. }
  146. //*****************************************************************************
  147. //* Name: CloseLogFile
  148. //* Author: Mooly Beery (MoolyB), May, 2000
  149. //*****************************************************************************
  150. //* DESCRIPTION:
  151. //* Closes the log file which accepts the debug output
  152. //*
  153. //* PARAMETERS:
  154. //*
  155. //* RETURN VALUE:
  156. //*
  157. //* Comments:
  158. //* this function should be used together with OpenLogFile()
  159. //*****************************************************************************
  160. void debugCloseLogFile()
  161. {
  162. InterlockedDecrement(&g_iLogFileRefCount);
  163. if (g_iLogFileRefCount==0)
  164. {
  165. if (g_hLogFile!=INVALID_HANDLE_VALUE)
  166. {
  167. ::CloseHandle(g_hLogFile);
  168. g_hLogFile = INVALID_HANDLE_VALUE;
  169. }
  170. }
  171. }
  172. DWORD
  173. GetDebugLevel(
  174. VOID
  175. )
  176. {
  177. DWORD rc;
  178. DWORD err;
  179. DWORD size;
  180. DWORD type;
  181. HKEY hkey;
  182. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  183. REGKEY_FAX_CLIENT,
  184. 0,
  185. KEY_READ,
  186. &hkey);
  187. if (err != ERROR_SUCCESS)
  188. return 0;
  189. size = sizeof(DWORD);
  190. err = RegQueryValueEx(hkey,
  191. REGVAL_DBGLEVEL,
  192. 0,
  193. &type,
  194. (LPBYTE)&rc,
  195. &size);
  196. if (err != ERROR_SUCCESS || type != REG_DWORD)
  197. rc = 0;
  198. RegCloseKey(hkey);
  199. return rc;
  200. }
  201. DWORD
  202. GetDebugLevelEx(
  203. VOID
  204. )
  205. {
  206. DWORD RetVal = 0;
  207. DWORD err;
  208. DWORD size;
  209. DWORD type;
  210. HKEY hkey;
  211. // first let's set the defaults
  212. FaxDebugLevelEx = 0; // Default get no debug output
  213. FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
  214. FaxContextLevelEx = DEBUG_CONTEXT_ALL;
  215. err = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  216. REGKEY_FAX_CLIENT,
  217. 0,
  218. KEY_READ,
  219. &hkey);
  220. if (err != ERROR_SUCCESS)
  221. return RetVal;
  222. size = sizeof(DWORD);
  223. err = RegQueryValueEx(hkey,
  224. REGVAL_DBGLEVEL_EX,
  225. 0,
  226. &type,
  227. (LPBYTE)&RetVal,
  228. &size);
  229. if (err != ERROR_SUCCESS || type != REG_DWORD)
  230. {
  231. RetVal = 0;
  232. }
  233. size = sizeof(DWORD);
  234. err = RegQueryValueEx(hkey,
  235. REGVAL_DBGFORMAT_EX,
  236. 0,
  237. &type,
  238. (LPBYTE)&FaxFormatLevelEx,
  239. &size);
  240. if (err != ERROR_SUCCESS || type != REG_DWORD)
  241. {
  242. FaxFormatLevelEx = DBG_PRNT_ALL_TO_STD;
  243. }
  244. err = RegQueryValueEx(hkey,
  245. REGVAL_DBGCONTEXT_EX,
  246. 0,
  247. &type,
  248. (LPBYTE)&FaxContextLevelEx,
  249. &size);
  250. if (err != ERROR_SUCCESS || type != REG_DWORD)
  251. {
  252. FaxContextLevelEx = DEBUG_CONTEXT_ALL;
  253. }
  254. RegCloseKey(hkey);
  255. return RetVal;
  256. }
  257. void dprintfex
  258. (
  259. DEBUG_MESSAGE_CONTEXT nMessageContext,
  260. DEBUG_MESSAGE_TYPE nMessageType,
  261. LPCTSTR lpctstrDbgFunctionName,
  262. LPCTSTR lpctstrFile,
  263. DWORD dwLine,
  264. LPCTSTR lpctstrFormat,
  265. ...
  266. )
  267. {
  268. TCHAR buf[2048] = {0};
  269. DWORD len;
  270. va_list arg_ptr;
  271. TCHAR szExtFormat[2048] = {0};
  272. LPTSTR lptstrMsgPrefix;
  273. TCHAR szTimeBuff[10];
  274. TCHAR szDateBuff[10];
  275. DWORD dwInd = 0;
  276. TCHAR bufLocalFile[MAX_PATH] = {0};
  277. LPTSTR lptstrShortFile = NULL;
  278. LPTSTR lptstrProject = NULL;
  279. DWORD dwLastError = GetLastError();
  280. static BOOL bChecked = FALSE;
  281. if (!bChecked)
  282. {
  283. if (FaxDebugLevelEx==-1)
  284. FaxDebugLevelEx = GetDebugLevelEx();
  285. bChecked = TRUE;
  286. }
  287. if (FaxDebugLevelEx == 0)
  288. {
  289. goto exit;
  290. }
  291. if (!(nMessageType & FaxDebugLevelEx))
  292. {
  293. goto exit;
  294. }
  295. if (!(nMessageContext & FaxContextLevelEx))
  296. {
  297. goto exit;
  298. }
  299. switch (nMessageType)
  300. {
  301. case DEBUG_VER_MSG:
  302. lptstrMsgPrefix=TEXT(" ");
  303. break;
  304. case DEBUG_WRN_MSG:
  305. lptstrMsgPrefix=TEXT("WRN");
  306. break;
  307. case DEBUG_ERR_MSG:
  308. lptstrMsgPrefix=TEXT("ERR");
  309. break;
  310. case DEBUG_FAX_TAPI_MSG:
  311. lptstrMsgPrefix=TEXT("TAP");
  312. break;
  313. default:
  314. _ASSERT(FALSE);
  315. lptstrMsgPrefix=TEXT(" ");
  316. break;
  317. }
  318. // Date & Time stamps
  319. if( FaxFormatLevelEx & DBG_PRNT_TIME_STAMP )
  320. {
  321. dwInd += _stprintf(&szExtFormat[dwInd],
  322. TEXT("[%-8s %-8s]"),
  323. _tstrdate(szDateBuff),
  324. _tstrtime(szTimeBuff));
  325. }
  326. // Tick Count
  327. if( FaxFormatLevelEx & DBG_PRNT_TICK_COUNT )
  328. {
  329. dwInd += _stprintf(&szExtFormat[dwInd],
  330. TEXT("[%09d]"),
  331. GetTickCount());
  332. }
  333. // Thread ID
  334. if( FaxFormatLevelEx & DBG_PRNT_THREAD_ID )
  335. {
  336. dwInd += _stprintf(&szExtFormat[dwInd],
  337. TEXT("[0x%05x]"),
  338. GetCurrentThreadId());
  339. }
  340. // Message type
  341. if( FaxFormatLevelEx & DBG_PRNT_MSG_TYPE )
  342. {
  343. dwInd += _stprintf(&szExtFormat[dwInd],
  344. TEXT("[%s]"),
  345. lptstrMsgPrefix);
  346. }
  347. // filename & line number
  348. if( FaxFormatLevelEx & DBG_PRNT_FILE_LINE )
  349. {
  350. _tcsncpy(bufLocalFile,lpctstrFile,MAX_PATH-1);
  351. lptstrShortFile = _tcsrchr(bufLocalFile,_T('\\'));
  352. if (lptstrShortFile)
  353. {
  354. (*lptstrShortFile) = _T('\0');
  355. lptstrProject = _tcsrchr(bufLocalFile,_T('\\'));
  356. (*lptstrShortFile) = _T('\\');
  357. if (lptstrProject)
  358. lptstrProject = _tcsinc(lptstrProject);
  359. }
  360. dwInd += _stprintf( &szExtFormat[dwInd],
  361. TEXT("[%-20s][%-4ld]"),
  362. lptstrProject,
  363. dwLine);
  364. }
  365. // Module name
  366. if( FaxFormatLevelEx & DBG_PRNT_MOD_NAME )
  367. {
  368. dwInd += _stprintf(&szExtFormat[dwInd],
  369. TEXT("[%-20s]"),
  370. lpctstrDbgFunctionName);
  371. }
  372. // Now comes the actual message
  373. va_start(arg_ptr, lpctstrFormat);
  374. _vsntprintf(buf, ARR_SIZE(buf) - 1, lpctstrFormat, arg_ptr);
  375. len = _tcslen(buf);
  376. _tcsncpy (&szExtFormat[dwInd], buf, ARR_SIZE(szExtFormat) - dwInd - 1);
  377. dwInd += len;
  378. //
  379. // Limit index to szExtFormat size
  380. //
  381. if (dwInd > ARR_SIZE(szExtFormat)-3)
  382. {
  383. dwInd = ARR_SIZE(szExtFormat)-3;
  384. }
  385. _stprintf( &szExtFormat[dwInd],TEXT("\r\n"));
  386. if( FaxFormatLevelEx & DBG_PRNT_TO_STD )
  387. {
  388. OutputDebugString( szExtFormat);
  389. }
  390. if ( FaxFormatLevelEx & DBG_PRNT_TO_FILE )
  391. {
  392. if (g_hLogFile!=INVALID_HANDLE_VALUE)
  393. {
  394. debugOutputFileString(szExtFormat);
  395. }
  396. }
  397. exit:
  398. SetLastError (dwLastError); // dprintfex will not change LastError
  399. return;
  400. }
  401. BOOL debugOutputFileString(LPCTSTR szMsg)
  402. {
  403. BOOL bRes = FALSE;
  404. //
  405. // Attempt to add the line to a log file
  406. //
  407. #ifdef UNICODE
  408. char sFileMsg[2000];
  409. int Count = WideCharToMultiByte(
  410. CP_ACP,
  411. 0,
  412. szMsg,
  413. -1,
  414. sFileMsg,
  415. sizeof(sFileMsg)/sizeof(sFileMsg[0]),
  416. NULL,
  417. NULL
  418. );
  419. if (Count==0)
  420. {
  421. return bRes;
  422. }
  423. #else
  424. const char* sFileMsg = szMsg;
  425. #endif
  426. DWORD dwNumBytesWritten = 0;
  427. DWORD dwNumOfBytesToWrite = strlen(sFileMsg);
  428. if (!::WriteFile(g_hLogFile,sFileMsg,dwNumOfBytesToWrite,&dwNumBytesWritten,NULL))
  429. {
  430. return bRes;
  431. }
  432. if (dwNumBytesWritten!=dwNumOfBytesToWrite)
  433. {
  434. return bRes;
  435. }
  436. // ::FlushFileBuffers(g_hLogFile);
  437. if (g_dwMaxSize != -1)
  438. { // There's a file size limitation, let's see if we exceeded it
  439. debugCheckFileSize();
  440. // Ignore return value - there's nothing we can do about it anyway
  441. }
  442. bRes = TRUE;
  443. return bRes;
  444. }
  445. //*****************************************************************************
  446. //* Name: debugCheckFileSize
  447. //* Author: Jonathan Barner (t-jonb), August 2001
  448. //*****************************************************************************
  449. //* DESCRIPTION:
  450. //* Checks whether the log file exceeded the maximum size specified
  451. //* in debugOpenLogFile. If so, renames the file (overwriting the last
  452. //* renamed file, if exists), and creates a new log file.
  453. //*
  454. //* PARAMETERS: none
  455. //* RETURN VALUE: TRUE - success, FALSE - failure
  456. //*
  457. //*****************************************************************************
  458. BOOL debugCheckFileSize()
  459. {
  460. DWORD dwSizeHigh=0, dwSizeLow=0;
  461. dwSizeLow = GetFileSize(g_hLogFile, &dwSizeHigh);
  462. if (dwSizeLow==INVALID_FILE_SIZE && (GetLastError()!=NO_ERROR))
  463. {
  464. return FALSE;
  465. }
  466. if (dwSizeHigh>0 || dwSizeLow>g_dwMaxSize)
  467. {
  468. TCHAR szPathToFileOld[MAX_PATH] = {0};
  469. PTCHAR lpszDot = NULL;
  470. _tcsncpy(szPathToFileOld, g_szPathToFile, MAX_PATH - 1);
  471. // Change File.txt into FileOld.txt
  472. lpszDot = _tcsrchr(szPathToFileOld, _T('.'));
  473. if (lpszDot != NULL)
  474. {
  475. *lpszDot = _T('\0');
  476. }
  477. if (_tcslen(szPathToFileOld)+7 > MAX_PATH) // strlen("Old.txt") = 7
  478. {
  479. return FALSE;
  480. }
  481. _tcscat(szPathToFileOld, _T("Old.txt"));
  482. if (! ::CloseHandle(g_hLogFile))
  483. {
  484. return FALSE;
  485. }
  486. g_hLogFile = INVALID_HANDLE_VALUE;
  487. ::MoveFileEx(g_szPathToFile, szPathToFileOld, MOVEFILE_REPLACE_EXISTING);
  488. // MoveFileEx could fail if the old file is open. In this case, do nothing
  489. g_hLogFile = ::SafeCreateFile(
  490. g_szPathToFile,
  491. GENERIC_WRITE,
  492. FILE_SHARE_WRITE | FILE_SHARE_READ,
  493. NULL,
  494. CREATE_ALWAYS, // overwrite old file
  495. FILE_ATTRIBUTE_NORMAL,
  496. NULL);
  497. if (g_hLogFile==INVALID_HANDLE_VALUE)
  498. {
  499. // We closed the file and never opened it again - so we
  500. // need to decrement reference count
  501. InterlockedDecrement(&g_iLogFileRefCount);
  502. return FALSE;
  503. }
  504. }
  505. return TRUE;
  506. }
  507. void
  508. fax_dprintf(
  509. LPCTSTR Format,
  510. ...
  511. )
  512. /*++
  513. Routine Description:
  514. Prints a debug string
  515. Arguments:
  516. format - printf() format string
  517. ... - Variable data
  518. Return Value:
  519. None.
  520. --*/
  521. {
  522. TCHAR buf[1024] = {0};
  523. DWORD len;
  524. va_list arg_ptr;
  525. static BOOL bChecked = FALSE;
  526. if (!bChecked) {
  527. FaxDebugLevel = (INT) GetDebugLevel();
  528. bChecked = TRUE;
  529. }
  530. if (!g_fIsSetupLogFileMode)
  531. {
  532. if (FaxDebugLevel <= 0)
  533. {
  534. return;
  535. }
  536. }
  537. va_start(arg_ptr, Format);
  538. _vsntprintf(buf, ARR_SIZE(buf) - 1, Format, arg_ptr);
  539. len = min(_tcslen( buf ), ARR_SIZE(buf)-3);
  540. if (buf[len-1] != TEXT('\n'))
  541. {
  542. buf[len] = TEXT('\r');
  543. buf[len+1] = TEXT('\n');
  544. buf[len+2] = 0;
  545. }
  546. OutputDebugString( buf );
  547. if (g_fIsSetupLogFileMode)
  548. {
  549. DebugLogPrint(buf);
  550. }
  551. } // fax_dprintf
  552. VOID
  553. AssertError(
  554. LPCTSTR Expression,
  555. LPCTSTR File,
  556. ULONG LineNumber
  557. )
  558. /*++
  559. Routine Description:
  560. Thie function is use together with the Assert MACRO.
  561. It checks to see if an expression is FALSE. if the
  562. expression is FALSE, then you end up here.
  563. Arguments:
  564. Expression - The text of the 'C' expression
  565. File - The file that caused the assertion
  566. LineNumber - The line number in the file.
  567. Return Value:
  568. None.
  569. --*/
  570. {
  571. fax_dprintf(
  572. TEXT("Assertion error: [%s] %s @ %d\n"),
  573. Expression,
  574. File,
  575. LineNumber
  576. );
  577. #ifdef DEBUG
  578. __try {
  579. DebugBreak();
  580. } __except (UnhandledExceptionFilter(GetExceptionInformation())) {
  581. // Nothing to do in here.
  582. }
  583. #endif // DEBUG
  584. }
  585. void debugSetProperties(DWORD dwLevel,DWORD dwFormat,DWORD dwContext)
  586. {
  587. FaxDebugLevelEx = dwLevel;
  588. FaxFormatLevelEx = dwFormat;
  589. FaxContextLevelEx = dwContext;
  590. }