Ejemplo n.º 1
0
static int
slow_poll(FILE *dbgfp, int dbgall, size_t *nbytes )
{
    int moreSources;
    struct timeval tv;
    fd_set fds;
#if defined( __hpux )
    size_t maxFD = 0;
#else
    int maxFD = 0;
#endif /* OS-specific brokenness */
    int bufPos, i, usefulness = 0;


    /* Fire up each randomness source */
    FD_ZERO(&fds);
    for (i = 0; dataSources[i].path != NULL; i++) {
	/* Since popen() is a fairly heavy function, we check to see whether
	 * the executable exists before we try to run it */
	if (access(dataSources[i].path, X_OK)) {
	    if( dbgfp && dbgall )
		fprintf(dbgfp, "%s not present%s\n", dataSources[i].path,
			       dataSources[i].hasAlternative ?
					", has alternatives" : "");
	    dataSources[i].pipe = NULL;
	}
	else
	    dataSources[i].pipe = my_popen(&dataSources[i]);

	if (dataSources[i].pipe != NULL) {
	    dataSources[i].pipeFD = fileno(dataSources[i].pipe);
	    if (dataSources[i].pipeFD > maxFD)
		maxFD = dataSources[i].pipeFD;

#ifdef O_NONBLOCK /* Ohhh what a hack (used for Atari) */
	    fcntl(dataSources[i].pipeFD, F_SETFL, O_NONBLOCK);
#else
#error O_NONBLOCK is missing
#endif

	    FD_SET(dataSources[i].pipeFD, &fds);
	    dataSources[i].length = 0;

	    /* If there are alternatives for this command, don't try and
	     * execute them */
	    while (dataSources[i].hasAlternative) {
		if( dbgfp && dbgall )
		    fprintf(dbgfp, "Skipping %s\n", dataSources[i + 1].path);
		i++;
	    }
	}
    }


    /* Suck all the data we can get from each of the sources */
    bufPos = 0;
    moreSources = 1;
    while (moreSources && bufPos <= gather_buffer_size) {
	/* Wait for data to become available from any of the sources, with a
	 * timeout of 10 seconds.  This adds even more randomness since data
	 * becomes available in a nondeterministic fashion.  Kudos to HP's QA
	 * department for managing to ship a select() which breaks its own
	 * prototype */
	tv.tv_sec = 10;
	tv.tv_usec = 0;

#if defined( __hpux ) && ( OS_VERSION == 9 )
	if (select(maxFD + 1, (int *)&fds, NULL, NULL, &tv) == -1)
#else  /*  */
	if (select(maxFD + 1, &fds, NULL, NULL, &tv) == -1)
#endif /* __hpux */
	    break;

	/* One of the sources has data available, read it into the buffer */
	for (i = 0; dataSources[i].path != NULL; i++) {
	    if( dataSources[i].pipe && FD_ISSET(dataSources[i].pipeFD, &fds)) {
		size_t noBytes;

		if ((noBytes = fread(gather_buffer + bufPos, 1,
				     gather_buffer_size - bufPos,
				     dataSources[i].pipe)) == 0) {
		    if (my_pclose(&dataSources[i]) == 0) {
			int total = 0;

			/* Try and estimate how much entropy we're getting
			 * from a data source */
			if (dataSources[i].usefulness) {
			    if (dataSources[i].usefulness < 0)
				total = (dataSources[i].length + 999)
					/ -dataSources[i].usefulness;
			    else
				total = dataSources[i].length
					/ dataSources[i].usefulness;
			}
			if( dbgfp )
			    fprintf(dbgfp,
			       "%s %s contributed %d bytes, "
			       "usefulness = %d\n", dataSources[i].path,
			       (dataSources[i].arg != NULL) ?
				       dataSources[i].arg : "",
				      dataSources[i].length, total);
			if( dataSources[i].length )
			    usefulness += total;
		    }
		    dataSources[i].pipe = NULL;
		}
		else {
		    int currPos = bufPos;
		    int endPos = bufPos + noBytes;

		    /* Run-length compress the input byte sequence */
		    while (currPos < endPos) {
			int ch = gather_buffer[currPos];

			/* If it's a single byte, just copy it over */
			if (ch != gather_buffer[currPos + 1]) {
			    gather_buffer[bufPos++] = ch;
			    currPos++;
			}
			else {
			    int count = 0;

			    /* It's a run of repeated bytes, replace them
			     * with the byte count mod 256 */
			    while ((ch == gather_buffer[currPos])
				    && currPos < endPos) {
				count++;
				currPos++;
			    }
			    gather_buffer[bufPos++] = count;
			    noBytes -= count - 1;
			}
		    }

		    /* Remember the number of (compressed) bytes of input we
		     * obtained */
		    dataSources[i].length += noBytes;
		}
	    }
	}

	/* Check if there is more input available on any of the sources */
	moreSources = 0;
	FD_ZERO(&fds);
	for (i = 0; dataSources[i].path != NULL; i++) {
	    if (dataSources[i].pipe != NULL) {
		FD_SET(dataSources[i].pipeFD, &fds);
		moreSources = 1;
	    }
	}
    }

    if( dbgfp ) {
	fprintf(dbgfp, "Got %d bytes, usefulness = %d\n", bufPos, usefulness);
	fflush(dbgfp);
    }
    *nbytes = bufPos;
    return usefulness;
}
Ejemplo n.º 2
0
void MachAttributes::init_machine_resources() {
    // defines the space of local machine resources, and their quantity
    m_machres_map.clear();

    // this may be filled from resource inventory scripts
    m_machres_attr.Clear();

    // these are reserved for standard/fixed resources
    std::set<string> fixedRes;
    fixedRes.insert("cpu");
    fixedRes.insert("cpus");
    fixedRes.insert("disk");
    fixedRes.insert("swap");
    fixedRes.insert("mem");
    fixedRes.insert("memory");
    fixedRes.insert("ram");

    // get the list of defined local resource names:
    char* ptmp = param("MACHINE_RESOURCE_NAMES");
    string resnames;
    if (NULL != ptmp) {
        // if admin defined MACHINE_RESOURCE_NAMES, then use this list
        // as the source of expected custom machine resources
        resnames = ptmp;
        free(ptmp);
    } else {
        // otherwise, build the list of custom machine resources from
        // all occurrences of MACHINE_RESOURCE_<resname>
        std::set<string> resset;
        Regex re;
        int err = 0;
        const char* pszMsg = 0;
        const string prefix = "MACHINE_RESOURCE_";
        const string invprefix = "INVENTORY_";
        const string restr = prefix + "(.+)";
        ASSERT(re.compile(restr.c_str(), &pszMsg, &err, PCRE_CASELESS));
	std::vector<std::string> resdef;
        const int n = param_names_matching(re, resdef);
        for (int j = 0;  j < n;  ++j) {
            string rname = resdef[j].substr(prefix.length());
            string testinv = rname.substr(0, invprefix.length());
            if (0 == strcasecmp(testinv.c_str(), invprefix.c_str())) {
                // if something was defined via MACHINE_RESOURCE_INVENTORY_<rname>, strip "INVENTORY_"
                rname = rname.substr(invprefix.length());
            }
            std::transform(rname.begin(), rname.end(), rname.begin(), ::tolower);
            resset.insert(rname);
        }
        for (std::set<string>::iterator j(resset.begin());  j != resset.end();  ++j) {
            resnames += " ";
            resnames += *j;
        }
    }

    // scan the list of local resources, to obtain their quantity and associated attributes (if any)
    StringList reslist(resnames.c_str());
    reslist.rewind();
    while (const char* rnp = reslist.next()) {
        string rname(rnp);
        std::transform(rname.begin(), rname.end(), rname.begin(), ::tolower);
        if (fixedRes.count(rname) > 0) {
            EXCEPT("pre-defined resource name '%s' is reserved", rname.c_str());
        }

        // If MACHINE_RESOURCE_<rname> is present, use that and move on:
        string pname;
        formatstr(pname, "MACHINE_RESOURCE_%s", rname.c_str());
        char* machresp = param(pname.c_str());
        if (machresp) {
            int v = param_integer(pname.c_str(), 0, 0, INT_MAX);
            m_machres_map[rname] = v;
            free(machresp);
            continue;
        }

        // current definition of REMIND macro is not working with gcc
        #pragma message("MACHINE_RESOURCE_INVENTORY_<rname> is deprecated, and will be removed when a solution using '|' in config files is fleshed out")
        // if we didn't find MACHINE_RESOURCE_<rname>, then try MACHINE_RESOURCE_INVENTORY_<rname>
        formatstr(pname, "MACHINE_RESOURCE_INVENTORY_%s", rname.c_str());
        char* invscriptp = param(pname.c_str());
        if (NULL == invscriptp) {
            EXCEPT("Missing configuration for local machine resource %s", rname.c_str());
        }

        // if there is an inventory script, then attempt to execute it and use its output to
        // identify the local resource quantity, and any associated attributes:
        string invscript = invscriptp;
        free(invscriptp);

        ArgList invcmd;
        StringList invcmdal(invscript.c_str());
        invcmdal.rewind();
        while (char* invarg = invcmdal.next()) {
            invcmd.AppendArg(invarg);
        }
        FILE* fp = my_popen(invcmd, "r", FALSE);
        if (NULL == fp) {
            EXCEPT("Failed to execute local resource inventory script \"%s\"\n", invscript.c_str());
        }

        ClassAd invad;
        char invline[1000];
        while (fgets(invline, sizeof(invline), fp)) {
            if (!invad.Insert(invline)) {
                dprintf(D_ALWAYS, "Failed to insert \"%s\" into machine resource attributes: ignoring\n", invline);
            }
        }
        my_pclose(fp);

        // require the detected machine resource to be present as an attribute
        string ccname(rname.c_str());
        *(ccname.begin()) = toupper(*(ccname.begin()));
        string detname;
        formatstr(detname, "%s%s", ATTR_DETECTED_PREFIX, ccname.c_str());
        int v = 0;
        if (!invad.LookupInteger(detname.c_str(), v)) {
            EXCEPT("Missing required attribute \"%s = <n>\" from output of %s\n", detname.c_str(),  invscript.c_str());
        }

        // success
        m_machres_map[rname] = v;
        invad.Delete(rname.c_str());
        m_machres_attr.Update(invad);
    }

    for (slotres_map_t::iterator j(m_machres_map.begin());  j != m_machres_map.end();  ++j) {
        dprintf(D_ALWAYS, "Local machine resource %s = %d\n", j->first.c_str(), int(j->second));
    }
}
Ejemplo n.º 3
0
/*
 * Do variable interpolation on a string, then invoke it as a shell command.
 * Write an appropriate set of AV pairs to standard input of the command and
 * read its standard output into outarray.  Return the commands final status
 * when it terminates
 */
