Exemple #1
0
static char * prDbiOpenFlags(int dbflags, int print_dbenv_flags)
{
    ARGV_t flags = NULL;
    const struct poptOption *opt;
    char *buf;

    for (opt = rdbOptions; opt->longName != NULL; opt++) {
        if (opt->argInfo != POPT_BIT_SET)
            continue;
        if (print_dbenv_flags) {
            if (!(opt->arg == &staticcfg.db_eflags))
                continue;
        } else {
            if (!(opt->arg == &staticdbicfg.dbi_oflags))
                continue;
        }
        if ((dbflags & opt->val) != opt->val)
            continue;
        argvAdd(&flags, opt->longName);
        dbflags &= ~opt->val;
    }   
    if (dbflags) {
        char *df = NULL;
        rasprintf(&df, "0x%x", (unsigned)dbflags);
        argvAdd(&flags, df);
        free(df);
    }   
    buf = argvJoin(flags, ":");
    argvFree(flags);
            
    return buf ? buf : xstrdup("(none)");
}
Exemple #2
0
static rpmRC sepoltransRemove(sepoltrans * pt, const sepol * pol)
{
    rpmRC rc = RPMRC_OK;

    if (pol->flags & RPMPOL_FLAG_BASE) {
	return RPMRC_FAIL;
    }

    if (pt->execsemodule) {
	if (argvAdd(&pt->semodargs, "-r") < 0 || argvAdd(&pt->semodargs, pol->name) < 0) {
	    rc = RPMRC_FAIL;
	}
    } else {
	if (semanage_module_remove(pt->sh, (char *) pol->name) < 0) {
	    rc = RPMRC_FAIL;
	}
    }

    if (rc != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, _("Failed to remove policy module: %s\n"),
	       pol->name);
    } else {
	pt->changes++;
    }

    return rc;
}
Exemple #3
0
/*@-mustmod@*/
int argvFgets(ARGV_t * argvp, void * fd)
{
    FILE * fp = (fd ? fdGetFILE(fd) : stdin);
    ARGV_t av = NULL;
    char buf[BUFSIZ];
    char * b, * be;
    int rc = 0;

    if (fp == NULL)
	return -2;
    while (!rc && (b = fgets(buf, (int)sizeof(buf), fp)) != NULL) {
	buf[sizeof(buf)-1] = '\0';
	be = b + strlen(buf);
	if (be > b) be--;
	while (strchr("\r\n", *be) != NULL)
	    *be-- = '\0';
	rc = argvAdd(&av, b);
    }

    if (!rc)
	rc = ferror(fp);
    if (!rc)
	rc = (feof(fp) ? 0 : 1);
    if (!rc && argvp)
	*argvp = av;
    else
	av = argvFree(av);
    
/*@-nullstate@*/	/* XXX *argvp may be NULL. */
    return rc;
/*@=nullstate@*/
}
Exemple #4
0
static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags)
{
    rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER);
    rpmds ds = NULL;
    char **fdeps = NULL;
    int numfiles;
    char deptype = 'R';
    int fileix;
    int rc = 0;

    numfiles = rpmfiFC(fi);
    if (numfiles <= 0) {
	goto exit;
    }

    if (tagN == RPMTAG_PROVIDENAME)
	deptype = 'P';
    else if (tagN == RPMTAG_REQUIRENAME)
	deptype = 'R';

    ds = rpmdsNew(h, tagN, 0);
    fdeps = xmalloc(numfiles * sizeof(*fdeps));

    while ((fileix = rpmfiNext(fi)) >= 0) {
	ARGV_t deps = NULL;
	const uint32_t * ddict = NULL;
	int ndx = rpmfiFDepends(fi, &ddict);
	if (ddict != NULL) {
	    while (ndx-- > 0) {
		const char * DNEVR;
		unsigned dix = *ddict++;
		char mydt = ((dix >> 24) & 0xff);
		if (mydt != deptype)
		    continue;
		dix &= 0x00ffffff;
		(void) rpmdsSetIx(ds, dix-1);
		if (rpmdsNext(ds) < 0)
		    continue;
		DNEVR = rpmdsDNEVR(ds);
		if (DNEVR != NULL) {
		    argvAdd(&deps, DNEVR + 2);
		}
	    }
	}
	fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup("");
	argvFree(deps);
    }
    td->data = fdeps;
    td->count = numfiles;
    td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
    td->type = RPM_STRING_ARRAY_TYPE;
    rc = 1;

