Exemple #1
0
int
kill_family(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc > 2) {
		fprintf(stderr,
		        "error: argument synopsis for %s: [<pid>]\n",
		        argv[0]);
		return 1;
	}
	pid_t pid = 0;
	if (argc == 2) {
		pid = atoi(argv[1]);
		if (pid == 0) {
			fprintf(stderr, "error: invalid pid: %s\n", argv[1]);
			return 1;
		}
	}
	bool success;
	if (!pfc.kill_family(pid, success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	return 0;
}
Exemple #2
0
static int
track_by_associated_cgroup(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if ((argc != 2) && (argc != 3)) {
		fprintf(stderr,
			"error: argument synopsis for %s: <cgroup> [<pid>]\n",
			argv[0]);
		return 1;
	}
	const char * cgroup = argv[1];
	pid_t pid = 0;
	if (argc == 3) {
		pid = atoi(argv[2]);
		if (pid <= 0) {
			fprintf(stderr, "error: invalid pid: %s\n", argv[2]);
			return 1;
		}
	}
	bool success;
	if (!pfc.track_family_via_cgroup(pid, cgroup, success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
			"error: %s command failed with ProcD\n",
			argv[0]);
		return 1;
	}
	return 0;
}
Exemple #3
0
int
signal_process(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if ((argc != 2) && (argc != 3)) {
		fprintf(stderr,
		        "error: argument synopsis for %s: <signal> [<pid>]\n",
		        argv[0]);
		return 1;
	}
	int signal = atoi(argv[1]);
	if (signal == 0) {
		fprintf(stderr, "invalid signal: %s\n", argv[1]);
		return 1;
	}
	pid_t pid = 0;
	if (argc == 3) {
		pid = atoi(argv[2]);
		if (pid == 0) {
			fprintf(stderr, "error: invalid pid: %s\n", argv[2]);
			return 1;
		}
	}
	bool success;
	if (!pfc.signal_process(pid, signal, success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	return 0;
}
Exemple #4
0
static int
register_family(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc != 4) {
		fprintf(stderr,
		        "error: argument synopsis for %s: "
		            "<pid> <watcher_pid> <max_snapshot interval>\n",
		        argv[0]);
		return 1;
	}
	pid_t pid = atoi(argv[1]);
	pid_t watcher = atoi(argv[2]);
	int max_snapshot_interval = atoi(argv[3]);
	bool success;
	if (!pfc.register_subfamily(pid,
	                            watcher,
	                            max_snapshot_interval,
	                            success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	return 0;
}
Exemple #5
0
// This function assumes that privledge separation has already been determined
// to be available.
void
UserProc::send_sig_privsep( int sig )
{
	ProcFamilyClient pfc;
	char *tmp = NULL;
	bool response;
	bool ret;

	tmp = param("PROCD_ADDRESS");
	if (tmp != NULL) {
		ret = pfc.initialize(tmp);
		if (ret == false) {
			EXCEPT("Failure to initialize the ProcFamilyClient object");
		}
		free(tmp);
	} else {
		EXCEPT("privsep is enabled, but PROCD_ADDRESS is not defined!");
	}

	// continue the family first
	ret = pfc.continue_family(pid, response);
	if (ret == false) {
		EXCEPT("UserProc::send_sig_privsep(): Couldn't talk to procd while "
			"trying to continue the user job.");
	}

	if (response == false) {
		EXCEPT("UserProc::send_sig_privsep(): "
			"Procd refused to continue user job");
	}

	// now (unless it is a continue) send the requested signal
	if (sig != SIGCONT) {
		ret = pfc.signal_process(pid, sig, response);

		if (ret == false) {
			EXCEPT("UserProc::send_sig_privsep(): Couldn't talk to procd while "
				"trying to send signal %d to the user job.", sig);
		}

		if (response == false) {
			EXCEPT("UserProc::send_sig_privsep(): "
				"Procd refused to send signal %d to user job", sig);
		}
	}
}
Exemple #6
0
static int
dump(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc > 2) {
		fprintf(stderr,
		        "error: argument synopsis for %s: [<pid>]\n",
		        argv[0]);
		return 1;
	}
	pid_t pid = 0;
	if (argc == 2) {
		pid = atoi(argv[1]);
		if (pid == 0) {
			fprintf(stderr, "error: invalid pid: %s\n", argv[1]);
			return 1;
		}
	}

	bool response;
	std::vector<ProcFamilyDump> vec;
	if (!pfc.dump(pid, response, vec)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!response) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}

	for (size_t i = 0; i < vec.size(); ++i) {
		printf("%u %u %u %d\n",
		       (unsigned)vec[i].parent_root,
		       (unsigned)vec[i].root_pid,
		       (unsigned)vec[i].watcher_pid,
		       (int)vec[i].procs.size());
		for (size_t j = 0; j < vec[i].procs.size(); ++j) {
			printf("%u %u " PROCAPI_BIRTHDAY_FORMAT " %ld %ld\n",
			       (unsigned)vec[i].procs[j].pid,
			       (unsigned)vec[i].procs[j].ppid,
			       vec[i].procs[j].birthday,
			       vec[i].procs[j].user_time,
			       vec[i].procs[j].sys_time);
		}
	}

	return 0;
}
Exemple #7
0
static int
get_usage(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc > 2) {
		fprintf(stderr,
		        "error: argument synopsis for %s: [<pid>]\n",
		        argv[0]);
		return 1;
	}
	pid_t pid = 0;
	if (argc == 2) {
		pid = atoi(argv[1]);
		if (pid == 0) {
			fprintf(stderr, "error: invalid pid: %s\n", argv[1]);
			return 1;
		}
	}
	ProcFamilyUsage pfu;
	bool success;
	if (!pfc.get_usage(pid, pfu, success)) {
	fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	printf("Number of Processes: %d\n", pfu.num_procs);
	printf("User CPU Time (s): %ld\n", pfu.user_cpu_time);
	printf("System CPU Time (s): %ld\n", pfu.sys_cpu_time);
	printf("CPU Percentage (%%): %f\n", pfu.percent_cpu);
	printf("Maximum Image Size (KB): %lu\n", pfu.max_image_size);
	printf("Total Image Size(KB): %lu\n", pfu.total_image_size);
	if (pfu.total_proportional_set_size_available) {
		printf("Proportional Set Size (KB): %lu\n", pfu.total_proportional_set_size);
	}
	if (pfu.block_read_bytes >= 0)
		printf("Bytes read from block devices (KB): %lu\n", pfu.block_read_bytes/1024);
	if (pfu.block_write_bytes >= 0)
		printf("Bytes written to block devices (KB): %lu\n", pfu.block_write_bytes/1024);
	return 0;
}
Exemple #8
0
int
quit(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc != 1) {
		fprintf(stderr,
		        "error: no arguments required for %s\n",
		        argv[0]);
		return 1;
	}
	bool success;
	if (!pfc.quit(success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	return 0;
}
Exemple #9
0
int
unregister_family(ProcFamilyClient& pfc, int argc, char* argv[])
{
	if (argc != 2) {
		fprintf(stderr,
		        "error: argument synopsis for %s: <pid>\n",
		        argv[0]);
		return 1;
	}
	pid_t pid = atoi(argv[1]);
	bool success;
	if (!pfc.unregister_family(pid, success)) {
		fprintf(stderr, "error: communication error with ProcD\n");
		return 1;
	}
	if (!success) {
		fprintf(stderr,
		        "error: %s command failed with ProcD\n",
		        argv[0]);
		return 1;
	}
	return 0;
}
Exemple #10
0
int
main(int argc, char* argv[])
{
	char *procd_address = NULL;
	myDistro->Init(argc, argv);

	if (argc < 2) {
		fprintf(stderr, 
			"Usage: %s <options w/arguments> <command> [<arg> ...]\n",
			argv[0]);
		list_commands();
		return 1;
	}

	config();
	Termlog = 1;
	dprintf_config("TOOL", get_param_functions());

	int cmd_argc = argc - 1;
	char** cmd_argv = argv + 1;

	// Process the first set of options.
	while(cmd_argv[0] != NULL && cmd_argv[0][0] == '-')
	{
		if (strcmp(cmd_argv[0], "-A") == MATCH) {
			cmd_argc--;
			cmd_argv++;
			if (cmd_argc == 0) {
				fprintf(stderr, "error: -A needs an argument\n");
				list_commands();
				return 1;
			}
			// store the argument to -A as the file we'll use.
			procd_address = cmd_argv[0];
			cmd_argc--;
			cmd_argv++;
			continue;
		} else if (strcmp(cmd_argv[0], "-h") == MATCH) {
			cmd_argc--;
			cmd_argv++;
			fprintf(stderr, 
				"Usage: %s <options w/arguments> <command> [<arg> ...]\n",
				argv[0]);
			list_commands();
			return 1;
			continue;
		}

		// This is the failure case if we manage to pass all checks above.
		fprintf(stderr, "error: Don't understand option %s\n", cmd_argv[0]);
		list_commands();
		return 1;
	}

	// If there are no command line arguments left, then there is no
	// command specified after the options, which is a failure.
	if (cmd_argc == 0) {
		fprintf(stderr, 
			"Please specify a command.\n"
			"Usage: %s <options w/arguments> <command> [<arg> ...]\n",
			argv[0]);
		list_commands();
		return 1;
	}

	// If a procd address wasn't specified on the command line, see if we
	// have an entry in a config file to use.
	if (procd_address == NULL) {
		procd_address = param("PROCD_ADDRESS");
		if (procd_address == NULL) {
			fprintf(stderr, "error: PROCD_ADDRESS not defined\n");
			return 1;
		}
	}

	
	ProcFamilyClient pfc;
	if (!pfc.initialize(procd_address)) {
		fprintf(stderr, "error: failed to initialize ProcD client\n");
		return 1;
	}

	// Process this single command we should be performing
	if (strcasecmp(cmd_argv[0], "REGISTER_FAMILY") == 0) {
		return register_family(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "TRACK_BY_ASSOCIATED_GID") == 0) {
		return track_by_associated_gid(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "TRACK_BY_ASSOCIATED_CGROUP") == 0) {
		return track_by_associated_cgroup(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "GET_USAGE") == 0) {
		return get_usage(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "DUMP") == 0) {
		return dump(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "LIST") == 0) {
		return list(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "SIGNAL_PROCESS") == 0) {
		return signal_process(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "SUSPEND_FAMILY") == 0) {
		return suspend_family(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "CONTINUE_FAMILY") == 0) {
		return continue_family(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "KILL_FAMILY") == 0) {
		return kill_family(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "UNREGISTER_FAMILY") == 0) {
		return unregister_family(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "SNAPSHOT") == 0) {
		return snapshot(pfc, cmd_argc, cmd_argv);
	}
	else if (strcasecmp(cmd_argv[0], "QUIT") == 0) {
		return quit(pfc, cmd_argc, cmd_argv);
	}
	else {
		fprintf(stderr, "error: invalid command: %s\n", cmd_argv[0]);
		list_commands();
		return 1;
	}
}
Exemple #11
0
void
UserProc::execute()
{
	ArgList new_args;
	char    **argv;
	char	**argp;
	char	**envp;
	sigset_t	sigmask;
	MyString	a_out_name;
	MyString	shortname;
	int		user_syscall_fd = -1;
	const	int READ_END = 0;
	const	int WRITE_END = 1;
	int		pipe_fds[2];
	FILE	*cmd_fp;
	char	buf[128];
	ReliSock	*new_reli = NULL;

	pipe_fds[0] = -1;
	pipe_fds[1] = -1;

	shortname.formatstr( "condor_exec.%d.%d", cluster, proc );
	a_out_name.formatstr( "%s/%s/%s", Execute, local_dir, shortname.Value() );

		// Set up arg vector according to class of job
	switch( job_class ) {

	  case CONDOR_UNIVERSE_STANDARD:
		if( pipe(pipe_fds) < 0 ) {
			EXCEPT( "pipe()" );}

			dprintf( D_ALWAYS, "Pipe built\n" );
		
			// The user process should not try to read commands from
			// 0, 1, or 2 since we'll be using the commands to redirect
			// those.
		if( pipe_fds[READ_END] < 14 ) {
			dup2( pipe_fds[READ_END], 14 );
			close( pipe_fds[READ_END] );
			pipe_fds[READ_END] = 14;
		}
		dprintf( D_ALWAYS, "New pipe_fds[%d,%d]\n", pipe_fds[0], pipe_fds[1] );
		sprintf( buf, "%d", pipe_fds[READ_END] );
		dprintf( D_ALWAYS, "cmd_fd = %s\n", buf );

		new_args.AppendArg(shortname);
		new_args.AppendArg("-_condor_cmd_fd");
		new_args.AppendArg(buf);
		break;

	  case CONDOR_UNIVERSE_PVM:
#if 1
		EXCEPT( "Don't know how to deal with PVM jobs" );
#else
		new_args.AppendArg(shortname);
		new_args.AppendArg("-1");
		new_args.AppendArg(in);
		new_args.AppendArg(out);
		new_args.AppendArg(err);
#endif
		break;

	  case CONDOR_UNIVERSE_VANILLA:
	  	if (privsep_enabled()) {
			EXCEPT("Don't know how to deal with Vanilla jobs");
		}
		new_args.AppendArg(shortname.Value());
		break;
	}

	new_args.AppendArgsFromArgList(args);

		// take care of USER_JOB_WRAPPER
	support_job_wrapper(a_out_name,&new_args);

	MyString exec_name;
	exec_name = a_out_name;

	// If privsep is turned on, then we need to use the PrivSep
	// Switchboard to launch the job
	//
	FILE* switchboard_in_fp;
	FILE* switchboard_err_fp;
	int switchboard_child_in_fd;
	int switchboard_child_err_fd;
	if (privsep_enabled()) {

		// create the pipes that we'll use to communicate
		//
		if (!privsep_create_pipes(switchboard_in_fp,
		                          switchboard_child_in_fd,
		                          switchboard_err_fp,
		                          switchboard_child_err_fd)) {
			EXCEPT("can't launch job: privsep_create_pipes failure");
		}
	}

	argv = new_args.GetStringArray();

		// Set an environment variable that tells the job where it may put scratch data
		// even if it moves to a different directory.

		// get the environment vector
	envp = env_obj.getStringArray();

		// We may run more than one of these, so each needs its own
		// remote system call connection to the shadow
	if( job_class == CONDOR_UNIVERSE_PVM ) {
		new_reli = NewConnection( v_pid );
		user_syscall_fd = new_reli->get_file_desc();
	}

		// print out arguments to execve
	dprintf( D_ALWAYS, "Calling execve( \"%s\"", exec_name.Value() );
	for( argp = argv; *argp; argp++ ) {							// argv
		dprintf( D_ALWAYS | D_NOHEADER, ", \"%s\"", *argp );
	}
	dprintf( D_ALWAYS | D_NOHEADER, ", 0" );
	for( argp = envp; *argp; argp++ ) {							// envp
		dprintf( D_ALWAYS | D_NOHEADER, ", \"%s\"", *argp );
	}
	dprintf( D_ALWAYS | D_NOHEADER, ", 0 )\n" );


	if( (pid = fork()) < 0 ) {
		EXCEPT( "fork" );
	}

	if( pid == 0 ) {	// the child

			// Block only these 3 signals which have special meaning for
			// checkpoint/restart purposes.  Leave other signals ublocked
			// so that if we get an exception during the restart process,
			// we will get a core file to debug.
		sigemptyset( &sigmask );
		// for some reason if we block these, the user process is unable
		// to unblock some or all of them.
#if 0
		sigaddset( &sigmask, SIGUSR1 );
		sigaddset( &sigmask, SIGUSR2 );
		sigaddset( &sigmask, SIGTSTP );
#endif
		sigprocmask( SIG_SETMASK, &sigmask, 0 );

			// renice
		renice_self( "JOB_RENICE_INCREMENT" );

			// make certain the syscall sockets which are being passed
			// to the user job are setup to be blocking sockets.  this
			// is done by calling timeout(0) CEDAR method.
			// we must do this because the syscall lib does _not_ 
			// expect to see any failures due to errno EAGAIN...
		if ( SyscallStream ) {
			SyscallStream->timeout(0);
		}
		if ( new_reli ) {
			new_reli->timeout(0);
		}

			// If I'm using privledge separation, connect to the procd.
			// we need to register a family with the procd for the newly
			// created process, so that the ProcD will allow us to send
			// signals to it
			//
		if (privsep_enabled() == true) {
			MyString procd_address;
			bool response;
			bool ret;
			ProcFamilyClient pfc;

			procd_address = get_procd_address();
			ret = pfc.initialize(procd_address.Value());
			if (ret == false) {
				EXCEPT("Failure to initialize the ProcFamilyClient object");
			}

			ret = pfc.register_subfamily(getpid(), getppid(), 60, response);

			if (ret == false) {
				EXCEPT("Could not communicate with procd. Aborting.");
			}

			if (response == false) {
				EXCEPT("Procd refused to register job subfamily. Aborting.");
			}
		}

			// If there is a requested coresize for this job, enforce it.
			// Do it before the set_priv_final to ensure root can alter 
			// the coresize to the requested amount. Otherwise, just
			// use whatever the current default is.
		if (coredump_limit_exists == TRUE) {
			limit( RLIMIT_CORE, coredump_limit, CONDOR_HARD_LIMIT, "max core size" );
		}

			// child process should have only it's submitting uid, and cannot
			// switch back to root or some other uid.  
			// It'd be nice to check for errors here, but
			// unfortunately, we can't, since this only returns the
			// previous priv state, not whether it worked or not. 
			//  -Derek Wright 4/30/98
		set_user_priv_final();

		switch( job_class ) {
		  
		  case CONDOR_UNIVERSE_STANDARD:
			// if we're using PrivSep, the chdir here could fail. instead,
			// we pass the job's IWD to the switchboard via pipe
			//
		  	if (!privsep_enabled()) {
				if( chdir(local_dir) < 0 ) {
					EXCEPT( "chdir(%s)", local_dir );
				}
			}
			close( pipe_fds[WRITE_END] );
			break;

		  case CONDOR_UNIVERSE_PVM:
			if( chdir(local_dir) < 0 ) {
				EXCEPT( "chdir(%s)", local_dir );
			}
			close( pipe_fds[WRITE_END] );
			dup2( user_syscall_fd, RSC_SOCK );
			break;

		  case CONDOR_UNIVERSE_VANILLA:
			set_iwd();
			open_std_file( 0 );
			open_std_file( 1 );
			open_std_file( 2 );

			(void)close( RSC_SOCK );
			(void)close( CLIENT_LOG );

			break;
		}

			// Make sure we're not root
		if( getuid() == 0 ) {
				// EXCEPT( "We're about to start as root, aborting." );
				// You can't see this error message at all.  So, just
				// exit(4), which is what EXCEPT normally gives. 
			exit( 4 );
		}

#if defined( LINUX ) && (defined(I386) || defined(X86_64))
		// adjust the execution domain of the child to be suitable for
		// checkpointing.
		patch_personality();
#endif 

			// if we're using privsep, we'll exec the PrivSep Switchboard
			// first, which is setuid; it will then setuid to the user we
			// give it and exec the real job
			//
		if (privsep_enabled()) {
			close(fileno(switchboard_in_fp));
			close(fileno(switchboard_err_fp));
			privsep_get_switchboard_command("exec",
			                                switchboard_child_in_fd,
			                                switchboard_child_err_fd,
			                                exec_name,
			                                new_args);
			deleteStringArray(argv);
			argv = new_args.GetStringArray();
		}

			// Everything's ready, start it up...
		errno = 0;
		execve( exec_name.Value(), argv, envp );

			// A successful call to execve() never returns, so it is an
			// error if we get here.  A number of errors are possible
			// but the most likely is that there is insufficient swap
			// space to start the new process.  We don't try to log
			// anything, since we have the UID/GID of the job's owner
			// and cannot write into the log files...
		exit( JOB_EXEC_FAILED );
	}

		// The parent

		// PrivSep - we have at this point only spawned the switchboard
		// with the "exec" command. we need to use our pipe to it in
		// order to tell it how to execute the user job, and then use
		// the error pipe to make sure everything worked
		//
	if (privsep_enabled()) {

		close(switchboard_child_in_fd);
		close(switchboard_child_err_fd);

		privsep_exec_set_uid(switchboard_in_fp, uid);
		privsep_exec_set_path(switchboard_in_fp, exec_name.Value());
		privsep_exec_set_args(switchboard_in_fp, new_args);
		privsep_exec_set_env(switchboard_in_fp, env_obj);
		privsep_exec_set_iwd(switchboard_in_fp, local_dir);
		privsep_exec_set_inherit_fd(switchboard_in_fp, pipe_fds[0]);
		privsep_exec_set_inherit_fd(switchboard_in_fp, RSC_SOCK);
		privsep_exec_set_inherit_fd(switchboard_in_fp, CLIENT_LOG);
		privsep_exec_set_is_std_univ(switchboard_in_fp);
		fclose(switchboard_in_fp);

		if (!privsep_get_switchboard_response(switchboard_err_fp)) {
			EXCEPT("error starting job: "
			           "privsep get_switchboard_response failure");
		}
	}

	dprintf( D_ALWAYS, "Started user job - PID = %d\n", pid );
	if( job_class != CONDOR_UNIVERSE_VANILLA ) {
			// Send the user process its startup environment conditions
		close( pipe_fds[READ_END] );
		cmd_fp = fdopen( pipe_fds[WRITE_END], "w" );
		dprintf( D_ALWAYS, "cmd_fp = %p\n", cmd_fp );

		if( is_restart() ) {
#if 1
			fprintf( cmd_fp, "restart\n" );
			dprintf( D_ALWAYS, "restart\n" );
#else
			fprintf( cmd_fp, "restart %s\n", target_ckpt );
			dprintf( D_ALWAYS, "restart %s\n", target_ckpt );
#endif
			fprintf( cmd_fp, "end\n" );
			dprintf( D_ALWAYS, "end\n" );
		} else {
			fprintf( cmd_fp, "end\n" );
			dprintf( D_ALWAYS, "end\n" );
		}
		fclose( cmd_fp );
	}

	deleteStringArray(argv);
	deleteStringArray(envp);
	state = EXECUTING;

	if( new_reli ) {
		delete new_reli;
	}

	// removed some vanilla-specific code here
	//
	ASSERT(job_class != CONDOR_UNIVERSE_VANILLA);
}