int
call_pre_process(char *string, struct author_data *data, char ***outargsp,
		 int *outargs_cntp, char *error, int err_len)
{
    char **new_args;
    int readfd, writefd, errorfd;
    int status, i;
    char *cmd = substitute(string, data);
#if HAVE_PID_T
    pid_t pid;
#else
    int pid;
#endif

    pid = my_popen(cmd, &readfd, &writefd, &errorfd);
    memset(error, '\0', err_len);

    free(cmd);

    if (pid < 0) {
	close_fds(readfd, writefd, errorfd);
	return(1);		/* deny */
    }

    for (i = 0; i < data->num_in_args; i++) {
	if (debug & DEBUG_AUTHOR_FLAG)
	    report(LOG_DEBUG, "input %s", data->input_args[i]);
    }

    if (write_args(writefd, data->input_args, data->num_in_args)) {
	close_fds(readfd, writefd, errorfd);
	return(1);		/* deny */
    }

    close(writefd);
    writefd = -1;

    new_args = read_args(0, readfd);
    *outargsp = new_args;

    if (debug & DEBUG_AUTHOR_FLAG) {
	for (i = 0; new_args[i]; i++) {
	    report(LOG_DEBUG, "output %s", new_args[i]);
	}
    }

    read_string(errorfd, error, err_len);
    if (error[0] != '\0') {
	report(LOG_ERR, "Error from program (%d): \"%s\" ",
	       strlen(error), error);
    }

    /* count the args */
    for (i = 0; new_args[i]; i++)
	 /* NULL stmt */ ;

    *outargs_cntp = i;

    status = waitfor(pid);
    close_fds(readfd, writefd, errorfd);
    return(status);
}
Ejemplo n.º 4
0
/*
 * Do variable interpolation on a string, then invoke it as a shell command.
 * Write an appropriate set of AV pairs to standard input of the command and
 * read its standard output into outarray.  Return the commands final status
 * when it terminates
 */