exit:
    rpmfiFree(fi);
    rpmdsFree(ds);
    return rc;
}
Exemple #5
0
int argvAddNum(ARGV_t *argvp, int val)
{
    char *valstr = NULL;
    int rc;
    rasprintf(&valstr, "%d", val);
    rc = argvAdd(argvp, valstr);
    free(valstr);
    return rc;
}
Exemple #6
0
int
main(int argc, char *argv[])
{
    poptContext con = rpmioInit(argc, argv, optionsTable);
    ARGV_t av = poptGetArgs(con);
    int ac = argvCount(av);;
    const char ** keyids = NULL;
    int ec = 0;
    int xx;

_rpmhkp_lvl = RPMLOG_INFO;	/* XXX default is RPMLOG_DEBUG */

    if (_hkp_keyserver == NULL)
	_hkp_keyserver = xstrdup("keys.rpm5.org");
    if (_rpmhkp_spew)
	_rpmhkp_debug = -1;

    /* XXX no macros are loaded if using poptIO. */
    addMacro(NULL, "_hkp_keyserver",		NULL, _hkp_keyserver, -1);
    addMacro(NULL, "_hkp_keyserver_query",	NULL, _hkp_keyserver_query, -1);

    if (ac == 0) {
	xx = argvAppend(&keyids, _keyids);
    } else {
	int gotstdin = 0;
	int i;
	for (i = 0; i < ac; i++) {
	    if (strcmp(av[i], "-")) {
		xx = argvAdd(&keyids, (ARGstr_t)av[i]);
		continue;
	    }
	    if (gotstdin)
		continue;
	    gotstdin++;
	    if (argvFgets(&keyids, NULL))
		goto exit;
	}
    }

    ec = rpmhkpReadKeys(keyids);

    if (_rpmhkp_stats)
	_rpmhkpPrintStats(NULL);

exit:
    keyids = argvFree(keyids);
    _hkp_keyserver = _free(_hkp_keyserver);

/*@i@*/ urlFreeCache();

    con = rpmioFini(con);

    return ec;
}
Exemple #7
0
static int rpmNoGlob(const char *fn, int *argcPtr, ARGV_t * argvPtr)
{
    struct stat sb;
    int rc = stat(fn, &sb);
    if (rc == 0) {
	argvAdd(argvPtr, fn);
	*argcPtr = 1;
    } else {
	*argcPtr = 0;
    }
    return rc;
}
Exemple #8
0
static void rpmdictAdd(rpmdict dict, const char * key)
{
    rpmuint64_t * val = NULL;
    void ** data = (void **)&val;
    if (htGetEntry(dict->ht, key, &data, NULL, NULL)) {
	(void) argvAdd(&dict->av, key);
	val = (rpmuint64_t *) xcalloc(1, sizeof(*val));
	htAddEntry(dict->ht, dict->av[dict->ac++], val);
    } else
	val = (rpmuint64_t *)data[0];
    val[0]++;
}
Exemple #9
0
static rpmRC sepoltransInstall(sepoltrans * pt, const sepol * pol)
{
    rpmRC rc = RPMRC_OK;
    char *path = NULL;

    rc = sepolWritePolicy(pol, &path);
    if (rc != RPMRC_OK) {
	return rc;
    }
    argvAdd(&pt->filelist, path);

    if (pt->execsemodule) {
	const char *flag = (pol->flags & RPMPOL_FLAG_BASE) ? "-b" : "-i";
	if (argvAdd(&pt->semodargs, flag) < 0 || argvAdd(&pt->semodargs, path) < 0) {
	    rc = RPMRC_FAIL;
	}
    } else {
	if (pol->flags & RPMPOL_FLAG_BASE) {
	    if (semanage_module_install_base_file(pt->sh, path) < 0) {
		rc = RPMRC_FAIL;
	    }
	} else {
	    if (semanage_module_install_file(pt->sh, path) < 0) {
		rc = RPMRC_FAIL;
	    }
	}
    }

    if (rc != RPMRC_OK) {
	rpmlog(RPMLOG_ERR, _("Failed to install policy module: %s (%s)\n"),
	       pol->name, path);
    } else {
	pt->changes++;
    }

    _free(path);

    return rc;
}
Exemple #10
0
static void addDep(ARGV_t *deps,
		   const char *soname, const char *ver, const char *marker)
{
    char *dep = NULL;

    if (skipSoname(soname))
	return;

    if (ver || marker) {
	rasprintf(&dep,
		  "%s(%s)%s", soname, ver ? ver : "", marker ? marker : "");
    }
    argvAdd(deps, dep ? dep : soname);
    free(dep);
}
Exemple #11
0
static sepoltrans *sepoltransNew(void)
{
    sepoltrans *pt = xcalloc(1, sizeof(*pt));
    pt->semodulepath = rpmExpand("%{__semodule}", NULL);
    pt->execsemodule = (!rpmChrootDone() && access(pt->semodulepath, X_OK) == 0);
    pt->changes = 0;

    if (pt->execsemodule) {
	argvAdd(&pt->semodargs, "semodule");
    } else {
	pt->sh = semanage_handle_create();
	if (!pt->sh) {
	    rpmlog(RPMLOG_ERR, _("Failed to create semanage handle\n"));
	    goto err;
	}
	semanage_set_create_store(pt->sh, 1);
	semanage_set_check_contexts(pt->sh, 0);
	if (semanage_connect(pt->sh) < 0) {
	    rpmlog(RPMLOG_ERR, _("Failed to connect to policy handler\n"));
	    goto err;
	}
	if (semanage_begin_transaction(pt->sh) < 0) {
	    rpmlog(RPMLOG_ERR, _("Failed to begin policy transaction: %s\n"),
		   errno ? strerror(errno) : "");
	    goto err;
	}
	semanage_set_reload(pt->sh, !rpmChrootDone());
    }

    return pt;

  err:
    if (pt->sh) {
	if (semanage_is_connected(pt->sh)) {
	    semanage_disconnect(pt->sh);
	}
	semanage_handle_destroy(pt->sh);
    }
    free(pt);

    return NULL;
}
Exemple #12
0
rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
                   ARGV_const_t prefixes, int warn_only, rpmPlugins plugins)
{
    ARGV_t args = NULL;
    rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
    rpmRC rc;
    int script_type = RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC;

    if (script == NULL) return RPMRC_OK;

    /* construct a new argv as we can't modify the one from header */
    if (script->args) {
        argvAppend(&args, script->args);
    } else {
        argvAdd(&args, "/bin/sh");
    }

    if (rstreq(args[0], "<lua>"))
        script_type = RPMSCRIPTLET_NONE;

    /* Run scriptlet pre hook for all plugins */
    rc = rpmpluginsCallScriptletPre(plugins, script->descr, script_type);

    if (rc != RPMRC_FAIL) {
        if (script_type & RPMSCRIPTLET_EXEC) {
            rc = runExtScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
        } else {
            rc = runLuaScript(plugins, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
        }
    }

    /* Run scriptlet post hook for all plugins */
    rpmpluginsCallScriptletPost(plugins, script->descr, script_type, rc);

    argvFree(args);

    return rc;
}
Exemple #13
0
static ModuleRec newModule(const char *path, const char *name,
			   const char *types, uint32_t flags)
{
    ModuleRec mod;
    uint8_t *raw = NULL;
    ssize_t rawlen = 0;
    const char *buildDir = "%{_builddir}/%{?buildsubdir}/";

    if (!path) {
	rpmlog(RPMLOG_ERR, _("%%semodule requires a file path\n"));
	return NULL;
    }

    mod = xcalloc(1, sizeof(*mod));

    mod->path = rpmGenPath(buildDir, NULL, path);

    if ((rpmioSlurp(mod->path, &raw, &rawlen)) != 0 || raw == NULL) {
	rpmlog(RPMLOG_ERR, _("Failed to read  policy file: %s\n"),
	       mod->path);
	goto err;
    }

    mod->data = b64encode(raw, rawlen, -1);
    if (!mod->data) {
	rpmlog(RPMLOG_ERR, _("Failed to encode policy file: %s\n"),
	       mod->path);
	goto err;
    }

    if (name) {
	mod->name = xstrdup(name);
    } else {
	/* assume base name (minus extension) if name is not given */
	char *tmp = xstrdup(mod->path);
	char *bname = basename(tmp);
	char *end = strchr(bname, '.');
	if (end)
	    *end = '\0';
	if (strlen(bname) > 0) {
	    mod->name = xstrdup(bname);
	} else {
	    rpmlog(RPMLOG_ERR, _("Failed to determine a policy name: %s\n"),
		   mod->path);
	    _free(tmp);
	    goto err;
	}
	_free(tmp);
    }

    if (types) {
	mod->types = argvSplitString(types, ",", ARGV_SKIPEMPTY);
	argvSort(mod->types, NULL);
	if (argvSearch(mod->types, RPMPOL_TYPE_DEFAULT, NULL) && argvCount(mod->types) > 1) {
	    rpmlog(RPMLOG_WARNING, _("'%s' type given with other types in %%semodule %s. Compacting types to '%s'.\n"),
		   RPMPOL_TYPE_DEFAULT, mod->path, RPMPOL_TYPE_DEFAULT);
	    mod->types = argvFree(mod->types);
	    argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
	}
    } else {
	argvAdd(&mod->types, RPMPOL_TYPE_DEFAULT);
    }

    mod->flags = flags;

    return mod;

  err:
    freeModule(mod);
    return NULL;
}
Exemple #14
0
/**
 * Retrieve trigger info.
 * @param mode		type of trigger (see tMode_e)
 * @param h		header
 * @retval td		tag data container
 * @param hgflags	header get flags
 * @return		1 on success
 */
static int triggercondsTagFor(tMode mode, Header h, rpmtd td,
				headerGetFlags hgflags)
{
    uint32_t * indices;
    int i, j;
    char ** conds;
    struct rpmtd_s nametd, indextd, flagtd, versiontd, scripttd;
    int hgeflags = HEADERGET_MINMEM;
    rpmTagVal triggername, triggerindex, triggerflags;
    rpmTagVal triggerversion, triggerscripts;

    switch (mode) {
	case NORMALTRIGGER:
	    triggername = RPMTAG_TRIGGERNAME;
	    triggerindex = RPMTAG_TRIGGERINDEX;
	    triggerflags = RPMTAG_TRIGGERFLAGS;
	    triggerversion = RPMTAG_TRIGGERVERSION;
	    triggerscripts = RPMTAG_TRIGGERSCRIPTS;
	    break;
	case FILETRIGGER:
	    triggername = RPMTAG_FILETRIGGERNAME;
	    triggerindex = RPMTAG_FILETRIGGERINDEX;
	    triggerflags = RPMTAG_FILETRIGGERFLAGS;
	    triggerversion = RPMTAG_FILETRIGGERVERSION;
	    triggerscripts = RPMTAG_FILETRIGGERSCRIPTS;
	    break;
	case TRANSFILETRIGGER:
	    triggername = RPMTAG_TRANSFILETRIGGERNAME;
	    triggerindex = RPMTAG_TRANSFILETRIGGERINDEX;
	    triggerflags = RPMTAG_TRANSFILETRIGGERFLAGS;
	    triggerversion = RPMTAG_TRANSFILETRIGGERVERSION;
	    triggerscripts = RPMTAG_TRANSFILETRIGGERSCRIPTS;
	    break;
	default:
	    return 0;
    }

    if (!headerGet(h, triggername, &nametd, hgeflags)) {
	return 0;
    }

    headerGet(h, triggerindex, &indextd, hgeflags);
    headerGet(h, triggerflags, &flagtd, hgeflags);
    headerGet(h, triggerversion, &versiontd, hgeflags);
    headerGet(h, triggerscripts, &scripttd, hgeflags);

    td->type = RPM_STRING_ARRAY_TYPE;
    td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED;
    td->data = conds = xmalloc(sizeof(*conds) * rpmtdCount(&scripttd));
    td->count = rpmtdCount(&scripttd);

    indices = indextd.data;

    while ((i = rpmtdNext(&scripttd)) >= 0) {
	rpm_flag_t *flag;
	char *flagStr, *item;
	ARGV_t items = NULL;

	rpmtdInit(&nametd); rpmtdInit(&flagtd); rpmtdInit(&versiontd);
	while ((j = rpmtdNext(&nametd)) >= 0) {
	    /* flag and version arrays match name array size always */
	    rpmtdNext(&flagtd); rpmtdNext(&versiontd);

	    if (indices[j] != i)
		continue;

	    flag = rpmtdGetUint32(&flagtd);
	    if (flag && *flag & RPMSENSE_SENSEMASK) {
		flagStr = rpmtdFormat(&flagtd, RPMTD_FORMAT_DEPFLAGS, NULL);
		rasprintf(&item, "%s %s %s", rpmtdGetString(&nametd),
					     flagStr,
					     rpmtdGetString(&versiontd));
		free(flagStr);
	    } else {
		item = xstrdup(rpmtdGetString(&nametd));
	    }

	    argvAdd(&items, item);
	    free(item);
	}

	conds[i] = argvJoin(items, ", ");
	argvFree(items);
    }

    rpmtdFreeData(&nametd);
    rpmtdFreeData(&versiontd);
    rpmtdFreeData(&flagtd);
    rpmtdFreeData(&indextd);
    rpmtdFreeData(&scripttd);
    return 1;
}
Exemple #15
0
static int rpmtsSetupCollections(rpmts ts)
{
    /* seenCollectionsPost and TEs are basically a key-value pair. each item in
     * seenCollectionsPost is a collection that has been seen from any package,
     * and the associated index in the TEs is the last transaction element
     * where that collection was seen. */
    ARGV_t seenCollectionsPost = NULL;
    rpmte *TEs = NULL;
    int numSeenPost = 0;

    /* seenCollectionsPre is a list of collections that have been seen from
     * only removed packages */
    ARGV_t seenCollectionsPre = NULL;
    int numSeenPre = 0;

    ARGV_const_t collname;
    int installing = 1;
    int i;

    rpmte p;
    rpmtsi pi = rpmtsiInit(ts);
    while ((p = rpmtsiNext(pi, 0)) != NULL) {
	/* detect when we switch from installing to removing packages, and
	 * update the lastInCollectionAdd lists */
	if (installing && rpmteType(p) == TR_REMOVED) {
	    installing = 0;
	    for (i = 0; i < numSeenPost; i++) {
		rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
	    }
	}

	rpmteSetupCollectionPlugins(p);

	for (collname = rpmteCollections(p); collname && *collname; collname++) {
	    /* figure out if we've seen this collection in post before */
	    for (i = 0; i < numSeenPost && strcmp(*collname, seenCollectionsPost[i]); i++) {
	    }
	    if (i < numSeenPost) {
		/* we've seen the collection, update the index */
		TEs[i] = p;
	    } else {
		/* haven't seen the collection yet, add it */
		argvAdd(&seenCollectionsPost, *collname);
		TEs = xrealloc(TEs, sizeof(*TEs) * (numSeenPost + 1));
		TEs[numSeenPost] = p;
		numSeenPost++;
	    }

	    /* figure out if we've seen this collection in pre remove before */
	    if (installing == 0) {
		for (i = 0; i < numSeenPre && strcmp(*collname, seenCollectionsPre[i]); i++) {
		}
		if (i >= numSeenPre) {
		    /* haven't seen this collection, add it */
		    rpmteAddToFirstInCollectionRemove(p, *collname);
		    argvAdd(&seenCollectionsPre, *collname);
		    numSeenPre++;
		}
	    }
	}
    }
    rpmtsiFree(pi);

    /* we've looked at all the rpmte's, update the lastInCollectionAny lists */
    for (i = 0; i < numSeenPost; i++) {
	rpmteAddToLastInCollectionAny(TEs[i], seenCollectionsPost[i]);
	if (installing == 1) {
	    /* lastInCollectionAdd is only updated above if packages were
	     * removed. if nothing is removed in the transaction, we need to
	     * update that list here */
	    rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]);
	}
    }

    argvFree(seenCollectionsPost);
    argvFree(seenCollectionsPre);
    _free(TEs);

    return 0;
}
Exemple #16
0
/**
 * Identify type of dependency.
 * @param td		tag data container
 * @return		formatted string
 */
