/// 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; }
/// 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); } }
/// 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*/ }
/// 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); }
/// 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); }
/// 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; }
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; }
/// 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); }
// 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; }
// 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)); } } }
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; }
/// 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; }
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'; }
/// 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); } }
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); }
// 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; }
/// 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; }
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; }
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; }
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; } } }
/// 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); } } }
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); }