int
call_post_process(char *string, struct author_data *data, char ***outargsp,
		  int *outargs_cntp)
{
    char **new_args;
    int status;
    int readfd, writefd, errorfd;
    int i;
    char *cmd = substitute(string, data);
#if HAVE_PID_T
    pid_t pid;
#else
    int pid;
#endif

    pid = my_popen(cmd, &readfd, &writefd, &errorfd);
    free(cmd);

    if (pid < 0) {
	close_fds(readfd, writefd, errorfd);
	return(1);		/* deny */
    }

    /* If the status is AUTHOR_STATUS_PASS_ADD then the current output args
     * represent *additions* to the input args, not the full set */

    if (data->status == AUTHOR_STATUS_PASS_ADD) {

	for (i = 0; i < data->num_in_args; i++) {
	    if (debug & DEBUG_AUTHOR_FLAG)
		report(LOG_DEBUG, "input %s", data->input_args[i]);
	}

	if (write_args(writefd, data->input_args, data->num_in_args)) {
	    close_fds(readfd, writefd, errorfd);
	    return(1);		/* deny */
	}
    }
    for (i = 0; i < data->num_out_args; i++) {
	if (debug & DEBUG_AUTHOR_FLAG)
	    report(LOG_DEBUG, "input %s", data->output_args[i]);
    }

    if (write_args(writefd, data->output_args, data->num_out_args)) {
	close_fds(readfd, writefd, errorfd);
	return(1);		/* deny */
    }

    close(writefd);
    writefd = -1;

    new_args = read_args(0, readfd);
    *outargsp = new_args;

    if (debug & DEBUG_AUTHOR_FLAG) {
	for (i = 0; new_args[i]; i++) {
	    report(LOG_DEBUG, "output %s", new_args[i]);
	}
    }
    /* count the output args */
    for (i = 0; new_args[i]; i++)
	 /* NULL stmt */ ;

    *outargs_cntp = i;

    status = waitfor(pid);
    close_fds(readfd, writefd, errorfd);

    return(status);
}
Ejemplo n.º 5
0
ClassAd * java_detect()
{
	MyString path;
	ArgList args;
	MyString command;
	MyString args_string;
	MyString args_error;

#ifndef WIN32
	sigset_t mask;
#endif

	if(!java_config(path,&args,0)) return 0;
	int benchmark_time = param_integer("JAVA_BENCHMARK_TIME",0);

	args.InsertArg(path.Value(),0);
	args.AppendArg("CondorJavaInfo");
	args.AppendArg("old");
	args.AppendArg(benchmark_time);

	/*
	N.B. Certain version of Java do not set up their own signal
	masks correctly.  DaemonCore has already blocked off a bunch
	of signals.  We have to reset them, otherwise some JVMs go
	off into an infinite loop.  However, we leave SIGCHLD blocked,
	as DaemonCore has already set up a handler, but isn't prepared
	to actually handle it before the DC constructor completes.
	*/

#ifndef WIN32
	sigemptyset(&mask);
	sigaddset(&mask,SIGCHLD);
	sigprocmask(SIG_SETMASK,&mask,0);
#endif

	FILE *stream = my_popen(args,"r",0);
	if(!stream) {
		MyString arg_str;
		args.GetArgsStringForDisplay(&arg_str);
		dprintf(D_ALWAYS,"JavaDetect: failed to execute %s\n",arg_str.Value());
		return 0;
	}

	int eof=0,error=0,empty=0;
	ClassAd *ad = new ClassAd(stream,"***",eof,error,empty);

	int rc = my_pclose(stream);
	if( rc!=0 ) {
		MyString arg_str;
		args.GetArgsStringForDisplay(&arg_str);
		dprintf(D_ALWAYS,"JavaDetect: failure status %d when executing %s\n",rc,arg_str.Value());
		error = 1;
	}

	if(error || empty) {
		delete ad;
		return 0;
	} else {
		return ad;
	}
}
Ejemplo n.º 6
0
bool
VMUniverseMgr::testVMGahp(const char* gahppath, const char* vmtype)
{
	m_needCheck = false;

	if( !m_starter_has_vmcode ) {
		return false;
	}

	if( !gahppath || !vmtype ) {
		return false;
	}

#if defined(WIN32)
		// On Windows machine, the option that Starter log file includes 
		// logs from vmgahp causes deadlock even if the option works well 
		// on Linux machine. I guess that is due to Windows Pipes but 
		// I don't know the exact reason.
		// Until the problem is solved, 
		// this option will be disabled on Windows machine.
	char *need_log_file = param("VM_GAHP_LOG");
	if( need_log_file ) {
		free(need_log_file);
	}else {
		dprintf( D_ALWAYS, "To support vm universe, '%s' must be defined "
				"in condor config file, which is a log file for vmgahp.\n", 
				"VM_GAHP_LOG"); 
		return false;
	}
#endif

	// vmgahp is daemonCore, so we need to add -f -t options of daemonCore.
	// Then, try to execute vmgahp with 
	// vmtype <vmtype>"
	// and grab the output as a ClassAd
	ArgList systemcmd;
	systemcmd.AppendArg(gahppath);
	systemcmd.AppendArg("-f");
	char *gahp_log_file = param("VM_GAHP_LOG");
	if( gahp_log_file ) {
		free(gahp_log_file);
	}else {
		systemcmd.AppendArg("-t");
	}
	systemcmd.AppendArg("-M");
	systemcmd.AppendArg(VMGAHP_TEST_MODE);
	systemcmd.AppendArg("vmtype");
	systemcmd.AppendArg(vmtype);

#if !defined(WIN32)
	if( can_switch_ids() ) {
		MyString tmp_str;
		tmp_str.formatstr("%d", (int)get_condor_uid());
		SetEnv("VMGAHP_USER_UID", tmp_str.Value());
	}
#endif

	priv_state prev_priv;
	if( (strcasecmp(vmtype, CONDOR_VM_UNIVERSE_XEN) == MATCH) || (strcasecmp(vmtype, CONDOR_VM_UNIVERSE_KVM) == MATCH) ) {
		// Xen requires root privilege
		prev_priv = set_root_priv();
	}else {
		prev_priv = set_condor_priv();

	}
	FILE* fp = NULL;
	fp = my_popen(systemcmd, "r", FALSE );
	set_priv(prev_priv);

	if( !fp ) {
		dprintf( D_ALWAYS, "Failed to execute %s, ignoring\n", gahppath );
		return false;
	}

	bool read_something = false;
	char buf[2048];

	m_vmgahp_info.Clear();
	while( fgets(buf, 2048, fp) ) {
		if( !m_vmgahp_info.Insert(buf) ) {
			dprintf( D_ALWAYS, "Failed to insert \"%s\" into VMInfo, "
					 "ignoring invalid parameter\n", buf );
			continue;
		}
		read_something = true;
	}
	my_pclose( fp );
	if( !read_something ) {
		MyString args_string;
		systemcmd.GetArgsStringForDisplay(&args_string,0);
		dprintf( D_ALWAYS, 
				 "Warning: '%s' did not produce any valid output.\n", 
				 args_string.Value());
		if( (strcasecmp(vmtype, CONDOR_VM_UNIVERSE_XEN) == 0) ) {
			MyString err_msg;
			err_msg += "\n#######################################################\n";
			err_msg += "##### Make sure the followings ";
			err_msg += "to use VM universe for Xen\n";
			err_msg += "### - The owner of script progrm like ";
			err_msg += "'condor_vm_xen.sh' must be root\n";
			err_msg += "### - The script program must be executable\n";
			err_msg += "### - Other writable bit for the above files is ";
			err_msg += "not allowed.\n";
			err_msg += "#########################################################\n";
			dprintf( D_ALWAYS, "%s", err_msg.Value());
		} else if( (strcasecmp(vmtype, CONDOR_VM_UNIVERSE_KVM) == 0)) {
		        MyString err_msg;
			err_msg += "\n#######################################################\n";
			err_msg += "##### Make sure the followings ";
			err_msg += "to use VM universe for KVM\n";
			err_msg += "### - The owner of script progrm like ";
			err_msg += "'condor_vm_xen.sh' must be root\n";
			err_msg += "### - The script program must be executable\n";
			err_msg += "### - Other writable bit for the above files is ";
			err_msg += "not allowed.\n";
			err_msg += "#########################################################\n";
			dprintf( D_ALWAYS, "%s", err_msg.Value());
		}else if( strcasecmp(vmtype, CONDOR_VM_UNIVERSE_VMWARE ) == 0 ) {
			MyString err_msg;
			MyString err_msg2;
			err_msg += "\n#######################################################\n";
			err_msg += "##### Make sure the followings ";
			err_msg += "to use VM universe for VMware\n";

			if( can_switch_ids() ) {
				// Condor runs as root
				err_msg += "### - The script program like 'condor_vm_vmware'";
				err_msg += " must be readable for anybody.\n";
			}

			err_msg += "### - Check the path of vmware-cmd, vmrun, and mkisofs ";
			err_msg += "in 'condor_vm_vmware\n'";
			err_msg += "#########################################################\n";
			dprintf( D_ALWAYS, "%s", err_msg.Value());
		}
		return false;
	}

	// For debug
	printVMGahpInfo(D_ALWAYS);

	// Read vm_type
	MyString tmp_vmtype;
	if( m_vmgahp_info.LookupString( ATTR_VM_TYPE, tmp_vmtype) != 1 ) {
		dprintf( D_ALWAYS, "There is no %s in the output of vmgahp. "
				"So VM Universe will be disabled\n", ATTR_VM_TYPE);
		return false;
	}
	if( strcasecmp(tmp_vmtype.Value(), vmtype) != 0 ) {
		dprintf( D_ALWAYS, "The vmgahp(%s) doesn't support this vmtype(%s)\n",
				gahppath, vmtype);
		return false;
	}
	dprintf( D_ALWAYS, "VMType('%s') is supported\n", vmtype);

	// Read vm_memory
	if( m_vmgahp_info.LookupInteger(ATTR_VM_MEMORY, m_vm_max_memory) != 1 ) {
		dprintf( D_ALWAYS, "There is no %s in the output of vmgahp\n",ATTR_VM_MEMORY);
		return false;
	}
	if( m_vm_max_memory == 0 ) {
		dprintf( D_ALWAYS, "There is no sufficient memory for virtual machines\n");
		return false;
	}

	dprintf( D_ALWAYS, "The maximum available memory for vm universe is "
			"set to %d MB\n", m_vm_max_memory);

	// Read vm_networking
	bool tmp_networking = false;
	MyString tmp_networking_types;

	m_vmgahp_info.LookupBool(ATTR_VM_NETWORKING, tmp_networking);
	if( tmp_networking ) {
		if( m_vmgahp_info.LookupString( ATTR_VM_NETWORKING_TYPES, 
					tmp_networking_types) != 1 ) {
			tmp_networking = false;
			m_vmgahp_info.Assign(ATTR_VM_NETWORKING, false);
		}
	}

	m_vm_networking = param_boolean("VM_NETWORKING",false);
	if( m_vm_networking ) {
		if( !tmp_networking ) {
			dprintf( D_ALWAYS, "Even if VM_NETWORKING is TRUE in condor config,"
					" VM_NETWORKING is disabled because vmgahp doesn't "
					"support VM_NETWORKING\n");
			m_vm_networking = false;
		}
	}
	if( m_vm_networking == false ) {
		dprintf( D_ALWAYS, "VM networking is disabled\n");
	}else {
		dprintf( D_ALWAYS, "VM networking is enabled\n");
		dprintf( D_ALWAYS, "Supported networking types are %s\n", 
				tmp_networking_types.Value());
	}
			
	// Now, we received correct information from vmgahp
	m_vm_type = tmp_vmtype;
	m_vmgahp_server = gahppath;

	return true;
}
Ejemplo n.º 7
0
int
run_simple_docker_command(const std::string &command, const std::string &container, int timeout, CondorError &, bool ignore_output)
{
  ArgList args;
  if ( ! add_docker_arg(args))
    return -1;
  args.AppendArg( command );
  args.AppendArg( container.c_str() );

  MyString displayString;
  args.GetArgsStringForLogging( & displayString );
  dprintf( D_FULLDEBUG, "Attempting to run: %s\n", displayString.c_str() );

#if 1
	MyPopenTimer pgm;
	if (pgm.start_program( args, true, NULL, false ) < 0) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	if ( ! pgm.wait_and_close(timeout) || pgm.output_size() <= 0) {
		int error = pgm.error_code();
		if( error ) {
			dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), pgm.error_str(), error );
			if (pgm.was_timeout()) {
				dprintf( D_ALWAYS | D_FAILURE, "Declaring a hung docker\n");
				return DockerAPI::docker_hung;
			}
		} else {
			dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
		}
		return -3;
	}

	// On a success, Docker writes the containerID back out.
	MyString line;
	line.readLine(pgm.output());
	line.chomp(); line.trim();
	if (!ignore_output && line != container.c_str()) {
		// Didn't get back the result I expected, report the error and check to see if docker is hung.
		dprintf( D_ALWAYS | D_FAILURE, "Docker %s failed, printing first few lines of output.\n", command.c_str());
		for (int ii = 0; ii < 10; ++ii) {
			if ( ! line.readLine(pgm.output(), false)) break;
			dprintf( D_ALWAYS | D_FAILURE, "%s\n", line.c_str() );
		}
		return -4;
	}

