int urlGetFile(const char * url, const char * dest) { char *cmd = NULL; const char *target = NULL; char *urlhelper = NULL; int rc; pid_t pid, wait; urlhelper = rpmExpand("%{?_urlhelper}", NULL); if (dest == NULL) { urlPath(url, &target); } else { target = dest; } /* XXX TODO: sanity checks like target == dest... */ rasprintf(&cmd, "%s %s %s", urlhelper, target, url); urlhelper = _free(urlhelper); if ((pid = fork()) == 0) { ARGV_t argv = NULL; argvSplit(&argv, cmd, " "); execvp(argv[0], argv); exit(127); /* exit with 127 for compatibility with bash(1) */ } wait = waitpid(pid, &rc, 0); cmd = _free(cmd); return rc; }
char * _RequestPass(/*@unused@*/ const char * prompt) { /*@only@*/ /*@relnull@*/ static char * password = NULL; #if defined(HAVE_KEYUTILS_H) const char * foo = "user rpm:yyyy spoon"; ARGV_t av = NULL; int xx = argvSplit(&av, foo, NULL); key_serial_t dest = 0; key_serial_t key = 0; if (password != NULL) { free(password); password = NULL; } assert(av != NULL); assert(av[0] != NULL); assert(av[1] != NULL); assert(av[2] != NULL); key = request_key(av[0], av[1], av[2], dest); av = argvFree(av); /*@-nullstate@*/ /* XXX *password may be null. */ xx = keyctl_read_alloc(key, (void **)&password); /*@=nullstate@*/ if (password == NULL) password = (char *) ""; #endif /* HAVE_KEYUTILS_H */ /*@-statictrans@*/ return password; /*@=statictrans@*/ }
void rpmInitMacros(rpmMacroContext mc, const char * macrofiles) { ARGV_t pattern, globs = NULL; if (macrofiles == NULL) return; argvSplit(&globs, macrofiles, ":"); for (pattern = globs; *pattern; pattern++) { ARGV_t path, files = NULL; /* Glob expand the macro file path element, expanding ~ to $HOME. */ if (rpmGlob(*pattern, NULL, &files) != 0) { continue; } /* Read macros from each file. */ for (path = files; *path; path++) { if (rpmFileHasSuffix(*path, ".rpmnew") || rpmFileHasSuffix(*path, ".rpmsave") || rpmFileHasSuffix(*path, ".rpmorig")) { continue; } (void) rpmLoadMacroFile(mc, *path); } argvFree(files); } argvFree(globs); /* Reload cmdline macros */ rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE); }
int rpmMkdirs(const char *root, const char *pathstr) { ARGV_t dirs = NULL; int rc = 0; argvSplit(&dirs, pathstr, ":"); for (char **d = dirs; *d; d++) { char *path = rpmGetPath(root ? root : "", *d, NULL); if ((rc = rpmioMkpath(path, 0755, -1, -1)) != 0) { const char *msg = _("failed to create directory"); /* try to be more informative if the failing part was a macro */ if (**d == '%') { rpmlog(RPMLOG_ERR, "%s %s: %s: %m\n", msg, *d, path); } else { rpmlog(RPMLOG_ERR, "%s %s: %m\n", msg, path); } } free(path); if (rc) break; } argvFree(dirs); return rc; }
/** * Parse arguments (to next new line) for parameterized macro. * @todo Use popt rather than getopt to parse args. * @param mb macro expansion state * @param me macro entry slot * @param se arguments to parse * @param lastc stop parsing at lastc * @return address to continue parsing */ static const char * grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se, const char * lastc) { const char *opts, *o; char *args = NULL; ARGV_t argv = NULL; int argc = 0; int c; /* Copy macro name as argv[0] */ argvAdd(&argv, me->name); addMacro(mb->mc, "0", NULL, me->name, mb->depth); /* * Make a copy of se up to lastc string that we can pass to argvSplit(). * Append the results to main argv. */ { ARGV_t av = NULL; char *s = xcalloc((lastc-se)+1, sizeof(*s)); memcpy(s, se, (lastc-se)); argvSplit(&av, s, " \t"); argvAppend(&argv, av); argvFree(av); free(s); } /* * The macro %* analoguous to the shell's $* means "Pass all non-macro * parameters." Consequently, there needs to be a macro that means "Pass all * (including macro parameters) options". This is useful for verifying * parameters during expansion and yet transparently passing all parameters * through for higher level processing (e.g. %description and/or %setup). * This is the (potential) justification for %{**} ... */ args = argvJoin(argv + 1, " "); addMacro(mb->mc, "**", NULL, args, mb->depth); free(args); /* * POSIX states optind must be 1 before any call but glibc uses 0 * to (re)initialize getopt structures, eww. */ #ifdef __GLIBC__ optind = 0; #else optind = 1; #endif opts = me->opts; argc = argvCount(argv); /* Define option macros. */ while((c = getopt(argc, argv, opts)) != -1) { char *name = NULL, *body = NULL; if (c == '?' || (o = strchr(opts, c)) == NULL) { rpmlog(RPMLOG_ERR, _("Unknown option %c in %s(%s)\n"), (char)c, me->name, opts); goto exit; } rasprintf(&name, "-%c", c); if (optarg) { rasprintf(&body, "-%c %s", c, optarg); } else { rasprintf(&body, "-%c", c); } addMacro(mb->mc, name, NULL, body, mb->depth); free(name); free(body); if (optarg) { rasprintf(&name, "-%c*", c); addMacro(mb->mc, name, NULL, optarg, mb->depth); free(name); } } /* Add argument count (remaining non-option items) as macro. */ { char *ac = NULL; rasprintf(&ac, "%d", (argc - optind)); addMacro(mb->mc, "#", NULL, ac, mb->depth); free(ac); } /* Add macro for each argument */ if (argc - optind) { for (c = optind; c < argc; c++) { char *name = NULL; rasprintf(&name, "%d", (c - optind + 1)); addMacro(mb->mc, name, NULL, argv[c], mb->depth); free(name); } } /* Add concatenated unexpanded arguments as yet another macro. */ args = argvJoin(argv + optind, " "); addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth); free(args); exit: argvFree(argv); return *lastc ? lastc + 1 : lastc; }
rpmts rpmtsCreate(void) { rpmts ts; tsMembers tsmem; ts = xcalloc(1, sizeof(*ts)); memset(&ts->ops, 0, sizeof(ts->ops)); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1); ts->dsi = NULL; ts->solve = NULL; ts->solveData = NULL; ts->rdb = NULL; ts->dbmode = O_RDONLY; ts->scriptFd = NULL; ts->tid = (rpm_tid_t) time(NULL); ts->color = rpmExpandNumeric("%{?_transaction_color}"); ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2; ts->netsharedPaths = NULL; ts->installLangs = NULL; { char *tmp = rpmExpand("%{_netsharedpath}", NULL); if (tmp && *tmp != '%') { argvSplit(&ts->netsharedPaths, tmp, ":"); } free(tmp); tmp = rpmExpand("%{_install_langs}", NULL); if (tmp && *tmp != '%') { ARGV_t langs = NULL; argvSplit(&langs, tmp, ":"); /* If we'll be installing all languages anyway, don't bother */ for (ARGV_t l = langs; *l; l++) { if (rstreq(*l, "all")) { langs = argvFree(langs); break; } } ts->installLangs = langs; } free(tmp); } tsmem = xcalloc(1, sizeof(*ts->members)); tsmem->pool = NULL; tsmem->delta = 5; tsmem->addedPackages = NULL; tsmem->removedPackages = removedHashCreate(128, uintId, uintCmp, NULL, NULL); tsmem->orderAlloced = 0; tsmem->orderCount = 0; tsmem->order = NULL; ts->members = tsmem; ts->rootDir = NULL; ts->keyring = NULL; ts->nrefs = 0; ts->plugins = NULL; return rpmtsLink(ts); }
static int open_dso(const char * path, pid_t * pidp, rpm_loff_t *fsizep) { static const char * cmd = NULL; static int initted = 0; int fdno; if (!initted) { cmd = rpmExpand("%{?__prelink_undo_cmd}", NULL); initted++; } if (pidp) *pidp = 0; if (fsizep) { struct stat sb, * st = &sb; if (stat(path, st) < 0) return -1; *fsizep = st->st_size; } fdno = open(path, O_RDONLY); if (fdno < 0) return fdno; if (!(cmd && *cmd)) return fdno; if (pidp != NULL && is_prelinked(fdno)) { int pipes[2]; pid_t pid; close(fdno); pipes[0] = pipes[1] = -1; if (pipe(pipes) < 0) return -1; pid = fork(); if (pid < 0) { close(pipes[0]); close(pipes[1]); return -1; } if (pid == 0) { ARGV_t av, lib; int dfd; argvSplit(&av, cmd, " "); close(pipes[0]); dfd = dup2(pipes[1], STDOUT_FILENO); close(pipes[1]); if (dfd >= 0 && (lib = argvSearch(av, "library", NULL)) != NULL) { *lib = (char *) path; unsetenv("MALLOC_CHECK_"); execve(av[0], av+1, environ); } _exit(127); /* not normally reached */ } else { *pidp = pid; fdno = pipes[0]; close(pipes[1]); } } return fdno; }
int parsePrep(Spec spec, int verify) { rpmParseState nextPart; int res, rc; rpmiob iob; ARGV_t saveLines = NULL; ARGV_t lines; const char * cp; int xx; if (spec->prep != NULL) { rpmlog(RPMLOG_ERR, _("line %d: second %%prep\n"), spec->lineNum); return RPMRC_FAIL; } spec->prep = rpmiobNew(0); /* There are no options to %prep */ if ((rc = readLine(spec, STRIP_NOTHING)) > 0) return PART_NONE; if (rc) return rc; /* Check to make sure that all sources/patches are present. */ if (verify) { rc = prepFetch(spec); if (rc) return RPMRC_FAIL; } iob = rpmiobNew(0); while ((nextPart = isPart(spec)) == PART_NONE) { /* Need to expand the macros inline. That way we */ /* can give good line number information on error. */ iob = rpmiobAppend(iob, spec->line, 0); if ((rc = readLine(spec, STRIP_NOTHING)) > 0) { nextPart = PART_NONE; break; } if (rc) return rc; } xx = argvSplit(&saveLines, rpmiobStr(iob), "\n"); /*@-usereleased@*/ for (lines = saveLines; *lines; lines++) { res = 0; for (cp = *lines; *cp == ' ' || *cp == '\t'; cp++) {}; if (!strncmp(cp, "%setup", sizeof("%setup")-1)) { res = doSetupMacro(spec, cp); #ifndef DYING } else if (! strncmp(cp, "%patch", sizeof("%patch")-1)) { res = doPatchMacro(spec, cp); #endif } else { spec->prep = rpmiobAppend(spec->prep, *lines, 1); } if (res && !spec->force) { saveLines = argvFree(saveLines); iob = rpmiobFree(iob); return res; } } /*@=usereleased@*/ saveLines = argvFree(saveLines); iob = rpmiobFree(iob); return nextPart; }
static rpmRC handlePreambleTag(rpmSpec spec, Package pkg, rpmTagVal tag, const char *macro, const char *lang) { char * field = spec->line; char * end; int multiToken = 0; rpmsenseFlags tagflags = RPMSENSE_ANY; rpmRC rc = RPMRC_FAIL; if (field == NULL) /* XXX can't happen */ goto exit; /* Find the start of the "field" and strip trailing space */ while ((*field) && (*field != ':')) field++; if (*field != ':') { rpmlog(RPMLOG_ERR, _("line %d: Malformed tag: %s\n"), spec->lineNum, spec->line); goto exit; } field++; SKIPSPACE(field); if (!*field) { /* Empty field */ rpmlog(RPMLOG_ERR, _("line %d: Empty tag: %s\n"), spec->lineNum, spec->line); goto exit; } end = findLastChar(field); *(end+1) = '\0'; /* See if this is multi-token */ end = field; SKIPNONSPACE(end); if (*end != '\0') multiToken = 1; switch (tag) { case RPMTAG_NAME: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, WHITELIST_NAME)) goto exit; headerPutString(pkg->header, tag, field); /* Main pkg name is unknown at the start, populate as soon as we can */ if (pkg == spec->packages) pkg->name = rpmstrPoolId(spec->pool, field, 1); break; case RPMTAG_VERSION: case RPMTAG_RELEASE: SINGLE_TOKEN_ONLY; if (rpmCharCheck(spec, field, "._+%{}~")) goto exit; headerPutString(pkg->header, tag, field); break; case RPMTAG_URL: case RPMTAG_DISTTAG: case RPMTAG_BUGURL: /* XXX TODO: validate format somehow */ case RPMTAG_VCS: SINGLE_TOKEN_ONLY; headerPutString(pkg->header, tag, field); break; case RPMTAG_GROUP: case RPMTAG_SUMMARY: case RPMTAG_DISTRIBUTION: case RPMTAG_VENDOR: case RPMTAG_LICENSE: case RPMTAG_PACKAGER: if (addLangTag(spec, pkg->header, tag, field, lang)) goto exit; break; case RPMTAG_BUILDROOT: /* just silently ignore BuildRoot */ macro = NULL; break; case RPMTAG_PREFIXES: { struct rpmtd_s td; const char *str; if (addOrAppendListEntry(pkg->header, tag, field)) goto exit; headerGet(pkg->header, tag, &td, HEADERGET_MINMEM); while ((str = rpmtdNextString(&td))) { size_t len = strlen(str); if (len > 1 && str[len-1] == '/') { rpmlog(RPMLOG_ERR, _("line %d: Prefixes must not end with \"/\": %s\n"), spec->lineNum, spec->line); rpmtdFreeData(&td); goto exit; } } rpmtdFreeData(&td); break; } case RPMTAG_DOCDIR: SINGLE_TOKEN_ONLY; if (field[0] != '/') { rpmlog(RPMLOG_ERR, _("line %d: Docdir must begin with '/': %s\n"), spec->lineNum, spec->line); goto exit; } macro = NULL; rpmPopMacro(NULL, "_docdir"); rpmPushMacro(NULL, "_docdir", NULL, field, RMIL_SPEC); break; case RPMTAG_EPOCH: { SINGLE_TOKEN_ONLY; uint32_t epoch; if (parseUnsignedNum(field, &epoch)) { rpmlog(RPMLOG_ERR, _("line %d: Epoch field must be an unsigned number: %s\n"), spec->lineNum, spec->line); goto exit; } headerPutUint32(pkg->header, tag, &epoch, 1); break; } case RPMTAG_AUTOREQPROV: pkg->autoReq = parseYesNo(field); pkg->autoProv = pkg->autoReq; break; case RPMTAG_AUTOREQ: pkg->autoReq = parseYesNo(field); break; case RPMTAG_AUTOPROV: pkg->autoProv = parseYesNo(field); break; case RPMTAG_SOURCE: case RPMTAG_PATCH: macro = NULL; if (addSource(spec, pkg, field, tag)) goto exit; break; case RPMTAG_ICON: SINGLE_TOKEN_ONLY; if (addSource(spec, pkg, field, tag) || readIcon(pkg->header, field)) goto exit; break; case RPMTAG_NOSOURCE: case RPMTAG_NOPATCH: spec->noSource = 1; if (parseNoSource(spec, field, tag)) goto exit; break; case RPMTAG_ORDERFLAGS: case RPMTAG_REQUIREFLAGS: if (parseBits(lang, installScriptBits, &tagflags)) { rpmlog(RPMLOG_ERR, _("line %d: Bad %s: qualifiers: %s\n"), spec->lineNum, rpmTagGetName(tag), spec->line); goto exit; } /* fallthrough */ case RPMTAG_PREREQ: case RPMTAG_RECOMMENDFLAGS: case RPMTAG_SUGGESTFLAGS: case RPMTAG_SUPPLEMENTFLAGS: case RPMTAG_ENHANCEFLAGS: case RPMTAG_CONFLICTFLAGS: case RPMTAG_OBSOLETEFLAGS: case RPMTAG_PROVIDEFLAGS: if (parseRCPOT(spec, pkg, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_BUILDPREREQ: case RPMTAG_BUILDREQUIRES: case RPMTAG_BUILDCONFLICTS: if (parseRCPOT(spec, spec->sourcePackage, field, tag, 0, tagflags)) goto exit; break; case RPMTAG_EXCLUDEARCH: case RPMTAG_EXCLUSIVEARCH: case RPMTAG_EXCLUDEOS: case RPMTAG_EXCLUSIVEOS: if (addOrAppendListEntry(spec->buildRestrictions, tag, field)) goto exit; break; case RPMTAG_BUILDARCHS: { int BACount; const char **BANames = NULL; if (poptParseArgvString(field, &BACount, &BANames)) { rpmlog(RPMLOG_ERR, _("line %d: Bad BuildArchitecture format: %s\n"), spec->lineNum, spec->line); goto exit; } if (spec->packages == pkg) { if (spec->BANames) { rpmlog(RPMLOG_ERR, _("line %d: Duplicate BuildArch entry: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } spec->BACount = BACount; spec->BANames = BANames; } else { if (BACount != 1 || !rstreq(BANames[0], "noarch")) { rpmlog(RPMLOG_ERR, _("line %d: Only noarch subpackages are supported: %s\n"), spec->lineNum, spec->line); BANames = _free(BANames); goto exit; } headerPutString(pkg->header, RPMTAG_ARCH, "noarch"); } if (!BACount) spec->BANames = _free(spec->BANames); break; } case RPMTAG_REMOVEPATHPOSTFIXES: argvSplit(&pkg->removePostfixes, field, ":"); break; default: rpmlog(RPMLOG_ERR, _("Internal error: Bogus tag %d\n"), tag); goto exit; } if (macro) { rpmPushMacro(spec->macros, macro, NULL, field, RMIL_SPEC); /* Add a separate uppercase macro for tags from the main package */ if (pkg == spec->packages) { char *m = xstrdup(macro); for (char *p = m; *p; ++p) *p = rtoupper(*p); rpmPushMacro(spec->macros, m, NULL, field, RMIL_SPEC); free(m); } } rc = RPMRC_OK; exit: return rc; }