7 #include <rpmcli.h> /* XXX rpmcliPackagesTotal */
9 #include <rpmmacro.h> /* XXX rpmExpand("%{_dependency_whiteout}" */
11 #include "rpmdb.h" /* XXX response cache needs dbiOpen et al. */
16 #define _RPMTE_INTERNAL
19 #define _RPMTS_INTERNAL
24 /*@access tsortInfo @*/
27 /*@access dbiIndex @*/ /* XXX for dbi->dbi_txnid */
29 /*@access alKey @*/ /* XXX for reordering and RPMAL_NOMATCH assign */
33 typedef /*@abstract@*/ struct orderListIndex_s * orderListIndex;
34 /*@access orderListIndex@*/
38 struct orderListIndex_s {
45 int _cacheDependsRC = 1;
47 /*@observer@*/ /*@unchecked@*/
48 const char *rpmNAME = PACKAGE;
50 /*@observer@*/ /*@unchecked@*/
51 const char *rpmEVR = VERSION;
54 int rpmFLAGS = RPMSENSE_EQUAL;
57 * Compare removed package instances (qsort/bsearch).
58 * @param a 1st instance address
59 * @param b 2nd instance address
60 * @return result of comparison
62 static int intcmp(const void * a, const void * b)
63 /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
67 int rc = (*aptr - *bptr);
72 * Add removed package instance to ordered transaction set.
73 * @param ts transaction set
75 * @param dboffset rpm database instance
76 * @param depends installed package of pair (or RPMAL_NOMATCH on erase)
77 * @return 0 on success
79 static int removePackage(rpmts ts, Header h, int dboffset,
80 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
81 /*@globals fileSystem @*/
82 /*@modifies ts, h, fileSystem @*/
86 /* Filter out duplicate erasures. */
87 if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
89 if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
90 sizeof(*ts->removedPackages), intcmp) != NULL)
95 if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
96 ts->allocedRemovedPackages += ts->delta;
97 ts->removedPackages = xrealloc(ts->removedPackages,
98 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
101 if (ts->removedPackages != NULL) { /* XXX can't happen. */
103 ts->removedPackages[ts->numRemovedPackages] = dboffset;
104 ts->numRemovedPackages++;
106 if (ts->numRemovedPackages > 1)
107 qsort(ts->removedPackages, ts->numRemovedPackages,
108 sizeof(*ts->removedPackages), intcmp);
111 if (ts->orderCount >= ts->orderAlloced) {
112 ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
113 /*@-type +voidabstract @*/
114 ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
115 /*@=type =voidabstract @*/
118 p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
120 ts->order[ts->orderCount] = p;
127 int rpmtsAddInstallElement(rpmts ts, Header h,
128 fnpyKey key, int upgrade, rpmRelocation * relocs)
130 uint_32 tscolor = rpmtsColor(ts);
133 rpmdbMatchIterator mi;
139 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
144 alKey pkgKey; /* addedPackages key */
151 * Check for previously added versions with the same name and arch/os.
152 * FIXME: only catches previously added, older packages.
154 add = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_LESS));
156 xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
158 xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
159 hcolor = hGetColor(h);
161 pkgKey = RPMAL_NOMATCH;
162 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
167 /* XXX Only added packages need be checked for dupes. */
168 if (rpmteType(p) == TR_REMOVED)
172 if (arch == NULL || (parch = rpmteA(p)) == NULL)
174 if (os == NULL || (pos = rpmteO(p)) == NULL)
176 if (strcmp(arch, parch) || strcmp(os, pos))
180 if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
181 continue; /* XXX can't happen */
183 rc = rpmdsCompare(add, this);
185 const char * pkgNEVR = rpmdsDNEVR(this);
186 const char * addNEVR = rpmdsDNEVR(add);
187 rpmMessage(RPMMESS_WARNING,
188 _("package %s was already added, replacing with %s\n"),
189 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
190 (addNEVR ? addNEVR + 2 : "?addNEVR?"));
192 pkgKey = rpmteAddedKey(p);
197 add = rpmdsFree(add);
199 isSource = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
201 if (oc >= ts->orderAlloced) {
202 ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
203 /*@-type +voidabstract @*/
204 ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
205 /*@=type =voidabstract @*/
208 p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
210 if (duplicate && oc < ts->orderCount) {
211 /*@-type -unqualifiedtrans@*/
213 ts->order[oc] = rpmteFree(ts->order[oc]);
215 /*@=type =unqualifiedtrans@*/
223 rpmcliPackagesTotal++;
226 pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
227 rpmteDS(p, RPMTAG_PROVIDENAME),
228 rpmteFI(p, RPMTAG_BASENAMES), tscolor);
229 if (pkgKey == RPMAL_NOMATCH) {
231 ts->order[oc] = rpmteFree(ts->order[oc]);
236 (void) rpmteSetAddedKey(p, pkgKey);
239 ts->numAddedPackages++;
245 /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
249 /* Do lazy (readonly?) open of rpm database. */
250 if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
251 if ((ec = rpmtsOpenDB(ts, ts->dbmode)) != 0)
255 /* On upgrade, erase older packages of same color (if any). */
257 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, rpmteN(p), 0);
258 while((oh = rpmdbNextIterator(mi)) != NULL) {
260 /* Ignore colored packages not in our rainbow. */
261 ohcolor = hGetColor(oh);
262 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
265 /* Skip packages that contain identical NEVR. */
266 if (rpmVersionCompare(h, oh) == 0)
269 xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), pkgKey);
271 mi = rpmdbFreeIterator(mi);
273 obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
274 obsoletes = rpmdsInit(obsoletes);
275 if (obsoletes != NULL)
276 while (rpmdsNext(obsoletes) >= 0) {
279 if ((Name = rpmdsN(obsoletes)) == NULL)
280 continue; /* XXX can't happen */
282 /* Ignore colored obsoletes not in our rainbow. */
283 dscolor = rpmdsColor(obsoletes);
284 if (tscolor && dscolor && !(tscolor & dscolor))
287 /* XXX avoid self-obsoleting packages. */
288 if (!strcmp(rpmteN(p), Name))
291 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
293 xx = rpmdbPruneIterator(mi,
294 ts->removedPackages, ts->numRemovedPackages, 1);
296 while((oh = rpmdbNextIterator(mi)) != NULL) {
297 /* Ignore colored packages not in our rainbow. */
298 ohcolor = hGetColor(oh);
299 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
300 /*@innercontinue@*/ continue;
303 * Rpm prior to 3.0.3 does not have versioned obsoletes.
304 * If no obsoletes version info is available, match all names.
306 if (rpmdsEVR(obsoletes) == NULL
307 || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote))
308 xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), pkgKey);
310 mi = rpmdbFreeIterator(mi);
312 obsoletes = rpmdsFree(obsoletes);
321 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
323 return removePackage(ts, h, dboffset, RPMAL_NOMATCH);
327 * Check dep for an unsatisfied dependency.
328 * @param ts transaction set
329 * @param dep dependency
330 * @param adding dependency is from added package set?
331 * @return 0 if satisfied, 1 if not satisfied, 2 if error
333 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
334 /*@globals _cacheDependsRC, rpmGlobalMacroContext,
335 fileSystem, internalState @*/
336 /*@modifies ts, _cacheDependsRC, rpmGlobalMacroContext,
337 fileSystem, internalState @*/
339 DBT * key = alloca(sizeof(*key));
340 DBT * data = alloca(sizeof(*data));
341 rpmdbMatchIterator mi;
344 int _cacheThisRC = 1;
349 if ((Name = rpmdsN(dep)) == NULL)
350 return 0; /* XXX can't happen */
353 * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
355 if (_cacheDependsRC) {
357 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
365 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
366 DBC * dbcursor = NULL;
369 size_t DNEVRlen = strlen(DNEVR);
371 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
373 memset(key, 0, sizeof(*key));
374 /*@i@*/ key->data = (void *) DNEVR;
375 key->size = DNEVRlen;
376 memset(data, 0, sizeof(*data));
378 data->size = datalen;
379 /*@-nullstate@*/ /* FIX: data->data may be NULL */
380 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
383 DNEVRlen = key->size;
385 datalen = data->size;
388 if (xx == 0 && datap && datalen == 4)
389 memcpy(&rc, datap, datalen);
391 xx = dbiCclose(dbi, dbcursor, 0);
396 rpmdsNotify(dep, _("(cached)"), rc);
403 rc = 0; /* assume dependency is satisfied */
405 #if defined(DYING) || defined(__LCLINT__)
406 { static /*@observer@*/ const char noProvidesString[] = "nada";
407 static /*@observer@*/ const char * rcProvidesString = noProvidesString;
408 int_32 Flags = rpmdsFlags(dep);
412 if (rcProvidesString == noProvidesString)
413 rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
415 if (rcProvidesString != NULL && !(Flags & RPMSENSE_SENSEMASK)) {
418 /*@-observertrans -mayaliasunique@*/
419 while ((start = strstr(rcProvidesString, Name))) {
420 /*@=observertrans =mayaliasunique@*/
422 if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
423 rpmdsNotify(dep, _("(rpmrc provides)"), rc);
427 rcProvidesString = start + 1;
434 * New features in rpm packaging implicitly add versioned dependencies
435 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
436 * Check those dependencies now.
438 if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1)) {
439 if (rpmCheckRpmlibProvides(dep)) {
440 rpmdsNotify(dep, _("(rpmlib provides)"), rc);
446 /* Search added packages for the dependency. */
447 if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
449 * XXX Ick, context sensitive answers from dependency cache.
450 * XXX Always resolve added dependencies within context to disambiguate.
452 if (_rpmds_nopromote)
457 /* XXX only the installer does not have the database open here. */
458 if (rpmtsGetRdb(ts) != NULL) {
460 if (Name[0] == '/') {
461 /* depFlags better be 0! */
463 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
465 (void) rpmdbPruneIterator(mi,
466 ts->removedPackages, ts->numRemovedPackages, 1);
468 while ((h = rpmdbNextIterator(mi)) != NULL) {
469 rpmdsNotify(dep, _("(db files)"), rc);
470 mi = rpmdbFreeIterator(mi);
473 mi = rpmdbFreeIterator(mi);
477 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
478 (void) rpmdbPruneIterator(mi,
479 ts->removedPackages, ts->numRemovedPackages, 1);
480 while ((h = rpmdbNextIterator(mi)) != NULL) {
481 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
482 rpmdsNotify(dep, _("(db provides)"), rc);
483 mi = rpmdbFreeIterator(mi);
487 mi = rpmdbFreeIterator(mi);
489 #if defined(DYING) || defined(__LCLINT__)
490 mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
491 (void) rpmdbPruneIterator(mi,
492 ts->removedPackages, ts->numRemovedPackages, 1);
493 while ((h = rpmdbNextIterator(mi)) != NULL) {
494 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
495 rpmdsNotify(dep, _("(db package)"), rc);
496 mi = rpmdbFreeIterator(mi);
500 mi = rpmdbFreeIterator(mi);
506 * Search for an unsatisfied dependency.
509 if (adding && !retrying && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST)) {
510 if (ts->solve != NULL) {
511 xx = (*ts->solve) (ts, dep, ts->solveData);
516 rpmalMakeIndex(ts->addedPackages);
524 rc = 1; /* dependency is unsatisfied */
525 rpmdsNotify(dep, NULL, rc);
529 * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
531 if (_cacheDependsRC && _cacheThisRC) {
533 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
540 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
541 DBC * dbcursor = NULL;
542 size_t DNEVRlen = strlen(DNEVR);
544 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
546 memset(key, 0, sizeof(*key));
547 /*@i@*/ key->data = (void *) DNEVR;
548 key->size = DNEVRlen;
549 memset(data, 0, sizeof(*data));
551 data->size = sizeof(rc);
554 xx = dbiPut(dbi, dbcursor, key, data, 0);
556 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
567 * Check added requires/conflicts against against installed+added packages.
568 * @param ts transaction set
569 * @param pkgNEVR package name-version-release
570 * @param requires Requires: dependencies (or NULL)
571 * @param conflicts Conflicts: dependencies (or NULL)
572 * @param depName dependency name to filter (or NULL)
573 * @param tscolor color bits for transaction set (0 disables)
574 * @param adding dependency is from added package set?
575 * @return 0 no problems found
577 static int checkPackageDeps(rpmts ts, const char * pkgNEVR,
578 /*@null@*/ rpmds requires, /*@null@*/ rpmds conflicts,
579 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
580 /*@globals rpmGlobalMacroContext,
581 fileSystem, internalState @*/
582 /*@modifies ts, requires, conflicts, rpmGlobalMacroContext,
583 fileSystem, internalState */
590 requires = rpmdsInit(requires);
591 if (requires != NULL)
592 while (!ourrc && rpmdsNext(requires) >= 0) {
594 if ((Name = rpmdsN(requires)) == NULL)
595 continue; /* XXX can't happen */
597 /* Filter out requires that came along for the ride. */
598 if (depName != NULL && strcmp(depName, Name))
601 /* Ignore colored requires not in our rainbow. */
602 dscolor = rpmdsColor(requires);
603 if (tscolor && dscolor && !(tscolor & dscolor))
606 rc = unsatisfiedDepend(ts, requires, adding);
609 case 0: /* requirements are satisfied. */
610 /*@switchbreak@*/ break;
611 case 1: /* requirements are not satisfied. */
612 { fnpyKey * suggestedKeys = NULL;
615 if (ts->availablePackages != NULL) {
616 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
621 rpmdsProblem(ts->probs, pkgNEVR, requires, suggestedKeys, adding);
624 /*@switchbreak@*/ break;
625 case 2: /* something went wrong! */
628 /*@switchbreak@*/ break;
632 conflicts = rpmdsInit(conflicts);
633 if (conflicts != NULL)
634 while (!ourrc && rpmdsNext(conflicts) >= 0) {
636 if ((Name = rpmdsN(conflicts)) == NULL)
637 continue; /* XXX can't happen */
639 /* Filter out conflicts that came along for the ride. */
640 if (depName != NULL && strcmp(depName, Name))
643 /* Ignore colored conflicts not in our rainbow. */
644 dscolor = rpmdsColor(conflicts);
645 if (tscolor && dscolor && !(tscolor & dscolor))
648 rc = unsatisfiedDepend(ts, conflicts, adding);
650 /* 1 == unsatisfied, 0 == satsisfied */
652 case 0: /* conflicts exist. */
653 rpmdsProblem(ts->probs, pkgNEVR, conflicts, NULL, adding);
654 /*@switchbreak@*/ break;
655 case 1: /* conflicts don't exist. */
656 /*@switchbreak@*/ break;
657 case 2: /* something went wrong! */
660 /*@switchbreak@*/ break;
668 * Check dependency against installed packages.
669 * Adding: check name/provides dep against each conflict match,
670 * Erasing: check name/provides/filename dep against each requiredby match.
671 * @param ts transaction set
672 * @param dep dependency name
673 * @param mi rpm database iterator
674 * @param adding dependency is from added package set?
675 * @return 0 no problems found
677 static int checkPackageSet(rpmts ts, const char * dep,
678 /*@only@*/ /*@null@*/ rpmdbMatchIterator mi, int adding)
679 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
680 /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
686 (void) rpmdbPruneIterator(mi,
687 ts->removedPackages, ts->numRemovedPackages, 1);
688 while ((h = rpmdbNextIterator(mi)) != NULL) {
689 const char * pkgNEVR;
690 rpmds requires, conflicts;
693 pkgNEVR = hGetNEVR(h, NULL);
694 requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
695 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
696 conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
697 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
698 rc = checkPackageDeps(ts, pkgNEVR, requires, conflicts, dep, 0, adding);
699 conflicts = rpmdsFree(conflicts);
700 requires = rpmdsFree(requires);
701 pkgNEVR = _free(pkgNEVR);
708 mi = rpmdbFreeIterator(mi);
714 * Check to-be-erased dependencies against installed requires.
715 * @param ts transaction set
716 * @param dep requires name
717 * @return 0 no problems found
719 static int checkDependentPackages(rpmts ts, const char * dep)
720 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
721 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
723 rpmdbMatchIterator mi;
724 mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, dep, 0);
725 return checkPackageSet(ts, dep, mi, 0);
729 * Check to-be-added dependencies against installed conflicts.
730 * @param ts transaction set
731 * @param dep conflicts name
732 * @return 0 no problems found
734 static int checkDependentConflicts(rpmts ts, const char * dep)
735 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
736 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
740 if (rpmtsGetRdb(ts) != NULL) { /* XXX is this necessary? */
741 rpmdbMatchIterator mi;
742 mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, dep, 0);
743 rc = checkPackageSet(ts, dep, mi, 1);
750 /*@observer@*/ /*@owned@*/ /*@null@*/
752 /*@observer@*/ /*@dependent@*/ /*@null@*/
757 static struct badDeps_s {
758 /*@observer@*/ /*@null@*/ const char * pname;
759 /*@observer@*/ /*@null@*/ const char * qname;
761 { "libtermcap", "bash" },
762 { "modutils", "vixie-cron" },
763 { "ypbind", "yp-tools" },
764 { "ghostscript-fonts", "ghostscript" },
766 { "libgnomeprint15", "gnome-print" },
767 { "nautilus", "nautilus-mozilla" },
769 { "arts", "kdelibs-sound" },
771 { "pango-gtkbeta-devel", "pango-gtkbeta" },
772 { "XFree86", "Mesa" },
773 { "compat-glibc", "db2" },
774 { "compat-glibc", "db1" },
775 { "pam", "initscripts" },
776 { "initscripts", "sysklogd" },
778 { "egcs-c++", "libstdc++" },
780 { "pilot-link-devel", "pilot-link" },
782 { "pam", "pamconfig" },
787 static int badDepsInitialized = 0;
789 /*@unchecked@*/ /*@only@*/ /*@null@*/
790 static struct badDeps_s * badDeps = NULL;
795 /*@-modobserver -observertrans @*/
796 static void freeBadDeps(void)
797 /*@globals badDeps, badDepsInitialized @*/
798 /*@modifies badDeps, badDepsInitialized @*/
801 struct badDeps_s * bdp;
802 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
803 bdp->pname = _free(bdp->pname);
804 badDeps = _free(badDeps);
806 badDepsInitialized = 0;
808 /*@=modobserver =observertrans @*/
811 * Check for dependency relations to be ignored.
813 * @param p successor element (i.e. with Requires: )
814 * @param q predecessor element (i.e. with Provides: )
815 * @return 1 if dependency is to be ignored.
818 static int ignoreDep(const rpmte p, const rpmte q)
819 /*@globals badDeps, badDepsInitialized @*/
820 /*@modifies badDeps, badDepsInitialized @*/
822 struct badDeps_s * bdp;
825 if (!badDepsInitialized) {
826 char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
827 const char ** av = NULL;
831 if (s != NULL && *s != '\0'
832 && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
833 && ac > 0 && av != NULL)
835 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
836 for (i = 0; i < ac; i++, bdp++) {
837 char * pname, * qname;
841 pname = xstrdup(av[i]);
842 if ((qname = strchr(pname, '>')) != NULL)
848 rpmMessage(RPMMESS_DEBUG,
849 _("ignore package name relation(s) [%d]\t%s -> %s\n"),
850 i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
857 badDepsInitialized++;
863 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
864 if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
873 * Recursively mark all nodes with their predecessors.
874 * @param tsi successor chain
875 * @param q predecessor
877 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
878 /*@globals internalState @*/
880 /*@modifies internalState @*/
884 /*@-branchstate@*/ /* FIX: q is kept */
885 while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
887 if (rpmteTSI(p)->tsi_chain != NULL)
889 /*@-assignexpose -temptrans@*/
890 rpmteTSI(p)->tsi_chain = q;
891 /*@=assignexpose =temptrans@*/
892 if (rpmteTSI(p)->tsi_next != NULL)
893 markLoop(rpmteTSI(p)->tsi_next, p);
898 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
901 if (isLegacyPreReq(f))
904 if (f & RPMSENSE_SCRIPT_PRE)
905 return "Requires(pre):";
906 if (f & RPMSENSE_SCRIPT_POST)
907 return "Requires(post):";
908 if (f & RPMSENSE_SCRIPT_PREUN)
909 return "Requires(preun):";
910 if (f & RPMSENSE_SCRIPT_POSTUN)
911 return "Requires(postun):";
912 if (f & RPMSENSE_SCRIPT_VERIFY)
913 return "Requires(verify):";
914 if (f & RPMSENSE_FIND_REQUIRES)
915 return "Requires(auto):";
920 * Find (and eliminate co-requisites) "q <- p" relation in dependency loop.
921 * Search all successors of q for instance of p. Format the specific relation,
922 * (e.g. p contains "Requires: q"). Unlink and free co-requisite (i.e.
923 * pure Requires: dependencies) successor node(s).
924 * @param q sucessor (i.e. package required by p)
925 * @param p predecessor (i.e. package that "Requires: q")
926 * @param requires relation
927 * @param zap max. no. of co-requisites to remove (-1 is all)?
928 * @retval nzaps address of no. of relations removed
929 * @return (possibly NULL) formatted "q <- p" releation (malloc'ed)
932 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
933 static /*@owned@*/ /*@null@*/ const char *
934 zapRelation(rpmte q, rpmte p,
935 /*@null@*/ rpmds requires,
936 int zap, /*@in@*/ /*@out@*/ int * nzaps)
937 /*@modifies q, p, requires, *nzaps @*/
941 const char *dp = NULL;
943 for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
945 /* XXX Note: the loop traverses "not found", break on "found". */
947 tsi_prev = tsi, tsi = tsi->tsi_next)
952 /*@-abstractcompare@*/
953 if (tsi->tsi_suc != p)
955 /*@=abstractcompare@*/
957 if (requires == NULL) continue; /* XXX can't happen */
959 (void) rpmdsSetIx(requires, tsi->tsi_reqx);
961 Flags = rpmdsFlags(requires);
963 dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
966 * Attempt to unravel a dependency loop by eliminating Requires's.
969 if (zap && !(Flags & RPMSENSE_PREREQ)) {
970 rpmMessage(RPMMESS_DEBUG,
971 _("removing %s \"%s\" from tsort relations.\n"),
972 (rpmteNEVR(p) ? rpmteNEVR(p) : "???"), dp);
973 rpmteTSI(p)->tsi_count--;
974 if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
975 tsi->tsi_next = NULL;
984 /* XXX Note: the loop traverses "not found", get out now! */
993 * Record next "q <- p" relation (i.e. "p" requires "q").
994 * @param ts transaction set
995 * @param p predecessor (i.e. package that "Requires: q")
996 * @param selected boolean package selected array
997 * @param requires relation
1001 static inline int addRelation(rpmts ts,
1002 /*@dependent@*/ rpmte p,
1003 unsigned char * selected,
1005 /*@globals fileSystem, internalState @*/
1006 /*@modifies ts, p, *selected, fileSystem, internalState @*/
1015 if ((Name = rpmdsN(requires)) == NULL)
1018 /* Avoid rpmlib feature dependencies. */
1019 if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
1022 /* Avoid package config dependencies. */
1023 if (!strncmp(Name, "config(", sizeof("config(")-1))
1026 pkgKey = RPMAL_NOMATCH;
1027 key = rpmalSatisfiesDepend(ts->addedPackages, requires, &pkgKey);
1029 /* Ordering depends only on added package relations. */
1030 if (pkgKey == RPMAL_NOMATCH)
1033 /* XXX Set q to the added package that has pkgKey == q->u.addedKey */
1034 /* XXX FIXME: bsearch is possible/needed here */
1035 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
1037 /* XXX Only added packages need be checked for matches. */
1038 if (rpmteType(q) == TR_REMOVED)
1041 if (pkgKey == rpmteAddedKey(q))
1044 qi = rpmtsiFree(qi);
1045 if (q == NULL || i == ts->orderCount)
1048 /* Avoid certain dependency relations. */
1049 if (ignoreDep(p, q))
1052 /* Avoid redundant relations. */
1053 /* XXX TODO: add control bit. */
1055 if (selected[i] != 0)
1062 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1063 rpmteTSI(p)->tsi_count++; /* bump p predecessor count */
1065 if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
1066 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
1068 tsi = xcalloc(1, sizeof(*tsi));
1071 tsi->tsi_reqx = rpmdsIx(requires);
1073 tsi->tsi_next = rpmteTSI(q)->tsi_next;
1075 rpmteTSI(q)->tsi_next = tsi;
1076 rpmteTSI(q)->tsi_qcnt++; /* bump q successor count */
1083 * Compare ordered list entries by index (qsort/bsearch).
1084 * @param one 1st ordered list entry
1085 * @param two 2nd ordered list entry
1086 * @return result of comparison
1088 static int orderListIndexCmp(const void * one, const void * two) /*@*/
1091 long a = (long) ((const orderListIndex)one)->pkgKey;
1092 long b = (long) ((const orderListIndex)two)->pkgKey;
1098 * Add element to list sorting by tsi_qcnt.
1099 * @param p new element
1100 * @retval qp address of first element
1101 * @retval rp address of last element
1105 static void addQ(/*@dependent@*/ rpmte p,
1106 /*@in@*/ /*@out@*/ rpmte * qp,
1107 /*@in@*/ /*@out@*/ rpmte * rp)
1108 /*@modifies p, *qp, *rp @*/
1112 /* Mark the package as queued. */
1113 rpmteTSI(p)->tsi_reqx = 1;
1115 if ((*rp) == NULL) { /* 1st element */
1116 /*@-dependenttrans@*/ /* FIX: double indirection */
1118 /*@=dependenttrans@*/
1122 /* Find location in queue using metric tsi_qcnt. */
1123 for (qprev = NULL, q = (*qp);
1125 qprev = q, q = rpmteTSI(q)->tsi_suc)
1127 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
1131 if (qprev == NULL) { /* insert at beginning of list */
1132 rpmteTSI(p)->tsi_suc = q;
1133 /*@-dependenttrans@*/
1134 (*qp) = p; /* new head */
1135 /*@=dependenttrans@*/
1136 } else if (q == NULL) { /* insert at end of list */
1137 rpmteTSI(qprev)->tsi_suc = p;
1138 /*@-dependenttrans@*/
1139 (*rp) = p; /* new tail */
1140 /*@=dependenttrans@*/
1141 } else { /* insert between qprev and q */
1142 rpmteTSI(p)->tsi_suc = q;
1143 rpmteTSI(qprev)->tsi_suc = p;
1150 int rpmtsOrder(rpmts ts)
1154 int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
1161 int orderingCount = 0;
1162 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
1165 int newOrderCount = 0;
1166 orderListIndex orderList;
1179 rpmalMakeIndex(ts->addedPackages);
1182 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
1184 /* T1. Initialize. */
1186 numOrderList = ts->orderCount;
1189 if (oType & TR_ADDED)
1190 numOrderList += ts->numAddedPackages;
1191 if (oType & TR_REMOVED)
1192 numOrderList += ts->numRemovedPackages;
1194 ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
1195 loopcheck = numOrderList;
1198 pi = rpmtsiInit(ts);
1199 while ((p = rpmtsiNext(pi, oType)) != NULL)
1201 pi = rpmtsiFree(pi);
1203 /* Record all relations. */
1204 rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
1205 pi = rpmtsiInit(ts);
1206 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1208 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
1211 memset(selected, 0, sizeof(*selected) * ts->orderCount);
1213 /* Avoid narcisstic relations. */
1214 selected[rpmtsiOc(pi)] = 1;
1216 /* T2. Next "q <- p" relation. */
1218 /* First, do pre-requisites. */
1219 requires = rpmdsInit(requires);
1220 if (requires != NULL)
1221 while (rpmdsNext(requires) >= 0) {
1223 Flags = rpmdsFlags(requires);
1225 switch (rpmteType(p)) {
1227 /* Skip if not %preun/%postun requires or legacy prereq. */
1228 if (isInstallPreReq(Flags)
1229 || !( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1230 /*@innercontinue@*/ continue;
1231 /*@switchbreak@*/ break;
1233 /* Skip if not %pre/%post requires or legacy prereq. */
1234 if (isErasePreReq(Flags)
1235 || !( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1236 /*@innercontinue@*/ continue;
1237 /*@switchbreak@*/ break;
1240 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1241 (void) addRelation(ts, p, selected, requires);
1245 /* Then do co-requisites. */
1246 requires = rpmdsInit(requires);
1247 if (requires != NULL)
1248 while (rpmdsNext(requires) >= 0) {
1250 Flags = rpmdsFlags(requires);
1252 switch (rpmteType(p)) {
1254 /* Skip if %preun/%postun requires or legacy prereq. */
1255 if (isInstallPreReq(Flags)
1256 || ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1257 /*@innercontinue@*/ continue;
1258 /*@switchbreak@*/ break;
1260 /* Skip if %pre/%post requires or legacy prereq. */
1261 if (isErasePreReq(Flags)
1262 || ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1263 /*@innercontinue@*/ continue;
1264 /*@switchbreak@*/ break;
1267 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1268 (void) addRelation(ts, p, selected, requires);
1272 pi = rpmtsiFree(pi);
1274 /* Save predecessor count and mark tree roots. */
1276 pi = rpmtsiInit(ts);
1277 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1280 npreds = rpmteTSI(p)->tsi_count;
1282 (void) rpmteSetNpreds(p, npreds);
1285 (void) rpmteSetTree(p, treex++);
1287 (void) rpmteSetTree(p, -1);
1289 (void) rpmteSetParent(p, NULL);
1293 pi = rpmtsiFree(pi);
1295 /* T4. Scan for zeroes. */
1296 rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
1299 if (pi != NULL) pi = rpmtsiFree(pi);
1302 pi = rpmtsiInit(ts);
1303 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1305 /* Prefer packages in chainsaw or anaconda presentation order. */
1307 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
1309 if (rpmteTSI(p)->tsi_count != 0)
1311 rpmteTSI(p)->tsi_suc = NULL;
1315 pi = rpmtsiFree(pi);
1317 /* T5. Output front of queue (T7. Remove from queue.) */
1318 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
1320 /* Mark the package as unqueued. */
1321 rpmteTSI(q)->tsi_reqx = 0;
1324 switch (rpmteType(q)) {
1326 if (!(oType & TR_ADDED))
1328 /*@switchbreak@*/ break;
1330 if (!(oType & TR_REMOVED))
1332 /*@switchbreak@*/ break;
1335 /*@notreached@*/ /*@switchbreak@*/ break;
1337 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
1339 rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s%c%s\n",
1340 orderingCount, rpmteNpreds(q),
1341 rpmteTSI(q)->tsi_qcnt, rpmteTree(q), rpmteDepth(q),
1342 (2 * rpmteDepth(q)), "",
1344 (rpmteNEVR(q) ? rpmteNEVR(q) : "???"));
1346 treex = rpmteTree(q);
1347 depth = rpmteDepth(q);
1348 (void) rpmteSetDegree(q, 0);
1349 tsbytes += rpmtePkgFileSize(q);
1351 ordering[orderingCount] = rpmteAddedKey(q);
1356 /* T6. Erase relations. */
1357 tsi_next = rpmteTSI(q)->tsi_next;
1358 rpmteTSI(q)->tsi_next = NULL;
1359 while ((tsi = tsi_next) != NULL) {
1360 tsi_next = tsi->tsi_next;
1361 tsi->tsi_next = NULL;
1363 if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
1365 (void) rpmteSetTree(p, treex);
1366 (void) rpmteSetDepth(p, depth+1);
1367 (void) rpmteSetParent(p, q);
1368 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
1370 /* XXX TODO: add control bit. */
1371 rpmteTSI(p)->tsi_suc = NULL;
1372 addQ(p, &rpmteTSI(q)->tsi_suc, &r);
1377 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
1379 (void) rpmtsUnorderedSuccessors(ts, orderingCount);
1380 rpmMessage(RPMMESS_DEBUG,
1381 _("========== successors only (%d bytes)\n"), (int)tsbytes);
1383 /* Relink the queue in presentation order. */
1385 pi = rpmtsiInit(ts);
1386 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1387 /* Is this element in the queue? */
1388 if (rpmteTSI(p)->tsi_reqx == 0)
1389 /*@innercontinue@*/ continue;
1393 pi = rpmtsiFree(pi);
1394 tsi->tsi_suc = NULL;
1398 /* T8. End of process. Check for loops. */
1399 if (loopcheck != 0) {
1402 /* T9. Initialize predecessor chain. */
1404 qi = rpmtsiInit(ts);
1405 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1406 rpmteTSI(q)->tsi_chain = NULL;
1407 rpmteTSI(q)->tsi_reqx = 0;
1408 /* Mark packages already sorted. */
1409 if (rpmteTSI(q)->tsi_count == 0)
1410 rpmteTSI(q)->tsi_count = -1;
1412 qi = rpmtsiFree(qi);
1414 /* T10. Mark all packages with their predecessors. */
1415 qi = rpmtsiInit(ts);
1416 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1417 if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
1419 rpmteTSI(q)->tsi_next = NULL;
1421 rpmteTSI(q)->tsi_next = tsi;
1423 qi = rpmtsiFree(qi);
1425 /* T11. Print all dependency loops. */
1426 ri = rpmtsiInit(ts);
1427 while ((r = rpmtsiNext(ri, oType)) != NULL)
1433 /* T12. Mark predecessor chain, looking for start of loop. */
1434 for (q = rpmteTSI(r)->tsi_chain; q != NULL;
1435 q = rpmteTSI(q)->tsi_chain)
1437 if (rpmteTSI(q)->tsi_reqx)
1438 /*@innerbreak@*/ break;
1439 rpmteTSI(q)->tsi_reqx = 1;
1442 /* T13. Print predecessor chain from start of loop. */
1443 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
1447 /* Unchain predecessor loop. */
1448 rpmteTSI(p)->tsi_chain = NULL;
1451 rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
1455 /* Find (and destroy if co-requisite) "q <- p" relation. */
1456 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
1457 requires = rpmdsInit(requires);
1458 if (requires == NULL)
1459 /*@innercontinue@*/ continue; /* XXX can't happen */
1460 dp = zapRelation(q, p, requires, 1, &nzaps);
1462 /* Print next member of loop. */
1464 if (rpmteNEVR(p) != NULL)
1465 (void) stpcpy(buf, rpmteNEVR(p));
1466 rpmMessage(RPMMESS_DEBUG, " %-40s %s\n", buf,
1467 (dp ? dp : "not found!?!"));
1472 /* Walk (and erase) linear part of predecessor chain as well. */
1473 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
1474 p = q, q = rpmteTSI(q)->tsi_chain)
1476 /* Unchain linear part of predecessor loop. */
1477 rpmteTSI(p)->tsi_chain = NULL;
1478 rpmteTSI(p)->tsi_reqx = 0;
1481 ri = rpmtsiFree(ri);
1483 /* If a relation was eliminated, then continue sorting. */
1484 /* XXX TODO: add control bit. */
1485 if (nzaps && nrescans-- > 0) {
1486 rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
1490 /* Return no. of packages that could not be ordered. */
1491 rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
1496 /* Clean up tsort remnants (if any). */
1497 pi = rpmtsiInit(ts);
1498 while ((p = rpmtsiNext(pi, 0)) != NULL)
1500 pi = rpmtsiFree(pi);
1503 * The order ends up as installed packages followed by removed packages,
1504 * with removes for upgrades immediately following the installation of
1505 * the new package. This would be easier if we could sort the
1506 * addedPackages array, but we store indexes into it in various places.
1508 orderList = xcalloc(numOrderList, sizeof(*orderList));
1510 pi = rpmtsiInit(ts);
1511 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1512 /* Prepare added package ordering permutation. */
1513 switch (rpmteType(p)) {
1515 orderList[j].pkgKey = rpmteAddedKey(p);
1516 /*@switchbreak@*/ break;
1518 orderList[j].pkgKey = RPMAL_NOMATCH;
1519 /*@switchbreak@*/ break;
1521 orderList[j].orIndex = rpmtsiOc(pi);
1524 pi = rpmtsiFree(pi);
1526 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
1529 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
1532 for (i = 0, newOrderCount = 0; i < orderingCount; i++)
1534 struct orderListIndex_s key;
1535 orderListIndex needle;
1537 key.pkgKey = ordering[i];
1538 needle = bsearch(&key, orderList, numOrderList,
1539 sizeof(key), orderListIndexCmp);
1540 /* bsearch should never, ever fail */
1544 j = needle->orIndex;
1545 if ((q = ts->order[j]) == NULL)
1548 newOrder[newOrderCount++] = q;
1549 ts->order[j] = NULL;
1551 for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
1552 if ((q = ts->order[j]) == NULL)
1553 /*@innerbreak@*/ break;
1554 if (rpmteType(q) == TR_REMOVED
1555 && rpmteDependsOnKey(q) == needle->pkgKey)
1557 newOrder[newOrderCount++] = q;
1558 ts->order[j] = NULL;
1560 /*@innerbreak@*/ break;
1565 for (j = 0; j < ts->orderCount; j++) {
1566 if ((p = ts->order[j]) == NULL)
1568 newOrder[newOrderCount++] = p;
1569 ts->order[j] = NULL;
1571 assert(newOrderCount == ts->orderCount);
1574 ts->order = _free(ts->order);
1576 ts->order = newOrder;
1577 ts->orderAlloced = ts->orderCount;
1578 orderList = _free(orderList);
1580 #ifdef DYING /* XXX now done at the CLI level just before rpmtsRun(). */
1585 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
1591 int rpmtsCheck(rpmts ts)
1593 uint_32 tscolor = rpmtsColor(ts);
1594 rpmdbMatchIterator mi = NULL;
1595 rpmtsi pi = NULL; rpmte p;
1596 int closeatexit = 0;
1600 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1602 /* Do lazy, readonly, open of rpm database. */
1603 if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
1604 if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
1609 ts->probs = rpmpsFree(ts->probs);
1610 ts->probs = rpmpsCreate();
1612 rpmalMakeIndex(ts->addedPackages);
1615 * Look at all of the added packages and make sure their dependencies
1618 pi = rpmtsiInit(ts);
1619 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1622 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1623 rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
1624 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1626 rc = checkPackageDeps(ts, rpmteNEVR(p),
1627 rpmteDS(p, RPMTAG_REQUIRENAME),
1628 rpmteDS(p, RPMTAG_CONFLICTNAME),
1634 #if defined(DYING) || defined(__LCLINT__)
1635 /* XXX all packages now have Provides: name = version-release */
1636 /* Adding: check name against conflicts matches. */
1637 rc = checkDependentConflicts(ts, rpmteN(p));
1643 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1644 provides = rpmdsInit(provides);
1645 if (provides == NULL || rpmdsN(provides) == NULL)
1647 while (rpmdsNext(provides) >= 0) {
1650 if ((Name = rpmdsN(provides)) == NULL)
1651 /*@innercontinue@*/ continue; /* XXX can't happen */
1653 /* Adding: check provides key against conflicts matches. */
1654 if (!checkDependentConflicts(ts, Name))
1655 /*@innercontinue@*/ continue;
1657 /*@innerbreak@*/ break;
1662 pi = rpmtsiFree(pi);
1665 * Look at the removed packages and make sure they aren't critical.
1667 pi = rpmtsiInit(ts);
1668 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1672 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1673 rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
1674 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1677 #if defined(DYING) || defined(__LCLINT__)
1678 /* XXX all packages now have Provides: name = version-release */
1679 /* Erasing: check name against requiredby matches. */
1680 rc = checkDependentPackages(ts, rpmteN(p));
1686 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1687 provides = rpmdsInit(provides);
1688 if (provides != NULL)
1689 while (rpmdsNext(provides) >= 0) {
1692 if ((Name = rpmdsN(provides)) == NULL)
1693 /*@innercontinue@*/ continue; /* XXX can't happen */
1695 /* Erasing: check provides against requiredby matches. */
1696 if (!checkDependentPackages(ts, Name))
1697 /*@innercontinue@*/ continue;
1699 /*@innerbreak@*/ break;
1705 fi = rpmteFI(p, RPMTAG_BASENAMES);
1706 fi = rpmfiInit(fi, 0);
1707 while (rpmfiNext(fi) >= 0) {
1708 const char * fn = rpmfiFN(fi);
1710 /* Erasing: check filename against requiredby matches. */
1711 if (!checkDependentPackages(ts, fn))
1712 /*@innercontinue@*/ continue;
1714 /*@innerbreak@*/ break;
1719 pi = rpmtsiFree(pi);
1724 mi = rpmdbFreeIterator(mi);
1725 pi = rpmtsiFree(pi);
1727 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1731 xx = rpmtsCloseDB(ts);
1732 else if (_cacheDependsRC)
1733 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);