static char * deptypeFormat(rpmtd td)
{
    char *val = NULL;
    if (rpmtdClass(td) != RPM_NUMERIC_CLASS) {
	val = xstrdup(_("(not a number)"));
    } else {
	ARGV_t sdeps = NULL;
	uint64_t item = rpmtdGetNumber(td);

	if (item & RPMSENSE_SCRIPT_PRE)
	    argvAdd(&sdeps, "pre");
	if (item & RPMSENSE_SCRIPT_POST)
	    argvAdd(&sdeps, "post");
	if (item & RPMSENSE_SCRIPT_PREUN)
	    argvAdd(&sdeps, "preun");
	if (item & RPMSENSE_SCRIPT_POSTUN)
	    argvAdd(&sdeps, "postun");
	if (item & RPMSENSE_SCRIPT_VERIFY)
	    argvAdd(&sdeps, "verify");
	if (item & RPMSENSE_INTERP)
	    argvAdd(&sdeps, "interp");
	if (item & RPMSENSE_RPMLIB)
	    argvAdd(&sdeps, "rpmlib");
	if ((item & RPMSENSE_FIND_REQUIRES) || (item & RPMSENSE_FIND_PROVIDES))
	    argvAdd(&sdeps, "auto");
	if (item & RPMSENSE_PREREQ)
	    argvAdd(&sdeps, "prereq");
	if (item & RPMSENSE_PRETRANS)
	    argvAdd(&sdeps, "pretrans");
	if (item & RPMSENSE_POSTTRANS)
	    argvAdd(&sdeps, "posttrans");
	if (item & RPMSENSE_CONFIG)
	    argvAdd(&sdeps, "config");
	if (item & RPMSENSE_MISSINGOK)
	    argvAdd(&sdeps, "missingok");

	if (sdeps) {
	    val = argvJoin(sdeps, ",");
	} else {
	    val = xstrdup("manual");
	}

	argvFree(sdeps);
    }
    return val;
}
Exemple #17
0
static int parseHTML(rpmtget tget)
{
    miRE mire = tget->mires;
    int noffsets = 3;
    int offsets[3];
    ssize_t nr = (tget->b != NULL ? (ssize_t)tget->nb : tgetFill(tget));
    int xx;

    xx = mireSetEOptions(mire, offsets, noffsets);

    while (tget->nb > 0) {
	char * gbn, * hbn;
	char * f, * fe;
	char * g, * ge;
	char * h, * he;
	char * t;
	mode_t mode;
	size_t nb;

	offsets[0] = offsets[1] = -1;
	xx = mireRegexec(mire, tget->b, tget->nb);
	if (xx == 0 && offsets[0] != -1 && offsets[1] != -1) {

	    /* [f:fe) contains |<a href="..."| match. */
	    f = tget->b + offsets[0];
	    fe = tget->b + offsets[1];

	    /* [h:he) contains the href basename. */
	    he = fe;
	    if (he[-1] == '"') he--;
	    if (he[-1] == '/') {
		mode = S_IFDIR | 0755;
		he--;
	    } else
		mode = S_IFREG | 0644;
	    h = he;
	    while (h > f && (h[-1] != '"' && h[-1] != '/'))
		h--;
	    nb = (size_t)(he - h);
	    hbn = t = xmalloc(nb + 1 + 1);
	    while (h < he)
		*t++ = *h++;
	    if (S_ISDIR(mode))
		*t++ = '/';
	    *t = '\0';

	    /* [g:ge) contains the URI basename. */
	    g = fe;
	    while (*g != '>')
		g++;
	    ge = ++g;
	    while (*ge != '<')
		ge++;
	    nb = (size_t)(ge - g);
	    gbn = t = xmalloc(nb + 1 + 1);
	    while (g < ge)
		*t++ = *g++;
	    if (S_ISDIR(mode))
		*t++ = '/';
	    *t = '\0';

	    /* Filter out weirdos and "." and "..". */
	    if (!strcmp(gbn, hbn) && strcmp(hbn, "./") && strcmp(hbn, "../")) {
		fprintf(stderr, "\t%s\n", gbn);
		xx = argvAdd(&tget->av, gbn);
	    }

	    gbn = _free(gbn);
	    hbn = _free(hbn);

	    offsets[1] += (ge - fe);
	    tget->b += offsets[1];
	    tget->nb -= offsets[1];
	} else {
	    size_t nb = tget->nb;
	    if (nr > 0) nb -= 1024;	/* XXX overlap a bit if filling. */
	    tget->b += nb;
	    tget->nb -= nb;
	}

	if (nr > 0)
	    nr = tgetFill(tget);
    }

    xx = mireSetEOptions(mire, NULL, 0);

    return 0;
}
Exemple #18
0
/**
 * Run an external script.
 */
