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, rpmGlobalMacroContext @*/
820 /*@modifies badDeps, badDepsInitialized, rpmGlobalMacroContext @*/
822 struct badDeps_s * bdp;
824 if (!badDepsInitialized) {
825 char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
826 const char ** av = NULL;
830 if (s != NULL && *s != '\0'
831 && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
832 && ac > 0 && av != NULL)
834 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
835 for (i = 0; i < ac; i++, bdp++) {
836 char * pname, * qname;
840 pname = xstrdup(av[i]);
841 if ((qname = strchr(pname, '>')) != NULL)
847 rpmMessage(RPMMESS_DEBUG,
848 _("ignore package name relation(s) [%d]\t%s -> %s\n"),
849 i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
856 badDepsInitialized++;
861 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
862 if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
871 * Recursively mark all nodes with their predecessors.
872 * @param tsi successor chain
873 * @param q predecessor
875 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
876 /*@globals internalState @*/
878 /*@modifies internalState @*/
882 /*@-branchstate@*/ /* FIX: q is kept */
883 while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
885 if (rpmteTSI(p)->tsi_chain != NULL)
887 /*@-assignexpose -temptrans@*/
888 rpmteTSI(p)->tsi_chain = q;
889 /*@=assignexpose =temptrans@*/
890 if (rpmteTSI(p)->tsi_next != NULL)
891 markLoop(rpmteTSI(p)->tsi_next, p);
896 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
899 if (isLegacyPreReq(f))
902 if (f & RPMSENSE_SCRIPT_PRE)
903 return "Requires(pre):";
904 if (f & RPMSENSE_SCRIPT_POST)
905 return "Requires(post):";
906 if (f & RPMSENSE_SCRIPT_PREUN)
907 return "Requires(preun):";
908 if (f & RPMSENSE_SCRIPT_POSTUN)
909 return "Requires(postun):";
910 if (f & RPMSENSE_SCRIPT_VERIFY)
911 return "Requires(verify):";
912 if (f & RPMSENSE_FIND_REQUIRES)
913 return "Requires(auto):";
918 * Find (and eliminate co-requisites) "q <- p" relation in dependency loop.
919 * Search all successors of q for instance of p. Format the specific relation,
920 * (e.g. p contains "Requires: q"). Unlink and free co-requisite (i.e.
921 * pure Requires: dependencies) successor node(s).
922 * @param q sucessor (i.e. package required by p)
923 * @param p predecessor (i.e. package that "Requires: q")
924 * @param requires relation
925 * @param zap max. no. of co-requisites to remove (-1 is all)?
926 * @retval nzaps address of no. of relations removed
927 * @return (possibly NULL) formatted "q <- p" releation (malloc'ed)
930 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
931 static /*@owned@*/ /*@null@*/ const char *
932 zapRelation(rpmte q, rpmte p,
933 /*@null@*/ rpmds requires,
934 int zap, /*@in@*/ /*@out@*/ int * nzaps)
935 /*@modifies q, p, requires, *nzaps @*/
939 const char *dp = NULL;
941 for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
943 /* XXX Note: the loop traverses "not found", break on "found". */
945 tsi_prev = tsi, tsi = tsi->tsi_next)
950 /*@-abstractcompare@*/
951 if (tsi->tsi_suc != p)
953 /*@=abstractcompare@*/
955 if (requires == NULL) continue; /* XXX can't happen */
957 (void) rpmdsSetIx(requires, tsi->tsi_reqx);
959 Flags = rpmdsFlags(requires);
961 dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
964 * Attempt to unravel a dependency loop by eliminating Requires's.
967 if (zap && !(Flags & RPMSENSE_PREREQ)) {
968 rpmMessage(RPMMESS_DEBUG,
969 _("removing %s \"%s\" from tsort relations.\n"),
970 (rpmteNEVR(p) ? rpmteNEVR(p) : "???"), dp);
971 rpmteTSI(p)->tsi_count--;
972 if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
973 tsi->tsi_next = NULL;
982 /* XXX Note: the loop traverses "not found", get out now! */
991 * Record next "q <- p" relation (i.e. "p" requires "q").
992 * @param ts transaction set
993 * @param p predecessor (i.e. package that "Requires: q")
994 * @param selected boolean package selected array
995 * @param requires relation
999 static inline int addRelation(rpmts ts,
1000 /*@dependent@*/ rpmte p,
1001 unsigned char * selected,
1003 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
1004 /*@modifies ts, p, *selected, rpmGlobalMacroContext,
1005 fileSystem, internalState @*/
1014 if ((Name = rpmdsN(requires)) == NULL)
1017 /* Avoid rpmlib feature dependencies. */
1018 if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
1021 /* Avoid package config dependencies. */
1022 if (!strncmp(Name, "config(", sizeof("config(")-1))
1025 pkgKey = RPMAL_NOMATCH;
1026 key = rpmalSatisfiesDepend(ts->addedPackages, requires, &pkgKey);
1028 /* Ordering depends only on added package relations. */
1029 if (pkgKey == RPMAL_NOMATCH)
1032 /* XXX Set q to the added package that has pkgKey == q->u.addedKey */
1033 /* XXX FIXME: bsearch is possible/needed here */
1034 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
1036 /* XXX Only added packages need be checked for matches. */
1037 if (rpmteType(q) == TR_REMOVED)
1040 if (pkgKey == rpmteAddedKey(q))
1043 qi = rpmtsiFree(qi);
1044 if (q == NULL || i == ts->orderCount)
1047 /* Avoid certain dependency relations. */
1048 if (ignoreDep(p, q))
1051 /* Avoid redundant relations. */
1052 /* XXX TODO: add control bit. */
1054 if (selected[i] != 0)
1061 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1062 rpmteTSI(p)->tsi_count++; /* bump p predecessor count */
1064 if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
1065 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
1067 tsi = xcalloc(1, sizeof(*tsi));
1070 tsi->tsi_reqx = rpmdsIx(requires);
1072 tsi->tsi_next = rpmteTSI(q)->tsi_next;
1073 rpmteTSI(q)->tsi_next = tsi;
1074 rpmteTSI(q)->tsi_qcnt++; /* bump q successor count */
1080 * Compare ordered list entries by index (qsort/bsearch).
1081 * @param one 1st ordered list entry
1082 * @param two 2nd ordered list entry
1083 * @return result of comparison
1085 static int orderListIndexCmp(const void * one, const void * two) /*@*/
1088 long a = (long) ((const orderListIndex)one)->pkgKey;
1089 long b = (long) ((const orderListIndex)two)->pkgKey;
1095 * Add element to list sorting by tsi_qcnt.
1096 * @param p new element
1097 * @retval qp address of first element
1098 * @retval rp address of last element
1102 static void addQ(/*@dependent@*/ rpmte p,
1103 /*@in@*/ /*@out@*/ rpmte * qp,
1104 /*@in@*/ /*@out@*/ rpmte * rp)
1105 /*@modifies p, *qp, *rp @*/
1109 /* Mark the package as queued. */
1110 rpmteTSI(p)->tsi_reqx = 1;
1112 if ((*rp) == NULL) { /* 1st element */
1113 /*@-dependenttrans@*/ /* FIX: double indirection */
1115 /*@=dependenttrans@*/
1119 /* Find location in queue using metric tsi_qcnt. */
1120 for (qprev = NULL, q = (*qp);
1122 qprev = q, q = rpmteTSI(q)->tsi_suc)
1124 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
1128 if (qprev == NULL) { /* insert at beginning of list */
1129 rpmteTSI(p)->tsi_suc = q;
1130 /*@-dependenttrans@*/
1131 (*qp) = p; /* new head */
1132 /*@=dependenttrans@*/
1133 } else if (q == NULL) { /* insert at end of list */
1134 rpmteTSI(qprev)->tsi_suc = p;
1135 /*@-dependenttrans@*/
1136 (*rp) = p; /* new tail */
1137 /*@=dependenttrans@*/
1138 } else { /* insert between qprev and q */
1139 rpmteTSI(p)->tsi_suc = q;
1140 rpmteTSI(qprev)->tsi_suc = p;
1147 int rpmtsOrder(rpmts ts)
1151 int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
1158 int orderingCount = 0;
1159 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
1162 int newOrderCount = 0;
1163 orderListIndex orderList;
1176 rpmalMakeIndex(ts->addedPackages);
1179 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
1181 /* T1. Initialize. */
1183 numOrderList = ts->orderCount;
1186 if (oType & TR_ADDED)
1187 numOrderList += ts->numAddedPackages;
1188 if (oType & TR_REMOVED)
1189 numOrderList += ts->numRemovedPackages;
1191 ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
1192 loopcheck = numOrderList;
1195 pi = rpmtsiInit(ts);
1196 while ((p = rpmtsiNext(pi, oType)) != NULL)
1198 pi = rpmtsiFree(pi);
1200 /* Record all relations. */
1201 rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
1202 pi = rpmtsiInit(ts);
1203 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1205 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
1208 memset(selected, 0, sizeof(*selected) * ts->orderCount);
1210 /* Avoid narcisstic relations. */
1211 selected[rpmtsiOc(pi)] = 1;
1213 /* T2. Next "q <- p" relation. */
1215 /* First, do pre-requisites. */
1216 requires = rpmdsInit(requires);
1217 if (requires != NULL)
1218 while (rpmdsNext(requires) >= 0) {
1220 Flags = rpmdsFlags(requires);
1222 switch (rpmteType(p)) {
1224 /* Skip if not %preun/%postun requires or legacy prereq. */
1225 if (isInstallPreReq(Flags)
1226 || !( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1227 /*@innercontinue@*/ continue;
1228 /*@switchbreak@*/ break;
1230 /* Skip if not %pre/%post requires or legacy prereq. */
1231 if (isErasePreReq(Flags)
1232 || !( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1233 /*@innercontinue@*/ continue;
1234 /*@switchbreak@*/ break;
1237 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1238 (void) addRelation(ts, p, selected, requires);
1242 /* Then do co-requisites. */
1243 requires = rpmdsInit(requires);
1244 if (requires != NULL)
1245 while (rpmdsNext(requires) >= 0) {
1247 Flags = rpmdsFlags(requires);
1249 switch (rpmteType(p)) {
1251 /* Skip if %preun/%postun requires or legacy prereq. */
1252 if (isInstallPreReq(Flags)
1253 || ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1254 /*@innercontinue@*/ continue;
1255 /*@switchbreak@*/ break;
1257 /* Skip if %pre/%post requires or legacy prereq. */
1258 if (isErasePreReq(Flags)
1259 || ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1260 /*@innercontinue@*/ continue;
1261 /*@switchbreak@*/ break;
1264 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1265 (void) addRelation(ts, p, selected, requires);
1269 pi = rpmtsiFree(pi);
1271 /* Save predecessor count and mark tree roots. */
1273 pi = rpmtsiInit(ts);
1274 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1277 npreds = rpmteTSI(p)->tsi_count;
1279 (void) rpmteSetNpreds(p, npreds);
1282 (void) rpmteSetTree(p, treex++);
1284 (void) rpmteSetTree(p, -1);
1286 (void) rpmteSetParent(p, NULL);
1290 pi = rpmtsiFree(pi);
1292 /* T4. Scan for zeroes. */
1293 rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
1296 if (pi != NULL) pi = rpmtsiFree(pi);
1299 pi = rpmtsiInit(ts);
1300 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1302 /* Prefer packages in chainsaw or anaconda presentation order. */
1304 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
1306 if (rpmteTSI(p)->tsi_count != 0)
1308 rpmteTSI(p)->tsi_suc = NULL;
1312 pi = rpmtsiFree(pi);
1314 /* T5. Output front of queue (T7. Remove from queue.) */
1315 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
1317 /* Mark the package as unqueued. */
1318 rpmteTSI(q)->tsi_reqx = 0;
1321 switch (rpmteType(q)) {
1323 if (!(oType & TR_ADDED))
1325 /*@switchbreak@*/ break;
1327 if (!(oType & TR_REMOVED))
1329 /*@switchbreak@*/ break;
1332 /*@notreached@*/ /*@switchbreak@*/ break;
1334 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
1336 rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s%c%s\n",
1337 orderingCount, rpmteNpreds(q),
1338 rpmteTSI(q)->tsi_qcnt, rpmteTree(q), rpmteDepth(q),
1339 (2 * rpmteDepth(q)), "",
1341 (rpmteNEVR(q) ? rpmteNEVR(q) : "???"));
1343 treex = rpmteTree(q);
1344 depth = rpmteDepth(q);
1345 (void) rpmteSetDegree(q, 0);
1346 tsbytes += rpmtePkgFileSize(q);
1348 ordering[orderingCount] = rpmteAddedKey(q);
1353 /* T6. Erase relations. */
1354 tsi_next = rpmteTSI(q)->tsi_next;
1355 rpmteTSI(q)->tsi_next = NULL;
1356 while ((tsi = tsi_next) != NULL) {
1357 tsi_next = tsi->tsi_next;
1358 tsi->tsi_next = NULL;
1360 if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
1362 (void) rpmteSetTree(p, treex);
1363 (void) rpmteSetDepth(p, depth+1);
1364 (void) rpmteSetParent(p, q);
1365 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
1367 /* XXX TODO: add control bit. */
1368 rpmteTSI(p)->tsi_suc = NULL;
1369 addQ(p, &rpmteTSI(q)->tsi_suc, &r);
1374 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
1376 (void) rpmtsUnorderedSuccessors(ts, orderingCount);
1377 rpmMessage(RPMMESS_DEBUG,
1378 _("========== successors only (%d bytes)\n"), (int)tsbytes);
1380 /* Relink the queue in presentation order. */
1382 pi = rpmtsiInit(ts);
1383 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1384 /* Is this element in the queue? */
1385 if (rpmteTSI(p)->tsi_reqx == 0)
1386 /*@innercontinue@*/ continue;
1390 pi = rpmtsiFree(pi);
1391 tsi->tsi_suc = NULL;
1395 /* T8. End of process. Check for loops. */
1396 if (loopcheck != 0) {
1399 /* T9. Initialize predecessor chain. */
1401 qi = rpmtsiInit(ts);
1402 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1403 rpmteTSI(q)->tsi_chain = NULL;
1404 rpmteTSI(q)->tsi_reqx = 0;
1405 /* Mark packages already sorted. */
1406 if (rpmteTSI(q)->tsi_count == 0)
1407 rpmteTSI(q)->tsi_count = -1;
1409 qi = rpmtsiFree(qi);
1411 /* T10. Mark all packages with their predecessors. */
1412 qi = rpmtsiInit(ts);
1413 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1414 if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
1416 rpmteTSI(q)->tsi_next = NULL;
1418 rpmteTSI(q)->tsi_next = tsi;
1420 qi = rpmtsiFree(qi);
1422 /* T11. Print all dependency loops. */
1423 ri = rpmtsiInit(ts);
1424 while ((r = rpmtsiNext(ri, oType)) != NULL)
1430 /* T12. Mark predecessor chain, looking for start of loop. */
1431 for (q = rpmteTSI(r)->tsi_chain; q != NULL;
1432 q = rpmteTSI(q)->tsi_chain)
1434 if (rpmteTSI(q)->tsi_reqx)
1435 /*@innerbreak@*/ break;
1436 rpmteTSI(q)->tsi_reqx = 1;
1439 /* T13. Print predecessor chain from start of loop. */
1440 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
1444 /* Unchain predecessor loop. */
1445 rpmteTSI(p)->tsi_chain = NULL;
1448 rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
1452 /* Find (and destroy if co-requisite) "q <- p" relation. */
1453 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
1454 requires = rpmdsInit(requires);
1455 if (requires == NULL)
1456 /*@innercontinue@*/ continue; /* XXX can't happen */
1457 dp = zapRelation(q, p, requires, 1, &nzaps);
1459 /* Print next member of loop. */
1461 if (rpmteNEVR(p) != NULL)
1462 (void) stpcpy(buf, rpmteNEVR(p));
1463 rpmMessage(RPMMESS_DEBUG, " %-40s %s\n", buf,
1464 (dp ? dp : "not found!?!"));
1469 /* Walk (and erase) linear part of predecessor chain as well. */
1470 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
1471 p = q, q = rpmteTSI(q)->tsi_chain)
1473 /* Unchain linear part of predecessor loop. */
1474 rpmteTSI(p)->tsi_chain = NULL;
1475 rpmteTSI(p)->tsi_reqx = 0;
1478 ri = rpmtsiFree(ri);
1480 /* If a relation was eliminated, then continue sorting. */
1481 /* XXX TODO: add control bit. */
1482 if (nzaps && nrescans-- > 0) {
1483 rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
1487 /* Return no. of packages that could not be ordered. */
1488 rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
1493 /* Clean up tsort remnants (if any). */
1494 pi = rpmtsiInit(ts);
1495 while ((p = rpmtsiNext(pi, 0)) != NULL)
1497 pi = rpmtsiFree(pi);
1500 * The order ends up as installed packages followed by removed packages,
1501 * with removes for upgrades immediately following the installation of
1502 * the new package. This would be easier if we could sort the
1503 * addedPackages array, but we store indexes into it in various places.
1505 orderList = xcalloc(numOrderList, sizeof(*orderList));
1507 pi = rpmtsiInit(ts);
1508 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1509 /* Prepare added package ordering permutation. */
1510 switch (rpmteType(p)) {
1512 orderList[j].pkgKey = rpmteAddedKey(p);
1513 /*@switchbreak@*/ break;
1515 orderList[j].pkgKey = RPMAL_NOMATCH;
1516 /*@switchbreak@*/ break;
1518 orderList[j].orIndex = rpmtsiOc(pi);
1521 pi = rpmtsiFree(pi);
1523 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
1526 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
1529 for (i = 0, newOrderCount = 0; i < orderingCount; i++)
1531 struct orderListIndex_s key;
1532 orderListIndex needle;
1534 key.pkgKey = ordering[i];
1535 needle = bsearch(&key, orderList, numOrderList,
1536 sizeof(key), orderListIndexCmp);
1537 /* bsearch should never, ever fail */
1541 j = needle->orIndex;
1542 if ((q = ts->order[j]) == NULL)
1545 newOrder[newOrderCount++] = q;
1546 ts->order[j] = NULL;
1548 for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
1549 if ((q = ts->order[j]) == NULL)
1550 /*@innerbreak@*/ break;
1551 if (rpmteType(q) == TR_REMOVED
1552 && rpmteDependsOnKey(q) == needle->pkgKey)
1554 newOrder[newOrderCount++] = q;
1555 ts->order[j] = NULL;
1557 /*@innerbreak@*/ break;
1562 for (j = 0; j < ts->orderCount; j++) {
1563 if ((p = ts->order[j]) == NULL)
1565 newOrder[newOrderCount++] = p;
1566 ts->order[j] = NULL;
1568 assert(newOrderCount == ts->orderCount);
1571 ts->order = _free(ts->order);
1573 ts->order = newOrder;
1574 ts->orderAlloced = ts->orderCount;
1575 orderList = _free(orderList);
1577 #ifdef DYING /* XXX now done at the CLI level just before rpmtsRun(). */
1582 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
1588 int rpmtsCheck(rpmts ts)
1590 uint_32 tscolor = rpmtsColor(ts);
1591 rpmdbMatchIterator mi = NULL;
1592 rpmtsi pi = NULL; rpmte p;
1593 int closeatexit = 0;
1597 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1599 /* Do lazy, readonly, open of rpm database. */
1600 if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
1601 if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
1606 ts->probs = rpmpsFree(ts->probs);
1607 ts->probs = rpmpsCreate();
1609 rpmalMakeIndex(ts->addedPackages);
1612 * Look at all of the added packages and make sure their dependencies
1615 pi = rpmtsiInit(ts);
1616 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1619 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1620 rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
1621 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1623 rc = checkPackageDeps(ts, rpmteNEVR(p),
1624 rpmteDS(p, RPMTAG_REQUIRENAME),
1625 rpmteDS(p, RPMTAG_CONFLICTNAME),
1631 #if defined(DYING) || defined(__LCLINT__)
1632 /* XXX all packages now have Provides: name = version-release */
1633 /* Adding: check name against conflicts matches. */
1634 rc = checkDependentConflicts(ts, rpmteN(p));
1640 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1641 provides = rpmdsInit(provides);
1642 if (provides == NULL || rpmdsN(provides) == NULL)
1644 while (rpmdsNext(provides) >= 0) {
1647 if ((Name = rpmdsN(provides)) == NULL)
1648 /*@innercontinue@*/ continue; /* XXX can't happen */
1650 /* Adding: check provides key against conflicts matches. */
1651 if (!checkDependentConflicts(ts, Name))
1652 /*@innercontinue@*/ continue;
1654 /*@innerbreak@*/ break;
1659 pi = rpmtsiFree(pi);
1662 * Look at the removed packages and make sure they aren't critical.
1664 pi = rpmtsiInit(ts);
1665 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1669 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1670 rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
1671 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1674 #if defined(DYING) || defined(__LCLINT__)
1675 /* XXX all packages now have Provides: name = version-release */
1676 /* Erasing: check name against requiredby matches. */
1677 rc = checkDependentPackages(ts, rpmteN(p));
1683 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1684 provides = rpmdsInit(provides);
1685 if (provides != NULL)
1686 while (rpmdsNext(provides) >= 0) {
1689 if ((Name = rpmdsN(provides)) == NULL)
1690 /*@innercontinue@*/ continue; /* XXX can't happen */
1692 /* Erasing: check provides against requiredby matches. */
1693 if (!checkDependentPackages(ts, Name))
1694 /*@innercontinue@*/ continue;
1696 /*@innerbreak@*/ break;
1702 fi = rpmteFI(p, RPMTAG_BASENAMES);
1703 fi = rpmfiInit(fi, 0);
1704 while (rpmfiNext(fi) >= 0) {
1705 const char * fn = rpmfiFN(fi);
1707 /* Erasing: check filename against requiredby matches. */
1708 if (!checkDependentPackages(ts, fn))
1709 /*@innercontinue@*/ continue;
1711 /*@innerbreak@*/ break;
1716 pi = rpmtsiFree(pi);
1721 mi = rpmdbFreeIterator(mi);
1722 pi = rpmtsiFree(pi);
1724 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1728 xx = rpmtsCloseDB(ts);
1729 else if (_cacheDependsRC)
1730 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);