Source code of Windows XP (NT5)
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.

518 lines
16 KiB

  1. /*---------------------------------------------------------------------------
  2. File: Monitor.cpp
  3. Comments: Functions to monitor the status of the DCT Agents.
  4. This involves spawning a thread which periodically reads the dispatch log,
  5. and scans the result directory for result files.
  6. (c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
  7. Proprietary and confidential to Mission Critical Software, Inc.
  8. REVISION LOG ENTRY
  9. Revision By: Christy Boles
  10. Revised on 03/15/99 15:43:35
  11. ---------------------------------------------------------------------------
  12. */
  13. #include "StdAfx.h"
  14. #include "Resource.h"
  15. #include "Common.hpp"
  16. #include "Err.hpp"
  17. #include "UString.hpp"
  18. #include "TNode.hpp"
  19. #include "ServList.hpp"
  20. #include "Globals.h"
  21. #include "Monitor.h"
  22. #include "ResStr.h"
  23. #include <lm.h> // to remove result share
  24. //#import "\bin\McsVarSetMin.tlb" no_namespace , named_guids
  25. //#import "\bin\DBManager.tlb" no_namespace, named_guids
  26. #import "VarSet.tlb" no_namespace , named_guids rename("property", "aproperty")
  27. #import "DBMgr.tlb" no_namespace, named_guids
  28. //#include "..\Common\Include\McsPI.h"
  29. #include "McsPI.h"
  30. #include "McsPI_i.c"
  31. #include "afxdao.h"
  32. void LookForResults(WCHAR * dir = NULL);
  33. void WaitForMoreResults(WCHAR * dir);
  34. void ProcessResults(TServerNode * pServer, WCHAR const * directory, WCHAR const * filename);
  35. GlobalData gData;
  36. DWORD __stdcall ResultMonitorFn(void * arg)
  37. {
  38. WCHAR logdir[MAX_PATH] = L"";
  39. BOOL bFirstPassDone;
  40. CoInitialize(NULL);
  41. gData.GetFirstPassDone(&bFirstPassDone);
  42. // wait until the other monitoring thread has a chance to build the server list,
  43. // so we can check for pre-existing input files before using the changenotify mechanism
  44. while ( ! bFirstPassDone || !*logdir )
  45. {
  46. Sleep(500);
  47. gData.GetFirstPassDone(&bFirstPassDone);
  48. gData.GetResultDir(logdir);
  49. }
  50. LookForResults(logdir);
  51. WaitForMoreResults(logdir);
  52. CoUninitialize();
  53. return 0;
  54. }
  55. void WaitForMoreResults(WCHAR * logdir)
  56. {
  57. WCHAR resultWC[MAX_PATH];
  58. HANDLE hFind;
  59. DWORD rc = 0;
  60. BOOL bDone;
  61. long nIntervalSeconds;
  62. safecopy(resultWC,logdir);
  63. hFind = FindFirstChangeNotification(resultWC,FALSE,FILE_NOTIFY_CHANGE_FILE_NAME);
  64. if ( hFind == INVALID_HANDLE_VALUE )
  65. {
  66. rc = GetLastError();
  67. return;
  68. }
  69. gData.GetDone(&bDone);
  70. gData.GetWaitInterval(&nIntervalSeconds);
  71. while (! bDone && !rc)
  72. {
  73. if ( WAIT_OBJECT_0 == WaitForSingleObject(hFind,nIntervalSeconds * 1000 ) )
  74. {
  75. LookForResults(logdir);
  76. }
  77. else
  78. {
  79. LookForResults(logdir);
  80. }
  81. if ( ! FindNextChangeNotification(hFind) )
  82. {
  83. rc = GetLastError();
  84. }
  85. gData.GetDone(&bDone);
  86. gData.GetWaitInterval(&nIntervalSeconds);
  87. }
  88. FindCloseChangeNotification(hFind);
  89. }
  90. void LookForResults(WCHAR * arglogdir)
  91. {
  92. TNodeListEnum e;
  93. TServerNode * s;
  94. DWORD nInstalled = 0;
  95. DWORD nRunning = 0;
  96. DWORD nFinished = 0;
  97. DWORD nError = 0;
  98. HWND gListWnd;
  99. HWND gSummaryWnd;
  100. WCHAR logdir[MAX_PATH];
  101. if ( ! (arglogdir && *arglogdir) )
  102. {
  103. gData.GetResultDir(logdir);
  104. }
  105. else
  106. {
  107. safecopy(logdir,arglogdir);
  108. }
  109. for ( s = (TServerNode*)e.OpenFirst(gData.GetUnsafeServerList()) ; s ; gData.Lock(),s = (TServerNode*)e.Next(),gData.Unlock() )
  110. {
  111. if ( s->IsInstalled() )
  112. nInstalled++;
  113. if ( s->IsFinished() )
  114. nFinished++;
  115. if ( s->HasFailed() )
  116. nError++;
  117. // Check jobs that were running but not finished
  118. if ( *s->GetJobFile() && s->IsRunning() )
  119. {
  120. nRunning++;
  121. // Look for results
  122. WCHAR resultWC[MAX_PATH];
  123. HANDLE hFind;
  124. WIN32_FIND_DATA fdata;
  125. WCHAR sTime[32];
  126. if ( logdir[UStrLen(logdir)-1] == L'\\' )
  127. {
  128. swprintf(resultWC,L"%s%s.result",logdir,s->GetJobFile());
  129. }
  130. else
  131. {
  132. swprintf(resultWC,L"%s\\%s.result",logdir,s->GetJobFile());
  133. }
  134. hFind = FindFirstFile(resultWC,&fdata);
  135. s->SetTimeStamp(gTTime.FormatIsoLcl( gTTime.Now( NULL ), sTime ));
  136. if ( hFind != INVALID_HANDLE_VALUE )
  137. {
  138. // found something
  139. gData.Lock();
  140. if ( ! s->IsFinished() )
  141. {
  142. gData.Unlock();
  143. ProcessResults(s,logdir,fdata.cFileName);
  144. }
  145. else
  146. {
  147. gData.Unlock();
  148. }
  149. nRunning--;
  150. nFinished++;
  151. FindClose(hFind);
  152. }
  153. gData.GetListWindow(&gListWnd);
  154. // SendMessage(gListWnd,DCT_UPDATE_ENTRY,NULL,(long)s);
  155. SendMessage(gListWnd,DCT_UPDATE_ENTRY,NULL,(LPARAM)s);
  156. }
  157. }
  158. e.Close();
  159. // Update the summary window
  160. ComputerStats stat;
  161. // get the total servers number
  162. gData.GetComputerStats(&stat);
  163. stat.numError = nError;
  164. stat.numFinished = nFinished;
  165. stat.numRunning = nRunning;
  166. stat.numInstalled = nInstalled;
  167. gData.SetComputerStats(&stat);
  168. gData.GetSummaryWindow(&gSummaryWnd);
  169. // SendMessage(gSummaryWnd,DCT_UPDATE_COUNTS,0,(long)&stat);
  170. SendMessage(gSummaryWnd,DCT_UPDATE_COUNTS,0,(LPARAM)&stat);
  171. }
  172. BOOL // ret- TRUE if successful
  173. ReadResults(
  174. TServerNode * pServer, // in - pointer to server node containing server name
  175. WCHAR const * directory, // in - directory where results files are stored
  176. WCHAR const * filename, // in - filename for this agent's job
  177. DetailStats * pStats, // out- counts of items processed by the agent
  178. CString & plugInText, // out- text results from plug-ins
  179. BOOL bStore // in - bool, whether to store plug-in text
  180. )
  181. {
  182. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  183. WCHAR path[MAX_PATH];
  184. HRESULT hr = S_OK;
  185. BOOL bSuccess = FALSE;
  186. if ( directory[UStrLen(directory)-1] == '\\' )
  187. {
  188. swprintf(path,L"%ls%ls",directory,filename);
  189. }
  190. else
  191. {
  192. swprintf(path,L"%ls\\%ls",directory,filename);
  193. }
  194. // Read the varset data from the file
  195. IVarSetPtr pVarSet;
  196. IStoragePtr store = NULL;
  197. // Try to create the COM objects
  198. hr = pVarSet.CreateInstance(CLSID_VarSet);
  199. if ( SUCCEEDED(hr) )
  200. {
  201. // Read the VarSet from the data file
  202. int tries = 0;
  203. do
  204. {
  205. tries++;
  206. hr = StgOpenStorage(path,NULL,STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&store);
  207. if ( SUCCEEDED(hr) )
  208. {
  209. // Load the data into a new varset
  210. hr = OleLoad(store,IID_IUnknown,NULL,(void **)&pVarSet);
  211. }
  212. if ( tries > 2 )
  213. break;
  214. Sleep(500);
  215. } while ( hr == STG_E_SHAREVIOLATION || hr == STG_E_LOCKVIOLATION );
  216. }
  217. if ( SUCCEEDED(hr) )
  218. {
  219. pStats->directoriesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Directories_Changed));
  220. pStats->directoriesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Directories_Examined));
  221. pStats->directoriesUnchanged = (pStats->directoriesExamined - pStats->directoriesChanged);
  222. pStats->filesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Files_Changed));
  223. pStats->filesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Files_Examined));
  224. pStats->filesUnchanged = (pStats->filesExamined - pStats->filesChanged );
  225. pStats->sharesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Shares_Changed));
  226. pStats->sharesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Shares_Examined));
  227. pStats->sharesUnchanged = (pStats->sharesExamined - pStats->sharesChanged );
  228. pStats->membersChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Members_Changed));
  229. pStats->membersExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Members_Examined));
  230. pStats->membersUnchanged = (pStats->membersExamined - pStats->membersChanged );
  231. pStats->rightsChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_UserRights_Changed));
  232. pStats->rightsExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_UserRights_Examined));
  233. pStats->rightsUnchanged = (pStats->rightsExamined - pStats->rightsChanged );
  234. long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
  235. _bstr_t logfile = pVarSet->get(GET_BSTR(DCTVS_Results_LogFile));
  236. if ( level > 2 )
  237. {
  238. CString message;
  239. message.FormatMessage(IDS_SeeLogForAgentErrors_S,(WCHAR*)logfile);
  240. pServer->SetMessageText(message.GetBuffer(0));
  241. }
  242. pServer->SetSeverity(level);
  243. // build the UNC path for the log file
  244. WCHAR logPath[MAX_PATH];
  245. swprintf(logPath,L"\\\\%s\\%c$\\%s",pServer->GetServer(),((WCHAR*)logfile)[0],((WCHAR*)logfile) + 3);
  246. pServer->SetLogPath(logPath);
  247. bSuccess = TRUE;
  248. // Try to get information from any plug-ins that ran
  249. // create the COM object for each plug-in
  250. _bstr_t bStrGuid;
  251. WCHAR key[300];
  252. CLSID clsid;
  253. for ( int i = 0 ; ; i++ )
  254. {
  255. swprintf(key,L"Plugin.%ld",i);
  256. bStrGuid = pVarSet->get(key);
  257. if ( bStrGuid.length() == 0 )
  258. break;
  259. IMcsDomPlugIn * pPlugIn = NULL;
  260. hr = CLSIDFromString(bStrGuid,&clsid);
  261. if ( SUCCEEDED(hr) )
  262. {
  263. hr = CoCreateInstance(clsid,NULL,CLSCTX_ALL,IID_IMcsDomPlugIn,(void**)&pPlugIn);
  264. if ( SUCCEEDED(hr) )
  265. {
  266. BSTR name = NULL;
  267. BSTR result = NULL;
  268. hr = pPlugIn->GetName(&name);
  269. if ( SUCCEEDED(hr) )
  270. {
  271. hr = pPlugIn->GetResultString(pVarSet,&result);
  272. if ( SUCCEEDED(hr) )
  273. {
  274. plugInText += (WCHAR*)name;
  275. plugInText += L"\n";
  276. plugInText += (WCHAR*)result;
  277. plugInText += L"\n\n";
  278. SysFreeString(result);
  279. }
  280. SysFreeString(name);
  281. if ( bStore )
  282. {
  283. pVarSet->put(L"LocalServer",pServer->GetServer());
  284. pPlugIn->StoreResults(pVarSet);
  285. }
  286. }
  287. pPlugIn->Release();
  288. }
  289. }
  290. }
  291. }
  292. else
  293. {
  294. CString message;
  295. CString title;
  296. if ( hr != STG_E_SHAREVIOLATION && hr != STG_E_LOCKVIOLATION )
  297. {
  298. message.FormatMessage(IDS_FailedToLoadResults,filename,hr);
  299. title.LoadString(IDS_MessageTitle);
  300. if ( hr != STG_E_FILENOTFOUND )
  301. MessageBox(NULL,message,title,MB_OK | MB_ICONERROR);
  302. }
  303. else
  304. {
  305. // the agent has still not finished writing its results file, for some reason
  306. // we'll check it again later
  307. pServer->SetStatus(pServer->GetStatus() & ~Agent_Status_Finished);
  308. }
  309. }
  310. return bSuccess;
  311. }
  312. void
  313. ProcessSecRefs(
  314. TServerNode * pServer,
  315. WCHAR const * directory,
  316. WCHAR const * filename
  317. )
  318. {
  319. AFX_MANAGE_STATE(AfxGetStaticModuleState());
  320. WCHAR path[MAX_PATH];
  321. DWORD rc = 0;
  322. BOOL bSuccess = FALSE;
  323. FILE * pFile;
  324. WCHAR * pDot;
  325. if ( directory[UStrLen(directory)-1] == '\\' )
  326. {
  327. swprintf(path,L"%ls%ls",directory,filename);
  328. }
  329. else
  330. {
  331. swprintf(path,L"%ls\\%ls",directory,filename);
  332. }
  333. // check to see if a secrefs file was written
  334. pDot = wcsrchr(path,L'.');
  335. if ( pDot )
  336. {
  337. UStrCpy(pDot,L".secrefs");
  338. pFile = _wfopen(path,L"rb");
  339. if ( pFile )
  340. {
  341. IIManageDBPtr pDB;
  342. rc = pDB.CreateInstance(CLSID_IManageDB);
  343. if ( SUCCEEDED(rc) )
  344. {
  345. // there are some secrefs here, load them into the database
  346. WCHAR account[300] = L"";
  347. WCHAR type[100] = L"";
  348. DWORD nOwner = 0;
  349. DWORD nGroup = 0;
  350. DWORD nDacl = 0;
  351. DWORD nSacl = 0;
  352. WCHAR domPart[300];
  353. WCHAR acctPart[300];
  354. WCHAR acctSid[300] = L"";
  355. WCHAR * slash;
  356. CString typeString;
  357. //move past the UNICODE Byte Order Mark
  358. fgetwc(pFile);
  359. //get entries
  360. while ( 7 == fwscanf(pFile,L"%[^,],%[^,],%[^,],%ld,%ld,%ld,%ld\r\n",account,acctSid,type,&nOwner,&nGroup,&nDacl,&nSacl) )
  361. {
  362. safecopy(domPart,account);
  363. slash = wcschr(domPart,L'\\');
  364. if ( slash )
  365. {
  366. *slash = 0;
  367. UStrCpy(acctPart,slash+1);
  368. }
  369. else
  370. {
  371. domPart[0] = 0;
  372. safecopy(acctPart,account);
  373. }
  374. //for sIDs with no resolvable account, change domain and account to (Unknown)
  375. if ((wcsstr(account, L"S-") == account) && (domPart[0] == 0))
  376. {
  377. wcscpy(acctPart, GET_STRING(IDS_UnknownSid));
  378. wcscpy(domPart, GET_STRING(IDS_UnknownSid));
  379. }
  380. typeString.FormatMessage(IDS_OwnerRef_S,type);
  381. rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nOwner,typeString.AllocSysString());
  382. typeString.FormatMessage(IDS_GroupRef_S,type);
  383. rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nGroup,typeString.AllocSysString());
  384. //since local group members are not referenced in DACL, but we use that
  385. //field to keep track of reference, use a different type string
  386. if (!UStrCmp(type, GET_STRING(IDS_STReference_Member)))
  387. typeString.FormatMessage(IDS_MemberRef_S);
  388. else
  389. typeString.FormatMessage(IDS_DACLRef_S,type);
  390. rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nDacl,typeString.AllocSysString());
  391. typeString.FormatMessage(IDS_SACLRef_S,type);
  392. rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nSacl,typeString.AllocSysString());
  393. // make sure there's not any data left over in these
  394. account[0] = 0;
  395. type[0] = 0;
  396. acctSid[0] = 0;
  397. nOwner = 0;
  398. nGroup = 0;
  399. nDacl = 0;
  400. nSacl = 0;
  401. }
  402. }
  403. fclose(pFile);
  404. }
  405. }
  406. }
  407. void
  408. ProcessResults(
  409. TServerNode * pServer,
  410. WCHAR const * directory,
  411. WCHAR const * filename
  412. )
  413. {
  414. HRESULT hr = S_OK;
  415. DetailStats stats;
  416. HWND hWnd;
  417. CString PLText;
  418. memset(&stats,0,(sizeof stats));
  419. if ( ReadResults(pServer,directory,filename,&stats,PLText,TRUE) )
  420. {
  421. pServer->SetFinished();
  422. if ( ! pServer->HasFailed() && ! pServer->GetSeverity() )
  423. {
  424. pServer->SetMessageText(L"");
  425. }
  426. gData.AddDetailStats(&stats);
  427. gData.GetSummaryWindow(&hWnd);
  428. // get the stats for this job, and send them to the summary window
  429. // SendMessage(hWnd, DCT_UPDATE_TOTALS, 0, (long)&stats);
  430. SendMessage(hWnd, DCT_UPDATE_TOTALS, 0, (LPARAM)&stats);
  431. // also get import the security references
  432. ProcessSecRefs(pServer,directory,filename);
  433. }
  434. }