static int rpmts_SolveCallback(rpmts ts, rpmds ds, const void * data) { struct rpmtsCallbackType_s * cbInfo = (struct rpmtsCallbackType_s *) data; PyObject * args, * result; int res = 1; if (cbInfo->tso == NULL) return res; if (cbInfo->cb == Py_None) return res; PyEval_RestoreThread(cbInfo->_save); args = Py_BuildValue("(Oissi)", cbInfo->tso, rpmdsTagN(ds), rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds)); result = PyEval_CallObject(cbInfo->cb, args); Py_DECREF(args); if (!result) { die(cbInfo->cb); } else { if (PyInt_Check(result)) res = PyInt_AsLong(result); Py_DECREF(result); } cbInfo->_save = PyEval_SaveThread(); return res; }
static rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds) { rpmte * ret = NULL; int i, found; const char * name; availableIndexEntry result; int resultCnt; int obsolete; availablePackage alp; int rc; if (al == NULL || ds == NULL || (name = rpmdsN(ds)) == NULL) return ret; if (al->providesHash == NULL && al->fileHash == NULL) rpmalMakeIndex(al); obsolete = (rpmdsTagN(ds) == RPMTAG_OBSOLETENAME); if (!obsolete && *name == '/') { /* First, look for files "contained" in package ... */ ret = rpmalAllFileSatisfiesDepend(al, ds); if (ret != NULL && *ret != NULL) return ret; /* ... then, look for files "provided" by package. */ ret = _free(ret); } rpmalProvidesHashGetEntry(al->providesHash, name, &result, &resultCnt, NULL); if (resultCnt==0) return NULL; ret = xmalloc((resultCnt+1) * sizeof(*ret)); for (found=i=0; i<resultCnt; i++) { alp = al->list + result[i].pkgNum; if (alp->p == NULL) // deleted continue; (void) rpmdsSetIx(alp->provides, result[i].entryIx); /* Obsoletes are on package name, filter out other provide matches */ if (obsolete && !rstreq(rpmdsN(alp->provides), rpmteN(alp->p))) continue; rc = 0; if (rpmdsIx(alp->provides) >= 0) rc = rpmdsCompare(alp->provides, ds); if (rc) { rpmdsNotify(ds, "(added provide)", 0); ret[found] = alp->p; found++; } } ret[found] = NULL; return ret; }
static rpmte * rpmalAllFileSatisfiesDepend(const rpmal al, const char *fileName, const rpmds filterds) { const char *slash; rpmte * ret = NULL; if (al == NULL || fileName == NULL || *fileName != '/') return NULL; /* Split path into dirname and basename components for lookup */ if ((slash = strrchr(fileName, '/')) != NULL) { availableIndexFileEntry result; int resultCnt = 0; size_t bnStart = (slash - fileName) + 1; rpmsid baseName; if (al->fileHash == NULL) rpmalMakeFileIndex(al); baseName = rpmstrPoolId(al->pool, fileName + bnStart, 0); if (!baseName) return NULL; /* no match possible */ rpmalFileHashGetEntry(al->fileHash, baseName, &result, &resultCnt, NULL); if (resultCnt > 0) { int i, found; ret = xmalloc((resultCnt+1) * sizeof(*ret)); fingerPrint * fp = NULL; rpmsid dirName = rpmstrPoolIdn(al->pool, fileName, bnStart, 1); if (!al->fpc) al->fpc = fpCacheCreate(1001, NULL); fpLookup(al->fpc, rpmstrPoolStr(al->pool, dirName), fileName + bnStart, &fp); for (found = i = 0; i < resultCnt; i++) { availablePackage alp = al->list + result[i].pkgNum; if (alp->p == NULL) /* deleted */ continue; /* ignore self-conflicts/obsoletes */ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds) continue; if (result[i].dirName != dirName && !fpLookupEquals(al->fpc, fp, rpmstrPoolStr(al->pool, result[i].dirName), fileName + bnStart)) continue; ret[found] = alp->p; found++; } _free(fp); ret[found] = NULL; } } return ret; }
static int haveRichDep(Package pkg) { for (int i = 0; i < PACKAGE_NUM_DEPS; i++) { rpmds ds = rpmdsInit(pkg->dependencies[i]); rpmTagVal tagN = rpmdsTagN(ds); if (tagN != RPMTAG_REQUIRENAME && tagN != RPMTAG_CONFLICTNAME) continue; while (rpmdsNext(ds) >= 0) { if (rpmdsIsRich(ds)) return 1; } } return 0; }
/* Check a dependency set for problems */ static void checkDS(rpmts ts, depCache dcache, rpmte te, const char * pkgNEVRA, rpmds ds, rpm_color_t tscolor) { rpm_color_t dscolor; /* require-problems are unsatisfied, others appear "satisfied" */ int is_problem = (rpmdsTagN(ds) == RPMTAG_REQUIRENAME); ds = rpmdsInit(ds); while (rpmdsNext(ds) >= 0) { /* Ignore colored dependencies not in our rainbow. */ dscolor = rpmdsColor(ds); if (tscolor && dscolor && !(tscolor & dscolor)) continue; if (unsatisfiedDepend(ts, dcache, ds) == is_problem) rpmteAddDepProblem(te, pkgNEVRA, ds, NULL); } }
static void finalizeDeps(Package pkg) { /* check if the package has a dependency with a '~' */ if (haveTildeDep(pkg)) (void) rpmlibNeedsFeature(pkg, "TildeInVersions", "4.10.0-1"); /* check if the package has a rich dependency */ if (haveRichDep(pkg)) (void) rpmlibNeedsFeature(pkg, "RichDependencies", "4.12.0-1"); /* All dependencies added finally, write them into the header */ for (int i = 0; i < PACKAGE_NUM_DEPS; i++) { /* Nuke any previously added dependencies from the header */ headerDel(pkg->header, rpmdsTagN(pkg->dependencies[i])); headerDel(pkg->header, rpmdsTagEVR(pkg->dependencies[i])); headerDel(pkg->header, rpmdsTagF(pkg->dependencies[i])); headerDel(pkg->header, rpmdsTagTi(pkg->dependencies[i])); /* ...and add again, now with automatic dependencies included */ rpmdsPutToHeader(pkg->dependencies[i], pkg->header); } }
int rpmdsPutToHeader(rpmds ds, Header h) { rpmTagVal tagN = rpmdsTagN(ds); rpmTagVal tagEVR = rpmdsTagEVR(ds); rpmTagVal tagF = rpmdsTagF(ds); rpmTagVal tagTi = rpmdsTagTi(ds); if (!tagN) return -1; rpmds pi = rpmdsInit(ds); while (rpmdsNext(pi) >= 0) { rpmsenseFlags flags = rpmdsFlags(pi); uint32_t index = rpmdsTi(pi); headerPutString(h, tagN, rpmdsN(pi)); headerPutString(h, tagEVR, rpmdsEVR(pi)); headerPutUint32(h, tagF, &flags, 1); if (tagTi != RPMTAG_NOT_FOUND) { headerPutUint32(h, tagTi, &index, 1); } } return 0; }
/** * Check dep for an unsatisfied dependency. * @param ts transaction set * @param dcache dependency cache * @param dep dependency * @return 0 if satisfied, 1 if not satisfied */ static int unsatisfiedDepend(rpmts ts, depCache dcache, rpmds dep) { tsMembers tsmem = rpmtsMembers(ts); int rc; int retrying = 0; int adding = (rpmdsInstance(dep) == 0); rpmsenseFlags dsflags = rpmdsFlags(dep); retry: rc = 0; /* assume dependency is satisfied */ /* * New features in rpm packaging implicitly add versioned dependencies * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)". * Check those dependencies now. */ if (dsflags & RPMSENSE_RPMLIB) { if (tsmem->rpmlib == NULL) rpmdsRpmlibPool(rpmtsPool(ts), &(tsmem->rpmlib), NULL); if (tsmem->rpmlib != NULL && rpmdsSearch(tsmem->rpmlib, dep) >= 0) { rpmdsNotify(dep, "(rpmlib provides)", rc); goto exit; } goto unsatisfied; } /* Dont look at pre-requisites of already installed packages */ if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags)) goto exit; /* Handle rich dependencies */ if (rpmdsIsRich(dep)) { rpmds ds1, ds2; rpmrichOp op; char *emsg = 0; if (rpmdsParseRichDep(dep, &ds1, &ds2, &op, &emsg) != RPMRC_OK) { rc = rpmdsTagN(dep) == RPMTAG_CONFLICTNAME ? 0 : 1; if (rpmdsInstance(dep) != 0) rc = !rc; /* ignore errors for installed packages */ rpmdsNotify(dep, emsg ? emsg : "(parse error)", rc); _free(emsg); goto exit; } if (op == RPMRICHOP_IF) { if (rpmdsIsRich(ds2)) { /* check if this is a IF...ELSE combination */ rpmds ds21 = NULL, ds22 = NULL; rpmrichOp op2; if (rpmdsParseRichDep(ds2, &ds21, &ds22, &op2, NULL) == RPMRC_OK && op2 == RPMRICHOP_ELSE) { rc = unsatisfiedDepend(ts, dcache, ds21); if (rc) { rpmdsFree(ds1); ds1 = ds22; ds22 = NULL; } rc = 1; } rpmdsFree(ds21); rpmdsFree(ds22); } if (!rc) rc = !unsatisfiedDepend(ts, dcache, ds2); } if (op != RPMRICHOP_IF || rc) rc = unsatisfiedDepend(ts, dcache, ds1); if ((rc && op == RPMRICHOP_OR) || (!rc && op == RPMRICHOP_AND)) rc = unsatisfiedDepend(ts, dcache, ds2); ds1 = rpmdsFree(ds1); ds2 = rpmdsFree(ds2); rpmdsNotify(dep, "(rich)", rc); goto exit; } /* Pretrans dependencies can't be satisfied by added packages. */ if (!(dsflags & RPMSENSE_PRETRANS)) { rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep); int match = matches && *matches; _free(matches); if (match) goto exit; } /* See if the rpmdb provides it */ if (rpmdbProvides(ts, dcache, dep) == 0) goto exit; /* Search for an unsatisfied dependency. */ if (adding && !retrying && !(dsflags & RPMSENSE_PRETRANS)) { int xx = rpmtsSolve(ts, dep); if (xx == 0) goto exit; if (xx == -1) { retrying = 1; goto retry; } } unsatisfied: if (dsflags & RPMSENSE_MISSINGOK) { /* note the result, but missingok deps are never unsatisfied */ rpmdsNotify(dep, "(missingok)", 1); } else { /* dependency is unsatisfied */ rc = 1; rpmdsNotify(dep, NULL, rc); } exit: return rc; }
/* Cached rpmdb provide lookup, returns 0 if satisfied, 1 otherwise */ static int rpmdbProvides(rpmts ts, depCache dcache, rpmds dep) { const char * Name = rpmdsN(dep); const char * DNEVR = rpmdsDNEVR(dep); rpmTagVal deptag = rpmdsTagN(dep); int *cachedrc = NULL; rpmdbMatchIterator mi = NULL; Header h = NULL; int rc = 0; /* pretrans deps are provided by current packages, don't prune erasures */ int prune = (rpmdsFlags(dep) & RPMSENSE_PRETRANS) ? 0 : 1; unsigned int keyhash = 0; /* See if we already looked this up */ if (prune) { keyhash = depCacheKeyHash(dcache, DNEVR); if (depCacheGetHEntry(dcache, DNEVR, keyhash, &cachedrc, NULL, NULL)) { rc = *cachedrc; rpmdsNotify(dep, "(cached)", rc); return rc; } } /* * See if a filename dependency is a real file in some package, * taking file state into account: replaced, wrong colored and * not installed files can not satisfy a dependency. */ if (deptag != RPMTAG_OBSOLETENAME && Name[0] == '/') { mi = rpmtsPrunedIterator(ts, RPMDBI_INSTFILENAMES, Name, prune); while ((h = rpmdbNextIterator(mi)) != NULL) { /* Ignore self-conflicts */ if (deptag == RPMTAG_CONFLICTNAME) { unsigned int instance = headerGetInstance(h); if (instance && instance == rpmdsInstance(dep)) continue; } rpmdsNotify(dep, "(db files)", rc); break; } rpmdbFreeIterator(mi); } /* Otherwise look in provides no matter what the dependency looks like */ if (h == NULL) { rpmstrPool tspool = rpmtsPool(ts); /* Obsoletes use just name alone, everything else uses provides */ rpmTagVal dbtag = RPMDBI_PROVIDENAME; int selfevr = 0; if (deptag == RPMTAG_OBSOLETENAME) { dbtag = RPMDBI_NAME; selfevr = 1; } mi = rpmtsPrunedIterator(ts, dbtag, Name, prune); while ((h = rpmdbNextIterator(mi)) != NULL) { /* Provide-indexes can't be used with nevr-only matching */ int prix = (selfevr) ? -1 : rpmdbGetIteratorFileNum(mi); int match = rpmdsMatches(tspool, h, prix, dep, selfevr, _rpmds_nopromote); /* Ignore self-obsoletes and self-conflicts */ if (match && (deptag == RPMTAG_OBSOLETENAME || deptag == RPMTAG_CONFLICTNAME)) { unsigned int instance = headerGetInstance(h); if (instance && instance == rpmdsInstance(dep)) match = 0; } if (match) { rpmdsNotify(dep, "(db provides)", rc); break; } } rpmdbFreeIterator(mi); } rc = (h != NULL) ? 0 : 1; /* Cache the relatively expensive rpmdb lookup results */ /* Caching the oddball non-pruned case would mess up other results */ if (prune) depCacheAddHEntry(dcache, xstrdup(DNEVR), keyhash, rc); return rc; }
/** * Check dep for an unsatisfied dependency. * @param ts transaction set * @param dep dependency * @return 0 if satisfied, 1 if not satisfied */ static int unsatisfiedDepend(rpmts ts, depCache dcache, rpmds dep) { tsMembers tsmem = rpmtsMembers(ts); int rc; int retrying = 0; int adding = (rpmdsInstance(dep) == 0); rpmsenseFlags dsflags = rpmdsFlags(dep); retry: rc = 0; /* assume dependency is satisfied */ /* * New features in rpm packaging implicitly add versioned dependencies * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)". * Check those dependencies now. */ if (dsflags & RPMSENSE_RPMLIB) { if (tsmem->rpmlib == NULL) rpmdsRpmlibPool(rpmtsPool(ts), &(tsmem->rpmlib), NULL); if (tsmem->rpmlib != NULL && rpmdsSearch(tsmem->rpmlib, dep) >= 0) { rpmdsNotify(dep, "(rpmlib provides)", rc); goto exit; } goto unsatisfied; } /* Dont look at pre-requisites of already installed packages */ if (!adding && isInstallPreReq(dsflags) && !isErasePreReq(dsflags)) goto exit; /* Pretrans dependencies can't be satisfied by added packages. */ if (!(dsflags & RPMSENSE_PRETRANS)) { rpmte *matches = rpmalAllSatisfiesDepend(tsmem->addedPackages, dep); int match = 0; /* * Handle definitive matches within the added package set. * Self-obsoletes and -conflicts fall through here as we need to * check for possible other matches in the rpmdb. */ for (rpmte *m = matches; m && *m; m++) { rpmTagVal dtag = rpmdsTagN(dep); /* Requires match, look no further */ if (dtag == RPMTAG_REQUIRENAME) { match = 1; break; } /* Conflicts/obsoletes match on another package, look no further */ if (rpmteDS(*m, dtag) != dep) { match = 1; break; } } free(matches); if (match) goto exit; } /* See if the rpmdb provides it */ if (rpmdbProvides(ts, dcache, dep) == 0) goto exit; /* Search for an unsatisfied dependency. */ if (adding && !retrying && !(dsflags & RPMSENSE_PRETRANS)) { int xx = rpmtsSolve(ts, dep); if (xx == 0) goto exit; if (xx == -1) { retrying = 1; goto retry; } } unsatisfied: if (dsflags & RPMSENSE_MISSINGOK) { /* note the result, but missingok deps are never unsatisfied */ rpmdsNotify(dep, "(missingok)", 1); } else { /* dependency is unsatisfied */ rc = 1; rpmdsNotify(dep, NULL, rc); } exit: return rc; }
static PyObject * rpmdsDep_TagN(rpmdsDepObject * s) { return Py_BuildValue("i", rpmdsTagN(s->ds)); }
rpmte * rpmalAllSatisfiesDepend(const rpmal al, const rpmds ds) { rpmte * ret = NULL; int i, ix, found; rpmsid nameId; const char *name; availableIndexEntry result; int resultCnt; int obsolete; rpmTagVal dtag; rpmds filterds = NULL; availablePackage alp; int rc; if (al == NULL || ds == NULL || (nameId = rpmdsNId(ds)) == 0) return ret; dtag = rpmdsTagN(ds); obsolete = (dtag == RPMTAG_OBSOLETENAME); if (dtag == RPMTAG_OBSOLETENAME || dtag == RPMTAG_CONFLICTNAME) filterds = ds; name = rpmstrPoolStr(al->pool, nameId); if (!obsolete && *name == '/') { /* First, look for files "contained" in package ... */ ret = rpmalAllFileSatisfiesDepend(al, name, filterds); if (ret != NULL && *ret != NULL) { rpmdsNotify(ds, "(added files)", 0); return ret; } /* ... then, look for files "provided" by package. */ ret = _free(ret); } if (al->providesHash == NULL) rpmalMakeProvidesIndex(al); rpmalDepHashGetEntry(al->providesHash, nameId, &result, &resultCnt, NULL); if (resultCnt==0) return NULL; ret = xmalloc((resultCnt+1) * sizeof(*ret)); for (found=i=0; i<resultCnt; i++) { alp = al->list + result[i].pkgNum; if (alp->p == NULL) /* deleted */ continue; /* ignore self-conflicts/obsoletes */ if (filterds && rpmteDS(alp->p, rpmdsTagN(filterds)) == filterds) continue; ix = result[i].entryIx; if (obsolete) { /* Obsoletes are on package NEVR only */ rpmds thisds; if (!rstreq(rpmdsNIndex(alp->provides, ix), rpmteN(alp->p))) continue; thisds = rpmteDS(alp->p, RPMTAG_NAME); rc = rpmdsCompareIndex(thisds, rpmdsIx(thisds), ds, rpmdsIx(ds)); } else { rc = rpmdsCompareIndex(alp->provides, ix, ds, rpmdsIx(ds)); } if (rc) ret[found++] = alp->p; } if (found) { rpmdsNotify(ds, "(added provide)", 0); ret[found] = NULL; } else { ret = _free(ret); } return ret; }