Blame lib/verify.c

2ff057
/** \ingroup rpmcli
2ff057
 * \file lib/verify.c
2ff057
 * Verify installed payload files from package metadata.
2ff057
 */
2ff057
2ff057
#include "system.h"
2ff057
2ff057
#include <errno.h>
2ff057
#if WITH_CAP
2ff057
#include <sys/capability.h>
2ff057
#endif
2ff057
#if WITH_ACL
2ff057
#include <acl/libacl.h>
2ff057
#endif
2ff057
2ff057
#include <rpm/rpmcli.h>
2ff057
#include <rpm/header.h>
2ff057
#include <rpm/rpmlog.h>
2ff057
#include <rpm/rpmfi.h>
2ff057
#include <rpm/rpmts.h>
2ff057
#include <rpm/rpmdb.h>
2ff057
#include <rpm/rpmfileutil.h>
2ff057
2ff057
#include "lib/misc.h"
2ff057
#include "lib/rpmchroot.h"
2ff057
#include "lib/rpmte_internal.h"	/* rpmteProcess() */
2ff057
#include "lib/rpmug.h"
2ff057
2ff057
#include "debug.h"
2ff057
2ff057
#define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
2ff057
2ff057
/* If cap_compare() (Linux extension) not available, do it the hard way */
2ff057
#if WITH_CAP && !defined(HAVE_CAP_COMPARE)
2ff057
static int cap_compare(cap_t acap, cap_t bcap)
2ff057
{
2ff057
    int rc = 0;
2ff057
    size_t asize = cap_size(acap);
2ff057
    size_t bsize = cap_size(bcap);
2ff057
2ff057
    if (asize != bsize) {
2ff057
	rc = 1;
2ff057
    } else {
2ff057
	char *abuf = xcalloc(asize, sizeof(*abuf));
2ff057
	char *bbuf = xcalloc(bsize, sizeof(*bbuf));
2ff057
	cap_copy_ext(abuf, acap, asize);
2ff057
	cap_copy_ext(bbuf, bcap, bsize);
2ff057
	rc = memcmp(abuf, bbuf, asize);
2ff057
	free(abuf);
2ff057
	free(bbuf);
2ff057
    }
2ff057
    return rc;
2ff057
}
2ff057
#endif
2ff057
	
2ff057
rpmVerifyAttrs rpmfilesVerify(rpmfiles fi, int ix, rpmVerifyAttrs omitMask)
2ff057
{
2ff057
    rpm_mode_t fmode = rpmfilesFMode(fi, ix);
2ff057
    rpmfileAttrs fileAttrs = rpmfilesFFlags(fi, ix);
2ff057
    rpmVerifyAttrs flags = rpmfilesVFlags(fi, ix);
2ff057
    char * fn = rpmfilesFN(fi, ix);
2ff057
    struct stat sb, fsb;
2ff057
    rpmVerifyAttrs vfy = RPMVERIFY_NONE;
2ff057
2ff057
    /*
2ff057
     * Check to see if the file was installed - if not pretend all is OK.
2ff057
     */
2ff057
    switch (rpmfilesFState(fi, ix)) {
2ff057
    case RPMFILE_STATE_NETSHARED:
2ff057
    case RPMFILE_STATE_NOTINSTALLED:
2ff057
	goto exit;
2ff057
	break;
2ff057
    case RPMFILE_STATE_REPLACED:
2ff057
	/* For replaced files we can only verify if it exists at all */
2ff057
	flags = RPMVERIFY_LSTATFAIL;
2ff057
	break;
2ff057
    case RPMFILE_STATE_WRONGCOLOR:
2ff057
	/*
2ff057
	 * Files with wrong color are supposed to share some attributes
2ff057
	 * with the actually installed file - verify what we can.
2ff057
	 */
2ff057
	flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE |
2ff057
		   RPMVERIFY_MTIME | RPMVERIFY_RDEV);
2ff057
	break;
2ff057
    case RPMFILE_STATE_NORMAL:
2ff057
    /* File from a non-installed package, try to verify nevertheless */
2ff057
    case RPMFILE_STATE_MISSING:
2ff057
	break;
2ff057
    }