static rpmRC runExtScript(rpmPlugins plugins, ARGV_const_t prefixes,
                          const char *sname, rpmlogLvl lvl, FD_t scriptFd,
                          ARGV_t * argvp, const char *script, int arg1, int arg2)
{
    FD_t out = NULL;
    char * fn = NULL;
    pid_t pid, reaped;
    int status;
    rpmRC rc = RPMRC_FAIL;

    rpmlog(RPMLOG_DEBUG, "%s: scriptlet start\n", sname);

    if (script) {
        fn = writeScript(*argvp[0], script);
        if (fn == NULL) {
            rpmlog(RPMLOG_ERR,
                   _("Couldn't create temporary file for %s: %s\n"),
                   sname, strerror(errno));
            goto exit;
        }

        argvAdd(argvp, fn);
        if (arg1 >= 0) {
            argvAddNum(argvp, arg1);
        }
        if (arg2 >= 0) {
            argvAddNum(argvp, arg2);
        }
    }

    if (scriptFd != NULL) {
        if (rpmIsVerbose()) {
            out = fdDup(Fileno(scriptFd));
        } else {
            out = Fopen("/dev/null", "w.fdio");
            if (Ferror(out)) {
                out = fdDup(Fileno(scriptFd));
            }
        }
    } else {
        out = fdDup(STDOUT_FILENO);
    }
    if (out == NULL) {
        rpmlog(RPMLOG_ERR, _("Couldn't duplicate file descriptor: %s: %s\n"),
               sname, strerror(errno));
        goto exit;
    }

    pid = fork();
    if (pid == (pid_t) -1) {
        rpmlog(RPMLOG_ERR, _("Couldn't fork %s: %s\n"),
               sname, strerror(errno));
        goto exit;
    } else if (pid == 0) {/* Child */
        rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
               sname, *argvp[0], (unsigned)getpid());

        /* Run scriptlet post fork hook for all plugins */
        if (rpmpluginsCallScriptletForkPost(plugins, *argvp[0], RPMSCRIPTLET_FORK | RPMSCRIPTLET_EXEC) != RPMRC_FAIL) {
            doScriptExec(*argvp, prefixes, scriptFd, out);
        } else {
            _exit(126); /* exit 126 for compatibility with bash(1) */
        }
    }

    do {
        reaped = waitpid(pid, &status, 0);
    } while (reaped == -1 && errno == EINTR);

    rpmlog(RPMLOG_DEBUG, "%s: waitpid(%d) rc %d status %x\n",
           sname, (unsigned)pid, (unsigned)reaped, status);

    if (reaped < 0) {
        rpmlog(lvl, _("%s scriptlet failed, waitpid(%d) rc %d: %s\n"),
               sname, pid, reaped, strerror(errno));
    } else if (!WIFEXITED(status) || WEXITSTATUS(status)) {
        if (WIFSIGNALED(status)) {
            rpmlog(lvl, _("%s scriptlet failed, signal %d\n"),
                   sname, WTERMSIG(status));
        } else {
            rpmlog(lvl, _("%s scriptlet failed, exit status %d\n"),
                   sname, WEXITSTATUS(status));
        }
    } else {
        /* if we get this far we're clear */
        rc = RPMRC_OK;
    }

