예제 #1
0
int
Job::declare_file(const MyString &name,
                  filesize_t size,
				  CondorError &errstack)
{
	JobFile *ignored;
	JobFile jobFile;
	jobFile.size = size;
	jobFile.currentOffset = 0;

	jobFile.name = name;

	jobFile.file =
		safe_open_wrapper_follow((spoolDirectory + DIR_DELIM_STRING + jobFile.name).Value(),
			 O_WRONLY | O_CREAT | _O_BINARY,
			 0600);
	if (-1 != jobFile.file) {
		if (0 == declaredFiles.lookup(name, ignored)) {
			close(jobFile.file);
			errstack.pushf("SOAP",
						   ALREADYEXISTS,
						   "File '%s' already declared.",
						   name.Value());

			return 4;
		}

		if (declaredFiles.insert(name, jobFile)) {
			close(jobFile.file);
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to record file '%s'.",
						   name.Value());

			return 2;
		}
	} else {
			// If there is a path delimiter in the name we assume that
			// the client knows what she is doing and will set a
			// proper Iwd later on. If there is no path delimiter we
			// have a problem.
		if (-1 != name.FindChar(DIR_DELIM_CHAR)) {
			dprintf(D_FULLDEBUG,
					"Failed to open '%s' for writing, reason: %s\n",
					(spoolDirectory+DIR_DELIM_STRING+jobFile.name).Value(),
					strerror(errno));

			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to open '%s' for writing, reason: %s",
						   name.Value(),
						   strerror(errno));

			return 3;
		}
	}

	return 0;
}
예제 #2
0
int
Job::get_file(const MyString &name,
              int offset,
              int length,
              unsigned char *&data,
			  CondorError &errstack)
{
	memset(data, 0, length);
	int file = safe_open_wrapper_follow((spoolDirectory + DIR_DELIM_STRING + name).Value(),
					O_RDONLY | _O_BINARY,
					0);

	if (-1 != file) {
		if (-1 == lseek(file, offset, SEEK_SET)) {
			close(file);
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to lseek in file '%s', reason: %s",
						   name.Value(),
						   strerror(errno));

			return 2;
		}
		int result;
		if (-1 == 
			(result = full_read(file, data, sizeof(unsigned char) * length))) {
			close(file);
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to read from file '%s', wanted to "
						   "read %d bytes but received %d",
						   name.Value(),
						   length,
						   result);

			return 3;
		}
		if (-1 == close(file)) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to close file '%s', reason: %s",
						   name.Value(),
						   strerror(errno));

			return 4;
		}
	} else {
		errstack.pushf("SOAP",
					   FAIL,
					   "Failed to open file '%s', reason: %s",
					   name.Value(),
					   strerror(errno));

		return 1;
	}

	return 0;
}
예제 #3
0
int
Job::put_file(const MyString &name,
			  int offset,
			  char * data,
			  int data_length,
			  CondorError &errstack)
{
	JobFile jobFile;
	if (-1 == declaredFiles.lookup(name, jobFile)) {
		errstack.pushf("SOAP",
					   FAIL,
					   "File '%s' has not been declared.",
					   name.Value());

		return 1;
	}

	if (-1 != jobFile.file) {
		if (-1 == lseek(jobFile.file, offset, SEEK_SET)) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to lseek in file '%s', reason: %s",
						   name.Value(),
						   strerror(errno));

			return 2;
		}
		int result;
		if (data_length !=
			(result = full_write(jobFile.file, data, data_length))) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to write to from file '%s', wanted to write %d bytes but was only able to write %d",
						   name.Value(),
						   data_length,
						   result);

			return 3;
		}
	} else {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to open file '%s', it should not "
						   "contain any path separators.",
						   name.Value());

		return 5;
	}

	return 0;
}
예제 #4
0
///////////////////////////////////////////////////////////////////////////////
// Note: on Unix/Linux, the file ID is a string encoding the combination of
// device number and inode; on Windows the file ID is simply the value
// _fullpath() returns on the path we're given.  The Unix/Linux version
// is preferable because it will work correctly even if there are hard
// links to log files; but there are no inodes on Windows, so we're
// doing what we can.
bool
GetFileID( const MyString &filename, MyString &fileID,
			CondorError &errstack )
{

		// Make sure the log file exists.  Even though we may later call
		// InitializeFile(), we have to make sure the file exists here
		// first so we make sure that the file exists and we can therefore
		// get an inode or real path for it.
		// We *don't* want to truncate the file here, though, because
		// we don't know for sure whether it's the first time we're seeing
		// it.
	if ( access( filename.Value(), F_OK ) != 0 ) {
		if ( !MultiLogFiles::InitializeFile( filename.Value(),
					false, errstack ) ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error initializing log file %s", filename.Value() );
			return false;
		}
	}

#ifdef WIN32
	char *tmpRealPath = realpath( filename.Value(), NULL );
	if ( !tmpRealPath ) {
		errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error (%d, %s) getting real path for specified path %s",
					errno, strerror( errno ), filename.Value() );
		return false;
	}

	fileID = tmpRealPath;
	free( tmpRealPath );