2ff057
2ff057
    if (fn == NULL || lstat(fn, &sb) != 0 || rpmfilesStat(fi, ix, 0, &fsb)) {
2ff057
	vfy |= RPMVERIFY_LSTATFAIL;
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    /* If we expected a directory but got a symlink to one, follow the link */
2ff057
    if (S_ISDIR(fmode) && S_ISLNK(sb.st_mode)) {
2ff057
	struct stat dsb;
2ff057
	/* ...if it actually points to a directory  */
2ff057
	if (stat(fn, &dsb) == 0 && S_ISDIR(dsb.st_mode)) {
2ff057
	    /* ...and is by a legit user, to match fsmVerify() behavior */
2ff057
	    if (sb.st_uid == 0 || sb.st_uid == dsb.st_uid)
2ff057
		sb = dsb; /* struct assignment */
2ff057
	}
2ff057
    }
2ff057
2ff057
    /* Links have no mode, other types have no linkto */
2ff057
    if (S_ISLNK(sb.st_mode))
2ff057
	flags &= ~(RPMVERIFY_MODE);
2ff057
    else
2ff057
	flags &= ~(RPMVERIFY_LINKTO);
2ff057
2ff057
    /* Not all attributes of non-regular files can be verified */
2ff057
    if (!S_ISREG(sb.st_mode))
2ff057
	flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE |
2ff057
		   RPMVERIFY_MTIME | RPMVERIFY_CAPS);
2ff057
2ff057
    /* Content checks of %ghost files are meaningless. */
2ff057
    if (fileAttrs & RPMFILE_GHOST)
2ff057
	flags &= ~(RPMVERIFY_FILEDIGEST | RPMVERIFY_FILESIZE |
2ff057
		   RPMVERIFY_MTIME | RPMVERIFY_LINKTO);
2ff057
2ff057
    /* Don't verify any features in omitMask. */
2ff057
    flags &= ~(omitMask | RPMVERIFY_FAILURES);
2ff057
2ff057
2ff057
    if (flags & RPMVERIFY_FILEDIGEST) {
2ff057
	const unsigned char *digest; 
2ff057
	int algo;
2ff057
	size_t diglen;
2ff057
2ff057
	/* XXX If --nomd5, then prelinked library sizes are not corrected. */
2ff057
	if ((digest = rpmfilesFDigest(fi, ix, &algo, &diglen))) {
2ff057
	    unsigned char fdigest[diglen];
2ff057
	    rpm_loff_t fsize;
2ff057
2ff057
	    if (rpmDoDigest(algo, fn, 0, fdigest, &fsize)) {
2ff057
		vfy |= (RPMVERIFY_READFAIL|RPMVERIFY_FILEDIGEST);
2ff057
	    } else {
2ff057
		sb.st_size = fsize;
2ff057
		if (memcmp(fdigest, digest, diglen))
2ff057
		    vfy |= RPMVERIFY_FILEDIGEST;
2ff057
	    }
2ff057
	} else {
2ff057
	    vfy |= RPMVERIFY_FILEDIGEST;
2ff057
	} 
2ff057
    } 
2ff057
2ff057
    if (flags & RPMVERIFY_LINKTO) {
2ff057
	char linkto[1024+1];
2ff057
	int size = 0;
2ff057
2ff057
	if ((size = readlink(fn, linkto, sizeof(linkto)-1)) == -1)
2ff057
	    vfy |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
2ff057
	else {
2ff057
	    const char * flink = rpmfilesFLink(fi, ix);
2ff057
	    linkto[size] = '\0';
2ff057
	    if (flink == NULL || !rstreq(linkto, flink))
2ff057
		vfy |= RPMVERIFY_LINKTO;
2ff057
	}
2ff057
    } 
2ff057
2ff057
    if (flags & RPMVERIFY_FILESIZE) {
2ff057
	if (sb.st_size != rpmfilesFSize(fi, ix))
2ff057
	    vfy |= RPMVERIFY_FILESIZE;
2ff057
    } 
2ff057
2ff057
    if (flags & RPMVERIFY_MODE) {
2ff057
	rpm_mode_t metamode = fmode;
2ff057
	rpm_mode_t filemode;
2ff057
2ff057
	/*
2ff057
	 * Platforms (like AIX) where sizeof(rpm_mode_t) != sizeof(mode_t)
2ff057
	 * need the (rpm_mode_t) cast here. 
2ff057
	 */
2ff057
	filemode = (rpm_mode_t)sb.st_mode;
2ff057
2ff057
	/*
2ff057
	 * Comparing the type of %ghost files is meaningless, but perms are OK.
2ff057
	 */
2ff057
	if (fileAttrs & RPMFILE_GHOST) {
2ff057
	    metamode &= ~0xf000;
2ff057
	    filemode &= ~0xf000;
2ff057
	}
2ff057
2ff057
	if (metamode != filemode)
2ff057
	    vfy |= RPMVERIFY_MODE;
2ff057
2ff057
#if WITH_ACL
2ff057
	/*
2ff057
	 * For now, any non-default acl's on a file is a difference as rpm
2ff057
	 * cannot have set them.
2ff057
	 */
2ff057
	acl_t facl = acl_get_file(fn, ACL_TYPE_ACCESS);
2ff057
	if (facl) {
2ff057
	    if (acl_equiv_mode(facl, NULL) == 1) {
2ff057
		vfy |= RPMVERIFY_MODE;
2ff057
	    }
2ff057
	    acl_free(facl);
2ff057
	}
2ff057
#endif 
2ff057
    }
