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.

527 lines
19 KiB

  1. /*---------------------------------------------------------------------------
  2. File: ScanLog.cpp
  3. Comments: Routines to scan the dispatch log for the DCT agents
  4. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  5. Proprietary and confidential to Mission Critical Software, Inc.
  6. REVISION LOG ENTRY
  7. Revision By: Christy Boles
  8. Revised on 03/15/99 13:29:18
  9. ---------------------------------------------------------------------------
  10. */
  11. #include "StdAfx.h"
  12. #include "Common.hpp"
  13. #include "UString.hpp"
  14. #include "TNode.hpp"
  15. #include "ServList.hpp"
  16. #include "Globals.h"
  17. #include "Monitor.h"
  18. #include "FParse.hpp"
  19. #include "afxdao.h"
  20. #include "errDct.hpp"
  21. #include "scanlog.h"
  22. #include <Winnls.h>
  23. #define AR_Status_Created (0x00000001)
  24. #define AR_Status_Replaced (0x00000002)
  25. #define AR_Status_AlreadyExisted (0x00000004)
  26. #define AR_Status_RightsUpdated (0x00000008)
  27. #define AR_Status_DomainChanged (0x00000010)
  28. #define AR_Status_Rebooted (0x00000020)
  29. #define AR_Status_Warning (0x40000000)
  30. #define AR_Status_Error (0x80000000)
  31. #define BYTE_ORDER_MARK (0xFEFF)
  32. extern DWORD __stdcall MonitorRunningAgent(void *);
  33. void ParseInputFile(const WCHAR * filename);
  34. DWORD __stdcall LogReaderFn(void * arg)
  35. {
  36. WCHAR logfile[MAX_PATH];
  37. BOOL bDone;
  38. long nSeconds;
  39. CoInitialize(NULL);
  40. gData.GetLogPath(logfile);
  41. gData.GetDone(&bDone);
  42. gData.GetWaitInterval(&nSeconds);
  43. while ( ! bDone )
  44. {
  45. ParseInputFile(logfile);
  46. Sleep(nSeconds * 1000);
  47. gData.GetDone(&bDone);
  48. if (bDone)
  49. {
  50. // before we finish up this thread, set the LogDone to TRUE
  51. gData.SetLogDone(TRUE);
  52. break;
  53. }
  54. // if the dispatcher.csv has been processed, we should terminate this thread
  55. gData.GetLogDone(&bDone);
  56. gData.GetWaitInterval(&nSeconds);
  57. }
  58. CoUninitialize();
  59. return 0;
  60. }
  61. bool ConvertToLocalUserDefault(WCHAR* originalTimestamp, WCHAR* convertedTimestamp, size_t size)
  62. {
  63. SYSTEMTIME st;
  64. bool bConverted = false;
  65. int cFields = _stscanf(
  66. originalTimestamp,
  67. _T("%hu-%hu-%hu %hu:%hu:%hu"),
  68. &st.wYear,
  69. &st.wMonth,
  70. &st.wDay,
  71. &st.wHour,
  72. &st.wMinute,
  73. &st.wSecond
  74. );
  75. if (cFields == 6)
  76. {
  77. // format date and time using LOCALE_USER_DEFAULT
  78. WCHAR formatedDate[100];
  79. WCHAR formatedTime[100];
  80. st.wMilliseconds = 0;
  81. int formatedDateLen =
  82. GetDateFormatW(LOCALE_USER_DEFAULT, NULL, &st, NULL, formatedDate, sizeof(formatedDate)/sizeof(formatedDate[0]));
  83. int formatedTimeLen =
  84. GetTimeFormatW(LOCALE_USER_DEFAULT, NULL, &st, NULL, formatedTime, sizeof(formatedTime)/sizeof(formatedTime[0]));
  85. if (formatedDateLen != 0 && formatedTimeLen != 0 && formatedDateLen + formatedTimeLen + 1 < (int) size)
  86. {
  87. swprintf(convertedTimestamp, L"%s %s", formatedDate, formatedTime);
  88. bConverted = true;
  89. }
  90. }
  91. return bConverted;
  92. }
  93. BOOL TErrorLogParser::ScanFileEntry(
  94. WCHAR * string, // in - line from TError log file
  95. WCHAR * timestamp, // out- timestamp from this line
  96. int * pSeverity, // out- severity level of this message
  97. int * pSourceLine, // out- the source line for this message
  98. WCHAR * msgtext // out- the textual part of the message
  99. )
  100. {
  101. BOOL bScan = FALSE;
  102. // skip byte order mark if present
  103. if (string[0] == BYTE_ORDER_MARK)
  104. {
  105. ++string;
  106. }
  107. // initialize return values
  108. *timestamp = L'\0';
  109. *pSeverity = 0;
  110. *pSourceLine = 0;
  111. *msgtext = L'\0';
  112. // scan fields
  113. //2001-09-11 20:27:32 ERR2:0080 Unable...
  114. SYSTEMTIME st;
  115. _TCHAR szError[4];
  116. int cFields = _stscanf(
  117. string,
  118. _T("%hu-%hu-%hu %hu:%hu:%hu %3[^0-9]%d:%d %[^\r\n]"),
  119. &st.wYear,
  120. &st.wMonth,
  121. &st.wDay,
  122. &st.wHour,
  123. &st.wMinute,
  124. &st.wSecond,
  125. szError,
  126. pSeverity,
  127. pSourceLine,
  128. msgtext
  129. );
  130. // if warning or error message
  131. // else re-scan message
  132. if ((cFields >= 9) && ((_tcsicmp(szError, _T("WRN")) == 0) || (_tcsicmp(szError, _T("ERR")) == 0)))
  133. {
  134. bScan = TRUE;
  135. }
  136. else
  137. {
  138. *pSeverity = 0;
  139. *pSourceLine = 0;
  140. cFields = _stscanf(
  141. string,
  142. _T("%hu-%hu-%hu %hu:%hu:%hu %[^\r\n]"),
  143. &st.wYear,
  144. &st.wMonth,
  145. &st.wDay,
  146. &st.wHour,
  147. &st.wMinute,
  148. &st.wSecond,
  149. msgtext
  150. );
  151. if (cFields >= 6)
  152. {
  153. bScan = TRUE;
  154. }
  155. }
  156. if (bScan)
  157. {
  158. _stprintf(
  159. timestamp,
  160. _T("%hu-%02hu-%02hu %02hu:%02hu:%02hu"),
  161. st.wYear,
  162. st.wMonth,
  163. st.wDay,
  164. st.wHour,
  165. st.wMinute,
  166. st.wSecond
  167. );
  168. }
  169. return bScan;
  170. }
  171. BOOL GetServerFromMessage(WCHAR const * msg,WCHAR * server)
  172. {
  173. BOOL bSuccess = FALSE;
  174. int ndx = 0;
  175. for ( ndx = 0 ; msg[ndx] ; ndx++ )
  176. {
  177. if ( msg[ndx] == L'\\' && msg[ndx+1] == L'\\' )
  178. {
  179. bSuccess = TRUE;
  180. break;
  181. }
  182. }
  183. if ( bSuccess )
  184. {
  185. int i = 0;
  186. ndx+=2; // strip of the backslashes
  187. for ( i=0; msg[ndx] && msg[ndx] != L'\\' && msg[ndx]!= L' ' && msg[ndx] != L',' && msg[ndx] != L'\t' && msg[ndx] != L'\n' ; i++,ndx++)
  188. {
  189. server[i] = msg[ndx];
  190. }
  191. server[i] = 0;
  192. }
  193. else
  194. {
  195. server[0] = 0;
  196. }
  197. return bSuccess;
  198. }
  199. void ParseInputFile(WCHAR const * gLogFile)
  200. {
  201. FILE * pFile = 0;
  202. WCHAR server[MAX_PATH];
  203. int nRead = 0;
  204. int count = 0;
  205. HWND lWnd = NULL;
  206. long totalRead;
  207. BOOL bNeedToCheckResults = FALSE;
  208. TErrorLogParser parser;
  209. TErrorDct edct;
  210. BOOL bTotalReadGlobal; // indicates whether we have read the total number of agents
  211. BOOL bTotalReadLocal = FALSE; // indicates whether we will encounter total read in the file this time
  212. parser.Open(gLogFile);
  213. gData.GetLinesRead(&totalRead);
  214. gData.GetTotalRead(&bTotalReadGlobal);
  215. if ( parser.IsOpen() )
  216. {
  217. // scan the file
  218. while ( ! parser.IsEof() )
  219. {
  220. if ( parser.ScanEntry() )
  221. {
  222. nRead++;
  223. if ( nRead < totalRead )
  224. continue;
  225. // the first three lines each have their own specific format
  226. if ( nRead == 1 )
  227. {
  228. // first comes the name of the human-readable log file
  229. gData.SetReadableLogFile(parser.GetMessage());
  230. }
  231. else if ( nRead == 2 )
  232. {
  233. // next, the name result directory - this is needed to look for the result files
  234. WCHAR const * dirName = parser.GetMessage();
  235. gData.SetResultDir(dirName);
  236. }
  237. else if ( nRead == 3 )
  238. {
  239. // now the count of computers being dispatched to
  240. count = _wtoi(parser.GetMessage());
  241. ComputerStats cStat;
  242. gData.GetComputerStats(&cStat);
  243. cStat.total = count;
  244. gData.SetComputerStats(&cStat);
  245. bTotalReadLocal = TRUE;
  246. continue;
  247. }
  248. else // all other message have the following format: COMPUTER<tab>Action<tab>RetCode
  249. {
  250. WCHAR action[50];
  251. WCHAR const * pAction = wcschr(parser.GetMessage(),L'\t');
  252. WCHAR const * retcode = wcsrchr(parser.GetMessage(),L'\t');
  253. TServerNode * pServer = NULL;
  254. if ( GetServerFromMessage(parser.GetMessage(),server)
  255. && pAction
  256. && retcode
  257. && pAction != retcode
  258. )
  259. {
  260. // UStrCpy(action,pAction+1,retcode - pAction);
  261. UStrCpy(action,pAction+1,(int)(retcode - pAction));
  262. // add the server to the list, if it isn't already there
  263. gData.Lock();
  264. pServer = gData.GetUnsafeServerList()->FindServer(server);
  265. if ( ! pServer )
  266. pServer = gData.GetUnsafeServerList()->AddServer(server);
  267. gData.Unlock();
  268. retcode++;
  269. DWORD rc = _wtoi(retcode);
  270. if ( pServer )
  271. {
  272. if ( UStrICmp(pServer->GetTimeStamp(),parser.GetTimestamp()) < 0 )
  273. {
  274. pServer->SetTimeStamp(parser.GetTimestamp());
  275. }
  276. if ( !UStrICmp(action,L"WillInstall") )
  277. {
  278. pServer->SetIncluded(TRUE);
  279. }
  280. else if (! UStrICmp(action,L"JobFile") )
  281. {
  282. // this part is in the form of "%d,%d,job path"
  283. // where the number is indicative of whether account reference
  284. // result is expected
  285. WCHAR acctRefResultFlag = L'0';
  286. WCHAR joinRenameFlag = L'0';
  287. const WCHAR* msg = retcode;
  288. WCHAR* comma = wcschr(msg, L',');
  289. if ( comma )
  290. {
  291. if ( comma != msg )
  292. {
  293. acctRefResultFlag = *msg;
  294. WCHAR* msg1 = comma + 1;
  295. comma = wcschr(msg1, L',');
  296. if (comma != msg1)
  297. joinRenameFlag = *msg1;
  298. }
  299. pServer->SetJobPath(comma+1);
  300. }
  301. else
  302. {
  303. pServer->SetJobPath(L"");
  304. }
  305. // set whether account reference result is expected or not
  306. if (acctRefResultFlag == L'0')
  307. pServer->SetAccountReferenceResultExpected(FALSE);
  308. else
  309. pServer->SetAccountReferenceResultExpected(TRUE);
  310. // set whether join & rename is expected or not
  311. if (joinRenameFlag == L'0')
  312. pServer->SetJoinDomainWithRename(FALSE);
  313. else
  314. pServer->SetJoinDomainWithRename(TRUE);
  315. }
  316. else if (!UStrICmp(action,L"RemoteResultPath"))
  317. {
  318. pServer->SetRemoteResultPath(retcode);
  319. }
  320. else if (! UStrICmp(action,L"Install") )
  321. {
  322. if ( rc )
  323. {
  324. if ( ! *pServer->GetMessageText() )
  325. {
  326. TErrorDct errTemp;
  327. WCHAR text[2000];
  328. errTemp.ErrorCodeToText(rc,DIM(text),text);
  329. pServer->SetMessageText(text);
  330. }
  331. pServer->SetSeverity(2);
  332. pServer->SetFailed();
  333. pServer->SetIncluded(TRUE);
  334. gData.GetListWindow(&lWnd);
  335. SendMessage(lWnd,DCT_ERROR_ENTRY,NULL,(LPARAM)pServer);
  336. }
  337. else
  338. {
  339. pServer->SetInstalled();
  340. pServer->SetIncluded(TRUE);
  341. gData.GetListWindow(&lWnd);
  342. SendMessage(lWnd,DCT_UPDATE_ENTRY,NULL,(LPARAM)pServer);
  343. }
  344. }
  345. else if ( ! UStrICmp(action,L"Start") )
  346. {
  347. if ( rc )
  348. {
  349. if ( ! *pServer->GetMessageText() )
  350. {
  351. TErrorDct errTemp;
  352. WCHAR text[2000];
  353. errTemp.ErrorCodeToText(rc,DIM(text),text);
  354. pServer->SetMessageText(text);
  355. }
  356. pServer->SetSeverity(2);
  357. pServer->SetFailed();
  358. pServer->SetIncluded(TRUE);
  359. gData.GetListWindow(&lWnd);
  360. SendMessage(lWnd,DCT_ERROR_ENTRY,NULL,(LPARAM)pServer);
  361. }
  362. else
  363. {
  364. // extract the filename and GUID from the end of the message
  365. WCHAR filename[MAX_PATH];
  366. WCHAR guid[100];
  367. WCHAR * comma1 = wcschr(parser.GetMessage(),L',');
  368. WCHAR * comma2 = NULL;
  369. if ( comma1 )
  370. {
  371. comma2 = wcschr(comma1 + 1,L',');
  372. if ( comma2 )
  373. {
  374. // UStrCpy(filename,comma1+1,(comma2-comma1)); // skip the comma & space before the filename
  375. UStrCpy(filename,comma1+1,(int)(comma2-comma1)); // skip the comma & space before the filename
  376. safecopy(guid,comma2+1); // skip the comma & space before the guid
  377. pServer->SetJobID(guid);
  378. pServer->SetJobFile(filename);
  379. pServer->SetStarted();
  380. bNeedToCheckResults = TRUE;
  381. // launch a worker thread to monitor the agent
  382. // IsMonitoringTried is used to make sure that at most one
  383. // thread is created to monitor a particular agent.
  384. // The reason for adding this logic is that in case that lWnd
  385. // is NULL the total number of read lines will not be set in
  386. // gData so that the same line containing "Start" could be read
  387. // more than once and thus more than one thread will be
  388. // created to monitor an agent. This is problematic.
  389. // lWnd will be NULL if server list dialog has not been initialized
  390. // or it is command line case where there is no UI.
  391. if (!pServer->IsMonitoringTried())
  392. {
  393. // mark that we have tried to monitor the agent
  394. pServer->SetMonitoringTried(TRUE);
  395. DWORD id;
  396. HANDLE aThread = CreateThread(NULL,0,&MonitorRunningAgent,(void*)pServer,0,&id);
  397. if (aThread == NULL)
  398. {
  399. // indicate so if we have run out of resource to monitor the agent
  400. pServer->SetFailed();
  401. pServer->SetOutOfResourceToMonitor(TRUE);
  402. }
  403. else
  404. {
  405. CloseHandle(aThread);
  406. }
  407. }
  408. }
  409. gData.GetListWindow(&lWnd);
  410. SendMessage(lWnd,DCT_UPDATE_ENTRY,NULL,(LPARAM)pServer);
  411. }
  412. }
  413. }
  414. else if ( ! UStrICmp(action,L"Finished") )
  415. {
  416. SendMessage(lWnd,DCT_UPDATE_ENTRY,NULL,NULL);
  417. }
  418. }
  419. }
  420. else
  421. {
  422. // if dispatcher finished dispatching agents set log done
  423. LPCWSTR psz = parser.GetMessage();
  424. if (wcsstr(psz, L"All") && wcsstr(psz, L"Finished"))
  425. {
  426. gData.SetLogDone(TRUE);
  427. ComputerStats cStat;
  428. gData.GetComputerStats(&cStat);
  429. if (cStat.total == 0 && bTotalReadGlobal)
  430. {
  431. gData.GetListWindow(&lWnd);
  432. SendMessage(lWnd,DCT_UPDATE_ENTRY,NULL,NULL);
  433. }
  434. }
  435. }
  436. }
  437. }
  438. else
  439. {
  440. // once we hit an invalid entry, we stop scanning
  441. break;
  442. }
  443. }
  444. // if we don't have the handle from the list window, we couldn't really send the messages
  445. // in that case we must read the lines again next time, so that we can resend the messages.
  446. if ( lWnd )
  447. {
  448. // if we have sent the messages, we don't need to send them again
  449. gData.SetLinesRead(nRead);
  450. }
  451. // we signal the first pass done only after the total number of server has been read
  452. // and we only need to set it once
  453. if (!bTotalReadGlobal && bTotalReadLocal)
  454. {
  455. gData.SetFirstPassDone(TRUE);
  456. gData.SetTotalRead(TRUE);
  457. }
  458. parser.Close();
  459. }
  460. }