Example #1
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 );
}
Example #2
0
bool
glexec_starter_prepare(const char* starter_path,
                       const char* proxy_file,
                       const ArgList& orig_args,
                       const Env* orig_env,
                       const int orig_std_fds[3],
                       ArgList& glexec_args,
                       Env& glexec_env,
                       int glexec_std_fds[3])
{
    // if GLEXEC_STARTER is set, use glexec to invoke the
    // starter (or fail if we can't). this involves:
    //   - verifying that we have a delegated proxy from
    //     the user stored, since we need to hand it to
    //     glexec so it can look up the UID/GID
    //   - invoking 'glexec_starter_setup.sh' via glexec to
    //     setup the starter's "private directory" for a copy
    //     of the job's proxy to go into, as well as the StarterLog
    //     and execute dir
    //   - adding the contents of the GLEXEC and config param
    //     and the path to 'condor_glexec_wrapper' to the front
    //     of the command line
    //   - setting up glexec's environment (setting the
    //     mode, handing off the proxy, etc.)
    //   - creating a UNIX-domain socket to use to communicate
    //     with our wrapper script, and munging the std_fds
    //     array

    // verify that we have a stored proxy
    if( proxy_file == NULL ) {
        dprintf( D_ALWAYS,
                 "cannot use glexec to spawn starter: no proxy "
                 "(is GLEXEC_STARTER set in the shadow?)\n" );
        return false;
    }

    // using the file name of the proxy that was stashed ealier, construct
    // the name of the starter's "private directory". the naming scheme is
    // (where XXXXXX is randomly generated via condor_mkstemp):
    //   - $(GLEXEC_USER_DIR)/startd-tmp-proxy-XXXXXX
    //       - startd's copy of the job's proxy
    //   - $(GLEXEC_USER_DIR)/starter-tmp-dir-XXXXXX
    //       - starter's private dir
    //
    MyString glexec_private_dir;
    char* dir_part = condor_dirname(proxy_file);
    ASSERT(dir_part != NULL);
    glexec_private_dir = dir_part;
    free(dir_part);
    glexec_private_dir += "/starter-tmp-dir-";
    const char* random_part = proxy_file;
    random_part += strlen(random_part) - 6;
    glexec_private_dir += random_part;
    dprintf(D_ALWAYS,
            "GLEXEC: starter private dir is '%s'\n",
            glexec_private_dir.Value());

    // get the glexec command line prefix from config
    char* glexec_argstr = param( "GLEXEC" );
    if ( ! glexec_argstr ) {
        dprintf( D_ALWAYS,
                 "cannot use glexec to spawn starter: "
                 "GLEXEC not given in config\n" );
        return false;
    }

    // cons up a command line for my_system. we'll run the
    // script $(LIBEXEC)/glexec_starter_setup.sh, which
    // will create the starter's "private directory" (and
    // its log and execute subdirectories). the value of
    // glexec_private_dir will be passed as an argument to
    // the script

    // parse the glexec args for invoking glexec_starter_setup.sh.
    // do not free them yet, except on an error, as we use them
    // again below.
    MyString setup_err;
    ArgList  glexec_setup_args;
    glexec_setup_args.SetArgV1SyntaxToCurrentPlatform();
    if( ! glexec_setup_args.AppendArgsV1RawOrV2Quoted( glexec_argstr,
            &setup_err ) ) {
        dprintf( D_ALWAYS,
                 "GLEXEC: failed to parse GLEXEC from config: %s\n",
                 setup_err.Value() );
        free( glexec_argstr );
        return 0;
    }

    // set up the rest of the arguments for the glexec setup script
    char* tmp = param("LIBEXEC");
    if (tmp == NULL) {
        dprintf( D_ALWAYS,
                 "GLEXEC: LIBEXEC not defined; can't find setup script\n" );
        free( glexec_argstr );
        return 0;
    }
    MyString libexec = tmp;
    free(tmp);
    MyString setup_script = libexec;
    setup_script += "/glexec_starter_setup.sh";
    glexec_setup_args.AppendArg(setup_script.Value());
    glexec_setup_args.AppendArg(glexec_private_dir.Value());

    // debug info.  this display format totally screws up the quoting, but
    // my_system gets it right.
    MyString disp_args;
    glexec_setup_args.GetArgsStringForDisplay(&disp_args, 0);
    dprintf (D_ALWAYS, "GLEXEC: about to glexec: ** %s **\n",
             disp_args.Value());

    // the only thing actually needed by glexec at this point is the cert, so
    // that it knows who to map to.  the pipe outputs the username that glexec
    // ended up using, on a single text line by itself.
    SetEnv( "GLEXEC_CLIENT_CERT", proxy_file );

    // create the starter's private dir
    int ret = my_system(glexec_setup_args);

    // clean up
    UnsetEnv( "GLEXEC_CLIENT_CERT");

    if ( ret != 0 ) {
        dprintf(D_ALWAYS,
                "GLEXEC: error creating private dir: my_system returned %d\n",
                ret);
        free( glexec_argstr );
        return 0;
    }

    // now prepare the starter command line, starting with glexec and its
    // options (if any), then condor_glexec_wrapper.
    MyString err;
    if( ! glexec_args.AppendArgsV1RawOrV2Quoted( glexec_argstr,
            &err ) ) {
        dprintf( D_ALWAYS,
                 "failed to parse GLEXEC from config: %s\n",
                 err.Value() );
        free( glexec_argstr );
        return 0;
    }
    free( glexec_argstr );
    MyString wrapper_path = libexec;
    wrapper_path += "/condor_glexec_wrapper";
    glexec_args.AppendArg(wrapper_path.Value());

    // complete the command line by adding in the original
    // arguments. we also make sure that the full path to the
    // starter is given
    int starter_path_pos = glexec_args.Count();
    glexec_args.AppendArgsFromArgList( orig_args );
    glexec_args.RemoveArg( starter_path_pos );
    glexec_args.InsertArg( starter_path, starter_path_pos );

    // set up the environment stuff
    if( orig_env ) {
        // first merge in the original
        glexec_env.MergeFrom( *orig_env );
    }

    // GLEXEC_MODE - get account from lcmaps
    glexec_env.SetEnv( "GLEXEC_MODE", "lcmaps_get_account" );

    // GLEXEC_CLIENT_CERT - cert to use for the mapping
    glexec_env.SetEnv( "GLEXEC_CLIENT_CERT", proxy_file );

#if defined(HAVE_EXT_GLOBUS) && !defined(SKIP_AUTHENTICATION)
    // GLEXEC_SOURCE_PROXY -  proxy to provide to the child
    //                        (file is owned by us)
    glexec_env.SetEnv( "GLEXEC_SOURCE_PROXY", proxy_file );
    dprintf (D_ALWAYS,
             "GLEXEC: setting GLEXEC_SOURCE_PROXY to %s\n",
             proxy_file);

    // GLEXEC_TARGET_PROXY - child-owned file to copy its proxy to.
    // this needs to be in a directory owned by that user, and not world
    // writable.  glexec enforces this.  hence, all the whoami/mkdir mojo
    // above.
    MyString child_proxy_file = glexec_private_dir;
    child_proxy_file += "/glexec_starter_proxy";
    dprintf (D_ALWAYS, "GLEXEC: setting GLEXEC_TARGET_PROXY to %s\n",
             child_proxy_file.Value());
    glexec_env.SetEnv( "GLEXEC_TARGET_PROXY", child_proxy_file.Value() );

    // _CONDOR_GSI_DAEMON_PROXY - starter's proxy
    MyString var_name;
    var_name.sprintf("_CONDOR_%s", STR_GSI_DAEMON_PROXY);
    glexec_env.SetEnv( var_name.Value(), child_proxy_file.Value() );
    var_name.sprintf("_condor_%s", STR_GSI_DAEMON_PROXY);
    glexec_env.SetEnv( var_name.Value(), child_proxy_file.Value() );
#endif

    // the EXECUTE dir should be owned by the mapped user.  we created this
    // earlier, and now we override it in the condor_config via the
    // environment.
    MyString execute_dir = glexec_private_dir;
    execute_dir += "/execute";
    glexec_env.SetEnv ( "_CONDOR_EXECUTE", execute_dir.Value());
    glexec_env.SetEnv ( "_condor_EXECUTE", execute_dir.Value());

    // the LOG dir should be owned by the mapped user.  we created this
    // earlier, and now we override it in the condor_config via the
    // environment.
    MyString log_dir = glexec_private_dir;
    log_dir += "/log";
    glexec_env.SetEnv ( "_CONDOR_LOG", log_dir.Value());
    glexec_env.SetEnv ( "_condor_LOG", log_dir.Value());
    glexec_env.SetEnv ( "_CONDOR_LOCK", log_dir.Value());
    glexec_env.SetEnv ( "_condor_LOCK", log_dir.Value());

    // PROCD_ADDRESS: the Starter that we are about to create will
    // not have access to our ProcD. we'll explicitly set PROCD_ADDRESS
    // to be in its LOG directory. the Starter will see that its
    // PROCD_ADDRESS knob is different from what it inherits in
    // CONDOR_PROCD_ADDRESS, and know it needs to create its own ProcD
    //
    MyString procd_address = log_dir;
    procd_address += "/procd_pipe";
    glexec_env.SetEnv( "_CONDOR_PROCD_ADDRESS", procd_address.Value() );
    glexec_env.SetEnv( "_condor_PROCD_ADDRESS", procd_address.Value() );

    // CONDOR_GLEXEC_STARTER_CLEANUP_FLAG: this serves as a flag in the
    // Starter's environment that it will check for in order to determine
    // whether to do GLEXEC_STARTER-specific cleanup
    //
    glexec_env.SetEnv( "CONDOR_GLEXEC_STARTER_CLEANUP_FLAG",
                       "CONDOR_GLEXEC_STARTER_CLEANUP_FLAG" );

    // now set up a socket pair for communication with
    // condor_glexec_wrapper
    //
    if (socketpair(PF_UNIX, SOCK_STREAM, 0, s_saved_sock_fds) == -1)
    {
        dprintf(D_ALWAYS,
                "GLEXEC: socketpair error: %s\n",
                strerror(errno));
        return false;
    }
    glexec_std_fds[0] = s_saved_sock_fds[1];
    if (orig_std_fds == NULL) {
        s_saved_starter_stdin = -1;
        glexec_std_fds[1] = glexec_std_fds[2] = -1;
    }
    else {
        s_saved_starter_stdin = orig_std_fds[0];
        glexec_std_fds[1] = orig_std_fds[1];
        glexec_std_fds[2] = orig_std_fds[2];
    }

    // save the environment we're handing back to the caller for use in
    // glexec_starter_handle_env()
    //
    s_saved_env.Clear();
    s_saved_env.MergeFrom(glexec_env);

    return true;
}
Example #3
0
GridUniverseLogic::gman_node_t *
GridUniverseLogic::StartOrFindGManager(const char* owner, const char* domain,
	   	const char* attr_value, const char* attr_name, int cluster, int proc)
{
	gman_node_t* gman_node;
	int pid;

		// If attr_value is an empty string, convert to NULL since code
		// after this point expects that.
	if ( attr_value && strlen(attr_value)==0 ) {
		attr_value = NULL;
		attr_name = NULL;
	}

	if ( (gman_node=lookupGmanByOwner(owner, attr_value, cluster, proc)) ) {
		// found it
		return gman_node;
	}

	// not found.  fire one up!  we want to run the GManager as the user.

	// but first, make certain we are not shutting down...
	if (!gman_pid_table) {
		// destructor has already been called; we are probably
		// closing down.
		return NULL;
	}


#ifndef WIN32
	if (owner && strcasecmp(owner, "root") == 0 ) {
		dprintf(D_ALWAYS, "Tried to start condor_gmanager as root.\n");
		return NULL;
	}
#endif

	dprintf( D_FULLDEBUG, "Starting condor_gmanager for owner %s (%d.%d)\n",
			owner, cluster, proc);

	char *gman_binary;
	gman_binary = param("GRIDMANAGER");
	if ( !gman_binary ) {
		dprintf(D_ALWAYS,"ERROR - GRIDMANAGER not defined in config file\n");
		return NULL;
	}

	ArgList args;
	MyString error_msg;

	args.AppendArg("condor_gridmanager");
	args.AppendArg("-f");

	char *gman_args = param("GRIDMANAGER_ARGS");

	if(!args.AppendArgsV1RawOrV2Quoted(gman_args,&error_msg)) {
		dprintf( D_ALWAYS, "ERROR: failed to parse gridmanager args: %s\n",
				 error_msg.Value());
		free(gman_binary);
		free(gman_args);
		return NULL;
	}
	free(gman_args);

	// build a constraint
	if ( !owner ) {
		dprintf(D_ALWAYS,"ERROR - missing owner field\n");
		free(gman_binary);
		return NULL;
	}
	MyString constraint;
	if ( !attr_name  ) {
		constraint.formatstr("(%s=?=\"%s\"&&%s==%d)",
						   ATTR_OWNER,owner,
						   ATTR_JOB_UNIVERSE,CONDOR_UNIVERSE_GRID);
	} else {
		constraint.formatstr("(%s=?=\"%s\"&&%s=?=\"%s\"&&%s==%d)",
						   ATTR_OWNER,owner,
						   attr_name,attr_value,
						   ATTR_JOB_UNIVERSE,CONDOR_UNIVERSE_GRID);

		args.AppendArg("-A");
		args.AppendArg(attr_value);
	}
	args.AppendArg("-C");
	args.AppendArg(constraint.Value());

	MyString full_owner_name(owner);
	if ( domain && *domain ) {
		full_owner_name.formatstr_cat( "@%s", domain );
	}
	args.AppendArg("-o");
	args.AppendArg(full_owner_name.Value());

	if (!init_user_ids(owner, domain)) {
		dprintf(D_ALWAYS,"ERROR - init_user_ids() failed in GRIDMANAGER\n");
		free(gman_binary);
		return NULL;
	}

	static bool first_time_through = true;
	if ( first_time_through ) {
		// Note: Because first_time_through is static, this block runs only 
		// once per schedd invocation.
		first_time_through = false;

		// Clean up any old / abandoned scratch dirs.
		dprintf(D_FULLDEBUG,"Checking for old gridmanager scratch dirs\n");
		char *prefix = temp_dir_path();
		ASSERT(prefix);
		Directory tmp( prefix, PRIV_USER );
		const char *f;
		char const *dot;
		int fname_pid;
		int mypid = daemonCore->getpid();
		int scratch_pre_len = strlen(scratch_prefix);
		while ( (f=tmp.Next()) ) {
				// skip regular files -- we only need to inspect subdirs
			if ( !tmp.IsDirectory() ) {
				continue;
			}
				// skip if it does not start with our prefix
			if ( strncmp(scratch_prefix,f,scratch_pre_len) ) {
				continue;
			}
				// skip if does not end w/ a pid
			dot = strrchr(f,'.');
			if ( !dot ) {
				continue;
			}
				// skip if this pid is still alive and not ours
			dot++;	// skip over period
			fname_pid = atoi(dot);
			if ( fname_pid != mypid && daemonCore->Is_Pid_Alive(fname_pid) ) {
					continue;
			}
				// if we made it here, blow away this subdir
			if ( tmp.Remove_Current_File() ) {
				dprintf(D_ALWAYS,"Removed old scratch dir %s\n",
				tmp.GetFullPath());
			}
		}	// end of while for cleanup of old scratch dirs

		dprintf(D_FULLDEBUG,"Done checking for old scratch dirs\n");			

		if (prefix != NULL) {
			free(prefix);
			prefix = NULL;
		}

	}	// end of once-per-schedd invocation block

	// Create a temp dir for the gridmanager and append proper
	// command-line arguments to tell where it is.
	bool failed = false;
	gman_node = new gman_node_t;
	char *finalpath = scratchFilePath(gman_node);
	priv_state saved_priv = set_user_priv();
	if ( (mkdir(finalpath,0700)) < 0 ) {
		// mkdir failed.  
		dprintf(D_ALWAYS,"ERROR - mkdir(%s,0700) failed in GRIDMANAGER, errno=%d (%s)\n",
				finalpath, errno, strerror(errno));
		failed = true;
	}
	set_priv(saved_priv);
	uninit_user_ids();
	args.AppendArg("-S");	// -S = "ScratchDir" argument
	args.AppendArg(finalpath);
	delete [] finalpath;
	if ( failed ) {
		// we already did dprintf reason to the log...
		free(gman_binary);
		delete gman_node;
		return NULL;
	}

	if(IsFulldebug(D_FULLDEBUG)) {
		MyString args_string;
		args.GetArgsStringForDisplay(&args_string);
		dprintf(D_FULLDEBUG,"Really Execing %s\n",args_string.Value());
	}

	pid = daemonCore->Create_Process( 
		gman_binary,			// Program to exec
		args,					// Command-line args
		PRIV_ROOT,				// Run as root, so it can switch to
		                        //   PRIV_CONDOR
		rid						// Reaper ID
		);

	free(gman_binary);

	if ( pid <= 0 ) {
		dprintf ( D_ALWAYS, "StartOrFindGManager: Create_Process problems!\n" );
		if (gman_node) delete gman_node;
		return NULL;
	}

	// If we made it here, we happily started up a new gridmanager process

	dprintf( D_ALWAYS, "Started condor_gmanager for owner %s pid=%d\n",
			owner,pid);

	// Make a new gman_node entry for our hashtable & insert it
	if ( !gman_node ) {
		gman_node = new gman_node_t;
	}
	gman_node->pid = pid;
	gman_node->owner[0] = '\0';
	gman_node->domain[0] = '\0';
	if ( owner ) {
		strcpy(gman_node->owner,owner);
	}
	if ( domain ) {
		strcpy(gman_node->domain,domain);
	}
	MyString owner_key(owner);
	if(attr_value){
		owner_key += attr_value;
	}
	if (cluster) {
		owner_key.formatstr_cat( "-%d.%d", cluster, proc );
	}

	ASSERT( gman_pid_table->insert(owner_key,gman_node) == 0 );

	// start timer to signal gridmanager if we haven't already
	if ( gman_node->add_timer_id == -1 ) {  // == -1 means no timer set
		gman_node->add_timer_id = daemonCore->Register_Timer(job_added_delay,
			GridUniverseLogic::SendAddSignal,
			"GridUniverseLogic::SendAddSignal");
		daemonCore->Register_DataPtr(gman_node);
	}

	// All done
	return gman_node;
}
Example #4
0
void
do_process_request(const ClassAd *inputAd, ClassAd *resultAd, const int req_number, 
				   const char *iwd, const char *stdio_iwd)
{
		// Check for inputAd
	if ( !inputAd ) {
		handle_process_request_error("No input ad",req_number,resultAd);
		return;
	}

		// Map the CMD specified in the input via the config file.
	MyString UnmappedJobName,JobName;
	if (inputAd->LookupString(ATTR_JOB_CMD,UnmappedJobName) == 0 ) {
			// no CMD specified.
		handle_process_request_error("No CMD specified",req_number,resultAd);
		return;
	}
	char *auth_commands = param("SOAPSHELL_AUTHORIZED_COMMANDS");
	StringList auth_list(auth_commands,",");
	if ( auth_commands ) free(auth_commands);
		// Each command needs four tuples; anything else is a misconfiguration
	if ( auth_list.number() % 4 != 0 ) {
		handle_process_request_error("Service is misconfigured: SOAPSHELL_AUTHORIZED_COMMANDS malformed",req_number,resultAd);
		return;
	}

	if ( auth_list.contains_anycase(UnmappedJobName.Value()) == TRUE ) {
		JobName = auth_list.next();
	}
	if ( JobName.IsEmpty() ) {
			// the CMD not authorized
		handle_process_request_error("Requested CMD not authorized via SOAPSHELL_AUTHORIZED_COMMANDS",req_number,resultAd);
		return;
	}

		// handle command line arguments.
	ArgList args;
	args.SetArgV1SyntaxToCurrentPlatform();
	args.AppendArg(JobName.Value());	// set argv[0] to command
	char *soapshell_args = auth_list.next();
	if ( soapshell_args && strcmp(soapshell_args,"*") ) {
		if(!args.AppendArgsV1RawOrV2Quoted(soapshell_args,NULL)) {
			dprintf( D_ALWAYS, "ERROR: SOAPSHELL_ARGS config macro invalid\n" );
		}
	} else if(!args.AppendArgsFromClassAd(inputAd,NULL)) {
		handle_process_request_error("Failed to setup CMD arguments",req_number,resultAd);
		return;
	}
		
		// handle the environment.
	Env job_env;
	char *env_str = auth_list.next();
	if ( env_str && strcmp(env_str,"*") ) {
		if(!job_env.MergeFromV1RawOrV2Quoted(env_str,NULL) ) {
			dprintf(D_ALWAYS,"ERROR: SOAPSHELL_ENVIRONMENT config macro invalid\n");
		}
	} else if(!job_env.MergeFrom(inputAd,NULL)) {
		// bad environment string in job ad!
		handle_process_request_error("Request has faulty environment string",req_number,resultAd);
		return;
	}

		// Write input files into iwd (we will write stdin later)
	if ( !write_input_files(inputAd, iwd) ) {
		// failed to write input files
		handle_process_request_error("Failed to write input files",req_number,resultAd);
		return;
	}

		// handle stdin, stdout, and stderr redirection
	const char* jobstdin_ = dircat(stdio_iwd,"stdin");
	MyString jobstdin(jobstdin_);
	const char* jobstdout_ = dircat(stdio_iwd,"stdout");
	MyString jobstdout(jobstdout_);
	const char* jobstderr_ = dircat(stdio_iwd,"stderr");
	MyString jobstderr(jobstderr_);
	delete [] jobstdin_;
	delete [] jobstdout_;
	delete [] jobstderr_;
	int flags = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND | O_LARGEFILE;
		// write stdin file is needed
	{
		char *input = NULL;
		unsigned char *output = NULL;
		int output_length = 0;
		int fd = -1;
		inputAd->LookupString(ATTR_JOB_INPUT,&input);
		if ( input ) {
			// Caller needs to free *output if non-NULL
			condor_base64_decode(input,&output,&output_length);
			if ( output ) {
				fd = safe_open_wrapper_follow( jobstdin.Value(), flags, 0666 );
				if ( fd > -1 ) {
					write(fd,output,output_length);
					close(fd);
				}
				free(output);
			}
			free(input);
			if ( fd < 0 ) {
				handle_process_request_error("Failed to write stdin",req_number,resultAd);
				return;
			}
		}
	}
	int fds[3]; 
		// initialize these to -2 to mean they're not specified.
		// -1 will be treated as an error.
	fds[0] = -2; fds[1] = -2; fds[2] = -2;	
	fds[0] = safe_open_wrapper_follow( jobstdin.Value(), O_RDONLY | O_LARGEFILE ); // stdin	
	fds[1] = safe_open_wrapper_follow( jobstdout.Value(), flags, 0666 );	// stdout
	fds[2] = safe_open_wrapper_follow( jobstderr.Value(), flags, 0666 );	// stderr
	/* Bail out if we couldn't open stdout/err files correctly */
	if( fds[1]==-1 || fds[2]==-1 ) {
		/* only close ones that had been opened correctly */
		for ( int i = 0; i <= 2; i++ ) {
			if ( fds[i] >= 0 ) {
				daemonCore->Close_FD ( fds[i] );
			}
		}
		handle_process_request_error("Failed to write stdout/err files",req_number,resultAd);
		return;
	}

		// Print what we are about to do to the log
	MyString args_string;
	args.GetArgsStringForDisplay(&args_string,1);
	dprintf( D_ALWAYS, "About to exec %s %s\n", JobName.Value(),
				 args_string.Value() );

		// Spawn a process, baby!!!
	int JobPid = daemonCore->Create_Process( JobName.Value(),	// executable
		                                     args,				// args
		                                     PRIV_UNKNOWN,		// priv_state - TODO
		                                     0,					// reaper id - TODO
		                                     FALSE,				// want_command_port
		                                     &job_env,			// job environment
		                                     iwd,				// job iwd
		                                     NULL,				// family_info - TODO
		                                     NULL,				// sock_inherit_list
		                                     fds				// stdio redirection
										);

		// NOTE: Create_Process() saves the errno for us if it is an
		// "interesting" error.
	char const *create_process_error = NULL;
	if(JobPid == FALSE && errno) create_process_error = strerror(errno);

		// now close the descriptors in fds array.  our child has inherited
		// them already, so we should close them so we do not leak descriptors.
	for ( int i = 0; i <= 2; i++ ) {
		if ( fds[i] >= 0 ) {
			daemonCore->Close_FD ( fds[i] );
		}
	}

	if ( JobPid == FALSE ) {
		JobPid = -1;
		MyString errormsg;
		errormsg.formatstr("Create_Process failed %s",create_process_error ? create_process_error : "");
		handle_process_request_error(errormsg.Value(),req_number,resultAd);
		return;
	}


	dprintf(D_ALWAYS,"Create_Process succeeded, pid=%d\n",JobPid);

		// TODO - For now, just deal w/ one at a time. :(
		// So for now just wait for the child to exit.
#ifdef WIN32
#error This service does not yet work on Windows
#else
	{
		int exit_status;
		pid_t pid;
		for (;;) {
			pid = wait(&exit_status);
			dprintf(D_FULLDEBUG,"WAIT returned %d, errno=%d\n",pid,errno);
			if (pid == JobPid ) break;
			if (pid == -1 && errno != EINTR) {
				EXCEPT("waitpid failed errno=%d",errno);
			}
		}
		if ( WIFEXITED(exit_status) ) {
			int status = WEXITSTATUS(exit_status);
			resultAd->Assign("EXIT_STATUS",status);
		}		
	}
#endif

		// Job has completed, exit status is in the ad.  Now put
		// the output files into the result ad.
	stash_output_file(resultAd, jobstdout.Value(), ATTR_JOB_OUTPUT);
	stash_output_file(resultAd, jobstderr.Value(), ATTR_JOB_ERROR);

}
Example #5
0
// I really need a good way to determine the type of a classad
// attribute.  Right now I just try all four possibilities, which is a
// horrible mess...
bool VirshType::CreateVirshConfigFile(const char*  /*filename*/)
{
  vmprintf(D_FULLDEBUG, "In VirshType::CreateVirshConfigFile\n");
  //  std::string name;
  char * tmp = param("LIBVIRT_XML_SCRIPT");
  if(tmp == NULL)
    {
      vmprintf(D_ALWAYS, "LIBVIRT_XML_SCRIPT not defined\n");
      return false;
    }
  // This probably needs some work...
  ArgList args;
  args.AppendArg(tmp);
  free(tmp);

  // We might want to have specific debugging output enabled in the
  // helper script; however, it is not clear where that output should
  // go.  This gives us a way to do so even in cases where the script
  // is unable to read from condor_config (why would this ever
  // happen?)
  tmp = param("LIBVIRT_XML_SCRIPT_ARGS");
  if(tmp != NULL)
    {
      MyString errormsg;
      args.AppendArgsV1RawOrV2Quoted(tmp,&errormsg);
      free(tmp);
    }
  StringList input_strings, output_strings, error_strings;
  MyString classad_string;
  m_classAd.sPrint(classad_string);
  classad_string += VMPARAM_XEN_BOOTLOADER;
  classad_string += " = \"";
  classad_string += m_xen_bootloader;
  classad_string += "\"\n";
  if(classad_string.find(VMPARAM_XEN_INITRD) < 1)
    {
      classad_string += VMPARAM_XEN_INITRD;
      classad_string += " = \"";
      classad_string += m_xen_initrd_file;
      classad_string += "\"\n";
    }
  if(!m_vm_bridge_interface.empty())
    {
      classad_string += VMPARAM_BRIDGE_INTERFACE;
      classad_string += " = \"";
      classad_string += m_vm_bridge_interface.c_str();
      classad_string += "\"\n";
    }
  if(classad_string.find(ATTR_JOB_VM_NETWORKING_TYPE) < 1)
    {
      classad_string += ATTR_JOB_VM_NETWORKING_TYPE;
      classad_string += " = \"";
      classad_string += m_vm_networking_type.Value();
      classad_string += "\"\n";
    }
  input_strings.append(classad_string.Value());
  
  tmp = input_strings.print_to_string();
  vmprintf(D_FULLDEBUG, "LIBVIRT_XML_SCRIPT_ARGS input_strings= %s\n", tmp);
  free(tmp);

  int ret = systemCommand(args, PRIV_ROOT, &output_strings, &input_strings, &error_strings, false);
  error_strings.rewind();
  if(ret != 0)
    {
      vmprintf(D_ALWAYS, "XML helper script could not be executed\n");
      output_strings.rewind();
      // If there is any output from the helper, write it to the debug
      // log.  Presumably, this is separate from the script's own
      // debug log.
      while((tmp = error_strings.next()) != NULL)
	{
	  vmprintf(D_FULLDEBUG, "Helper stderr output: %s\n", tmp);
	}
      return false;
    }
  error_strings.rewind();
  while((tmp = error_strings.next()) != NULL)
    {
      vmprintf(D_ALWAYS, "Helper stderr output: %s\n", tmp);
    }
  output_strings.rewind();
  while((tmp = output_strings.next()) != NULL)
    {
      m_xml += tmp;
    }
  return true;
}