2ff057
2ff057
    if (flags & RPMVERIFY_RDEV) {
2ff057
	if (S_ISCHR(fmode) != S_ISCHR(sb.st_mode)
2ff057
	 || S_ISBLK(fmode) != S_ISBLK(sb.st_mode))
2ff057
	{
2ff057
	    vfy |= RPMVERIFY_RDEV;
2ff057
	} else if (S_ISDEV(fmode) && S_ISDEV(sb.st_mode)) {
2ff057
	    rpm_rdev_t st_rdev = (sb.st_rdev & 0xffff);
2ff057
	    rpm_rdev_t frdev = (rpmfilesFRdev(fi, ix) & 0xffff);
2ff057
	    if (st_rdev != frdev)
2ff057
		vfy |= RPMVERIFY_RDEV;
2ff057
	} 
2ff057
    }
2ff057
2ff057
#if WITH_CAP
2ff057
    if (flags & RPMVERIFY_CAPS) {
2ff057
	/*
2ff057
 	 * Empty capability set ("=") is not exactly the same as no
2ff057
 	 * capabilities at all but suffices for now... 
2ff057
 	 */
2ff057
	cap_t cap, fcap;
2ff057
	cap = cap_from_text(rpmfilesFCaps(fi, ix));
2ff057
	if (!cap) {
2ff057
	    cap = cap_from_text("=");
2ff057
	}
2ff057
	fcap = cap_get_file(fn);
2ff057
	if (!fcap) {
2ff057
	    fcap = cap_from_text("=");
2ff057
	}
2ff057
	
2ff057
	if (cap_compare(cap, fcap) != 0)
2ff057
	    vfy |= RPMVERIFY_CAPS;
2ff057
2ff057
	cap_free(fcap);
2ff057
	cap_free(cap);
2ff057
    }
2ff057
#endif
2ff057
2ff057
    if ((flags & RPMVERIFY_MTIME) && (sb.st_mtime != rpmfilesFMtime(fi, ix))) {
2ff057
	vfy |= RPMVERIFY_MTIME;
2ff057
    }
2ff057
2ff057
    if ((flags & RPMVERIFY_USER) && (sb.st_uid != fsb.st_uid))
2ff057
	vfy |= RPMVERIFY_USER;
2ff057
2ff057
    if ((flags & RPMVERIFY_GROUP) && (sb.st_gid != fsb.st_gid))
2ff057
	vfy |= RPMVERIFY_GROUP;
2ff057
2ff057
exit:
2ff057
    free(fn);
2ff057
    return vfy;
2ff057
}
2ff057
2ff057
int rpmVerifyFile(const rpmts ts, const rpmfi fi,
2ff057
		rpmVerifyAttrs * res, rpmVerifyAttrs omitMask)
2ff057
{
2ff057
    rpmVerifyAttrs vfy = rpmfiVerify(fi, omitMask);
2ff057
    if (res)
2ff057
	*res = vfy;
2ff057
2ff057
    return (vfy & RPMVERIFY_LSTATFAIL) ? 1 : 0;
2ff057
}
2ff057
2ff057
/**
2ff057
 * Return exit code from running verify script from header.
2ff057
 * @param ts		transaction set
2ff057
 * @param h		header
2ff057
 * @return              0 on success
2ff057
 */
2ff057
static int rpmVerifyScript(rpmts ts, Header h)
2ff057
{
2ff057
    int rc = 0;
2ff057
2ff057
    if (headerIsEntry(h, RPMTAG_VERIFYSCRIPT)) {
2ff057
	/* fake up a erasure transaction element */
2ff057
	rpmte p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL);
2ff057
2ff057
	if (p != NULL) {
2ff057
	    rpmteSetHeader(p, h);
2ff057
2ff057
	    rc = (rpmpsmRun(ts, p, PKG_VERIFY) != RPMRC_OK);
2ff057
2ff057
	    /* clean up our fake transaction bits */
2ff057
	    rpmteFree(p);
2ff057
	} else {
2ff057
	    rc = RPMRC_FAIL;
2ff057
	}
2ff057
    }
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
#define unknown "?"
2ff057
#define	_verify(_RPMVERIFY_F, _C, _pad)	\
2ff057
	((verifyResult & _RPMVERIFY_F) ? _C : _pad)
