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.
555 lines
18 KiB
555 lines
18 KiB
/*---------------------------------------------------------------------------
|
|
File: Monitor.cpp
|
|
|
|
Comments: Functions to monitor the status of the DCT Agents.
|
|
|
|
This involves spawning a thread which periodically reads the dispatch log,
|
|
and scans the result directory for result files.
|
|
|
|
(c) Copyright 1999, Mission Critical Software, Inc., All Rights Reserved
|
|
Proprietary and confidential to Mission Critical Software, Inc.
|
|
|
|
REVISION LOG ENTRY
|
|
Revision By: Christy Boles
|
|
Revised on 03/15/99 15:43:35
|
|
|
|
---------------------------------------------------------------------------
|
|
*/
|
|
|
|
|
|
#include "StdAfx.h"
|
|
#include "Resource.h"
|
|
#include "Common.hpp"
|
|
#include "Err.hpp"
|
|
#include "UString.hpp"
|
|
#include "TNode.hpp"
|
|
#include "ServList.hpp"
|
|
#include "Globals.h"
|
|
#include "Monitor.h"
|
|
#include "ResStr.h"
|
|
#include <lm.h> // to remove result share
|
|
|
|
|
|
//#import "\bin\McsVarSetMin.tlb" no_namespace , named_guids
|
|
//#import "\bin\DBManager.tlb" no_namespace, named_guids
|
|
#import "VarSet.tlb" no_namespace , named_guids rename("property", "aproperty")
|
|
#import "DBMgr.tlb" no_namespace, named_guids
|
|
|
|
//#include "..\Common\Include\McsPI.h"
|
|
#include "McsPI.h"
|
|
#include "McsPI_i.c"
|
|
|
|
#include "afxdao.h"
|
|
|
|
void LookForResults(WCHAR * dir = NULL);
|
|
void WaitForMoreResults(WCHAR * dir);
|
|
void ProcessResults(TServerNode * pServer, WCHAR const * directory, WCHAR const * filename);
|
|
|
|
GlobalData gData;
|
|
|
|
DWORD __stdcall ResultMonitorFn(void * arg)
|
|
{
|
|
WCHAR logdir[MAX_PATH] = L"";
|
|
BOOL bFirstPassDone;
|
|
|
|
CoInitialize(NULL);
|
|
|
|
gData.GetFirstPassDone(&bFirstPassDone);
|
|
|
|
// wait until the other monitoring thread has a chance to build the server list,
|
|
// so we can check for pre-existing input files before using the changenotify mechanism
|
|
|
|
while ( ! bFirstPassDone || !*logdir )
|
|
{
|
|
Sleep(500);
|
|
gData.GetFirstPassDone(&bFirstPassDone);
|
|
gData.GetResultDir(logdir);
|
|
}
|
|
LookForResults(logdir);
|
|
WaitForMoreResults(logdir);
|
|
|
|
CoUninitialize();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void WaitForMoreResults(WCHAR * logdir)
|
|
{
|
|
WCHAR resultWC[MAX_PATH];
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
BOOL bDone;
|
|
long nIntervalSeconds;
|
|
|
|
safecopy(resultWC,logdir);
|
|
|
|
gData.GetDone(&bDone);
|
|
gData.GetWaitInterval(&nIntervalSeconds);
|
|
while (! bDone)
|
|
{
|
|
if (hFind == INVALID_HANDLE_VALUE)
|
|
{
|
|
hFind = FindFirstChangeNotification(resultWC, FALSE, FILE_NOTIFY_CHANGE_FILE_NAME);
|
|
}
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
WaitForSingleObject(hFind,nIntervalSeconds * 1000 );
|
|
else
|
|
Sleep(nIntervalSeconds * 1000);
|
|
|
|
LookForResults(logdir);
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (! FindNextChangeNotification(hFind))
|
|
{
|
|
FindCloseChangeNotification(hFind);
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
gData.GetDone(&bDone); // we still listen to global done
|
|
// in case that we use it to force a stop
|
|
gData.GetWaitInterval(&nIntervalSeconds);
|
|
|
|
ComputerStats stats;
|
|
gData.GetComputerStats(&stats);
|
|
|
|
// if all agents either finished or failed, we consider it done
|
|
if (stats.numFinished + stats.numError >= stats.total)
|
|
break;
|
|
}
|
|
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
FindCloseChangeNotification(hFind);
|
|
|
|
gData.SetDone(TRUE);
|
|
}
|
|
|
|
|
|
void LookForResults(WCHAR * arglogdir)
|
|
{
|
|
TNodeListEnum e;
|
|
TServerNode * s;
|
|
DWORD nInstalled = 0;
|
|
DWORD nRunning = 0;
|
|
DWORD nFinished = 0;
|
|
DWORD nError = 0;
|
|
HWND gListWnd;
|
|
HWND gSummaryWnd;
|
|
WCHAR logdir[MAX_PATH];
|
|
|
|
if ( ! (arglogdir && *arglogdir) )
|
|
{
|
|
gData.GetResultDir(logdir);
|
|
}
|
|
else
|
|
{
|
|
safecopy(logdir,arglogdir);
|
|
}
|
|
|
|
for ( s = (TServerNode*)e.OpenFirst(gData.GetUnsafeServerList()) ; s ; gData.Lock(),s = (TServerNode*)e.Next(),gData.Unlock() )
|
|
{
|
|
if ( s->IsInstalled() )
|
|
nInstalled++;
|
|
if (s->HasFailed())
|
|
nError++;
|
|
// only when result has been processed do we consider it finished
|
|
else if (s->IsFinished() && s->IsResultPullingTried() && (!s->HasResult() || s->IsResultProcessed()))
|
|
nFinished++;
|
|
else
|
|
nRunning++;
|
|
|
|
// Check jobs that finished, got result pulled but not yet processed
|
|
if ( *s->GetJobFile() && s->IsFinished() && s->IsResultPullingTried()
|
|
&& s->HasResult() && !s->IsResultProcessed() )
|
|
{
|
|
// Look for results
|
|
WCHAR resultWC[MAX_PATH];
|
|
HANDLE hFind;
|
|
WIN32_FIND_DATA fdata;
|
|
WCHAR sTime[32];
|
|
|
|
if ( logdir[UStrLen(logdir)-1] == L'\\' )
|
|
{
|
|
swprintf(resultWC,L"%s%s.result",logdir,s->GetJobFile());
|
|
}
|
|
else
|
|
{
|
|
swprintf(resultWC,L"%s\\%s.result",logdir,s->GetJobFile());
|
|
}
|
|
hFind = FindFirstFile(resultWC,&fdata);
|
|
|
|
s->SetTimeStamp(gTTime.FormatIsoLcl( gTTime.Now( NULL ), sTime ));
|
|
|
|
if ( hFind != INVALID_HANDLE_VALUE )
|
|
{
|
|
ProcessResults(s,logdir,fdata.cFileName);
|
|
s->SetResultProcessed(TRUE);
|
|
nRunning--;
|
|
nFinished++;
|
|
FindClose(hFind);
|
|
}
|
|
gData.GetListWindow(&gListWnd);
|
|
SendMessage(gListWnd,DCT_UPDATE_ENTRY,NULL,(LPARAM)s);
|
|
}
|
|
}
|
|
e.Close();
|
|
|
|
// Update the summary window
|
|
ComputerStats stat;
|
|
|
|
// get the total servers number
|
|
gData.GetComputerStats(&stat);
|
|
stat.numError = nError;
|
|
stat.numFinished = nFinished;
|
|
stat.numRunning = nRunning;
|
|
stat.numInstalled = nInstalled;
|
|
|
|
gData.SetComputerStats(&stat);
|
|
|
|
gData.GetSummaryWindow(&gSummaryWnd);
|
|
SendMessage(gSummaryWnd,DCT_UPDATE_COUNTS,0,(LPARAM)&stat);
|
|
}
|
|
|
|
BOOL // ret- TRUE if successful
|
|
ReadResults(
|
|
TServerNode * pServer, // in - pointer to server node containing server name
|
|
WCHAR const * directory, // in - directory where results files are stored
|
|
WCHAR const * filename, // in - filename for this agent's job
|
|
DetailStats * pStats, // out- counts of items processed by the agent
|
|
CString & plugInText, // out- text results from plug-ins
|
|
BOOL bStore // in - bool, whether to store plug-in text
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
WCHAR path[MAX_PATH];
|
|
HRESULT hr = S_OK;
|
|
BOOL bSuccess = FALSE;
|
|
|
|
if ( directory[UStrLen(directory)-1] == '\\' )
|
|
{
|
|
swprintf(path,L"%ls%ls",directory,filename);
|
|
}
|
|
else
|
|
{
|
|
swprintf(path,L"%ls\\%ls",directory,filename);
|
|
}
|
|
|
|
// Read the varset data from the file
|
|
IVarSetPtr pVarSet;
|
|
IStoragePtr store;
|
|
|
|
// attempt to open result file
|
|
|
|
for (int nTries = 0; nTries < 6; nTries++)
|
|
{
|
|
hr = StgOpenStorage(path, NULL, STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE, NULL, 0, &store);
|
|
|
|
// if sharing or lock violation then...
|
|
|
|
if ((hr == STG_E_SHAREVIOLATION) || (hr == STG_E_LOCKVIOLATION))
|
|
{
|
|
// wait one second before trying again
|
|
Sleep(1000);
|
|
}
|
|
else
|
|
{
|
|
// otherwise stop trying
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// load VarSet from file
|
|
hr = OleLoad(store, IID_IVarSet, NULL, (void**)&pVarSet);
|
|
}
|
|
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
pStats->directoriesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Directories_Changed));
|
|
pStats->directoriesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Directories_Examined));
|
|
pStats->directoriesUnchanged = (pStats->directoriesExamined - pStats->directoriesChanged);
|
|
|
|
pStats->filesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Files_Changed));
|
|
pStats->filesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Files_Examined));
|
|
pStats->filesUnchanged = (pStats->filesExamined - pStats->filesChanged );
|
|
|
|
pStats->sharesChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Shares_Changed));
|
|
pStats->sharesExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Shares_Examined));
|
|
pStats->sharesUnchanged = (pStats->sharesExamined - pStats->sharesChanged );
|
|
|
|
pStats->membersChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Members_Changed));
|
|
pStats->membersExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_Members_Examined));
|
|
pStats->membersUnchanged = (pStats->membersExamined - pStats->membersChanged );
|
|
|
|
pStats->rightsChanged = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_UserRights_Changed));
|
|
pStats->rightsExamined = (long)pVarSet->get(GET_BSTR(DCTVS_Stats_UserRights_Examined));
|
|
pStats->rightsUnchanged = (pStats->rightsExamined - pStats->rightsChanged );
|
|
|
|
|
|
long level = pVarSet->get(GET_BSTR(DCTVS_Results_ErrorLevel));
|
|
_bstr_t logfile = pVarSet->get(GET_BSTR(DCTVS_Results_LogFile));
|
|
_bstr_t logfileIsInvalid = pVarSet->get(GET_BSTR(DCTVS_Results_LogFileIsInvalid));
|
|
BOOL bLogfileIsInvalid =
|
|
(!logfileIsInvalid == false && !UStrICmp(logfileIsInvalid, GET_STRING(IDS_YES))) ? TRUE : FALSE;
|
|
|
|
if ( level > 2 )
|
|
{
|
|
CString message;
|
|
|
|
message.FormatMessage(IDS_SeeLogForAgentErrors_S,(WCHAR*)logfile);
|
|
|
|
pServer->SetMessageText(message.GetBuffer(0));
|
|
}
|
|
pServer->SetSeverity(level);
|
|
|
|
// build the UNC path for the log file
|
|
WCHAR logPath[MAX_PATH];
|
|
|
|
swprintf(logPath,L"\\\\%s\\%c$\\%s",pServer->GetServer(),((WCHAR*)logfile)[0],((WCHAR*)logfile) + 3);
|
|
|
|
if (bLogfileIsInvalid)
|
|
{
|
|
pServer->SetLogPath(logfile);
|
|
pServer->SetLogPathValid(FALSE);
|
|
}
|
|
else
|
|
{
|
|
pServer->SetLogPath(logPath);
|
|
pServer->SetLogPathValid(TRUE);
|
|
}
|
|
bSuccess = TRUE;
|
|
|
|
// Try to get information from any plug-ins that ran
|
|
// create the COM object for each plug-in
|
|
_bstr_t bStrGuid;
|
|
WCHAR key[300];
|
|
CLSID clsid;
|
|
|
|
for ( int i = 0 ; ; i++ )
|
|
{
|
|
swprintf(key,L"Plugin.%ld",i);
|
|
bStrGuid = pVarSet->get(key);
|
|
|
|
if ( bStrGuid.length() == 0 )
|
|
break;
|
|
|
|
IMcsDomPlugIn * pPlugIn = NULL;
|
|
|
|
hr = CLSIDFromString(bStrGuid,&clsid);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = CoCreateInstance(clsid,NULL,CLSCTX_ALL,IID_IMcsDomPlugIn,(void**)&pPlugIn);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
BSTR name = NULL;
|
|
BSTR result = NULL;
|
|
|
|
hr = pPlugIn->GetName(&name);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
hr = pPlugIn->GetResultString(pVarSet,&result);
|
|
if ( SUCCEEDED(hr) )
|
|
{
|
|
plugInText += (WCHAR*)name;
|
|
plugInText += L"\n";
|
|
plugInText += (WCHAR*)result;
|
|
plugInText += L"\n\n";
|
|
SysFreeString(result);
|
|
}
|
|
SysFreeString(name);
|
|
if ( bStore )
|
|
{
|
|
pVarSet->put(L"LocalServer",pServer->GetServer());
|
|
pPlugIn->StoreResults(pVarSet);
|
|
}
|
|
}
|
|
pPlugIn->Release();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
CString message;
|
|
CString title;
|
|
|
|
if ( hr != STG_E_SHAREVIOLATION && hr != STG_E_LOCKVIOLATION )
|
|
{
|
|
message.FormatMessage(IDS_FailedToLoadResults,filename,hr);
|
|
title.LoadString(IDS_MessageTitle);
|
|
if ( hr != STG_E_FILENOTFOUND )
|
|
MessageBox(NULL,message,title,MB_OK | MB_ICONERROR);
|
|
}
|
|
else
|
|
{
|
|
// the agent has still not finished writing its results file, for some reason
|
|
// we'll check it again later
|
|
pServer->SetStatus(pServer->GetStatus() & ~Agent_Status_Finished);
|
|
}
|
|
}
|
|
return bSuccess;
|
|
}
|
|
|
|
void
|
|
ProcessSecRefs(
|
|
TServerNode * pServer,
|
|
WCHAR const * directory,
|
|
WCHAR const * filename
|
|
)
|
|
{
|
|
AFX_MANAGE_STATE(AfxGetStaticModuleState());
|
|
|
|
const DWORD NOREF = 0;
|
|
|
|
WCHAR path[MAX_PATH];
|
|
DWORD rc = 0;
|
|
BOOL bSuccess = FALSE;
|
|
FILE * pFile;
|
|
WCHAR * pDot;
|
|
|
|
if ( directory[UStrLen(directory)-1] == '\\' )
|
|
{
|
|
swprintf(path,L"%ls%ls",directory,filename);
|
|
}
|
|
else
|
|
{
|
|
swprintf(path,L"%ls\\%ls",directory,filename);
|
|
}
|
|
// check to see if a secrefs file was written
|
|
pDot = wcsrchr(path,L'.');
|
|
if ( pDot )
|
|
{
|
|
UStrCpy(pDot,L".secrefs");
|
|
pFile = _wfopen(path,L"rb");
|
|
if ( pFile )
|
|
{
|
|
IIManageDBPtr pDB;
|
|
|
|
rc = pDB.CreateInstance(CLSID_IManageDB);
|
|
if ( SUCCEEDED(rc) )
|
|
{
|
|
// there are some secrefs here, load them into the database
|
|
WCHAR account[300] = L"";
|
|
WCHAR type[100] = L"";
|
|
DWORD nOwner = 0;
|
|
DWORD nGroup = 0;
|
|
DWORD nDacl = 0;
|
|
DWORD nSacl = 0;
|
|
WCHAR domPart[300];
|
|
WCHAR acctPart[300];
|
|
WCHAR acctSid[300] = L"";
|
|
WCHAR * slash;
|
|
CString typeString;
|
|
|
|
//remove any old references for this machine in the table
|
|
_variant_t var;
|
|
WCHAR sFilter[MAX_PATH];
|
|
wsprintf(sFilter, L"Server = \"%s\"", pServer->GetServer());
|
|
var = sFilter;
|
|
rc = pDB->raw_ClearTable(L"AccountRefs", var);
|
|
|
|
//move past the UNICODE Byte Order Mark
|
|
fgetwc(pFile);
|
|
|
|
//get entries
|
|
while ( 7 == fwscanf(pFile,L"%[^,],%[^,],%[^,],%ld,%ld,%ld,%ld\r\n",account,acctSid,type,&nOwner,&nGroup,&nDacl,&nSacl) )
|
|
{
|
|
|
|
safecopy(domPart,account);
|
|
slash = wcschr(domPart,L'\\');
|
|
if ( slash )
|
|
{
|
|
*slash = 0;
|
|
UStrCpy(acctPart,slash+1);
|
|
}
|
|
else
|
|
{
|
|
domPart[0] = 0;
|
|
safecopy(acctPart,account);
|
|
}
|
|
|
|
//for sIDs with no resolvable account, change domain and account to (Unknown)
|
|
if ((wcsstr(account, L"S-") == account) && (domPart[0] == 0))
|
|
{
|
|
wcscpy(acctPart, GET_STRING(IDS_UnknownSid));
|
|
wcscpy(domPart, GET_STRING(IDS_UnknownSid));
|
|
}
|
|
|
|
if (nOwner != NOREF)
|
|
{
|
|
typeString.FormatMessage(IDS_OwnerRef_S,type);
|
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nOwner,typeString.AllocSysString());
|
|
}
|
|
|
|
if (nGroup != NOREF)
|
|
{
|
|
typeString.FormatMessage(IDS_GroupRef_S,type);
|
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nGroup,typeString.AllocSysString());
|
|
}
|
|
|
|
if (nDacl != NOREF)
|
|
{
|
|
//since local group members are not referenced in DACL, but we use that
|
|
//field to keep track of reference, use a different type string
|
|
if (!UStrCmp(type, GET_STRING(IDS_STReference_Member)))
|
|
typeString.FormatMessage(IDS_MemberRef_S);
|
|
else
|
|
typeString.FormatMessage(IDS_DACLRef_S,type);
|
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nDacl,typeString.AllocSysString());
|
|
}
|
|
|
|
if (nSacl != NOREF)
|
|
{
|
|
typeString.FormatMessage(IDS_SACLRef_S,type);
|
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nSacl,typeString.AllocSysString());
|
|
}
|
|
|
|
// make sure there's not any data left over in these
|
|
account[0] = 0;
|
|
type[0] = 0;
|
|
acctSid[0] = 0;
|
|
nOwner = 0;
|
|
nGroup = 0;
|
|
nDacl = 0;
|
|
nSacl = 0;
|
|
}
|
|
}
|
|
fclose(pFile);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
void
|
|
ProcessResults(
|
|
TServerNode * pServer,
|
|
WCHAR const * directory,
|
|
WCHAR const * filename
|
|
)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
DetailStats stats;
|
|
HWND hWnd;
|
|
CString PLText;
|
|
memset(&stats,0,(sizeof stats));
|
|
|
|
if ( ReadResults(pServer,directory,filename,&stats,PLText,TRUE) )
|
|
{
|
|
if ( ! pServer->HasFailed() && ! pServer->GetSeverity() )
|
|
{
|
|
pServer->SetMessageText(L"");
|
|
}
|
|
gData.AddDetailStats(&stats);
|
|
gData.GetSummaryWindow(&hWnd);
|
|
// get the stats for this job, and send them to the summary window
|
|
// SendMessage(hWnd, DCT_UPDATE_TOTALS, 0, (long)&stats);
|
|
SendMessage(hWnd, DCT_UPDATE_TOTALS, 0, (LPARAM)&stats);
|
|
}
|
|
|
|
// also get import the security references
|
|
if (pServer->IsAccountReferenceResultExpected())
|
|
ProcessSecRefs(pServer,directory,filename);
|
|
}
|