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.

760 lines
20 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. Author:
  6. Revision History:
  7. --*/
  8. #include "precomp.h"
  9. #pragma hdrstop
  10. HANDLE hDebugLog;
  11. Winnt32DebugLevel DebugLevel;
  12. BOOL
  13. StartDebugLog(
  14. IN LPCTSTR DebugFileLog,
  15. IN Winnt32DebugLevel Level
  16. )
  17. /*++
  18. Routine Description:
  19. Create a file to be used for logging debugging information.
  20. Note: There can be only one debug log. Second and subsequent
  21. calls to this routine return TRUE if a debug log is already in use.
  22. Arguments:
  23. DebugFileLog - supplies filename of file to be used for debugging log.
  24. Level - supplies logging level desired.
  25. Return Value:
  26. Boolean value indicating whether the file log was successfully started.
  27. --*/
  28. {
  29. DWORD Written;
  30. TCHAR Text[512];
  31. if(hDebugLog) {
  32. return(TRUE);
  33. }
  34. if(Level > Winnt32LogMax) {
  35. Level = Winnt32LogMax;
  36. }
  37. DebugLevel = Level;
  38. hDebugLog = CreateFile(
  39. DebugFileLog,
  40. GENERIC_WRITE,
  41. FILE_SHARE_READ,
  42. NULL,
  43. Winnt32Restarted () ? OPEN_ALWAYS : CREATE_ALWAYS,
  44. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
  45. NULL
  46. );
  47. if(hDebugLog == INVALID_HANDLE_VALUE) {
  48. hDebugLog = NULL;
  49. return(FALSE);
  50. }
  51. if(GetLastError() == ERROR_ALREADY_EXISTS) {
  52. //
  53. // Appending to existing file
  54. //
  55. SetFilePointer(hDebugLog,0,NULL,FILE_END);
  56. if (LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR))) {
  57. DebugLog(
  58. Winnt32LogMax,
  59. Text,
  60. 0
  61. );
  62. }
  63. }
  64. if( CheckUpgradeOnly ) {
  65. if (LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR))) {
  66. DebugLog( Winnt32LogInformation,
  67. Text,
  68. 0 );
  69. }
  70. if (LoadString( hInst, IDS_APPTITLE_CHECKUPGRADE, Text, sizeof(Text)/sizeof(TCHAR))) {
  71. DebugLog( Winnt32LogInformation,
  72. Text,
  73. 0 );
  74. }
  75. if (LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR))) {
  76. DebugLog( Winnt32LogInformation,
  77. Text,
  78. 0 );
  79. }
  80. }
  81. return(TRUE);
  82. }
  83. VOID
  84. CloseDebugLog(
  85. VOID
  86. )
  87. /*++
  88. Routine Description:
  89. Close the logging file.
  90. Arguments:
  91. Return Value:
  92. --*/
  93. {
  94. if( hDebugLog ) {
  95. CloseHandle( hDebugLog );
  96. }
  97. }
  98. BOOL
  99. DebugLog(
  100. IN Winnt32DebugLevel Level,
  101. IN LPCTSTR Text, OPTIONAL
  102. IN UINT MessageId,
  103. ...
  104. )
  105. /*++
  106. Routine Description:
  107. Write some text into the debug log file, if there is one.
  108. Arguments:
  109. Level - supplies the logging level for this log event. Only items
  110. with a level greater than or equal to the one specified by the user
  111. are actually logged.
  112. Text - if specified, supplies the format string for the text message
  113. to go into the log file. If not specified, MessageId must be.
  114. MessageId - if Text is not specified, supplies the message id for the
  115. item in the message table that has the text of the item to be
  116. written into the log file.
  117. Additional arguments supply insertion values for the message.
  118. Return Value:
  119. --*/
  120. {
  121. va_list arglist;
  122. BOOL b;
  123. va_start(arglist,MessageId);
  124. b = DebugLog2 (Level, Text, MessageId, arglist);
  125. va_end(arglist);
  126. return b;
  127. }
  128. BOOL
  129. DebugLog2(
  130. IN Winnt32DebugLevel Level,
  131. IN LPCTSTR Text, OPTIONAL
  132. IN UINT MessageId,
  133. IN va_list ArgList
  134. )
  135. /*++
  136. Routine Description:
  137. Write some text into the debug log file, if there is one.
  138. Arguments:
  139. Level - supplies the logging level for this log event. Only items
  140. with a level greater than or equal to the one specified by the user
  141. are actually logged.
  142. Text - if specified, supplies the format string for the text message
  143. to go into the log file. If not specified, MessageId must be.
  144. MessageId - if Text is not specified, supplies the message id for the
  145. item in the message table that has the text of the item to be
  146. written into the log file.
  147. Additional arguments supply insertion values for the message.
  148. Return Value:
  149. --*/
  150. {
  151. CHAR AnsiMessage[5000];
  152. DWORD Size;
  153. DWORD Written;
  154. LPCTSTR Message;
  155. BOOL b;
  156. DWORD rc;
  157. if(!hDebugLog) {
  158. return(FALSE);
  159. }
  160. if((Level & ~WINNT32_HARDWARE_LOG) > DebugLevel) {
  161. return(TRUE);
  162. }
  163. rc = GetLastError ();
  164. if(Text) {
  165. Size = FormatMessage(
  166. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_STRING,
  167. Text,
  168. 0,0,
  169. (LPTSTR)&Message,
  170. 0,
  171. &ArgList
  172. );
  173. } else {
  174. Size = FormatMessage(
  175. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_HMODULE,
  176. hInst,
  177. MessageId,
  178. 0,
  179. (LPTSTR)&Message,
  180. 0,
  181. &ArgList
  182. );
  183. }
  184. if(Size) {
  185. #ifdef UNICODE
  186. if (WideCharToMultiByte(
  187. CP_ACP,
  188. 0,
  189. Message,
  190. -1,
  191. AnsiMessage,
  192. ARRAYSIZE(AnsiMessage) - 1,
  193. NULL,
  194. NULL
  195. )) {
  196. AnsiMessage[ARRAYSIZE(AnsiMessage) - 1] = 0;
  197. } else {
  198. AnsiMessage[0] = 0;
  199. }
  200. #else
  201. StringCchCopyA(AnsiMessage,sizeof(AnsiMessage),Message);
  202. #endif
  203. b = WriteFile(hDebugLog,AnsiMessage,lstrlenA(AnsiMessage),&Written,NULL);
  204. if ((Level & WINNT32_HARDWARE_LOG) == 0) {
  205. if (Text && b) {
  206. if (Level <= Winnt32LogError && rc) {
  207. CHAR buffer[50];
  208. b = WriteFile(
  209. hDebugLog,
  210. buffer,
  211. wsprintfA (buffer, " (rc=%u[0x%X])", rc, rc),
  212. &Written,
  213. NULL
  214. );
  215. }
  216. b = WriteFile(hDebugLog,"\r\n", 2, &Written,NULL);
  217. }
  218. }
  219. LocalFree((HLOCAL)Message);
  220. } else {
  221. b = FALSE;
  222. }
  223. SetLastError (rc);
  224. return(b);
  225. }
  226. #if ASSERTS_ON
  227. VOID
  228. AssertFail(
  229. IN PSTR FileName,
  230. IN UINT LineNumber,
  231. IN PSTR Condition
  232. )
  233. {
  234. int i;
  235. CHAR Name[MAX_PATH];
  236. PCHAR p;
  237. CHAR Msg[4096];
  238. //
  239. // Use dll name as caption
  240. //
  241. GetModuleFileNameA(hInst,Name,MAX_PATH);
  242. Name[ARRAYSIZE(Name) - 1] = 0;
  243. if(p = strrchr(Name,'\\')) {
  244. p++;
  245. } else {
  246. p = Name;
  247. }
  248. StringCchPrintfA(
  249. Msg,
  250. ARRAYSIZE(Msg),
  251. "Assertion failure at line %u in file %s: %s\n\nCall DebugBreak()?",
  252. LineNumber,
  253. FileName,
  254. Condition
  255. );
  256. i = MessageBoxA(
  257. NULL,
  258. Msg,
  259. p,
  260. MB_YESNO | MB_TASKMODAL | MB_ICONSTOP | MB_SETFOREGROUND
  261. );
  262. if(i == IDYES) {
  263. DebugBreak();
  264. }
  265. }
  266. #endif
  267. VOID
  268. MyEnumerateDirectory(
  269. LPTSTR DirectoryName,
  270. DWORD Index,
  271. BOOL Recordable
  272. )
  273. /*++
  274. Routine Description:
  275. This routine will enumerate all files in a directory structure.
  276. It then prints those filenames into the debug logfile.
  277. Arguments:
  278. DirectoryName Name of the directory we're currently examining.
  279. Index Indicates our recurse-level. Used for formatting
  280. the output.
  281. Recordable This determines if we will be logging this item
  282. or not. Some items we don't care about.
  283. Return Value:
  284. --*/
  285. {
  286. TCHAR TmpDirectoryString[MAX_PATH];
  287. TCHAR TmpName[MAX_PATH];
  288. HANDLE FindHandle;
  289. WIN32_FIND_DATA FoundData;
  290. DWORD i;
  291. //
  292. // Fix our path so we know where we're looking...
  293. //
  294. if( DirectoryName[0] ) {
  295. if (FAILED(StringCchCopy(TmpDirectoryString, ARRAYSIZE(TmpDirectoryString), DirectoryName )))
  296. {
  297. return;
  298. }
  299. if( ISNT() )
  300. {
  301. if (!ConcatenatePaths( TmpDirectoryString, TEXT("*"), MAX_PATH ))
  302. return;
  303. }
  304. else
  305. {
  306. if (!ConcatenatePaths( TmpDirectoryString, TEXT("*.*"), MAX_PATH ))
  307. return;
  308. }
  309. } else {
  310. if( ISNT() ) {
  311. lstrcpy( TmpDirectoryString, TEXT("*") );
  312. } else {
  313. lstrcpy( TmpDirectoryString, TEXT("*.*") );
  314. }
  315. }
  316. //
  317. // Get the first item.
  318. //
  319. FindHandle = FindFirstFile( TmpDirectoryString, &FoundData );
  320. if( !FindHandle || (FindHandle == INVALID_HANDLE_VALUE) ) {
  321. //
  322. // The directory is empty.
  323. //
  324. return;
  325. }
  326. //
  327. // Now look at every item in the directory.
  328. //
  329. do {
  330. TmpName[0] = 0;
  331. for( i = 0; i < Index; i++ ) {
  332. StringCchCat( TmpName, ARRAYSIZE(TmpName), TEXT(" ") );
  333. }
  334. if( FoundData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ) {
  335. //
  336. // Directory. Ignore . and .. entries.
  337. //
  338. if(lstrcmp(FoundData.cFileName,TEXT("."))
  339. && lstrcmp(FoundData.cFileName,TEXT(".."))) {
  340. //
  341. // Print the entry.
  342. //
  343. StringCchCat( TmpName, ARRAYSIZE(TmpName), TEXT("\\") );
  344. StringCchCat( TmpName, ARRAYSIZE(TmpName), FoundData.cFileName );
  345. StringCchCat( TmpName, ARRAYSIZE(TmpName), TEXT("\n") );
  346. if( ( !lstrcmpi( FoundData.cFileName, TEXT("Start Menu"))) ||
  347. ( Recordable ) ) {
  348. Recordable = TRUE;
  349. if( !_tcsrchr( TmpName, TEXT('%') ) ) {
  350. DebugLog( Winnt32LogInformation,
  351. TmpName,
  352. 0 );
  353. }
  354. }
  355. //
  356. // Call ourselves on this directory. We want to make sure that we cannot
  357. // infinitely recurse by calling MyEnumerateDirectory on the same directory
  358. // which occupies the entire TmpName buffer.
  359. //
  360. if (FAILED(StringCchCopy( TmpName, ARRAYSIZE(TmpName), DirectoryName )))
  361. {
  362. break;
  363. }
  364. if (!ConcatenatePaths( TmpName, FoundData.cFileName, MAX_PATH ))
  365. {
  366. break;
  367. }
  368. MyEnumerateDirectory( TmpName, Index+1, Recordable );
  369. //
  370. // If we just recursed into a Start Menu directory,
  371. // we need to turn off recordability.
  372. //
  373. if( !lstrcmpi( FoundData.cFileName, TEXT("Start Menu"))) {
  374. Recordable = FALSE;
  375. }
  376. }
  377. } else {
  378. //
  379. // File. Just print it.
  380. //
  381. if( Recordable ) {
  382. StringCchCat( TmpName, ARRAYSIZE(TmpName), FoundData.cFileName );
  383. StringCchCat( TmpName, ARRAYSIZE(TmpName), TEXT("\n") );
  384. if( !_tcsrchr( TmpName, TEXT('%') ) ) {
  385. DebugLog( Winnt32LogInformation,
  386. TmpName,
  387. 0 );
  388. }
  389. }
  390. }
  391. } while( FindNextFile( FindHandle, &FoundData ) );
  392. CloseHandle (FindHandle);
  393. }
  394. VOID
  395. GatherOtherLogFiles(
  396. VOID
  397. )
  398. /*++
  399. Routine Description:
  400. This routine will launch winmsd in a batch-mode, then
  401. copy it's output onto the backend of our debug log.
  402. Arguments:
  403. Return Value:
  404. --*/
  405. {
  406. STARTUPINFO StartupInfo;
  407. PROCESS_INFORMATION ProcessInfo;
  408. DWORD dw,
  409. ExitCode;
  410. BOOL Done;
  411. TCHAR FileName[MAX_PATH];
  412. TCHAR ComputerName[MAX_PATH];
  413. MSG msg;
  414. TCHAR Text[512];
  415. //
  416. // If we're on Win9X, we will also want %windir%\upgrade.txt.
  417. //
  418. if( !ISNT() ) {
  419. //
  420. // %windir%\upgrade.txt
  421. //
  422. FileName[0] = TEXT('\0');
  423. MyGetWindowsDirectory( FileName, MAX_PATH );
  424. if (ConcatenatePaths( FileName, TEXT("upgrade.txt"), MAX_PATH ))
  425. {
  426. if( !ConcatenateFile( hDebugLog, FileName ) )
  427. {
  428. DebugLog( Winnt32LogInformation,
  429. TEXT("\r\nFailed to append upgrade.txt!\r\n"),
  430. 0 );
  431. }
  432. }
  433. //
  434. // %windir%\beta-upg.log
  435. //
  436. FileName[0] = TEXT('\0');
  437. MyGetWindowsDirectory( FileName, MAX_PATH );
  438. if (ConcatenatePaths( FileName, TEXT("beta-upg.log"), MAX_PATH ))
  439. {
  440. if( !ConcatenateFile( hDebugLog, FileName ) ) {
  441. DebugLog( Winnt32LogInformation,
  442. TEXT("\r\nFailed to append beta-upg.log!\r\n"),
  443. 0 );
  444. }
  445. }
  446. //
  447. // %windir%\config.dmp
  448. //
  449. FileName[0] = TEXT('\0');
  450. MyGetWindowsDirectory( FileName, MAX_PATH );
  451. if (ConcatenatePaths( FileName, TEXT("config.dmp"), MAX_PATH ))
  452. {
  453. if( !ConcatenateFile( hDebugLog, FileName ) ) {
  454. DebugLog( Winnt32LogInformation,
  455. TEXT("\r\nFailed to append config.dmp!\r\n"),
  456. 0 );
  457. }
  458. }
  459. }
  460. #if 0
  461. //
  462. // remove winmsd call for now.
  463. //
  464. if( ISNT() && (BuildNumber > NT351) ) {
  465. //
  466. // If we're on NT, run winmsd and capture his
  467. // output.
  468. //
  469. ZeroMemory(&StartupInfo,sizeof(StartupInfo));
  470. StartupInfo.cb = sizeof(StartupInfo);
  471. lstrcpy( FileName, TEXT( "winmsd.exe /a" ) );
  472. if( CreateProcess( NULL,
  473. FileName,
  474. NULL,
  475. NULL,
  476. FALSE,
  477. 0,
  478. NULL,
  479. NULL,
  480. &StartupInfo,
  481. &ProcessInfo ) ) {
  482. //
  483. // Wait for him.
  484. //
  485. //
  486. // Process any messages that may already be in the queue.
  487. //
  488. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  489. DispatchMessage(&msg);
  490. }
  491. //
  492. // Wait for process to terminate or more messages in the queue.
  493. //
  494. Done = FALSE;
  495. do {
  496. switch(MsgWaitForMultipleObjects(1,&ProcessInfo.hProcess,FALSE,INFINITE,QS_ALLINPUT)) {
  497. case WAIT_OBJECT_0:
  498. //
  499. // Process has terminated.
  500. //
  501. dw = GetExitCodeProcess(ProcessInfo.hProcess,&ExitCode) ? NO_ERROR : GetLastError();
  502. Done = TRUE;
  503. break;
  504. case WAIT_OBJECT_0+1:
  505. //
  506. // Messages in the queue.
  507. //
  508. while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
  509. DispatchMessage(&msg);
  510. }
  511. break;
  512. default:
  513. //
  514. // Error.
  515. //
  516. dw = GetLastError();
  517. Done = TRUE;
  518. break;
  519. }
  520. } while(!Done);
  521. }
  522. CloseHandle( ProcessInfo.hThread );
  523. CloseHandle( ProcessInfo.hProcess );
  524. if( dw == NO_ERROR ) {
  525. //
  526. // Concatenate him onto the end of our logfile. His
  527. // logfile will be <computer_name>.txt and will be
  528. // located in our directory. Map the file...
  529. //
  530. DebugLog( Winnt32LogInformation,
  531. TEXT("\r\n\r\n********************************************************************\r\n\r\n"),
  532. 0 );
  533. DebugLog( Winnt32LogInformation,
  534. TEXT("\t\tWinMSD Log\n"),
  535. 0 );
  536. DebugLog( Winnt32LogInformation,
  537. TEXT("\r\n********************************************************************\r\n\r\n"),
  538. 0 );
  539. GetCurrentDirectory( MAX_PATH, FileName );
  540. dw = MAX_PATH;
  541. GetComputerName( ComputerName, &dw );
  542. ConcatenatePaths( FileName, ComputerName, MAX_PATH );
  543. lstrcat( FileName, TEXT(".txt") );
  544. ConcatenateFile( hDebugLog, FileName );
  545. } else {
  546. //
  547. // Should we log our failure to be sneaky??
  548. //
  549. }
  550. }
  551. #endif
  552. //
  553. // Go enumerate the Start Menu
  554. // for all users... Don't do this for NT 3.51.
  555. //
  556. if( !(ISNT() && (BuildNumber <= NT351)) ){
  557. if (LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR)))
  558. {
  559. DebugLog( Winnt32LogInformation,
  560. Text,
  561. 0 );
  562. }
  563. if (LoadString( hInst, IDS_COMPAT_STRT_MENU, Text, sizeof(Text)/sizeof(TCHAR)))
  564. {
  565. DebugLog( Winnt32LogInformation,
  566. Text,
  567. 0 );
  568. }
  569. if (LoadString( hInst, IDS_COMPAT_DIVIDER, Text, sizeof(Text)/sizeof(TCHAR)))
  570. {
  571. DebugLog( Winnt32LogInformation,
  572. Text,
  573. 0 );
  574. }
  575. if( !ISNT() ) {
  576. //
  577. // On Win9X, we can find Start Menu items in
  578. // two places!
  579. //
  580. MyGetWindowsDirectory( FileName, MAX_PATH );
  581. if (ConcatenatePaths( FileName, TEXT("Start Menu"), MAX_PATH ))
  582. {
  583. MyEnumerateDirectory( FileName, 0, TRUE );
  584. }
  585. } else {
  586. if( BuildNumber >= 1890 ) {
  587. //
  588. // Starting on build 1890, we moved/renamed the Profiles
  589. // directory. Of course, that only happens on clean installs
  590. // of these new builds. We need to see if there's anything
  591. // in the new directory structure.
  592. //
  593. MyGetWindowsDirectory( FileName, MAX_PATH );
  594. FileName[3] = 0;
  595. if (ConcatenatePaths( FileName, TEXT("Documents and Settings"), MAX_PATH ))
  596. {
  597. MyEnumerateDirectory( FileName, 0, FALSE );
  598. }
  599. }
  600. }
  601. MyGetWindowsDirectory( FileName, MAX_PATH );
  602. if (ConcatenatePaths( FileName, TEXT("Profiles"), MAX_PATH))
  603. {
  604. MyEnumerateDirectory( FileName, 0, FALSE );
  605. }
  606. }
  607. }