exit:
    if (out)
        Fclose(out);	/* XXX dup'd STDOUT_FILENO */

    if (fn) {
        if (!rpmIsDebug())
            unlink(fn);
        free(fn);
    }
    return rc;
}
Exemple #19
0
Fichier : macro.c Projet : xrg/RPM
/**
 * 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; 
}
Exemple #20
0
int parseFiles(rpmSpec spec)
{
    int nextPart, res = PART_ERROR;
    Package pkg;
    int rc, argc;
    int arg;
    const char ** argv = NULL;
    const char *name = NULL;
    int flag = PART_SUBNAME;
    poptContext optCon = NULL;
    struct poptOption optionsTable[] = {
	{ NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
	{ NULL, 'f', POPT_ARG_STRING, NULL, 'f', NULL, NULL},
	{ 0, 0, 0, 0, 0, NULL, NULL}
    };

    /* XXX unmask %license while parsing %files */
    addMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC);

    if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
	rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%files: %s\n"),
		 spec->lineNum, poptStrerror(rc));
	goto exit;
    }

    optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
    while ((arg = poptGetNextOpt(optCon)) > 0) {
	if (arg == 'n') {
	    flag = PART_NAME;
	}
    }

    if (arg < -1) {
	rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
		 spec->lineNum,
		 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
		 spec->line);
	goto exit;
    }

    if (poptPeekArg(optCon)) {
	if (name == NULL)
	    name = poptGetArg(optCon);
	if (poptPeekArg(optCon)) {
	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
		     spec->lineNum,
		     spec->line);
	    goto exit;
	}
    }

    if (lookupPackage(spec, name, flag, &pkg)) {
	rpmlog(RPMLOG_ERR, _("line %d: Package does not exist: %s\n"),
		 spec->lineNum, spec->line);
	goto exit;
    }

    for (arg=1; arg<argc; arg++) {
	if (rstreq(argv[arg], "-f") && argv[arg+1]) {
	    char *file = rpmGetPath(argv[arg+1], NULL);
	    argvAdd(&(pkg->fileFile), file);
	    free(file);
	}
    }

    pkg->fileList = argvNew();

    if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
	nextPart = PART_NONE;
    } else if (rc < 0) {
	goto exit;
    } else {
	while (! (nextPart = isPart(spec->line))) {
	    argvAdd(&(pkg->fileList), spec->line);
	    if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
		nextPart = PART_NONE;
		break;
	    } else if (rc < 0) {
		goto exit;
	    }
	}
    }
    res = nextPart;

