rpm-build/lib/depends.c

2358 lines
63 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"
#include "rpmdb.h" /* XXX response cache needs dbiOpen et al. */
#include "debug.h"
/*@access dbiIndex@*/ /* XXX compared with NULL */
/*@access dbiIndexSet@*/ /* XXX compared with NULL */
/*@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@*/
static int _cacheDependsRC = 1;
int headerNVR(Header h, const char **np, const char **vp, const char **rp)
{
int type;
int count;
if (np) {
if (!(headerGetEntry(h, RPMTAG_NAME, &type, (void **) np, &count)
&& type == RPM_STRING_TYPE && count == 1))
*np = NULL;
}
if (vp) {
if (!(headerGetEntry(h, RPMTAG_VERSION, &type, (void **) vp, &count)
&& type == RPM_STRING_TYPE && count == 1))
*vp = NULL;
}
if (rp) {
if (!(headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) rp, &count)
&& type == RPM_STRING_TYPE && count == 1))
*rp = NULL;
}
return 0;
}
/**
* Return formatted dependency string.
* @param depend type of dependency ("R" == Requires, "C" == Conflcts)
* @param key dependency name string
* @param keyEVR dependency [epoch:]version[-release] string
* @param keyFlags dependency logical range qualifiers
* @return formatted dependency (malloc'ed)
*/
static /*@only@*/ char * printDepend(const char * depend, const char * key,
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;
}
#ifdef UNUSED
static /*@only@*/ const char *buildEVR(int_32 *e, const char *v, const char *r)
{
const char *pEVR;
char *p;
pEVR = p = xmalloc(21 + strlen(v) + 1 + strlen(r) + 1);
*p = '\0';
if (e) {
sprintf(p, "%d:", *e);
while (*p)
p++;
}
(void) stpcpy( stpcpy( stpcpy(p, v) , "-") , r);
return pEVR;
}
#endif
struct orderListIndex {
int alIndex;
int orIndex;
};
/**
* Destroy available item index.
* @param al available list
*/
static void alFreeIndex(availableList al)
/*@modifies al @*/
{
if (al->index.size) {
al->index.index = _free(al->index.index);
al->index.size = 0;
}
}
/**
* Initialize available packckages, items, and directories list.
* @param al available list
*/
static void alCreate(availableList al)
/*@modifies al @*/
{
al->alloced = al->delta;
al->size = 0;
al->list = xcalloc(al->alloced, sizeof(*al->list));
al->index.index = NULL;
al->index.size = 0;
al->numDirs = 0;
al->dirs = NULL;
}
/**
* Free available packages, items, and directories members.
* @param al available list
*/
static void alFree(availableList al)
/*@modifies al @*/
{
HFD_t hfd = headerFreeData;
struct availablePackage * p;
rpmRelocation * r;
int i;
if ((p = al->list) != NULL)
for (i = 0; i < al->size; i++, p++) {
{ tsortInfo tsi;
while ((tsi = p->tsi.tsi_next) != NULL) {
p->tsi.tsi_next = tsi->tsi_next;
tsi->tsi_next = NULL;
tsi = _free(tsi);
}
}
p->provides = hfd(p->provides, -1);
p->providesEVR = hfd(p->providesEVR, -1);
p->requires = hfd(p->requires, -1);
p->requiresEVR = hfd(p->requiresEVR, -1);
p->baseNames = hfd(p->baseNames, -1);
p->h = headerFree(p->h);
if (p->relocs) {
for (r = p->relocs; (r->oldPath || r->newPath); r++) {
r->oldPath = _free(r->oldPath);
r->newPath = _free(r->newPath);
}
p->relocs = _free(p->relocs);
}
if (p->fd != NULL)
p->fd = fdFree(p->fd, "alAddPackage (alFree)");
}
if (al->dirs != NULL)
for (i = 0; i < al->numDirs; i++) {
al->dirs[i].dirName = _free(al->dirs[i].dirName);
al->dirs[i].files = _free(al->dirs[i].files);
}
al->dirs = _free(al->dirs);
al->numDirs = 0;
al->list = _free(al->list);
al->alloced = 0;
alFreeIndex(al);
}
/**
* Compare two directory info entries by name (qsort/bsearch).
* @param one 1st directory info
* @param two 2nd directory info
* @return result of comparison
*/
static int dirInfoCompare(const void * one, const void * two) /*@*/
{
const dirInfo a = (const dirInfo) one;
const dirInfo b = (const dirInfo) two;
int lenchk = a->dirNameLen - b->dirNameLen;
if (lenchk)
return lenchk;
/* XXX FIXME: this might do "backward" strcmp for speed */
return strcmp(a->dirName, b->dirName);
}
/**
* Add package to available list.
* @param al available list
* @param h package header
* @param key package private data
* @param fd package file handle
* @param relocs package file relocations
* @return available package pointer
*/
static /*@exposed@*/ struct availablePackage *
alAddPackage(availableList al,
Header h, /*@null@*/ /*@dependent@*/ const void * key,
/*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs)
/*@modifies al, h @*/
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmTagType dnt, bnt;
struct availablePackage * p;
rpmRelocation * r;
int i;
int_32 * dirIndexes;
const char ** dirNames;
int numDirs, dirNum;
int * dirMapping;
struct dirInfo_s dirNeedle;
dirInfo dirMatch;
int first, last, fileNum;
int origNumDirs;
int pkgNum;
uint_32 multiLibMask = 0;
uint_32 * fileFlags = NULL;
uint_32 * pp = NULL;
if (al->size == al->alloced) {
al->alloced += al->delta;
al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
}
pkgNum = al->size++;
p = al->list + pkgNum;
p->h = headerLink(h); /* XXX reference held by transaction set */
p->depth = p->npreds = 0;
memset(&p->tsi, 0, sizeof(p->tsi));
p->multiLib = 0; /* MULTILIB */
(void) headerNVR(p->h, &p->name, &p->version, &p->release);
/* XXX This should be added always so that packages look alike.
* XXX However, there is logic in files.c/depends.c that checks for
* XXX existence (rather than value) that will need to change as well.
*/
if (hge(p->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
multiLibMask = *pp;
if (multiLibMask) {
for (i = 0; i < pkgNum - 1; i++) {
if (!strcmp (p->name, al->list[i].name)
&& hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
(void **) &pp, NULL)
&& !rpmVersionCompare(p->h, al->list[i].h)
&& *pp && !(*pp & multiLibMask))
p->multiLib = multiLibMask;
}
}
if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL))
p->epoch = NULL;
if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides,
&p->providesCount)) {
p->providesCount = 0;
p->provides = NULL;
p->providesEVR = NULL;
p->provideFlags = NULL;
} else {
if (!hge(h, RPMTAG_PROVIDEVERSION,
NULL, (void **) &p->providesEVR, NULL))
p->providesEVR = NULL;
if (!hge(h, RPMTAG_PROVIDEFLAGS,
NULL, (void **) &p->provideFlags, NULL))
p->provideFlags = NULL;
}
if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires,
&p->requiresCount)) {
p->requiresCount = 0;
p->requires = NULL;
p->requiresEVR = NULL;
p->requireFlags = NULL;
} else {
if (!hge(h, RPMTAG_REQUIREVERSION,
NULL, (void **) &p->requiresEVR, NULL))
p->requiresEVR = NULL;
if (!hge(h, RPMTAG_REQUIREFLAGS,
NULL, (void **) &p->requireFlags, NULL))
p->requireFlags = NULL;
}
if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **)&p->baseNames, &p->filesCount))
{
p->filesCount = 0;
p->baseNames = NULL;
} else {
(void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
(void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
(void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
/* XXX FIXME: We ought to relocate the directory list here */
dirMapping = alloca(sizeof(*dirMapping) * numDirs);
/* allocated enough space for all the directories we could possible
need to add */
al->dirs = xrealloc(al->dirs,
sizeof(*al->dirs) * (al->numDirs + numDirs));
origNumDirs = al->numDirs;
for (dirNum = 0; dirNum < numDirs; dirNum++) {
dirNeedle.dirName = (char *) dirNames[dirNum];
dirNeedle.dirNameLen = strlen(dirNames[dirNum]);
dirMatch = bsearch(&dirNeedle, al->dirs, origNumDirs,
sizeof(dirNeedle), dirInfoCompare);
if (dirMatch) {
dirMapping[dirNum] = dirMatch - al->dirs;
} else {
dirMapping[dirNum] = al->numDirs;
al->dirs[al->numDirs].dirName = xstrdup(dirNames[dirNum]);
al->dirs[al->numDirs].dirNameLen = strlen(dirNames[dirNum]);
al->dirs[al->numDirs].files = NULL;
al->dirs[al->numDirs].numFiles = 0;
al->numDirs++;
}
}
dirNames = hfd(dirNames, dnt);
first = 0;
while (first < p->filesCount) {
last = first;
while ((last + 1) < p->filesCount) {
if (dirIndexes[first] != dirIndexes[last + 1])
/*@innerbreak@*/ break;
last++;
}
dirMatch = al->dirs + dirMapping[dirIndexes[first]];
dirMatch->files = xrealloc(dirMatch->files,
sizeof(*dirMatch->files) *
(dirMatch->numFiles + last - first + 1));
if (p->baseNames != NULL) /* XXX can't happen */
for (fileNum = first; fileNum <= last; fileNum++) {
dirMatch->files[dirMatch->numFiles].baseName =
p->baseNames[fileNum];
dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum;
dirMatch->files[dirMatch->numFiles].fileFlags =
fileFlags[fileNum];
dirMatch->numFiles++;
}
first = last + 1;
}
if (origNumDirs + al->numDirs)
qsort(al->dirs, al->numDirs, sizeof(dirNeedle), dirInfoCompare);
}
p->key = key;
p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL);
if (relocs) {
for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++)
{};
p->relocs = xmalloc((i + 1) * sizeof(*p->relocs));
for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
}
p->relocs[i].oldPath = NULL;
p->relocs[i].newPath = NULL;
} else {
p->relocs = NULL;
}
alFreeIndex(al);
return p;
}
/**
* Compare two available index entries by name (qsort/bsearch).
* @param one 1st available index entry
* @param two 2nd available index entry
* @return result of comparison
*/
static int indexcmp(const void * one, const void * two) /*@*/
{
const struct availableIndexEntry * a = one;
const struct availableIndexEntry * b = two;
int lenchk = a->entryLen - b->entryLen;
if (lenchk)
return lenchk;
return strcmp(a->entry, b->entry);
}
/**
* Generate index for available list.
* @param al available list
*/
static void alMakeIndex(availableList al)
/*@modifies al @*/
{
struct availableIndex * ai = &al->index;
int i, j, k;
if (ai->size || al->list == NULL) return;
for (i = 0; i < al->size; i++)
ai->size += al->list[i].providesCount;
if (ai->size) {
ai->index = xcalloc(ai->size, sizeof(*ai->index));
k = 0;
for (i = 0; i < al->size; i++) {
for (j = 0; j < al->list[i].providesCount; j++) {
/* If multilib install, skip non-multilib provides. */
if (al->list[i].multiLib &&
!isDependsMULTILIB(al->list[i].provideFlags[j])) {
ai->size--;
continue;
}
ai->index[k].package = al->list + i;
ai->index[k].entry = al->list[i].provides[j];
ai->index[k].entryLen = strlen(al->list[i].provides[j]);
ai->index[k].entryIx = j;
ai->index[k].type = IET_PROVIDES;
k++;
}
}
qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
}
}
/* 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;
int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
const char * BName, const char * BEVR, int BFlags)
{
const char *aDepend = printDepend(NULL, AName, AEVR, AFlags);
const char *bDepend = printDepend(NULL, BName, BEVR, BFlags);
char *aEVR, *bEVR;
const char *aE, *aV, *aR, *bE, *bV, *bR;
int result;
int sense;
/* Different names don't overlap. */
if (strcmp(AName, BName)) {
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 = "";
/* Optimize: when both EVRs are non-existent or empty, always overlap. */
if (!(*AEVR || *BEVR)) {
2002-03-25 23:16:26 +03:00
result = 1;
goto exit;
}
/* Both AEVR and BEVR exist. */
aEVR = xstrdup(AEVR);
parseEVR(aEVR, &aE, &aV, &aR);
bEVR = xstrdup(BEVR);
parseEVR(bEVR, &bE, &bV, &bR);
/* rpmEVRcmp() is also shared; the code moved to rpmvercmp.c */
sense = rpmEVRcmp(aE, aV, aR, aDepend, bE, bV, bR, bDepend);
2002-03-25 23:16:26 +03:00
aEVR = _free(aEVR);
bEVR = _free(bEVR);
/* 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:
rpmMessage(RPMMESS_DEBUG, _(" %s A %s\tB %s\n"),
(result ? _("YES") : _("NO ")), aDepend, bDepend);
aDepend = _free(aDepend);
bDepend = _free(bDepend);
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;
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;
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) headerNVR(h, &name, &version, &release);
pkgEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
*p = '\0';
if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
sprintf(p, "%d:", *epoch);
while (*p != '\0')
p++;
}
(void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
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->delta = 5;
ts->numRemovedPackages = 0;
ts->allocedRemovedPackages = ts->delta;
ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
sizeof(*ts->removedPackages));
/* 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;
ts->addedPackages.delta = ts->delta;
alCreate(&ts->addedPackages);
ts->availablePackages.delta = ts->delta;
alCreate(&ts->availablePackages);
ts->orderAlloced = ts->delta;
ts->orderCount = 0;
ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order));
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;
}
if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
ts->allocedRemovedPackages += ts->delta;
ts->removedPackages = xrealloc(ts->removedPackages,
sizeof(int *) * ts->allocedRemovedPackages);
}
if (ts->removedPackages != NULL) { /* XXX can't happen. */
ts->removedPackages[ts->numRemovedPackages++] = dboffset;
qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp);
}
if (ts->orderCount == ts->orderAlloced) {
ts->orderAlloced += ts->delta;
ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
}
ts->order[ts->orderCount].type = TR_REMOVED;
ts->order[ts->orderCount].u.removed.dboffset = dboffset;
ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends;
return 0;
}
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;
int alNum;
/*
* 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.
*/
if (ts->orderCount == ts->orderAlloced) {
ts->orderAlloced += ts->delta;
ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
}
ts->order[ts->orderCount].type = TR_ADDED;
if (ts->addedPackages.list == NULL)
return 0;
alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
ts->addedPackages.list;
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) headerNVR(h, &name, NULL, NULL);
{ rpmdbMatchIterator mi;
Header h2;
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
while((h2 = rpmdbNextIterator(mi)) != NULL) {
if (rpmVersionCompare(h, h2))
(void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
else {
uint_32 *p, multiLibMask = 0, oldmultiLibMask = 0;
if (hge(h2, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
oldmultiLibMask = *p;
if (hge(h, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
multiLibMask = *p;
if (oldmultiLibMask && multiLibMask
&& !(oldmultiLibMask & multiLibMask)) {
ts->addedPackages.list[alNum].multiLib = multiLibMask;
}
}
}
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;
}
void rpmtransAvailablePackage(rpmTransactionSet ts, Header h, const void * key)
{
struct availablePackage * al;
al = alAddPackage(&ts->availablePackages, h, key, NULL, NULL);
}
int rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
{
return removePackage(ts, dboffset, -1);
}
rpmTransactionSet rpmtransFree(rpmTransactionSet ts)
{
if (ts) {
alFree(&ts->addedPackages);
alFree(&ts->availablePackages);
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);
conflicts[i].suggestedPackages = _free(conflicts[i].suggestedPackages);
}
return (conflicts = _free(conflicts));
}
/**
* Check added package file lists for package(s) that provide a file.
* @param al available list
* @param keyType type of dependency
* @param fileName file name to search for
* @return available package pointer
*/
static /*@only@*/ /*@null@*/ struct availablePackage **
alAllFileSatisfiesDepend(const availableList al,
const char * keyType, const char * fileName)
/*@*/
{
int i, found;
const char * dirName;
const char * baseName;
struct dirInfo_s dirNeedle;
dirInfo dirMatch;
struct availablePackage ** ret;
/* Solaris 2.6 bsearch sucks down on this. */
if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
return NULL;
{ char * t;
dirName = t = xstrdup(fileName);
if ((t = strrchr(t, '/')) != NULL) {
t++; /* leave the trailing '/' */
*t = '\0';
}
}
dirNeedle.dirName = (char *) dirName;
dirNeedle.dirNameLen = strlen(dirName);
dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs,
sizeof(dirNeedle), dirInfoCompare);
if (dirMatch == NULL) {
dirName = _free(dirName);
return NULL;
}
/* rewind to the first match */
while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, &dirNeedle) == 0)
dirMatch--;
/*@-nullptrarith@*/ /* FIX: fileName NULL ??? */
baseName = strrchr(fileName, '/') + 1;
/*@=nullptrarith@*/
for (found = 0, ret = NULL;
dirMatch <= al->dirs + al->numDirs &&
dirInfoCompare(dirMatch, &dirNeedle) == 0;
dirMatch++)
{
/* XXX FIXME: these file lists should be sorted and bsearched */
for (i = 0; i < dirMatch->numFiles; i++) {
if (dirMatch->files[i].baseName == NULL ||
strcmp(dirMatch->files[i].baseName, baseName))
continue;
/*
* If a file dependency would be satisfied by a file
* we are not going to install, skip it.
*/
if (al->list[dirMatch->files[i].pkgNum].multiLib &&
!isFileMULTILIB(dirMatch->files[i].fileFlags))
continue;
if (keyType)
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
keyType, fileName);
ret = xrealloc(ret, (found+2) * sizeof(*ret));
if (ret) /* can't happen */
ret[found++] = al->list + dirMatch->files[i].pkgNum;
/*@innerbreak@*/ break;
}
}
dirName = _free(dirName);
/*@-mods@*/ /* FIX: al->list might be modified. */
if (ret)
ret[found] = NULL;
/*@=mods@*/
return ret;
}
#ifdef DYING
/**
* Check added package file lists for first package that provides a file.
* @param al available list
* @param keyType type of dependency
* @param fileName file name to search for
* @return available package pointer
*/
/*@unused@*/ static /*@dependent@*/ /*@null@*/ struct availablePackage *
alFileSatisfiesDepend(const availableList al,
const char * keyType, const char * fileName)
/*@*/
{
struct availablePackage * ret;
struct availablePackage ** tmp =
alAllFileSatisfiesDepend(al, keyType, fileName);
if (tmp) {
ret = tmp[0];
tmp = _free(tmp);
return ret;
}
return NULL;
}
#endif /* DYING */
/**
* Check added package file lists for package(s) that have a provide.
* @param al available list
* @param keyType type of dependency
* @param keyDepend dependency string representation
* @param keyName dependency name string
* @param keyEVR dependency [epoch:]version[-release] string
* @param keyFlags dependency logical range qualifiers
* @return available package pointer
*/
static /*@only@*/ /*@null@*/ struct availablePackage **
alAllSatisfiesDepend(const availableList al,
const char * keyType, const char * keyDepend,
const char * keyName, const char * keyEVR, int keyFlags)
/*@*/
{
struct availableIndexEntry needle, * match;
struct availablePackage * p, ** ret = NULL;
int i, rc, found;
if (*keyName == '/') {
ret = alAllFileSatisfiesDepend(al, keyType, keyName);
/* XXX Provides: /path was broken with added packages (#52183). */
if (ret != NULL && *ret != NULL)
return ret;
}
if (!al->index.size || al->index.index == NULL) return NULL;
needle.entry = keyName;
needle.entryLen = strlen(keyName);
match = bsearch(&needle, al->index.index, al->index.size,
sizeof(*al->index.index), indexcmp);
if (match == NULL) return NULL;
/* rewind to the first match */
while (match > al->index.index && indexcmp(match-1, &needle) == 0)
match--;
for (ret = NULL, found = 0;
match < al->index.index + al->index.size &&
indexcmp(match, &needle) == 0;
match++)
{
p = match->package;
rc = 0;
switch (match->type) {
case IET_PROVIDES:
i = match->entryIx;
{ const char * proEVR;
int proFlags;
proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
if ((keyFlags & RPMSENSE_SENSEMASK) && !(proFlags & RPMSENSE_SENSEMASK))
proFlags |= RPMSENSE_EQUAL;
2002-03-25 23:16:26 +03:00
rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
keyName, keyEVR, keyFlags);
if (rc)
/*@switchbreak@*/ break;
}
if (keyType && keyDepend && rc)
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
keyType, keyDepend+2);
break;
}
if (rc) {
ret = xrealloc(ret, (found + 2) * sizeof(*ret));
if (ret) /* can't happen */
ret[found++] = p;
}
}
if (ret)
ret[found] = NULL;
return ret;
}
/**
* Check added package file lists for first package that has a provide.
* @todo Eliminate.
* @param al available list
* @param keyType type of dependency
* @param keyDepend dependency string representation
* @param keyName dependency name string
* @param keyEVR dependency [epoch:]version[-release] string
* @param keyFlags dependency logical range qualifiers
* @return available package pointer
*/
static inline /*@only@*/ /*@null@*/ struct availablePackage *
alSatisfiesDepend(const availableList al,
const char * keyType, const char * keyDepend,
const char * keyName, const char * keyEVR, int keyFlags)
/*@*/
{
struct availablePackage * ret;
struct availablePackage ** tmp =
alAllSatisfiesDepend(al, keyType, keyDepend, keyName, keyEVR, keyFlags);
if (tmp) {
ret = tmp[0];
tmp = _free(tmp);
return ret;
}
return NULL;
}
/**
* Check key for an unsatisfied dependency.
* @todo Eliminate rpmrc provides.
* @param ts transaction set
* @param keyType type of dependency
* @param keyDepend dependency string representation
* @param keyName dependency name string
* @param keyEVR dependency [epoch:]version[-release] string
* @param keyFlags dependency logical range qualifiers
* @retval suggestion possible package(s) to resolve dependency
* @return 0 if satisfied, 1 if not satisfied, 2 if error
*/
static int unsatisfiedDepend(rpmTransactionSet ts,
const char * keyType, const char * keyDepend,
const char * keyName, const char * keyEVR, int keyFlags,
/*@null@*/ /*@out@*/ struct availablePackage *** suggestion)
/*@modifies ts, *suggestion @*/
{
rpmdbMatchIterator mi;
Header h;
int rc = 0; /* assume dependency is satisfied */
if (suggestion) *suggestion = NULL;
/*
* Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
*/
if (_cacheDependsRC) {
dbiIndex dbi;
dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
if (dbi == NULL)
_cacheDependsRC = 0;
else {
DBC * dbcursor = NULL;
size_t keylen = strlen(keyDepend);
void * datap = NULL;
size_t datalen = 0;
int xx;
xx = dbiCopen(dbi, &dbcursor, 0);
/*@-mods@*/ /* FIX: keyDepends mod undocumented. */
xx = dbiGet(dbi, dbcursor, (void **)&keyDepend, &keylen, &datap, &datalen, 0);
/*@=mods@*/
if (xx == 0 && datap && datalen == 4) {
memcpy(&rc, datap, datalen);
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s %-s (cached)\n"),
keyType, keyDepend, (rc ? _("NO ") : _("YES")));
xx = dbiCclose(dbi, NULL, 0);
if (suggestion && rc == 1)
*suggestion = alAllSatisfiesDepend(&ts->availablePackages,
NULL, NULL, keyName, keyEVR, keyFlags);
return rc;
}
xx = dbiCclose(dbi, dbcursor, 0);
}
}
#ifdef DYING
{ static /*@observer@*/ const char noProvidesString[] = "nada";
static /*@observer@*/ const char * rcProvidesString = noProvidesString;
const char * start;
int i;
if (rcProvidesString == noProvidesString)
rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
if (rcProvidesString != NULL && !(keyFlags & RPMSENSE_SENSEMASK)) {
i = strlen(keyName);
/*@-observertrans -mayaliasunique@*/
while ((start = strstr(rcProvidesString, keyName))) {
/*@=observertrans =mayaliasunique@*/
if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmrc provides)\n"),
keyType, keyDepend+2);
goto exit;
}
rcProvidesString = start + 1;
}
}
}
#endif
/*
* 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);
goto exit;
}
goto unsatisfied;
}
if (alSatisfiesDepend(&ts->addedPackages, keyType, keyDepend,
keyName, keyEVR, keyFlags))
{
goto exit;
}
/* XXX only the installer does not have the database open here. */
if (ts->rpmdb != NULL) {
if (*keyName == '/') {
/* keyFlags better be 0! */
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_BASENAMES, keyName, 0);
(void) rpmdbPruneIterator(mi,
ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db files)\n"),
keyType, keyDepend+2);
mi = rpmdbFreeIterator(mi);
goto exit;
}
mi = rpmdbFreeIterator(mi);
}
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_PROVIDENAME, keyName, 0);
(void) rpmdbPruneIterator(mi,
ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db provides)\n"),
keyType, keyDepend+2);
mi = rpmdbFreeIterator(mi);
goto exit;
}
}
mi = rpmdbFreeIterator(mi);
#ifndef DYING
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, keyName, 0);
(void) rpmdbPruneIterator(mi,
ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db package)\n"),
keyType, keyDepend+2);
mi = rpmdbFreeIterator(mi);
goto exit;
}
}
mi = rpmdbFreeIterator(mi);
#endif
}
if (suggestion)
*suggestion = alAllSatisfiesDepend(&ts->availablePackages, NULL, NULL,
keyName, keyEVR, keyFlags);
unsatisfied:
rpmMessage(RPMMESS_DEBUG, _("%s: %-45s NO\n"), keyType, keyDepend+2);
rc = 1; /* dependency is unsatisfied */
exit:
/*
* If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
*/
if (_cacheDependsRC) {
dbiIndex dbi;
dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
if (dbi == NULL) {
_cacheDependsRC = 0;
} else {
DBC * dbcursor = NULL;
int xx;
xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
xx = dbiPut(dbi, dbcursor, keyDepend, strlen(keyDepend), &rc, sizeof(rc), 0);
if (xx)
_cacheDependsRC = 0;
#if 0 /* XXX NOISY */
else
rpmMessage(RPMMESS_DEBUG, _("%s: (%s, %s) added to Depends cache.\n"), keyType, keyDepend, (rc ? _("NO ") : _("YES")));
#endif
xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
}
}
return rc;
}
/**
* 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
* @param multiLib skip multilib colored dependencies?
* @return 0 no problems found
*/
static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp,
Header h, const char * keyName, uint_32 multiLib)
/*@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;
struct availablePackage ** suggestion;
(void) headerNVR(h, &name, &version, &release);
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;
/* If this requirement comes from the core package only, not libraries,
then if we're installing the libraries only, don't count it in. */
if (multiLib && !isDependsMULTILIB(requireFlags[i]))
continue;
keyDepend = printDepend("R",
requires[i], requiresEVR[i], requireFlags[i]);
rc = unsatisfiedDepend(ts, " Requires", keyDepend,
requires[i], requiresEVR[i], requireFlags[i], &suggestion);
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);
if (psp->num == psp->alloced) {
psp->alloced += 5;
psp->problems = xrealloc(psp->problems, sizeof(*psp->problems) *
psp->alloced);
}
{ 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;
if (suggestion) {
int j;
for (j = 0; suggestion[j]; j++)
{};
pp->suggestedPackages =
xmalloc( (j + 1) * sizeof(*pp->suggestedPackages) );
for (j = 0; suggestion[j]; j++)
pp->suggestedPackages[j] = suggestion[j]->key;
pp->suggestedPackages[j] = NULL;
} else {
pp->suggestedPackages = NULL;
}
}
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;
/* If this requirement comes from the core package only, not libraries,
then if we're installing the libraries only, don't count it in. */
if (multiLib && !isDependsMULTILIB(conflictFlags[i]))
continue;
keyDepend = printDepend("C", conflicts[i], conflictsEVR[i], conflictFlags[i]);
rc = unsatisfiedDepend(ts, "Conflicts", keyDepend,
conflicts[i], conflictsEVR[i], conflictFlags[i], NULL);
/* 1 == unsatisfied, 0 == satsisfied */
switch (rc) {
case 0: /* conflicts exist. */
rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"),
name, keyDepend+2);
if (psp->num == psp->alloced) {
psp->alloced += 5;
psp->problems = xrealloc(psp->problems,
sizeof(*psp->problems) * psp->alloced);
}
{ 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;
pp->suggestedPackages = NULL;
}
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;
}
/**
* Check dependency against installed packages.
* Adding: check name/provides key against each conflict match,
* Erasing: check name/provides/filename key against each requiredby match.
* @param ts transaction set
* @param psp dependency problems
* @param key dependency name
* @param mi rpm database iterator
* @return 0 no problems found
*/
static int checkPackageSet(rpmTransactionSet ts, problemsSet psp,
const char * key, /*@only@*/ /*@null@*/ rpmdbMatchIterator mi)
/*@modifies ts, mi, psp @*/
{
Header h;
int rc = 0;
(void) rpmdbPruneIterator(mi,
ts->removedPackages, ts->numRemovedPackages, 1);
while ((h = rpmdbNextIterator(mi)) != NULL) {
if (checkPackageDeps(ts, psp, h, key, 0)) {
rc = 1;
break;
}
}
mi = rpmdbFreeIterator(mi);
return rc;
}
/**
* Erasing: check name/provides/filename key against requiredby matches.
* @param ts transaction set
* @param psp dependency problems
* @param key requires name
* @return 0 no problems found
*/
static int checkDependentPackages(rpmTransactionSet ts,
problemsSet psp, const char * key)
/*@modifies ts, psp @*/
{
rpmdbMatchIterator mi;
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_REQUIRENAME, key, 0);
return checkPackageSet(ts, psp, key, mi);
}
/**
* Adding: check name/provides key against conflicts matches.
* @param ts transaction set
* @param psp dependency problems
* @param key conflicts name
* @return 0 no problems found
*/
static int checkDependentConflicts(rpmTransactionSet ts,
problemsSet psp, const char * key)
/*@modifies ts, psp @*/
{
int rc = 0;
if (ts->rpmdb) { /* XXX is this necessary? */
rpmdbMatchIterator mi;
mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_CONFLICTNAME, key, 0);
rc = checkPackageSet(ts, psp, key, mi);
}
return rc;
}
struct badDeps_s {
/*@observer@*/ /*@null@*/ const char * pname;
/*@observer@*/ /*@null@*/ const char * qname;
};
#ifdef DYING
static struct badDeps_s {
/*@observer@*/ /*@null@*/ const char * pname;
/*@observer@*/ /*@null@*/ const char * qname;
} badDeps[] = {
{ "libtermcap", "bash" },
{ "modutils", "vixie-cron" },
{ "ypbind", "yp-tools" },
{ "ghostscript-fonts", "ghostscript" },
/* 7.2 only */
{ "libgnomeprint15", "gnome-print" },
{ "nautilus", "nautilus-mozilla" },
/* 7.1 only */
{ "arts", "kdelibs-sound" },
/* 7.0 only */
{ "pango-gtkbeta-devel", "pango-gtkbeta" },
{ "XFree86", "Mesa" },
{ "compat-glibc", "db2" },
{ "compat-glibc", "db1" },
{ "pam", "initscripts" },
{ "initscripts", "sysklogd" },
/* 6.2 */
{ "egcs-c++", "libstdc++" },
/* 6.1 */
{ "pilot-link-devel", "pilot-link" },
/* 5.2 */
{ "pam", "pamconfig" },
{ NULL, NULL }
};
#else
static struct badDeps_s * badDeps = NULL;
#endif
/**
* Check for dependency relations to be ignored.
*
* @param p successor package (i.e. with Requires: )
* @param q predecessor package (i.e. with Provides: )
* @return 1 if dependency is to be ignored.
*/
static int ignoreDep(const struct availablePackage * p,
const struct availablePackage * q)
/*@*/
{
struct badDeps_s * bdp;
static int _initialized = 0;
const char ** av = NULL;
int ac = 0;
if (!_initialized) {
char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
int i;
if (s != NULL && *s != '\0'
&& !(i = poptParseArgvString(s, &ac, (const char ***)&av))
&& ac > 0 && av != NULL)
{
bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
for (i = 0; i < ac; i++, bdp++) {
char * p, * q;
if (av[i] == NULL)
break;
p = xstrdup(av[i]);
if ((q = strchr(p, '>')) != NULL)
*q++ = '\0';
bdp->pname = p;
bdp->qname = q;
rpmMessage(RPMMESS_DEBUG,
_("ignore package name relation(s) [%d]\t%s -> %s\n"),
i, bdp->pname, bdp->qname);
}
bdp->pname = bdp->qname = NULL;
}
av = _free(av);
s = _free(s);
_initialized++;
}
if (badDeps != NULL)
for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
if (!strcmp(p->name, bdp->pname) && !strcmp(q->name, bdp->qname))
return 1;
}
return 0;
}
/**
* Recursively mark all nodes with their predecessors.
* @param tsi successor chain
* @param q predecessor
*/
static void markLoop(/*@special@*/ tsortInfo tsi,
struct availablePackage * q)
/*@uses tsi @*/
/*@modifies internalState @*/
{
struct availablePackage * p;
while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
tsi = tsi->tsi_next;
if (p->tsi.tsi_pkg != NULL)
continue;
p->tsi.tsi_pkg = q;
if (p->tsi.tsi_next != NULL)
markLoop(p->tsi.tsi_next, p);
}
}
static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
{
if (isLegacyPreReq(f))
return "PreReq:";
f = _notpre(f);
if (f & RPMSENSE_SCRIPT_PRE)
return "Requires(pre):";
if (f & RPMSENSE_SCRIPT_POST)
return "Requires(post):";
if (f & RPMSENSE_SCRIPT_PREUN)
return "Requires(preun):";
if (f & RPMSENSE_SCRIPT_POSTUN)
return "Requires(postun):";
if (f & RPMSENSE_SCRIPT_VERIFY)
return "Requires(verify):";
if (f & RPMSENSE_FIND_REQUIRES)
return "Requires(auto):";
return "Requires:";
}
/**
* Find (and eliminate co-requisites) "q <- p" relation in dependency loop.
* Search all successors of q for instance of p. Format the specific relation,
* (e.g. p contains "Requires: q"). Unlink and free co-requisite (i.e.
* pure Requires: dependencies) successor node(s).
* @param q sucessor (i.e. package required by p)
* @param p predecessor (i.e. package that "Requires: q")
* @param zap max. no. of co-requisites to remove (-1 is all)?
* @retval nzaps address of no. of relations removed
* @return (possibly NULL) formatted "q <- p" releation (malloc'ed)
*/
static /*@owned@*/ /*@null@*/ const char *
zapRelation(struct availablePackage * q, struct availablePackage * p,
int zap, /*@in@*/ /*@out@*/ int * nzaps)
/*@modifies q, p, *nzaps @*/
{
tsortInfo tsi_prev;
tsortInfo tsi;
const char *dp = NULL;
for (tsi_prev = &q->tsi, tsi = q->tsi.tsi_next;
tsi != NULL;
/* XXX Note: the loop traverses "not found", break on "found". */
/*@-nullderef@*/
tsi_prev = tsi, tsi = tsi->tsi_next)
/*@=nullderef@*/
{
int j;
if (tsi->tsi_suc != p)
continue;
if (p->requires == NULL) continue; /* XXX can't happen */
if (p->requireFlags == NULL) continue; /* XXX can't happen */
if (p->requiresEVR == NULL) continue; /* XXX can't happen */
j = tsi->tsi_reqx;
dp = printDepend( identifyDepend(p->requireFlags[j]),
p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
/*
* Attempt to unravel a dependency loop by eliminating Requires's.
*/
if (zap && !(p->requireFlags[j] & RPMSENSE_PREREQ)) {
rpmMessage(RPMMESS_DEBUG,
_("removing %s-%s-%s \"%s\" from tsort relations.\n"),
p->name, p->version, p->release, dp);
p->tsi.tsi_count--;
if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
tsi->tsi_next = NULL;
tsi->tsi_suc = NULL;
tsi = _free(tsi);
if (nzaps)
(*nzaps)++;
if (zap)
zap--;
}
/* XXX Note: the loop traverses "not found", get out now! */
break;
}
return dp;
}
/**
* Record next "q <- p" relation (i.e. "p" requires "q").
* @param ts transaction set
* @param p predecessor (i.e. package that "Requires: q")
* @param selected boolean package selected array
* @param j relation index
* @return 0 always
*/
static inline int addRelation( const rpmTransactionSet ts,
struct availablePackage * p, unsigned char * selected, int j)
/*@modifies p->tsi.tsi_u.count, p->depth, *selected @*/
{
struct availablePackage * q;
tsortInfo tsi;
int matchNum;
if (!p->requires || !p->requiresEVR || !p->requireFlags)
return 0;
q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL,
p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
/* Ordering depends only on added package relations. */
if (q == NULL)
return 0;
/* Avoid rpmlib feature dependencies. */
if (!strncmp(p->requires[j], "rpmlib(", sizeof("rpmlib(")-1))
return 0;
/* Avoid certain dependency relations. */
if (ignoreDep(p, q))
return 0;
/* Avoid redundant relations. */
/* XXX TODO: add control bit. */
matchNum = q - ts->addedPackages.list;
if (selected[matchNum] != 0)
return 0;
selected[matchNum] = 1;
/* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
p->tsi.tsi_count++; /* bump p predecessor count */
if (p->depth <= q->depth) /* Save max. depth in dependency tree */
p->depth = q->depth + 1;
tsi = xmalloc(sizeof(*tsi));
tsi->tsi_suc = p;
tsi->tsi_reqx = j;
tsi->tsi_next = q->tsi.tsi_next;
q->tsi.tsi_next = tsi;
q->tsi.tsi_qcnt++; /* bump q successor count */
return 0;
}
/**
* Compare ordered list entries by index (qsort/bsearch).
* @param one 1st ordered list entry
* @param two 2nd ordered list entry
* @return result of comparison
*/
static int orderListIndexCmp(const void * one, const void * two) /*@*/
{
int a = ((const struct orderListIndex *)one)->alIndex;
int b = ((const struct orderListIndex *)two)->alIndex;
return (a - b);
}
/**
* Add element to list sorting by initial successor count.
* @param p new element
* @retval qp address of first element
* @retval rp address of last element
*/
static void addQ(struct availablePackage * p,
/*@in@*/ /*@out@*/ struct availablePackage ** qp,
/*@in@*/ /*@out@*/ struct availablePackage ** rp)
/*@modifies p->tsi, *qp, *rp @*/
{
struct availablePackage *q, *qprev;
/* Mark the package as queued. */
p->tsi.tsi_reqx = 1;
if ((*rp) == NULL) { /* 1st element */
(*rp) = (*qp) = p;
return;
}
for (qprev = NULL, q = (*qp); q != NULL; qprev = q, q = q->tsi.tsi_suc) {
if (q->tsi.tsi_qcnt <= p->tsi.tsi_qcnt)
break;
}
if (qprev == NULL) { /* insert at beginning of list */
p->tsi.tsi_suc = q;
(*qp) = p; /* new head */
} else if (q == NULL) { /* insert at end of list */
qprev->tsi.tsi_suc = p;
(*rp) = p; /* new tail */
} else { /* insert between qprev and q */
p->tsi.tsi_suc = q;
qprev->tsi.tsi_suc = p;
}
}
int rpmdepOrder(rpmTransactionSet ts)
{
int npkgs = ts->addedPackages.size;
#ifdef DYING
int chainsaw = ts->transFlags & RPMTRANS_FLAG_CHAINSAW;
#else
2002-04-05 12:04:32 +04:00
int chainsaw = 0;
2002-03-25 23:16:26 +03:00
#endif
struct availablePackage * p;
struct availablePackage * q;
struct availablePackage * r;
tsortInfo tsi;
tsortInfo tsi_next;
int * ordering = alloca(sizeof(*ordering) * (npkgs + 1));
int orderingCount = 0;
unsigned char * selected = alloca(sizeof(*selected) * (npkgs + 1));
int loopcheck;
transactionElement newOrder;
int newOrderCount = 0;
struct orderListIndex * orderList;
int nrescans = 10;
int _printed = 0;
int treex;
int depth;
int qlen;
int i, j;
alMakeIndex(&ts->addedPackages);
alMakeIndex(&ts->availablePackages);
/* T1. Initialize. */
loopcheck = npkgs;
/* Record all relations. */
rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, p++) {
int matchNum;
if (p->requiresCount <= 0)
continue;
memset(selected, 0, sizeof(*selected) * npkgs);
/* Avoid narcisstic relations. */
matchNum = p - ts->addedPackages.list;
selected[matchNum] = 1;
/* T2. Next "q <- p" relation. */
/* First, do pre-requisites. */
for (j = 0; j < p->requiresCount; j++) {
if (p->requireFlags == NULL) continue; /* XXX can't happen */
/* Skip if not %pre/%post requires or legacy prereq. */
2003-07-09 21:21:28 +04:00
if (!( isInstallPreReq(p->requireFlags[j]) ||
2002-03-25 23:16:26 +03:00
isLegacyPreReq(p->requireFlags[j]) ))
continue;
/* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
(void) addRelation(ts, p, selected, j);
}
/* Then do co-requisites. */
for (j = 0; j < p->requiresCount; j++) {
if (p->requireFlags == NULL) continue; /* XXX can't happen */
2003-07-09 21:21:28 +04:00
/* Skip if %pre/%post/%preun/%postun requires or legacy prereq. */
2002-03-25 23:16:26 +03:00
if (isErasePreReq(p->requireFlags[j]) ||
( isInstallPreReq(p->requireFlags[j]) ||
isLegacyPreReq(p->requireFlags[j]) ))
continue;
/* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
(void) addRelation(ts, p, selected, j);
}
}
/* Save predecessor count and mark tree roots. */
treex = 0;
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, p++) {
p->npreds = p->tsi.tsi_count;
p->tree = (p->npreds == 0 ? treex++ : -1);
}
/* T4. Scan for zeroes. */
rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
rescan:
q = r = NULL;
qlen = 0;
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, p++) {
/* Prefer packages in chainsaw or presentation order. */
if (!chainsaw)
p->tsi.tsi_qcnt = (npkgs - i);
if (p->tsi.tsi_count != 0)
continue;
p->tsi.tsi_suc = NULL;
addQ(p, &q, &r);
qlen++;
}
/* T5. Output front of queue (T7. Remove from queue.) */
for (; q != NULL; q = q->tsi.tsi_suc) {
/* Mark the package as unqueued. */
q->tsi.tsi_reqx = 0;
rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s %s-%s-%s\n",
orderingCount, q->npreds, q->tsi.tsi_qcnt,
q->tree, q->depth,
2*q->depth, "",
q->name, q->version, q->release);
treex = q->tree;
depth = q->depth;
q->degree = 0;
ordering[orderingCount++] = q - ts->addedPackages.list;
qlen--;
loopcheck--;
/* T6. Erase relations. */
tsi_next = q->tsi.tsi_next;
q->tsi.tsi_next = NULL;
while ((tsi = tsi_next) != NULL) {
tsi_next = tsi->tsi_next;
tsi->tsi_next = NULL;
p = tsi->tsi_suc;
if (p && (--p->tsi.tsi_count) <= 0) {
p->tree = treex;
p->depth = depth + 1;
p->parent = q;
q->degree++;
/* XXX TODO: add control bit. */
p->tsi.tsi_suc = NULL;
/*@-nullstate@*/ /* FIX: q->tsi.tsi_u.suc may be NULL */
addQ(p, &q->tsi.tsi_suc, &r);
/*@=nullstate@*/
qlen++;
}
tsi = _free(tsi);
}
if (!_printed && loopcheck == qlen && q->tsi.tsi_suc != NULL) {
_printed++;
rpmMessage(RPMMESS_DEBUG,
_("========== successors only (presentation order)\n"));
/* Relink the queue in presentation order. */
tsi = &q->tsi;
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, p++) {
/* Is this element in the queue? */
if (p->tsi.tsi_reqx == 0)
/*@innercontinue@*/ continue;
tsi->tsi_suc = p;
tsi = &p->tsi;
}
tsi->tsi_suc = NULL;
}
}
/* T8. End of process. Check for loops. */
if (loopcheck != 0) {
int nzaps;
/* T9. Initialize predecessor chain. */
nzaps = 0;
if ((q = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, q++) {
q->tsi.tsi_pkg = NULL;
q->tsi.tsi_reqx = 0;
/* Mark packages already sorted. */
if (q->tsi.tsi_count == 0)
q->tsi.tsi_count = -1;
}
/* T10. Mark all packages with their predecessors. */
if ((q = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, q++) {
if ((tsi = q->tsi.tsi_next) == NULL)
continue;
q->tsi.tsi_next = NULL;
markLoop(tsi, q);
q->tsi.tsi_next = tsi;
}
/* T11. Print all dependency loops. */
if ((r = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, r++) {
int printed;
printed = 0;
/* T12. Mark predecessor chain, looking for start of loop. */
for (q = r->tsi.tsi_pkg; q != NULL; q = q->tsi.tsi_pkg) {
if (q->tsi.tsi_reqx)
/*@innerbreak@*/ break;
q->tsi.tsi_reqx = 1;
}
/* T13. Print predecessor chain from start of loop. */
while ((p = q) != NULL && (q = p->tsi.tsi_pkg) != NULL) {
const char * dp;
char buf[4096];
/* Unchain predecessor loop. */
p->tsi.tsi_pkg = NULL;
if (!printed) {
rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
printed = 1;
}
/* Find (and destroy if co-requisite) "q <- p" relation. */
dp = zapRelation(q, p, 1, &nzaps);
/* Print next member of loop. */
sprintf(buf, "%s-%s-%s", p->name, p->version, p->release);
rpmMessage(RPMMESS_DEBUG, " %-40s %s\n", buf,
(dp ? dp : "not found!?!"));
dp = _free(dp);
}
/* Walk (and erase) linear part of predecessor chain as well. */
for (p = r, q = r->tsi.tsi_pkg;
q != NULL;
p = q, q = q->tsi.tsi_pkg)
{
/* Unchain linear part of predecessor loop. */
p->tsi.tsi_pkg = NULL;
p->tsi.tsi_reqx = 0;
}
}
/* If a relation was eliminated, then continue sorting. */
/* XXX TODO: add control bit. */
if (nzaps && nrescans-- > 0) {
rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
goto rescan;
}
return 1;
}
/*
* The order ends up as installed packages followed by removed packages,
* with removes for upgrades immediately following the installation of
* the new package. This would be easier if we could sort the
* addedPackages array, but we store indexes into it in various places.
*/
orderList = xmalloc(npkgs * sizeof(*orderList));
for (i = 0, j = 0; i < ts->orderCount; i++) {
if (ts->order[i].type == TR_ADDED) {
orderList[j].alIndex = ts->order[i].u.addedIndex;
orderList[j].orIndex = i;
j++;
}
}
assert(j <= npkgs);
qsort(orderList, npkgs, sizeof(*orderList), orderListIndexCmp);
newOrder = xmalloc(ts->orderCount * sizeof(*newOrder));
for (i = 0, newOrderCount = 0; i < orderingCount; i++) {
struct orderListIndex * needle, key;
key.alIndex = ordering[i];
needle = bsearch(&key, orderList, npkgs, sizeof(key),orderListIndexCmp);
/* bsearch should never, ever fail */
if (needle == NULL) continue;
newOrder[newOrderCount++] = ts->order[needle->orIndex];
for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
if (ts->order[j].type == TR_REMOVED &&
ts->order[j].u.removed.dependsOnIndex == needle->alIndex) {
newOrder[newOrderCount++] = ts->order[j];
} else
/*@innerbreak@*/ break;
}
}
for (i = 0; i < ts->orderCount; i++) {
if (ts->order[i].type == TR_REMOVED &&
ts->order[i].u.removed.dependsOnIndex == -1) {
newOrder[newOrderCount++] = ts->order[i];
}
}
assert(newOrderCount == ts->orderCount);
ts->order = _free(ts->order);
ts->order = newOrder;
ts->orderAlloced = ts->orderCount;
orderList = _free(orderList);
return 0;
}
/**
* Close a single database index.
* @param db rpm database
* @param rpmtag rpm tag
* @return 0 on success
*/
static int rpmdbCloseDBI(/*@null@*/ rpmdb db, int rpmtag)
/*@ modifies db, fileSystem @*/
{
int dbix;
int rc = 0;
if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
return 0;
for (dbix = 0; dbix < dbiTagsMax; dbix++) {
if (dbiTags[dbix] != rpmtag)
continue;
if (db->_dbi[dbix] != NULL) {
int xx;
/*@-unqualifiedtrans@*/ /* FIX: double indirection. */
xx = dbiClose(db->_dbi[dbix], 0);
if (xx && rc == 0) rc = xx;
db->_dbi[dbix] = NULL;
/*@=unqualifiedtrans@*/
}
break;
}
return rc;
}
int rpmdepCheck(rpmTransactionSet ts,
rpmDependencyConflict * conflicts, int * numConflicts)
{
HGE_t hge = (HGE_t)headerGetEntryMinMemory;
HFD_t hfd = headerFreeData;
rpmdbMatchIterator mi = NULL;
Header h = NULL;
struct availablePackage * p;
problemsSet ps;
int npkgs;
int i, j;
int rc;
npkgs = ts->addedPackages.size;
ps = xcalloc(1, sizeof(*ps));
ps->alloced = 5;
ps->num = 0;
ps->problems = xcalloc(ps->alloced, sizeof(*ps->problems));
*conflicts = NULL;
*numConflicts = 0;
alMakeIndex(&ts->addedPackages);
alMakeIndex(&ts->availablePackages);
/*
* Look at all of the added packages and make sure their dependencies
* are satisfied.
*/
if ((p = ts->addedPackages.list) != NULL)
for (i = 0; i < npkgs; i++, p++)
{
rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n" ,
p->name, p->version, p->release);
rc = checkPackageDeps(ts, ps, p->h, NULL, p->multiLib);
if (rc)
goto exit;
/* Adding: check name against conflicts matches. */
rc = checkDependentConflicts(ts, ps, p->name);
if (rc)
goto exit;
if (p->providesCount == 0 || p->provides == NULL)
continue;
rc = 0;
for (j = 0; j < p->providesCount; j++) {
/* Adding: check provides key against conflicts matches. */
if (!checkDependentConflicts(ts, ps, p->provides[j]))
continue;
rc = 1;
/*@innerbreak@*/ break;
}
if (rc)
goto exit;
}
/*
* Look at the removed packages and make sure they aren't critical.
*/
if (ts->numRemovedPackages > 0) {
mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
(void) rpmdbAppendIterator(mi,
ts->removedPackages, ts->numRemovedPackages);
while ((h = rpmdbNextIterator(mi)) != NULL) {
{ const char * name, * version, * release;
(void) headerNVR(h, &name, &version, &release);
rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n" ,
name, version, release);
/* Erasing: check name against requiredby matches. */
rc = checkDependentPackages(ts, ps, name);
if (rc)
goto exit;
}
{ const char ** provides;
int providesCount;
rpmTagType pnt;
if (hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides,
&providesCount))
{
rc = 0;
for (j = 0; j < providesCount; j++) {
/* Erasing: check provides against requiredby matches. */
if (!checkDependentPackages(ts, ps, provides[j]))
continue;
rc = 1;
/*@innerbreak@*/ break;
}
provides = hfd(provides, pnt);
if (rc)
goto exit;
}
}
{ const char ** baseNames, ** dirNames;
int_32 * dirIndexes;
rpmTagType dnt, bnt;
int fileCount;
char * fileName = NULL;
int fileAlloced = 0;
int len;
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);
rc = 0;
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 (!checkDependentPackages(ts, ps, fileName))
continue;
rc = 1;
/*@innerbreak@*/ break;
}
fileName = _free(fileName);
baseNames = hfd(baseNames, bnt);
dirNames = hfd(dirNames, dnt);
if (rc)
goto exit;
}
}
}
mi = rpmdbFreeIterator(mi);
}
if (ps->num) {
*conflicts = ps->problems;
ps->problems = NULL;
*numConflicts = ps->num;
}
rc = 0;
exit:
mi = rpmdbFreeIterator(mi);
ps->problems = _free(ps->problems);
ps = _free(ps);
if (_cacheDependsRC)
(void) rpmdbCloseDBI(ts->rpmdb, RPMDBI_DEPENDS);
return rc;
}