#else
  // Read from Docker's combined output and error streams.
  FILE * dockerResults = my_popen( args, "r", 1 , 0, false);
  if( dockerResults == NULL ) {
    dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
    return -2;
  }

  // On a success, Docker writes the containerID back out.
  char buffer[1024];
  if( NULL == fgets( buffer, 1024, dockerResults ) ) {
    if( errno ) {
      dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), strerror( errno ), errno );
    } else {
      dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
    }
    my_pclose( dockerResults );
    return -3;
  }

  size_t length = strlen( buffer );
  if (!ignore_output) {
    if( length < 1 || strncmp( buffer, container.c_str(), length - 1 ) != 0 ) {
      dprintf( D_ALWAYS | D_FAILURE, "Docker %s failed, printing first few lines of output.\n", command.c_str() );
      dprintf( D_ALWAYS | D_FAILURE, "%s", buffer );
      while( NULL != fgets( buffer, 1024, dockerResults ) ) {
	dprintf( D_ALWAYS | D_FAILURE, "%s", buffer );
      }
      my_pclose( dockerResults );
      return -4;
    }
  }

  my_pclose( dockerResults );
#endif
  return 0;
}
Ejemplo n.º 8
0
Archivo: man.c Proyecto: haggaie/man
/*
 * Create command to format FILE, in the directory PATH/manX
 */
static char *
make_roff_command (const char *path, const char *file) {
     FILE *fp;
     static char buf [BUFSIZE];
     char line [BUFSIZE], bufh [BUFSIZE], buft [BUFSIZE];
     int status, ll;
     char *cp, *fgr, *pl;
     char *command = "";
     const char *expander;
     const char *converter;

     /* if window size differs much from 80, try to adapt */
     /* (but write only standard formatted files to the cat directory,
	see can_use_cache) */
     ll = setll();
     pl = setpl();
     if (ll && debug)
	  gripe (NO_CAT_FOR_NONSTD_LL);

     expander = get_expander (file);
     converter = get_converter (path);

     /* head */
     bufh[0] = 0;
     if (ll || pl) {
	  /* some versions of echo do not accept the -e flag,
	     so we just use two echo calls when needed */
	  strcat(bufh, "(");
	  if (ll) {
	       /*
		* We should set line length and title line length.
		* However, a .lt command here fails, only
		*  .ev 1; .lt ...; .ev helps for my version of groff.
		* The LL assignment is needed by the mandoc macros.
		*/
	       sprintf(eos(bufh), "echo \".ll %d.%di\"; ", ll/10, ll%10);
	       sprintf(eos(bufh), "echo \".nr LL %d.%di\"; ", ll/10, ll%10);
#if 0
	       sprintf(eos(bufh), "echo \".lt %d.%di\"; ", ll/10, ll%10);
#endif
	  }
	  if (pl)
	       sprintf(eos(bufh), "echo \".pl %.128s\"; ", pl);
     }

     /* tail */
     buft[0] = 0;
     if (ll || pl) {
	  if (pl && !strcmp(pl, VERY_LONG_PAGE))
	      /* At end of the nroff source, set the page length to
		 the current position plus 10 lines.  This plus setpl()
		 gives us a single page that just contains the whole
		 man page. (William Webber, [email protected]) */
	      strcat(buft, "; echo \".\\\\\\\"\"; echo \".pl \\n(nlu+10\"");
#if 0
	      /* In case this doesnt work for some reason,
		 michaelkjohnson suggests: I've got a simple
		 awk invocation that I throw into the pipeline: */

		 awk 'BEGIN {RS="\n\n\n\n*"} /.*/ {print}'
#endif
	  strcat(buft, ")");
     }

     if (expander && *expander) {
	  if (converter && *converter)
	     command = my_xsprintf("%s%s '%S' | %s%s",
				   bufh, expander, file, converter, buft);
	  else
	     command = my_xsprintf("%s%s '%S'%s",
				   bufh, expander, file, buft);
     } else if (ll || pl) {
	  const char *cat = getval("CAT");
	  if (!cat || !*cat)
		  cat = "cat";

	  if (converter && *converter)
	      command = my_xsprintf("%s%s '%S' | %s%s",
				    bufh, cat, file, converter, buft);
	  else
	      command = my_xsprintf("%s%s '%S'%s",
				    bufh, cat, file, buft);
     }

     if (strlen(command) >= sizeof(buf))
	  exit(1);
     strcpy(buf, command);

     if (roff_directive != NULL) {
	  if (debug)
	       gripe (ROFF_FROM_COMMAND_LINE);

	  status = parse_roff_directive (roff_directive, file,
					 buf, sizeof(buf));

	  if (status == 0)
	       return buf;

	  if (status == -1)
	       gripe (ROFF_CMD_FROM_COMMANDLINE_ERROR);
     }

     if (expander && *expander) {
	  char *cmd = my_xsprintf ("%s %S", expander, file);
	  fp = my_popen (cmd, "r");
	  if (fp == NULL) {
	       perror("popen");
	       gripe (EXPANSION_FAILED, cmd);
	       return (NULL);
	  }
	  fgr = fgets (line, sizeof(line), fp);
	  pclose (fp);
     } else {
	  fp = fopen (file, "r");
	  if (fp == NULL) {
	       perror("fopen");
	       gripe (OPEN_ERROR, file);
	       return (NULL);
	  }
	  fgr = fgets (line, sizeof(line), fp);
	  fclose (fp);
     }

     if (fgr == NULL) {
	  perror("fgets");
	  gripe (READ_ERROR, file);
	  return (NULL);
     }

     cp = &line[0];
     if (*cp++ == '\'' && *cp++ == '\\' && *cp++ == '"' && *cp++ == ' ') {
	  if (debug)
	       gripe (ROFF_FROM_FILE, file);

	  status = parse_roff_directive (cp, file, buf, sizeof(buf));

	  if (status == 0)
	       return buf;

	  if (status == -1)
	       gripe (ROFF_CMD_FROM_FILE_ERROR, file);
     }

     if ((cp = getenv ("MANROFFSEQ")) != NULL) {
	  if (debug)
	       gripe (ROFF_FROM_ENV);

	  status = parse_roff_directive (cp, file, buf, sizeof(buf));

	  if (status == 0)
	       return buf;

	  if (status == -1)
	       gripe (MANROFFSEQ_ERROR);
     }

     if (debug)
	  gripe (USING_DEFAULT);

     (void) parse_roff_directive ("t", file, buf, sizeof(buf));

     return buf;
}
Ejemplo n.º 9
0
//
// FIXME: We have a lot of boilerplate code in this function and file.
//
int DockerAPI::version( std::string & version, CondorError & /* err */ ) {

	ArgList versionArgs;
	if ( ! add_docker_arg(versionArgs))
		return -1;
	versionArgs.AppendArg( "-v" );

	MyString displayString;
	versionArgs.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: '%s'.\n", displayString.c_str() );

#if 1
	MyPopenTimer pgm;
	if (pgm.start_program(versionArgs, true, NULL, false) < 0) {
		// treat 'file not found' as not really error
		int d_level = (pgm.error_code() == ENOENT) ? D_FULLDEBUG : (D_ALWAYS | D_FAILURE);
		dprintf(d_level, "Failed to run '%s' errno=%d %s.\n", displayString.c_str(), pgm.error_code(), pgm.error_str() );
		return -2;
	}

	int exitCode;
	if ( ! pgm.wait_for_exit(default_timeout, &exitCode)) {
		pgm.close_program(1);
		dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), pgm.error_str(), pgm.error_code() );
		return -3;
	}

	if (pgm.output_size() <= 0) {
		dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
		return -3;
	}

	MyStringSource * src = &pgm.output();
	MyString line;
	if (line.readLine(*src, false)) {
		line.chomp();
		bool jansens = strstr( line.c_str(), "Jansens" ) != NULL;
		bool bad_size = ! src->isEof() || line.size() > 1024 || line.size() < (int)sizeof("Docker version ");
		if (bad_size && ! jansens) {
			// check second line of output for the word Jansens also.
			MyString tmp; tmp.readLine(*src, false);
			jansens = strstr( tmp.c_str(), "Jansens" ) != NULL;
		}
		if (jansens) {
			dprintf( D_ALWAYS | D_FAILURE, "The DOCKER configuration setting appears to point to OpenBox's docker.  If you want to use Docker.IO, please set DOCKER appropriately in your configuration.\n" );
			return -5;
		} else if (bad_size) {
			dprintf( D_ALWAYS | D_FAILURE, "Read more than one line (or a very long line) from '%s', which we think means it's not Docker.  The (first line of the) trailing text was '%s'.\n", displayString.c_str(), line.c_str() );
			return -5;
		}
	}

	if( exitCode != 0 ) {
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, line.c_str() );
		return -4;
	}

	version = line.c_str();

