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 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
381 DNEVRlen = key->size;
383 datalen = data->size;
386 if (xx == 0 && datap && datalen == 4)
387 memcpy(&rc, datap, datalen);
389 xx = dbiCclose(dbi, dbcursor, 0);
394 rpmdsNotify(dep, _("(cached)"), rc);
401 rc = 0; /* assume dependency is satisfied */
403 #if defined(DYING) || defined(__LCLINT__)
404 { static /*@observer@*/ const char noProvidesString[] = "nada";
405 static /*@observer@*/ const char * rcProvidesString = noProvidesString;
406 int_32 Flags = rpmdsFlags(dep);
410 if (rcProvidesString == noProvidesString)
411 rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
413 if (rcProvidesString != NULL && !(Flags & RPMSENSE_SENSEMASK)) {
416 /*@-observertrans -mayaliasunique@*/
417 while ((start = strstr(rcProvidesString, Name))) {
418 /*@=observertrans =mayaliasunique@*/
420 if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
421 rpmdsNotify(dep, _("(rpmrc provides)"), rc);
425 rcProvidesString = start + 1;
432 * New features in rpm packaging implicitly add versioned dependencies
433 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
434 * Check those dependencies now.
436 if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1)) {
437 if (rpmCheckRpmlibProvides(dep)) {
438 rpmdsNotify(dep, _("(rpmlib provides)"), rc);
444 /* Search added packages for the dependency. */
445 if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
447 * XXX Ick, context sensitive answers from dependency cache.
448 * XXX Always resolve added dependencies within context to disambiguate.
450 if (_rpmds_nopromote)
455 /* XXX only the installer does not have the database open here. */
456 if (rpmtsGetRdb(ts) != NULL) {
458 if (Name[0] == '/') {
459 /* depFlags better be 0! */
461 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
463 (void) rpmdbPruneIterator(mi,
464 ts->removedPackages, ts->numRemovedPackages, 1);
466 while ((h = rpmdbNextIterator(mi)) != NULL) {
467 rpmdsNotify(dep, _("(db files)"), rc);
468 mi = rpmdbFreeIterator(mi);
471 mi = rpmdbFreeIterator(mi);
475 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
476 (void) rpmdbPruneIterator(mi,
477 ts->removedPackages, ts->numRemovedPackages, 1);
478 while ((h = rpmdbNextIterator(mi)) != NULL) {
479 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
480 rpmdsNotify(dep, _("(db provides)"), rc);
481 mi = rpmdbFreeIterator(mi);
485 mi = rpmdbFreeIterator(mi);
487 #if defined(DYING) || defined(__LCLINT__)
488 mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
489 (void) rpmdbPruneIterator(mi,
490 ts->removedPackages, ts->numRemovedPackages, 1);
491 while ((h = rpmdbNextIterator(mi)) != NULL) {
492 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
493 rpmdsNotify(dep, _("(db package)"), rc);
494 mi = rpmdbFreeIterator(mi);
498 mi = rpmdbFreeIterator(mi);
504 * Search for an unsatisfied dependency.
507 if (adding && !retrying && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST)) {
508 if (ts->solve != NULL) {
509 xx = (*ts->solve) (ts, dep, ts->solveData);
514 rpmalMakeIndex(ts->addedPackages);
522 rc = 1; /* dependency is unsatisfied */
523 rpmdsNotify(dep, NULL, rc);
527 * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
529 if (_cacheDependsRC && _cacheThisRC) {
531 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
538 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
539 DBC * dbcursor = NULL;
540 size_t DNEVRlen = strlen(DNEVR);
542 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
544 memset(key, 0, sizeof(*key));
545 /*@i@*/ key->data = (void *) DNEVR;
546 key->size = DNEVRlen;
547 memset(data, 0, sizeof(*data));
549 data->size = sizeof(rc);
552 xx = dbiPut(dbi, dbcursor, key, data, 0);
554 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
565 * Check added requires/conflicts against against installed+added packages.
566 * @param ts transaction set
567 * @param pkgNEVR package name-version-release
568 * @param requires Requires: dependencies (or NULL)
569 * @param conflicts Conflicts: dependencies (or NULL)
570 * @param depName dependency name to filter (or NULL)
571 * @param tscolor color bits for transaction set (0 disables)
572 * @param adding dependency is from added package set?
573 * @return 0 no problems found
575 static int checkPackageDeps(rpmts ts, const char * pkgNEVR,
576 /*@null@*/ rpmds requires, /*@null@*/ rpmds conflicts,
577 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
578 /*@globals rpmGlobalMacroContext,
579 fileSystem, internalState @*/
580 /*@modifies ts, requires, conflicts, rpmGlobalMacroContext,
581 fileSystem, internalState */
588 requires = rpmdsInit(requires);
589 if (requires != NULL)
590 while (!ourrc && rpmdsNext(requires) >= 0) {
592 if ((Name = rpmdsN(requires)) == NULL)
593 continue; /* XXX can't happen */
595 /* Filter out requires that came along for the ride. */
596 if (depName != NULL && strcmp(depName, Name))
599 /* Ignore colored requires not in our rainbow. */
600 dscolor = rpmdsColor(requires);
601 if (tscolor && dscolor && !(tscolor & dscolor))
604 rc = unsatisfiedDepend(ts, requires, adding);
607 case 0: /* requirements are satisfied. */
608 /*@switchbreak@*/ break;
609 case 1: /* requirements are not satisfied. */
610 { fnpyKey * suggestedKeys = NULL;
613 if (ts->availablePackages != NULL) {
614 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
619 rpmdsProblem(ts->probs, pkgNEVR, requires, suggestedKeys, adding);
622 /*@switchbreak@*/ break;
623 case 2: /* something went wrong! */
626 /*@switchbreak@*/ break;
630 conflicts = rpmdsInit(conflicts);
631 if (conflicts != NULL)
632 while (!ourrc && rpmdsNext(conflicts) >= 0) {
634 if ((Name = rpmdsN(conflicts)) == NULL)
635 continue; /* XXX can't happen */
637 /* Filter out conflicts that came along for the ride. */
638 if (depName != NULL && strcmp(depName, Name))
641 /* Ignore colored conflicts not in our rainbow. */
642 dscolor = rpmdsColor(conflicts);
643 if (tscolor && dscolor && !(tscolor & dscolor))
646 rc = unsatisfiedDepend(ts, conflicts, adding);
648 /* 1 == unsatisfied, 0 == satsisfied */
650 case 0: /* conflicts exist. */
651 rpmdsProblem(ts->probs, pkgNEVR, conflicts, NULL, adding);
652 /*@switchbreak@*/ break;
653 case 1: /* conflicts don't exist. */
654 /*@switchbreak@*/ break;
655 case 2: /* something went wrong! */
658 /*@switchbreak@*/ break;
666 * Check dependency against installed packages.
667 * Adding: check name/provides dep against each conflict match,
668 * Erasing: check name/provides/filename dep against each requiredby match.
669 * @param ts transaction set
670 * @param dep dependency name
671 * @param mi rpm database iterator
672 * @param adding dependency is from added package set?
673 * @return 0 no problems found
675 static int checkPackageSet(rpmts ts, const char * dep,
676 /*@only@*/ /*@null@*/ rpmdbMatchIterator mi, int adding)
677 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
678 /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
684 (void) rpmdbPruneIterator(mi,
685 ts->removedPackages, ts->numRemovedPackages, 1);
686 while ((h = rpmdbNextIterator(mi)) != NULL) {
687 const char * pkgNEVR;
688 rpmds requires, conflicts;
691 pkgNEVR = hGetNEVR(h, NULL);
692 requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
693 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
694 conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
695 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
696 rc = checkPackageDeps(ts, pkgNEVR, requires, conflicts, dep, 0, adding);
697 conflicts = rpmdsFree(conflicts);
698 requires = rpmdsFree(requires);
699 pkgNEVR = _free(pkgNEVR);
706 mi = rpmdbFreeIterator(mi);
712 * Check to-be-erased dependencies against installed requires.
713 * @param ts transaction set
714 * @param dep requires name
715 * @return 0 no problems found
717 static int checkDependentPackages(rpmts ts, const char * dep)
718 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
719 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
721 rpmdbMatchIterator mi;
722 mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, dep, 0);
723 return checkPackageSet(ts, dep, mi, 0);
727 * Check to-be-added dependencies against installed conflicts.
728 * @param ts transaction set
729 * @param dep conflicts name
730 * @return 0 no problems found
732 static int checkDependentConflicts(rpmts ts, const char * dep)
733 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
734 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
738 if (rpmtsGetRdb(ts) != NULL) { /* XXX is this necessary? */
739 rpmdbMatchIterator mi;
740 mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, dep, 0);
741 rc = checkPackageSet(ts, dep, mi, 1);
748 /*@observer@*/ /*@owned@*/ /*@null@*/
750 /*@observer@*/ /*@dependent@*/ /*@null@*/
755 static struct badDeps_s {
756 /*@observer@*/ /*@null@*/ const char * pname;
757 /*@observer@*/ /*@null@*/ const char * qname;
759 { "libtermcap", "bash" },
760 { "modutils", "vixie-cron" },
761 { "ypbind", "yp-tools" },
762 { "ghostscript-fonts", "ghostscript" },
764 { "libgnomeprint15", "gnome-print" },
765 { "nautilus", "nautilus-mozilla" },
767 { "arts", "kdelibs-sound" },
769 { "pango-gtkbeta-devel", "pango-gtkbeta" },
770 { "XFree86", "Mesa" },
771 { "compat-glibc", "db2" },
772 { "compat-glibc", "db1" },
773 { "pam", "initscripts" },
774 { "initscripts", "sysklogd" },
776 { "egcs-c++", "libstdc++" },
778 { "pilot-link-devel", "pilot-link" },
780 { "pam", "pamconfig" },
785 static int badDepsInitialized = 0;
787 /*@unchecked@*/ /*@only@*/ /*@null@*/
788 static struct badDeps_s * badDeps = NULL;
793 /*@-modobserver -observertrans @*/
794 static void freeBadDeps(void)
795 /*@globals badDeps, badDepsInitialized @*/
796 /*@modifies badDeps, badDepsInitialized @*/
799 struct badDeps_s * bdp;
800 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
801 bdp->pname = _free(bdp->pname);
802 badDeps = _free(badDeps);
804 badDepsInitialized = 0;
806 /*@=modobserver =observertrans @*/
809 * Check for dependency relations to be ignored.
811 * @param p successor element (i.e. with Requires: )
812 * @param q predecessor element (i.e. with Provides: )
813 * @return 1 if dependency is to be ignored.
816 static int ignoreDep(const rpmte p, const rpmte q)
817 /*@globals badDeps, badDepsInitialized @*/
818 /*@modifies badDeps, badDepsInitialized @*/
820 struct badDeps_s * bdp;
823 if (!badDepsInitialized) {
824 char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
825 const char ** av = NULL;
829 if (s != NULL && *s != '\0'
830 && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
831 && ac > 0 && av != NULL)
833 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
834 for (i = 0; i < ac; i++, bdp++) {
835 char * pname, * qname;
839 pname = xstrdup(av[i]);
840 if ((qname = strchr(pname, '>')) != NULL)
846 rpmMessage(RPMMESS_DEBUG,
847 _("ignore package name relation(s) [%d]\t%s -> %s\n"),
848 i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
855 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 fileSystem @*/
1004 /*@modifies ts, p, *selected, fileSystem @*/
1013 if ((Name = rpmdsN(requires)) == NULL)
1016 /* Avoid rpmlib feature dependencies. */
1017 if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
1020 /* Avoid package config dependencies. */
1021 if (!strncmp(Name, "config(", sizeof("config(")-1))
1024 pkgKey = RPMAL_NOMATCH;
1025 key = rpmalSatisfiesDepend(ts->addedPackages, requires, &pkgKey);
1027 /* Ordering depends only on added package relations. */
1028 if (pkgKey == RPMAL_NOMATCH)
1031 /* XXX Set q to the added package that has pkgKey == q->u.addedKey */
1032 /* XXX FIXME: bsearch is possible/needed here */
1033 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
1035 /* XXX Only added packages need be checked for matches. */
1036 if (rpmteType(q) == TR_REMOVED)
1039 if (pkgKey == rpmteAddedKey(q))
1042 qi = rpmtsiFree(qi);
1043 if (q == NULL || i == ts->orderCount)
1046 /* Avoid certain dependency relations. */
1047 if (ignoreDep(p, q))
1050 /* Avoid redundant relations. */
1051 /* XXX TODO: add control bit. */
1053 if (selected[i] != 0)
1060 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1061 rpmteTSI(p)->tsi_count++; /* bump p predecessor count */
1063 if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
1064 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
1066 tsi = xcalloc(1, sizeof(*tsi));
1069 tsi->tsi_reqx = rpmdsIx(requires);
1071 tsi->tsi_next = rpmteTSI(q)->tsi_next;
1073 rpmteTSI(q)->tsi_next = tsi;
1074 rpmteTSI(q)->tsi_qcnt++; /* bump q successor count */
1081 * Compare ordered list entries by index (qsort/bsearch).
1082 * @param one 1st ordered list entry
1083 * @param two 2nd ordered list entry
1084 * @return result of comparison
1086 static int orderListIndexCmp(const void * one, const void * two) /*@*/
1089 long a = (long) ((const orderListIndex)one)->pkgKey;
1090 long b = (long) ((const orderListIndex)two)->pkgKey;
1096 * Add element to list sorting by tsi_qcnt.
1097 * @param p new element
1098 * @retval qp address of first element
1099 * @retval rp address of last element
1103 static void addQ(/*@dependent@*/ rpmte p,
1104 /*@in@*/ /*@out@*/ rpmte * qp,
1105 /*@in@*/ /*@out@*/ rpmte * rp)
1106 /*@modifies p, *qp, *rp @*/
1110 /* Mark the package as queued. */
1111 rpmteTSI(p)->tsi_reqx = 1;
1113 if ((*rp) == NULL) { /* 1st element */
1114 /*@-dependenttrans@*/ /* FIX: double indirection */
1116 /*@=dependenttrans@*/
1120 /* Find location in queue using metric tsi_qcnt. */
1121 for (qprev = NULL, q = (*qp);
1123 qprev = q, q = rpmteTSI(q)->tsi_suc)
1125 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
1129 if (qprev == NULL) { /* insert at beginning of list */
1130 rpmteTSI(p)->tsi_suc = q;
1131 /*@-dependenttrans@*/
1132 (*qp) = p; /* new head */
1133 /*@=dependenttrans@*/
1134 } else if (q == NULL) { /* insert at end of list */
1135 rpmteTSI(qprev)->tsi_suc = p;
1136 /*@-dependenttrans@*/
1137 (*rp) = p; /* new tail */
1138 /*@=dependenttrans@*/
1139 } else { /* insert between qprev and q */
1140 rpmteTSI(p)->tsi_suc = q;
1141 rpmteTSI(qprev)->tsi_suc = p;
1148 int rpmtsOrder(rpmts ts)
1152 int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
1159 int orderingCount = 0;
1160 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
1163 int newOrderCount = 0;
1164 orderListIndex orderList;
1177 rpmalMakeIndex(ts->addedPackages);
1180 /* T1. Initialize. */
1182 numOrderList = ts->orderCount;
1185 if (oType & TR_ADDED)
1186 numOrderList += ts->numAddedPackages;
1187 if (oType & TR_REMOVED)
1188 numOrderList += ts->numRemovedPackages;
1190 ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
1191 loopcheck = numOrderList;
1194 pi = rpmtsiInit(ts);
1195 while ((p = rpmtsiNext(pi, oType)) != NULL)
1197 pi = rpmtsiFree(pi);
1199 /* Record all relations. */
1200 rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
1201 pi = rpmtsiInit(ts);
1202 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1204 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
1207 memset(selected, 0, sizeof(*selected) * ts->orderCount);
1209 /* Avoid narcisstic relations. */
1210 selected[rpmtsiOc(pi)] = 1;
1212 /* T2. Next "q <- p" relation. */
1214 /* First, do pre-requisites. */
1215 requires = rpmdsInit(requires);
1216 if (requires != NULL)
1217 while (rpmdsNext(requires) >= 0) {
1219 Flags = rpmdsFlags(requires);
1221 switch (rpmteType(p)) {
1223 /* Skip if not %preun/%postun requires or legacy prereq. */
1224 if (isInstallPreReq(Flags)
1225 || !( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1226 /*@innercontinue@*/ continue;
1227 /*@switchbreak@*/ break;
1229 /* Skip if not %pre/%post requires or legacy prereq. */
1230 if (isErasePreReq(Flags)
1231 || !( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1232 /*@innercontinue@*/ continue;
1233 /*@switchbreak@*/ break;
1236 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1237 (void) addRelation(ts, p, selected, requires);
1241 /* Then do co-requisites. */
1242 requires = rpmdsInit(requires);
1243 if (requires != NULL)
1244 while (rpmdsNext(requires) >= 0) {
1246 Flags = rpmdsFlags(requires);
1248 switch (rpmteType(p)) {
1250 /* Skip if %preun/%postun requires or legacy prereq. */
1251 if (isInstallPreReq(Flags)
1252 || ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
1253 /*@innercontinue@*/ continue;
1254 /*@switchbreak@*/ break;
1256 /* Skip if %pre/%post requires or legacy prereq. */
1257 if (isErasePreReq(Flags)
1258 || ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
1259 /*@innercontinue@*/ continue;
1260 /*@switchbreak@*/ break;
1263 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
1264 (void) addRelation(ts, p, selected, requires);
1268 pi = rpmtsiFree(pi);
1270 /* Save predecessor count and mark tree roots. */
1272 pi = rpmtsiInit(ts);
1273 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1276 npreds = rpmteTSI(p)->tsi_count;
1278 (void) rpmteSetNpreds(p, npreds);
1281 (void) rpmteSetTree(p, treex++);
1283 (void) rpmteSetTree(p, -1);
1285 (void) rpmteSetParent(p, NULL);
1289 pi = rpmtsiFree(pi);
1291 /* T4. Scan for zeroes. */
1292 rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
1295 if (pi != NULL) pi = rpmtsiFree(pi);
1298 pi = rpmtsiInit(ts);
1299 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1301 /* Prefer packages in chainsaw or anaconda presentation order. */
1303 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
1305 if (rpmteTSI(p)->tsi_count != 0)
1307 rpmteTSI(p)->tsi_suc = NULL;
1311 pi = rpmtsiFree(pi);
1313 /* T5. Output front of queue (T7. Remove from queue.) */
1314 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
1316 /* Mark the package as unqueued. */
1317 rpmteTSI(q)->tsi_reqx = 0;
1320 switch (rpmteType(q)) {
1322 if (!(oType & TR_ADDED))
1324 /*@switchbreak@*/ break;
1326 if (!(oType & TR_REMOVED))
1328 /*@switchbreak@*/ break;
1331 /*@notreached@*/ /*@switchbreak@*/ break;
1333 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
1335 rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s%c%s\n",
1336 orderingCount, rpmteNpreds(q),
1337 rpmteTSI(q)->tsi_qcnt, rpmteTree(q), rpmteDepth(q),
1338 (2 * rpmteDepth(q)), "",
1340 (rpmteNEVR(q) ? rpmteNEVR(q) : "???"));
1342 treex = rpmteTree(q);
1343 depth = rpmteDepth(q);
1344 (void) rpmteSetDegree(q, 0);
1345 tsbytes += rpmtePkgFileSize(q);
1347 ordering[orderingCount] = rpmteAddedKey(q);
1352 /* T6. Erase relations. */
1353 tsi_next = rpmteTSI(q)->tsi_next;
1354 rpmteTSI(q)->tsi_next = NULL;
1355 while ((tsi = tsi_next) != NULL) {
1356 tsi_next = tsi->tsi_next;
1357 tsi->tsi_next = NULL;
1359 if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
1361 (void) rpmteSetTree(p, treex);
1362 (void) rpmteSetDepth(p, depth+1);
1363 (void) rpmteSetParent(p, q);
1364 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
1366 /* XXX TODO: add control bit. */
1367 rpmteTSI(p)->tsi_suc = NULL;
1368 addQ(p, &rpmteTSI(q)->tsi_suc, &r);
1373 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
1375 (void) rpmtsUnorderedSuccessors(ts, orderingCount);
1376 rpmMessage(RPMMESS_DEBUG,
1377 _("========== successors only (%d bytes)\n"), (int)tsbytes);
1379 /* Relink the queue in presentation order. */
1381 pi = rpmtsiInit(ts);
1382 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1383 /* Is this element in the queue? */
1384 if (rpmteTSI(p)->tsi_reqx == 0)
1385 /*@innercontinue@*/ continue;
1389 pi = rpmtsiFree(pi);
1390 tsi->tsi_suc = NULL;
1394 /* T8. End of process. Check for loops. */
1395 if (loopcheck != 0) {
1398 /* T9. Initialize predecessor chain. */
1400 qi = rpmtsiInit(ts);
1401 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1402 rpmteTSI(q)->tsi_chain = NULL;
1403 rpmteTSI(q)->tsi_reqx = 0;
1404 /* Mark packages already sorted. */
1405 if (rpmteTSI(q)->tsi_count == 0)
1406 rpmteTSI(q)->tsi_count = -1;
1408 qi = rpmtsiFree(qi);
1410 /* T10. Mark all packages with their predecessors. */
1411 qi = rpmtsiInit(ts);
1412 while ((q = rpmtsiNext(qi, oType)) != NULL) {
1413 if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
1415 rpmteTSI(q)->tsi_next = NULL;
1417 rpmteTSI(q)->tsi_next = tsi;
1419 qi = rpmtsiFree(qi);
1421 /* T11. Print all dependency loops. */
1422 ri = rpmtsiInit(ts);
1423 while ((r = rpmtsiNext(ri, oType)) != NULL)
1429 /* T12. Mark predecessor chain, looking for start of loop. */
1430 for (q = rpmteTSI(r)->tsi_chain; q != NULL;
1431 q = rpmteTSI(q)->tsi_chain)
1433 if (rpmteTSI(q)->tsi_reqx)
1434 /*@innerbreak@*/ break;
1435 rpmteTSI(q)->tsi_reqx = 1;
1438 /* T13. Print predecessor chain from start of loop. */
1439 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
1443 /* Unchain predecessor loop. */
1444 rpmteTSI(p)->tsi_chain = NULL;
1447 rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
1451 /* Find (and destroy if co-requisite) "q <- p" relation. */
1452 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
1453 requires = rpmdsInit(requires);
1454 if (requires == NULL)
1455 /*@innercontinue@*/ continue; /* XXX can't happen */
1456 dp = zapRelation(q, p, requires, 1, &nzaps);
1458 /* Print next member of loop. */
1460 if (rpmteNEVR(p) != NULL)
1461 (void) stpcpy(buf, rpmteNEVR(p));
1462 rpmMessage(RPMMESS_DEBUG, " %-40s %s\n", buf,
1463 (dp ? dp : "not found!?!"));
1468 /* Walk (and erase) linear part of predecessor chain as well. */
1469 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
1470 p = q, q = rpmteTSI(q)->tsi_chain)
1472 /* Unchain linear part of predecessor loop. */
1473 rpmteTSI(p)->tsi_chain = NULL;
1474 rpmteTSI(p)->tsi_reqx = 0;
1477 ri = rpmtsiFree(ri);
1479 /* If a relation was eliminated, then continue sorting. */
1480 /* XXX TODO: add control bit. */
1481 if (nzaps && nrescans-- > 0) {
1482 rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
1486 /* Return no. of packages that could not be ordered. */
1487 rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
1492 /* Clean up tsort remnants (if any). */
1493 pi = rpmtsiInit(ts);
1494 while ((p = rpmtsiNext(pi, 0)) != NULL)
1496 pi = rpmtsiFree(pi);
1499 * The order ends up as installed packages followed by removed packages,
1500 * with removes for upgrades immediately following the installation of
1501 * the new package. This would be easier if we could sort the
1502 * addedPackages array, but we store indexes into it in various places.
1504 orderList = xcalloc(numOrderList, sizeof(*orderList));
1506 pi = rpmtsiInit(ts);
1507 while ((p = rpmtsiNext(pi, oType)) != NULL) {
1508 /* Prepare added package ordering permutation. */
1509 switch (rpmteType(p)) {
1511 orderList[j].pkgKey = rpmteAddedKey(p);
1512 /*@switchbreak@*/ break;
1514 orderList[j].pkgKey = RPMAL_NOMATCH;
1515 /*@switchbreak@*/ break;
1517 orderList[j].orIndex = rpmtsiOc(pi);
1520 pi = rpmtsiFree(pi);
1522 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
1525 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
1528 for (i = 0, newOrderCount = 0; i < orderingCount; i++)
1530 struct orderListIndex_s key;
1531 orderListIndex needle;
1533 key.pkgKey = ordering[i];
1534 needle = bsearch(&key, orderList, numOrderList,
1535 sizeof(key), orderListIndexCmp);
1536 /* bsearch should never, ever fail */
1540 j = needle->orIndex;
1541 if ((q = ts->order[j]) == NULL)
1544 newOrder[newOrderCount++] = q;
1545 ts->order[j] = NULL;
1547 for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
1548 if ((q = ts->order[j]) == NULL)
1549 /*@innerbreak@*/ break;
1550 if (rpmteType(q) == TR_REMOVED
1551 && rpmteDependsOnKey(q) == needle->pkgKey)
1553 newOrder[newOrderCount++] = q;
1554 ts->order[j] = NULL;
1556 /*@innerbreak@*/ break;
1561 for (j = 0; j < ts->orderCount; j++) {
1562 if ((p = ts->order[j]) == NULL)
1564 newOrder[newOrderCount++] = p;
1565 ts->order[j] = NULL;
1567 assert(newOrderCount == ts->orderCount);
1570 ts->order = _free(ts->order);
1572 ts->order = newOrder;
1573 ts->orderAlloced = ts->orderCount;
1574 orderList = _free(orderList);
1576 #ifdef DYING /* XXX now done at the CLI level just before rpmtsRun(). */
1585 int rpmtsCheck(rpmts ts)
1587 uint_32 tscolor = rpmtsColor(ts);
1588 rpmdbMatchIterator mi = NULL;
1589 rpmtsi pi = NULL; rpmte p;
1590 int closeatexit = 0;
1594 /* Do lazy, readonly, open of rpm database. */
1595 if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
1596 if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
1601 ts->probs = rpmpsFree(ts->probs);
1602 ts->probs = rpmpsCreate();
1604 rpmalMakeIndex(ts->addedPackages);
1607 * Look at all of the added packages and make sure their dependencies
1610 pi = rpmtsiInit(ts);
1611 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1614 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1615 rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
1616 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1618 rc = checkPackageDeps(ts, rpmteNEVR(p),
1619 rpmteDS(p, RPMTAG_REQUIRENAME),
1620 rpmteDS(p, RPMTAG_CONFLICTNAME),
1626 #if defined(DYING) || defined(__LCLINT__)
1627 /* XXX all packages now have Provides: name = version-release */
1628 /* Adding: check name against conflicts matches. */
1629 rc = checkDependentConflicts(ts, rpmteN(p));
1635 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1636 provides = rpmdsInit(provides);
1637 if (provides == NULL || rpmdsN(provides) == NULL)
1639 while (rpmdsNext(provides) >= 0) {
1642 if ((Name = rpmdsN(provides)) == NULL)
1643 /*@innercontinue@*/ continue; /* XXX can't happen */
1645 /* Adding: check provides key against conflicts matches. */
1646 if (!checkDependentConflicts(ts, Name))
1647 /*@innercontinue@*/ continue;
1649 /*@innerbreak@*/ break;
1654 pi = rpmtsiFree(pi);
1657 * Look at the removed packages and make sure they aren't critical.
1659 pi = rpmtsiInit(ts);
1660 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1664 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
1665 rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
1666 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1669 #if defined(DYING) || defined(__LCLINT__)
1670 /* XXX all packages now have Provides: name = version-release */
1671 /* Erasing: check name against requiredby matches. */
1672 rc = checkDependentPackages(ts, rpmteN(p));
1678 provides = rpmteDS(p, RPMTAG_PROVIDENAME);
1679 provides = rpmdsInit(provides);
1680 if (provides != NULL)
1681 while (rpmdsNext(provides) >= 0) {
1684 if ((Name = rpmdsN(provides)) == NULL)
1685 /*@innercontinue@*/ continue; /* XXX can't happen */
1687 /* Erasing: check provides against requiredby matches. */
1688 if (!checkDependentPackages(ts, Name))
1689 /*@innercontinue@*/ continue;
1691 /*@innerbreak@*/ break;
1697 fi = rpmteFI(p, RPMTAG_BASENAMES);
1698 fi = rpmfiInit(fi, 0);
1699 while (rpmfiNext(fi) >= 0) {
1700 const char * fn = rpmfiFN(fi);
1702 /* Erasing: check filename against requiredby matches. */
1703 if (!checkDependentPackages(ts, fn))
1704 /*@innercontinue@*/ continue;
1706 /*@innerbreak@*/ break;
1711 pi = rpmtsiFree(pi);
1716 mi = rpmdbFreeIterator(mi);
1717 pi = rpmtsiFree(pi);
1720 xx = rpmtsCloseDB(ts);
1721 else if (_cacheDependsRC)
1722 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);