2ff057
#define	_verifylink(_RPMVERIFY_F, _C, _pad)	\
2ff057
	((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
2ff057
	 (verifyResult & _RPMVERIFY_F) ? _C : _pad)
2ff057
#define	_verifyfile(_RPMVERIFY_F, _C, _pad)	\
2ff057
	((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
2ff057
	 (verifyResult & _RPMVERIFY_F) ? _C : _pad)
2ff057
char * rpmVerifyString(uint32_t verifyResult, const char *pad)
2ff057
{
2ff057
    char *fmt = NULL;
2ff057
    rasprintf(&fmt, "%s%s%s%s%s%s%s%s%s",
2ff057
		_verify(RPMVERIFY_FILESIZE, "S", pad),
2ff057
		_verify(RPMVERIFY_MODE, "M", pad),
2ff057
		_verifyfile(RPMVERIFY_FILEDIGEST, "5", pad),
2ff057
		_verify(RPMVERIFY_RDEV, "D", pad),
2ff057
		_verifylink(RPMVERIFY_LINKTO, "L", pad),
2ff057
		_verify(RPMVERIFY_USER, "U", pad),
2ff057
		_verify(RPMVERIFY_GROUP, "G", pad),
2ff057
		_verify(RPMVERIFY_MTIME, "T", pad),
2ff057
		_verify(RPMVERIFY_CAPS, "P", pad));
2ff057
		
2ff057
    return fmt;
2ff057
}
2ff057
#undef _verifyfile
2ff057
#undef _verifylink
2ff057
#undef _verify
2ff057
#undef aok
2ff057
#undef unknown
2ff057
2ff057
char * rpmFFlagsString(uint32_t fflags, const char *pad)
2ff057
{
2ff057
    char *fmt = NULL;
2ff057
    rasprintf(&fmt, "%s%s%s%s%s%s%s%s%s",
2ff057
		(fflags & RPMFILE_DOC) ? "d" : pad,
2ff057
		(fflags & RPMFILE_CONFIG) ? "c" : pad,
2ff057
		(fflags & RPMFILE_SPECFILE) ? "s" : pad,
2ff057
		(fflags & RPMFILE_MISSINGOK) ? "m" : pad,
2ff057
		(fflags & RPMFILE_NOREPLACE) ? "n" : pad,
2ff057
		(fflags & RPMFILE_GHOST) ? "g" : pad,
2ff057
		(fflags & RPMFILE_LICENSE) ? "l" : pad,
2ff057
		(fflags & RPMFILE_README) ? "r" : pad,
2ff057
		(fflags & RPMFILE_ARTIFACT) ? "a" : pad);
2ff057
    return fmt;
2ff057
}
2ff057
2ff057
static const char * stateStr(rpmfileState fstate)
2ff057
{
2ff057
    switch (fstate) {
2ff057
    case RPMFILE_STATE_NORMAL:
2ff057
	return NULL;
2ff057
    case RPMFILE_STATE_NOTINSTALLED:
2ff057
	return rpmIsVerbose() ? _("not installed") : NULL;
2ff057
    case RPMFILE_STATE_NETSHARED:
2ff057
	return rpmIsVerbose() ? _("net shared") : NULL;
2ff057
    case RPMFILE_STATE_WRONGCOLOR:
2ff057
	return rpmIsVerbose() ? _("wrong color") : NULL;
2ff057
    case RPMFILE_STATE_REPLACED:
2ff057
	return _("replaced");
2ff057
    case RPMFILE_STATE_MISSING:
2ff057
	return _("no state");
2ff057
    }
2ff057
    return _("unknown state");
2ff057
}
2ff057
2ff057
/**
2ff057
 * Check file info from header against what's actually installed.
2ff057
 * @param ts		transaction set
2ff057
 * @param h		header to verify
2ff057
 * @param omitMask	bits to disable verify checks
2ff057
 * @param skipAttr	skip files with these attrs (eg %ghost)
2ff057
 * @return		0 no problems, 1 problems found
2ff057
 */
2ff057
static int verifyHeader(rpmts ts, Header h, rpmVerifyAttrs omitMask,
2ff057
			rpmfileAttrs skipAttrs)
2ff057
{
2ff057
    rpmVerifyAttrs verifyResult = 0;
2ff057
    rpmVerifyAttrs verifyAll = 0; /* assume no problems */
2ff057
    rpmfi fi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_FLAGS_VERIFY);
2ff057
2ff057
    if (fi == NULL)
2ff057
	return 1;
2ff057
2ff057
    rpmfiInit(fi, 0);
2ff057
    while (rpmfiNext(fi) >= 0) {
2ff057
	rpmfileAttrs fileAttrs = rpmfiFFlags(fi);
2ff057
	char *buf = NULL, *attrFormat;
2ff057
	const char *fstate = NULL;
2ff057
	char ac;
2ff057
2ff057
	/* Skip on attributes (eg from --noghost) */
2ff057
	if (skipAttrs & fileAttrs)
2ff057
	    continue;
2ff057
2ff057
	verifyResult = rpmfiVerify(fi, omitMask);
2ff057
2ff057
	/* Filter out timestamp differences of shared files */
2ff057
	if (verifyResult & RPMVERIFY_MTIME) {
2ff057
	    rpmdbMatchIterator mi;
2ff057
	    mi = rpmtsInitIterator(ts, RPMDBI_BASENAMES, rpmfiFN(fi), 0);
2ff057
	    if (rpmdbGetIteratorCount(mi) > 1) 
2ff057
		verifyResult &= ~RPMVERIFY_MTIME;
2ff057
	    rpmdbFreeIterator(mi);
2ff057
	}
2ff057
2ff057
	/* State is only meaningful for installed packages */
2ff057
	if (headerGetInstance(h))
2ff057
	    fstate = stateStr(rpmfiFState(fi));
2ff057
2ff057
	attrFormat = rpmFFlagsString(fileAttrs, "");
2ff057
	ac = rstreq(attrFormat, "") ? ' ' : attrFormat[0];
2ff057
	if (verifyResult & RPMVERIFY_LSTATFAIL) {
2ff057
	    if (!(fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST)) || rpmIsVerbose()) {
2ff057
		rasprintf(&buf, _("missing   %c %s"), ac, rpmfiFN(fi));
2ff057
		if ((verifyResult & RPMVERIFY_LSTATFAIL) != 0 &&
2ff057
		    errno != ENOENT) {
2ff057
		    char *app;
2ff057
		    rasprintf(&app, " (%s)", strerror(errno));
2ff057
		    rstrcat(&buf, app);
2ff057
		    free(app);
2ff057
		}
2ff057
	    }
2ff057
	} else if (verifyResult || fstate || rpmIsVerbose()) {
2ff057
	    char *verifyFormat = rpmVerifyString(verifyResult, ".");
2ff057
	    rasprintf(&buf, "%s  %c %s", verifyFormat, ac, rpmfiFN(fi));
2ff057
	    free(verifyFormat);
2ff057
	}
2ff057
	free(attrFormat);
2ff057
2ff057
	if (buf) {
2ff057
	    if (fstate)
2ff057
		buf = rstrscat(&buf, " (", fstate, ")", NULL);
2ff057
	    rpmlog(RPMLOG_NOTICE, "%s\n", buf);
2ff057
	    buf = _free(buf);
2ff057
	}
2ff057
2ff057
	/* Filter out missing %ghost/%missingok errors from final result */
2ff057
	if (fileAttrs & (RPMFILE_MISSINGOK|RPMFILE_GHOST))
2ff057
	    verifyResult &= ~RPMVERIFY_LSTATFAIL;
2ff057
2ff057
	verifyAll |= verifyResult;
2ff057
    }
2ff057
    rpmfiFree(fi);
2ff057
	
2ff057
    return (verifyAll != 0) ? 1 : 0;
2ff057
}
2ff057
2ff057
/**
2ff057
 * Check installed package dependencies for problems.
2ff057
 * @param ts		transaction set
2ff057
 * @param h		header
2ff057
 * @return		number of problems found (0 for no problems)
2ff057
 */