#else
	StatWrapper swrap;
	if ( swrap.Stat( filename.Value() ) != 0 ) {
		errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error getting inode for log file %s",
					filename.Value() );
		return false;
	}
	fileID.formatstr( "%llu:%llu", (unsigned long long)swrap.GetBuf()->st_dev,
				(unsigned long long)swrap.GetBuf()->st_ino );
#endif

	return true;
}
예제 #5
0
bool
ODSHistoryFile::init(CondorError &errstack)
{
	StatWrapper stat_wrapper;

	if (stat_wrapper.Stat(m_name.c_str())) {
		errstack.pushf("ODSHistoryFile::init", 1,
					   "Failed to stat %s: %d (%s)\n",
					   m_name.c_str(),
					   stat_wrapper.GetErrno(),
					   strerror(stat_wrapper.GetErrno()));
		return false;
	}

	m_stat = (StatStructType *) malloc(sizeof(StatStructType));
	ASSERT(m_stat);
	memcpy(m_stat, stat_wrapper.GetBuf(), sizeof(StatStructType));
	if (!S_ISREG(m_stat->st_mode)) {
		errstack.pushf("ODSHistoryFile::init", 2,
					   "%s: not a regular file\n",
					   m_name.c_str());
		return false;
	}

	m_file = safe_fopen_wrapper(m_name.c_str(), "r");
	if (NULL == m_file) {
		errstack.pushf("ODSHistoryFile::init", 4,
					   "Failed to fopen %s: %d (%s)\n",
					   m_name.c_str(), errno, strerror(errno));
		return false;
	}
	
	m_writer = new ODSMongodbOps(DB_NAME);
    if (!m_writer->init("localhost")) {
        errstack.pushf("ODSHistoryFile::init", 5,
                       "Unable to init ODS writer\n");
        return false;
    }

	return true;
}
예제 #6
0
int
Job::get_spool_list(List<FileInfo> &file_list,
					CondorError &errstack)
{
	StatInfo directoryInfo(spoolDirectory.Value());
	if (directoryInfo.IsDirectory()) {
		Directory directory(spoolDirectory.Value());
		const char * name;
		FileInfo *info;
		while (NULL != (name = directory.Next())) {
			info = new FileInfo();
			info->initialize(name, directory.GetFileSize());
			ASSERT(info);

			if (!file_list.Append(info)) {
				errstack.pushf("SOAP",
							   FAIL,
							   "Error adding %s to file list.",
							   name);

				return 2;
			}
		}

		return 0;
	} else {
		dprintf(D_ALWAYS, "spoolDirectory == '%s'\n",
				spoolDirectory.Value());

		errstack.pushf("SOAP",
					   FAIL,
					   "spool directory '%s' is not actually a directory.",
					   spoolDirectory.Value());

		return 1;
	}
}
예제 #7
0
bool
MultiLogFiles::InitializeFile(const char *filename, bool truncate,
			CondorError &errstack)
{
	dprintf( D_LOG_FILES, "MultiLogFiles::InitializeFile(%s, %d)\n",
				filename, (int)truncate );

	int flags = O_WRONLY;
	if ( truncate ) {
		flags |= O_TRUNC;
		dprintf( D_ALWAYS, "MultiLogFiles: truncating log file %s\n",
					filename );
	}

		// Two-phase attempt at open here is to make things work if
		// a log file is a symlink to another file (see gittrac #2704).
	int fd = safe_create_fail_if_exists( filename, flags );
	if ( fd < 0 && errno == EEXIST ) {
		fd = safe_open_no_create_follow( filename, flags );
	}
	if ( fd < 0 ) {
		errstack.pushf("MultiLogFiles", UTIL_ERR_OPEN_FILE,
					"Error (%d, %s) opening file %s for creation "
					"or truncation", errno, strerror( errno ), filename );
		return false;
	}

	if ( close( fd ) != 0 ) {
		errstack.pushf("MultiLogFiles", UTIL_ERR_CLOSE_FILE,
					"Error (%d, %s) closing file %s for creation "
					"or truncation", errno, strerror( errno ), filename );
		return false;
	}

	return true;
}
예제 #8
0
bool
MultiLogFiles::makePathAbsolute(MyString &filename, CondorError &errstack)
{
	if ( !fullpath(filename.Value()) ) {
			// I'd like to use realpath() here, but I'm not sure
			// if that's portable across all platforms.  wenger 2009-01-09.
		MyString	currentDir;
		if ( !condor_getcwd(currentDir) ) {
			errstack.pushf( "MultiLogFiles", UTIL_ERR_GET_CWD,
						"ERROR: condor_getcwd() failed with errno %d (%s) at %s:%d",
						errno, strerror(errno), __FILE__, __LINE__);
			return false;
		}

		filename = currentDir + DIR_DELIM_STRING + filename;
	}

	return true;
}
예제 #9
0
//---------------------------------------------------------------------------
bool
Job::UnmonitorLogFile( ReadMultipleUserLogs &condorLogReader,
			ReadMultipleUserLogs &storkLogReader )
{
	debug_printf( DEBUG_DEBUG_2, "Unmonitoring log file <%s> for node %s\n",
				GetLogFile(), GetJobName() );

	if ( !_logIsMonitored ) {
		debug_printf( DEBUG_DEBUG_1, "Warning: log file for node "
					"%s is already unmonitored\n", GetJobName() );
		return true;
	}

	ReadMultipleUserLogs &logReader = (_jobType == TYPE_CONDOR) ?
				condorLogReader : storkLogReader;

	debug_printf( DEBUG_DEBUG_1, "Unmonitoring log file <%s> for node %s\n",
				GetLogFile(), GetJobName() );

	CondorError errstack;
	bool result = logReader.unmonitorLogFile( GetLogFile(), errstack );
	if ( !result ) {
		errstack.pushf( "DAGMan::Job", DAGMAN_ERR_LOG_FILE,
					"ERROR: Unable to unmonitor log " "file for node %s",
					GetJobName() );
		debug_printf( DEBUG_QUIET, "%s\n", errstack.getFullText().c_str() );
		EXCEPT( "Fatal log file monitoring error!\n" );
	}

	if ( result ) {
		delete [] _logFile;
		_logFile = NULL;
		_logIsMonitored = false;
	}

	return result;
}
예제 #10
0
int
Job::initialize(CondorError &errstack)
{
	char * Spool = param("SPOOL");
	ASSERT(Spool);

	char *ckpt_name = gen_ckpt_name(Spool, id.cluster, id.proc, 0);
	spoolDirectory = ckpt_name;
	free(ckpt_name); ckpt_name = NULL;

	if (Spool) {
		free(Spool);
		Spool = NULL;
	}

	struct stat stats;
	if (-1 == stat(spoolDirectory.Value(), &stats)) {
		if (ENOENT == errno && spoolDirectory.Length() != 0) {

				// We assume here that the job is not a standard universe
				// job.  Spooling works differently for standard universe.
				// Unfortunately, we might not know the job universe
				// yet, so standard universe is problematic with SOAP
				// (and always has been).

			if( !SpooledJobFiles::createJobSpoolDirectory_PRIV_CONDOR(id.cluster,id.proc,false) ) {
				errstack.pushf("SOAP",
							   FAIL,
							   "Creation of spool directory '%s' failed, "
							   "reason: %s",
							   spoolDirectory.Value(),
							   strerror(errno));
				return 1;
			} else {
				dprintf(D_FULLDEBUG,
						"mkdir(%s) succeeded.\n",
						spoolDirectory.Value());
			}
		} else {
			dprintf(D_FULLDEBUG, "ERROR: stat(%s) errno: %d (%s)\n",
					spoolDirectory.Value(),
					errno,
					strerror(errno));

			errstack.pushf("SOAP",
						   FAIL,
						   "stat(%s) failed, reason: %s",
						   spoolDirectory.Value(),
						   strerror(errno));

			return 2;
		}
	} else {
		dprintf(D_FULLDEBUG,
				"WARNING: Job '%d.%d''s spool '%s' already exists.\n",
				id.cluster,
				id.proc,
				spoolDirectory.Value());
	}

	return 0;
}
예제 #11
0
int
Job::get_file(const MyString &name,
              int offset,
              int length,
              unsigned char *&data,
			  CondorError &errstack)
{
#if !defined(WIN32)
	TemporaryPrivSentry sentry( true );
	if ( param_boolean( "CHOWN_JOB_SPOOL_FILES", false ) == false ) {
		ClassAd *job_ad = GetJobAd_as_ClassAd( id.cluster, id.proc );
		if ( job_ad == NULL ) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to retrieve job ad for file '%s'",
						   name.Value());
			return 5;
		}
		if ( !init_user_ids_from_ad( *job_ad ) ) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to init user ids for file '%s'",
						   name.Value());
			return 6;
		}
		set_user_priv();
	}