#else
	FILE * dockerResults = my_popen( versionArgs, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	char buffer[1024];
	if( NULL == fgets( buffer, 1024, dockerResults ) ) {
		if( errno ) {
			dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), strerror( errno ), errno );
		} else {
			dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
		}
		my_pclose( dockerResults );
		return -3;
	}

	if( NULL != fgets( buffer, 1024, dockerResults ) ) {
		if( strstr( buffer, "Jansens" ) != NULL ) {
			dprintf( D_ALWAYS | D_FAILURE, "The DOCKER configuration setting appears to point to OpenBox's docker.  If you want to use Docker.IO, please set DOCKER appropriately in your configuration.\n" );
		} else {
			dprintf( D_ALWAYS | D_FAILURE, "Read more than one line (or a very long line) from '%s', which we think means it's not Docker.  The (first line of the) trailing text was '%s'.\n", displayString.c_str(), buffer );
		}
		my_pclose( dockerResults );
		return -5;
	}

	int exitCode = my_pclose( dockerResults );
	if( exitCode != 0 ) {
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, buffer );
		return -4;
	}

	size_t end = strlen(buffer);
	if (end > 0 && buffer[end-1] == '\n') { buffer[end-1] = '\0'; }
	version = buffer;
#endif
	sscanf(version.c_str(), "Docker version %d.%d", &DockerAPI::majorVersion, &DockerAPI::minorVersion);
	return 0;
}
Ejemplo n.º 10
0
int DockerAPI::inspect( const std::string & containerID, ClassAd * dockerAd, CondorError & /* err */ ) {
	if( dockerAd == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "dockerAd is NULL.\n" );
		return -2;
	}

	ArgList inspectArgs;
	if ( ! add_docker_arg(inspectArgs))
		return -1;
	inspectArgs.AppendArg( "inspect" );
	inspectArgs.AppendArg( "--format" );
	StringList formatElements(	"ContainerId=\"{{.Id}}\" "
								"Pid={{.State.Pid}} "
								"Name=\"{{.Name}}\" "
								"Running={{.State.Running}} "
								"ExitCode={{.State.ExitCode}} "
								"StartedAt=\"{{.State.StartedAt}}\" "
								"FinishedAt=\"{{.State.FinishedAt}}\" "
								"DockerError=\"{{.State.Error}}\" "
								"OOMKilled=\"{{.State.OOMKilled}}\" " );
	char * formatArg = formatElements.print_to_delimed_string( "\n" );
	inspectArgs.AppendArg( formatArg );
	free( formatArg );
	inspectArgs.AppendArg( containerID );

	MyString displayString;
	inspectArgs.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: %s\n", displayString.c_str() );

#if 1
	MyPopenTimer pgm;
	if (pgm.start_program(inspectArgs, true, NULL, false) < 0) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -6;
	}

	MyStringSource * src = NULL;
	if (pgm.wait_and_close(default_timeout)) {
		src = &pgm.output();
	}

	int expected_rows = formatElements.number();
	dprintf( D_FULLDEBUG, "exit_status=%d, error=%d, %d bytes. expecting %d lines\n",
		pgm.exit_status(), pgm.error_code(), pgm.output_size(), expected_rows );

	// If the output isn't exactly formatElements.number() lines long,
	// something has gone wrong and we'll at least be able to print out
	// the error message(s).
	std::vector<std::string> correctOutput(expected_rows);
	if (src) {
		MyString line;
		int i=0;
		while (line.readLine(*src,false)) {
			line.chomp();
			//dprintf( D_FULLDEBUG, "\t[%2d] %s\n", i, line.c_str() );
			if (i >= expected_rows) {
				if (line.empty()) continue;
				correctOutput.push_back(line.c_str());
			} else {
				correctOutput[i] = line.c_str();
			}
			std::string::iterator first = 
				std::find(correctOutput[i].begin(),
					correctOutput[i].end(),
					'\"');
			if (first != correctOutput[i].end()) {
				std::replace(++first,
					--correctOutput[i].end(), '\"','\'');
			}
			//dprintf( D_FULLDEBUG, "\tfix: %s\n", correctOutput[i].c_str() );
			++i;
		}
	}
#else
	FILE * dockerResults = my_popen( inspectArgs, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Unable to run '%s'.\n", displayString.c_str() );
		return -6;
	}

	// If the output isn't exactly formatElements.number() lines long,
	// something has gone wrong and we'll at least be able to print out
	// the error message(s).
	char buffer[1024];
	std::vector<std::string> correctOutput(formatElements.number());
	for( int i = 0; i < formatElements.number(); ++i ) {
		if( fgets( buffer, 1024, dockerResults ) != NULL ) {
			correctOutput[i] = buffer;
			std::string::iterator first = 
				std::find(correctOutput[i].begin(),
					correctOutput[i].end(),
					'\"');
			if (first != correctOutput[i].end()) {
				std::replace(++first,
					-- --correctOutput[i].end(), '\"','\'');
			}
		}
	}
	my_pclose( dockerResults );
#endif

	int attrCount = 0;
	for( int i = 0; i < formatElements.number(); ++i ) {
		if( correctOutput[i].empty() || dockerAd->Insert( correctOutput[i].c_str() ) == FALSE ) {
			break;
		}
		++attrCount;
	}

	if( attrCount != formatElements.number() ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to create classad from Docker output (%d).  Printing up to the first %d (nonblank) lines.\n", attrCount, formatElements.number() );
		for( int i = 0; i < formatElements.number() && ! correctOutput[i].empty(); ++i ) {
			dprintf( D_ALWAYS | D_FAILURE, "%s", correctOutput[i].c_str() );
		}
		return -4;
	}

	dprintf( D_FULLDEBUG, "docker inspect printed:\n" );
	for( int i = 0; i < formatElements.number() && ! correctOutput[i].empty(); ++i ) {
		dprintf( D_FULLDEBUG, "\t%s\n", correctOutput[i].c_str() );
	}
	return 0;
}
Ejemplo n.º 11
0
int DockerAPI::detect( CondorError & err ) {
	// FIXME: Remove ::version() as a public API and return it from here,
	// because there's no point in doing this twice.
	std::string version;
	int rval = DockerAPI::version( version, err );
	if( rval  != 0 ) {
		dprintf(D_ALWAYS, "DockerAPI::detect() failed to detect the Docker version; assuming absent.\n" );
		return -4;
	}

	ArgList infoArgs;
	if ( ! add_docker_arg(infoArgs))
		return -1;
	infoArgs.AppendArg( "info" );

	MyString displayString;
	infoArgs.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: '%s'.\n", displayString.c_str() );

#if 1
	MyPopenTimer pgm;
	if (pgm.start_program(infoArgs, true, NULL, false) < 0) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	int exitCode;
	if ( ! pgm.wait_for_exit(default_timeout, &exitCode) || exitCode != 0) {
		pgm.close_program(1);
		MyString line;
		line.readLine(pgm.output(), false); line.chomp();
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, line.c_str());
		return -3;
	}

	if (IsFulldebug(D_ALWAYS)) {
		MyString line;
		do {
			line.readLine(pgm.output(), false);
			line.chomp();
			dprintf( D_FULLDEBUG, "[docker info] %s\n", line.c_str() );
		} while (line.readLine(pgm.output(), false));
	}

#else
	FILE * dockerResults = my_popen( infoArgs, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	// Even if we don't care about the success output, the failure output
	// can be handy for debugging...
	char buffer[1024];
	std::vector< std::string > output;
	while( fgets( buffer, 1024, dockerResults ) != NULL ) {
		size_t end = strlen(buffer);
		if (end > 0 && buffer[end-1] == '\n') { buffer[end-1] = '\0'; }
		output.push_back( buffer );
	}
	for( unsigned i = 0; i < output.size(); ++i ) {
		dprintf( D_FULLDEBUG, "[docker info] %s\n", output[i].c_str() );
	}

	int exitCode = my_pclose( dockerResults );
	if( exitCode != 0 ) {
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, output[0].c_str() );
		return -3;
	}
