Beispiel #1
0
void
email_corefile_tail( FILE* output, const char * subsystem_name )
{
#ifdef WIN32
	char *ptmp;
	FILE *input;
	int ch;
	long loc = -1;

	ptmp = param("LOG");
	if ( ptmp ) {
		char file[MAX_PATH];
		sprintf(file,"%s\\core.%s.WIN32",ptmp,
			subsystem_name);
		free(ptmp);
		if( (input=safe_fopen_wrapper_follow(file,"r",0644)) == NULL ) {
			dprintf( D_FULLDEBUG, 
				"Failed to email %s: cannot open file\n", file );
			return;
		}

		/* This is slow, but who cares.  Basically, each "core" entry
		** begins with a '=' character.  So we scan through the file and
		** find the location of the last '=' ; this is the offset where 
		** we will start to email.  Thus we send only the most recent core.
		*/
		while( (ch=getc(input)) != EOF ) {
			if( ch == '=' ) {
				loc = ftell(input);
			}
		}

		/* Now send it */
		if ( loc != -1 ) {
			fprintf(output,"*** Last entry in core file %s\n\n",
				condor_basename(file));
			
			(void)fseek( input, loc, 0 );

			while( (ch=getc(input)) != EOF ) {
				(void)putc( ch, output );
			}

			fprintf(output,"*** End of file %s\n\n",
				condor_basename(file));
		}

		(void)fclose(input);
	}
#else
		// Shut the compiler up
	output = output;
	subsystem_name = subsystem_name;
#endif	// of ifdef WIN32
}
Beispiel #2
0
// check if a file was transferred.
// if so, fullname will have full path in working directory.
// Otherwise, fullname will be same to file_name
bool 
VMType::isTransferedFile(const char* file_name, MyString& fullname) 
{
	if( !file_name || m_initial_working_files.isEmpty() ) {
		return false;
	}

	// check if this file was transferred.
	MyString tmp_fullname;
	if( filelist_contains_file(file_name,
				&m_initial_working_files, true) ) {
		// this file was transferred.
		// make full path with workingdir
		tmp_fullname.formatstr("%s%c%s", m_workingpath.Value(), 
				DIR_DELIM_CHAR, condor_basename(file_name));
		fullname = tmp_fullname;
		return true;
	}else {
		// this file is not transferred
		if( fullpath(file_name) == false ) {
			vmprintf(D_ALWAYS, "Warning: The file(%s) doesn't have "
					"full path even though it is not "
					"transferred\n", file_name);
		}
		fullname = file_name;
		return false;
	}
	return false;
}
const char *
SharedPortEndpoint::deserialize(const char *inherit_buf)
{
	YourStringDeserializer in(inherit_buf);
	if ( ! in.deserialize_string(m_full_name, "*") || ! in.deserialize_sep("*") ) {
		EXCEPT("Failed to parse serialized shared-port information at offset %d: '%s'", (int)in.offset(), inherit_buf);
	}

	m_local_id = condor_basename(m_full_name.c_str());
	auto_free_ptr socket_dir(condor_dirname(m_full_name.c_str()));
	m_socket_dir = socket_dir.ptr();
#ifdef WIN32
	/*
	Deserializing requires getting the handles out of the buffer and getting the pid pipe name
	stored.  Registering the pipe is handled by StartListener().
	*/
	in.deserialize_int((LONG_PTR*)&pipe_end);
	in.deserialize_sep("*"); // note: terminator is missing from HTCondor prior to 8.5.7 so it is optional here...
	inherit_buf = in.next_pos();
#else
	inherit_buf = m_listener_sock.serialize(in.next_pos());
#endif
	m_listening = true;

	ASSERT( StartListener() );

	return inherit_buf;
}
Beispiel #4
0
//---------------------------------------------------------------------------
void
DagmanClassad::GetSetBatchName( const MyString &primaryDagFile,
			MyString &batchName )
{
	if ( !_valid ) {
		debug_printf( DEBUG_VERBOSE,
					"Skipping ClassAd query -- DagmanClassad object is invalid\n" );
		return;
	}

	Qmgr_connection *queue = OpenConnection();
	if ( !queue ) {
		return;
	}

	if ( !GetDagAttribute( ATTR_JOB_BATCH_NAME, batchName, false ) ) {
			// Default batch name is top-level DAG's primary
			// DAG file (base name only).
		batchName = condor_basename( primaryDagFile.Value() );
		batchName += "+";
		batchName += IntToStr( _dagmanId._cluster );
		SetDagAttribute( ATTR_JOB_BATCH_NAME, batchName );
	}

	CloseConnection( queue );

	debug_printf( DEBUG_VERBOSE, "Workflow batch-name: <%s>\n",
				batchName.Value() );
}
Beispiel #5
0
bool
privsep_enabled()
{
    static bool first_time = true;
    static bool answer;

    if (first_time) {

        first_time = false;

        if (is_root()) {
            answer = false;
        }
        else {
            answer = param_boolean("PRIVSEP_ENABLED", false);
        }

        if (answer) {
            switchboard_path = param("PRIVSEP_SWITCHBOARD");
            if (switchboard_path == NULL) {
                EXCEPT("PRIVSEP_ENABLED is true, but "
                       "PRIVSEP_SWITCHBOARD is undefined");
            }
            switchboard_file = condor_basename(switchboard_path);
        }
    }

    return answer;
}
Beispiel #6
0
void
run_preen()
{
	int		child_pid;
	char *args=NULL;
	const char	*preen_base;
	ArgList arglist;
	MyString error_msg;

	dprintf(D_FULLDEBUG, "Entered run_preen.\n");

	if( FS_Preen == NULL ) {
		return;
	}
	preen_base = condor_basename( FS_Preen );
	arglist.AppendArg(preen_base);

	args = param("PREEN_ARGS");
	if(!arglist.AppendArgsV1RawOrV2Quoted(args,&error_msg)) {
		EXCEPT("ERROR: failed to parse preen args: %s",error_msg.Value());
	}
	free(args);

	child_pid = daemonCore->Create_Process(
					FS_Preen,		// program to exec
					arglist,   		// args
					PRIV_ROOT,		// privledge level
					1,				// which reaper ID to use; use default reaper
					FALSE );		// we do _not_ want this process to have a command port; PREEN is not a daemon core process
	dprintf( D_ALWAYS, "Preen pid is %d\n", child_pid );
}
char *
SharedPortEndpoint::deserialize(char *inherit_buf)
{
	char *ptr;
	ptr = strchr(inherit_buf,'*');
	ASSERT( ptr );
	m_full_name.formatstr("%.*s",(int)(ptr-inherit_buf),inherit_buf);
	inherit_buf = ptr+1;

	m_local_id = condor_basename( m_full_name.Value() );
	char *socket_dir = condor_dirname( m_full_name.Value() );
	m_socket_dir = socket_dir;
	free( socket_dir );
#ifdef WIN32
	/*
	Deserializing requires getting the handles out of the buffer and getting the pid pipe name
	stored.  Registering the pipe is handled by StartListener().
	*/
	sscanf_s(inherit_buf, "%d", (int*)&pipe_end);

	//m_pipe_out = daemonCore->Inherit_Pipe_Handle(out_pipe, false, true, true, 4096);
#else
	inherit_buf = m_listener_sock.serialize(inherit_buf);
#endif
	m_listening = true;

	ASSERT( StartListener() );

	return inherit_buf;
}
Beispiel #8
0
void
usage( char *name )
{
	dprintf( D_ALWAYS, 
		"Usage: %s [-f] [-b] [-t] [-p <port>] [-s <schedd addr>] [-o <owern@uid-domain>] [-C <job constraint>] [-S <scratch dir>] [-A <aux id>]\n",
		condor_basename( name ) );
	DC_Exit( 1 );
}
Beispiel #9
0
StringList *NordugridJob::buildStageOutLocalList( StringList *stage_list )
{
	StringList *stage_local_list;
	char *remaps = NULL;
	MyString local_name;
	char *remote_name;
	std::string stdout_name = "";
	std::string stderr_name = "";
	std::string buff;
	std::string iwd = "/";

	if ( jobAd->LookupString( ATTR_JOB_IWD, iwd ) ) {
		if ( iwd.length() > 1 && iwd[iwd.length() - 1] != '/' ) {
			iwd += '/';
		}
	}

	jobAd->LookupString( ATTR_JOB_OUTPUT, stdout_name );
	jobAd->LookupString( ATTR_JOB_ERROR, stderr_name );

	stage_local_list = new StringList;

	jobAd->LookupString( ATTR_TRANSFER_OUTPUT_REMAPS, &remaps );

	stage_list->rewind();
	while ( (remote_name = stage_list->next()) ) {
			// stdout and stderr don't get remapped, and their paths
			// are evaluated locally
		if ( strcmp( REMOTE_STDOUT_NAME, remote_name ) == 0 ) {
			local_name = stdout_name.c_str();
		} else if ( strcmp( REMOTE_STDERR_NAME, remote_name ) == 0 ) {
			local_name = stderr_name.c_str();
		} else if( remaps && filename_remap_find( remaps, remote_name,
												  local_name ) ) {
				// file is remapped
		} else {
			local_name = condor_basename( remote_name );
		}

		if ( (local_name.Length() && local_name[0] == '/')
			 || IsUrl( local_name.Value() ) ) {
			buff = local_name;
		} else {
			formatstr( buff, "%s%s", iwd.c_str(), local_name.Value() );
		}
		stage_local_list->append( buff.c_str() );
	}

	if ( remaps ) {
		free( remaps );
	}

	return stage_local_list;
}
Beispiel #10
0
// This checks if filename is in the given file_list.
// If use_base is true, we will compare two files with basenames. 
bool
filelist_contains_file(const char *filename, StringList *file_list, bool use_base)
{
	if( !filename || !file_list ) {
		return false;
	}

	if( !use_base ) {
		return file_list->contains(filename);
	}

	file_list->rewind();
	char *tmp_file = NULL;
	while( (tmp_file = file_list->next()) != NULL ) {
		if( strcmp(condor_basename(filename), 
					condor_basename(tmp_file)) == MATCH ) {
			return true;
		}
	}
	return false;
}
Beispiel #11
0
void
email_asciifile_tail( FILE* output, const char* file, int lines )
{
	FILE	*input;
	int		ch, last_ch;
	long	loc;
	int		first_line = TRUE;
	TAIL_QUEUE	queue, *q = &queue;

	if( !file ) {
		return;
	}		

	if( (input=safe_fopen_wrapper_follow(file,"r",0644)) == NULL ) {
	    // try the .old file in the off shoot case we hit this during the transition.
	    std::string szTmp = file;
	    szTmp += ".old"; 
	    
	    if( (input=safe_fopen_wrapper_follow(szTmp.c_str(),"r",0644)) == NULL ) {
		dprintf( D_FULLDEBUG, "Failed to email %s: cannot open file\n", file );
		return;
	    }
	}

	init_queue( q, lines );
	last_ch = '\n';

	while( (ch=getc(input)) != EOF ) {
		if( last_ch == '\n' && ch != '\n' ) {
			insert_queue( q, ftell(input) - 1 );
		}
		last_ch = ch;
	}

	while( !empty_queue( q ) ) {
		loc = delete_queue( q );
		/* If this is the first line, print header */
		if ( first_line ) {
			first_line = FALSE;
			fprintf(output,"\n*** Last %d line(s) of file %s:\n",
				lines, file);
		}
		/* Now print the line */
		display_line( loc, input, output );
	}
	(void)fclose( input );

	/* if we printed any of the file, print a footer */
	if ( first_line == FALSE ) {
		fprintf(output,"*** End of file %s\n\n", condor_basename(file));
	}
}
Beispiel #12
0
// Returns true if the filename is a history file, false otherwise.
// If backup_time is not NULL, returns the time from the timestamp in
// the file.
static bool isHistoryBackup(const char *fullFilename, time_t *backup_time)
{
    bool       is_history_filename;
    const char *filename;
    const char *history_base;
    int        history_base_length;

    if (backup_time != NULL) {
        *backup_time = -1;
    }
    
    is_history_filename = false;
    history_base        = condor_basename(BaseJobHistoryFileName);
    history_base_length = strlen(history_base);
    filename            = condor_basename(fullFilename);

    if (   !strncmp(filename, history_base, history_base_length)
        && filename[history_base_length] == '.') {
        // The filename begins correctly, now see if it ends in an 
        // ISO time
        struct tm file_time;
        bool is_utc;

        iso8601_to_time(filename + history_base_length + 1, &file_time, &is_utc);
        if (   file_time.tm_year != -1 && file_time.tm_mon != -1 
            && file_time.tm_mday != -1 && file_time.tm_hour != -1
            && file_time.tm_min != -1  && file_time.tm_sec != -1
            && !is_utc) {
            // This appears to be a proper history file backup.
            is_history_filename = true;
            if (backup_time != NULL) {
                *backup_time = mktime(&file_time);
            }
        }
    }

    return is_history_filename;
}
Beispiel #13
0
int main(int argc, char **argv)
{
    config(); // Initialize param.
    const char * progname = condor_basename(argv[0]);
    if(progname[0] == 'v') {
        return vanilla2grid(argc,argv);
    } else if(progname[0] == 'g') {
        return grid2vanilla(argc,argv);
    } else {
        fprintf(stderr, "Program must be named vanilla2grid or grid2vanilla\n");
        return 1;
    }

}
Beispiel #14
0
static int attr_list_has_file( const char *attr, const char *path )
{
	char const *file;
	MyString str;

	file = condor_basename(path);

	Shadow->getJobAd()->LookupString(attr,str);
	StringList list(str.Value());

	if( list.contains_withwildcard(path) || list.contains_withwildcard(file) ) {
		return 1;
	} else {
		return 0;
	}
}
int
GLExecPrivSepHelper::run_script(ArgList& args,MyString &error_desc)
{
	if (!proxy_valid_right_now()) {
		dprintf(D_ALWAYS, "GLExecPrivSepHelper::run_script: not invoking glexec since the proxy is not valid!\n");
		error_desc += "The job proxy is not valid.";
		return INVALID_PROXY_RC;
	}

		/* Note that set_user_priv is a no-op if condor is running as
		   non-root (the "usual" mode for invoking glexec) */
	priv_state priv_saved = set_user_priv();
	FILE* fp = my_popen(args, "r", TRUE);
	set_priv(priv_saved);
	if (fp == NULL) {
		dprintf(D_ALWAYS,
		        "GLExecPrivSepHelper::run_script: "
		            "my_popen failure on %s: errno=%d (%s)\n",
		        args.GetArg(0),
			errno,
			strerror(errno));
		return -1;
	}
	MyString str;
	while (str.readLine(fp, true));

	priv_saved = set_user_priv();
	int ret = my_pclose(fp);
	set_priv(priv_saved);

	if (ret != 0) {
		str.trim();
		dprintf(D_ALWAYS,
		        "GLExecPrivSepHelper::run_script: %s exited "
		            "with status %d and following output:\n%s\n",
		        args.GetArg(0),
		        ret,
		        str.Value());
		error_desc.formatstr_cat("%s exited with status %d and the following output: %s",
				       condor_basename(args.GetArg(0)),
				       ret,
				       str.Value());
		error_desc.replaceString("\n","; ");
	}
	return ret;
}
Beispiel #16
0
int
main( int argc, char *argv[] )
{

	/**	Retrieve the program's name */
	name = condor_basename ( argv[0] );
	if ( !name ) {
		name = argv[0];
	}

	/**	Parse the command line and populate the global state */
	parse_command_line ( argc, argv );

	/**	Grab the user's input */
	serialize_input ();

	if ( ad ) {
		wake_machine ();
	}

	return 0;

}
Beispiel #17
0
bool
LocalUserLog::initFromJobAd( ClassAd* ad, const char* path_attr,
							 const char* xml_attr,
							 bool write_event_log )
{
	MyString tmp, dagmanLogFilename, logfilename;
	bool use_xml = false;
	const char* iwd = jic->jobIWD();
	int cluster = jic->jobCluster();
	int proc = jic->jobProc();
	int subproc = jic->jobSubproc();
	std::vector<const char*> logfiles;
	
	dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: path_attr = %s\n", path_attr);
	dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: xml_attr = %s\n", xml_attr);

		// Look for the "regular" user log file (e.g., UserLog or
		// StarterUserLog).
	if( ! ad->LookupString(path_attr, tmp) ) {
			// The fact that this attribute is not found in the ClassAd
			// indicates we do not want logging to a log file specified
			// in the submit file.
			// These semantics are defined in JICShadow::init.
			// We still need to check below for a DAGMan-specified
			// workflow log file for local universe!!
		dprintf( D_FULLDEBUG, "No %s found in job ClassAd\n", path_attr );

	} else {
		dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: tmp = %s\n",
			tmp.Value());
		if( fullpath (tmp.Value() ) ) {
				// we have a full pathname in the job ad.  however, if the
				// job is using a different iwd (namely, filetransfer is
				// being used), we want to just stick it in the local iwd
				// for the job, instead.
			if( jic->iwdIsChanged() ) {
				const char* base = condor_basename(tmp.Value());
				logfilename.formatstr( "%s/%s", iwd, base);
			} else {
				logfilename = tmp;
			}
		} else {
				// no full path, so, use the job's iwd...
			logfilename.formatstr( "%s/%s", iwd, tmp.Value());
		}
		logfiles.push_back( logfilename.Value());
	}

		// Look for the special workflow log file for DAGMan (local
		// universe only -- for other universes, the schedd or the
		// shadow will log to that file and trying to write it in
		// the starter will cause the starter to crash -- see
		// gittrac #5299).
	std::vector<ULogEventNumber> mask_vec;
	if ( jic->jobUniverse() == CONDOR_UNIVERSE_LOCAL &&
				ad->LookupString(ATTR_DAGMAN_WORKFLOW_LOG, tmp) ) {
		dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: %s is defined\n",
			ATTR_DAGMAN_WORKFLOW_LOG);
		dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: tmp = %s\n",
			tmp.Value());
		if( fullpath (tmp.Value() ) ) {
				// we have a full pathname in the job ad.  however, if the
				// job is using a different iwd (namely, filetransfer is
				// being used), we want to just stick it in the local iwd
				// for the job, instead.
			if( jic->iwdIsChanged() ) {
				const char* base = condor_basename(tmp.Value());
				dagmanLogFilename.formatstr( "%s/%s", iwd, base);
			} else {
				dagmanLogFilename = tmp;
			}
		} else {
				// no full path, so, use the job's iwd...
			dagmanLogFilename.formatstr( "%s/%s", iwd, tmp.Value());
		}
		logfiles.push_back( dagmanLogFilename.Value());
		MyString msk;
		if( ad->LookupString(ATTR_DAGMAN_WORKFLOW_MASK, msk) ) {
				// Check the mask of the DAGMan log
			dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: msk = %s\n",
				msk.Value());
			Tokenize(msk.Value());
			while(const char* mask = GetNextToken(",",true)) {
				dprintf( D_FULLDEBUG, "Adding \"%s\" to the mask\n",mask);
				mask_vec.push_back(ULogEventNumber(atoi(mask)));
			}
		}
	}

	if ( logfiles.empty() && write_event_log ) {
		char *global_log = param( "EVENT_LOG" );
		if ( global_log ) {
			logfiles.push_back( UNIX_NULL_FILE );
			free( global_log );
		}
	}

	if ( logfiles.empty() ) {
		return initNoLogging();
	}

	ad->LookupBool( xml_attr, use_xml );
	for(std::vector<const char*>::iterator p = logfiles.begin();
			p != logfiles.end(); ++p) {
		dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: UserLog "
			"file %s\n",*p);
	}
	bool ret = init( logfiles, use_xml, cluster, proc, subproc );
	if(ret) { 
		for(std::vector<ULogEventNumber>::iterator m = mask_vec.begin();
				m != mask_vec.end(); ++m) {
			u_log.AddToMask(*m);
		}
	}
	dprintf( D_FULLDEBUG, "LocalUserLog::initFromJobAd: returning %s\n",
		ret?"True":"False");
	return ret;
}
Beispiel #18
0
int
VanillaProc::StartJob()
{
	dprintf(D_FULLDEBUG,"in VanillaProc::StartJob()\n");

	// vanilla jobs, unlike standard jobs, are allowed to run 
	// shell scripts (or as is the case on NT, batch files).  so
	// edit the ad so we start up a shell, pass the executable as
	// an argument to the shell, if we are asked to run a .bat file.
#ifdef WIN32

	CHAR		interpreter[MAX_PATH+1],
				systemshell[MAX_PATH+1];    
	const char* jobtmp				= Starter->jic->origJobName();
	int			joblen				= strlen(jobtmp);
	const char	*extension			= joblen > 0 ? &(jobtmp[joblen-4]) : NULL;
	bool		binary_executable	= ( extension && 
										( MATCH == strcasecmp ( ".exe", extension ) || 
										  MATCH == strcasecmp ( ".com", extension ) ) ),
				java_universe		= ( CONDOR_UNIVERSE_JAVA == job_universe );
	ArgList		arguments;
	MyString	filename,
				jobname, 
				error;
	
	if ( extension && !java_universe && !binary_executable ) {

		/** since we do not actually know how long the extension of
			the file is, we'll need to hunt down the '.' in the path,
			if it exists */
		extension = strrchr ( jobtmp, '.' );

		if ( !extension ) {

			dprintf ( 
				D_ALWAYS, 
				"VanillaProc::StartJob(): Failed to extract "
				"the file's extension.\n" );

			/** don't fail here, since we want executables to run
				as usual.  That is, some condor jobs submit 
				executables that do not have the '.exe' extension,
				but are, nonetheless, executable binaries.  For
				instance, a submit script may contain:

				executable = executable$(OPSYS) */

		} else {

			/** pull out the path to the executable */
			if ( !JobAd->LookupString ( 
				ATTR_JOB_CMD, 
				jobname ) ) {
				
				/** fall back on Starter->jic->origJobName() */
				jobname = jobtmp;

			}

			/** If we transferred the job, it may have been
				renamed to condor_exec.exe even though it is
				not an executable. Here we rename it back to
				a the correct extension before it will run. */
			if ( MATCH == strcasecmp ( 
					CONDOR_EXEC, 
					condor_basename ( jobname.Value () ) ) ) {
				filename.formatstr ( "condor_exec%s", extension );
				if (rename(CONDOR_EXEC, filename.Value()) != 0) {
					dprintf (D_ALWAYS, "VanillaProc::StartJob(): ERROR: "
							"failed to rename executable from %s to %s\n", 
							CONDOR_EXEC, filename.Value() );
				}
			} else {
				filename = jobname;
			}
			
			/** Since we've renamed our executable, we need to
				update the job ad to reflect this change. */
			if ( !JobAd->Assign ( 
				ATTR_JOB_CMD, 
				filename ) ) {

				dprintf (
					D_ALWAYS,
					"VanillaProc::StartJob(): ERROR: failed to "
					"set new executable name.\n" );

				return FALSE;

			}

			/** We've moved the script to argv[1], so we need to 
				add	the remaining arguments to positions argv[2]..
				argv[/n/]. */
			if ( !arguments.AppendArgsFromClassAd ( JobAd, &error ) ||
				 !arguments.InsertArgsIntoClassAd ( JobAd, NULL, 
				&error ) ) {

				dprintf (
					D_ALWAYS,
					"VanillaProc::StartJob(): ERROR: failed to "
					"get arguments from job ad: %s\n",
					error.Value () );

				return FALSE;

			}

			/** Since we know already we don't want this file returned
				to us, we explicitly add it to an exception list which
				will stop the file transfer mechanism from considering
				it for transfer back to its submitter */
			Starter->jic->removeFromOutputFiles (
				filename.Value () );

		}
			
	}
#endif

	// set up a FamilyInfo structure to tell OsProc to register a family
	// with the ProcD in its call to DaemonCore::Create_Process
	//
	FamilyInfo fi;

	// take snapshots at no more than 15 seconds in between, by default
	//
	fi.max_snapshot_interval = param_integer("PID_SNAPSHOT_INTERVAL", 15);

	m_dedicated_account = Starter->jic->getExecuteAccountIsDedicated();
	if( ThisProcRunsAlongsideMainProc() ) {
			// If we track a secondary proc's family tree (such as
			// sshd) using the same dedicated account as the job's
			// family tree, we could end up killing the job when we
			// clean up the secondary family.
		m_dedicated_account = NULL;
	}
	if (m_dedicated_account) {
			// using login-based family tracking
		fi.login = m_dedicated_account;
			// The following message is documented in the manual as the
			// way to tell whether the dedicated execution account
			// configuration is being used.
		dprintf(D_ALWAYS,
		        "Tracking process family by login \"%s\"\n",
		        fi.login);
	}

	FilesystemRemap * fs_remap = NULL;
#if defined(LINUX)
	// on Linux, we also have the ability to track processes via
	// a phony supplementary group ID
	//
	gid_t tracking_gid = 0;
	if (param_boolean("USE_GID_PROCESS_TRACKING", false)) {
		if (!can_switch_ids() &&
		    (Starter->condorPrivSepHelper() == NULL))
		{
			EXCEPT("USE_GID_PROCESS_TRACKING enabled, but can't modify "
			           "the group list of our children unless running as "
			           "root or using PrivSep");
		}
		fi.group_ptr = &tracking_gid;
	}

	// Increase the OOM score of this process; the child will inherit it.
	// This way, the job will be heavily preferred to be killed over a normal process.
	// OOM score is currently exponential - a score of 4 is a factor-16 increase in
	// the OOM score.
	setupOOMScore(4,800);
#endif

#if defined(HAVE_EXT_LIBCGROUP)
	// Determine the cgroup
	std::string cgroup_base;
	param(cgroup_base, "BASE_CGROUP", "");
	MyString cgroup_str;
	const char *cgroup = NULL;
		/* Note on CONDOR_UNIVERSE_LOCAL - The cgroup setup code below
		 *  requires a unique name for the cgroup. It relies on
		 *  uniqueness of the MachineAd's Name
		 *  attribute. Unfortunately, in the local universe the
		 *  MachineAd (mach_ad elsewhere) is never populated, because
		 *  there is no machine. As a result the ASSERT on
		 *  starter_name fails. This means that the local universe
		 *  will not work on any machine that has BASE_CGROUP
		 *  configured. A potential workaround is to set
		 *  STARTER.BASE_CGROUP on any machine that is also running a
		 *  schedd, but that disables cgroup support from a
		 *  co-resident startd. Instead, I'm disabling cgroup support
		 *  from within the local universe until the intraction of
		 *  local universe and cgroups can be properly worked
		 *  out. -matt 7 nov '12
		 */
	if (CONDOR_UNIVERSE_LOCAL != job_universe && cgroup_base.length()) {
		MyString cgroup_uniq;
		std::string starter_name, execute_str;
		param(execute_str, "EXECUTE", "EXECUTE_UNKNOWN");
			// Note: Starter is a global variable from os_proc.cpp
		Starter->jic->machClassAd()->EvalString(ATTR_NAME, NULL, starter_name);
		if (starter_name.size() == 0) {
			char buf[16];
			sprintf(buf, "%d", getpid());
			starter_name = buf;
		}
		//ASSERT (starter_name.size());
		cgroup_uniq.formatstr("%s_%s", execute_str.c_str(), starter_name.c_str());
		const char dir_delim[2] = {DIR_DELIM_CHAR, '\0'};
		cgroup_uniq.replaceString(dir_delim, "_");
		cgroup_str.formatstr("%s%ccondor%s", cgroup_base.c_str(), DIR_DELIM_CHAR,
			cgroup_uniq.Value());
		cgroup_str += this->CgroupSuffix();
		
		cgroup = cgroup_str.Value();
		ASSERT (cgroup != NULL);
		fi.cgroup = cgroup;
		dprintf(D_FULLDEBUG, "Requesting cgroup %s for job.\n", cgroup);
	}

#endif

// The chroot stuff really only works on linux
#ifdef LINUX
	{
        // Have Condor manage a chroot
       std::string requested_chroot_name;
       JobAd->EvalString("RequestedChroot", NULL, requested_chroot_name);
       const char * allowed_root_dirs = param("NAMED_CHROOT");
       if (requested_chroot_name.size()) {
               dprintf(D_FULLDEBUG, "Checking for chroot: %s\n", requested_chroot_name.c_str());
               StringList chroot_list(allowed_root_dirs);
               chroot_list.rewind();
               const char * next_chroot;
               bool acceptable_chroot = false;
               std::string requested_chroot;
               while ( (next_chroot=chroot_list.next()) ) {
                       MyString chroot_spec(next_chroot);
                       chroot_spec.Tokenize();
                       const char * chroot_name = chroot_spec.GetNextToken("=", false);
                       if (chroot_name == NULL) {
                               dprintf(D_ALWAYS, "Invalid named chroot: %s\n", chroot_spec.Value());
                       }
                       const char * next_dir = chroot_spec.GetNextToken("=", false);
                       if (chroot_name == NULL) {
                               dprintf(D_ALWAYS, "Invalid named chroot: %s\n", chroot_spec.Value());
                       }
                       dprintf(D_FULLDEBUG, "Considering directory %s for chroot %s.\n", next_dir, chroot_spec.Value());
                       if (IsDirectory(next_dir) && chroot_name && (strcmp(requested_chroot_name.c_str(), chroot_name) == 0)) {
                               acceptable_chroot = true;
                               requested_chroot = next_dir;
                       }
               }
               // TODO: path to chroot MUST be all root-owned, or we have a nice security exploit.
               // Is this the responsibility of Condor to check, or the sysadmin who set it up?
               if (!acceptable_chroot) {
                       return FALSE;
               }
               dprintf(D_FULLDEBUG, "Will attempt to set the chroot to %s.\n", requested_chroot.c_str());

               std::stringstream ss;
               std::stringstream ss2;
               ss2 << Starter->GetExecuteDir() << DIR_DELIM_CHAR << "dir_" << getpid();
               std::string execute_dir = ss2.str();
               ss << requested_chroot << DIR_DELIM_CHAR << ss2.str();
               std::string full_dir_str = ss.str();
               if (is_trivial_rootdir(requested_chroot)) {
                   dprintf(D_FULLDEBUG, "Requested a trivial chroot %s; this is a no-op.\n", requested_chroot.c_str());
               } else if (IsDirectory(execute_dir.c_str())) {
                       {
                           TemporaryPrivSentry sentry(PRIV_ROOT);
                           if( mkdir(full_dir_str.c_str(), S_IRWXU) < 0 ) {
                               dprintf( D_FAILURE|D_ALWAYS,
                                   "Failed to create sandbox directory in chroot (%s): %s\n",
                                   full_dir_str.c_str(),
                                   strerror(errno) );
                               return FALSE;
                           }
                           if (chown(full_dir_str.c_str(),
                                     get_user_uid(),
                                     get_user_gid()) == -1)
                           {
                               EXCEPT("chown error on %s: %s",
                                      full_dir_str.c_str(),
                                      strerror(errno));
                           }
                       }
                       if (!fs_remap) {
                               fs_remap = new FilesystemRemap();
                       }
                       dprintf(D_FULLDEBUG, "Adding mapping: %s -> %s.\n", execute_dir.c_str(), full_dir_str.c_str());
                       if (fs_remap->AddMapping(execute_dir, full_dir_str)) {
                               // FilesystemRemap object prints out an error message for us.
                               return FALSE;
                       }
                       dprintf(D_FULLDEBUG, "Adding mapping %s -> %s.\n", requested_chroot.c_str(), "/");
                       std::string root_str("/");
                       if (fs_remap->AddMapping(requested_chroot, root_str)) {
                               return FALSE;
                       }
               } else {
                       dprintf(D_ALWAYS, "Unable to do chroot because working dir %s does not exist.\n", execute_dir.c_str());
               }
       } else {
               dprintf(D_FULLDEBUG, "Value of RequestedChroot is unset.\n");
       }
	}
// End of chroot 
#endif


	// On Linux kernel 2.4.19 and later, we can give each job its
	// own FS mounts.
	auto_free_ptr mount_under_scratch(param("MOUNT_UNDER_SCRATCH"));
	if (mount_under_scratch) {
		// try evaluating mount_under_scratch as a classad expression, if it is
		// an expression it must return a string. if it's not an expression, just
		// use it as a string (as we did before 8.3.6)
		classad::Value value;
		if (JobAd->EvaluateExpr(mount_under_scratch.ptr(), value)) {
			const char * pval = NULL;
			if (value.IsStringValue(pval)) {
				mount_under_scratch.set(strdup(pval));
			} else {
				// was an expression, but not a string, so report and error and fail.
				dprintf(D_ALWAYS | D_ERROR,
					"ERROR: MOUNT_UNDER_SCRATCH does not evaluate to a string, it is : %s\n",
					ClassAdValueToString(value));
				return FALSE;
			}
		}
	}

	// if execute dir is encrypted, add /tmp and /var/tmp to mount_under_scratch
	bool encrypt_execdir = false;
	JobAd->LookupBool(ATTR_ENCRYPT_EXECUTE_DIRECTORY,encrypt_execdir);
	if (encrypt_execdir || param_boolean_crufty("ENCRYPT_EXECUTE_DIRECTORY",false)) {
		// prepend /tmp, /var/tmp to whatever admin wanted. don't worry
		// if admin already listed /tmp etc - subdirs can appear twice
		// in this list because AddMapping() ok w/ duplicate entries
		MyString buf("/tmp,/var/tmp,");
		buf += mount_under_scratch.ptr();
		mount_under_scratch.set(buf.StrDup());
	}
	if (mount_under_scratch) {
		std::string working_dir = Starter->GetWorkingDir();

		if (IsDirectory(working_dir.c_str())) {
			StringList mount_list(mount_under_scratch);

			mount_list.rewind();
			if (!fs_remap) {
				fs_remap = new FilesystemRemap();
			}
			char * next_dir;
			while ( (next_dir=mount_list.next()) ) {
				if (!*next_dir) {
					// empty string?
					mount_list.deleteCurrent();
					continue;
				}
				std::string next_dir_str(next_dir);
				// Gah, I wish I could throw an exception to clean up these nested if statements.
				if (IsDirectory(next_dir)) {
					char * full_dir = dirscat(working_dir, next_dir_str);
					if (full_dir) {
						std::string full_dir_str(full_dir);
						delete [] full_dir; full_dir = NULL;
						if (!mkdir_and_parents_if_needed( full_dir_str.c_str(), S_IRWXU, PRIV_USER )) {
							dprintf(D_ALWAYS, "Failed to create scratch directory %s\n", full_dir_str.c_str());
							delete fs_remap;
							return FALSE;
						}
						dprintf(D_FULLDEBUG, "Adding mapping: %s -> %s.\n", full_dir_str.c_str(), next_dir_str.c_str());
						if (fs_remap->AddMapping(full_dir_str, next_dir_str)) {
							// FilesystemRemap object prints out an error message for us.
							delete fs_remap;
							return FALSE;
						}
					} else {
						dprintf(D_ALWAYS, "Unable to concatenate %s and %s.\n", working_dir.c_str(), next_dir_str.c_str());
						delete fs_remap;
						return FALSE;
					}
				} else {
					dprintf(D_ALWAYS, "Unable to add mapping %s -> %s because %s doesn't exist.\n", working_dir.c_str(), next_dir, next_dir);
				}
			}
		} else {
			dprintf(D_ALWAYS, "Unable to perform mappings because %s doesn't exist.\n", working_dir.c_str());
			delete fs_remap;
			return FALSE;
		}
		mount_under_scratch.clear();
	}

#if defined(LINUX)
	// On Linux kernel 2.6.24 and later, we can give each
	// job its own PID namespace
	if (param_boolean("USE_PID_NAMESPACES", false)) {
		if (!can_switch_ids()) {
			EXCEPT("USE_PID_NAMESPACES enabled, but can't perform this "
				"call in Linux unless running as root.");
		}
		fi.want_pid_namespace = this->SupportsPIDNamespace();
		if (fi.want_pid_namespace) {
			if (!fs_remap) {
				fs_remap = new FilesystemRemap();
			}
			fs_remap->RemapProc();
		}

		// When PID Namespaces are enabled, need to run the job
		// under the condor_pid_ns_init program, so that signals
		// propagate through to the child.  

		// First tell the program where to log output status
		// via an environment variable
		if (param_boolean("USE_PID_NAMESPACE_INIT", true)) {
			Env env;
			MyString env_errors;
			MyString arg_errors;
			std::string filename;

			filename = Starter->GetWorkingDir();
			filename += "/.condor_pid_ns_status";
		
			env.MergeFrom(JobAd, &env_errors);
			env.SetEnv("_CONDOR_PID_NS_INIT_STATUS_FILENAME", filename);
			env.InsertEnvIntoClassAd(JobAd, &env_errors);

			Starter->jic->removeFromOutputFiles(condor_basename(filename.c_str()));
			this->m_pid_ns_status_filename = filename;
			
			// Now, set the job's CMD to the wrapper, and shift
			// over the arguments by one

			ArgList args;
			std::string cmd;

			JobAd->LookupString(ATTR_JOB_CMD, cmd);
			args.AppendArg(cmd);
			args.AppendArgsFromClassAd(JobAd, &arg_errors);
			args.InsertArgsIntoClassAd(JobAd, NULL, & arg_errors);
	
			std::string libexec;
			if( !param(libexec,"LIBEXEC") ) {
				dprintf(D_ALWAYS, "Cannot find LIBEXEC so can not run condor_pid_ns_init\n");
				return 0;
			}
			std::string c_p_n_i = libexec + "/condor_pid_ns_init";
			JobAd->Assign(ATTR_JOB_CMD, c_p_n_i);
		}
	}
	dprintf(D_FULLDEBUG, "PID namespace option: %s\n", fi.want_pid_namespace ? "true" : "false");
#endif


	// have OsProc start the job
	//
	int retval = OsProc::StartJob(&fi, fs_remap);

	if (fs_remap != NULL) {
		delete fs_remap;
	}

#if defined(HAVE_EXT_LIBCGROUP)

	// Set fairshare limits.  Note that retval == 1 indicates success, 0 is failure.
	// See Note near setup of param(BASE_CGROUP)
	if (CONDOR_UNIVERSE_LOCAL != job_universe && cgroup && retval) {
		std::string mem_limit;
		param(mem_limit, "CGROUP_MEMORY_LIMIT_POLICY", "soft");
		bool mem_is_soft = mem_limit == "soft";
		std::string cgroup_string = cgroup;
		CgroupLimits climits(cgroup_string);
		if (mem_is_soft || (mem_limit == "hard")) {
			ClassAd * MachineAd = Starter->jic->machClassAd();
			int MemMb;
			if (MachineAd->LookupInteger(ATTR_MEMORY, MemMb)) {
				uint64_t MemMb_big = MemMb;
				m_memory_limit = MemMb_big;
				climits.set_memory_limit_bytes(1024*1024*MemMb_big, mem_is_soft);

				// Note that ATTR_VIRTUAL_MEMORY on Linux
				// is sum of memory and swap, in Kilobytes

				int VMemKb;
				if (MachineAd->LookupInteger(ATTR_VIRTUAL_MEMORY, VMemKb)) {

					uint64_t memsw_limit = ((uint64_t)1024) * VMemKb;
					if (VMemKb > 0) {
						// we're not allowed to set memsw limit <
						// the hard memory limit.  If we haven't set the hard
						// memory limit, the default may be infinity.
						// So, if we've set soft, set hard limit to memsw - one page
						if (mem_is_soft) {
							uint64_t hard_limit = memsw_limit - 4096;
							climits.set_memory_limit_bytes(hard_limit, false);
						}
						climits.set_memsw_limit_bytes(memsw_limit);
					}
				} else {
					dprintf(D_ALWAYS, "Not setting virtual memory limit in cgroup because "
						"Virtual Memory attribute missing in machine ad.\n");
				}
			} else {
				dprintf(D_ALWAYS, "Not setting memory limit in cgroup because "
					"Memory attribute missing in machine ad.\n");
			}
		} else if (mem_limit == "none") {
			dprintf(D_FULLDEBUG, "Not enforcing memory limit.\n");
		} else {
			dprintf(D_ALWAYS, "Invalid value of CGROUP_MEMORY_LIMIT_POLICY: %s.  Ignoring.\n", mem_limit.c_str());
		}

		// Now, set the CPU shares
		ClassAd * MachineAd = Starter->jic->machClassAd();
		int numCores = 1;
		if (MachineAd->LookupInteger(ATTR_CPUS, numCores)) {
			climits.set_cpu_shares(numCores*100);
		} else {
			dprintf(D_FULLDEBUG, "Invalid value of Cpus in machine ClassAd; ignoring.\n");
		}
		setupOOMEvent(cgroup);
	}

    m_statistics.Reconfig();

	// Now that the job is started, decrease the likelihood that the starter
	// is killed instead of the job itself.
	if (retval)
	{
		setupOOMScore(0,0);
	}

#endif

	return retval;
}
Beispiel #19
0
int JavaProc::StartJob()
{
	
	MyString java_cmd;
	char* jarfiles = NULL;
	ArgList args;
	MyString arg_buf;

	// Since we are adding to the argument list, we may need to deal
	// with platform-specific arg syntax in the user's args in order
	// to successfully merge them with the additional java VM args.
	args.SetArgV1SyntaxToCurrentPlatform();

	// Construct the list of jar files for the command line
	// If a jar file is transferred locally, use its local name
	// (in the execute directory)
	// otherwise use the original name

	StringList jarfiles_orig_list;
	StringList jarfiles_local_list;
	StringList* jarfiles_final_list = NULL;

	if( JobAd->LookupString(ATTR_JAR_FILES,&jarfiles) ) {
		jarfiles_orig_list.initializeFromString( jarfiles );
		free( jarfiles );
		jarfiles = NULL;

		char * jarfile_name;
		const char * base_name;
		struct stat stat_buff;
		if( Starter->jic->iwdIsChanged() ) {
				// If the job's IWD has been changed (because we're
				// running in the sandbox due to file transfer), we
				// need to use a local version of the path to the jar
				// files, not the full paths from the submit machine. 
			jarfiles_orig_list.rewind();
			while( (jarfile_name = jarfiles_orig_list.next()) ) {
					// Construct the local name
				base_name = condor_basename( jarfile_name );
				MyString local_name = execute_dir;
				local_name += DIR_DELIM_CHAR;
				local_name += base_name; 

				if( stat(local_name.Value(), &stat_buff) == 0 ) {
						// Jar file exists locally, use local name
					jarfiles_local_list.append( local_name.Value() );
				} else {
						// Use the original name
					jarfiles_local_list.append (jarfile_name);
				}
			} // while(jarfiles_orig_list)

				// jarfiles_local_list is our real copy...
			jarfiles_final_list = &jarfiles_local_list;

		} else {  // !iwdIsChanged()

				// just use jarfiles_orig_list as our real copy...
			jarfiles_final_list = &jarfiles_orig_list;
		}			
	}

	startfile.formatstr("%s%cjvm.start",execute_dir,DIR_DELIM_CHAR);
	endfile.formatstr("%s%cjvm.end",execute_dir,DIR_DELIM_CHAR);

	if( !java_config(java_cmd,&args,jarfiles_final_list) ) {
		dprintf(D_FAILURE|D_ALWAYS,"JavaProc: Java is not configured!\n");
		return 0;
	}

	JobAd->Assign(ATTR_JOB_CMD, java_cmd.Value());

	arg_buf.formatstr("-Dchirp.config=%s%cchirp.config",execute_dir,DIR_DELIM_CHAR);
	args.AppendArg(arg_buf.Value());

	char *jvm_args1 = NULL;
	char *jvm_args2 = NULL;
	MyString jvm_args_error;
	bool jvm_args_success = true;
	JobAd->LookupString(ATTR_JOB_JAVA_VM_ARGS1, &jvm_args1);
	JobAd->LookupString(ATTR_JOB_JAVA_VM_ARGS2, &jvm_args2);
	if(jvm_args2) {
		jvm_args_success = args.AppendArgsV2Raw(jvm_args2, &jvm_args_error);
	}
	else if(jvm_args1) {
		jvm_args_success = args.AppendArgsV1Raw(jvm_args1, &jvm_args_error);
	}
	free(jvm_args1);
	free(jvm_args2);
	if (!jvm_args_success) {
		dprintf(D_ALWAYS, "JavaProc: failed to parse JVM args: %s\n",
				jvm_args_error.Value());
		return 0;
	}

	args.AppendArg("CondorJavaWrapper");
	args.AppendArg(startfile.Value());
	args.AppendArg(endfile.Value());

	MyString args_error;
	if(!args.AppendArgsFromClassAd(JobAd,&args_error)) {
		dprintf(D_ALWAYS,"JavaProc: failed to read job arguments: %s\n",
				args_error.Value());
		return 0;
	}

	// We are just talking to ourselves, so it is fine to use argument
	// syntax compatible with this current version of Condor.
	CondorVersionInfo ver_info;
	if(!args.InsertArgsIntoClassAd(JobAd,&ver_info,&args_error)) {
		dprintf(D_ALWAYS,"JavaProc: failed to insert java job arguments: %s\n",
				args_error.Value());
		return 0;
	}

	dprintf(D_ALWAYS,"JavaProc: Cmd=%s\n",java_cmd.Value());
	MyString args_string;
	args.GetArgsStringForDisplay(&args_string);
	dprintf(D_ALWAYS,"JavaProc: Args=%s\n",args_string.Value());

	return VanillaProc::StartJob();
}
Beispiel #20
0
void
main_pre_dc_init( int argc, char* argv[] )
{	
	param_functions *p_funcs = NULL;
		// figure out what get_mySubSystem() should be based on argv[0], or
		// if we see "-gridshell" anywhere on the command-line
	const char* base = condor_basename(argv[0]);
	char const *tmp;
	tmp = strrchr(base, '_' );
	if( tmp && strncasecmp(tmp, "_gridshell", 10) == MATCH ) {
		get_mySubSystem()->setName( "GRIDSHELL" );
		is_gridshell = true;
	} else { 
		int i, len;
		for( i=1; i<argc; i++ ) {
			len = strlen(argv[i]);
			if( len < 3 ) {
					// ambiguous, bail out, since we don't want to get
					// confused with just "-" or something
				continue;
			}
			if( strncasecmp(argv[i], "-gridshell", MIN(len,10)) == MATCH ) {
				get_mySubSystem()->setName( "GRIDSHELL" );
				is_gridshell = true;
				break;
			}
		}
	}
	if( ! is_gridshell ) {
		get_mySubSystem()->setName( "STARTER" );
	}

		// if we were passed "-classad", just print our classad and
		// exit, without going back to daemoncore or anything.  we
		// need to do this *after* we set get_mySubSystem(), since this ends
		// up calling functions that rely on it being defined...  
	if( argc == 2 && strncasecmp(argv[1],"-cla",4) == MATCH ) {
			// needed for Java stuff
		config(true);

			// Would like to log errors to stderr if stderr is not
			// /dev/null to make it easier for users to debug, but not
			// sure how to do that on windows.  On Windows, when
			// condor_starter is run by the startd, setting Termlog=1
			// causes a dprintf to abort with an error if any calls to
			// dprintf() are made in a debug level that is turned on.
			// I have not found a way to detect when stderr is in this
			// state, so I am just leaving Termlog turned off in all
			// cases.

		//Termlog = 1;

		p_funcs = get_param_functions();
		dprintf_config(get_mySubSystem()->getName(), p_funcs);

		printClassAd();
		exit(0);
	}

		// if we're still here, stash the cwd for future reference
	MyString cwd;
	if( ! condor_getcwd(cwd)) {
		dprintf( D_ALWAYS, "ERROR calling getcwd(): %s (errno %d)\n", 
				 strerror(errno), errno );
	} else {
		orig_cwd = strdup(cwd.Value());
	}

		// if we're the gridshell, assume a "-f" option.  all that
		// does in DaemonCore-land is set a global variable, so we'll
		// just do that here, ourselves...
	if( is_gridshell ) {
		Foreground = 1;
	}

		// finally, dup() our standard file streams, so we can pass
		// those onto the actual user job if requested.
	starter_stdin_fd = dup( 0 );
	starter_stdout_fd = dup( 1 );
	starter_stderr_fd = dup( 2 );
}
Beispiel #21
0
int
VanillaProc::StartJob()
{
	dprintf(D_FULLDEBUG,"in VanillaProc::StartJob()\n");

	// vanilla jobs, unlike standard jobs, are allowed to run 
	// shell scripts (or as is the case on NT, batch files).  so
	// edit the ad so we start up a shell, pass the executable as
	// an argument to the shell, if we are asked to run a .bat file.
#ifdef WIN32

	CHAR		interpreter[MAX_PATH+1],
				systemshell[MAX_PATH+1];    
	const char* jobtmp				= Starter->jic->origJobName();
	int			joblen				= strlen(jobtmp);
	const char	*extension			= joblen > 0 ? &(jobtmp[joblen-4]) : NULL;
	bool		binary_executable	= ( extension && 
										( MATCH == strcasecmp ( ".exe", extension ) || 
										  MATCH == strcasecmp ( ".com", extension ) ) ),
				java_universe		= ( CONDOR_UNIVERSE_JAVA == job_universe );
	ArgList		arguments;
	MyString	filename,
				jobname, 
				error;
	
	if ( extension && !java_universe && !binary_executable ) {

		/** since we do not actually know how long the extension of
			the file is, we'll need to hunt down the '.' in the path,
			if it exists */
		extension = strrchr ( jobtmp, '.' );

		if ( !extension ) {

			dprintf ( 
				D_ALWAYS, 
				"VanillaProc::StartJob(): Failed to extract "
				"the file's extension.\n" );

			/** don't fail here, since we want executables to run
				as usual.  That is, some condor jobs submit 
				executables that do not have the '.exe' extension,
				but are, nonetheless, executable binaries.  For
				instance, a submit script may contain:

				executable = executable$(OPSYS) */

		} else {

			/** pull out the path to the executable */
			if ( !JobAd->LookupString ( 
				ATTR_JOB_CMD, 
				jobname ) ) {
				
				/** fall back on Starter->jic->origJobName() */
				jobname = jobtmp;

			}

			/** If we transferred the job, it may have been
				renamed to condor_exec.exe even though it is
				not an executable. Here we rename it back to
				a the correct extension before it will run. */
			if ( MATCH == strcasecmp ( 
					CONDOR_EXEC, 
					condor_basename ( jobname.Value () ) ) ) {
				filename.formatstr ( "condor_exec%s", extension );
				if (rename(CONDOR_EXEC, filename.Value()) != 0) {
					dprintf (D_ALWAYS, "VanillaProc::StartJob(): ERROR: "
							"failed to rename executable from %s to %s\n", 
							CONDOR_EXEC, filename.Value() );
				}
			} else {
				filename = jobname;
			}
			
			/** Since we've renamed our executable, we need to
				update the job ad to reflect this change. */
			if ( !JobAd->Assign ( 
				ATTR_JOB_CMD, 
				filename ) ) {

				dprintf (
					D_ALWAYS,
					"VanillaProc::StartJob(): ERROR: failed to "
					"set new executable name.\n" );

				return FALSE;

			}

			/** We've moved the script to argv[1], so we need to 
				add	the remaining arguments to positions argv[2]..
				argv[/n/]. */
			if ( !arguments.AppendArgsFromClassAd ( JobAd, &error ) ||
				 !arguments.InsertArgsIntoClassAd ( JobAd, NULL, 
				&error ) ) {

				dprintf (
					D_ALWAYS,
					"VanillaProc::StartJob(): ERROR: failed to "
					"get arguments from job ad: %s\n",
					error.Value () );

				return FALSE;

			}

			/** Since we know already we don't want this file returned
				to us, we explicitly add it to an exception list which
				will stop the file transfer mechanism from considering
				it for transfer back to its submitter */
			Starter->jic->removeFromOutputFiles (
				filename.Value () );

		}
			
	}
#endif

	// set up a FamilyInfo structure to tell OsProc to register a family
	// with the ProcD in its call to DaemonCore::Create_Process
	//
	FamilyInfo fi;

	// take snapshots at no more than 15 seconds in between, by default
	//
	fi.max_snapshot_interval = param_integer("PID_SNAPSHOT_INTERVAL", 15);

	m_dedicated_account = Starter->jic->getExecuteAccountIsDedicated();
	if( ThisProcRunsAlongsideMainProc() ) {
			// If we track a secondary proc's family tree (such as
			// sshd) using the same dedicated account as the job's
			// family tree, we could end up killing the job when we
			// clean up the secondary family.
		m_dedicated_account = NULL;
	}
	if (m_dedicated_account) {
			// using login-based family tracking
		fi.login = m_dedicated_account;
			// The following message is documented in the manual as the
			// way to tell whether the dedicated execution account
			// configuration is being used.
		dprintf(D_ALWAYS,
		        "Tracking process family by login \"%s\"\n",
		        fi.login);
	}

	FilesystemRemap * fs_remap = NULL;
#if defined(LINUX)
	// on Linux, we also have the ability to track processes via
	// a phony supplementary group ID
	//
	gid_t tracking_gid = 0;
	if (param_boolean("USE_GID_PROCESS_TRACKING", false)) {
		if (!can_switch_ids() &&
		    (Starter->condorPrivSepHelper() == NULL))
		{
			EXCEPT("USE_GID_PROCESS_TRACKING enabled, but can't modify "
			           "the group list of our children unless running as "
			           "root or using PrivSep");
		}
		fi.group_ptr = &tracking_gid;
	}
#endif

#if defined(HAVE_EXT_LIBCGROUP)
	// Determine the cgroup
	std::string cgroup_base;
	param(cgroup_base, "BASE_CGROUP", "");
	MyString cgroup_str;
	const char *cgroup = NULL;
	if (cgroup_base.length()) {
		MyString cgroup_uniq;
		std::string starter_name, execute_str;
		param(execute_str, "EXECUTE", "EXECUTE_UNKNOWN");
			// Note: Starter is a global variable from os_proc.cpp
		Starter->jic->machClassAd()->EvalString(ATTR_NAME, NULL, starter_name);
		ASSERT (starter_name.size());
		cgroup_uniq.formatstr("%s_%s", execute_str.c_str(), starter_name.c_str());
		const char dir_delim[2] = {DIR_DELIM_CHAR, '\0'};
		cgroup_uniq.replaceString(dir_delim, "_");
		cgroup_str.formatstr("%s%ccondor%s", cgroup_base.c_str(), DIR_DELIM_CHAR,
			cgroup_uniq.Value());
		cgroup = cgroup_str.Value();
		ASSERT (cgroup != NULL);
		fi.cgroup = cgroup;
		dprintf(D_FULLDEBUG, "Requesting cgroup %s for job.\n", cgroup);
	}

#endif

// The chroot stuff really only works on linux
#ifdef LINUX
	{
        // Have Condor manage a chroot
       std::string requested_chroot_name;
       JobAd->EvalString("RequestedChroot", NULL, requested_chroot_name);
       const char * allowed_root_dirs = param("NAMED_CHROOT");
       if (requested_chroot_name.size()) {
               dprintf(D_FULLDEBUG, "Checking for chroot: %s\n", requested_chroot_name.c_str());
               StringList chroot_list(allowed_root_dirs);
               chroot_list.rewind();
               const char * next_chroot;
               bool acceptable_chroot = false;
               std::string requested_chroot;
               while ( (next_chroot=chroot_list.next()) ) {
                       MyString chroot_spec(next_chroot);
                       chroot_spec.Tokenize();
                       const char * chroot_name = chroot_spec.GetNextToken("=", false);
                       if (chroot_name == NULL) {
                               dprintf(D_ALWAYS, "Invalid named chroot: %s\n", chroot_spec.Value());
                       }
                       const char * next_dir = chroot_spec.GetNextToken("=", false);
                       if (chroot_name == NULL) {
                               dprintf(D_ALWAYS, "Invalid named chroot: %s\n", chroot_spec.Value());
                       }
                       dprintf(D_FULLDEBUG, "Considering directory %s for chroot %s.\n", next_dir, chroot_spec.Value());
                       if (IsDirectory(next_dir) && chroot_name && (strcmp(requested_chroot_name.c_str(), chroot_name) == 0)) {
                               acceptable_chroot = true;
                               requested_chroot = next_dir;
                       }
               }
               // TODO: path to chroot MUST be all root-owned, or we have a nice security exploit.
               // Is this the responsibility of Condor to check, or the sysadmin who set it up?
               if (!acceptable_chroot) {
                       return FALSE;
               }
               dprintf(D_FULLDEBUG, "Will attempt to set the chroot to %s.\n", requested_chroot.c_str());

               std::stringstream ss;
               std::stringstream ss2;
               ss2 << Starter->GetExecuteDir() << DIR_DELIM_CHAR << "dir_" << getpid();
               std::string execute_dir = ss2.str();
               ss << requested_chroot << DIR_DELIM_CHAR << ss2.str();
               std::string full_dir_str = ss.str();
               if (is_trivial_rootdir(requested_chroot)) {
                   dprintf(D_FULLDEBUG, "Requested a trivial chroot %s; this is a no-op.\n", requested_chroot.c_str());
               } else if (IsDirectory(execute_dir.c_str())) {
                       {
                           TemporaryPrivSentry sentry(PRIV_ROOT);
                           if( mkdir(full_dir_str.c_str(), S_IRWXU) < 0 ) {
                               dprintf( D_FAILURE|D_ALWAYS,
                                   "Failed to create sandbox directory in chroot (%s): %s\n",
                                   full_dir_str.c_str(),
                                   strerror(errno) );
                               return FALSE;
                           }
                           if (chown(full_dir_str.c_str(),
                                     get_user_uid(),
                                     get_user_gid()) == -1)
                           {
                               EXCEPT("chown error on %s: %s",
                                      full_dir_str.c_str(),
                                      strerror(errno));
                           }
                       }
                       if (!fs_remap) {
                               fs_remap = new FilesystemRemap();
                       }
                       dprintf(D_FULLDEBUG, "Adding mapping: %s -> %s.\n", execute_dir.c_str(), full_dir_str.c_str());
                       if (fs_remap->AddMapping(execute_dir, full_dir_str)) {
                               // FilesystemRemap object prints out an error message for us.
                               return FALSE;
                       }
                       dprintf(D_FULLDEBUG, "Adding mapping %s -> %s.\n", requested_chroot.c_str(), "/");
                       std::string root_str("/");
                       if (fs_remap->AddMapping(requested_chroot, root_str)) {
                               return FALSE;
                       }
               } else {
                       dprintf(D_ALWAYS, "Unable to do chroot because working dir %s does not exist.\n", execute_dir.c_str());
               }
       } else {
               dprintf(D_FULLDEBUG, "Value of RequestedChroot is unset.\n");
       }
	}
// End of chroot 
#endif


	// On Linux kernel 2.4.19 and later, we can give each job its
	// own FS mounts.
	char * mount_under_scratch = param("MOUNT_UNDER_SCRATCH");
	if (mount_under_scratch) {

		std::string working_dir = Starter->GetWorkingDir();

		if (IsDirectory(working_dir.c_str())) {
			StringList mount_list(mount_under_scratch);
			free(mount_under_scratch);

			mount_list.rewind();
			if (!fs_remap) {
				fs_remap = new FilesystemRemap();
			}
			char * next_dir;
			while ( (next_dir=mount_list.next()) ) {
				if (!*next_dir) {
					// empty string?
					mount_list.deleteCurrent();
					continue;
				}
				std::string next_dir_str(next_dir);
				// Gah, I wish I could throw an exception to clean up these nested if statements.
				if (IsDirectory(next_dir)) {
					char * full_dir = dirscat(working_dir, next_dir_str);
					if (full_dir) {
						std::string full_dir_str(full_dir);
						delete [] full_dir; full_dir = NULL;
						if (!mkdir_and_parents_if_needed( full_dir_str.c_str(), S_IRWXU, PRIV_USER )) {
							dprintf(D_ALWAYS, "Failed to create scratch directory %s\n", full_dir_str.c_str());
							return FALSE;
						}
						dprintf(D_FULLDEBUG, "Adding mapping: %s -> %s.\n", full_dir_str.c_str(), next_dir_str.c_str());
						if (fs_remap->AddMapping(full_dir_str, next_dir_str)) {
							// FilesystemRemap object prints out an error message for us.
							return FALSE;
						}
					} else {
						dprintf(D_ALWAYS, "Unable to concatenate %s and %s.\n", working_dir.c_str(), next_dir_str.c_str());
						return FALSE;
					}
				} else {
					dprintf(D_ALWAYS, "Unable to add mapping %s -> %s because %s doesn't exist.\n", working_dir.c_str(), next_dir, next_dir);
				}
			}
		} else {
			dprintf(D_ALWAYS, "Unable to perform mappings because %s doesn't exist.\n", working_dir.c_str());
			return FALSE;
		}
	}

	// have OsProc start the job
	//
	int retval = OsProc::StartJob(&fi, fs_remap);

	if (fs_remap != NULL) {
		delete fs_remap;
	}

#if defined(HAVE_EXT_LIBCGROUP)

	// Set fairshare limits.  Note that retval == 1 indicates success, 0 is failure.
	if (cgroup && retval) {
		std::string mem_limit;
		param(mem_limit, "MEMORY_LIMIT", "soft");
		bool mem_is_soft = mem_limit == "soft";
		std::string cgroup_string = cgroup;
		CgroupLimits climits(cgroup_string);
		if (mem_is_soft || (mem_limit == "hard")) {
			ClassAd * MachineAd = Starter->jic->machClassAd();
			int MemMb;
			if (MachineAd->LookupInteger(ATTR_MEMORY, MemMb)) {
				uint64_t MemMb_big = MemMb;
				climits.set_memory_limit_bytes(1024*1024*MemMb_big, mem_is_soft);
			} else {
				dprintf(D_ALWAYS, "Not setting memory soft limit in cgroup because "
					"Memory attribute missing in machine ad.\n");
			}
		} else if (mem_limit == "none") {
			dprintf(D_FULLDEBUG, "Not enforcing memory soft limit.\n");
		} else {
			dprintf(D_ALWAYS, "Invalid value of MEMORY_LIMIT: %s.  Ignoring.\n", mem_limit.c_str());
		}

		// Now, set the CPU shares
		ClassAd * MachineAd = Starter->jic->machClassAd();
		int slotWeight;
		if (MachineAd->LookupInteger(ATTR_SLOT_WEIGHT, slotWeight)) {
			climits.set_cpu_shares(slotWeight*100);
		} else {
			dprintf(D_FULLDEBUG, "Invalid value of SlotWeight in machine ClassAd; ignoring.\n");
		}
	}

#endif

	return retval;
}
Beispiel #22
0
/** Set up things in deep and shallow options that aren't directly specified
	on the command line.
	@param deepOpts: the condor_submit_dag deep options
	@param shallowOpts: the condor_submit_dag shallow options
	@return 0 if successful, 1 if failed
*/
int
setUpOptions( SubmitDagDeepOptions &deepOpts,
			SubmitDagShallowOptions &shallowOpts )
{
	shallowOpts.strLibOut = shallowOpts.primaryDagFile + ".lib.out";
	shallowOpts.strLibErr = shallowOpts.primaryDagFile + ".lib.err";

	if ( deepOpts.strOutfileDir != "" ) {
		shallowOpts.strDebugLog = deepOpts.strOutfileDir + DIR_DELIM_STRING +
					condor_basename( shallowOpts.primaryDagFile.Value() );
	} else {
		shallowOpts.strDebugLog = shallowOpts.primaryDagFile;
	}
	shallowOpts.strDebugLog += ".dagman.out";

	shallowOpts.strSchedLog = shallowOpts.primaryDagFile + ".dagman.log";
	shallowOpts.strSubFile = shallowOpts.primaryDagFile + DAG_SUBMIT_FILE_SUFFIX;

	MyString	rescueDagBase;

		// If we're running each DAG in its own directory, write any rescue
		// DAG to the current directory, to avoid confusion (since the
		// rescue DAG must be run from the current directory).
	if ( deepOpts.useDagDir ) {
		if ( !condor_getcwd( rescueDagBase ) ) {
			fprintf( stderr, "ERROR: unable to get cwd: %d, %s\n",
					errno, strerror(errno) );
			return 1;
		}
		rescueDagBase += DIR_DELIM_STRING;
		rescueDagBase += condor_basename(shallowOpts.primaryDagFile.Value());
	} else {
		rescueDagBase = shallowOpts.primaryDagFile;
	}

		// If we're running multiple DAGs, put "_multi" in the rescue
		// DAG name to indicate that the rescue DAG is for *all* of
		// the DAGs we're running.
	if ( shallowOpts.dagFiles.number() > 1 ) {
		rescueDagBase += "_multi";
	}

	shallowOpts.strRescueFile = rescueDagBase + ".rescue";

	shallowOpts.strLockFile = shallowOpts.primaryDagFile + ".lock";

	if (deepOpts.strDagmanPath == "" ) {
		deepOpts.strDagmanPath = which( dagman_exe );
	}

	if (deepOpts.strDagmanPath == "")
	{
		fprintf( stderr, "ERROR: can't find %s in PATH, aborting.\n",
				 dagman_exe );
		return 1;
	}

	MyString	msg;
	if ( !GetConfigFile( shallowOpts.dagFiles, deepOpts.useDagDir,
				shallowOpts.strConfigFile, msg) ) {
		fprintf( stderr, "ERROR: %s\n", msg.Value() );
		return 1;
	}

	return 0;
}
Beispiel #23
0
HRESULT
WindowsFirewallHelper::addTrusted( const char *app_path ) {

	const char *app_basename;
	BSTR app_path_bstr = NULL;
	BSTR app_basename_bstr = NULL;

	HRESULT hr = S_OK;
	INetFwAuthorizedApplication* fwApp = NULL;
	
	if ( ! ready() || ! i_can_add) { 
		return S_FALSE;
	}

	if ( !firewallIsOn() ) {
		// firewall is turned off, so there's nothing to do.
		return S_FALSE;
	}

	if ( applicationIsTrusted(app_path) ) {
		// this app is already set to be trusted, so do nothing.
		return S_OK;
	}

	// now, if the basename of the app is condor_<something>, we 
	// want to make sure there aren't any other entries of the same
	// condor daemon with a different path. We only do this for "condor_" 
	// executables as a safety to keep us from removing trusted applications
	// that have nothing to do with condor.
	app_basename = condor_basename(app_path);

	if ( _strnicmp(app_basename, "condor_", strlen("condor_")) == 0 ) {
		
		hr = removeByBasename(app_basename);

	}

	// now just add the application to the trusted list.
	
    // Create an instance of an authorized application.
    hr = CoCreateInstance(
		__uuidof(NetFwAuthorizedApplication),
		NULL,
		CLSCTX_INPROC_SERVER,
		__uuidof(INetFwAuthorizedApplication),
		reinterpret_cast<void**>
		(static_cast<INetFwAuthorizedApplication**>(&fwApp))
		);
	if (FAILED(hr))
	{
		i_can_add = false;
		dprintf(D_ERROR | D_FULLDEBUG, "WinFirewall: CoCreateInstance failed: 0x%08lx %s\n", hr, GetHRString(hr));
		return hr;
	}
	
	app_path_bstr = charToBstr(app_path);
	// Set the process image file name.
	hr = fwApp->put_ProcessImageFileName(app_path_bstr);
	if (FAILED(hr))
	{
		if ( hr == 0x80070002 ) {
			dprintf(D_ERROR, "WinFirewall Error: Could not find trusted app image %s\n",
				app_path);
		} else {
			dprintf(D_ERROR, "put_ProcessImageFileName failed: 0x%08lx %s\n", hr, GetHRString(hr));
		}
		goto error;
	}
	
        // Allocate a BSTR for the application friendly name.
        app_basename_bstr = charToBstr(app_basename);

        // Set the application friendly name.
        hr = fwApp->put_Name(app_basename_bstr);
        if (FAILED(hr))
        {
            dprintf(D_ERROR | D_FULLDEBUG, "WinFirewall: put_Name failed: 0x%08lx %s\n", hr, GetHRString(hr));
            goto error;
        }

        // Add the application to the collection.
        hr = fwApps->Add(fwApp);
        if (FAILED(hr))
        {
            dprintf(D_ERROR, "WinFirewall: Add failed: 0x%08lx %s\n", hr, GetHRString(hr));
            goto error;
        }

		// it seems like we should always inform users somehow that we're 
		// doing this.
        dprintf(D_STATUS, "Authorized application %s is now enabled in the"
			   " firewall.\n",
            app_path );

error:

    // Free the BSTRs.
    SysFreeString(app_path_bstr);
    SysFreeString(app_basename_bstr);

    // Release the authorized application instance.
    if (fwApp != NULL)
    {
        fwApp->Release();
    }

	if (hr == E_ACCESSDENIED) i_can_add = false;
    return hr;

}
Beispiel #24
0
HRESULT
WindowsFirewallHelper::removeByBasename( const char *name ) {
	
	HRESULT hr = S_OK;
	 
	IUnknown* pUnknown = NULL;
	IEnumVARIANT* pEnum = NULL;
    INetFwAuthorizedApplication* fwApp = NULL;
 
	bool result = true;
	long count;
	unsigned long cnt;
	int i;
	VARIANT v;

	if ( ! ready() ) {
		return S_FALSE;
	}

	hr = fwApps->get__NewEnum(&pUnknown);
	if ( hr != S_OK ) {
		dprintf(D_ERROR, "Failed to get enumerator for Authorized "
				"Applications (err=%x)\n", hr);
		return hr;
	}

	hr = fwApps->get_Count(&count);
	if ( hr != S_OK ) {
		dprintf(D_ERROR, "Failed to get count of Authorized "
				"Applications (err=%x)\n", hr);
		return hr;
	}

	hr = pUnknown->QueryInterface(IID_IEnumVARIANT, (void**)&pEnum);
	if ( hr != S_OK ) {
		if ( hr == E_NOINTERFACE ) {
			dprintf(D_ERROR, "Failed to QueryInterface for trusted "
					"applications. Interface not supported.\n");
		} else {
			dprintf(D_ERROR, "Failed to QueryInterface for trusted "
				   "applications. (err=%x)\n", hr);
		}
		return hr;
	}

	for (i=0; i<count; i++) {
		BSTR str = NULL;
		size_t len;
		char *tmp;
	    const char *bn;

		hr = pEnum->Next(1, &v, &cnt);
		// interesting tidbit: Microsoft says Enum->Next() function
		// either returns S_OK or S_FALSE. Funny, on Win2k3 SP1
		// it returns 0x80020008, or Bad Variable Type. Sigh.
		if ( hr != S_OK ) {
			// no more elements. stop.
			hr = S_FALSE;
			break;
		}

		fwApp = (INetFwAuthorizedApplication*)v.byref;

		fwApp->get_ProcessImageFileName(&str);

		// This should not be printing to stdout, but if you are
		// reading this and think it is necessary to print these 
		// executable names then dprintf() them.
		// printf("Result is %lS\n", str);

		len = wcslen(str);
		tmp = (char*) malloc((len*2+1) * sizeof(char));
		ASSERT(tmp);
		sprintf(tmp, "%S", str);

		bn = condor_basename(tmp);

		if ( 0 == strcasecmp(bn, name) ) {
			
			// basenames match, so remove it from the list.
			
			hr = removeTrusted(tmp);
		}
		free(tmp);

		SysFreeString(str);

		if (hr == E_ACCESSDENIED) {
			// don't have enough privilege to remove, so don't bother to keep trying.
			break;
		}
	}

	return hr;
}
Beispiel #25
0
int
getCommandFromArgv( int argc, char* argv[] )
{
	char* cmd_str = NULL;
	int size, baselen;
	char* base = strdup( condor_basename(argv[0]) ); 

		// See if there's an '-' in our name, if not, append argv[1].
	cmd_str = strrchr( base, '_');

		// now, make sure we're not looking at "condor_cod" or
		// something.  if cmd_str is pointing at cod, we want to move
		// beyond that...
	if( cmd_str && !strncasecmp(cmd_str, "_cod", 4) ) {
		if( cmd_str[4] ) {
			cmd_str = &cmd_str[4];
		} else {
			cmd_str = NULL;
		}
	}
		// finally, see what we've got after that...
	if( !cmd_str ) {

			// If there's no argv[1], print usage.
		if( ! argv[1] ) { usage( base ); }

			// If argv[1] begins with '-', print usage, don't append.
		if( argv[1][0] == '-' ) { 
				// The one exception is if we got a "cod -v", we
				// should print the version, not give an error.
			if( argv[1][1] == 'v' ) {
				version();
			} if( argv[1][1] == 'h' ) {
			      usage( base, 0 );
			} else {
				usage( base );
			}
		}
		size = strlen(argv[1]);
		baselen = strlen(base);
			// we also need to store the space and the '\0'.
		my_name = (char*)malloc( size + baselen + 2 );
		ASSERT( my_name != NULL );
		sprintf( my_name, "%s %s", base, argv[1] );
			// skip past the basename and the space...
		cmd_str = my_name+baselen+1;
		free( base );
		argv++; argc--;
	} else {
		my_name = base;
		cmd_str++;
	}
		// Figure out what kind of tool we are.
	if( !strcmp( cmd_str, "request" ) ) {
			// this is the only one that doesn't require a claim id 
		needs_id = false;
		return CA_REQUEST_CLAIM;
	} else if( !strcmp( cmd_str, "release" ) ) {
		return CA_RELEASE_CLAIM;
	} else if( !strcmp( cmd_str, "activate" ) ) {
		return CA_ACTIVATE_CLAIM;
	} else if( !strcmp( cmd_str, "deactivate" ) ) {
		return CA_DEACTIVATE_CLAIM;
	} else if( !strcmp( cmd_str, "suspend" ) ) {
		return CA_SUSPEND_CLAIM;
	} else if( !strcmp( cmd_str, "resume" ) ) {
		return CA_RESUME_CLAIM;
	} else if( !strcmp( cmd_str, "renew" ) ) {
		return CA_RENEW_LEASE_FOR_CLAIM;
	} else if( !strcmp( cmd_str, "delegate_proxy" ) ) {
		return DELEGATE_GSI_CRED_STARTD;
	} else {
		fprintf( stderr, "ERROR: unknown command \"%s\"\n", my_name );
		usage( "cod" );
	}
	return -1;
}
Beispiel #26
0
/* Helper function: write the input files mime encode in the inputAd into iwd */
bool
write_input_files(const ClassAd* inputAd, const char *iwd)
{
	bool return_value = true;
	char *file_name, *file_data;
	unsigned char *output;
	char buf[60];
	int i, output_length, fd;
	int flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND | O_LARGEFILE;

	TmpDir tmpdir;
	MyString tmpdir_error;
	if (tmpdir.Cd2TmpDir(iwd,tmpdir_error) == false ) {
		// We failed to cd to our iwd.  This should NEVER happen.
		EXCEPT("write_input_files iwd failure: %s",tmpdir_error.Value());
	}

	i=0; file_name=NULL; file_data=NULL;output=NULL;
	while (return_value==true) {	// keep looping until break or failure
		i++;
		sprintf(buf,"INPUT_FILE_NAME_%d",i);
		inputAd->LookupString(buf,&file_name);
		if (!file_name) break;		// no more files
		sprintf(buf,"INPUT_FILE_DATA_%d",i);
		inputAd->LookupString(buf,&file_data);
		if ( file_data ) {
			// Caller needs to free *output if non-NULL
			condor_base64_decode(file_data,&output,&output_length);
			if ( output ) {
				fd = safe_open_wrapper_follow( condor_basename(file_name), flags, 0666 );
				if ( fd > -1 ) {
					write(fd,output,output_length);
					close(fd);
					dprintf(D_FULLDEBUG,"Wrote %d bytes to file %s%c%s\n",
								output_length, iwd, DIR_DELIM_CHAR, 
								condor_basename(file_name));
				} else {
					return_value = false;
				}
				free(output);
				output = NULL;
			} else {
				dprintf(D_ALWAYS,"Failed to decode base64 in attribute %s for file %s\n",
						buf,condor_basename(file_name));
				return_value = false;
			}
			free(file_data);
			file_data = NULL;
		} else {
			// INPUT_FILE_NAME specified, but no data... so just touch the file
			fd = safe_open_wrapper_follow( condor_basename(file_name), flags, 0666 );
			if ( fd > -1 ) {
				close(fd);
				dprintf(D_FULLDEBUG,"Wrote empty file %s%c%s\n",
								iwd, DIR_DELIM_CHAR, 
								condor_basename(file_name));
			}
		}
		free(file_name);
		file_name = NULL;
	}

	if ( return_value ) {
		dprintf(D_ALWAYS,"Wrote %d files to subdir %s\n",i-1,iwd);
	} else {
		dprintf(D_ALWAYS,"Failed to write file %d to subdir %s\n",i,iwd);
	}
		
	return return_value;
}
Beispiel #27
0
bool
ProcFamilyProxy::start_procd()
{
	// we'll only start one ProcD
	//
	ASSERT(m_procd_pid == -1);

	// now, we build up an ArgList for the procd
	//
	MyString exe;
	ArgList args;

	// path to the executable
	//
	char* path = param("PROCD");
	if (path == NULL) {
		dprintf(D_ALWAYS, "start_procd: PROCD not defined in configuration\n");
		return false;
	}
	exe = path;
	args.AppendArg(condor_basename(path));
	free(path);

	// the procd's address
	//
	args.AppendArg("-A");
	args.AppendArg(m_procd_addr);

	// the (optional) procd log file
	//
	if (m_procd_log.Length() > 0) {
		args.AppendArg("-L");
		args.AppendArg(m_procd_log);
	}
	
	// the (optional) procd log file size
	//
	char *procd_log_size = param("MAX_PROCD_LOG");
	if (procd_log_size != NULL) {
		args.AppendArg("-R");
		args.AppendArg(procd_log_size);
		free(procd_log_size);
	}
	
	Env env;
	// The procd can't param, so pass this via the environment
	if (param_boolean("USE_PSS", false)) {
		env.SetEnv("_condor_USE_PSS=TRUE");
	}

	// the (optional) maximum snapshot interval
	// (the procd will default to every minute)
	//
	char* max_snapshot_interval = param("PROCD_MAX_SNAPSHOT_INTERVAL");
	if (max_snapshot_interval != NULL) {
		args.AppendArg("-S");
		args.AppendArg(max_snapshot_interval);
		free(max_snapshot_interval);
	}

	// (optional) make the procd sleep on startup so a
	// debugger can attach
	//
	bool debug = param_boolean("PROCD_DEBUG", false);
	if (debug) {
		args.AppendArg("-D");
	}

#if !defined(WIN32)
	// On UNIX, we need to tell the procd to allow connections from the
	// condor user
	//
	args.AppendArg("-C");
	args.AppendArg(get_condor_uid());
#endif

#if defined(WIN32)
	// on Windows, we need to tell the procd what program to use to send
	// softkills
	//
	char* softkill_path = param("WINDOWS_SOFTKILL");
	if ( softkill_path == NULL ) {
		dprintf(D_ALWAYS,
		        "WINDOWS_SOFTKILL undefined; "
		        	"ProcD won't be able to send WM_CLOSE to jobs\n");
	}
	else {
		args.AppendArg("-K");
		args.AppendArg(softkill_path);
		free(softkill_path);
	}
#endif

#if defined(LINUX)
	// enable group-based tracking if a group ID range is given in the
	// config file
	//
	if (param_boolean("USE_GID_PROCESS_TRACKING", false)) {
		if (!can_switch_ids() && !privsep_enabled()) {
			EXCEPT("USE_GID_PROCESS_TRACKING enabled, but can't modify "
			           "the group list of our children unless running as "
			           "root or using PrivSep");
		}
		int min_tracking_gid = param_integer("MIN_TRACKING_GID", 0);
		if (min_tracking_gid == 0) {
			EXCEPT("USE_GID_PROCESS_TRACKING enabled, "
			           "but MIN_TRACKING_GID is %d\n",
			       min_tracking_gid);
		}
		int max_tracking_gid = param_integer("MAX_TRACKING_GID", 0);
		if (max_tracking_gid == 0) {
			EXCEPT("USE_GID_PROCESS_TRACKING enabled, "
			           "but MAX_TRACKING_GID is %d\n",
			       max_tracking_gid);
		}
		if (min_tracking_gid > max_tracking_gid) {
			EXCEPT("invalid tracking gid range: %d - %d\n",
			       min_tracking_gid,
			       max_tracking_gid);
		}
		args.AppendArg("-G");
		args.AppendArg(min_tracking_gid);
		args.AppendArg(max_tracking_gid);
	}
#endif

	// for the GLEXEC_JOB feature, we'll need to pass the ProcD paths
	// to glexec and the condor_glexec_kill script
	//
	if (param_boolean("GLEXEC_JOB", false)) {
		args.AppendArg("-I");
		char* libexec = param("LIBEXEC");
		if (libexec == NULL) {
			EXCEPT("GLEXEC_JOB is defined, but LIBEXEC not configured");
		}
		MyString glexec_kill;
		glexec_kill.formatstr("%s/condor_glexec_kill", libexec);
		free(libexec);
		args.AppendArg(glexec_kill.Value());
		char* glexec = param("GLEXEC");
		if (glexec == NULL) {
			EXCEPT("GLEXEC_JOB is defined, but GLEXEC not configured");
		}
		args.AppendArg(glexec);
		free(glexec);
		int glexec_retries = param_integer("GLEXEC_RETRIES",3,0);
		int glexec_retry_delay = param_integer("GLEXEC_RETRY_DELAY",5,0);
		args.AppendArg(glexec_retries);
		args.AppendArg(glexec_retry_delay);
	}

	// done constructing the argument list; now register a reaper for
	// notification when the procd exits
	//
	if (m_reaper_id == FALSE) {
		m_reaper_id = daemonCore->Register_Reaper(
			"condor_procd reaper",
			(ReaperHandlercpp)&ProcFamilyProxyReaperHelper::procd_reaper,
			"condor_procd reaper",
			m_reaper_helper
		);
	}
	if (m_reaper_id == FALSE) {
		dprintf(D_ALWAYS,
		        "start_procd: unable to register a reaper for the procd\n");
		return false;
	}

	// we start the procd with a pipe coming back to us on its stderr.
	// the procd will close this pipe after it starts listening for
	// commands.
	//
	int pipe_ends[2];
	if (daemonCore->Create_Pipe(pipe_ends) == FALSE) {
		dprintf(D_ALWAYS, "start_procd: error creating pipe for the procd\n");
		return false;
	}
	int std_io[3];
	std_io[0] = -1;
	std_io[1] = -1;
	std_io[2] = pipe_ends[1];

	// use Create_Process to start the procd
	//
	if (privsep_enabled()) {
		m_procd_pid = privsep_spawn_procd(exe.Value(),
		                                  args,
		                                  std_io,
		                                  m_reaper_id);
	}
	else {
		m_procd_pid = daemonCore->Create_Process(exe.Value(),
		                                         args,
		                                         PRIV_ROOT,
		                                         m_reaper_id,
		                                         FALSE,
		                                         &env,
		                                         NULL,
		                                         NULL,
		                                         NULL,
		                                         std_io);
	}
	if (m_procd_pid == FALSE) {
		dprintf(D_ALWAYS, "start_procd: unable to execute the procd\n");
		daemonCore->Close_Pipe(pipe_ends[0]);
		daemonCore->Close_Pipe(pipe_ends[1]);
		m_procd_pid = -1;
		return false;
	}

	// now close the pipe end we handed to the child and then block on the
	// pipe until it closes (which tells us the procd is listening for
	// commands)
	//
	if (daemonCore->Close_Pipe(pipe_ends[1]) == FALSE) {
		dprintf(D_ALWAYS, "error closing procd's pipe end\n");
		daemonCore->Shutdown_Graceful(m_procd_pid);
		daemonCore->Close_Pipe(pipe_ends[0]);
		m_procd_pid = -1;
		return false;
	}
	const int MAX_PROCD_ERR_LEN = 80;
	char err_msg[MAX_PROCD_ERR_LEN + 1];
	int ret = daemonCore->Read_Pipe(pipe_ends[0], err_msg, MAX_PROCD_ERR_LEN);
	if (ret != 0) {
		daemonCore->Shutdown_Graceful(m_procd_pid);
		daemonCore->Close_Pipe(pipe_ends[0]);
		m_procd_pid = -1;
		if (ret == -1) {
			dprintf(D_ALWAYS, "start_procd: error reading pipe from procd\n");
			return false;
		}
		err_msg[ret] = '\0';
		dprintf(D_ALWAYS,
		        "start_procd: error received from procd: %s\n",
		        err_msg);
		return false;
	}
	if (daemonCore->Close_Pipe(pipe_ends[0]) == FALSE) {
		dprintf(D_ALWAYS, "start_procd: error closing pipe to procd\n");
		daemonCore->Shutdown_Graceful(m_procd_pid);
		m_procd_pid = -1;
		return false;
	}

	// OK, the ProcD's up and running!
	//
	return true;
}
Beispiel #28
0
int main(int argc, char *argv[]) {

    MyString my_full_name;
    const char *full_name;
    char* pw = NULL;
    struct StoreCredOptions options;
    int result = FAILURE_ABORTED;
    bool pool_password_arg = false;
    bool pool_password_delete = false;
    Daemon *daemon = NULL;
    char *credd_host;

    MyName = condor_basename(argv[0]);

    // load up configuration file
    myDistro->Init( argc, argv );
    config();

    if (!parseCommandLine(&options, argc, argv)) {
        goto cleanup;
    }

    // if -h was given, just print usage
    if (options.help || (options.mode == 0)) {
        usage();
        goto cleanup;
    }

#if !defined(WIN32)
    // if the -f argument was given, we just want to prompt for a password
    // and write it to a file (in our weirdo XORed format)
    //
    if (options.password_file != NULL) {
        if (options.pw[0] == '\0') {
            pw = get_password();
            printf("\n");
        }
        else {
            pw = strnewp(options.pw);
            SecureZeroMemory(options.pw, MAX_PASSWORD_LENGTH + 1);
        }
        result = write_password_file(options.password_file, pw);
        SecureZeroMemory(pw, strlen(pw));
        if (result != SUCCESS) {
            fprintf(stderr,
                    "error writing password file: %s\n",
                    options.password_file);
        }
        goto cleanup;
    }
#endif

    // determine the username to use
    if ( strcmp(options.username, "") == 0 ) {
        // default to current user and domain
        char* my_name = my_username();
        char* my_domain = my_domainname();

        my_full_name.formatstr("%s@%s", my_name, my_domain);
        if ( my_name) {
            free(my_name);
        }
        if ( my_domain) {
            free(my_domain);
        }
        my_name = my_domain = NULL;
    } else if (strcmp(options.username, POOL_PASSWORD_USERNAME) == 0) {
#if !defined(WIN32)
        // we don't support querying the pool password on UNIX
        // (since it is not possible to do so through the
        //  STORE_POOL_CRED command)
        if (options.mode == QUERY_MODE) {
            fprintf(stderr, "Querying the pool password is not supported.\n");
            goto cleanup;
        }
#endif
        // append the correct domain name if we're using the pool pass
        // we first try POOL_PASSWORD_DOMAIN, then UID_DOMAIN
        pool_password_arg = true;
        char *domain;
        if ((domain = param("SEC_PASSWORD_DOMAIN")) == NULL) {
            if ((domain = param("UID_DOMAIN")) == NULL) {
                fprintf(stderr, "ERROR: could not domain for pool password\n");
                goto cleanup;
            }
        }
        my_full_name.formatstr(POOL_PASSWORD_USERNAME "@%s", domain);
        free(domain);
    } else {
        // username was specified on the command line
        my_full_name += options.username;
    }
    full_name = my_full_name.Value();
    printf("Account: %s\n\n", full_name);

    // determine where to direct our command
    daemon = NULL;
    credd_host = NULL;
    if (options.daemonname != NULL) {
        if (pool_password_arg && (options.mode != QUERY_MODE)) {
            // daemon named on command line; go to master for pool password
            //printf("sending command to master: %s\n", options.daemonname);
            daemon = new Daemon(DT_MASTER, options.daemonname);
        }
        else {
            // daemon named on command line; go to schedd for user password
            //printf("sending command to schedd: %s\n", options.daemonname);
            daemon = new Daemon(DT_SCHEDD, options.daemonname);
        }
    }
    else if (!pool_password_arg && ((credd_host = param("CREDD_HOST")) != NULL)) {
        // no daemon given, use credd for user passwords if CREDD_HOST is defined
        // (otherwise, we use the local schedd)
        //printf("sending command to CREDD: %s\n", credd_host);
        daemon = new Daemon(DT_CREDD);
    }
    else {
        //printf("sending command to local daemon\n");
    }

    // flag the case where we're deleting the pool password
    if (pool_password_arg && (options.mode == DELETE_MODE)) {
        pool_password_delete = true;
    }

    switch (options.mode) {
    case ADD_MODE:
    case DELETE_MODE:
        if (!pool_password_delete) {
            if ( strcmp(options.pw, "") == 0 ) {
                // get password from the user.
                pw = get_password();
                printf("\n\n");
            } else {
                // got the passwd from the command line.
                pw = strnewp(options.pw);
                SecureZeroMemory(options.pw, MAX_PASSWORD_LENGTH);
            }
        }
        if ( pw || pool_password_delete) {
            result = store_cred(full_name, pw, options.mode, daemon);
            if ((result == FAILURE_NOT_SECURE) && goAheadAnyways()) {
                // if user is ok with it, send the password in the clear
                result = store_cred(full_name, pw, options.mode, daemon, true);
            }
            if (pw) {
                SecureZeroMemory(pw, strlen(pw));
                delete[] pw;
            }
        }
        break;
    case QUERY_MODE:
        result = queryCredential(full_name, daemon);
        break;
#if defined(WIN32)
    case CONFIG_MODE:
        return interactive();
        break;
#endif
    default:
        fprintf(stderr, "Internal error\n");
        goto cleanup;
    }

    // output result of operation
    switch (result) {
    case SUCCESS:
        if (options.mode == QUERY_MODE) {
            printf("A credential is stored and is valid.\n");
        }
        else {
            printf("Operation succeeded.\n");
        }
        break;

    case FAILURE:
        printf("Operation failed.\n");
        if (pool_password_arg && (options.mode != QUERY_MODE)) {
            printf("    Make sure you have CONFIG access to the target Master.\n");
        }
        else {
            printf("    Make sure your ALLOW_WRITE setting includes this host.\n");
        }
        break;

    case FAILURE_BAD_PASSWORD:
        if (options.mode == QUERY_MODE) {
            printf("A credential is stored, but it is invalid. "
                   "Run 'condor_store_cred add' again.\n");
        }
        else {
            printf("Operation failed: bad password.\n");
        }
        break;

    case FAILURE_NOT_FOUND:
        if (options.mode == QUERY_MODE) {
            printf("No credential is stored.\n");
        }
        else {
            printf("Operation failed: username not found.\n");
        }
        break;

    case FAILURE_NOT_SECURE:
    case FAILURE_ABORTED:
        printf("Operation aborted.\n");
        break;

    case FAILURE_NOT_SUPPORTED:
        printf("Operation failed.\n"
               "    The target daemon is not running as SYSTEM.\n");
        break;

    default:
        fprintf(stderr, "Operation failed: unknown error code\n");
    }

cleanup:
    if (options.daemonname) {
        delete[] options.daemonname;
    }
    if (daemon) {
        delete daemon;
    }

    if ( result == SUCCESS ) {
        return 0;
    } else {
        return 1;
    }
}
Beispiel #29
0
int
main(int argc, char *argv[])
{
	char	*arg;
	int		nArgs = 0;				// number of args 
	int	 i, result;
	char* pool = NULL;
	char* scheddName = NULL;
	char* scheddAddr = NULL;
	MyString method;
	char *tmp;

	myDistro->Init( argc, argv );
	MyName = condor_basename(argv[0]);
	config();

#if !defined(WIN32)
	install_sig_handler(SIGPIPE, SIG_IGN );
#endif

	// dig around in the config file looking for what the config file says
	// about getting files from Condor. This defaults with the global variable
	// initialization.
	tmp = param( "SANDBOX_TRANSFER_METHOD" );
	if ( tmp != NULL ) {
		method = tmp;
		free( tmp );
		string_to_stm( method, st_method );
	}

	char **args = (char **)malloc(sizeof(char *) * argc); // args 
	if ( ! args) exit(2);

	// parse the arguments.
	for( argv++; (arg = *argv); argv++ ) {
		if( arg[0] == '-' ) {
			if( ! arg[1] ) {
				usage();
			}
			switch( arg[1] ) {
			case 'd':
				// dprintf to console
				dprintf_set_tool_debug("TOOL", 0);
				break;
			case 'c':
				args[nArgs] = arg;
				nArgs++;
				argv++;
				if( ! *argv ) {
					fprintf( stderr, 
							 "%s: -constraint requires another argument\n", 
							 MyName);
					exit(1);
				}				
				args[nArgs] = *argv;
				nArgs++;
				break;
			case 'a':
				if( arg[2] && arg[2] == 'd' ) {
					argv++;
					if( ! *argv ) {
						fprintf( stderr, 
								 "%s: -addr requires another argument\n", 
								 MyName);
						exit(1);
					}				
					if( is_valid_sinful(*argv) ) {
						scheddAddr = strdup(*argv);
						if( ! scheddAddr ) {
							fprintf( stderr, "Out of Memory!\n" );
							exit(1);
						}
					} else {
						fprintf( stderr, 
								 "%s: \"%s\" is not a valid address\n",
								 MyName, *argv );
						fprintf( stderr, "Should be of the form "
								 "<ip.address.here:port>\n" );
						fprintf( stderr, 
								 "For example: <123.456.789.123:6789>\n" );
						exit( 1 );
					}
					break;
				}
				All = true;
				break;
			case 'n': 
				// use the given name as the schedd name to connect to
				argv++;
				if( ! *argv ) {
					fprintf( stderr, "%s: -name requires another argument\n", 
							 MyName);
					exit(1);
				}			
				if ( scheddName ) free(scheddName);
				scheddName = strdup(*argv);
				break;
			case 'p':
				// use the given name as the central manager to query
				argv++;
				if( ! *argv ) {
					fprintf( stderr, "%s: -pool requires another argument\n", 
							 MyName);
					exit(1);
				}				
				if( pool ) {
					free( pool );
				}
				pool = strdup( *argv );
				break;
			case 's':
				argv++;
				if( ! *argv ) {
					fprintf( stderr, "%s: -stm requires another argument\n", 
							 MyName);
					exit(1);
				}				
				method = *argv;
				string_to_stm(method, st_method);
				break;
			case 'v':
				version();
				break;
			case 'h':
				usage(0);
				break;
			default:
				fprintf( stderr, "Unrecognized option: %s\n", arg ); 
				usage();
				break;
			}
		} else {
			if( All ) {
					// If -all is set, there should be no other
					// constraint arguments.
				usage();
			}
			args[nArgs] = arg;
			nArgs++;
		}
	}

	// Check to make sure we have a valid sandbox transfer mechanism.
	if (st_method == STM_UNKNOWN) {
		fprintf( stderr,
			"%s: Unknown sandbox transfer method: %s\n", MyName,
			method.Value());
		usage();
		exit(1);
	}

	if( ! (All || nArgs) ) {
			// We got no indication of what to act on


		fprintf( stderr, "You did not specify any jobs\n" ); 
		usage();
	}

		// We're done parsing args, now make sure we know how to
		// contact the schedd. 
	if( ! scheddAddr ) {
			// This will always do the right thing, even if either or
			// both of scheddName or pool are NULL.
		schedd = new DCSchedd( scheddName, pool );
	} else {
		schedd = new DCSchedd( scheddAddr );
	}
	if( ! schedd->locate() ) {
		fprintf( stderr, "%s: %s\n", MyName, schedd->error() ); 
		exit( 1 );
	}

		// Process the args.
	if( All ) {
		handleAll();
	} else {
		for(i = 0; i < nArgs; i++) {
			if( match_prefix( args[i], "-constraint" ) ) {
				i++;
				addConstraint( args[i] );
			} else {
				procArg(args[i]);
			}
		}
	}

		// Sanity check: make certain we now have a constraint
	if ( global_constraint.Length() <= 0 ) {			
		fprintf( stderr, "Unable to create a job constraint!\n");
		exit(1);
	}

	fprintf(stdout,"Fetching data files...\n");

	switch(st_method) {
		case STM_USE_SCHEDD_ONLY:
			{ // start block

			// Get the sandbox directly from the schedd.
			// And now, do the work.
			CondorError errstack;
			result = schedd->receiveJobSandbox(global_constraint.Value(),
				&errstack);
			if ( !result ) {
				fprintf( stderr, "\n%s\n", errstack.getFullText(true).c_str() );
				fprintf( stderr, "ERROR: Failed to spool job files.\n" );
				exit(1);
			}
		
			// All done
			return 0;

			} //end block
			break;

		case STM_USE_TRANSFERD:
			{ // start block

			// NEW METHOD where we ask the schedd for a transferd, then get the
			// files from the transferd

			CondorError errstack;
			ClassAd respad;
			int invalid;
			MyString reason;
			MyString td_sinful;
			MyString td_cap;

			result = schedd->requestSandboxLocation(FTPD_DOWNLOAD, 
				global_constraint, FTP_CFTP, &respad, &errstack);
			if ( !result ) {
				fprintf( stderr, "\n%s\n", errstack.getFullText(true).c_str() );
				fprintf( stderr, "ERROR: Failed to spool job files.\n" );
				exit(1);
			}

			respad.LookupInteger(ATTR_TREQ_INVALID_REQUEST, invalid);
			if (invalid == TRUE) {
				fprintf( stderr, "ERROR: Failed to spool job files.\n" );
				respad.LookupString(ATTR_TREQ_INVALID_REASON, reason);
				fprintf( stderr, "%s\n", reason.Value());
				exit(EXIT_FAILURE);
			}

			respad.LookupString(ATTR_TREQ_TD_SINFUL, td_sinful);
			respad.LookupString(ATTR_TREQ_CAPABILITY, td_cap);

			dprintf(D_ALWAYS, 
				"td: %s, cap: %s\n", td_sinful.Value(), td_cap.Value());

			DCTransferD dctd(td_sinful.Value());

			result = dctd.download_job_files(&respad, &errstack);
			if ( !result ) {
				fprintf( stderr, "\n%s\n", errstack.getFullText(true).c_str() );
				fprintf( stderr, "ERROR: Failed to spool job files.\n" );
				exit(1);
			}

			} // end block
		break;

		default:
			EXCEPT("PROGRAMMER ERROR: st_method must be known.");
			break;
		}

	// All done
	return 0;
}
Beispiel #30
0
//-------------------------------------------------------------------------
bool
GetConfigAndAttrs( /* const */ StringList &dagFiles, bool useDagDir, 
			MyString &configFile, StringList &attrLines, MyString &errMsg )
{
	bool		result = true;

		// Note: destructor will change back to original directory.
	TmpDir		dagDir;

	dagFiles.rewind();
	char *dagFile;
	while ( (dagFile = dagFiles.next()) != NULL ) {

			//
			// Change to the DAG file's directory if necessary, and
			// get the filename we need to use for it from that directory.
			//
		const char *	newDagFile;
		if ( useDagDir ) {
			MyString	tmpErrMsg;
			if ( !dagDir.Cd2TmpDirFile( dagFile, tmpErrMsg ) ) {
				AppendError( errMsg,
						MyString("Unable to change to DAG directory ") +
						tmpErrMsg );
				return false;
			}
			newDagFile = condor_basename( dagFile );
		} else {
			newDagFile = dagFile;
		}

		StringList		configFiles;

			// Note: destructor will close file.
		MultiLogFiles::FileReader reader;
		errMsg = reader.Open( newDagFile );
		if ( errMsg != "" ) {
			return false;
		}

		MyString logicalLine;
		while ( reader.NextLogicalLine( logicalLine ) ) {
			if ( logicalLine != "" ) {
					// Note: StringList constructor removes leading
					// whitespace from lines.
				StringList tokens( logicalLine.Value(), " \t" );
				tokens.rewind();

				const char *firstToken = tokens.next();
				if ( !strcasecmp( firstToken, "config" ) ) {

						// Get the value.
					const char *newValue = tokens.next();
					if ( !newValue || !strcmp( newValue, "" ) ) {
						AppendError( errMsg, "Improperly-formatted "
									"file: value missing after keyword "
									"CONFIG" );
			    		result = false;
					} else {

							// Add the value we just found to the config
							// files list (if it's not already in the
							// list -- we don't want duplicates).
						configFiles.rewind();
						char *existingValue;
						bool alreadyInList = false;
						while ( ( existingValue = configFiles.next() ) ) {
							if ( !strcmp( existingValue, newValue ) ) {
								alreadyInList = true;
							}
						}

						if ( !alreadyInList ) {
								// Note: append copies the string here.
							configFiles.append( newValue );
						}
					}

					//some DAG commands are needed for condor_submit_dag, too...
				} else if ( !strcasecmp( firstToken, "SET_JOB_ATTR" ) ) {
						// Strip of DAGMan-specific command name; the
						// rest we pass to the submit file.
					logicalLine.replaceString( "SET_JOB_ATTR", "" );
					logicalLine.trim();
					if ( logicalLine == "" ) {
						AppendError( errMsg, "Improperly-formatted "
									"file: value missing after keyword "
									"SET_JOB_ATTR" );
						result = false;
					} else {
						attrLines.append( logicalLine.Value() );
					}
				}
			}
		}
	
		reader.Close();

			//
			// Check the specified config file(s) against whatever we
			// currently have, setting the config file if it hasn't
			// been set yet, flagging an error if config files conflict.
			//
		configFiles.rewind();
		char *		cfgFile;
		while ( (cfgFile = configFiles.next()) ) {
			MyString	cfgFileMS = cfgFile;
			MyString	tmpErrMsg;
			if ( MakePathAbsolute( cfgFileMS, tmpErrMsg ) ) {
				if ( configFile == "" ) {
					configFile = cfgFileMS;
				} else if ( configFile != cfgFileMS ) {
					AppendError( errMsg, MyString("Conflicting DAGMan ") +
								"config files specified: " + configFile +
								" and " + cfgFileMS );
					result = false;
				}
			} else {
				AppendError( errMsg, tmpErrMsg );
				result = false;
			}
		}

			//
			// Go back to our original directory.
			//
		MyString	tmpErrMsg;
		if ( !dagDir.Cd2MainDir( tmpErrMsg ) ) {
			AppendError( errMsg,
					MyString("Unable to change to original directory ") +
					tmpErrMsg );
			result = false;
		}
	}

	return result;
}