2ff057
static int verifyDependencies(rpmts ts, Header h)
2ff057
{
2ff057
    rpmps ps;
2ff057
    rpmte te;
2ff057
    int rc;
2ff057
2ff057
    rpmtsEmpty(ts);
2ff057
    (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL);
2ff057
2ff057
    (void) rpmtsCheck(ts);
2ff057
    te = rpmtsElement(ts, 0);
2ff057
    ps = rpmteProblems(te);
2ff057
    rc = rpmpsNumProblems(ps);
2ff057
2ff057
    if (rc > 0) {
2ff057
	rpmlog(RPMLOG_NOTICE, _("Unsatisfied dependencies for %s:\n"),
2ff057
	       rpmteNEVRA(te));
2ff057
	rpmpsi psi = rpmpsInitIterator(ps);
2ff057
	rpmProblem p;
2ff057
2ff057
	while ((p = rpmpsiNext(psi)) != NULL) {
2ff057
	    char * ps = rpmProblemString(p);
2ff057
	    rpmlog(RPMLOG_NOTICE, "\t%s\n", ps);
2ff057
	    free(ps);
2ff057
	}
2ff057
	rpmpsFreeIterator(psi);
2ff057
    }
2ff057
    rpmpsFree(ps);
2ff057
    rpmtsEmpty(ts);
2ff057
2ff057
    return rc;
2ff057
}
2ff057
2ff057
int showVerifyPackage(QVA_t qva, rpmts ts, Header h)
2ff057
{
2ff057
    rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
2ff057
    int ec = 0;
2ff057
    int rc;
2ff057
2ff057
    if (qva->qva_flags & VERIFY_DEPS) {
2ff057
	if ((rc = verifyDependencies(ts, h)) != 0)
2ff057
	    ec = rc;
2ff057
    }
2ff057
    if (qva->qva_flags & VERIFY_FILES) {
2ff057
	if ((rc = verifyHeader(ts, h, omitMask, qva->qva_fflags)) != 0)
2ff057
	    ec = rc;
2ff057
    }
2ff057
    if (qva->qva_flags & VERIFY_SCRIPT) {
2ff057
	if ((rc = rpmVerifyScript(ts, h)) != 0)
2ff057
	    ec = rc;
2ff057
    }
2ff057
2ff057
    return ec;
2ff057
}
2ff057
2ff057
int rpmcliVerify(rpmts ts, QVA_t qva, char * const * argv)
2ff057
{
2ff057
    rpmVSFlags vsflags, ovsflags;
2ff057
    int ec = 0;
2ff057
    FD_t scriptFd = fdDup(STDOUT_FILENO);
2ff057
2ff057
    /* 
2ff057
     * Open the DB + indices explicitly before possible chroot,
2ff057
     * otherwises BDB is going to be unhappy...
2ff057
     */
2ff057
    rpmtsOpenDB(ts, O_RDONLY);
2ff057
    rpmdbOpenAll(rpmtsGetRdb(ts));
2ff057
    if (rpmChrootSet(rpmtsRootDir(ts)) || rpmChrootIn()) {
2ff057
	ec = 1;
2ff057
	goto exit;
2ff057
    }
2ff057
2ff057
    if (qva->qva_showPackage == NULL)
2ff057
        qva->qva_showPackage = showVerifyPackage;
2ff057
2ff057
    vsflags = rpmExpandNumeric("%{?_vsflags_verify}");
2ff057
    if (rpmcliQueryFlags & VERIFY_DIGEST)
2ff057
	vsflags |= _RPMVSF_NODIGESTS;
2ff057
    if (rpmcliQueryFlags & VERIFY_SIGNATURE)
2ff057
	vsflags |= _RPMVSF_NOSIGNATURES;
2ff057
    if (rpmcliQueryFlags & VERIFY_HDRCHK)
2ff057
	vsflags |= RPMVSF_NOHDRCHK;
2ff057
    vsflags |= rpmcliVSFlags;
2ff057
    vsflags &= ~RPMVSF_NEEDPAYLOAD;
2ff057
2ff057
    rpmtsSetScriptFd(ts, scriptFd);
2ff057
    ovsflags = rpmtsSetVSFlags(ts, vsflags);
2ff057
    ec = rpmcliArgIter(ts, qva, argv);
2ff057
    rpmtsSetVSFlags(ts, ovsflags);
2ff057
    rpmtsSetScriptFd(ts, NULL);
2ff057
2ff057
    if (qva->qva_showPackage == showVerifyPackage)
2ff057
        qva->qva_showPackage = NULL;
2ff057
2ff057
    rpmtsEmpty(ts);
2ff057
2ff057
    if (rpmChrootOut() || rpmChrootSet(NULL))
2ff057
	ec = 1;
2ff057
2ff057
exit:
2ff057
    Fclose(scriptFd);
2ff057
2ff057
    return ec;
2ff057
}