574 lines
15 KiB
C
574 lines
15 KiB
C
/** \ingroup rpmcli
|
|
* \file lib/verify.c
|
|
* Verify installed payload files from package metadata.
|
|
*/
|
|
|
|
#include "system.h"
|
|
|
|
#include "psm.h"
|
|
#include "rpmcli.h"
|
|
|
|
#include "ugid.h"
|
|
#include "misc.h" /* XXX for uidToUname() and gnameToGid() */
|
|
#include "debug.h"
|
|
|
|
/*@access TFI_t*/
|
|
/*@access PSM_t*/
|
|
/*@access FD_t*/ /* XXX compared with NULL */
|
|
/*@access rpmdb*/ /* XXX compared with NULL */
|
|
|
|
#define S_ISDEV(m) (S_ISBLK((m)) || S_ISCHR((m)))
|
|
|
|
int rpmVerifyFile(const char * root, Header h, int filenum,
|
|
rpmVerifyAttrs * result, rpmVerifyAttrs omitMask)
|
|
{
|
|
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
|
|
HFD_t hfd = headerFreeData;
|
|
int_32 * fileFlags;
|
|
rpmfileAttrs fileAttrs = RPMFILE_NONE;
|
|
int_32 * verifyFlags;
|
|
rpmVerifyAttrs flags = RPMVERIFY_ALL;
|
|
unsigned short * modeList;
|
|
const char * fileStatesList;
|
|
const char * filespec = NULL;
|
|
int count;
|
|
int rc;
|
|
struct stat sb;
|
|
|
|
rc = hge(h, RPMTAG_FILEMODES, NULL, (void **) &modeList, &count);
|
|
if (hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
|
|
fileAttrs = fileFlags[filenum];
|
|
|
|
if (hge(h, RPMTAG_FILEVERIFYFLAGS, NULL, (void **) &verifyFlags, NULL))
|
|
flags = verifyFlags[filenum];
|
|
|
|
{
|
|
const char ** baseNames;
|
|
const char ** dirNames;
|
|
int_32 * dirIndexes;
|
|
rpmTagType bnt, dnt;
|
|
|
|
if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, NULL)
|
|
&& hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL)
|
|
&& hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL))
|
|
{
|
|
int nb = (strlen(dirNames[dirIndexes[filenum]]) +
|
|
strlen(baseNames[filenum]) + strlen(root) + 5);
|
|
char * t = alloca(nb);
|
|
filespec = t;
|
|
*t = '\0';
|
|
if (root && !(root[0] == '/' && root[1] == '\0')) {
|
|
t = stpcpy(t, root);
|
|
while (t > filespec && t[-1] == '/') {
|
|
--t;
|
|
*t = '\0';
|
|
}
|
|
}
|
|
t = stpcpy(t, dirNames[dirIndexes[filenum]]);
|
|
t = stpcpy(t, baseNames[filenum]);
|
|
}
|
|
baseNames = hfd(baseNames, bnt);
|
|
dirNames = hfd(dirNames, dnt);
|
|
}
|
|
|
|
*result = RPMVERIFY_NONE;
|
|
|
|
/*
|
|
* Check to see if the file was installed - if not pretend all is OK.
|
|
*/
|
|
if (hge(h, RPMTAG_FILESTATES, NULL, (void **) &fileStatesList, NULL) &&
|
|
fileStatesList != NULL)
|
|
{
|
|
rpmfileState fstate = fileStatesList[filenum];
|
|
switch (fstate) {
|
|
case RPMFILE_STATE_NETSHARED:
|
|
case RPMFILE_STATE_REPLACED:
|
|
case RPMFILE_STATE_NOTINSTALLED:
|
|
return 0;
|
|
/*@notreached@*/ break;
|
|
case RPMFILE_STATE_NORMAL:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (filespec == NULL) {
|
|
*result |= RPMVERIFY_LSTATFAIL;
|
|
return 1;
|
|
}
|
|
|
|
if (Lstat(filespec, &sb) != 0) {
|
|
*result |= RPMVERIFY_LSTATFAIL;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Not all attributes of non-regular files can be verified.
|
|
*/
|
|
if (S_ISDIR(sb.st_mode))
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_LINKTO);
|
|
else if (S_ISLNK(sb.st_mode)) {
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_MODE);
|
|
#if CHOWN_FOLLOWS_SYMLINK
|
|
flags &= ~(RPMVERIFY_USER | RPMVERIFY_GROUP);
|
|
#endif
|
|
}
|
|
else if (S_ISFIFO(sb.st_mode))
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_LINKTO);
|
|
else if (S_ISCHR(sb.st_mode))
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_LINKTO);
|
|
else if (S_ISBLK(sb.st_mode))
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_LINKTO);
|
|
else
|
|
flags &= ~(RPMVERIFY_LINKTO);
|
|
|
|
/*
|
|
* Content checks of %ghost files are meaningless.
|
|
*/
|
|
if (fileAttrs & RPMFILE_GHOST)
|
|
flags &= ~(RPMVERIFY_MD5 | RPMVERIFY_FILESIZE | RPMVERIFY_MTIME |
|
|
RPMVERIFY_LINKTO);
|
|
|
|
/*
|
|
* Don't verify any features in omitMask.
|
|
*/
|
|
flags &= ~(omitMask | RPMVERIFY_LSTATFAIL|RPMVERIFY_READFAIL|RPMVERIFY_READLINKFAIL);
|
|
|
|
if (flags & RPMVERIFY_MD5) {
|
|
unsigned char md5sum[40];
|
|
const char ** md5List;
|
|
rpmTagType mdt;
|
|
|
|
if (!hge(h, RPMTAG_FILEMD5S, &mdt, (void **) &md5List, NULL))
|
|
*result |= RPMVERIFY_MD5;
|
|
else {
|
|
rc = domd5(filespec, md5sum, 1);
|
|
if (rc)
|
|
*result |= (RPMVERIFY_READFAIL|RPMVERIFY_MD5);
|
|
else if (strcmp(md5sum, md5List[filenum]))
|
|
*result |= RPMVERIFY_MD5;
|
|
}
|
|
md5List = hfd(md5List, mdt);
|
|
}
|
|
|
|
if (flags & RPMVERIFY_LINKTO) {
|
|
char linkto[1024];
|
|
int size = 0;
|
|
const char ** linktoList;
|
|
rpmTagType ltt;
|
|
|
|
if (!hge(h, RPMTAG_FILELINKTOS, <t, (void **) &linktoList, NULL)
|
|
|| (size = Readlink(filespec, linkto, sizeof(linkto)-1)) == -1)
|
|
*result |= (RPMVERIFY_READLINKFAIL|RPMVERIFY_LINKTO);
|
|
else {
|
|
linkto[size] = '\0';
|
|
if (strcmp(linkto, linktoList[filenum]))
|
|
*result |= RPMVERIFY_LINKTO;
|
|
}
|
|
linktoList = hfd(linktoList, ltt);
|
|
}
|
|
|
|
if (flags & RPMVERIFY_FILESIZE) {
|
|
uint32_t *sizeList;
|
|
|
|
if (!hge(h, RPMTAG_FILESIZES, NULL, (void **) &sizeList, NULL)
|
|
|| sizeList[filenum] != sb.st_size)
|
|
*result |= RPMVERIFY_FILESIZE;
|
|
}
|
|
|
|
if (flags & RPMVERIFY_MODE) {
|
|
unsigned short metamode = modeList[filenum];
|
|
unsigned short filemode;
|
|
|
|
/*
|
|
* Platforms (like AIX) where sizeof(unsigned short) != sizeof(mode_t)
|
|
* need the (unsigned short) cast here.
|
|
*/
|
|
filemode = (unsigned short)sb.st_mode;
|
|
|
|
/*
|
|
* Comparing the type of %ghost files is meaningless, but perms are OK.
|
|
*/
|
|
if (fileAttrs & RPMFILE_GHOST) {
|
|
metamode &= ~0xf000;
|
|
filemode &= ~0xf000;
|
|
}
|
|
|
|
if (metamode != filemode)
|
|
*result |= RPMVERIFY_MODE;
|
|
}
|
|
|
|
if (flags & RPMVERIFY_RDEV) {
|
|
if (S_ISCHR(modeList[filenum]) != S_ISCHR(sb.st_mode) ||
|
|
S_ISBLK(modeList[filenum]) != S_ISBLK(sb.st_mode))
|
|
{
|
|
*result |= RPMVERIFY_RDEV;
|
|
} else if (S_ISDEV(modeList[filenum]) && S_ISDEV(sb.st_mode)) {
|
|
unsigned short * rdevList;
|
|
if (!hge(h, RPMTAG_FILERDEVS, NULL, (void **) &rdevList, NULL)
|
|
|| rdevList[filenum] != sb.st_rdev)
|
|
*result |= RPMVERIFY_RDEV;
|
|
}
|
|
}
|
|
|
|
if (flags & RPMVERIFY_MTIME) {
|
|
int_32 * mtimeList;
|
|
|
|
if (!hge(h, RPMTAG_FILEMTIMES, NULL, (void **) &mtimeList, NULL)
|
|
|| mtimeList[filenum] != sb.st_mtime)
|
|
*result |= RPMVERIFY_MTIME;
|
|
}
|
|
|
|
if (flags & RPMVERIFY_USER) {
|
|
const char * name;
|
|
const char ** unameList;
|
|
int_32 * uidList;
|
|
rpmTagType unt;
|
|
|
|
if (hge(h, RPMTAG_FILEUSERNAME, &unt, (void **) &unameList, NULL)) {
|
|
name = uidToUname(sb.st_uid);
|
|
if (!name || strcmp(unameList[filenum], name))
|
|
*result |= RPMVERIFY_USER;
|
|
unameList = hfd(unameList, unt);
|
|
} else if (hge(h, RPMTAG_FILEUIDS, NULL, (void **) &uidList, NULL)) {
|
|
if (uidList[filenum] != sb.st_uid)
|
|
*result |= RPMVERIFY_GROUP;
|
|
} else {
|
|
rpmError(RPMERR_INTERNAL, _("package lacks both user name and id "
|
|
"lists (this should never happen)\n"));
|
|
*result |= RPMVERIFY_GROUP;
|
|
}
|
|
}
|
|
|
|
if (flags & RPMVERIFY_GROUP) {
|
|
const char ** gnameList;
|
|
int_32 * gidList;
|
|
rpmTagType gnt;
|
|
gid_t gid;
|
|
|
|
if (hge(h, RPMTAG_FILEGROUPNAME, &gnt, (void **) &gnameList, NULL)) {
|
|
rc = gnameToGid(gnameList[filenum], &gid);
|
|
if (rc || (gid != sb.st_gid))
|
|
*result |= RPMVERIFY_GROUP;
|
|
gnameList = hfd(gnameList, gnt);
|
|
} else if (hge(h, RPMTAG_FILEGIDS, NULL, (void **) &gidList, NULL)) {
|
|
if (gidList[filenum] != sb.st_gid)
|
|
*result |= RPMVERIFY_GROUP;
|
|
} else {
|
|
rpmError(RPMERR_INTERNAL, _("package lacks both group name and id "
|
|
"lists (this should never happen)\n"));
|
|
*result |= RPMVERIFY_GROUP;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Return exit code from running verify script in header.
|
|
* @todo gnorpm/kpackage prevents static, should be using VERIFY_SCRIPT flag.
|
|
* @param rootDir path to top of install tree
|
|
* @param h header
|
|
* @param scriptFd file handle to use for stderr (or NULL)
|
|
* @return 0 on success
|
|
*/
|
|
int rpmVerifyScript(const char * rootDir, Header h, /*@null@*/ FD_t scriptFd)
|
|
{
|
|
rpmdb rpmdb = NULL;
|
|
rpmTransactionSet ts = rpmtransCreateSet(rpmdb, rootDir);
|
|
TFI_t fi = xcalloc(1, sizeof(*fi));
|
|
struct psm_s psmbuf;
|
|
PSM_t psm = &psmbuf;
|
|
int rc;
|
|
|
|
if (scriptFd != NULL)
|
|
ts->scriptFd = fdLink(scriptFd, "rpmVerifyScript");
|
|
fi->magic = TFIMAGIC;
|
|
loadFi(h, fi);
|
|
memset(psm, 0, sizeof(*psm));
|
|
psm->ts = ts;
|
|
psm->fi = fi;
|
|
psm->stepName = "verify";
|
|
psm->scriptTag = RPMTAG_VERIFYSCRIPT;
|
|
psm->progTag = RPMTAG_VERIFYSCRIPTPROG;
|
|
rc = psmStage(psm, PSM_SCRIPT);
|
|
freeFi(fi);
|
|
fi = _free(fi);
|
|
ts = rpmtransFree(ts);
|
|
return rc;
|
|
}
|
|
|
|
int rpmVerifyDigest(Header h)
|
|
{
|
|
HGE_t hge = (HGE_t)headerGetEntry; /* XXX headerGetEntryMinMemory? */
|
|
HFD_t hfd = headerFreeData;
|
|
void * uh = NULL;
|
|
rpmTagType uht;
|
|
int_32 uhc;
|
|
const char * hdigest;
|
|
rpmTagType hdt;
|
|
int ec = 0; /* assume no problems */
|
|
|
|
/* Retrieve header digest. */
|
|
if (!hge(h, RPMTAG_SHA1RHN, &hdt, (void **) &hdigest, NULL))
|
|
return 0;
|
|
|
|
/* Regenerate original header. */
|
|
if (!hge(h, RPMTAG_HEADERIMMUTABLE, &uht, &uh, &uhc))
|
|
return 0;
|
|
|
|
if (hdigest == NULL || uh == NULL)
|
|
return 0;
|
|
|
|
/* Compute header digest. */
|
|
{ DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
|
|
const char * digest;
|
|
size_t digestlen;
|
|
|
|
(void) rpmDigestUpdate(ctx, uh, uhc);
|
|
(void) rpmDigestFinal(ctx, (void **)&digest, &digestlen, 1);
|
|
|
|
/* XXX can't happen: report NULL malloc return as a digest failure. */
|
|
ec = (digest == NULL || strcmp(hdigest, digest)) ? 1 : 0;
|
|
digest = _free(digest);
|
|
}
|
|
|
|
uh = hfd(uh, uht);
|
|
hdigest = hfd(hdigest, hdt);
|
|
|
|
return ec;
|
|
}
|
|
|
|
/**
|
|
* Check file info from header against what's actually installed.
|
|
* @param qva parsed query/verify options
|
|
* @param h header
|
|
* @return 0 no problems, 1 problems found
|
|
*/
|
|
static int verifyHeader(QVA_t qva, Header h)
|
|
/*@modifies h @*/
|
|
{
|
|
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
|
|
char buf[BUFSIZ];
|
|
char * t, * te;
|
|
const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
|
|
const char ** fileNames = NULL;
|
|
int count;
|
|
int_32 * fileFlags = NULL;
|
|
rpmVerifyAttrs verifyResult = 0;
|
|
rpmVerifyAttrs omitMask = ((qva->qva_flags & VERIFY_ATTRS) ^ VERIFY_ATTRS);
|
|
int ec = 0; /* assume no problems */
|
|
int i;
|
|
|
|
te = t = buf;
|
|
*te = '\0';
|
|
|
|
if (!hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL))
|
|
goto exit;
|
|
|
|
if (!headerIsEntry(h, RPMTAG_BASENAMES))
|
|
goto exit;
|
|
|
|
rpmBuildFileList(h, &fileNames, &count);
|
|
|
|
for (i = 0; i < count; i++) {
|
|
rpmfileAttrs fileAttrs;
|
|
int rc;
|
|
|
|
fileAttrs = fileFlags[i];
|
|
|
|
/* If not verifying %ghost, skip ghost files. */
|
|
if (!(qva->qva_fflags & RPMFILE_GHOST)
|
|
&& (fileAttrs & RPMFILE_GHOST))
|
|
continue;
|
|
|
|
rc = rpmVerifyFile(prefix, h, i, &verifyResult, omitMask);
|
|
if (rc) {
|
|
/*@-internalglobs@*/ /* FIX: shrug */
|
|
if (!(fileAttrs & RPMFILE_MISSINGOK) || rpmIsVerbose()) {
|
|
sprintf(te, _("missing %s"), fileNames[i]);
|
|
te += strlen(te);
|
|
ec = rc;
|
|
}
|
|
/*@=internalglobs@*/
|
|
} else if (verifyResult) {
|
|
const char * size, * md5, * link, * mtime, * mode;
|
|
const char * group, * user, * rdev;
|
|
/*@observer@*/ static const char *const aok = ".";
|
|
/*@observer@*/ static const char *const unknown = "?";
|
|
|
|
ec = 1;
|
|
|
|
#define _verify(_RPMVERIFY_F, _C) \
|
|
((verifyResult & _RPMVERIFY_F) ? _C : aok)
|
|
#define _verifylink(_RPMVERIFY_F, _C) \
|
|
((verifyResult & RPMVERIFY_READLINKFAIL) ? unknown : \
|
|
(verifyResult & _RPMVERIFY_F) ? _C : aok)
|
|
#define _verifyfile(_RPMVERIFY_F, _C) \
|
|
((verifyResult & RPMVERIFY_READFAIL) ? unknown : \
|
|
(verifyResult & _RPMVERIFY_F) ? _C : aok)
|
|
|
|
md5 = _verifyfile(RPMVERIFY_MD5, "5");
|
|
size = _verify(RPMVERIFY_FILESIZE, "S");
|
|
link = _verifylink(RPMVERIFY_LINKTO, "L");
|
|
mtime = _verify(RPMVERIFY_MTIME, "T");
|
|
rdev = _verify(RPMVERIFY_RDEV, "D");
|
|
user = _verify(RPMVERIFY_USER, "U");
|
|
group = _verify(RPMVERIFY_GROUP, "G");
|
|
mode = _verify(RPMVERIFY_MODE, "M");
|
|
|
|
#undef _verify
|
|
#undef _verifylink
|
|
#undef _verifyfile
|
|
|
|
sprintf(te, "%s%s%s%s%s%s%s%s %c %s",
|
|
size, mode, md5, rdev, link, user, group, mtime,
|
|
((fileAttrs & RPMFILE_CONFIG) ? 'c' :
|
|
(fileAttrs & RPMFILE_DOC) ? 'd' :
|
|
(fileAttrs & RPMFILE_GHOST) ? 'g' :
|
|
(fileAttrs & RPMFILE_LICENSE) ? 'l' :
|
|
(fileAttrs & RPMFILE_README) ? 'r' : ' '),
|
|
fileNames[i]);
|
|
te += strlen(te);
|
|
}
|
|
|
|
if (te > t) {
|
|
*te++ = '\n';
|
|
*te = '\0';
|
|
rpmMessage(RPMMESS_NORMAL, "%s", t);
|
|
te = t = buf;
|
|
*t = '\0';
|
|
}
|
|
}
|
|
|
|
exit:
|
|
fileNames = _free(fileNames);
|
|
return ec;
|
|
}
|
|
|
|
/**
|
|
* Check installed package dependencies for problems.
|
|
* @param rpmdb rpm database
|
|
* @param h header
|
|
* @return 0 no problems, 1 problems found
|
|
*/
|
|
static int verifyDependencies(rpmdb rpmdb, Header h)
|
|
/*@modifies h @*/
|
|
{
|
|
rpmTransactionSet ts = rpmtransCreateSet(rpmdb, NULL);
|
|
unsigned int offset = headerGetInstance(h);
|
|
if (offset > 0)
|
|
rpmtransRemovePackage(ts, offset);
|
|
(void) rpmtransAddPackage(ts, h, NULL, NULL, 0, NULL);
|
|
|
|
rpmDependencyConflict conflicts;
|
|
int numConflicts;
|
|
(void) rpmdepCheck(ts, &conflicts, &numConflicts);
|
|
ts = rpmtransFree(ts);
|
|
|
|
/*@-branchstate@*/
|
|
if (numConflicts) {
|
|
const char *n, *v, *r;
|
|
char * t, * te;
|
|
int nb = 512;
|
|
(void) headerNVRD(h, &n, &v, &r, NULL); // we don't print the disttag
|
|
|
|
int i;
|
|
for (i = 0; i < numConflicts; i++) {
|
|
nb += strlen(conflicts[i].needsName) + sizeof(", ") - 1;
|
|
if (conflicts[i].needsFlags)
|
|
nb += strlen(conflicts[i].needsVersion) + 5;
|
|
}
|
|
te = t = alloca(nb);
|
|
*te = '\0';
|
|
sprintf(te, _("Unsatisfied dependencies for %s-%s-%s: "), n, v, r);
|
|
te += strlen(te);
|
|
for (i = 0; i < numConflicts; i++) {
|
|
if (i) te = stpcpy(te, ", ");
|
|
te = stpcpy(te, conflicts[i].needsName);
|
|
if (conflicts[i].needsFlags) {
|
|
int flags = conflicts[i].needsFlags;
|
|
*te++ = ' ';
|
|
if (flags & RPMSENSE_LESS) *te++ = '<';
|
|
if (flags & RPMSENSE_GREATER) *te++ = '>';
|
|
if (flags & RPMSENSE_EQUAL) *te++ = '=';
|
|
*te++ = ' ';
|
|
te = stpcpy(te, conflicts[i].needsVersion);
|
|
}
|
|
}
|
|
conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
|
|
if (te > t) {
|
|
*te++ = '\n';
|
|
*te = '\0';
|
|
rpmMessage(RPMMESS_NORMAL, "%s", t);
|
|
te = t;
|
|
*t = '\0';
|
|
}
|
|
return 1;
|
|
}
|
|
/*@=branchstate@*/
|
|
return 0;
|
|
}
|
|
|
|
int showVerifyPackage(QVA_t qva, rpmdb rpmdb, Header h)
|
|
{
|
|
const char * prefix = (qva->qva_prefix ? qva->qva_prefix : "");
|
|
int ec = 0;
|
|
int rc;
|
|
|
|
if (qva->qva_flags & VERIFY_DIGEST) {
|
|
if ((rc = rpmVerifyDigest(h)) != 0) {
|
|
const char *n, *v, *r;
|
|
(void) headerNVRD(h, &n, &v, &r, NULL); // we don't print the disttag
|
|
rpmMessage(RPMMESS_NORMAL,
|
|
_("%s-%s-%s: immutable header region digest check failed\n"),
|
|
n, v, r);
|
|
ec = rc;
|
|
}
|
|
}
|
|
if (qva->qva_flags & VERIFY_DEPS) {
|
|
if ((rc = verifyDependencies(rpmdb, h)) != 0)
|
|
ec = rc;
|
|
}
|
|
if (qva->qva_flags & VERIFY_FILES) {
|
|
if ((rc = verifyHeader(qva, h)) != 0)
|
|
ec = rc;
|
|
}
|
|
if (qva->qva_flags & VERIFY_SCRIPT) {
|
|
FD_t fdo = fdDup(STDOUT_FILENO);
|
|
if ((rc = rpmVerifyScript(prefix, h, fdo)) != 0)
|
|
ec = rc;
|
|
if (fdo)
|
|
rc = Fclose(fdo);
|
|
}
|
|
return ec;
|
|
}
|
|
|
|
int rpmVerify(QVA_t qva, rpmQVSources source, const char * arg)
|
|
{
|
|
rpmdb rpmdb = NULL;
|
|
int rc;
|
|
|
|
switch (source) {
|
|
case RPMQV_RPM:
|
|
if (!(qva->qva_flags & VERIFY_DEPS))
|
|
break;
|
|
/*@fallthrough@*/
|
|
default:
|
|
if ((rc = rpmdbOpen(qva->qva_prefix, &rpmdb, O_RDONLY, 0644)) != 0)
|
|
return 1;
|
|
break;
|
|
}
|
|
|
|
rc = rpmQueryVerify(qva, source, arg, rpmdb, showVerifyPackage);
|
|
|
|
if (rpmdb != NULL)
|
|
(void) rpmdbClose(rpmdb);
|
|
|
|
return rc;
|
|
}
|