exit:
    delMacro(NULL, "license");
    free(argv);
    poptFreeContext(optCon);
	
    return res;
}
Exemple #21
0
int parseFiles(rpmSpec spec)
{
    int nextPart, res = PART_ERROR;
    Package pkg;
    int rc, argc;
    int arg;
    const char ** argv = NULL;
    const char *name = NULL;
    int flag = PART_SUBNAME;
    poptContext optCon = NULL;
    struct poptOption optionsTable[] = {
	{ NULL, 'n', POPT_ARG_STRING, &name, 'n', NULL, NULL},
	{ NULL, 'f', POPT_ARG_STRING, NULL, 'f', NULL, NULL},
	{ 0, 0, 0, 0, 0, NULL, NULL}
    };

    /* XXX unmask %license while parsing %files */
    rpmPushMacro(spec->macros, "license", NULL, "%%license", RMIL_SPEC);

    if ((rc = poptParseArgvString(spec->line, &argc, &argv))) {
	rpmlog(RPMLOG_ERR, _("line %d: Error parsing %%files: %s\n"),
		 spec->lineNum, poptStrerror(rc));
	goto exit;
    }

    optCon = poptGetContext(NULL, argc, argv, optionsTable, 0);
    while ((arg = poptGetNextOpt(optCon)) > 0) {
	if (arg == 'n') {
	    flag = PART_NAME;
	}
    }

    if (arg < -1) {
	rpmlog(RPMLOG_ERR, _("line %d: Bad option %s: %s\n"),
		 spec->lineNum,
		 poptBadOption(optCon, POPT_BADOPTION_NOALIAS), 
		 spec->line);
	goto exit;
    }

    if (poptPeekArg(optCon)) {
	if (name == NULL)
	    name = poptGetArg(optCon);
	if (poptPeekArg(optCon)) {
	    rpmlog(RPMLOG_ERR, _("line %d: Too many names: %s\n"),
		     spec->lineNum,
		     spec->line);
	    goto exit;
	}
    }

    if (lookupPackage(spec, name, flag, &pkg))
	goto exit;

    /*
     * This should be an error, but its surprisingly commonly abused for the
     * effect of multiple -f arguments in versions that dont support it.
     * Warn but preserve behavior, except for leaking memory.
     */
    if (pkg->fileList != NULL) {
	rpmlog(RPMLOG_WARNING, _("line %d: multiple %%files for package '%s'\n"),
	       spec->lineNum, rpmstrPoolStr(pkg->pool, pkg->name));
	pkg->fileList = argvFree(pkg->fileList);
    }

    for (arg=1; arg<argc; arg++) {
	if (rstreq(argv[arg], "-f") && argv[arg+1]) {
	    char *file = rpmGetPath(argv[arg+1], NULL);
	    argvAdd(&(pkg->fileFile), file);
	    free(file);
	}
    }

    pkg->fileList = argvNew();

    if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
	nextPart = PART_NONE;
    } else if (rc < 0) {
	goto exit;
    } else {
	while (! (nextPart = isPart(spec->line))) {
	    argvAdd(&(pkg->fileList), spec->line);
	    if ((rc = readLine(spec, STRIP_COMMENTS)) > 0) {
		nextPart = PART_NONE;
		break;
	    } else if (rc < 0) {
		goto exit;
	    }
	}
    }
    res = nextPart;