#endif
	return 0;
}
Ejemplo n.º 12
0
int
DockerAPI::rmi(const std::string &image, CondorError &err) {
		// First, try to remove the named image
	run_simple_docker_command("rmi", image, default_timeout, err, true);
		
		// That may have succeed or failed.  It could have
		// failed if the image doesn't exist (anymore), or
		// if someone else deleted it outside of condor.
		// Check to see if the image still exists.  If it
		// has been removed, return 0.

	ArgList args;
	if ( ! add_docker_arg(args))
		return -1;
	args.AppendArg( "images" );
	args.AppendArg( "-q" );
	args.AppendArg( image );

	MyString displayString;
	args.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: '%s'.\n", displayString.c_str() );

#if 1
	MyPopenTimer pgm;
	if (pgm.start_program(args, true, NULL, false) < 0) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	int exitCode;
	if ( ! pgm.wait_for_exit(default_timeout, &exitCode) || exitCode != 0) {
		pgm.close_program(1);
		MyString line;
		line.readLine(pgm.output(), false); line.chomp();
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, line.c_str());
		return -3;
	}

	return pgm.output_size() > 0;
#else
	FILE * dockerResults = my_popen( args, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	char buffer[1024];
	std::vector< std::string > output;
	while( fgets( buffer, 1024, dockerResults ) != NULL ) {
		size_t end = strlen(buffer);
		if (end > 0 && buffer[end-1] == '\n') { buffer[end-1] = '\0'; }
		output.push_back( buffer );
	}

	int exitCode = my_pclose( dockerResults );
	if( exitCode != 0 ) {
		dprintf( D_ALWAYS, "'%s' did not exit successfully (code %d); the first line of output was '%s'.\n", displayString.c_str(), exitCode, output[0].c_str() );
		return -3;
	}

	if (output.size() == 0) {
		return 0;
	} else {
		return 1;
	}
#endif
}
Ejemplo n.º 13
0
int DockerAPI::rm( const std::string & containerID, CondorError & /* err */ ) {

	ArgList rmArgs;
	if ( ! add_docker_arg(rmArgs))
		return -1;
	rmArgs.AppendArg( "rm" );
	rmArgs.AppendArg( "-f" );  // if for some reason still running, kill first
	rmArgs.AppendArg( "-v" );  // also remove the volume
	rmArgs.AppendArg( containerID.c_str() );

	MyString displayString;
	rmArgs.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: %s\n", displayString.c_str() );

	// Read from Docker's combined output and error streams.
#if 1
	MyPopenTimer pgm;
	if (pgm.start_program( rmArgs, true, NULL, false ) < 0) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}
	const char * got_output = pgm.wait_and_close(default_timeout);

	// On a success, Docker writes the containerID back out.
	MyString line;
	if ( ! got_output || ! line.readLine(pgm.output(), false)) {
		int error = pgm.error_code();
		if( error ) {
			dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), pgm.error_str(), error );
			if (pgm.was_timeout()) {
				dprintf( D_ALWAYS | D_FAILURE, "Declaring a hung docker\n");
				return docker_hung;
			}
		} else {
			dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
		}
		return -3;
	}

	line.chomp(); line.trim();
	if (line != containerID.c_str()) {
		// Didn't get back the result I expected, report the error and check to see if docker is hung.
		return check_if_docker_offline(pgm, "Docker remove", -4);
	}
#else
	FILE * dockerResults = my_popen( rmArgs, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to run '%s'.\n", displayString.c_str() );
		return -2;
	}

	// On a success, Docker writes the containerID back out.
	char buffer[1024];
	if( NULL == fgets( buffer, 1024, dockerResults ) ) {
		if( errno ) {
			dprintf( D_ALWAYS | D_FAILURE, "Failed to read results from '%s': '%s' (%d)\n", displayString.c_str(), strerror( errno ), errno );
		} else {
			dprintf( D_ALWAYS | D_FAILURE, "'%s' returned nothing.\n", displayString.c_str() );
		}
		my_pclose( dockerResults );
		return -3;
	}

	int length = strlen( buffer );
	if( length < 1 || strncmp( buffer, containerID.c_str(), length - 1 ) != 0 ) {
		dprintf( D_ALWAYS | D_FAILURE, "Docker remove failed, printing first few lines of output.\n" );
		dprintf( D_ALWAYS | D_FAILURE, "%s", buffer );
		while( NULL != fgets( buffer, 1024, dockerResults ) ) {
			dprintf( D_ALWAYS | D_FAILURE, "%s", buffer );
		}
		my_pclose( dockerResults );
		return -4;
	}

	my_pclose( dockerResults );
#endif
	return 0;
}
Ejemplo n.º 14
0
int DockerAPI::inspect( const std::string & containerID, ClassAd * dockerAd, CondorError & /* err */ ) {
	if( dockerAd == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "dockerAd is NULL.\n" );
		return -2;
	}

	ArgList inspectArgs;
	if ( ! add_docker_arg(inspectArgs))
		return -1;
	inspectArgs.AppendArg( "inspect" );
	inspectArgs.AppendArg( "--format" );
	StringList formatElements(	"ContainerId=\"{{.Id}}\" "
								"Pid={{.State.Pid}} "
								"Name=\"{{.Name}}\" "
								"Running={{.State.Running}} "
								"ExitCode={{.State.ExitCode}} "
								"StartedAt=\"{{.State.StartedAt}}\" "
								"FinishedAt=\"{{.State.FinishedAt}}\" "
								"DockerError=\"{{.State.Error}}\" "
								"OOMKilled=\"{{.State.OOMKilled}}\" " );
	char * formatArg = formatElements.print_to_delimed_string( "\n" );
	inspectArgs.AppendArg( formatArg );
	free( formatArg );
	inspectArgs.AppendArg( containerID );

	MyString displayString;
	inspectArgs.GetArgsStringForLogging( & displayString );
	dprintf( D_FULLDEBUG, "Attempting to run: %s\n", displayString.c_str() );

	FILE * dockerResults = my_popen( inspectArgs, "r", 1 , 0, false);
	if( dockerResults == NULL ) {
		dprintf( D_ALWAYS | D_FAILURE, "Unable to run '%s'.\n", displayString.c_str() );
		return -6;
	}

	// If the output isn't exactly formatElements.number() lines long,
	// something has gone wrong and we'll at least be able to print out
	// the error message(s).
	char buffer[1024];
	std::vector<std::string> correctOutput(formatElements.number());
	for( int i = 0; i < formatElements.number(); ++i ) {
		if( fgets( buffer, 1024, dockerResults ) != NULL ) {
			correctOutput[i] = buffer;
			std::string::iterator first = 
				std::find(correctOutput[i].begin(),
					correctOutput[i].end(),
					'\"');
			if (first != correctOutput[i].end()) {
				std::replace(++first,
					-- --correctOutput[i].end(), '\"','\'');
			}
		}
	}
	my_pclose( dockerResults );

	int attrCount = 0;
	for( int i = 0; i < formatElements.number(); ++i ) {
		if( correctOutput[i].empty() || dockerAd->Insert( correctOutput[i].c_str() ) == FALSE ) {
			break;
		}
		++attrCount;
	}

	if( attrCount != formatElements.number() ) {
		dprintf( D_ALWAYS | D_FAILURE, "Failed to create classad from Docker output (%d).  Printing up to the first %d (nonblank) lines.\n", attrCount, formatElements.number() );
		for( int i = 0; i < formatElements.number() && ! correctOutput[i].empty(); ++i ) {
			dprintf( D_ALWAYS | D_FAILURE, "%s", correctOutput[i].c_str() );
		}
		return -4;
	}

	dprintf( D_FULLDEBUG, "docker inspect printed:\n" );
	for( int i = 0; i < formatElements.number() && ! correctOutput[i].empty(); ++i ) {
		dprintf( D_FULLDEBUG, "\t%s", correctOutput[i].c_str() );
	}

	return 0;
}
Ejemplo n.º 15
0
static bool
submit_try( ArgList &args, CondorID &condorID, bool prohibitMultiJobs )
{
  MyString cmd; // for debug output
  args.GetArgsStringForDisplay( &cmd );

  FILE * fp = my_popen( args, "r", MY_POPEN_OPT_WANT_STDERR );
  if (fp == NULL) {
    debug_printf( DEBUG_NORMAL, 
		  "ERROR: my_popen(%s) in submit_try() failed!\n",
		  cmd.Value() );
    return false;
  }
  
  //----------------------------------------------------------------------
  // Parse submit command output for a HTCondor job ID.  This
  // desperately needs to be replaced by HTCondor submit APIs.
  //
  // Typical condor_submit output for HTCondor v6 looks like:
  //
  //   Submitting job(s).
  //   Logging submit event(s).
  //   1 job(s) submitted to cluster 2267.
  //----------------------------------------------------------------------

  char buffer[UTIL_MAX_LINE_LENGTH];
  buffer[0] = '\0';

  	// Configure what we look for in the command output according to
	// which type of job we have.
  const char *marker = NULL;
  parse_submit_fnc parseFnc = NULL;

  marker = " submitted to cluster ";

  // Note: we *could* check how many jobs got submitted here, and
  // correlate that with how many submit events we see later on.
  // I'm not worrying about that for now...  wenger 2006-02-07.
  // We also have to check the number of jobs to get an accurate
  // count of submitted jobs to report in the dagman.out file.

  // We should also check whether we got more than one cluster, and
  // either deal with it correctly or generate an error message.
  parseFnc = parse_condor_submit;
  
  // Take all of the output (both stdout and stderr) from condor_submit,
  // and echo it to the dagman.out file.  Look for
  // the line (if any) containing the word "cluster" (HTCondor).
  // If we don't find such a line, something
  // went wrong with the submit, so we return false.  The caller of this
  // function can retry the submit by repeatedly calling this function.

  MyString  command_output("");
  MyString keyLine("");
  while (fgets(buffer, UTIL_MAX_LINE_LENGTH, fp)) {
    MyString buf_line = buffer;
	buf_line.chomp();
	debug_printf(DEBUG_VERBOSE, "From submit: %s\n", buf_line.Value());
	command_output += buf_line;
    if (strstr(buffer, marker) != NULL) {
	  keyLine = buf_line;
	}
  }

  { // Relocated this curly bracket to its previous position to hopefully
    // fix Coverity warning.  Not sure why these curly brackets are here
	// at all...  wenger 2013-06-12
    int status = my_pclose(fp) & 0xff;

    if (keyLine == "") {
      debug_printf(DEBUG_NORMAL, "failed while reading from pipe.\n");
      debug_printf(DEBUG_NORMAL, "Read so far: %s\n", command_output.Value());
      return false;
    }

    if (status != 0) {
		debug_printf(DEBUG_NORMAL, "Read from pipe: %s\n", 
					 command_output.Value());
		debug_printf( DEBUG_QUIET, "ERROR while running \"%s\": "
					  "my_pclose() failed with status %d (errno %d, %s)!\n",
					  cmd.Value(), status, errno, strerror( errno ) );
		return false;
    }
  }

  int	jobProcCount;
  if ( !parseFnc( keyLine.Value(), jobProcCount, condorID._cluster) ) {
		// We are going forward (do not return false here)
		// Expectation is that higher levels will catch that we
		// did not get a cluster initialized properly here, fail,
		// and write a rescue DAG. gt3658 2013-06-03
		//
		// This is better than the old failure that would submit
		// DAGMAN_MAX_SUBMIT_ATTEMPT copies of the same job.
      debug_printf( DEBUG_NORMAL, "WARNING: submit returned 0, but "
        "parsing submit output failed!\n" );
		// Returning here so we don't try to process invalid values
		// below.  (This should really return something like "submit failed
		// don't retry" -- see gittrac #3685.)
  	  return true;
  }

  	// Check for multiple job procs if configured to disallow that.
  if ( prohibitMultiJobs && (jobProcCount > 1) ) {
	debug_printf( DEBUG_NORMAL, "Submit generated %d job procs; "
				"disallowed by DAGMAN_PROHIBIT_MULTI_JOBS setting\n",
				jobProcCount );
	main_shutdown_rescue( EXIT_ERROR, Dag::DAG_STATUS_ERROR );
  }
  
  return true;
}
Ejemplo n.º 16
0
/**
 * merge_stderr_with_stdout is intended for clients of this function
 * that wish to have the old behavior, where stderr and stdout were
 * both added to the same StringList.
 */
