519 lines
16 KiB
C++
519 lines
16 KiB
C++
|
/*---------------------------------------------------------------------------
|
||
|
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;
|
||
|
DWORD rc = 0;
|
||
|
BOOL bDone;
|
||
|
long nIntervalSeconds;
|
||
|
|
||
|
safecopy(resultWC,logdir);
|
||
|
|
||
|
hFind = FindFirstChangeNotification(resultWC,FALSE,FILE_NOTIFY_CHANGE_FILE_NAME);
|
||
|
if ( hFind == INVALID_HANDLE_VALUE )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
gData.GetDone(&bDone);
|
||
|
gData.GetWaitInterval(&nIntervalSeconds);
|
||
|
while (! bDone && !rc)
|
||
|
{
|
||
|
if ( WAIT_OBJECT_0 == WaitForSingleObject(hFind,nIntervalSeconds * 1000 ) )
|
||
|
{
|
||
|
LookForResults(logdir);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
LookForResults(logdir);
|
||
|
}
|
||
|
if ( ! FindNextChangeNotification(hFind) )
|
||
|
{
|
||
|
rc = GetLastError();
|
||
|
}
|
||
|
gData.GetDone(&bDone);
|
||
|
gData.GetWaitInterval(&nIntervalSeconds);
|
||
|
}
|
||
|
|
||
|
FindCloseChangeNotification(hFind);
|
||
|
}
|
||
|
|
||
|
|
||
|
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->IsFinished() )
|
||
|
nFinished++;
|
||
|
if ( s->HasFailed() )
|
||
|
nError++;
|
||
|
|
||
|
|
||
|
// Check jobs that were running but not finished
|
||
|
if ( *s->GetJobFile() && s->IsRunning() )
|
||
|
{
|
||
|
nRunning++;
|
||
|
// 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 )
|
||
|
{
|
||
|
// found something
|
||
|
gData.Lock();
|
||
|
if ( ! s->IsFinished() )
|
||
|
{
|
||
|
gData.Unlock();
|
||
|
ProcessResults(s,logdir,fdata.cFileName);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gData.Unlock();
|
||
|
}
|
||
|
nRunning--;
|
||
|
nFinished++;
|
||
|
FindClose(hFind);
|
||
|
}
|
||
|
gData.GetListWindow(&gListWnd);
|
||
|
// SendMessage(gListWnd,DCT_UPDATE_ENTRY,NULL,(long)s);
|
||
|
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,(long)&stat);
|
||
|
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 = NULL;
|
||
|
|
||
|
// Try to create the COM objects
|
||
|
hr = pVarSet.CreateInstance(CLSID_VarSet);
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
|
||
|
// Read the VarSet from the data file
|
||
|
int tries = 0;
|
||
|
do
|
||
|
{
|
||
|
tries++;
|
||
|
hr = StgOpenStorage(path,NULL,STGM_DIRECT | STGM_READ | STGM_SHARE_EXCLUSIVE,NULL,0,&store);
|
||
|
if ( SUCCEEDED(hr) )
|
||
|
{
|
||
|
// Load the data into a new varset
|
||
|
hr = OleLoad(store,IID_IUnknown,NULL,(void **)&pVarSet);
|
||
|
}
|
||
|
if ( tries > 2 )
|
||
|
break;
|
||
|
Sleep(500);
|
||
|
} while ( hr == STG_E_SHAREVIOLATION || hr == STG_E_LOCKVIOLATION );
|
||
|
|
||
|
}
|
||
|
|
||
|
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));
|
||
|
|
||
|
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);
|
||
|
|
||
|
pServer->SetLogPath(logPath);
|
||
|
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());
|
||
|
|
||
|
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;
|
||
|
|
||
|
|
||
|
//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));
|
||
|
}
|
||
|
|
||
|
typeString.FormatMessage(IDS_OwnerRef_S,type);
|
||
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nOwner,typeString.AllocSysString());
|
||
|
|
||
|
typeString.FormatMessage(IDS_GroupRef_S,type);
|
||
|
rc = pDB->raw_AddAcctRef(domPart,acctPart,acctSid,pServer->GetServer(),nGroup,typeString.AllocSysString());
|
||
|
|
||
|
//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());
|
||
|
|
||
|
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) )
|
||
|
{
|
||
|
pServer->SetFinished();
|
||
|
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
|
||
|
ProcessSecRefs(pServer,directory,filename);
|
||
|
}
|
||
|
}
|