exit:
    rpmPopMacro(NULL, "license");
    free(argv);
    poptFreeContext(optCon);
	
    return res;
}
Exemple #22
0
int
main(int argc, char *argv[])
{
    poptContext optCon = NULL;
    ARGV_t av = NULL;
    rpmfc fc = NULL;
    int ec = 1;
    char buf[BUFSIZ];

    xsetprogname(argv[0]); /* Portability call -- see system.h */

    optCon = rpmcliInit(argc, argv, optionsTable);
    if (optCon == NULL)
	goto exit;

    /* normally files get passed through stdin but also accept files as args */
    if (poptPeekArg(optCon)) {
	const char *arg;
	while ((arg = poptGetArg(optCon)) != NULL) {
	    argvAdd(&av, arg);
	}
    } else {
	while (fgets(buf, sizeof(buf), stdin) != NULL) {
	    char *be = buf + strlen(buf) - 1;
	    while (strchr("\r\n", *be) != NULL)
		*be-- = '\0';
	    argvAdd(&av, buf);
	}
    }
    /* Make sure file names are sorted. */
    argvSort(av, NULL);

    /* Build file/package class and dependency dictionaries. */
    fc = rpmfcCreate(getenv("RPM_BUILD_ROOT"), 0);
    if (rpmfcClassify(fc, av, NULL) || rpmfcApply(fc))
	goto exit;

    if (_rpmfc_debug)
	rpmfcPrint(buf, fc, NULL);

    if (print_provides)
	rpmdsPrint(NULL, rpmfcProvides(fc), stdout);
    if (print_requires)
	rpmdsPrint(NULL, rpmfcRequires(fc), stdout);
    if (print_recommends)
	rpmdsPrint(NULL, rpmfcRecommends(fc), stdout);
    if (print_suggests)
	rpmdsPrint(NULL, rpmfcSuggests(fc), stdout);
    if (print_supplements)
	rpmdsPrint(NULL, rpmfcSupplements(fc), stdout);
    if (print_enhances)
	rpmdsPrint(NULL, rpmfcEnhances(fc), stdout);
    if (print_conflicts)
	rpmdsPrint(NULL, rpmfcConflicts(fc), stdout);
    if (print_obsoletes)
	rpmdsPrint(NULL, rpmfcObsoletes(fc), stdout);

    ec = 0;

exit:
    argvFree(av);
    rpmfcFree(fc);
    rpmcliFini(optCon);
    return ec;
}
Exemple #23
0
static int processFile(const char *fn, int dtype)
{
    int rc = 1;
    int fdno = -1;
    struct stat st;
    GElf_Ehdr *ehdr, ehdr_mem;
    elfInfo *ei = rcalloc(1, sizeof(*ei));

    fdno = open(fn, O_RDONLY);
    if (fdno < 0 || fstat(fdno, &st) < 0)
	goto exit;

    (void) elf_version(EV_CURRENT);
    ei->elf = elf_begin(fdno, ELF_C_READ, NULL);
    if (ei->elf == NULL || elf_kind(ei->elf) != ELF_K_ELF)
	goto exit;

    ehdr = gelf_getehdr(ei->elf, &ehdr_mem);
    if (ehdr == NULL)
	goto exit;

    if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) {
	ei->marker = mkmarker(ehdr);
    	ei->isDSO = (ehdr->e_type == ET_DYN);
	ei->isExec = (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH));

	processProgHeaders(ei, ehdr);
	processSections(ei);
    }

    /*
     * For DSOs which use the .gnu_hash section and don't have a .hash
     * section, we need to ensure that we have a new enough glibc.
     */
    if (ei->isExec && ei->gotGNUHASH && !ei->gotHASH && !soname_only) {
	argvAdd(&ei->requires, "rtld(GNU_HASH)");
    }

    /*
     * For DSOs, add DT_SONAME as provide. If its missing, we can fake
     * it from the basename if requested. The bizarre looking DT_DEBUG
     * check is used to avoid adding basename provides for PIE executables.
     */
    if (ei->isDSO && !ei->gotDEBUG) {
	if (!ei->soname && fake_soname) {
	    const char *bn = strrchr(fn, '/');
	    ei->soname = rstrdup(bn ? bn + 1 : fn);
	}
	if (ei->soname)
	    addDep(&ei->provides, ei->soname, NULL, ei->marker);
    }

    /* If requested and present, add dep for interpreter (ie dynamic linker) */
    if (ei->interp && require_interp)
	argvAdd(&ei->requires, ei->interp);

    rc = 0;
    /* dump the requested dependencies for this file */
    for (ARGV_t dep = dtype ? ei->requires : ei->provides; dep && *dep; dep++) {
	fprintf(stdout, "%s\n", *dep);
    }