int systemCommand( ArgList &args, priv_state priv, StringList *cmd_out, StringList * cmd_in,
		   StringList *cmd_err, bool merge_stderr_with_stdout)
{
	int result = 0;
	FILE *fp = NULL;
	FILE * fp_for_stdin = NULL;
	FILE * childerr = NULL;
	MyString line;
	char buff[1024];
	StringList *my_cmd_out = cmd_out;

	priv_state prev = PRIV_UNKNOWN;

	int stdout_pipes[2];
	int stdin_pipes[2];
	int pid;
	bool use_privsep = false;
	switch ( priv ) {
	case PRIV_ROOT:
		prev = set_root_priv();
		break;
	case PRIV_USER:
	case PRIV_USER_FINAL:
		prev = set_user_priv();
#if !defined(WIN32)
		if ( privsep_enabled() && (job_user_uid != get_condor_uid()) ) {
			use_privsep = true;
		}
#endif
		break;
	default:
		// Stay as Condor user
		;
	}
#if defined(WIN32)
	if((cmd_in != NULL) || (cmd_err != NULL))
	  {
	    vmprintf(D_ALWAYS, "Invalid use of systemCommand() in Windows.\n");
	    return -1;
	  }
	//if ( use_privsep ) {
	//	fp = privsep_popen(args, "r", want_stderr, job_user_uid);
	//}
	//else {
	fp = my_popen( args, "r", merge_stderr_with_stdout );
	//}
#else
	// The old way of doing things (and the Win32 way of doing
	//	things)
	// fp = my_popen( args, "r", want_stderr );
	if((cmd_err != NULL) && merge_stderr_with_stdout)
	  {
	    vmprintf(D_ALWAYS, "Invalid use of systemCommand().\n");
	    return -1;
	  }

	PrivSepForkExec psforkexec;
	char ** args_array = args.GetStringArray();
	int error_pipe[2];
		// AIX 5.2, Solaris 5.9, HPUX 11 don't have AF_LOCAL

	if(pipe(stdin_pipes) < 0)
	  {
	    vmprintf(D_ALWAYS, "Error creating pipe: %s\n", strerror(errno));
		deleteStringArray( args_array );
	    return -1;
	  }
	if(pipe(stdout_pipes) < 0)
	  {
	    vmprintf(D_ALWAYS, "Error creating pipe: %s\n", strerror(errno));
	    close(stdin_pipes[0]);
	    close(stdin_pipes[1]);
		deleteStringArray( args_array );
	    return -1;
	  }

	if ( use_privsep ) {
	  if(!psforkexec.init())
	    {
	      vmprintf(D_ALWAYS,
		       "my_popenv failure on %s\n",
		       args_array[0]);
	      close(stdin_pipes[0]);
	      close(stdin_pipes[1]);
	      close(stdout_pipes[0]);
	      close(stdout_pipes[1]);
		  deleteStringArray( args_array );
	      return -1;
	    }
	}

	if(cmd_err != NULL)
	  {
	    if(pipe(error_pipe) < 0)
	      {
		vmprintf(D_ALWAYS, "Could not open pipe for error output: %s\n", strerror(errno));
		close(stdin_pipes[0]);
		close(stdin_pipes[1]);
		close(stdout_pipes[0]);
		close(stdout_pipes[1]);
		deleteStringArray( args_array );
		return -1;
	      }
	  }
	// Now fork and do what my_popen used to do
	pid = fork();
	if(pid < 0)
	  {
	    vmprintf(D_ALWAYS, "Error forking: %s\n", strerror(errno));
		close(stdin_pipes[0]);
		close(stdin_pipes[1]);
		close(stdout_pipes[0]);
		close(stdout_pipes[1]);
		if(cmd_err != NULL) {
			close(error_pipe[0]);
			close(error_pipe[1]);
		}
		deleteStringArray( args_array );
	    return -1;
	  }
	if(pid == 0)
	  {
	    close(stdout_pipes[0]);
	    close(stdin_pipes[1]);
	    dup2(stdout_pipes[1], STDOUT_FILENO);
	    dup2(stdin_pipes[0], STDIN_FILENO);

	    if(merge_stderr_with_stdout) dup2(stdout_pipes[1], STDERR_FILENO);
	    else if(cmd_err != NULL) 
	      {
		close(error_pipe[0]);
		dup2(error_pipe[1], STDERR_FILENO);
	      }


	    uid_t euid = geteuid();
	    gid_t egid = getegid();
	    seteuid( 0 );
	    setgroups( 1, &egid );
	    setgid( egid );
	    setuid( euid );
	    
	    install_sig_handler(SIGPIPE, SIG_DFL);
	    sigset_t sigs;
	    sigfillset(&sigs);
	    sigprocmask(SIG_UNBLOCK, &sigs, NULL);


	    MyString cmd = args_array[0];

	    if ( use_privsep ) {
	    
	      ArgList al;
	      psforkexec.in_child(cmd, al);
          deleteStringArray( args_array );
	      args_array = al.GetStringArray();
	    }


	    execvp(cmd.Value(), args_array);
	    vmprintf(D_ALWAYS, "Could not execute %s: %s\n", args_array[0], strerror(errno));
	    exit(-1);
	  }
	close(stdin_pipes[0]);
	close(stdout_pipes[1]);
	fp_for_stdin = fdopen(stdin_pipes[1], "w");
	fp = fdopen(stdout_pipes[0], "r");
	if(cmd_err != NULL)
	  {
	    close(error_pipe[1]);
	    childerr = fdopen(error_pipe[0],"r");
	    if(childerr == 0)
	      {
		vmprintf(D_ALWAYS, "Could not open pipe for reading child error output: %s\n", strerror(errno));
		close(error_pipe[0]);
		close(stdin_pipes[1]);
		close(stdout_pipes[0]);
	    fclose(fp);
		fclose(fp_for_stdin);
		deleteStringArray( args_array );
		return -1;
	      }
	  }

	if ( use_privsep ) {
	  FILE* _fp = psforkexec.parent_begin();
	  privsep_exec_set_uid(_fp, job_user_uid);
	  privsep_exec_set_path(_fp, args_array[0]);
	  privsep_exec_set_args(_fp, args);
	  Env env;
	  env.MergeFrom(environ);
	  privsep_exec_set_env(_fp, env);
	  privsep_exec_set_iwd(_fp, ".");

	  privsep_exec_set_inherit_fd(_fp, 1);
	  privsep_exec_set_inherit_fd(_fp, 2);
	  privsep_exec_set_inherit_fd(_fp, 0);
	
	  if (!psforkexec.parent_end()) {
	    vmprintf(D_ALWAYS,
		     "my_popenv failure on %s\n",
		     args_array[0]);
	    fclose(fp);
		fclose(fp_for_stdin);
		if (childerr) {
			fclose(childerr);
		}
		deleteStringArray( args_array );
	    return -1;
	  }
	}

	deleteStringArray( args_array );
#endif
	set_priv( prev );
	if ( fp == NULL ) {
		MyString args_string;
		args.GetArgsStringForDisplay( &args_string, 0 );
		vmprintf( D_ALWAYS, "Failed to execute command: %s\n",
				  args_string.Value() );
		if (childerr)
			fclose(childerr);
		return -1;
	}

	if(cmd_in != NULL) {
	  cmd_in->rewind();
	  char * tmp;
	  while((tmp = cmd_in->next()) != NULL)
	    {
	      fprintf(fp_for_stdin, "%s\n", tmp);
	      fflush(fp_for_stdin);
	    }
	}
	if (fp_for_stdin) {
	  // So that we will not be waiting for output while the
	  // script waits for stdin to be closed.
	  fclose(fp_for_stdin);
	}

	if ( my_cmd_out == NULL ) {
		my_cmd_out = new StringList();
	}

	while ( fgets( buff, sizeof(buff), fp ) != NULL ) {
		line += buff;
		if ( line.chomp() ) {
			my_cmd_out->append( line.Value() );
			line = "";
		}
	}

	if(cmd_err != NULL)
	  {
	    while(fgets(buff, sizeof(buff), childerr) != NULL)
	      {
		line += buff;
		if(line.chomp())
		  {
		    cmd_err->append(line.Value());
		    line = "";
		  }
	      }
	    fclose(childerr);
	  }
#if defined(WIN32)
	result = my_pclose( fp );
#else
	// Why close first?  Just in case the child process is waiting
	// on a read, and we have nothing more to send it.  It will
	// now receive a SIGPIPE.
	fclose(fp);
	if(waitpid(pid, &result, 0) < 0)
	  {
	    vmprintf(D_ALWAYS, "Unable to wait: %s\n", strerror(errno));
		if ( cmd_out == NULL ) {
			delete my_cmd_out;
		}
	   
	    return -1;
	  }
#endif
	if( result != 0 ) {
		MyString args_string;
		args.GetArgsStringForDisplay(&args_string,0);
		vmprintf(D_ALWAYS,
		         "Command returned non-zero: %s\n",
		         args_string.Value());
		my_cmd_out->rewind();
		const char *next_line;
		while ( (next_line = my_cmd_out->next()) ) {
			vmprintf( D_ALWAYS, "  %s\n", next_line );
		}
	}
	if ( cmd_out == NULL ) {
		delete my_cmd_out;
	}
	return result;
}
Ejemplo n.º 17
0
Archivo: man.c Proyecto: haggaie/man
/*
 * Try to find the ultimate source file.  If the first line of the
 * current file is not of the form
 *
 *      .so man3/printf.3s
 *
 * the input file name is returned.
 *
 * For /cd/usr/src/usr.bin/util-linux-1.5/mount/umount.8.gz
 * (which contains `.so man8/mount.8')
 * we return /cd/usr/src/usr.bin/util-linux-1.5/mount/mount.8.gz .
 *
 * For /usr/man/man3/TIFFScanlineSize.3t
 * (which contains `.so TIFFsize.3t')
 * we return /usr/man/man3/TIFFsize.3t .
 */
