rpm-build/lib/depends.c

988 lines
27 KiB
C
Raw Normal View History

2002-03-25 23:16:26 +03:00
/** \ingroup rpmdep
* \file lib/depends.c
*/
#include "system.h"
#include "rpmlib.h"
#include "rpmmacro.h" /* XXX for rpmExpand() */
2002-03-25 23:16:26 +03:00
#include "depends.h"
2009-10-02 11:47:28 +04:00
#include "al.h"
#include "rpmhash.h"
2002-03-25 23:16:26 +03:00
#include "debug.h"
/*@access Header@*/ /* XXX compared with NULL */
/*@access FD_t@*/ /* XXX compared with NULL */
/*@access rpmdb@*/ /* XXX compared with NULL */
/*@access rpmdbMatchIterator@*/ /* XXX compared with NULL */
/*@access rpmTransactionSet@*/
/*@access rpmDependencyConflict@*/
/*@access availableList@*/
/*@only@*/ char * printDepend(const char * depend, const char * key,
2002-03-25 23:16:26 +03:00
const char * keyEVR, int keyFlags)
/*@*/
{
char * tbuf, * t;
size_t nb;
nb = 0;
if (depend) nb += strlen(depend) + 1;
if (key) nb += strlen(key);
if (keyFlags & RPMSENSE_SENSEMASK) {
if (nb) nb++;
if (keyFlags & RPMSENSE_LESS) nb++;
if (keyFlags & RPMSENSE_GREATER) nb++;
if (keyFlags & RPMSENSE_EQUAL) nb++;
}
if (keyEVR && *keyEVR) {
if (nb) nb++;
nb += strlen(keyEVR);
}
t = tbuf = xmalloc(nb + 1);
if (depend) {
while(*depend != '\0') *t++ = *depend++;
*t++ = ' ';
}
if (key)
while(*key != '\0') *t++ = *key++;
if (keyFlags & RPMSENSE_SENSEMASK) {
if (t != tbuf) *t++ = ' ';
if (keyFlags & RPMSENSE_LESS) *t++ = '<';
if (keyFlags & RPMSENSE_GREATER) *t++ = '>';
if (keyFlags & RPMSENSE_EQUAL) *t++ = '=';
}
if (keyEVR && *keyEVR) {
if (t != tbuf) *t++ = ' ';
while(*keyEVR != '\0') *t++ = *keyEVR++;
}
*t = '\0';
return tbuf;
}
/* parseEVR() moved to rpmvercmp.c */
2002-03-25 23:16:26 +03:00
const char *rpmNAME = PACKAGE;
const char *rpmEVR = VERSION;
int rpmFLAGS = RPMSENSE_EQUAL;
#include "set.h"
2002-03-25 23:16:26 +03:00
int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
const char * BName, const char * BEVR, int BFlags)
{
const char *aDepend = NULL;
const char *bDepend = NULL;
2002-03-25 23:16:26 +03:00
int result;
int sense;
/* Different names don't overlap. */
if (AName != BName && strcmp(AName, BName)) {
2002-03-25 23:16:26 +03:00
result = 0;
goto exit;
}
2004-01-22 14:56:33 +03:00
/* Same name. If either A or B is an existence test, always overlap. */
if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
2002-03-25 23:16:26 +03:00
result = 1;
goto exit;
}
if (!AEVR) AEVR = "";
if (!BEVR) BEVR = "";
if (*AEVR && *BEVR) {
/* equal version strings => equal versions */
if ((AFlags & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL &&
(BFlags & RPMSENSE_SENSEMASK) == RPMSENSE_EQUAL &&
strcmp(AEVR, BEVR) == 0)
{
result = 1;
goto exit;
}
}
/* something beats nothing */
else if (*AEVR) {
sense = 1;
goto sense_result;
}
else if (*BEVR) {
sense = -1 ;
goto sense_result;
}
else {
/* both EVRs are non-existent or empty, always overlap */
2002-03-25 23:16:26 +03:00
result = 1;
goto exit;
}
int aset = strncmp(AEVR, "set:", 4) == 0;
int bset = strncmp(BEVR, "set:", 4) == 0;
if (aset && bset) {
sense = rpmsetcmp(AEVR, BEVR);
if (sense < -1) {
if (sense == -3)
rpmMessage(RPMMESS_WARNING, _("failed to decode %s\n"), AEVR);
if (sense == -4)
rpmMessage(RPMMESS_WARNING, _("failed to decode %s\n"), BEVR);
/* neither is subset of each other */
result = 0;
goto exit;
}
}
else if (aset || bset) {
/* no overlap between a set and non-set */
result = 0;
goto exit;
}
else {
lib/depends.c: make rpmRangesOverlap() handle DistTag In a constraint (Requires, Conflicts), some components of E:V-R:D may be unspecified; here are the sensible possibilities: V E:V-R E:V-R:D Remember that the DistTag represents the ID of a particular build. (V represents a particular upstream version. E:V-R represents a particular source package release.) To satisfy a requirement, only the specified components must be checked. So, if the requirement doesn't specify a DistTag, then we don't have to check the DistTag to satisfy it. If the requirement does specify a DistTag, then if it is an "equals" requirement, then only the same DistTag can satisfy it. (I.e., we want that particular build.) A "less" (or "greater") requirement of a DistTag basically makes no sense, because the build IDs are not ordered. So, such a requirement cannot be satisfied, if it has come to checking the DistTag, i.e. the EVRs have been equal. (It cannot be satisfied by a package with an equal EVR and any DistTag value, but can be satisfied by a package with EVR which is strictly less or greater.) What does the last part mean for "Requires" and "Conflicts"? Requires: N>E:V-R:D would have the same effect as Requires: N>E:V-R Conflicts: N>E:V-R:D would have the same effect as Conflicts: N>E:V-R i.e., a conflict would not disallow packages with the specified E:V-R, but a different DistTag. (We can't do any better, unless there is a "not-equals" type of requirement in RPM.) Commit message author: Ivan Zakharyaschev <imz@altlinux.org> Commit is based on 6cb615d6112a2ca841481d8153ba652d512a2f23 of git://git.altlinux.org/gears/r/rpm.git (cherry picked from commit d169679410a0d02a731addb8b526ecbc8a3a56fc)
2019-01-16 22:35:19 +03:00
const char *aE, *aV, *aR, *aD, *bE, *bV, *bR, *bD;
/* Both AEVR and BEVR exist. */
lib/depends.c: make rpmRangesOverlap() handle DistTag In a constraint (Requires, Conflicts), some components of E:V-R:D may be unspecified; here are the sensible possibilities: V E:V-R E:V-R:D Remember that the DistTag represents the ID of a particular build. (V represents a particular upstream version. E:V-R represents a particular source package release.) To satisfy a requirement, only the specified components must be checked. So, if the requirement doesn't specify a DistTag, then we don't have to check the DistTag to satisfy it. If the requirement does specify a DistTag, then if it is an "equals" requirement, then only the same DistTag can satisfy it. (I.e., we want that particular build.) A "less" (or "greater") requirement of a DistTag basically makes no sense, because the build IDs are not ordered. So, such a requirement cannot be satisfied, if it has come to checking the DistTag, i.e. the EVRs have been equal. (It cannot be satisfied by a package with an equal EVR and any DistTag value, but can be satisfied by a package with EVR which is strictly less or greater.) What does the last part mean for "Requires" and "Conflicts"? Requires: N>E:V-R:D would have the same effect as Requires: N>E:V-R Conflicts: N>E:V-R:D would have the same effect as Conflicts: N>E:V-R i.e., a conflict would not disallow packages with the specified E:V-R, but a different DistTag. (We can't do any better, unless there is a "not-equals" type of requirement in RPM.) Commit message author: Ivan Zakharyaschev <imz@altlinux.org> Commit is based on 6cb615d6112a2ca841481d8153ba652d512a2f23 of git://git.altlinux.org/gears/r/rpm.git (cherry picked from commit d169679410a0d02a731addb8b526ecbc8a3a56fc)
2019-01-16 22:35:19 +03:00
parseEVRD(strdupa(AEVR), &aE, &aV, &aR, &aD);
parseEVRD(strdupa(BEVR), &bE, &bV, &bR, &bD);
/* rpmEVRcmp() is also shared; the code moved to rpmvercmp.c */
if (rpmIsDebug()) {
aDepend = printDepend(NULL, AName, AEVR, AFlags);
bDepend = printDepend(NULL, BName, BEVR, BFlags);
}
sense = rpmEVRcmp(aE, aV, aR, aDepend, bE, bV, bR, bDepend);
lib/depends.c: make rpmRangesOverlap() handle DistTag In a constraint (Requires, Conflicts), some components of E:V-R:D may be unspecified; here are the sensible possibilities: V E:V-R E:V-R:D Remember that the DistTag represents the ID of a particular build. (V represents a particular upstream version. E:V-R represents a particular source package release.) To satisfy a requirement, only the specified components must be checked. So, if the requirement doesn't specify a DistTag, then we don't have to check the DistTag to satisfy it. If the requirement does specify a DistTag, then if it is an "equals" requirement, then only the same DistTag can satisfy it. (I.e., we want that particular build.) A "less" (or "greater") requirement of a DistTag basically makes no sense, because the build IDs are not ordered. So, such a requirement cannot be satisfied, if it has come to checking the DistTag, i.e. the EVRs have been equal. (It cannot be satisfied by a package with an equal EVR and any DistTag value, but can be satisfied by a package with EVR which is strictly less or greater.) What does the last part mean for "Requires" and "Conflicts"? Requires: N>E:V-R:D would have the same effect as Requires: N>E:V-R Conflicts: N>E:V-R:D would have the same effect as Conflicts: N>E:V-R i.e., a conflict would not disallow packages with the specified E:V-R, but a different DistTag. (We can't do any better, unless there is a "not-equals" type of requirement in RPM.) Commit message author: Ivan Zakharyaschev <imz@altlinux.org> Commit is based on 6cb615d6112a2ca841481d8153ba652d512a2f23 of git://git.altlinux.org/gears/r/rpm.git (cherry picked from commit d169679410a0d02a731addb8b526ecbc8a3a56fc)
2019-01-16 22:35:19 +03:00
/* We can't merge the DistTag comparison into rpmEVRcmp(), because
rpmEVRcmp() doesn't have a return code for incomparable things.
That's similar to set comparison which is done in this function.
*/
if (sense == 0) {
if (bD && *bD) {
/* (Remember: we are in the case when the EVR components
are equal.) We might detect equal DistTags here.
If not, since DistTags have no order, there is
no possibility here that one thing will be less or greater
than the other; the result is "incomparable".
*/
if (aD && *aD && strcmp(aD, bD) == 0)
sense = 0;
else {
result = 0;
goto exit;
}
} else if (aD && *aD) {
/* Support for underspecification on the side of Requires/Conflicts */
rpmMessage(RPMMESS_DEBUG, _("the \"B\" dependency doesn't specify a disttag, letting it match any in \"A\"\n\tA %s\tB %s\n"),
aDepend, bDepend);
sense = 0;
}
}
}
2002-03-25 23:16:26 +03:00
sense_result:
2002-03-25 23:16:26 +03:00
/* Detect overlap of {A,B} range. */
result = 0;
if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
result = 1;
} else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
result = 1;
} else if (sense == 0 &&
(((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
result = 1;
}
exit:
if (rpmIsDebug()) {
if (!aDepend)
aDepend = printDepend(NULL, AName, AEVR, AFlags);
if (!bDepend)
bDepend = printDepend(NULL, BName, BEVR, BFlags);
rpmMessage(RPMMESS_DEBUG, _(" %s A %s\tB %s\n"),
(result ? _("YES") : _("NO ")), aDepend, bDepend);
aDepend = _free(aDepend);
bDepend = _free(bDepend);
}
2002-03-25 23:16:26 +03:00
return result;
}
/*@-typeuse@*/
typedef int (*dbrecMatch_t) (Header h, const char *reqName, const char * reqEVR, int reqFlags);
/*@=typeuse@*/
static int rangeMatchesDepFlags (Header h,
const char * reqName, const char * reqEVR, int reqFlags)
/*@*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType pnt, pvt;
const char ** provides;
const char ** providesEVR;
int_32 * provideFlags;
int providesCount;
int result;
int i;
if (!(reqFlags & RPMSENSE_SENSEMASK) || !reqEVR || !strlen(reqEVR))
return 1;
/* Get provides information from header */
/*
* Rpm prior to 3.0.3 does not have versioned provides.
* If no provides version info is available, match any requires.
*/
if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt,
(void **) &providesEVR, &providesCount))
return 1;
(void) hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
{
providesEVR = hfd(providesEVR, pvt);
return 0; /* XXX should never happen */
}
result = 0;
for (i = 0; i < providesCount; i++) {
/* Filter out provides that came along for the ride. */
if (strcmp(provides[i], reqName))
continue;
if (!(provideFlags[i] & RPMSENSE_SENSEMASK))
provideFlags[i] |= RPMSENSE_EQUAL; /* ALT21-139-g6cb9a9a */
2002-03-25 23:16:26 +03:00
result = rpmRangesOverlap(provides[i], providesEVR[i], provideFlags[i],
reqName, reqEVR, reqFlags);
/* If this provide matches the require, we're done. */
if (result)
break;
}
provides = hfd(provides, pnt);
providesEVR = hfd(providesEVR, pvt);
return result;
}
int headerMatchesDepFlags(Header h,
const char * reqName, const char * reqEVR, int reqFlags)
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
const char *name, *version, *release, *disttag;
2002-03-25 23:16:26 +03:00
int_32 * epoch;
const char *pkgEVR;
char *p;
int pkgFlags = RPMSENSE_EQUAL;
if (!((reqFlags & RPMSENSE_SENSEMASK) && reqEVR && *reqEVR))
return 1;
/* Get package information from header */
(void) headerNVRD(h, &name, &version, &release, &disttag);
2002-03-25 23:16:26 +03:00
pkgEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1
+ (disttag ? strlen(disttag) + 1 : 0));
2002-03-25 23:16:26 +03:00
*p = '\0';
if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
sprintf(p, "%d:", *epoch);
while (*p != '\0')
p++;
}
p = stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
if (disttag)
(void) stpcpy( stpcpy(p , ":") , disttag);
2002-03-25 23:16:26 +03:00
return rpmRangesOverlap(name, pkgEVR, pkgFlags, reqName, reqEVR, reqFlags);
}
rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir)
{
rpmTransactionSet ts;
int rootLen;
if (!rootDir) rootDir = "";
ts = xcalloc(1, sizeof(*ts));
ts->filesystemCount = 0;
ts->filesystems = NULL;
ts->di = NULL;
/*@-assignexpose@*/
ts->rpmdb = rpmdb;
/*@=assignexpose@*/
ts->scriptFd = NULL;
ts->id = 0;
ts->numRemovedPackages = 0;
ts->removedPackages = NULL;
2002-03-25 23:16:26 +03:00
/* This canonicalizes the root */
rootLen = strlen(rootDir);
if (!(rootLen && rootDir[rootLen - 1] == '/')) {
char * t;
t = alloca(rootLen + 2);
*t = '\0';
(void) stpcpy( stpcpy(t, rootDir), "/");
rootDir = t;
}
ts->rootDir = xstrdup(rootDir);
ts->currDir = NULL;
ts->chrootDone = 0;
alCreate(&ts->addedPackages);
alCreate(&ts->erasedPackages);
2002-03-25 23:16:26 +03:00
ts->orderCount = 0;
ts->order = NULL;
2002-03-25 23:16:26 +03:00
ts->selinuxEnabled = is_selinux_enabled() > 0;
2002-03-25 23:16:26 +03:00
return ts;
}
/**
* Compare removed package instances (qsort/bsearch).
* @param a 1st instance address
* @param b 2nd instance address
* @return result of comparison
*/
static int intcmp(const void * a, const void * b) /*@*/
{
const int * aptr = a;
const int * bptr = b;
int rc = (*aptr - *bptr);
return rc;
}
/**
* Add removed package instance to ordered transaction set.
* @param ts transaction set
* @param dboffset rpm database instance
* @param depends installed package of pair (or -1 on erase)
* @return 0 on success
*/
static int removePackage(rpmTransactionSet ts, int dboffset, int depends)
/*@modifies ts @*/
{
/* Filter out duplicate erasures. */
if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
sizeof(int), intcmp) != NULL)
return 0;
}
/* Fetch header. */
rpmdbMatchIterator mi = rpmdbInitIterator(ts->rpmdb,
RPMDBI_PACKAGES, &dboffset, sizeof(dboffset));
Header h = rpmdbNextIterator(mi);
if (h)
h = headerLink(h);
mi = rpmdbFreeIterator(mi);
if (h == NULL)
return 1;
struct availablePackage *alp =
alAddPackage(&ts->erasedPackages, h, NULL, NULL, NULL);
int alNum = alp - ts->erasedPackages.list;
AUTO_REALLOC(ts->removedPackages, ts->numRemovedPackages, 8);
ts->removedPackages[ts->numRemovedPackages++] = dboffset;
qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp);
2002-03-25 23:16:26 +03:00
AUTO_REALLOC(ts->order, ts->orderCount, 8);
transactionElement te = &ts->order[ts->orderCount++];
te->type = TR_REMOVED;
te->u.removed.dboffset = dboffset;
te->u.removed.dependsOnIndex = depends;
te->u.removed.erasedIndex = alNum;
2002-03-25 23:16:26 +03:00
return 0;
}
static int rpmDigestCompare(Header first, Header second)
{
const char * one, * two;
if (!headerGetEntry(first, RPMTAG_SHA1HEADER, NULL, (void **) &one, NULL))
one = NULL;
if (!headerGetEntry(second, RPMTAG_SHA1HEADER, NULL, (void **) &two, NULL))
two = NULL;
if (one && two)
return strcmp(one, two);
if (one && !two)
return 1;
if (!one && two)
return -1;
return 0;
}
2002-03-25 23:16:26 +03:00
int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
const void * key, int upgrade, rpmRelocation * relocs)
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType ont, ovt;
/* this is an install followed by uninstalls */
const char * name;
int count;
const char ** obsoletes;
/*
* FIXME: handling upgrades like this is *almost* okay. It doesn't
* check to make sure we're upgrading to a newer version, and it
* makes it difficult to generate a return code based on the number of
* packages which failed.
*/
struct availablePackage *alp =
alAddPackage(&ts->addedPackages, h, key, fd, relocs);
int alNum = alp - ts->addedPackages.list;
AUTO_REALLOC(ts->order, ts->orderCount, 8);
ts->order[ts->orderCount].type = TR_ADDED;
2002-03-25 23:16:26 +03:00
ts->order[ts->orderCount++].u.addedIndex = alNum;
if (!upgrade || ts->rpmdb == NULL)
return 0;
/* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
return 0;
(void) headerName(h, &name);
2002-03-25 23:16:26 +03:00
{ rpmdbMatchIterator mi;
Header h2;
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
while((h2 = rpmdbNextIterator(mi)) != NULL) {
if (rpmDigestCompare(h, h2) || rpmVersionCompare(h, h2))
2002-03-25 23:16:26 +03:00
(void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
}
mi = rpmdbFreeIterator(mi);
}
if (hge(h, RPMTAG_OBSOLETENAME, &ont, (void **) &obsoletes, &count)) {
const char ** obsoletesEVR;
int_32 * obsoletesFlags;
int j;
(void) hge(h, RPMTAG_OBSOLETEVERSION, &ovt, (void **) &obsoletesEVR,
NULL);
(void) hge(h, RPMTAG_OBSOLETEFLAGS, NULL, (void **) &obsoletesFlags,
NULL);
for (j = 0; j < count; j++) {
/* XXX avoid self-obsoleting packages. */
if (!strcmp(name, obsoletes[j]))
continue;
{ rpmdbMatchIterator mi;
Header h2;
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, obsoletes[j], 0);
(void) rpmdbPruneIterator(mi,
ts->removedPackages, ts->numRemovedPackages, 1);
while((h2 = rpmdbNextIterator(mi)) != NULL) {
/*
* Rpm prior to 3.0.3 does not have versioned obsoletes.
* If no obsoletes version info is available, match all names.
*/
if (obsoletesEVR == NULL ||
headerMatchesDepFlags(h2,
obsoletes[j], obsoletesEVR[j], obsoletesFlags[j]))
{
(void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
}
}
mi = rpmdbFreeIterator(mi);
}
}
obsoletesEVR = hfd(obsoletesEVR, ovt);
obsoletes = hfd(obsoletes, ont);
}
return 0;
}
int rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
{
return removePackage(ts, dboffset, -1);
}
rpmTransactionSet rpmtransFree(rpmTransactionSet ts)
{
if (ts) {
alFree(&ts->addedPackages);
alFree(&ts->erasedPackages);
2002-03-25 23:16:26 +03:00
ts->di = _free(ts->di);
ts->removedPackages = _free(ts->removedPackages);
ts->order = _free(ts->order);
if (ts->scriptFd != NULL)
ts->scriptFd =
fdFree(ts->scriptFd, "rpmtransSetScriptFd (rpmtransFree");
ts->rootDir = _free(ts->rootDir);
ts->currDir = _free(ts->currDir);
ts = _free(ts);
}
return NULL;
}
rpmDependencyConflict rpmdepFreeConflicts(rpmDependencyConflict conflicts,
int numConflicts)
{
int i;
if (conflicts)
for (i = 0; i < numConflicts; i++) {
conflicts[i].byHeader = headerFree(conflicts[i].byHeader);
conflicts[i].byName = _free(conflicts[i].byName);
conflicts[i].byVersion = _free(conflicts[i].byVersion);
conflicts[i].byRelease = _free(conflicts[i].byRelease);
conflicts[i].needsName = _free(conflicts[i].needsName);
conflicts[i].needsVersion = _free(conflicts[i].needsVersion);
}
return (conflicts = _free(conflicts));
}
static __thread
hashTable dbProvCache;
/* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
static
int dbSatisfiesDepend(rpmTransactionSet ts,
const char * keyName, const char * keyEVR, int keyFlags)
{
rpmdbMatchIterator mi;
Header h;
int rc = 1;
depends.c: provided actual dbProvCache implementation Based on rpm.org 2e76d0e6 by Panu Matilainen: > Add in-memory hash for caching rpmdb dependency lookups > - worst case behavior for uncached dependency lookups can be disastrous, > eg > 35s vs < 1s on my laptop for trying to remove /bin/sh provider > - we only bother caching rpmdb lookups, the other cases plenty fast already > - using in-memory cache avoids nasty in vs out of chroot issues with > temporary db files, which otherwise were about as fast However, we do not use full-blown printDepend-based caching (i.e. we no longer cache depends with versions). This is because, well, dependency versions are likely to differ. This is especially true if we consider upcoming set-versions for soname symbols - hashing symbol sets here will be just a waste of time and memory. And so now we cache satisfied/unsatisfied depends by just name. Thus, "yes" hit can be used immediately only for unversioned dependences. Top 10 dependencies which will be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -v = |sort |uniq -c |sort -n |tail 245 /usr/lib/perl5/vendor_perl 311 libm.so.6(GLIBC_2.2.5)(64bit) 386 libpthread.so.0(GLIBC_2.2.5)(64bit) 454 /lib64/ld-linux-x86-64.so.2 548 libc.so.6(GLIBC_2.3)(64bit) 587 /bin/sh 828 libc.so.6(GLIBC_2.3.4)(64bit) 906 libc.so.6(GLIBC_2.4)(64bit) 1128 rtld(GNU_HASH) 1140 libc.so.6(GLIBC_2.2.5)(64bit) $ Top 10 dependencies which will not be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -e = |sort |uniq -c |sort -n |tail 13 python-base = 2.6.5-alt2 14 mono(mscorlib) = 1.0 15 qt4-common = 4.6.2-alt6 16 mono(mscorlib) = 2.0 18 mktemp >= 1:1.3.1 20 koffice-common = 4:2.2.0-alt2 20 perl-base >= 1:5.8.0 23 alternatives >= 0:0.4 49 libqt4-core >= 4.6.2 54 perl-base >= 1:5.6.0 $ Here's a simple test to see if the cache works (using Panu's example - trying to remove /bin/sh). (before this change) $ time LD_LIBRARY_PATH=$PWD/1 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 6.18s user 3.44s system 94% cpu 10.182 total $ (after this change) $ time LD_LIBRARY_PATH=$PWD/2 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 0.11s user 0.09s system 91% cpu 0.218 total $
2010-07-05 23:31:58 +04:00
/* Lookup dbProvCache by keyName. */
const void ** cacheData = NULL;
if (htGetEntry(dbProvCache, keyName, &cacheData, NULL, NULL) == 0) {
if (*cacheData == NULL)
/* cache value is NULL (for "no"), the dependency is not satisfied */
return 1;
if ((keyFlags & RPMSENSE_SENSEMASK) == 0)
/* cache value is "yes", unversioned dependency is satisfied */
return 0;
}
if (*keyName == '/' && (keyFlags & RPMSENSE_SENSEMASK) == 0) {
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_BASENAMES, keyName, 0);
rpmdbPruneIterator(mi, ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
rc = 0;
break;
}
mi = rpmdbFreeIterator(mi);
}
if (rc == 1) {
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_PROVIDENAME, keyName, 0);
rpmdbPruneIterator(mi, ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
rc = 0;
break;
}
depends.c: provided actual dbProvCache implementation Based on rpm.org 2e76d0e6 by Panu Matilainen: > Add in-memory hash for caching rpmdb dependency lookups > - worst case behavior for uncached dependency lookups can be disastrous, > eg > 35s vs < 1s on my laptop for trying to remove /bin/sh provider > - we only bother caching rpmdb lookups, the other cases plenty fast already > - using in-memory cache avoids nasty in vs out of chroot issues with > temporary db files, which otherwise were about as fast However, we do not use full-blown printDepend-based caching (i.e. we no longer cache depends with versions). This is because, well, dependency versions are likely to differ. This is especially true if we consider upcoming set-versions for soname symbols - hashing symbol sets here will be just a waste of time and memory. And so now we cache satisfied/unsatisfied depends by just name. Thus, "yes" hit can be used immediately only for unversioned dependences. Top 10 dependencies which will be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -v = |sort |uniq -c |sort -n |tail 245 /usr/lib/perl5/vendor_perl 311 libm.so.6(GLIBC_2.2.5)(64bit) 386 libpthread.so.0(GLIBC_2.2.5)(64bit) 454 /lib64/ld-linux-x86-64.so.2 548 libc.so.6(GLIBC_2.3)(64bit) 587 /bin/sh 828 libc.so.6(GLIBC_2.3.4)(64bit) 906 libc.so.6(GLIBC_2.4)(64bit) 1128 rtld(GNU_HASH) 1140 libc.so.6(GLIBC_2.2.5)(64bit) $ Top 10 dependencies which will not be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -e = |sort |uniq -c |sort -n |tail 13 python-base = 2.6.5-alt2 14 mono(mscorlib) = 1.0 15 qt4-common = 4.6.2-alt6 16 mono(mscorlib) = 2.0 18 mktemp >= 1:1.3.1 20 koffice-common = 4:2.2.0-alt2 20 perl-base >= 1:5.8.0 23 alternatives >= 0:0.4 49 libqt4-core >= 4.6.2 54 perl-base >= 1:5.6.0 $ Here's a simple test to see if the cache works (using Panu's example - trying to remove /bin/sh). (before this change) $ time LD_LIBRARY_PATH=$PWD/1 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 6.18s user 3.44s system 94% cpu 10.182 total $ (after this change) $ time LD_LIBRARY_PATH=$PWD/2 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 0.11s user 0.09s system 91% cpu 0.218 total $
2010-07-05 23:31:58 +04:00
else {
/* version did not match */
rc = -1;
}
}
mi = rpmdbFreeIterator(mi);
}
depends.c: provided actual dbProvCache implementation Based on rpm.org 2e76d0e6 by Panu Matilainen: > Add in-memory hash for caching rpmdb dependency lookups > - worst case behavior for uncached dependency lookups can be disastrous, > eg > 35s vs < 1s on my laptop for trying to remove /bin/sh provider > - we only bother caching rpmdb lookups, the other cases plenty fast already > - using in-memory cache avoids nasty in vs out of chroot issues with > temporary db files, which otherwise were about as fast However, we do not use full-blown printDepend-based caching (i.e. we no longer cache depends with versions). This is because, well, dependency versions are likely to differ. This is especially true if we consider upcoming set-versions for soname symbols - hashing symbol sets here will be just a waste of time and memory. And so now we cache satisfied/unsatisfied depends by just name. Thus, "yes" hit can be used immediately only for unversioned dependences. Top 10 dependencies which will be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -v = |sort |uniq -c |sort -n |tail 245 /usr/lib/perl5/vendor_perl 311 libm.so.6(GLIBC_2.2.5)(64bit) 386 libpthread.so.0(GLIBC_2.2.5)(64bit) 454 /lib64/ld-linux-x86-64.so.2 548 libc.so.6(GLIBC_2.3)(64bit) 587 /bin/sh 828 libc.so.6(GLIBC_2.3.4)(64bit) 906 libc.so.6(GLIBC_2.4)(64bit) 1128 rtld(GNU_HASH) 1140 libc.so.6(GLIBC_2.2.5)(64bit) $ Top 10 dependencies which will not be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -e = |sort |uniq -c |sort -n |tail 13 python-base = 2.6.5-alt2 14 mono(mscorlib) = 1.0 15 qt4-common = 4.6.2-alt6 16 mono(mscorlib) = 2.0 18 mktemp >= 1:1.3.1 20 koffice-common = 4:2.2.0-alt2 20 perl-base >= 1:5.8.0 23 alternatives >= 0:0.4 49 libqt4-core >= 4.6.2 54 perl-base >= 1:5.6.0 $ Here's a simple test to see if the cache works (using Panu's example - trying to remove /bin/sh). (before this change) $ time LD_LIBRARY_PATH=$PWD/1 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 6.18s user 3.44s system 94% cpu 10.182 total $ (after this change) $ time LD_LIBRARY_PATH=$PWD/2 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 0.11s user 0.09s system 91% cpu 0.218 total $
2010-07-05 23:31:58 +04:00
/* Update dbProvCache.
* When versions did not match, it is still okay to say "yes" for the name. */
if (cacheData == NULL)
/* XXX keyName points to header memory, no need for strdup */
htAddEntry(dbProvCache, keyName, rc < 1 ? "yes" : NULL);
depends.c: provided actual dbProvCache implementation Based on rpm.org 2e76d0e6 by Panu Matilainen: > Add in-memory hash for caching rpmdb dependency lookups > - worst case behavior for uncached dependency lookups can be disastrous, > eg > 35s vs < 1s on my laptop for trying to remove /bin/sh provider > - we only bother caching rpmdb lookups, the other cases plenty fast already > - using in-memory cache avoids nasty in vs out of chroot issues with > temporary db files, which otherwise were about as fast However, we do not use full-blown printDepend-based caching (i.e. we no longer cache depends with versions). This is because, well, dependency versions are likely to differ. This is especially true if we consider upcoming set-versions for soname symbols - hashing symbol sets here will be just a waste of time and memory. And so now we cache satisfied/unsatisfied depends by just name. Thus, "yes" hit can be used immediately only for unversioned dependences. Top 10 dependencies which will be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -v = |sort |uniq -c |sort -n |tail 245 /usr/lib/perl5/vendor_perl 311 libm.so.6(GLIBC_2.2.5)(64bit) 386 libpthread.so.0(GLIBC_2.2.5)(64bit) 454 /lib64/ld-linux-x86-64.so.2 548 libc.so.6(GLIBC_2.3)(64bit) 587 /bin/sh 828 libc.so.6(GLIBC_2.3.4)(64bit) 906 libc.so.6(GLIBC_2.4)(64bit) 1128 rtld(GNU_HASH) 1140 libc.so.6(GLIBC_2.2.5)(64bit) $ Top 10 dependencies which will not be handled by the cache: $ rpm -qaR |grep -v rpmlib |grep -e = |sort |uniq -c |sort -n |tail 13 python-base = 2.6.5-alt2 14 mono(mscorlib) = 1.0 15 qt4-common = 4.6.2-alt6 16 mono(mscorlib) = 2.0 18 mktemp >= 1:1.3.1 20 koffice-common = 4:2.2.0-alt2 20 perl-base >= 1:5.8.0 23 alternatives >= 0:0.4 49 libqt4-core >= 4.6.2 54 perl-base >= 1:5.6.0 $ Here's a simple test to see if the cache works (using Panu's example - trying to remove /bin/sh). (before this change) $ time LD_LIBRARY_PATH=$PWD/1 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 6.18s user 3.44s system 94% cpu 10.182 total $ (after this change) $ time LD_LIBRARY_PATH=$PWD/2 rpm -e --test sh 2>&1 |tail /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by groff-base-1.20.1-alt0.20091013 /bin/sh is needed by libgnome-sharp-2.24.1-alt1 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kernel-image-std-def-2.6.32-alt15 /bin/sh is needed by kde4libs-4.4.5-alt1 /bin/sh is needed by kde4base-runtime-core-4.4.5-alt1 /bin/sh is needed by kde4base-konqueror-4.4.5-alt1 /usr/lib/bash is needed by bash-builtin-lockf-0.3.1-alt1 rpm -e --test sh 2>&1 0.11s user 0.09s system 91% cpu 0.218 total $
2010-07-05 23:31:58 +04:00
return rc ? 1 : 0;
}
2002-03-25 23:16:26 +03:00
/**
* Check key for an unsatisfied dependency.
* @todo Eliminate rpmrc provides.
* @param ts transaction set
* @param h header the dependency comes from
* @param tag RPMTAG_REQUIRENAME, PROVIDENAME or OBSOLETENAME
2002-03-25 23:16:26 +03:00
* @param keyDepend dependency string representation
* @param keyName dependency name string
* @param keyEVR dependency [epoch:]version[-release] string
* @param keyFlags dependency logical range qualifiers
* @return 0 if satisfied, 1 if not satisfied, 2 if error
*/
static int tsSatisfiesDepend(rpmTransactionSet ts,
Header h, rpmTag tag, const char * keyDepend,
const char * keyName, const char * keyEVR, int keyFlags)
/*@modifies ts @*/
2002-03-25 23:16:26 +03:00
{
const char *keyType;
switch (tag) {
case RPMTAG_REQUIRENAME:
keyType = " Requires";
break;
case RPMTAG_CONFLICTNAME:
keyType = " Conflicts";
break;
default:
assert(tag == RPMTAG_OBSOLETENAME);
keyType = " Obsoletes";
break;
}
2002-03-25 23:16:26 +03:00
/*
* New features in rpm packaging implicitly add versioned dependencies
* on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
* Check those dependencies now.
*/
if (!strncmp(keyName, "rpmlib(", sizeof("rpmlib(")-1)) {
if (rpmCheckRpmlibProvides(keyName, keyEVR, keyFlags)) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmlib provides)\n"),
keyType, keyDepend+2);
return 0;
2002-03-25 23:16:26 +03:00
}
goto unsatisfied;
}
struct availablePackage **all =
alAllSatisfiesDepend(&ts->addedPackages, keyName, keyEVR, keyFlags);
if (all) {
int ret = 1;
if (tag == RPMTAG_REQUIRENAME)
ret = 0;
else {
struct availablePackage **alpp;
for (alpp = all; *alpp; alpp++) {
// Conflicts are Obsoletes do not self match.
if ((*alpp)->h == h)
continue;
// Obsoletes match only against packags names, not Provides.
if (tag == RPMTAG_OBSOLETENAME && strcmp((*alpp)->name, keyName))
continue;
ret = 0;
break;
}
}
all = _free(all);
if (ret == 0) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provides)\n"),
keyType, keyDepend+2);
return 0;
}
2002-03-25 23:16:26 +03:00
}
if (dbSatisfiesDepend(ts, keyName, keyEVR, keyFlags) == 0) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmdb provides)\n"),
2002-03-25 23:16:26 +03:00
keyType, keyDepend+2);
return 0;
2002-03-25 23:16:26 +03:00
}
unsatisfied:
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s NO\n"), keyType, keyDepend+2);
return 1;
2002-03-25 23:16:26 +03:00
}
/**
* Check header requires/conflicts against against installed+added packages.
* @param ts transaction set
* @param psp dependency problems
* @param h header to check
* @param keyName dependency name
* @return 0 no problems found
*/
static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp,
2009-03-10 14:27:38 +03:00
Header h, const char * keyName)
2002-03-25 23:16:26 +03:00
/*@modifies ts, h, psp */
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType rnt, rvt;
rpmTagType cnt, cvt;
const char * name, * version, * release;
const char ** requires;
const char ** requiresEVR = NULL;
int_32 * requireFlags = NULL;
int requiresCount = 0;
const char ** conflicts;
const char ** conflictsEVR = NULL;
int_32 * conflictFlags = NULL;
int conflictsCount = 0;
rpmTagType type;
int i, rc;
int ourrc = 0;
/* FIXME: There is no psp->problems->byDisttag. We don't need it for now. */
(void) headerNVRD(h, &name, &version, &release, NULL);
2002-03-25 23:16:26 +03:00
if (!hge(h, RPMTAG_REQUIRENAME, &rnt, (void **) &requires, &requiresCount))
{
requiresCount = 0;
rvt = RPM_STRING_ARRAY_TYPE;
} else {
(void)hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **) &requireFlags, NULL);
(void)hge(h, RPMTAG_REQUIREVERSION, &rvt, (void **) &requiresEVR, NULL);
}
for (i = 0; i < requiresCount && !ourrc; i++) {
const char * keyDepend;
/* Filter out requires that came along for the ride. */
if (keyName && strcmp(keyName, requires[i]))
continue;
keyDepend = printDepend("R",
requires[i], requiresEVR[i], requireFlags[i]);
rc = tsSatisfiesDepend(ts, h, RPMTAG_REQUIRENAME, keyDepend,
keyName ?: requires[i], // points to added/erased header memory
requiresEVR[i], requireFlags[i]);
2002-03-25 23:16:26 +03:00
switch (rc) {
case 0: /* requirements are satisfied. */
break;
case 1: /* requirements are not satisfied. */
rpmMessage(RPMMESS_DEBUG, _("package %s-%s-%s require not satisfied: %s\n"),
name, version, release, keyDepend+2);
AUTO_REALLOC(psp->problems, psp->num, 8);
2002-03-25 23:16:26 +03:00
{ rpmDependencyConflict pp = psp->problems + psp->num;
pp->byHeader = headerLink(h);
pp->byName = xstrdup(name);
pp->byVersion = xstrdup(version);
pp->byRelease = xstrdup(release);
pp->needsName = xstrdup(requires[i]);
pp->needsVersion = xstrdup(requiresEVR[i]);
pp->needsFlags = requireFlags[i];
pp->sense = RPMDEP_SENSE_REQUIRES;
}
psp->num++;
break;
case 2: /* something went wrong! */
default:
ourrc = 1;
break;
}
keyDepend = _free(keyDepend);
}
if (requiresCount) {
requiresEVR = hfd(requiresEVR, rvt);
requires = hfd(requires, rnt);
}
if (!hge(h, RPMTAG_CONFLICTNAME, &cnt, (void **)&conflicts, &conflictsCount))
{
conflictsCount = 0;
cvt = RPM_STRING_ARRAY_TYPE;
} else {
(void) hge(h, RPMTAG_CONFLICTFLAGS, &type,
(void **) &conflictFlags, &conflictsCount);
(void) hge(h, RPMTAG_CONFLICTVERSION, &cvt,
(void **) &conflictsEVR, &conflictsCount);
}
for (i = 0; i < conflictsCount && !ourrc; i++) {
const char * keyDepend;
/* Filter out conflicts that came along for the ride. */
if (keyName && strcmp(keyName, conflicts[i]))
continue;
keyDepend = printDepend("C", conflicts[i], conflictsEVR[i], conflictFlags[i]);
rc = tsSatisfiesDepend(ts, h, RPMTAG_CONFLICTNAME, keyDepend,
keyName ?: conflicts[i], // points to added/erased header memory
conflictsEVR[i], conflictFlags[i]);
2002-03-25 23:16:26 +03:00
/* 1 == unsatisfied, 0 == satsisfied */
switch (rc) {
case 0: /* conflicts exist. */
rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"),
name, keyDepend+2);
AUTO_REALLOC(psp->problems, psp->num, 8);
2002-03-25 23:16:26 +03:00
{ rpmDependencyConflict pp = psp->problems + psp->num;
pp->byHeader = headerLink(h);
pp->byName = xstrdup(name);
pp->byVersion = xstrdup(version);
pp->byRelease = xstrdup(release);
pp->needsName = xstrdup(conflicts[i]);
pp->needsVersion = xstrdup(conflictsEVR[i]);
pp->needsFlags = conflictFlags[i];
pp->sense = RPMDEP_SENSE_CONFLICTS;
}
psp->num++;
break;
case 1: /* conflicts don't exist. */
break;
case 2: /* something went wrong! */
default:
ourrc = 1;
break;
}
keyDepend = _free(keyDepend);
}
if (conflictsCount) {
conflictsEVR = hfd(conflictsEVR, cvt);
conflicts = hfd(conflicts, cnt);
}
return ourrc;
}
/**
* Erasing: check provides key against tag (requires or conflicts) matches.
2002-03-25 23:16:26 +03:00
* @param ts transaction set
* @param psp dependency problems
* @param tag RPMTAG_REQUIRENAME or RPMTAG_CONFLICTNAME
* @param key requires name
2002-03-25 23:16:26 +03:00
* @return 0 no problems found
*/
static int checkDependent(rpmTransactionSet ts, problemsSet psp,
rpmTag tag, const char * key)
/*@modifies ts, psp @*/
2002-03-25 23:16:26 +03:00
{
rpmdbMatchIterator mi = rpmdbInitIterator(ts->rpmdb, tag, key, 0);
rpmdbPruneIterator(mi, ts->removedPackages, ts->numRemovedPackages, 1);
2002-03-25 23:16:26 +03:00
Header h;
int rc = 0;
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (checkPackageDeps(ts, psp, h, key)) {
2002-03-25 23:16:26 +03:00
rc = 1;
break;
}
}
mi = rpmdbFreeIterator(mi);
return rc;
}
int rpmdepCheck(rpmTransactionSet ts,
rpmDependencyConflict * conflicts, int * numConflicts)
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
struct availablePackage * p;
problemsSet ps;
int i, j;
int rc = 0;
2002-03-25 23:16:26 +03:00
ps = xcalloc(1, sizeof(*ps));
ps->num = 0;
ps->problems = NULL;
2002-03-25 23:16:26 +03:00
*conflicts = NULL;
*numConflicts = 0;
/* XXX figure some kind of heuristic for the cache size */
dbProvCache = htCreate(1024, hashFunctionString, hashEqualityString);
2002-03-25 23:16:26 +03:00
/*
* Look at all of the added packages and make sure their dependencies
* are satisfied.
*/
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < ts->addedPackages.size; i++, p++)
2002-03-25 23:16:26 +03:00
{
rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n" ,
p->name, p->version, p->release);
rc = checkPackageDeps(ts, ps, p->h, NULL);
2002-03-25 23:16:26 +03:00
if (rc)
goto exit;
for (j = 0; j < p->providesCount; j++) {
/* Adding: check provides key against conflicts matches. */
if (!checkDependent(ts, ps, RPMTAG_CONFLICTNAME, p->provides[j]))
2002-03-25 23:16:26 +03:00
continue;
rc = 1;
/*@innerbreak@*/ break;
}
if (rc)
goto exit;
}
/*
* Look at the removed packages and make sure they aren't critical.
*/
if ((p = ts->erasedPackages.list) != NULL)
for (i = 0; i < ts->erasedPackages.size; i++, p++)
{
rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n" ,
p->name, p->version, p->release);
for (j = 0; j < p->providesCount; j++) {
/* Erasing: check provides against requiredby matches. */
if (!checkDependent(ts, ps, RPMTAG_REQUIRENAME, p->provides[j]))
continue;
rc = 1;
/*@innerbreak@*/ break;
2002-03-25 23:16:26 +03:00
}
{ const char ** baseNames, ** dirNames;
int_32 * dirIndexes;
rpmTagType dnt, bnt;
int fileCount;
char * fileName = NULL;
int fileAlloced = 0;
int len;
Header h = p->h;
2002-03-25 23:16:26 +03:00
if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
{
(void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
(void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes,
NULL);
for (j = 0; j < fileCount; j++) {
len = strlen(baseNames[j]) + 1 +
strlen(dirNames[dirIndexes[j]]);
if (len > fileAlloced) {
fileAlloced = len * 2;
fileName = xrealloc(fileName, fileAlloced);
}
*fileName = '\0';
(void) stpcpy( stpcpy(fileName, dirNames[dirIndexes[j]]) , baseNames[j]);
/* Erasing: check filename against requiredby matches. */
if (!checkDependent(ts, ps, RPMTAG_REQUIRENAME, fileName))
2002-03-25 23:16:26 +03:00
continue;
rc = 1;
/*@innerbreak@*/ break;
}
fileName = _free(fileName);
baseNames = hfd(baseNames, bnt);
dirNames = hfd(dirNames, dnt);
if (rc)
goto exit;
}
}
}
if (ps->num) {
*conflicts = ps->problems;
ps->problems = NULL;
*numConflicts = ps->num;
}
rc = 0;
exit:
ps->problems = _free(ps->problems);
ps = _free(ps);
dbProvCache = htFree(dbProvCache, NULL, NULL);
2002-03-25 23:16:26 +03:00
return rc;
}