示例#1
0
/// Any PTXes which survived shopping are eligible to be winners,
/// as long as they've been seen and evaluated at all. This test is
/// necessary because not all commands are run in all PTXes, so the
/// fact that a PTX has not been invalidated could mean it was not
/// even evaluated.
/// This function returns the first eligible surviving PTX. It does not
/// establish a policy per se; since PTXes are stored in an order set by
/// the server, the policy of which matching PTX is 'best' can be
/// dictated by the server.
/// @return the chosen PTX id
static CCS
_shop_ptx_winner(shopping_state_s *ssp)
{
    dnode_t *dnp, *next;

    ssp->wix[0] = ssp->winner[0] = '\0';

    if (ssp->ptx_dict) {
	for (dnp = dict_first(ssp->ptx_dict); dnp;) {
	    CCS key, id;

	    next = dict_next(ssp->ptx_dict, dnp);

	    key = (CCS)dnode_getkey(dnp);
	    id = (CCS)dnode_get(dnp);

	    // Remember, only an evaluated PTX can be a winner.
	    // These are marked with a lower-case index, but
	    // convert it back to upper case before returning.
	    if (islower((int)key[0])) {
		snprintf(ssp->wix, charlen(ssp->wix), "%c%s",
		    toupper((int)key[0]), key + 1);
		snprintf(ssp->winner, charlen(ssp->winner), "%s", id);
		return ssp->winner;
	    }

	    dnp = next;
	}
    }

    return NULL;
}
示例#2
0
/// Modifies a string-valued property in place. Main reason to do this is if
/// the property is exported. Doing a putenv of the new value can cause
/// the environment block to be realloc-ed, i.e. moved, which can
/// confuse the host process badly.
/// So sometimes we need to overwrite the existing env value instead.
/// Our own exported numeric properties are zero-padded in the
/// environment block to ensure room for new values.
/// @param[in] prop     a property
/// @param[in] val      the new value
/// @param[in,out] envp optionally, a pointer to a custom env block
void
prop_mod_str(prop_e prop, CCS val, char *const *envp)
{
    int ovlen;
    char nbuf[PROP_NAME_MAX];

    assert(proptab[prop].pr_flags & PROP_FLAG_EXPORT);

    if (!proptab[prop].pr_value) {
	putil_int("property %s is not set", proptab[prop].pr_name);
    }

    if (proptab[prop].pr_value != val) {
	if (strlen(val) > strlen(proptab[prop].pr_value)) {
	    putil_int("property '%s=%s' has no room for value '%s'",
		      proptab[prop].pr_name, proptab[prop].pr_value, val);
	}

	ovlen = strlen(proptab[prop].pr_value);
	snprintf(proptab[prop].pr_value, ovlen + 1, "%*s", ovlen, val);
    }

    _prop_to_ev(prop, nbuf, charlen(nbuf));
    if (!_prop_modify_env_val(envp, nbuf, val)) {
	putil_warn("can't update env var %s to '%s'", nbuf, val);
    }
}
示例#3
0
/// Constructor - creates a new (singleton) Properties object.
/// @param[in] app      the name of this application
void
prop_init(CCS app)
{
    assert(!proptab[P_APP].pr_value);
    proptab[P_APP].pr_value = util_strdown(putil_strdup(app));
    prop_assert(P_APP);

    // Initialize the prefix which is used for exported properties.
    snprintf(PropEnvPrefix, charlen(PropEnvPrefix),
	"_%s_", proptab[P_APP].pr_value);
    util_strup(PropEnvPrefix);
    PropEnvPrefixLen = strlen(PropEnvPrefix);
#if defined(_WIN32)
    (void)MultiByteToWideChar(CP_ACP, 0, PropEnvPrefix, -1,
	PropEnvPrefixW, charlen(PropEnvPrefixW));
#endif	/*_WIN32*/
}
示例#4
0
/// Sets a signed numeric-valued property. Integral-valued but
/// handled as a long for flexibility.
/// @param[in] prop     a property
/// @param[in] val      the new value for this property as a signed long
void
prop_put_long(prop_e prop, long val)
{
    char vbuf[64];

    snprintf(vbuf, charlen(vbuf), "%ld", val);
    prop_put_str(prop, vbuf);
}
示例#5
0
/// Sets an unsigned numeric-valued property. Integral-valued but
/// handled as a long for flexibility.
/// @param[in] prop     a property
/// @param[in] val      the new value for this property as an unsigned long
void
prop_put_ulong(prop_e prop, unsigned long val)
{
    char vbuf[64];

    snprintf(vbuf, charlen(vbuf), "%lu", val);
    prop_put_str(prop, vbuf);
}
示例#6
0
/// Calculates a buffer big enough for the new env
/// block plus the 'envp' (char **) array which Unix uses and
/// Windows doesn't (but which we need for sorting on Windows anyway)
/// plus terminating nulls.
size_t
prop_new_env_block_sizeA(char *const *cenv)
{
    size_t plen;
    int prop;
    int charwidth = sizeof(char);

    // Figure out how many bytes are in the provided env.
    // We might end up counting properties twice for size
    // purposes but that's ok, the block is short-lived.
#if defined(_WIN32)
    char *sp;

    for (plen = 0, sp = (char *)cenv; *sp; sp += strlen(sp) + 1) {
	plen += (strlen(sp) + 1) * charwidth;
	plen += sizeof(char *);
    }
    // The Windows block will be terminated by double null chars.
    plen += charwidth;
#else	/*_WIN32*/
    char **ep;

    for (plen = 0, ep = (char **)cenv; *ep; ep++) {
	plen += strlen(*ep) + charwidth;
	plen += sizeof(char *);
    }
#endif	/*_WIN32*/

    // For the NULL pointer which terminates envp.
    // Remember that we construct an envp even for Windows which
    // doesn't use one because we need it for sorting, which
    // Windows does require.
    plen += sizeof(char **);

    // Add the additional bytes which must be exported from properties.
    for (prop = 0; proptab[prop].pr_name; prop++) {
	char name[PROP_NAME_MAX];

	if (!proptab[prop].pr_value ||
	    !(proptab[prop].pr_flags & PROP_FLAG_EXPORT)) {
	    continue;
	}
	_prop_to_ev((prop_e)prop, name, charlen(name));
	// Account for ["name" '=' "value" '\0']
	plen += (strlen(name) +
		 strlen(proptab[prop].pr_value) + 2) * charwidth;
	plen += sizeof(char *);
    }

    // Don't forget the extra pointer at the front for Unix/Win consistency.
    plen += sizeof(char **);

    return plen;
}
示例#7
0
unsigned char *
git_map_blob(CCS blob)
{
    int fd;
    unsigned long len;
    unsigned char *fdata;
    char hdr[] = "blob ", buf[256], *p;

    if ((fd = open64(blob, O_RDONLY|O_BINARY)) == -1) {
	putil_syserr(2, blob);
    }

    if (util_read_all(fd, buf, charlen(buf)) <= 0) {
	putil_syserr(2, blob);
    }

    // Scan for the header: "blob <len>\0" ...
    memset(buf, 0, sizeof(buf));
    for (p = buf; strncmp(buf, "blob ", 5); ) {
	if (util_read_all(fd, p, 1) <= 0) {
	    putil_syserr(2, blob);
	}
	if (*p == hdr[p - buf]) {
	    p++;
	} else {
	    p = buf;
	}
    }
    for (p = buf; *p && ((size_t)(p - buf) < charlen(buf)); p++) {
	if (util_read_all(fd, p, 1) <= 0) {
	    putil_syserr(2, blob);
	}
    }

    // ... then map that much of the blob.
    len = strtoul(buf, NULL, 10);
    fdata = util_map_file(blob, fd, 0, len);
    close(fd);

    return fdata;
}
示例#8
0
/// Modifies an unsigned numeric-valued property in place.
/// @param[in] prop     a property
/// @param[in] val      the new value
/// @param[in,out] envp optionally, a pointer to a custom env block
void
prop_mod_ulong(prop_e prop, unsigned long val, char *const *envp)
{
    char vbuf[64];

    assert(proptab[prop].pr_flags & PROP_FLAG_EXPORT);

    if (!proptab[prop].pr_value) {
	putil_int("property %s not set", proptab[prop].pr_name);
    }
    snprintf(vbuf, charlen(vbuf), "%lu", val);

    // Any overflows should be detected here.
    prop_mod_str(prop, vbuf, envp);
}
示例#9
0
// Export the specified property to the environment, uppercased,
// with the appname prefixed, and all dots replaced with underscores.
static void
_prop_export(prop_e prop)
{
    char namebuf[PROP_NAME_MAX];
    char *name;
    CS str;
    CCS val;

    if (!(val = prop_get_str(prop))) {
	_prop_report_missing(prop, 1);
    }
    _prop_to_ev(prop, namebuf, charlen(namebuf));
    name = namebuf;

    /* These properties are public so leave off the underscore */
    if (prop == P_BASE_DIR || prop == P_PROJECT_NAME) {
	name++;
    }

#if defined(_WIN32)
    str = (CS)alloca(PROP_STR_MAX);
    if (GetEnvironmentVariable(name, str, PROP_STR_MAX) && !strcmp(str, val)) {
	return;
    }
    if (!SetEnvironmentVariable(name, val)) {
	putil_syserr(0, name);
    }
    if (GetEnvironmentVariable(name, str, PROP_STR_MAX)) {
	assert(!strcmp(str, val));
    }
#else	/*_WIN32*/
    if ((str = putil_getenv(name)) && !strcmp(str, val)) {
	return;
    }
    str = (CS)putil_calloc(strlen(name) + strlen(val) + 2, CHARSIZE);
    strcpy(str, name);
    strcat(str, "=");
    strcat(str, val);
    putil_putenv(str);
    // Despite the confusing putenv man page we must NOT free this str.
    // Unfortunately Sun's bcheck will show it as a memory leak.
    // Sadly, so does valgrind 3.4.1 on Linux ...
    //putil_free(str);
#endif	/*_WIN32*/

    return;
}
示例#10
0
// Internal service routine to make verbosity easier.
static void
_ca_verbosity_pa(pa_o pa, ca_o ca, CCS action)
{
    // Checking the verbosity bit twice here is actually an optimization.
    if (vb_bitmatch(VB_PA)) {
        moment_s timestamp;

        timestamp = pa_get_timestamp(pa);
        if (timestamp.ntv_sec) {
            char tstamp[MOMENT_BUFMAX];

            (void)moment_format(timestamp, tstamp, charlen(tstamp));
            vb_printf(VB_PA, "%s %c %s: (%s %s)", action,
                      pa_get_op(pa), ca_get_prog(ca),
                      tstamp, pa_get_abs(pa));
        }
    }
}
示例#11
0
char *escape (unsigned char *s)
{
    int
	i,
	j,
	n;
    unsigned long
	c;

    j = 0;

    for (i = 0; s [i]; i += n) {
	n = charlen (s[i]);

	switch (n){
	    case 1: c = (unsigned char) s [i]; break;
	    case 2: c = bytes2 (s + i); break;
	    case 3: c = bytes3 (s + i); break;
	    case 4: c = bytes4 (s + i); break;
	    case 5: c = bytes5 (s + i); break;
	    case 6: c = bytes6 (s + i); break;
	    default: c = 32;
	}

	if (c == 43 || c == 45 || (c >= 48 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122))
	    buffer6[j++] = (char) c;
	else {
	    sprintf (buffer6 + j, "_%lu_", c);
	    for ( ; buffer6 [j]; j++)
		;
	}
    }

    if (! j) {
	buffer6 [j++] = '_';
	buffer6 [j++] = '_';
    }

    buffer6 [j] = '\0';

    return buffer6;

}
示例#12
0
/// Make sure the specified property will not be exported to children.
/// This has no effect on the current setting of the property.
/// WARNING: must not be called from the auditor.
/// @param[in] prop     the specified property
/// @param[in] forever  boolean - if set, newly set values no longer exported
void
prop_unexport(prop_e prop, int forever)
{
    char buf[PROP_NAME_MAX];

    _prop_to_ev(prop, buf, charlen(buf));

#if defined(_WIN32)
    SetEnvironmentVariable(buf, NULL);
#else	/*_WIN32*/
    putil_unsetenv(buf);
#endif	/*_WIN32*/

    if (forever) {
	proptab[prop].pr_flags &= ~PROP_FLAG_EXPORT;
    }

    return;
}
示例#13
0
void str2pattern ()
{
    char
	chr [10];
    int
	i,
	j,
	n;

    j = 0;
    for (i = 0; buffer [i]; i += n) {
	n = charlen (buffer [i]);
	memcpy (chr, buffer + i, n);
	chr [n] = '\0';
	if (bsearch (chr, valchars, n_valchars, sizeof (char *), searchcmp)) {
	    memcpy (buffer2 + j, buffer + i, n);
	    j += n;
	}
    }
    buffer2[ j] = '\0';
}
示例#14
0
/// Generates the 'pathcode' - a hash of all pathnames opened by this cmd.
/// The combination of command line and pathcode is believed
/// sufficent to uniquely identify any given command, because
/// if two commands with identical textual representations operate on the
/// same set of files, they must be functionally identical.
/// In other words the command line says what to do and the pathcode
/// says who it's done to. Thus 'touch foo' might be repeated in different
/// places but it's only the *same command* if the 'foo' it touches
/// is at the same absolute path. Similarly, 'make' might occur all
/// over in a recursive-make build but it's not the same make unless it
/// opens the same Makefile. Another way of putting it: if a cmd addresses
/// any files relative to CWD, this will be seen in the absolute paths
/// of the files it opens. If it doesn't then the CWD doesn't matter.
/// Of course there can still be semantically identical cmds which look
/// different: consider "rm foo bar" and "rm bar foo". But these cases
/// would be very rare in real life and don't break anything - we would
/// just miss a potential recycle opportunity.
/// @param[in] ca       the object pointer
void
ca_derive_pathcode(ca_o ca)
{
    pathcode_accumulator_s pca;

    pca.pca_buf = NULL;
    pca.pca_buflen = 0;
    pca.pca_count = 0;

    (void)ca_foreach_cooked_pa(ca, _ca_add_to_pathcode, &pca);

    if (pca.pca_buf) {
        char pcbuf[CODE_IDENTITY_HASH_MAX_LEN];

        (void)code_from_str(pca.pca_buf, pcbuf, charlen(pcbuf));
        putil_free(pca.pca_buf);
        snprintf(endof(pcbuf), leftlen(pcbuf), "-%d", pca.pca_count);
        ca_set_pathcode(ca, pcbuf);
    } else {
        ca_set_pathcode(ca, NULL);
    }
}
示例#15
0
void
tee_into(const char *into)
{
    FILE *teeout;
    ssize_t nread;
    char buf[BUFSIZ];
    moment_s start, delta;
    char tstamp[MOMENT_BUFMAX];
    char prev_char = '\n';
    ssize_t i;
    int timestamp_prefix = 0;

    if (prop_is_true(P_LOG_TIME_STAMP)) {
	timestamp_prefix = 1;
	moment_get_systime(&start);
    }

    teeout = fopen(into, "w");

    if (!teeout) {
	putil_syserr(2, into);
    }

    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(teeout, NULL, _IONBF, 0);

    while (1) {
	nread = read(0, buf, sizeof buf);
	if (nread == 0) {
	    break;
	} else if (nread < 0) {
#ifdef EINTR
	    if (errno == EINTR)
		continue;
	    else
#endif
		putil_syserr(2, "read");
	}

	if (timestamp_prefix) {
	    moment_since(start, &delta);
	    (void)moment_format_milli(delta, tstamp, charlen(tstamp));
	}

	for (i = 0; i < nread; i++) {
	    if (timestamp_prefix && prev_char == '\n') {
		fprintf(stdout, "%s: ", tstamp);
		fprintf(teeout, "%s: ", tstamp);
	    }
	    prev_char = buf[i];
	    putc(buf[i], stdout);
	    putc(buf[i], teeout);
	}
    }

    fflush(NULL);
    fclose(stdout);
    fclose(teeout);

    exit(0);
}
示例#16
0
// Parses out a line from a *.properties file. Handles leading and
// trailing whitespace and delimiters as per the J2SE 1.4 Properties spec.
static int
_prop_process_line(CS line, int win)
{
    char buf[1024];
    CS bp, ep;
    prop_e prop;

    snprintf(buf, charlen(buf), "%s", line);
    bp = buf;
    ep = endof(buf) - 1;

    if (ep == bp) {
	return 0;
    }

    while (ISSPACE(*ep)) {
	*ep-- = '\0';
    }

    while (ISSPACE(*bp)) {
	bp++;
    }

    if (*bp == '#' || *bp == '!' || *bp == '\0') {
	return 0;
    }

    for (ep = bp; *ep && !ISSPACE(*ep) && *ep != '=' && *ep != ':'; ep++) {
	if (*ep == '\\') {	// handle \-escapes in key
	    int i;

	    for (i = 0; ep[i]; i++) {
		ep[i] = ep[i + 1];
	    }
	}
    }

    if (*ep == '\0') {
	return 1;
    }

    if (ISSPACE(*ep)) {
	*ep++ = '\0';
	while (ISSPACE(*ep)) {
	    ep++;
	}
	if (*ep == '=' || *ep == ':') {
	    ep++;
	}
    } else {
	*ep++ = '\0';
    }

    while (ISSPACE(*ep)) {
	ep++;
    }

    prop = prop_from_name(bp);
    if (prop == P_BADPROP) {
	putil_warn("unrecognized property: %s", bp);
    } else {
	if (win) {
	    prop_unset(prop, 0);
	}
	prop_put_str(prop, ep);
    }

    return 0;
}
示例#17
0
/// Returns an allocated string representing the CA without its PAs.
/// @param[in] ca       the object pointer
/// @return a string which should be freed when no longer needed
CCS
ca_format_header(ca_o ca)
{
    CS hdr, p;
    CCS freetext;
    char started[MOMENT_BUFMAX];
    int ret;

    (void)moment_format(ca->ca_starttime, started, charlen(started));

    freetext = ca->ca_freetext ? ca->ca_freetext : "";

    // *INDENT-OFF*
    ret = asprintf(&hdr,
			  "%lu%s"			// 1  - PID
			  "%lu%s"			// 2  - DEPTH
			  "%lu%s"			// 3  - PPID
			  "%s%s"			// 4  - STARTED
			  "%lu%s"			// 5  - DURATION
			  "%s%s"			// 6  - HOST
			  "%s%s"			// 7  - RECYCLED
			  "%s%s"			// 8  - FREETEXT
			  // Divider - CommandAction above, Command below
			  "%s%s"			// 9  - PROG
			  "%s%s"			// 10 - RWD
			  "%s%s"			// 11 - PCCODE
			  "%s%s"			// 12 - CCODE
			  "%s%s"			// 13 - PATHCODE
			  "%s@",			// 14 - CMDLINE
	ca->ca_cmdid, FS1,
	ca->ca_depth, FS1,
	ca->ca_pcmdid, FS1,
	started, FS1,
	ca->ca_duration, FS1,
	ca->ca_host ? ca->ca_host : "?", FS1,
	ca->ca_recycled ? ca->ca_recycled : "", FS1,
	freetext, FS1,
	// Divider - CommandAction above, Command below
	ca->ca_prog, FS1,
	ca->ca_rwd ? ca->ca_rwd : ".", FS1,
	ca_get_pccode(ca), FS1,
	ca_get_ccode(ca), FS1,
	ca_get_pathcode(ca), FS1,
	ca->ca_line);
    // *INDENT-ON*

    if (ret < 0) {
        putil_syserr(2, NULL);
    }

    // Since a CSV line must be a SINGLE line, it cannot tolerate embedded
    // newlines and we must replace them with a conventional token.
    // This should be a rare occurrence so we don't worry too much
    // about efficiency here.
    // TODO - why not just use our existing util_encode() for this?
    if (strchr(hdr, '\n')) {
        CS nhdr, o, n;

        nhdr = (CS)putil_calloc(strlen(hdr) * 2, CHARSIZE);
        for (o = hdr, n = nhdr; *o; o++) {
            if (*o == '\n') {
                strcpy(n, CSV_NEWLINE_TOKEN);
                n = endof(n);
            } else {
                *n++ = *o;
            }
        }
        putil_free(hdr);
        hdr = (CS)putil_realloc(nhdr, strlen(nhdr) + CHARSIZE);
    }

    // We know this is present because we put it there.
    if ((p = strrchr(hdr, '@'))) {
        *p = '\n';
    }

    return hdr;
}
示例#18
0
static void
_shop_compare_prereqs(shopping_state_s *ssp, CCS cmdix)
{
    char key[64];
    struct cdb_find cdbf_prq;
    unsigned vlen;

    snprintf(key, charlen(key), "<%s", cmdix);
    if (cdb_findinit(&cdbf_prq, ssp->cdbp, key, strlen(key)) < 0) {
	putil_die("cdb_findinit: %s (%s)", key, ca_get_line(ssp->ca));
    }

    while (cdb_findnext(&cdbf_prq) > 0 && _shop_ptx_count(ssp)) {
	CCS pskey;
	CS pskeys, prqline, ptxes1, ptxbuf, ixstr;
	int ptxesleft;

	// Read a prereq line from the roadmap.
	vlen = cdb_datalen(ssp->cdbp);
	prqline = (CS)alloca(vlen + 1);
	cdb_read(ssp->cdbp, prqline, vlen, cdb_datapos(ssp->cdbp));
	prqline[vlen] = '\0';

	// Split the line into a list of path states and a list of ptxes.
	if (!(ptxes1 = strstr(prqline, FS1))) {
	    putil_int("bad format in roadmap: %s", prqline);
	    break;
	}
	*ptxes1++ = '\0';
	pskeys = prqline;

	// Here we make a temporary copy of the ptx list and take a
	// quick run through it. If none of the listed ptxes remain
	// eligible, we can skip evaluating this set of path states.
	// On the other hand, if we do go on to evaluate any of these
	// ptxes, mark them as having been evaluated. In order to
	// be a winner you must not only survive the war but also
	// show evidence of having fought. No one gets a medal for
	// hiding in a foxhole, so to speak.
	ptxbuf = (CS)alloca(strlen(ptxes1) + CHARSIZE);
	strcpy(ptxbuf, ptxes1);
	for (ptxesleft = 0, ixstr = util_strsep(&ptxbuf, FS2);
		 ixstr;
		 ixstr = util_strsep(&ptxbuf, FS2)) {
	    if (_shop_ptx_contains(ssp, ixstr)) {
		ptxesleft = 1;
		_shop_ptx_mark_as_seen(ssp, ixstr);
	    }
	}
	if (!ptxesleft) {
	    continue;
	}

	/*
	 * Evaluate individual path states. The format allows for
	 * pathstate keys to be enumerated, like S1+S2+S3+S4, or
	 * for ranges in the form "S1-4".
	 */
	for (pskey = util_strsep(&pskeys, FS2);
		pskey && _shop_ptx_count(ssp);
		pskey = util_strsep(&pskeys, FS2)) {
	    CS end;

	    if ((end = strchr(pskey, '-'))) {
		uint64_t i, first, last;
		char nkey[64], *p;

		// The following relies on the fact that Integer.toString
		// is guaranteed to use lower-case characters.
		*end++ = '\0';
		for (p = nkey; ISALPHA(*pskey) && ISUPPER(*pskey); ) {
		    *p++ = *pskey++;
		}
		first = strtol(pskey, NULL, RMAP_RADIX);
		last  = strtol(end, NULL, RMAP_RADIX);
		for (i = first; i <= last; i++) {
		    util_format_to_radix(RMAP_RADIX, p, charlen(nkey), i);
		    _shop_cmp_pathstate(ssp, nkey, ptxes1);
		}
	    } else {
		_shop_cmp_pathstate(ssp, pskey, ptxes1);
	    }
	}
    }

    ps_destroy(CurrentPS);
    CurrentPS = NULL;
}
示例#19
0
static shop_e
_shop_collect_targets(shopping_state_s *ssp, CCS cmdix)
{
    char key[64];
    struct cdb_find cdbf_tgt;
    unsigned vlen;
    shop_e rc;

    rc = SHOP_RECYCLED;

    vb_printf(VB_SHOP, "COLLECTING: [%s]", cmdix);

    // First we collect all targets of the winning command in the
    // "real" CA object ....

    snprintf(key, charlen(key), ">%s", cmdix);
    if (cdb_findinit(&cdbf_tgt, ssp->cdbp, key, strlen(key)) < 0) {
	putil_die("cdb_findinit: %s (%s)", key, ca_get_line(ssp->ca));
    }

    while (cdb_findnext(&cdbf_tgt) > 0) {
	CS buf, pskeys, csv, ptxes, ixstr;

	CCS pskey;

	vlen = cdb_datalen(ssp->cdbp);
	buf = (CS)alloca(vlen + 1);
	cdb_read(ssp->cdbp, buf, vlen, cdb_datapos(ssp->cdbp));
	buf[vlen] = '\0';

	if (!(ptxes = strstr(buf, FS1))) {
	    putil_int("bad format in roadmap: %s", buf);
	    rc = SHOP_ERR;
	    continue;
	}

	*ptxes++ = '\0';
	pskeys = buf;

	// Make sure to skip all targets not associated with the winning PTX.
	for (ixstr = util_strsep(&ptxes, FS2);
	     ixstr; ixstr = util_strsep(&ptxes, FS2)) {
	    if (!strcmp(ixstr, ssp->wix)) {
		ps_o tgt_ps;

		pa_o dummy_pa;

		for (pskey = util_strsep(&pskeys, FS2);
		     pskey && rc == SHOP_RECYCLED;
		     pskey = util_strsep(&pskeys, FS2)) {

		    if (cdb_find(ssp->cdbp, pskey, strlen(pskey)) <= 0) {
			putil_int("bad key in roadmap: %s", pskey);
			continue;
		    }

		    vlen = cdb_datalen(ssp->cdbp);
		    csv = (CS)alloca(vlen + 1);
		    cdb_read(ssp->cdbp, csv, vlen, cdb_datapos(ssp->cdbp));
		    csv[vlen] = '\0';
		    vb_printf(VB_SHOP, "COLLECTED [%s] %s", pskey, csv);
		    tgt_ps = ps_newFromCSVString(csv);

		    // Unfortunately, as noted elsewhere, a CA object
		    // doesn't hold PS objects, it holds PA objects.
		    // So we need a dummy PA to wrap the target PS in.
		    dummy_pa = pa_new();
		    pa_set_ps(dummy_pa, tgt_ps);
		    if (ps_is_link(tgt_ps)) {
			pa_set_op(dummy_pa, OP_LINK);
		    } else if (ps_is_symlink(tgt_ps)) {
			pa_set_op(dummy_pa, OP_SYMLINK);
		    } else if (ps_is_unlink(tgt_ps)) {
			pa_set_op(dummy_pa, OP_UNLINK);
		    } else {
			pa_set_op(dummy_pa, OP_CREAT);
		    }
		    pa_set_call(dummy_pa, "dummy");
		    pa_set_uploadable(dummy_pa, 1);
		    ca_record_pa(ssp->ca, dummy_pa);
		}
		// Once we've reached the winner, we're done.
		break;
	    }
	}
    }

    return rc;
}
示例#20
0
static shop_e
_shop_for_cmd(shopping_state_s *ssp, CCS cmdix)
{
    CCS line;
    unsigned len;
    CS cmdstate;
    CS pccode, has_tgt, agg, duration, kids, pathcode, rwd;
    int aggregated;

    line = ca_get_line(ssp->ca);

    if (cdb_find(ssp->cdbp, cmdix, strlen(cmdix)) <= 0) {
	putil_int("missing cmd at index=%s", cmdix);
	return SHOP_ERR;
    }

    len = cdb_datalen(ssp->cdbp);
    cmdstate = (CS)alloca(len + 1);
    cdb_read(ssp->cdbp, cmdstate, len, cdb_datapos(ssp->cdbp));
    cmdstate[len] = '\0';

    // This is one place where the number and order of fields is hard wired.
    // *INDENT-OFF*
    if (!(pccode = util_strsep(&cmdstate, FS1)) ||
	    !(pathcode = util_strsep(&cmdstate, FS1)) ||
	    !(has_tgt = util_strsep(&cmdstate, FS1)) ||
	    !(agg = util_strsep(&cmdstate, FS1)) ||
	    !(kids = util_strsep(&cmdstate, FS1)) ||
	    !(duration = util_strsep(&cmdstate, FS1)) ||
	    !(rwd = util_strsep(&cmdstate, FS1))) {
	cdb_read(ssp->cdbp, cmdstate, len, cdb_datapos(ssp->cdbp));
	cmdstate[len] = '\0';
	putil_int("bad format: '%s'", cmdstate);
	return SHOP_ERR;
    }
    // *INDENT-ON*

    aggregated = IS_TRUE(agg);

    vb_printf(VB_SHOP, "%sCMD MATCH: [%s] (%s) %s",
	      aggregated ? "AGGREGATED " : "", cmdix, rwd ? rwd : "", line);

    // If a command has no targets it is ineligible for
    // shopping and must run. Typically this would be
    // something like "echo blah blah".
    if (!IS_TRUE(has_tgt)) {
	CCS msg = "has no targets";

	vb_printf(VB_SHOP, "COMMAND invalidated due to '%s': [%s] %s",
	    msg, cmdix, line);

	return aggregated ? SHOP_MUSTRUN_AGG : SHOP_MUSTRUN;
    }

    // If a command has children we make it ineligible.
    // The problem is a command which both creates files
    // *and* runs children - if we recycle it then the
    // children are not run, even if they would have created
    // other (potentially recyclable) files. There may be an
    // answer in recursive shopping but it would be very complex,
    // so currently we take the easy way out and shop only at
    // the leaves of the tree.
    if (!CSV_FIELD_IS_NULL(kids)) {
	CCS msg = "has children";

	if (vb_bitmatch(VB_SHOP)) {
	    vb_printf(VB_SHOP, "COMMAND invalidated due to '%s': [%s] %s",
		msg, cmdix, line);
	} else {
	    vb_printf(VB_WHY, "COMMAND invalidated due to '%s'", msg);
	}

	return SHOP_MUSTRUN;
    }

    // Removed pccode chck here - could't see its value.

    // There is no current use for this ...
    //ca_set_duration_str(ssp->ca, strtoul(duration, NULL, 10));

    // No current use for pathcode ...

    // Make sure there are still PTXes left before we go shopping.
    if (!_shop_ptx_count(ssp)) {
	return SHOP_NOMATCH;
    }

    // We have now matched a command and parsed its metadata, and
    // still have PTXes in which it was run.
    // It's time to compare it against the current path states.
    // Look first at member prereqs, then at the general public.
    // This is because members are far more likely to change, so
    // shopping can "fail fast" if it considers them first. The
    // main thing here is to limit the number of stats and especially
    // dcode (checksumming) events because they are expensive.
    _shop_compare_prereqs(ssp, cmdix);

    if (_shop_ptx_count(ssp) && _shop_ptx_winner(ssp)) {
	snprintf(ssp->wincmd, charlen(ssp->wincmd), "%s", cmdix);
	return SHOP_RECYCLED;
    } else {
	if (aggregated) {
	    return SHOP_NOMATCH_AGG;
	} else {
	    return SHOP_NOMATCH;
	}
    }
}
示例#21
0
/// Given a properties file, load it into the properties object.
/// @param[in] fname    the name of a properties file
/// @param[in] verbose  verbosity string, or NULL
/// @param[in] win      boolean - should this setting win over previous?
void
prop_load(CCS fname, CCS verbose, int win)
{
    char buf[PROP_STR_MAX];

    if (fname) {
	FILE *fp;

	if ((fp = fopen(fname, "r"))) {
	    int ln;
	    char pstr[PROP_STR_MAX], *tp, *bp;

	    if (verbose) {
		printf("%s%s\n", verbose, fname);
	    }

	    for (ln = 1; fgets(buf, charlen(buf), fp); ln++) {
		// In case a line-continuation (\) character is found.
		while ((bp = strchr(buf, '\n')) &&
			bp > buf && *(bp - 1) == '\\') {
		    *--bp = '\0';
		    if (!fgets(pstr, charlen(pstr), fp)) {
			break;
		    }
		    ln++;
		    for (tp = pstr; ISSPACE(*tp); tp++);
		    strcpy(bp, tp);
		}
		if (_prop_process_line(buf, win)) {
		    putil_warn("malformed line (%d) in %s: '%s'", ln, fname,
			       buf);
		}
	    }
	    fclose(fp);
	} else {
	    if (verbose) {
		printf("%s%s (not present)\n", verbose, fname);
	    }
	}
    } else {
	int offset;

#if defined(_WIN32)
	char *env, *ep;

	if (!(env = GetEnvironmentStrings())) {
	    putil_syserr(2, "GetEnvironmentStrings");
	}

	for (ep = env; *ep; ep++) {
	    if ((offset = _prop_matches_ev_name(ep))) {
		strcpy(buf, ep + offset);
		_prop_load_from_ev(buf);
	    }
	    ep = strchr(ep, '\0');
	}

	FreeEnvironmentStrings(env);
#else	/*_WIN32*/
	char **envp;

	for (envp = environ; *envp; envp++) {
	    if ((offset = _prop_matches_ev_name(*envp))) {
		strcpy(buf, *envp + offset);
		_prop_load_from_ev(buf);
	    }
	}
#endif	/*_WIN32*/

	if (verbose) {
	    printf("%s[Environment]\n", verbose);
	}
    }
}
示例#22
0
void
git_store_blob(ps_o ps)
{
    CCS sha1, blob, path;
    CS blob_dir;
    int fd, ret;
    z_stream stream;
    char hdr[64];
    unsigned char cprsbuf[4096], *fdata;
    uint64_t fsize;
    struct stat64 stbuf;

    path = ps_get_abs(ps);
    sha1 = ps_get_dcode(ps);

    if ((fd = open64(path, O_RDONLY | O_BINARY)) == -1) {
	putil_syserr(2, path);
    }

    if (fstat64(fd, &stbuf)) {
	close(fd);
	putil_syserr(2, path);
    }

    fsize = stbuf.st_size;
    fdata = util_map_file(path, fd, 0, fsize);
    close(fd);

    blob = git_path_to_blob(sha1);
    if (!access(blob, F_OK)) {
	return;
    }
    if ((blob_dir = putil_dirname(blob))) {
	if (access(blob_dir, F_OK) && putil_mkdir_p(blob_dir)) {
	    putil_syserr(2, blob_dir);
	}
	putil_free(blob_dir);
    }

    if ((fd = open64(blob, O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0444)) == -1) {
	putil_syserr(2, blob);
    }

    memset(&stream, 0, sizeof(stream));
    if (deflateInit(&stream, Z_BEST_SPEED) != Z_OK) {
	putil_die("unable to compress %s: %s",
	    path, stream.msg ? stream.msg : "unknown error");
    }
    stream.avail_out = sizeof(cprsbuf);
    stream.next_out = cprsbuf;

    snprintf(hdr, charlen(hdr), "blob %lu", ps_get_size(ps));
    stream.next_in = (unsigned char *)hdr;
    stream.avail_in = strlen(hdr) + 1;
    while(deflate(&stream, 0) == Z_OK);

    stream.next_in = fdata;
    stream.avail_in = (uInt)fsize;
    do {
	ret = deflate(&stream, Z_FINISH);
	if (util_write_all(fd, cprsbuf, stream.next_out - cprsbuf) < 0) {
	    putil_syserr(2, blob);
	}
	stream.avail_out = sizeof(cprsbuf);
	stream.next_out = cprsbuf;
    } while (ret == Z_OK);

    close(fd);
    util_unmap_file(fdata, fsize);
    putil_free(blob);
}