#endif
	int file = safe_open_wrapper_follow((spoolDirectory + DIR_DELIM_STRING + name).Value(),
					O_RDONLY | _O_BINARY,
					0);

	if (-1 != file) {
		if (-1 == lseek(file, offset, SEEK_SET)) {
			close(file);
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to lseek in file '%s', reason: %s",
						   name.Value(),
						   strerror(errno));

			return 2;
		}
		int result;
		if (-1 == 
			(result = full_read(file, data, sizeof(unsigned char) * length))) {
			close(file);
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to read from file '%s', wanted to "
						   "read %d bytes but received %d",
						   name.Value(),
						   length,
						   result);

			return 3;
		}
		if (-1 == close(file)) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to close file '%s', reason: %s",
						   name.Value(),
						   strerror(errno));

			return 4;
		}
	} else {
		errstack.pushf("SOAP",
					   FAIL,
					   "Failed to open file '%s', reason: %s",
					   name.Value(),
					   strerror(errno));

		return 1;
	}

	return 0;
}
예제 #12
0
int
Job::submit(const struct condor__ClassAdStruct &jobAd,
			CondorError &errstack)
{
	int i, rval;

		// XXX: This is ugly, and only should happen when spooling,
		// i.e. not always with cedar.
	rval = SetAttributeString(id.cluster,
							  id.proc,
							  ATTR_JOB_IWD,
							  spoolDirectory.Value());
	if (rval < 0) {
		errstack.pushf("SOAP",
					   FAIL,
					   "Failed to set job %d.%d's %s attribute to '%s'.",
					   id.cluster,
					   id.proc,
					   ATTR_JOB_IWD,
					   spoolDirectory.Value());

		return rval;
	}

	StringList transferFiles;
	MyString currentKey;
	JobFile jobFile;
	declaredFiles.startIterations();
	while (declaredFiles.iterate(currentKey, jobFile)) {
		transferFiles.append(jobFile.name.Value());
	}

	char *fileList = NULL;
	if (0 == transferFiles.number()) {
		fileList = strdup("");
	} else {
		fileList = transferFiles.print_to_string();
		ASSERT(fileList);
	}

	rval = SetAttributeString(id.cluster,
							  id.proc,
							  ATTR_TRANSFER_INPUT_FILES,
							  fileList);

	if (fileList) {
		free(fileList);
		fileList = NULL;
	}

	if (rval < 0) {
		errstack.pushf("SOAP",
					   FAIL,
					   "Failed to set job %d.%d's %s attribute.",
					   id.cluster,
					   id.proc,
					   ATTR_TRANSFER_INPUT_FILES);

		return rval;
	}

	int found_iwd = 0;
	for (i = 0; i < jobAd.__size; i++) {
		const char* name = jobAd.__ptr[i].name;
		const char* value = jobAd.__ptr[i].value;
		if (!name) continue;
		if (!value) value="UNDEFINED";

			// XXX: This is a quick fix. If processing MyType or
			// TargetType they should be ignored. Ideally we could
			// convert the ClassAdStruct to a ClassAd and then iterate
			// the ClassAd.
		if (0 == strcmp(name, ATTR_MY_TYPE) ||
			0 == strcmp(name, ATTR_TARGET_TYPE)) {
			continue;
		}

		if ( jobAd.__ptr[i].type == STRING_ATTR ) {
				// string type - put value in quotes as hint for ClassAd parser

			found_iwd = found_iwd || !strcmp(name, ATTR_JOB_IWD);

			rval = SetAttributeString(id.cluster, id.proc, name, value);
		} else {
				// all other types can be deduced by the ClassAd parser
			rval = SetAttribute(id.cluster, id.proc, name, value);
		}
		if ( rval < 0 ) {
		errstack.pushf("SOAP",
					   FAIL,
					   "Failed to set job %d.%d's %s attribute.",
					   id.cluster,
					   id.proc,
					   name);

			return rval;
		}
	}

		// Trust the client knows what it is doing if there is an Iwd.
	if (!found_iwd) {
			// We need to make sure the Iwd is rewritten so files
			// in the spool directory can be found.
		rval = SetAttributeString(id.cluster,
								  id.proc,
								  ATTR_JOB_IWD,
								  spoolDirectory.Value());
		if (rval < 0) {
			errstack.pushf("SOAP",
						   FAIL,
						   "Failed to set %d.%d's %s attribute to '%s'.",
						   id.cluster,
						   id.proc,
						   ATTR_JOB_IWD,
						   spoolDirectory.Value());

			return rval;
		}
	}

	return 0;
}
예제 #13
0
//---------------------------------------------------------------------------
bool
Job::MonitorLogFile( ReadMultipleUserLogs &condorLogReader,
			ReadMultipleUserLogs &storkLogReader, bool nfsIsError,
			bool recovery, const char *defaultNodeLog, bool usingDefault )
{
	debug_printf( DEBUG_DEBUG_2,
				"Attempting to monitor log file for node %s\n",
				GetJobName() );

	if ( _logIsMonitored ) {
		debug_printf( DEBUG_DEBUG_1, "Warning: log file for node "
					"%s is already monitored\n", GetJobName() );
		return true;
	}

	ReadMultipleUserLogs &logReader = (_jobType == TYPE_CONDOR) ?
				condorLogReader : storkLogReader;

    std::string logFileStr;
	if ( _jobType == TYPE_CONDOR ) {
			// We check to see if the user has specified a log file
			// If not, we give him a default
    	MyString templogFileStr = MultiLogFiles::loadLogFileNameFromSubFile( _cmdFile,
					_directory, _logFileIsXml, usingDefault);
		logFileStr = templogFileStr.Value();
	} else {
		StringList logFiles;
		MyString tmpResult = MultiLogFiles::loadLogFileNamesFromStorkSubFile(
					_cmdFile, _directory, logFiles );
		if ( tmpResult != "" ) {
			debug_printf( DEBUG_QUIET, "Error getting Stork log file: %s\n",
						tmpResult.Value() );
			LogMonitorFailed();
			return false;
		} else if ( logFiles.number() != 1 ) {
			debug_printf( DEBUG_QUIET, "Error: %d Stork log files found "
						"in submit file %s; we want 1\n",
						logFiles.number(), _cmdFile );
			LogMonitorFailed();
			return false;
		} else {
			logFiles.rewind();
			logFileStr = logFiles.next();
		}
	}

		// Warn the user if the node's log file is in /tmp.
	if ( logFileStr.find( "/tmp" ) == 0 ) {
		debug_printf( DEBUG_QUIET, "Warning: "
					"Log file %s for node %s is in /tmp\n",
					logFileStr.c_str(), GetJobName() );
        check_warning_strictness( usingDefault ? DAG_STRICT_2 : DAG_STRICT_1 );
	}

	if ( logFileStr == "" ) {
		logFileStr = defaultNodeLog;
		_useDefaultLog = true;
			// Default User log is never XML
			// This could be specified in the submit file and should be
			// ignored.
		_logFileIsXml = false;
		debug_printf( DEBUG_NORMAL, "Unable to get log file from "
					"submit file %s (node %s); using default (%s)\n",
					_cmdFile, GetJobName(), logFileStr.c_str() );
		append_default_log = false;
	} else {
		append_default_log = usingDefault;
		if( append_default_log ) {
				// DAGman is not going to look at the user-specified log.
				// It will look at the defaultNode log.
			logFileStr = defaultNodeLog;
			_useDefaultLog = false;
			_logFileIsXml = false;
		}
	}

		// This function returns true if the log file is on NFS and
		// that is an error.  If the log file is on NFS, but nfsIsError
		// is false, it prints a warning but returns false.
	if ( MultiLogFiles::logFileNFSError( logFileStr.c_str(),
				nfsIsError ) ) {
		debug_printf( DEBUG_QUIET, "Error: log file %s on NFS\n",
					logFileStr.c_str() );
		LogMonitorFailed();
		return false;
	}

	delete [] _logFile;
		// Saving log file here in case submit file gets changed.
	_logFile = strnewp( logFileStr.c_str() );
	debug_printf( DEBUG_DEBUG_2, "Monitoring log file <%s> for node %s\n",
				GetLogFile(), GetJobName() );
	CondorError errstack;
	if ( !logReader.monitorLogFile( GetLogFile(), !recovery, errstack ) ) {
		errstack.pushf( "DAGMan::Job", DAGMAN_ERR_LOG_FILE,
					"ERROR: Unable to monitor log file for node %s",
					GetJobName() );
		debug_printf( DEBUG_QUIET, "%s\n", errstack.getFullText().c_str() );
		LogMonitorFailed();
		EXCEPT( "Fatal log file monitoring error!\n" );
		return false;
	}

	_logIsMonitored = true;

	return true;
}
예제 #14
0
// Note: logfile is not passed as a reference because we need a local
// copy to modify anyhow.
bool
ReadMultipleUserLogs::monitorLogFile( MyString logfile,
			bool truncateIfFirst, CondorError &errstack )
{
	dprintf( D_LOG_FILES, "ReadMultipleUserLogs::monitorLogFile(%s, %d)\n",
				logfile.Value(), truncateIfFirst );

	MyString fileID;
	if ( !GetFileID( logfile, fileID, errstack ) ) {
		errstack.push( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error getting file ID in monitorLogFile()" );
		return false;
	}

	LogFileMonitor *monitor;
	if ( allLogFiles.lookup( fileID, monitor ) == 0 ) {
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: found "
					"LogFileMonitor object for %s (%s)\n",
					logfile.Value(), fileID.Value() );

	} else {
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: didn't "
					"find LogFileMonitor object for %s (%s)\n",
					logfile.Value(), fileID.Value() );

			// Make sure the log file is in the correct state -- it must
			// exist, and be truncated if necessary.
		if ( !MultiLogFiles::InitializeFile( logfile.Value(),
					truncateIfFirst, errstack ) ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error initializing log file %s", logfile.Value() );
			return false;
		}

		monitor = new LogFileMonitor( logfile );
		ASSERT( monitor );
		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: created LogFileMonitor "
					"object for log file %s\n", logfile.Value() );
			// Note: we're only putting a pointer to the LogFileMonitor
			// object into the hash table; the actual LogFileMonitor should
			// only be deleted in this object's destructor.
		if ( allLogFiles.insert( fileID, monitor ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error inserting %s into allLogFiles",
						logfile.Value() );
			delete monitor;
			return false;
		}
	}

	if ( monitor->refCount < 1 ) {
			// Open the log file (return to previous location if it was
			// opened before).
	
		if ( monitor->state ) {
				// If we get here, we've monitored this log file before,
				// so restore the previous state.
			if ( monitor->stateError ) {
				errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
							"Monitoring log file %s fails because of "
							"previous error saving file state",
							logfile.Value() );
				return false;
			}

			monitor->readUserLog = new ReadUserLog( *(monitor->state) );
		} else {
				// Monitoring this log file for the first time, so create
				// the log reader from scratch.
			monitor->readUserLog =
						new ReadUserLog( monitor->logFile.Value() );
		}

		if ( activeLogFiles.insert( fileID, monitor ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error inserting %s (%s) into activeLogFiles",
						logfile.Value(), fileID.Value() );
			return false;
		} else {
			dprintf( D_LOG_FILES, "ReadMultipleUserLogs: added log "
						"file %s (%s) to active list\n", logfile.Value(),
						fileID.Value() );
		}
	}

	monitor->refCount++;
	
	return true;
}
예제 #15
0
// Note: logfile is not passed as a reference because we need a local
// copy to modify anyhow.
bool
ReadMultipleUserLogs::unmonitorLogFile( MyString logfile,
			CondorError &errstack )
{
	dprintf( D_LOG_FILES, "ReadMultipleUserLogs::unmonitorLogFile(%s)\n",
				logfile.Value() );

	MyString fileID;
	if ( !GetFileID( logfile, fileID, errstack ) ) {
		errstack.push( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Error getting file ID in unmonitorLogFile()" );
		return false;
	}

	LogFileMonitor *monitor;
	if ( activeLogFiles.lookup( fileID, monitor ) != 0 ) {
		errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
					"Didn't find LogFileMonitor object for log "
					"file %s (%s)!", logfile.Value(),
					fileID.Value() );
		dprintf( D_ALWAYS, "ReadMultipleUserLogs error: %s\n",
					errstack.message() );
		printAllLogMonitors( NULL );
		return false;
	}

	dprintf( D_LOG_FILES, "ReadMultipleUserLogs: found "
				"LogFileMonitor object for %s (%s)\n",
				logfile.Value(), fileID.Value() );

	monitor->refCount--;

	if ( monitor->refCount < 1 ) {
			// Okay, if we are no longer monitoring this file at all,
			// we need to close it.  We do that by saving its state
			// into a ReadUserLog::FileState object (so we can go back
			// to the right place if we later monitor it again) and
			// then deleting the ReadUserLog object.
		dprintf( D_LOG_FILES, "Closing file <%s>\n", logfile.Value() );

		if ( !monitor->state ) {
			monitor->state = new ReadUserLog::FileState();
			if ( !ReadUserLog::InitFileState( *(monitor->state) ) ) {
				errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
							"Unable to initialize ReadUserLog::FileState "
							"object for log file %s", logfile.Value() );
				monitor->stateError = true;
				delete monitor->state;
				monitor->state = NULL;
				return false;
			}
		}

		if ( !monitor->readUserLog->GetFileState( *(monitor->state) ) ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error getting state for log file %s",
						logfile.Value() );
			monitor->stateError = true;
			delete monitor->state;
			monitor->state = NULL;
			return false;
		}

		delete monitor->readUserLog;
		monitor->readUserLog = NULL;

			// Now we remove this file from the "active" list, so
			// we don't check it the next time we get an event.
		if ( activeLogFiles.remove( fileID ) != 0 ) {
			errstack.pushf( "ReadMultipleUserLogs", UTIL_ERR_LOG_FILE,
						"Error removing %s (%s) from activeLogFiles",
						logfile.Value(), fileID.Value() );
			dprintf( D_ALWAYS, "ReadMultipleUserLogs error: %s\n",
						errstack.message() );
			printAllLogMonitors( NULL );
			return false;
		}

		dprintf( D_LOG_FILES, "ReadMultipleUserLogs: removed "
					"log file %s (%s) from active list\n",
					logfile.Value(), fileID.Value() );
	}

	return true;
}