order.c: factored from depends.c
This commit is contained in:
parent
3231024392
commit
797f0ff2a5
@ -29,7 +29,7 @@ LIBS =
|
||||
lib_LTLIBRARIES = librpm.la
|
||||
librpm_la_SOURCES = \
|
||||
al.c closeall.c cpio.c depends.c formats.c fs.c fsm.c getdate.c \
|
||||
header_internal.c manifest.c misc.c package.c \
|
||||
header_internal.c manifest.c misc.c order.c package.c \
|
||||
problems.c poptI.c poptK.c poptQV.c psm.c query.c \
|
||||
rpmchecksig.c rpminstall.c rpmlead.c rpmlibprov.c rpmrc.c \
|
||||
signature.c stringbuf.c transaction.c \
|
||||
|
606
lib/depends.c
606
lib/depends.c
@ -93,11 +93,6 @@ static /*@only@*/ const char *buildEVR(int_32 *e, const char *v, const char *r)
|
||||
}
|
||||
#endif
|
||||
|
||||
struct orderListIndex {
|
||||
int alIndex;
|
||||
int orIndex;
|
||||
};
|
||||
|
||||
/* parseEVR() moved to rpmvercmp.c */
|
||||
|
||||
const char *rpmNAME = PACKAGE;
|
||||
@ -885,607 +880,6 @@ static int checkDependentConflicts(rpmTransactionSet ts,
|
||||
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 * 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,
|
||||
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;
|
||||
int anaconda = 0;
|
||||
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 _printed = 0;
|
||||
int treex;
|
||||
int depth;
|
||||
int qlen;
|
||||
int i, j;
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (!( 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);
|
||||
|
||||
}
|
||||
|
||||
/* Then do co-requisites. */
|
||||
for (j = 0; j < p->requiresCount; j++) {
|
||||
|
||||
if (p->requireFlags == NULL) continue; /* XXX can't happen */
|
||||
|
||||
/* Skip if %pre/%post/%preun/%postun requires or legacy prereq. */
|
||||
|
||||
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 anaconda presentation order. */
|
||||
if (anaconda)
|
||||
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) {
|
||||
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;
|
||||
orderList = _free(orderList);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close a single database index.
|
||||
* @param db rpm database
|
||||
|
614
lib/order.c
Normal file
614
lib/order.c
Normal file
@ -0,0 +1,614 @@
|
||||
#include "system.h"
|
||||
#include "rpmlib.h"
|
||||
#include "debug.h"
|
||||
|
||||
#include "rpmmacro.h" /* XXX for rpmExpand() */
|
||||
|
||||
#include "depends.h"
|
||||
#include "al.h"
|
||||
|
||||
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 * 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,
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
|
||||
struct orderListIndex {
|
||||
int alIndex;
|
||||
int orIndex;
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
|
||||
int rpmdepOrder(rpmTransactionSet ts)
|
||||
{
|
||||
int npkgs = ts->addedPackages.size;
|
||||
int anaconda = 0;
|
||||
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 _printed = 0;
|
||||
int treex;
|
||||
int depth;
|
||||
int qlen;
|
||||
int i, j;
|
||||
|
||||
/* 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. */
|
||||
|
||||
if (!( 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);
|
||||
|
||||
}
|
||||
|
||||
/* Then do co-requisites. */
|
||||
for (j = 0; j < p->requiresCount; j++) {
|
||||
|
||||
if (p->requireFlags == NULL) continue; /* XXX can't happen */
|
||||
|
||||
/* Skip if %pre/%post/%preun/%postun requires or legacy prereq. */
|
||||
|
||||
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 anaconda presentation order. */
|
||||
if (anaconda)
|
||||
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) {
|
||||
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;
|
||||
orderList = _free(orderList);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user