exit:
    if (fdno >= 0) close(fdno);
    if (ei) {
	argvFree(ei->provides);
	argvFree(ei->requires);
	free(ei->soname);
	free(ei->interp);
    	if (ei->elf) elf_end(ei->elf);
	rfree(ei);
    }
    return rc;
}
Exemple #24
0
static sepol *sepolNew(rpmte te)
{
    sepol *head = NULL;
    sepol *ret = NULL;
    sepolAction action;
    Header h;
    struct rpmtd_s policies, names, types, typesidx, flags;
    int i, j;
    int count;

    rpmtdReset(&policies);
    rpmtdReset(&names);
    rpmtdReset(&types);
    rpmtdReset(&typesidx);
    rpmtdReset(&flags);

    h = rpmteHeader(te);
    if (!h) {
	goto exit;
    }

    if (!headerIsEntry(h, RPMTAG_POLICIES)) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) {
	goto exit;
    }

    count = rpmtdCount(&policies);
    if (count <= 0) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM)
	|| rpmtdCount(&names) != count) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM)
	|| rpmtdCount(&flags) != count) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) {
	goto exit;
    }

    if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM)
	|| rpmtdCount(&types) != rpmtdCount(&typesidx)) {
	goto exit;
    }

    action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE;

    for (i = 0; i < count; i++) {
	sepol *pol = xcalloc(1, sizeof(*pol));
	pol->next = head;
	head = pol;

	pol->data = xstrdup(rpmtdNextString(&policies));
	pol->name = xstrdup(rpmtdNextString(&names));
	pol->flags = *rpmtdNextUint32(&flags);
	pol->action = action;

	for (j = 0; j < rpmtdCount(&types); j++) {
	    uint32_t index = ((uint32_t *) typesidx.data)[j];
	    if (index < 0 || index >= count) {
		goto exit;
	    }
	    if (index != i) {
		continue;
	    }
	    argvAdd(&pol->types, rpmtdNextString(&types));
	}
	argvSort(pol->types, NULL);
    }

    ret = head;

  exit:
    headerFree(h);

    rpmtdFreeData(&policies);
    rpmtdFreeData(&names);
    rpmtdFreeData(&types);
    rpmtdFreeData(&typesidx);
    rpmtdFreeData(&flags);

    if (!ret) {
	sepolFree(head);
    }

    return ret;
}
Exemple #25
0
/**
 * Parse %patch line.
 * This supports too many crazy syntaxes:
 * - %patchN is equal to %patch -P<N>
 * - -P<N> -P<N+1>... can be used to apply several patch on a single line
 * - Any trailing arguments are treated as patch numbers
 * - Any combination of the above, except unless at least one -P is specified,
 *   %patch is treated as %patch -P0 so that "%patch 1" is actually
 *   equal to "%patch -P0 -P1".
 *
 * @param spec		build info
 * @param line		current line from spec file
 * @return		RPMRC_OK on success
 */
static rpmRC doPatchMacro(rpmSpec spec, const char *line)
{
    char *opt_b, *opt_P, *opt_d;
    char *buf = NULL;
    int opt_p, opt_R, opt_E, opt_F;
    int argc, c;
    const char **argv = NULL;
    ARGV_t patch, patchnums = NULL;
    rpmRC rc = RPMRC_FAIL; /* assume failure */
    
    struct poptOption const patchOpts[] = {
	{ NULL, 'P', POPT_ARG_STRING, &opt_P, 'P', NULL, NULL },
	{ NULL, 'p', POPT_ARG_INT, &opt_p, 'p', NULL, NULL },
	{ NULL, 'R', POPT_ARG_NONE, &opt_R, 'R', NULL, NULL },
	{ NULL, 'E', POPT_ARG_NONE, &opt_E, 'E', NULL, NULL },
	{ NULL, 'b', POPT_ARG_STRING, &opt_b, 'b', NULL, NULL },
	{ NULL, 'z', POPT_ARG_STRING, &opt_b, 'z', NULL, NULL },
	{ NULL, 'F', POPT_ARG_INT, &opt_F, 'F', NULL, NULL },
	{ NULL, 'd', POPT_ARG_STRING, &opt_d, 'd', NULL, NULL },
	{ NULL, 0, 0, NULL, 0, NULL, NULL }
    };
    poptContext optCon = NULL;

    opt_p = opt_R = opt_E = 0;
    opt_F = rpmExpandNumeric("%{_default_patch_fuzz}");		/* get default fuzz factor for %patch */
    opt_b = opt_d = NULL;

    /* Convert %patchN to %patch -PN to simplify further processing */
    if (! strchr(" \t\n", line[6])) {
	rasprintf(&buf, "%%patch -P %s", line + 6);
    } else {
	if (strstr(line+6, " -P") == NULL)
	    rasprintf(&buf, "%%patch -P %d %s", INT_MAX, line + 6); /* INT_MAX denotes not numbered %patch */
	else
	    buf = xstrdup(line); /* it is not numberless patch because -P is present */
    }
    poptParseArgvString(buf, &argc, &argv);
    free(buf);

    /* 
     * Grab all -P<N> numbers for later processing. Stored as strings
     * at this point so we only have to worry about conversion in one place.
     */
    optCon = poptGetContext(NULL, argc, argv, patchOpts, 0);
    while ((c = poptGetNextOpt(optCon)) > 0) {
	switch (c) {
	case 'P': {
	    char *arg = poptGetOptArg(optCon);
	    if (arg) {
	    	argvAdd(&patchnums, arg);
	    	free(arg);
	    }
	    break;
	}
	default:
	    break;
	}
    }

    if (c < -1) {
	rpmlog(RPMLOG_ERR, _("%s: %s: %s\n"), poptStrerror(c), 
		poptBadOption(optCon, POPT_BADOPTION_NOALIAS), line);
	goto exit;
    }

    /* Any trailing arguments are treated as patch numbers */
    argvAppend(&patchnums, (ARGV_const_t) poptGetArgs(optCon));

    /* Convert to number, generate patch command and append to %prep script */
    for (patch = patchnums; *patch; patch++) {
	uint32_t pnum;
	char *s;
	if (parseUnsignedNum(*patch, &pnum)) {
	    rpmlog(RPMLOG_ERR, _("Invalid patch number %s: %s\n"),
		     *patch, line);
	    goto exit;
	}
	s = doPatch(spec, pnum, opt_p, opt_b, opt_R, opt_E, opt_F, opt_d);
	if (s == NULL) {
	    goto exit;
	}
	appendLineStringBuf(spec->prep, s);
	free(s);
    }
	
    rc = RPMRC_OK;

exit:
    argvFree(patchnums);
    free(argv);
    poptFreeContext(optCon);
    return rc;
}