static const char *
ultimate_source (const char *name0) {
     FILE *fp;
     char *name;
     const char *expander;
     int expfl = 0;
     char *fgr;
     char *beg;
     char *end;
     char *cp;
     char buf[BUFSIZE];
     static char ultname[BUFSIZE];

     if (strlen(name0) >= sizeof(ultname))
	     return name0;
     strcpy(ultname, name0);
     name = ultname;

again:
     expander = get_expander (name);
     if (expander && *expander) {
	  char *command;

	  command = my_xsprintf ("%s %S", expander, name);
	  fp = my_popen (command, "r");
	  if (fp == NULL) {
	       perror("popen");
	       gripe (EXPANSION_FAILED, command);
	       return (NULL);
	  }
	  fgr = fgets (buf, sizeof(buf), fp);

          #ifdef __APPLE__
          /* Man 1.5x randomly freezes under Mac OS X 10.4.7 when the 
             man page is compressed (with either gzip or bzip2), and 
             only with large pages.
             The freeze occurs at the pclose function, and a ps shows 
             that gunzip is still running. 

             The problem is the specification of pclose(): The pclose()
             function waits for the associated process to terminate
             and returns the exit status of the command as returned by 
             wait4().

             So, if gunzip is started to look at the start of a file and 
             the file is larger than the buffer used by stdio then the 
             first read does not read everything, and the pclose hangs. */

          /* Reading loop insures lockup cannot occur */
          char dummy[BUFSIZE]; 
          while (fgets (dummy,sizeof(dummy),fp) ); 
          #endif // __APPLE__

	  pclose (fp);
	  expfl = 1;
     } else {
	  fp = fopen (name, "r");
	  if (fp == NULL && expfl) {
	       char *extp = rindex (name0, '.');
	       if (extp && *extp && strlen(name)+strlen(extp) < BUFSIZE) {
		    strcat(name, extp);
		    fp = fopen (name, "r");
	       }
	  }
	  /*
	   * Some people have compressed man pages, but uncompressed
	   * .so files - we could glob for all possible extensions,
	   * for now: only try .gz
	   */
	  else if (fp == NULL && get_expander(".gz") &&
		   strlen(name)+strlen(".gz") < BUFSIZE) {
	       strcat(name, ".gz");
	       fp = fopen (name, "r");
	  }

	  if (fp == NULL) {
	       perror("fopen");
	       gripe (OPEN_ERROR, name);
	       return (NULL);
	  }
	  fgr = fgets (buf, sizeof(buf), fp);
	  fclose (fp);
     }

     if (fgr == NULL) {
	  perror("fgets");
	  gripe (READ_ERROR, name);
	  return (NULL);
     }

     if (strncmp(buf, ".so", 3))
	  return (my_strdup(name));

     beg = buf+3;
     while (*beg == ' ' || *beg == '\t')
	  beg++;

     end = beg;
     while (*end != ' ' && *end != '\t' && *end != '\n' && *end != '\0')
	  end++;		/* note that buf is NUL-terminated */
     *end = '\0';

     /* If name ends in path/manx/foo.9x then use path, otherwise
	try same directory. */
     if ((cp = rindex(name, '/')) == NULL) /* very strange ... */
	  return 0;
     *cp = 0;

     /* allow "man ./foo.3" where foo.3 contains ".so man2/bar.2" */
     if ((cp = rindex(name, '/')) != NULL && !strcmp(cp+1, "."))
	  *cp = 0;

     /* In all cases, the new name will be something from name
	followed by something from beg. */
     if (strlen(name) + strlen(beg) + 1 >= BUFSIZ)
	  return 0;		/* very long names, ignore */

     if (!index(beg, '/')) {
	  /* strange.. try same directory as the .so file */
	  strcat(name, "/");
	  strcat(name, beg);
     } else if((cp = rindex(name, '/')) != NULL && !strncmp(cp+1, "man", 3)) {
	  strcpy(cp+1, beg);
     } else if((cp = rindex(beg, '/')) != NULL) {
	  strcat(name, cp);
     } else {
	  strcat(name, "/");
	  strcat(name, beg);
     }

     goto again;
}