7 #include <rpm/rpmlib.h> /* rpmVersionCompare, rpmlib provides */
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmds.h>
12 #include <rpm/rpmfi.h>
14 #include "lib/rpmts_internal.h"
15 #include "lib/rpmte_internal.h"
16 #include "lib/rpmds_internal.h"
17 #include "lib/rpmfi_internal.h" /* rpmfiles stuff for now */
20 #include "lib/backend/dbiset.h"
24 const char * const RPMVERSION = VERSION;
26 const char * const rpmNAME = PACKAGE;
28 const char * const rpmEVR = VERSION;
30 const int rpmFLAGS = RPMSENSE_EQUAL;
36 #define HASHTYPE depCache
37 #define HTKEYTYPE const char *
38 #define HTDATATYPE int
39 #include "lib/rpmhash.H"
40 #include "lib/rpmhash.C"
45 #define HASHTYPE packageHash
46 #define HTKEYTYPE unsigned int
47 #define HTDATATYPE struct rpmte_s *
53 #define HASHTYPE filedepHash
54 #define HTKEYTYPE const char *
55 #define HTDATATYPE const char *
62 #define HASHTYPE depexistsHash
63 #define HTKEYTYPE const char *
64 #include "lib/rpmhash.H"
65 #include "lib/rpmhash.C"
76 * Check for supported payload format in header.
77 * @param h header to check
78 * @return RPMRC_OK if supported, RPMRC_FAIL otherwise
80 static rpmRC headerCheckPayloadFormat(Header h) {
82 const char *payloadfmt = headerGetString(h, RPMTAG_PAYLOADFORMAT);
84 * XXX Ugh, rpm 3.x packages don't have payload format tag. Instead
85 * of blindly allowing, should check somehow (HDRID existence or... ?)
87 if (!payloadfmt) return rc;
89 if (!rstreq(payloadfmt, "cpio")) {
90 char *nevra = headerGetAsString(h, RPMTAG_NEVRA);
91 if (payloadfmt && rstreq(payloadfmt, "drpm")) {
93 _("%s is a Delta RPM and cannot be directly installed\n"),
97 _("Unsupported payload (%s) in package %s\n"),
98 payloadfmt ? payloadfmt : "none", nevra);
107 * Add removed package instance to ordered transaction set.
108 * @param ts transaction set
110 * @param depends installed package of pair (or RPMAL_NOMATCH on erase)
111 * @return 0 on success
113 static int removePackage(rpmts ts, Header h, rpmte depends)
115 tsMembers tsmem = rpmtsMembers(ts);
117 unsigned int dboffset = headerGetInstance(h);
119 /* Can't remove what's not installed */
120 if (dboffset == 0) return 1;
122 /* Filter out duplicate erasures. */
123 if (packageHashGetEntry(tsmem->removedPackages, dboffset, &pp, NULL, NULL)) {
124 rpmteSetDependsOn(pp[0], depends);
128 p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL);
132 packageHashAddEntry(tsmem->removedPackages, dboffset, p);
134 if (tsmem->orderCount >= tsmem->orderAlloced) {
135 tsmem->orderAlloced += (tsmem->orderCount - tsmem->orderAlloced) + tsmem->delta;
136 tsmem->order = xrealloc(tsmem->order, sizeof(*tsmem->order) * tsmem->orderAlloced);
139 rpmteSetDependsOn(p, depends);
141 tsmem->order[tsmem->orderCount] = p;
147 /* Return rpmdb iterator with removals optionally pruned out */
148 rpmdbMatchIterator rpmtsPrunedIterator(rpmts ts, rpmDbiTagVal tag,
149 const char * key, int prune)
151 rpmdbMatchIterator mi = rpmtsInitIterator(ts, tag, key, 0);
153 tsMembers tsmem = rpmtsMembers(ts);
154 rpmdbPruneIterator(mi, tsmem->removedPackages);
160 * Decides whether to skip a package upgrade/obsoletion on TE color.
162 * @param tscolor color of this transaction
163 * @param color color of this transaction element
164 * @param ocolor header color of the upgraded/obsoleted package
166 * @return non-zero if the package should be skipped
168 static int skipColor(rpm_color_t tscolor, rpm_color_t color, rpm_color_t ocolor)
170 return tscolor && color && ocolor && !(color & ocolor);
173 static int rpmNameVersionCompare(Header first, Header second)
175 const char * one, * two;
178 one = headerGetString(first, RPMTAG_NAME);
179 two = headerGetString(second, RPMTAG_NAME);
180 rc = strcmp(one, two);
183 one = headerGetString(first, RPMTAG_ARCH);
184 two = headerGetString(second, RPMTAG_ARCH);
185 rc = strcmp(one, two);
188 return rpmVersionCompare(first, second);
191 /* Add erase elements for older packages of same color (if any). */
192 static int addSelfErasures(rpmts ts, rpm_color_t tscolor, int op,
193 rpmte p, rpm_color_t hcolor, Header h)
196 rpmdbMatchIterator mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(p), 0);
200 while ((oh = rpmdbNextIterator(mi)) != NULL) {
201 /* Ignore colored packages not in our rainbow. */
202 if (skipColor(tscolor, hcolor, headerGetNumber(oh, RPMTAG_HEADERCOLOR)))
205 cmp = rpmNameVersionCompare(h, oh);
207 /* On upgrade, skip packages that contain identical NEVR. */
208 if ((op == RPMTE_UPGRADE) && (cmp == 0))
211 /* On reinstall, skip packages with differing NEVR. */
212 if ((op == RPMTE_REINSTALL) && (cmp != 0))
215 if (removePackage(ts, oh, p)) {
220 rpmdbFreeIterator(mi);
224 /* Add erase elements for obsoleted packages of same color (if any). */
225 static int addObsoleteErasures(rpmts ts, rpm_color_t tscolor, rpmte p)
227 rpmstrPool tspool = rpmtsPool(ts);
228 rpmds obsoletes = rpmdsInit(rpmteDS(p, RPMTAG_OBSOLETENAME));
232 while (rpmdsNext(obsoletes) >= 0 && rc == 0) {
234 rpmdbMatchIterator mi = NULL;
236 if ((Name = rpmdsN(obsoletes)) == NULL)
237 continue; /* XXX can't happen */
239 mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, Name, 1);
241 while ((oh = rpmdbNextIterator(mi)) != NULL) {
242 const char *oarch = headerGetString(oh, RPMTAG_ARCH);
245 /* avoid self-obsoleting packages */
246 if (rstreq(rpmteN(p), Name) && rstreq(rpmteA(p), oarch)) {
247 char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA);
248 rpmlog(RPMLOG_DEBUG, " Not obsoleting: %s\n", ohNEVRA);
254 * Rpm prior to 3.0.3 does not have versioned obsoletes.
255 * If no obsoletes version info is available, match all names.
257 match = (rpmdsEVR(obsoletes) == NULL);
259 match = rpmdsMatches(tspool, oh, -1, obsoletes, 1,
263 char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA);
264 rpmlog(RPMLOG_DEBUG, " Obsoletes: %s\t\terases %s\n",
265 rpmdsDNEVR(obsoletes)+2, ohNEVRA);
268 if (removePackage(ts, oh, p)) {
274 rpmdbFreeIterator(mi);
280 * Lookup obsoletions in the added set. In theory there could
281 * be more than one obsoleting package, but we only care whether this
282 * has been obsoleted by *something* or not.
284 static rpmte checkObsoleted(rpmal addedPackages, rpmds thisds)
287 rpmte *matches = NULL;
289 matches = rpmalAllObsoletes(addedPackages, thisds);
298 * Filtered rpmal lookup: on colored transactions there can be more
299 * than one identical NEVR but different arch, this must be allowed.
300 * Only a single element needs to be considred as there can only ever
301 * be one previous element to be replaced.
303 static rpmte checkAdded(rpmal addedPackages, rpm_color_t tscolor,
307 rpmte *matches = NULL;
309 matches = rpmalAllSatisfiesDepend(addedPackages, ds);
311 const char * arch = rpmteA(te);
312 const char * os = rpmteO(te);
314 for (rpmte *m = matches; m && *m; m++) {
316 const char * parch = rpmteA(*m);
317 const char * pos = rpmteO(*m);
319 if (arch == NULL || parch == NULL || os == NULL || pos == NULL)
321 if (!rstreq(arch, parch) || !rstreq(os, pos))
333 * Check for previously added versions and obsoletions.
334 * Return index where to place this element, or -1 to skip.
335 * XXX OBSOLETENAME is a bit of a hack, but gives us what
336 * we want from rpmal: we're only interested in added package
337 * names here, not their provides.
339 static int findPos(rpmts ts, rpm_color_t tscolor, rpmte te, int upgrade)
341 tsMembers tsmem = rpmtsMembers(ts);
342 int oc = tsmem->orderCount;
344 const char * name = rpmteN(te);
345 const char * evr = rpmteEVR(te);
347 rpmstrPool tspool = rpmtsPool(ts);
348 rpmds oldChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
349 name, evr, (RPMSENSE_LESS));
350 rpmds newChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
351 name, evr, (RPMSENSE_GREATER));
352 rpmds sameChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME,
353 name, evr, (RPMSENSE_EQUAL));
354 rpmds obsChk = rpmteDS(te, RPMTAG_OBSOLETENAME);
356 /* If obsoleting package has already been added, skip this. */
357 if ((p = checkObsoleted(tsmem->addedPackages, rpmteDS(te, RPMTAG_NAME)))) {
362 /* If obsoleted package has already been added, replace with this. */
364 while (rpmdsNext(obsChk) >= 0) {
365 /* XXX Obsoletes are not colored */
366 if ((p = checkAdded(tsmem->addedPackages, 0, te, obsChk))) {
371 /* If same NEVR has already been added, skip this. */
372 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, sameChk))) {
379 /* ...if newer NEVR has already been added, skip this. */
380 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, newChk))) {
385 /* ...if older NEVR has already been added, replace with this. */
386 if ((p = checkAdded(tsmem->addedPackages, tscolor, te, oldChk))) {
392 /* If we found a previous element we've something to say */
393 if (p != NULL && rpmIsVerbose()) {
394 const char *msg = skip ?
395 _("package %s was already added, skipping %s\n") :
396 _("package %s was already added, replacing with %s\n");
397 rpmlog(RPMLOG_WARNING, msg, rpmteNEVRA(p), rpmteNEVRA(te));
400 /* If replacing a previous element, find out where it is. Pooh. */
401 if (!skip && p != NULL) {
402 for (oc = 0; oc < tsmem->orderCount; oc++) {
403 if (p == tsmem->order[oc])
411 return (skip) ? -1 : oc;
414 rpmal rpmtsCreateAl(rpmts ts, rpmElementTypes types)
420 rpmstrPool tspool = rpmtsPool(ts);
422 al = rpmalCreate(tspool, (rpmtsNElements(ts) / 4) + 1, rpmtsFlags(ts),
423 rpmtsColor(ts), rpmtsPrefColor(ts));
425 while ((p = rpmtsiNext(pi, types)))
432 static int addPackage(rpmts ts, Header h,
433 fnpyKey key, int op, rpmRelocation * relocs)
435 tsMembers tsmem = rpmtsMembers(ts);
436 rpm_color_t tscolor = rpmtsColor(ts);
438 int isSource = headerIsSource(h);
440 int oc = tsmem->orderCount;
442 /* Check for supported payload format if it's a package */
443 if (key && headerCheckPayloadFormat(h) != RPMRC_OK) {
448 /* Source packages are never "upgraded" */
452 /* Do lazy (readonly?) open of rpm database for upgrades. */
453 if (op != RPMTE_INSTALL && rpmtsGetRdb(ts) == NULL && rpmtsGetDBMode(ts) != -1) {
454 if ((ec = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
458 p = rpmteNew(ts, h, TR_ADDED, key, relocs);
464 /* Check binary packages for redundancies in the set */
466 oc = findPos(ts, tscolor, p, (op == RPMTE_UPGRADE));
467 /* If we're replacing a previously added element, free the old one */
468 if (oc >= 0 && oc < tsmem->orderCount) {
469 rpmalDel(tsmem->addedPackages, tsmem->order[oc]);
470 tsmem->order[oc] = rpmteFree(tsmem->order[oc]);
471 /* If newer NEVR was already added, we're done */
478 if (oc >= tsmem->orderAlloced) {
479 tsmem->orderAlloced += (oc - tsmem->orderAlloced) + tsmem->delta;
480 tsmem->order = xrealloc(tsmem->order,
481 tsmem->orderAlloced * sizeof(*tsmem->order));
485 tsmem->order[oc] = p;
486 if (oc == tsmem->orderCount) {
490 if (tsmem->addedPackages == NULL) {
491 tsmem->addedPackages = rpmalCreate(rpmtsPool(ts), 5, rpmtsFlags(ts),
492 tscolor, rpmtsPrefColor(ts));
494 rpmalAdd(tsmem->addedPackages, p);
496 /* Add erasure elements for old versions and obsoletions on upgrades */
497 /* XXX TODO: If either of these fails, we'd need to undo all additions */
498 if (op != RPMTE_INSTALL)
499 addSelfErasures(ts, tscolor, op, p, rpmteColor(p), h);
500 if (op == RPMTE_UPGRADE)
501 addObsoleteErasures(ts, tscolor, p);
507 int rpmtsAddInstallElement(rpmts ts, Header h,
508 fnpyKey key, int upgrade, rpmRelocation * relocs)
510 int op = (upgrade == 0) ? RPMTE_INSTALL : RPMTE_UPGRADE;
511 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
513 return addPackage(ts, h, key, op, relocs);
516 int rpmtsAddReinstallElement(rpmts ts, Header h, fnpyKey key)
518 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
520 /* TODO: pull relocations from installed package */
521 /* TODO: should reinstall of non-installed package fail? */
522 return addPackage(ts, h, key, RPMTE_REINSTALL, NULL);
525 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
527 if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL)
529 return removePackage(ts, h, NULL);
532 /* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */
533 static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep, dbiIndexSet *matches)
535 const char * Name = rpmdsN(dep);
536 const char * DNEVR = rpmdsDNEVR(dep);
537 rpmTagVal deptag = rpmdsTagN(dep);
538 int *cachedrc = NULL;
539 rpmdbMatchIterator mi = NULL;
542 /* pretrans deps are provided by current packages, don't prune erasures */
543 int prune = (rpmdsFlags(dep) & RPMSENSE_PRETRANS) ? 0 : 1;
544 unsigned int keyhash = 0;
546 /* See if we already looked this up */
547 if (prune && !matches) {
548 keyhash = depCacheKeyHash(dcache, DNEVR);
549 if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL, NULL)) {
551 rpmdsNotify(dep, "(cached)", rc);
557 *matches = dbiIndexSetNew(0);
559 * See if a filename dependency is a real file in some package,
560 * taking file state into account: replaced, wrong colored and
561 * not installed files can not satisfy a dependency.
563 if (deptag != RPMTAG_OBSOLETENAME && Name[0] == '/') {
564 mi = rpmtsPrunedIterator(ts, RPMDBI_INSTFILENAMES, Name, prune);
565 while ((h = rpmdbNextIterator(mi)) != NULL) {
566 /* Ignore self-conflicts */
567 if (deptag == RPMTAG_CONFLICTNAME) {
568 unsigned int instance = headerGetInstance(h);
569 if (instance && instance == rpmdsInstance(dep))
573 dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
576 rpmdsNotify(dep, "(db files)", rc);
579 rpmdbFreeIterator(mi);
582 /* Otherwise look in provides no matter what the dependency looks like */
584 rpmstrPool tspool = rpmtsPool(ts);
585 /* Obsoletes use just name alone, everything else uses provides */
586 rpmTagVal dbtag = RPMDBI_PROVIDENAME;
588 if (deptag == RPMTAG_OBSOLETENAME) {
593 mi = rpmtsPrunedIterator(ts, dbtag, Name, prune);
594 while ((h = rpmdbNextIterator(mi)) != NULL) {
595 /* Provide-indexes can't be used with nevr-only matching */
596 int prix = (selfevr) ? -1 : rpmdbGetIteratorFileNum(mi);
597 int match = rpmdsMatches(tspool, h, prix, dep, selfevr,
599 /* Ignore self-obsoletes and self-conflicts */
600 if (match && (deptag == RPMTAG_OBSOLETENAME || deptag == RPMTAG_CONFLICTNAME)) {
601 unsigned int instance = headerGetInstance(h);
602 if (instance && instance == rpmdsInstance(dep))
607 dbiIndexSetAppendOne(*matches, headerGetInstance(h), 0, 0);
610 rpmdsNotify(dep, "(db provides)", rc);
614 rpmdbFreeIterator(mi);
616 rc = (h != NULL) ? 0 : 1;
619 dbiIndexSetUniq(*matches, 0);
620 rc = dbiIndexSetCount(*matches) ? 0 : 1;
623 /* Cache the relatively expensive rpmdb lookup results */
624 /* Caching the oddball non-pruned case would mess up other results */
625 if (prune && !matches)
626 depCacheAddHEntry(dcache, xstrdup(DNEVR), keyhash, rc);
630 static dbiIndexSet unsatisfiedDependSet(rpmts ts, rpmds dep)
632 dbiIndexSet set1 = NULL, set2 = NULL;
633 tsMembers tsmem = rpmtsMembers(ts);
634 rpmsenseFlags dsflags = rpmdsFlags(dep);
636 if (dsflags & RPMSENSE_RPMLIB)
639 if (rpmdsIsRich(dep)) {
644 if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
645 rpmdsNotify(dep, emsg ? emsg : "(parse error)", 1);
649 /* only a subset of ops is supported in set mode */
650 if (op != RPMRICHOP_WITH && op != RPMRICHOP_WITHOUT
651 && op != RPMRICHOP_OR && op != RPMRICHOP_SINGLE) {
652 rpmdsNotify(dep, "(unsupported op in set mode)", 1);
656 set1 = unsatisfiedDependSet(ts, ds1);
657 if (op == RPMRICHOP_SINGLE)
659 if (op != RPMRICHOP_OR && dbiIndexSetCount(set1) == 0)
661 set2 = unsatisfiedDependSet(ts, ds2);
662 if (op == RPMRICHOP_WITH) {
663 dbiIndexSetFilterSet(set1, set2, 0);
664 } else if (op == RPMRICHOP_WITHOUT) {
665 dbiIndexSetPruneSet(set1, set2, 0);
666 } else if (op == RPMRICHOP_OR) {
667 dbiIndexSetAppendSet(set1, set2, 0);
670 ds1 = rpmdsFree(ds1);
671 ds2 = rpmdsFree(ds2);
675 /* match database entries */
676 rpmdbProvides(ts, NULL, dep, &set1);
678 /* Pretrans dependencies can't be satisfied by added packages. */
679 if (!(dsflags & RPMSENSE_PRETRANS)) {
680 rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
682 for (rpmte *p = matches; *p; p++)
683 dbiIndexSetAppendOne(set1, rpmalLookupTE(tsmem->addedPackages, *p), 1, 0);
689 set2 = dbiIndexSetFree(set2);
690 return set1 ? set1 : dbiIndexSetNew(0);
694 * Check dep for an unsatisfied dependency.
695 * @param ts transaction set
696 * @param dcache dependency cache
697 * @param dep dependency
698 * @return 0 if satisfied, 1 if not satisfied
700 static int unsatisfiedDepend(rpmts ts, depCache dcache, rpmds dep)
702 tsMembers tsmem = rpmtsMembers(ts);
705 int adding = (rpmdsInstance(dep) == 0);
706 rpmsenseFlags dsflags = rpmdsFlags(dep);
709 rc = 0; /* assume dependency is satisfied */
712 * New features in rpm packaging implicitly add versioned dependencies
713 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
714 * Check those dependencies now.
716 if (dsflags & RPMSENSE_RPMLIB) {
717 if (tsmem->rpmlib == NULL)
718 rpmdsRpmlibPool(rpmtsPool(ts), &(tsmem->rpmlib), NULL);
720 if (tsmem->rpmlib != NULL && rpmdsSearch(tsmem->rpmlib, dep) >= 0) {
721 rpmdsNotify(dep, "(rpmlib provides)", rc);
727 /* Dont look at pre-requisites of already installed packages */
728 if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags))
731 /* Handle rich dependencies */
732 if (rpmdsIsRich(dep)) {
736 if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) {
737 rc = rpmdsTagN(dep) == RPMTAG_CONFLICTNAME ? 0 : 1;
738 if (rpmdsInstance(dep) != 0)
739 rc = !rc; /* ignore errors for installed packages */
740 rpmdsNotify(dep, emsg ? emsg : "(parse error)", rc);
744 if (op == RPMRICHOP_WITH || op == RPMRICHOP_WITHOUT) {
745 /* switch to set mode processing */
746 dbiIndexSet set = unsatisfiedDependSet(ts, dep);
747 rc = dbiIndexSetCount(set) ? 0 : 1;
748 dbiIndexSetFree(set);
749 ds1 = rpmdsFree(ds1);
750 ds2 = rpmdsFree(ds2);
751 rpmdsNotify(dep, "(rich)", rc);
754 if (op == RPMRICHOP_IF || op == RPMRICHOP_UNLESS) {
755 /* A IF B -> A OR NOT(B) */
756 /* A UNLESS B -> A AND NOT(B) */
757 if (rpmdsIsRich(ds2)) {
758 /* check if this has an ELSE clause */
759 rpmds ds21 = NULL, ds22 = NULL;
761 if (rpmdsParseRichDep(ds2, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) {
762 /* A IF B ELSE C -> (A OR NOT(B)) AND (C OR B) */
763 /* A UNLESS B ELSE C -> (A AND NOT(B)) OR (C AND B) */
764 rc = !unsatisfiedDepend(ts, dcache, ds21); /* NOT(B) */
765 if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS)) {
766 rc = unsatisfiedDepend(ts, dcache, ds1); /* A */
768 rc = unsatisfiedDepend(ts, dcache, ds22); /* C */
777 rc = !unsatisfiedDepend(ts, dcache, ds2); /* NOT(B) */
778 if ((rc && op == RPMRICHOP_IF) || (!rc && op == RPMRICHOP_UNLESS))
779 rc = unsatisfiedDepend(ts, dcache, ds1);
781 rc = unsatisfiedDepend(ts, dcache, ds1);
782 if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND))
783 rc = unsatisfiedDepend(ts, dcache, ds2);
786 ds1 = rpmdsFree(ds1);
787 ds2 = rpmdsFree(ds2);
788 rpmdsNotify(dep, "(rich)", rc);
792 /* Pretrans dependencies can't be satisfied by added packages. */
793 if (!(dsflags & RPMSENSE_PRETRANS)) {
794 rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep);
795 int match = matches && *matches;
801 /* See if the rpmdb provides it */
802 if (rpmdbProvides(ts, dcache, dep, NULL) == 0)
805 /* Search for an unsatisfied dependency. */
806 if (adding && !retrying && !(dsflags & RPMSENSE_PRETRANS)) {
807 int xx = rpmtsSolve(ts, dep);
817 if (dsflags & RPMSENSE_MISSINGOK) {
818 /* note the result, but missingok deps are never unsatisfied */
819 rpmdsNotify(dep, "(missingok)", 1);
821 /* dependency is unsatisfied */
823 rpmdsNotify(dep, NULL, rc);
830 /* Check a dependency set for problems */
831 static void checkDS(rpmts ts, depCache dcache, rpmte te,
832 const char * pkgNEVRA, rpmds ds,
836 /* require-problems are unsatisfied, others appear "satisfied" */
837 int is_problem = (rpmdsTagN(ds) == RPMTAG_REQUIRENAME);
840 while (rpmdsNext(ds) >= 0) {
841 /* Ignore colored dependencies not in our rainbow. */
842 dscolor = rpmdsColor(ds);
843 if (tscolor && dscolor && !(tscolor & dscolor))
846 if (unsatisfiedDepend(ts, dcache, ds) == is_problem)
847 rpmteAddDepProblem(te, pkgNEVRA, ds, NULL);
851 /* Check a given dependency against installed packages */
852 static void checkInstDeps(rpmts ts, depCache dcache, rpmte te,
853 rpmTag depTag, const char *dep)
856 rpmdbMatchIterator mi = rpmtsPrunedIterator(ts, depTag, dep, 1);
857 rpmstrPool pool = rpmtsPool(ts);
858 /* require-problems are unsatisfied, others appear "satisfied" */
859 int is_problem = (depTag == RPMTAG_REQUIRENAME);
861 while ((h = rpmdbNextIterator(mi)) != NULL) {
865 /* Ignore self-obsoletes and self-conflicts */
866 if (depTag == RPMTAG_OBSOLETENAME || depTag == RPMTAG_CONFLICTNAME) {
867 unsigned int instance = headerGetInstance(h);
868 if (instance && instance == rpmteDBInstance(te))
872 pkgNEVRA = headerGetAsString(h, RPMTAG_NEVRA);
873 ds = rpmdsNewPool(pool, h, depTag, 0);
874 rpmdsSetIx(ds, rpmdbGetIteratorFileNum(mi));
876 if (unsatisfiedDepend(ts, dcache, ds) == is_problem)
877 rpmteAddDepProblem(te, pkgNEVRA, ds, NULL);
882 rpmdbFreeIterator(mi);
885 static void checkNotInstDeps(rpmts ts, depCache dcache, rpmte te,
886 rpmTag depTag, const char *dep)
888 char *ndep = rmalloc(strlen(dep) + 2);
890 strcpy(ndep + 1, dep);
891 checkInstDeps(ts, dcache, te, depTag, ndep);
895 static void checkInstFileDeps(rpmts ts, depCache dcache, rpmte te,
896 rpmTag depTag, rpmfi fi, int is_not,
897 filedepHash cache, fingerPrintCache *fpcp)
899 fingerPrintCache fpc = *fpcp;
900 fingerPrint * fp = NULL;
901 const char *basename = rpmfiBN(fi);
903 const char **dirnames = 0;
907 filedepHashGetEntry(cache, basename, &dirnames, &ndirnames, NULL);
911 *fpcp = fpc = fpCacheCreate(1001, NULL);
912 dirname = rpmfiDN(fi);
913 fpLookup(fpc, dirname, basename, &fp);
914 for (i = 0; i < ndirnames; i++) {
917 if (!strcmp(dirnames[i], dirname)) {
919 } else if (fpLookupEquals(fpc, fp, dirnames[i], basename)) {
920 fpdep = rmalloc(strlen(dirnames[i]) + strlen(basename) + 1);
921 strcpy(fpdep, dirnames[i]);
922 strcat(fpdep, basename);
928 checkInstDeps(ts, dcache, te, depTag, dep);
930 checkNotInstDeps(ts, dcache, te, depTag, dep);
936 static void addFileDepToHash(filedepHash hash, char *key, size_t keylen)
939 char *basename, *dirname;
940 if (!keylen || key[0] != '/')
942 for (i = keylen - 1; key[i] != '/'; i--)
944 dirname = rmalloc(i + 2);
945 memcpy(dirname, key, i + 1);
947 basename = rmalloc(keylen - i);
948 memcpy(basename, key + i + 1, keylen - i - 1);
949 basename[keylen - i - 1] = 0;
950 filedepHashAddEntry(hash, basename, dirname);
953 static void addDepToHash(depexistsHash hash, char *key, size_t keylen)
958 keystr = rmalloc(keylen + 1);
959 strncpy(keystr, key, keylen);
961 depexistsHashAddEntry(hash, keystr);
964 static void addIndexToDepHashes(rpmts ts, rpmDbiTag tag,
965 depexistsHash dephash, filedepHash filehash,
966 depexistsHash depnothash, filedepHash filenothash)
970 rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), tag);
974 while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) {
977 if (*key == '!' && keylen > 1) {
980 if (*key == '/' && filenothash)
981 addFileDepToHash(filenothash, key, keylen);
983 addDepToHash(depnothash, key, keylen);
985 if (*key == '/' && filehash)
986 addFileDepToHash(filehash, key, keylen);
988 addDepToHash(dephash, key, keylen);
991 rpmdbIndexIteratorFree(ii);
995 int rpmtsCheck(rpmts ts)
997 rpm_color_t tscolor = rpmtsColor(ts);
998 rpmtsi pi = NULL; rpmte p;
1001 depCache dcache = NULL;
1002 filedepHash confilehash = NULL; /* file conflicts of installed packages */
1003 filedepHash connotfilehash = NULL; /* file conflicts of installed packages */
1004 depexistsHash connothash = NULL;
1005 filedepHash reqfilehash = NULL; /* file requires of installed packages */
1006 filedepHash reqnotfilehash = NULL; /* file requires of installed packages */
1007 depexistsHash reqnothash = NULL;
1008 fingerPrintCache fpc = NULL;
1011 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1013 /* Do lazy, readonly, open of rpm database. */
1014 rdb = rpmtsGetRdb(ts);
1015 if (rdb == NULL && rpmtsGetDBMode(ts) != -1) {
1016 if ((rc = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0)
1018 rdb = rpmtsGetRdb(ts);
1023 rpmdbCtrl(rdb, RPMDB_CTRL_LOCK_RO);
1025 /* XXX FIXME: figure some kind of heuristic for the cache size */
1026 dcache = depCacheCreate(5001, rstrhash, strcmp,
1027 (depCacheFreeKey)rfree, NULL);
1029 /* build hashes of all confilict sdependencies */
1030 confilehash = filedepHashCreate(257, rstrhash, strcmp,
1031 (filedepHashFreeKey)rfree,
1032 (filedepHashFreeData)rfree);
1033 connothash = depexistsHashCreate(257, rstrhash, strcmp,
1034 (filedepHashFreeKey)rfree);
1035 connotfilehash = filedepHashCreate(257, rstrhash, strcmp,
1036 (filedepHashFreeKey)rfree,
1037 (filedepHashFreeData)rfree);
1038 addIndexToDepHashes(ts, RPMTAG_CONFLICTNAME, NULL, confilehash, connothash, connotfilehash);
1039 if (!filedepHashNumKeys(confilehash))
1040 confilehash = filedepHashFree(confilehash);
1041 if (!depexistsHashNumKeys(connothash))
1042 connothash= depexistsHashFree(connothash);
1043 if (!filedepHashNumKeys(connotfilehash))
1044 connotfilehash = filedepHashFree(connotfilehash);
1046 /* build hashes of all requires dependencies */
1047 reqfilehash = filedepHashCreate(8191, rstrhash, strcmp,
1048 (filedepHashFreeKey)rfree,
1049 (filedepHashFreeData)rfree);
1050 reqnothash = depexistsHashCreate(257, rstrhash, strcmp,
1051 (filedepHashFreeKey)rfree);
1052 reqnotfilehash = filedepHashCreate(257, rstrhash, strcmp,
1053 (filedepHashFreeKey)rfree,
1054 (filedepHashFreeData)rfree);
1055 addIndexToDepHashes(ts, RPMTAG_REQUIRENAME, NULL, reqfilehash, reqnothash, reqnotfilehash);
1056 if (!filedepHashNumKeys(reqfilehash))
1057 reqfilehash = filedepHashFree(reqfilehash);
1058 if (!depexistsHashNumKeys(reqnothash))
1059 reqnothash= depexistsHashFree(reqnothash);
1060 if (!filedepHashNumKeys(reqnotfilehash))
1061 reqnotfilehash = filedepHashFree(reqnotfilehash);
1064 * Look at all of the added packages and make sure their dependencies
1067 pi = rpmtsiInit(ts);
1068 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1069 rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME));
1071 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n",
1072 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1074 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_REQUIRENAME),
1076 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_CONFLICTNAME),
1078 checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_OBSOLETENAME),
1081 /* Check provides against conflicts in installed packages. */
1082 while (rpmdsNext(provides) >= 0) {
1083 const char *dep = rpmdsN(provides);
1084 checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
1085 if (reqnothash && depexistsHashHasEntry(reqnothash, dep))
1086 checkNotInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
1089 /* Skip obsoletion checks for source packages (ie build) */
1090 if (rpmteIsSource(p))
1093 /* Check package name (not provides!) against installed obsoletes */
1094 checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p));
1096 /* Check filenames against installed conflicts */
1097 if (confilehash || reqnotfilehash) {
1098 rpmfiles files = rpmteFiles(p);
1099 rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);
1100 while (rpmfiNext(fi) >= 0) {
1102 checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 0, confilehash, &fpc);
1104 checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 1, reqnotfilehash, &fpc);
1107 rpmfilesFree(files);
1113 * Look at the removed packages and make sure they aren't critical.
1115 pi = rpmtsiInit(ts);
1116 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1117 rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME));
1119 rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
1120 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1122 /* Check provides and filenames against installed dependencies. */
1123 while (rpmdsNext(provides) >= 0) {
1124 const char *dep = rpmdsN(provides);
1125 checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep);
1126 if (connothash && depexistsHashHasEntry(connothash, dep))
1127 checkNotInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep);
1130 if (reqfilehash || connotfilehash) {
1131 rpmfiles files = rpmteFiles(p);
1132 rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);;
1133 while (rpmfiNext(fi) >= 0) {
1134 if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) {
1136 checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 0, reqfilehash, &fpc);
1138 checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 1, connotfilehash, &fpc);
1142 rpmfilesFree(files);
1148 rpmdbCtrl(rdb, RPMDB_CTRL_UNLOCK_RO);
1151 depCacheFree(dcache);
1152 filedepHashFree(confilehash);
1153 filedepHashFree(connotfilehash);
1154 depexistsHashFree(connothash);
1155 filedepHashFree(reqfilehash);
1156 filedepHashFree(reqnotfilehash);
1157 depexistsHashFree(reqnothash);
1160 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
1163 (void) rpmtsCloseDB(ts);