static const char *matchFilesNext(matchFilesIter mfi) { const char *matchFile = NULL; int fx = 0; /* Decide if we iterate over given files (mfi->files) */ if (!mfi->ts) do { /* Get next file from mfi->fi */ rpmfiNext(mfi->fi); matchFile = rpmfiFN(mfi->fi); if (strlen(matchFile)) break; matchFile = NULL; /* If we are done with current mfi->fi, create mfi->fi for next prefix */ fx = rpmdsNext(mfi->rpmdsTrigger); mfi->pfx = rpmdsN(mfi->rpmdsTrigger); rpmfiFree(mfi->fi); mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx); } while (fx >= 0); /* or we iterate over files in rpmdb */ else do { rpmfiNext(mfi->fi); matchFile = rpmfiFN(mfi->fi); if (strlen(matchFile)) break; matchFile = NULL; /* If we are done with current mfi->fi, create mfi->fi for next package */ rpmfilesFree(mfi->files); rpmfiFree(mfi->fi); mfi->files = rpmtsNextFiles(mfi->ts, mfi->pi); mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx); if (mfi->files) continue; /* If we are done with all packages, go through packages with new prefix */ fx = rpmdsNext(mfi->rpmdsTrigger); mfi->pfx = rpmdsN(mfi->rpmdsTrigger); rpmdbFreeIterator(mfi->pi); mfi->pi = rpmdbInitPrefixIterator(rpmtsGetRdb(mfi->ts), RPMDBI_DIRNAMES, mfi->pfx, 0); rpmdbFilterIterator(mfi->pi, mfi->tranPkgs, 0); } while (fx >= 0); return matchFile; }
static int isNewDep(rpmds *dsp, rpmds bds, Header h, rpmTagVal indextag, uint32_t index) { int isnew = 1; if (!indextag) { /* With normal deps, we can just merge and see if anything got added */ isnew = (rpmdsMerge(dsp, bds) > 0); } else { struct rpmtd_s idx; rpmds ads = *dsp; headerGet(h, indextag, &idx, HEADERGET_MINMEM); /* rpmdsFind/Merge() probably isn't realiable with triggers... */ rpmdsInit(ads); while (isnew && rpmdsNext(ads) >= 0) { if (!rstreq(rpmdsN(ads), rpmdsN(bds))) continue; if (!rstreq(rpmdsEVR(ads), rpmdsEVR(bds))) continue; if (rpmdsFlags(ads) != rpmdsFlags(bds)) continue; if (indextag && rpmtdSetIndex(&idx, rpmdsIx(ads)) >= 0 && rpmtdGetNumber(&idx) != index) continue; isnew = 0; } rpmtdFreeData(&idx); rpmdsMerge(dsp, bds); } return isnew; }
static int depnevrsTagFiltered(Header h, rpmtd td, headerGetFlags hgflags, rpmTagVal tag, int strong) { rpmds ds = rpmdsNew(h, tag, 0); int ndeps = rpmdsCount(ds); if (ndeps > 0) { char **deps = xmalloc(sizeof(*deps) * ndeps); ndeps = 0; while (rpmdsNext(ds) >= 0) { if ((rpmdsFlags(ds) & RPMSENSE_STRONG) == (strong ? RPMSENSE_STRONG : 0)) deps[ndeps++] = rpmdsNewDNEVR(NULL, ds); } if (ndeps) { td->data = deps; td->type = RPM_STRING_ARRAY_TYPE; td->count = ndeps; td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED); } else { _free(deps); } } rpmdsFree(ds); return (ndeps > 0); }
int rpmdsAnyMatchesDep (const Header h, const rpmds req, int nopromote) { rpmds provides = NULL; int result = 0; /* Get provides information from header */ provides = rpmdsInit(rpmdsNew(h, RPMTAG_PROVIDENAME, 0)); if (provides == NULL) goto exit; /* XXX should never happen */ (void) rpmdsSetNoPromote(provides, nopromote); while (rpmdsNext(provides) >= 0) { result = rpmdsCompare(provides, req); /* If this provide matches the require, we're done. */ if (result) break; } exit: rpmdsFree(provides); return result; }
static int filedepTag(Header h, rpmTag tagN, rpmtd td, headerGetFlags hgflags) { rpmfi fi = rpmfiNew(NULL, h, RPMTAG_BASENAMES, RPMFI_NOHEADER); rpmds ds = NULL; char **fdeps = NULL; int numfiles; char deptype = 'R'; int fileix; int rc = 0; numfiles = rpmfiFC(fi); if (numfiles <= 0) { goto exit; } if (tagN == RPMTAG_PROVIDENAME) deptype = 'P'; else if (tagN == RPMTAG_REQUIRENAME) deptype = 'R'; ds = rpmdsNew(h, tagN, 0); fdeps = xmalloc(numfiles * sizeof(*fdeps)); while ((fileix = rpmfiNext(fi)) >= 0) { ARGV_t deps = NULL; const uint32_t * ddict = NULL; int ndx = rpmfiFDepends(fi, &ddict); if (ddict != NULL) { while (ndx-- > 0) { const char * DNEVR; unsigned dix = *ddict++; char mydt = ((dix >> 24) & 0xff); if (mydt != deptype) continue; dix &= 0x00ffffff; (void) rpmdsSetIx(ds, dix-1); if (rpmdsNext(ds) < 0) continue; DNEVR = rpmdsDNEVR(ds); if (DNEVR != NULL) { argvAdd(&deps, DNEVR + 2); } } } fdeps[fileix] = deps ? argvJoin(deps, " ") : xstrdup(""); argvFree(deps); } td->data = fdeps; td->count = numfiles; td->flags = RPMTD_ALLOCED | RPMTD_PTR_ALLOCED; td->type = RPM_STRING_ARRAY_TYPE; rc = 1; exit: rpmfiFree(fi); rpmdsFree(ds); return rc; }
int rpmdsSearch(rpmds ds, rpmds ods) { int comparison; int i, l, u; const char *ON = rpmdsN(ods); if (ds == NULL || ods == NULL) return -1; /* Binary search to find the [l,u) subset that contains N */ i = -1; l = 0; u = ds->Count; while (l < u) { i = (l + u) / 2; comparison = strcmp(ON, rpmdsNIndex(ds, i)); if (comparison < 0) u = i; else if (comparison > 0) l = i + 1; else { /* Set l to 1st member of set that contains N. */ if (!rstreq(ON, rpmdsNIndex(ds, l))) l = i; while (l > 0 && rstreq(ON, rpmdsNIndex(ds, l-1))) l--; /* Set u to 1st member of set that does not contain N. */ if (u >= ds->Count || !rstreq(ON, rpmdsNIndex(ds, u))) u = i; while (++u < ds->Count) { if (!rstreq(ON, rpmdsNIndex(ds, u))) break; } break; } } /* Check each member of [l,u) subset for ranges overlap. */ i = -1; if (l < u) { int save = rpmdsSetIx(ds, l-1); while ((l = rpmdsNext(ds)) >= 0 && (l < u)) { if ((i = rpmdsCompare(ods, ds)) != 0) break; } /* Return element index that overlaps, or -1. */ if (i) i = rpmdsIx(ds); else { (void) rpmdsSetIx(ds, save); i = -1; } } return i; }
void rpmtriggersPrepPostUnTransFileTrigs(rpmts ts, rpmte te) { rpmdbMatchIterator mi; rpmdbIndexIterator ii; Header trigH; const void *key; size_t keylen; rpmfiles files; rpmds rpmdsTriggers; rpmds rpmdsTrigger; int tix = 0; ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMDBI_TRANSFILETRIGGERNAME); mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES); files = rpmteFiles(te); /* Iterate over file triggers in rpmdb */ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) { char pfx[keylen + 1]; memcpy(pfx, key, keylen); pfx[keylen] = '\0'; /* Check if file trigger matches any file in this te */ rpmfi fi = rpmfilesFindPrefix(files, pfx); if (rpmfiFC(fi) > 0) { /* If yes then store it */ rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii), rpmdbIndexIteratorNumPkgs(ii)); } rpmfiFree(fi); } rpmdbIndexIteratorFree(ii); if (rpmdbGetIteratorCount(mi)) { /* Filter triggers and save only trans postun triggers into ts */ while((trigH = rpmdbNextIterator(mi)) != NULL) { rpmdsTriggers = rpmdsNew(trigH, RPMTAG_TRANSFILETRIGGERNAME, 0); while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, tix))) { if ((rpmdsNext(rpmdsTrigger) >= 0) && (rpmdsFlags(rpmdsTrigger) & RPMSENSE_TRIGGERPOSTUN)) { struct rpmtd_s priorities; headerGet(trigH, RPMTAG_TRANSFILETRIGGERPRIORITIES, &priorities, HEADERGET_MINMEM); rpmtdSetIndex(&priorities, tix); rpmtriggersAdd(ts->trigs2run, rpmdbGetIteratorOffset(mi), tix, *rpmtdGetUint32(&priorities)); } rpmdsFree(rpmdsTrigger); tix++; } rpmdsFree(rpmdsTriggers); } } rpmdbFreeIterator(mi); }
static void rpmdsPrint(const char * msg, rpmds ds, FILE * fp) { if (fp == NULL) fp = stderr; if (msg) fprintf(fp, "===================================== %s\n", msg); ds = rpmdsInit(ds); while (rpmdsNext(ds) >= 0) fprintf(fp, "%s\n", rpmdsDNEVR(ds)+2); }
static int haveTildeDep(Package pkg) { for (int i = 0; i < PACKAGE_NUM_DEPS; i++) { rpmds ds = rpmdsInit(pkg->dependencies[i]); while (rpmdsNext(ds) >= 0) { if (strchr(rpmdsEVR(ds), '~')) return 1; } } return 0; }
/* Add erase elements for obsoleted packages of same color (if any). */ static int addObsoleteErasures(rpmts ts, rpm_color_t tscolor, rpmte p) { rpmstrPool tspool = rpmtsPool(ts); rpmds obsoletes = rpmdsInit(rpmteDS(p, RPMTAG_OBSOLETENAME)); Header oh; int rc = 0; while (rpmdsNext(obsoletes) >= 0 && rc == 0) { const char * Name; rpmdbMatchIterator mi = NULL; if ((Name = rpmdsN(obsoletes)) == NULL) continue; /* XXX can't happen */ mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, Name, 1); while((oh = rpmdbNextIterator(mi)) != NULL) { const char *oarch = headerGetString(oh, RPMTAG_ARCH); int match; /* avoid self-obsoleting packages */ if (rstreq(rpmteN(p), Name) && rstreq(rpmteA(p), oarch)) { char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA); rpmlog(RPMLOG_DEBUG, " Not obsoleting: %s\n", ohNEVRA); free(ohNEVRA); continue; } /* * Rpm prior to 3.0.3 does not have versioned obsoletes. * If no obsoletes version info is available, match all names. */ match = (rpmdsEVR(obsoletes) == NULL); if (!match) match = rpmdsMatches(tspool, oh, -1, obsoletes, 1, _rpmds_nopromote); if (match) { char * ohNEVRA = headerGetAsString(oh, RPMTAG_NEVRA); rpmlog(RPMLOG_DEBUG, " Obsoletes: %s\t\terases %s\n", rpmdsDNEVR(obsoletes)+2, ohNEVRA); free(ohNEVRA); if (removePackage(ts, oh, p)) { rc = 1; break; } } } rpmdbFreeIterator(mi); } return rc; }
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; }
static VALUE rpmds_Ix_set(VALUE s, VALUE v) { rpmds ds = rpmds_ptr(s); int ix = FIX2INT(v); if (_debug) fprintf(stderr, "==> %s(0x%lx) ptr %p\n", __FUNCTION__, s, ds); if (ix != rpmdsIx(ds)) { (void) rpmdsSetIx(ds, ix-1); /* XXX flush and recreate N and DNEVR with a rpmdsNext() step */ (void) rpmdsNext(ds); } return INT2FIX(rpmdsIx(ds)); }
/* 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 int depnevrsTag(Header h, rpmtd td, headerGetFlags hgflags, rpmTagVal tag) { rpmds ds = rpmdsNew(h, tag, 0); int ndeps = rpmdsCount(ds); if (ndeps > 0) { char **deps = xmalloc(sizeof(*deps) * ndeps); int i; while ((i = rpmdsNext(ds)) >= 0) { deps[i] = rpmdsNewDNEVR(NULL, ds); } td->data = deps; td->type = RPM_STRING_ARRAY_TYPE; td->count = ndeps; td->flags |= (RPMTD_ALLOCED | RPMTD_PTR_ALLOCED); } rpmdsFree(ds); return (ndeps > 0); }
static PyObject * rpmds_iternext(rpmdsObject * s) { PyObject * result = NULL; /* Reset loop indices on 1st entry. */ if (s->cur == NULL) { s->ds = rpmdsInit(s->ds); } else { Py_DECREF(s->cur); } /* If more to do, return a (N, EVR, Flags) tuple. */ if (rpmdsNext(s->ds) >= 0) { s->cur = rpmdsDep_Wrap(s->ds); result = (PyObject*) s->cur; } else { s->cur = NULL; } return result; }
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; }
static void rpmalAddProvides(rpmal al, rpmalNum pkgNum, rpmds provides) { struct availableIndexEntry_s indexEntry; rpm_color_t dscolor; int skipconf = (al->tsflags & RPMTRANS_FLAG_NOCONFIGS); indexEntry.pkgNum = pkgNum; if (rpmdsInit(provides) != NULL) while (rpmdsNext(provides) >= 0) { /* Ignore colored provides not in our rainbow. */ dscolor = rpmdsColor(provides); if (al->tscolor && dscolor && !(al->tscolor & dscolor)) continue; /* Ignore config() provides if the files wont be installed */ if (skipconf & (rpmdsFlags(provides) & RPMSENSE_CONFIG)) continue; indexEntry.entryIx = rpmdsIx(provides); rpmalProvidesHashAddEntry(al->providesHash, rpmdsN(provides), indexEntry); } }
int rpmdsMatches(rpmstrPool pool, Header h, int prix, rpmds req, int selfevr, int nopromote) { rpmds provides; rpmTagVal tag = RPMTAG_PROVIDENAME; int result = 0; /* Get provides information from header */ if (selfevr) provides = rpmdsThisPool(pool, h, tag, RPMSENSE_EQUAL); else provides = rpmdsNewPool(pool, h, tag, 0); rpmdsSetNoPromote(provides, nopromote); /* * For a self-provide and indexed provide, we only need one comparison. * Otherwise loop through the provides until match or end. */ if (prix >= 0 || selfevr) { if (prix >= 0) rpmdsSetIx(provides, prix); result = rpmdsCompare(provides, req); } else { provides = rpmdsInit(provides); while (rpmdsNext(provides) >= 0) { result = rpmdsCompare(provides, req); /* If this provide matches the require, we're done. */ if (result) break; } } rpmdsFree(provides); return result; }
static PyObject * rpmds_subscript(rpmdsObject * s, PyObject * key) { int ix; rpmdsDepObject *dso = NULL; if (!PyInt_Check(key)) { PyErr_SetString(PyExc_TypeError, "integer expected"); return NULL; } ix = (int) PyInt_AsLong(key); if (ix >= 0 && ix < rpmdsCount(s->ds)) { /* XXX work around rpmds brokenness, fix this junk in rpm... */ rpmdsSetIx(s->ds, ix-1); if (rpmdsNext(s->ds) >= 0) { dso = rpmdsDep_Wrap(s->ds); } } if (dso == NULL) { PyErr_SetString(PyExc_IndexError, "index out of bounds"); } return (PyObject*) dso; }
static int rpmlibDeps(Header h) { rpmds req = rpmdsInit(rpmdsNew(h, RPMTAG_REQUIRENAME, 0)); rpmds rpmlib = NULL; rpmdsRpmlib(&rpmlib, NULL); int rc = 1; char *nvr = NULL; while (rpmdsNext(req) >= 0) { if (!(rpmdsFlags(req) & RPMSENSE_RPMLIB)) continue; if (rpmdsSearch(rpmlib, req) < 0) { if (!nvr) { nvr = headerGetAsString(h, RPMTAG_NEVRA); rpmlog(RPMLOG_ERR, _("Missing rpmlib features for %s:\n"), nvr); } rpmlog(RPMLOG_ERR, "\t%s\n", rpmdsDNEVR(req)+2); rc = 0; } } rpmdsFree(req); rpmdsFree(rpmlib); free(nvr); return rc; }
int rpmdsMerge(rpmds * dsp, rpmds ods) { rpmds ds; int save; int ocount; if (dsp == NULL || ods == NULL) return -1; ocount = rpmdsCount(*dsp); /* If not initialized yet, dup the 1st entry. */ if (*dsp == NULL) { save = ods->Count; ods->Count = 1; *dsp = rpmdsDup(ods); ods->Count = save; } ds = *dsp; if (ds == NULL) return -1; /* Ensure EVR and Flags exist */ if (ds->EVR == NULL) ds->EVR = xcalloc(ds->Count, sizeof(*ds->EVR)); if (ds->Flags == NULL) ds->Flags = xcalloc(ds->Count, sizeof(*ds->Flags)); if (ds->ti == NULL && ods->ti) { int i; ds->ti = xcalloc(ds->Count, sizeof(*ds->ti)); for (i = 0; i < ds->Count; i++) ds->ti[i] = -1; } /* * Add new entries. */ save = ods->i; ods = rpmdsInit(ods); while (rpmdsNext(ods) >= 0) { const char *OEVR; unsigned int u; /* * If this entry is already present, don't bother. */ if (doFind(ds, ods, &u) >= 0) continue; /* * Insert new entry. Ensure pool is unfrozen to allow additions. */ rpmstrPoolUnfreeze(ds->pool); ds->N = xrealloc(ds->N, (ds->Count+1) * sizeof(*ds->N)); if (u < ds->Count) { memmove(ds->N + u + 1, ds->N + u, (ds->Count - u) * sizeof(*ds->N)); } ds->N[u] = rpmstrPoolId(ds->pool, rpmdsN(ods), 1); ds->EVR = xrealloc(ds->EVR, (ds->Count+1) * sizeof(*ds->EVR)); if (u < ds->Count) { memmove(ds->EVR + u + 1, ds->EVR + u, (ds->Count - u) * sizeof(*ds->EVR)); } OEVR = rpmdsEVR(ods); ds->EVR[u] = rpmstrPoolId(ds->pool, OEVR ? OEVR : "", 1); ds->Flags = xrealloc(ds->Flags, (ds->Count+1) * sizeof(*ds->Flags)); if (u < ds->Count) { memmove(ds->Flags + u + 1, ds->Flags + u, (ds->Count - u) * sizeof(*ds->Flags)); } ds->Flags[u] = rpmdsFlags(ods); if (ds->ti || ods->ti) { ds->ti = xrealloc(ds->ti, (ds->Count+1) * sizeof(*ds->ti)); if (u < ds->Count) { memmove(ds->ti + u + 1, ds->ti + u, (ds->Count - u) * sizeof(*ds->ti)); } ds->ti[u] = rpmdsTi(ods); } ds->i = ds->Count; ds->Count++; } ods->i = save; return (ds->Count - ocount); }
int rpmdsMerge(rpmds * dsp, rpmds ods) { rpmds ds; const char ** N; const char ** EVR; rpmsenseFlags * Flags; int j; int save; if (dsp == NULL || ods == NULL) return -1; /* If not initialized yet, dup the 1st entry. */ if (*dsp == NULL) { save = ods->Count; ods->Count = 1; *dsp = rpmdsDup(ods); ods->Count = save; } ds = *dsp; if (ds == NULL) return -1; /* * Add new entries. */ save = ods->i; ods = rpmdsInit(ods); while (rpmdsNext(ods) >= 0) { /* * If this entry is already present, don't bother. */ if (rpmdsFind(ds, ods) >= 0) continue; /* * Insert new entry. */ for (j = ds->Count; j > ds->u; j--) ds->N[j] = ds->N[j-1]; ds->N[ds->u] = ods->N[ods->i]; N = rpmdsDupArgv(ds->N, ds->Count+1); ds->N = _free(ds->N); ds->N = N; /* XXX rpm prior to 3.0.2 did not always supply EVR and Flags. */ assert(ods->EVR != NULL); assert(ods->Flags != NULL); for (j = ds->Count; j > ds->u; j--) ds->EVR[j] = ds->EVR[j-1]; ds->EVR[ds->u] = ods->EVR[ods->i]; EVR = rpmdsDupArgv(ds->EVR, ds->Count+1); ds->EVR = _free(ds->EVR); ds->EVR = EVR; Flags = xmalloc((ds->Count+1) * sizeof(*Flags)); if (ds->u > 0) memcpy(Flags, ds->Flags, ds->u * sizeof(*Flags)); if (ds->u < ds->Count) memcpy(Flags + ds->u + 1, ds->Flags + ds->u, (ds->Count - ds->u) * sizeof(*Flags)); Flags[ds->u] = ods->Flags[ods->i]; ds->Flags = _free(ds->Flags); ds->Flags = Flags; ds->i = ds->Count; ds->Count++; } ods->i = save; return 0; }
/* * Check for previously added versions and obsoletions. * Return index where to place this element, or -1 to skip. * XXX OBSOLETENAME is a bit of a hack, but gives us what * we want from rpmal: we're only interested in added package * names here, not their provides. */ static int findPos(rpmts ts, rpm_color_t tscolor, rpmte te, int upgrade) { tsMembers tsmem = rpmtsMembers(ts); int oc = tsmem->orderCount; int skip = 0; const char * name = rpmteN(te); const char * evr = rpmteEVR(te); rpmte p; rpmstrPool tspool = rpmtsPool(ts); rpmds oldChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME, name, evr, (RPMSENSE_LESS)); rpmds newChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME, name, evr, (RPMSENSE_GREATER)); rpmds sameChk = rpmdsSinglePool(tspool, RPMTAG_OBSOLETENAME, name, evr, (RPMSENSE_EQUAL)); rpmds obsChk = rpmteDS(te, RPMTAG_OBSOLETENAME); /* If obsoleting package has already been added, skip this. */ if ((p = checkObsoleted(tsmem->addedPackages, rpmteDS(te, RPMTAG_NAME)))) { skip = 1; goto exit; } /* If obsoleted package has already been added, replace with this. */ rpmdsInit(obsChk); while (rpmdsNext(obsChk) >= 0) { /* XXX Obsoletes are not colored */ if ((p = checkAdded(tsmem->addedPackages, 0, te, obsChk))) { goto exit; } } /* If same NEVR has already been added, skip this. */ if ((p = checkAdded(tsmem->addedPackages, tscolor, te, sameChk))) { skip = 1; goto exit; } /* On upgrades... */ if (upgrade) { /* ...if newer NEVR has already been added, skip this. */ if ((p = checkAdded(tsmem->addedPackages, tscolor, te, newChk))) { skip = 1; goto exit; } /* ...if older NEVR has already been added, replace with this. */ if ((p = checkAdded(tsmem->addedPackages, tscolor, te, oldChk))) { goto exit; } } exit: /* If we found a previous element we've something to say */ if (p != NULL && rpmIsVerbose()) { const char *msg = skip ? _("package %s was already added, skipping %s\n") : _("package %s was already added, replacing with %s\n"); rpmlog(RPMLOG_WARNING, msg, rpmteNEVRA(p), rpmteNEVRA(te)); } /* If replacing a previous element, find out where it is. Pooh. */ if (!skip && p != NULL) { for (oc = 0; oc < tsmem->orderCount; oc++) { if (p == tsmem->order[oc]) break; } } rpmdsFree(oldChk); rpmdsFree(newChk); rpmdsFree(sameChk); return (skip) ? -1 : oc; }
int rpmtsCheck(rpmts ts) { rpm_color_t tscolor = rpmtsColor(ts); rpmtsi pi = NULL; rpmte p; int closeatexit = 0; int rc = 0; depCache dcache = NULL; conflictsCache confcache = NULL; (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0); /* Do lazy, readonly, open of rpm database. */ if (rpmtsGetRdb(ts) == NULL && rpmtsGetDBMode(ts) != -1) { if ((rc = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0) goto exit; closeatexit = 1; } /* XXX FIXME: figure some kind of heuristic for the cache size */ dcache = depCacheCreate(5001, rstrhash, strcmp, (depCacheFreeKey)rfree, NULL); confcache = conflictsCacheCreate(257, rstrhash, strcmp, (depCacheFreeKey)rfree); if (confcache) { rpmdbIndexIterator ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), RPMTAG_CONFLICTNAME); if (ii) { char *key; size_t keylen; while ((rpmdbIndexIteratorNext(ii, (const void**)&key, &keylen)) == 0) { char *k; if (!key || keylen == 0 || key[0] != '/') continue; k = rmalloc(keylen + 1); memcpy(k, key, keylen); k[keylen] = 0; conflictsCacheAddEntry(confcache, k); } rpmdbIndexIteratorFree(ii); } } /* * Look at all of the added packages and make sure their dependencies * are satisfied. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) { rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME)); rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_REQUIRENAME), NULL, tscolor); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_CONFLICTNAME), NULL, tscolor); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_OBSOLETENAME), NULL, tscolor); /* Check provides against conflicts in installed packages. */ while (rpmdsNext(provides) >= 0) { checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, rpmdsN(provides)); } /* Skip obsoletion checks for source packages (ie build) */ if (rpmteIsSource(p)) continue; /* Check package name (not provides!) against installed obsoletes */ checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p)); /* Check filenames against installed conflicts */ if (conflictsCacheNumKeys(confcache)) { rpmfi fi = rpmfiInit(rpmteFI(p), 0); while (rpmfiNext(fi) >= 0) { const char *fn = rpmfiFN(fi); if (!conflictsCacheHasEntry(confcache, fn)) continue; checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fn); } } } rpmtsiFree(pi); /* * Look at the removed packages and make sure they aren't critical. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME)); rpmfi fi = rpmfiInit(rpmteFI(p), 0); rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); /* Check provides and filenames against installed dependencies. */ while (rpmdsNext(provides) >= 0) { checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, rpmdsN(provides)); } while (rpmfiNext(fi) >= 0) { if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, rpmfiFN(fi)); } } rpmtsiFree(pi); exit: depCacheFree(dcache); conflictsCacheFree(confcache); (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0); if (closeatexit) (void) rpmtsCloseDB(ts); return rc; }
/** * Execute triggers. * @todo Trigger on any provides, not just package NVR. * @param ts transaction set * @param te transaction element * @param sense trigger type * @param sourceH header of trigger source * @param trigH header of triggered package * @param arg2 * @param triggersAlreadyRun * @return */ static rpmRC handleOneTrigger(rpmts ts, rpmte te, rpmsenseFlags sense, Header sourceH, Header trigH, int countCorrection, int arg2, unsigned char * triggersAlreadyRun) { rpmds trigger = rpmdsInit(rpmdsNew(trigH, RPMTAG_TRIGGERNAME, 0)); struct rpmtd_s pfx; const char * sourceName = headerGetString(sourceH, RPMTAG_NAME); const char * triggerName = headerGetString(trigH, RPMTAG_NAME); rpmRC rc = RPMRC_OK; int i; if (trigger == NULL) return rc; headerGet(trigH, RPMTAG_INSTPREFIXES, &pfx, HEADERGET_ALLOC|HEADERGET_ARGV); (void) rpmdsSetNoPromote(trigger, 1); while ((i = rpmdsNext(trigger)) >= 0) { uint32_t tix; if (!(rpmdsFlags(trigger) & sense)) continue; if (!rstreq(rpmdsN(trigger), sourceName)) continue; /* XXX Trigger on any provided dependency, not just the package NEVR */ if (!rpmdsAnyMatchesDep(sourceH, trigger, 1)) continue; tix = rpmdsTi(trigger); if (triggersAlreadyRun == NULL || triggersAlreadyRun[tix] == 0) { int arg1 = rpmdbCountPackages(rpmtsGetRdb(ts), triggerName); if (arg1 < 0) { /* XXX W2DO? fails as "execution of script failed" */ rc = RPMRC_FAIL; } else { rpmScript script = rpmScriptFromTriggerTag(trigH, triggertag(sense), tix); arg1 += countCorrection; rc = runScript(ts, te, pfx.data, script, arg1, arg2); if (triggersAlreadyRun != NULL) triggersAlreadyRun[tix] = 1; rpmScriptFree(script); } } /* * Each target/source header pair can only result in a single * script being run. */ break; } rpmtdFreeData(&pfx); rpmdsFree(trigger); return rc; }
rpmRC parseRCPOT(rpmSpec spec, Package pkg, const char *field, rpmTagVal tagN, int index, rpmsenseFlags tagflags) { const char *r, *re, *v, *ve; char *emsg = NULL; char * N = NULL, * EVR = NULL; rpmTagVal nametag = RPMTAG_NOT_FOUND; rpmsenseFlags Flags; rpmds *pdsp = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ switch (tagN) { default: case RPMTAG_REQUIREFLAGS: nametag = RPMTAG_REQUIRENAME; tagflags |= RPMSENSE_ANY; break; case RPMTAG_RECOMMENDFLAGS: nametag = RPMTAG_RECOMMENDNAME; break; case RPMTAG_SUGGESTFLAGS: nametag = RPMTAG_SUGGESTNAME; break; case RPMTAG_SUPPLEMENTFLAGS: nametag = RPMTAG_SUPPLEMENTNAME; break; case RPMTAG_ENHANCEFLAGS: nametag = RPMTAG_ENHANCENAME; break; case RPMTAG_PROVIDEFLAGS: nametag = RPMTAG_PROVIDENAME; break; case RPMTAG_OBSOLETEFLAGS: nametag = RPMTAG_OBSOLETENAME; break; case RPMTAG_CONFLICTFLAGS: nametag = RPMTAG_CONFLICTNAME; break; case RPMTAG_ORDERFLAGS: nametag = RPMTAG_ORDERNAME; break; case RPMTAG_PREREQ: /* XXX map legacy PreReq into Requires(pre,preun) */ nametag = RPMTAG_REQUIRENAME; tagflags |= (RPMSENSE_SCRIPT_PRE|RPMSENSE_SCRIPT_PREUN); break; case RPMTAG_TRIGGERPREIN: nametag = RPMTAG_TRIGGERNAME; tagflags |= RPMSENSE_TRIGGERPREIN; break; case RPMTAG_TRIGGERIN: nametag = RPMTAG_TRIGGERNAME; tagflags |= RPMSENSE_TRIGGERIN; break; case RPMTAG_TRIGGERPOSTUN: nametag = RPMTAG_TRIGGERNAME; tagflags |= RPMSENSE_TRIGGERPOSTUN; break; case RPMTAG_TRIGGERUN: nametag = RPMTAG_TRIGGERNAME; tagflags |= RPMSENSE_TRIGGERUN; break; case RPMTAG_BUILDPREREQ: case RPMTAG_BUILDREQUIRES: nametag = RPMTAG_REQUIRENAME; tagflags |= RPMSENSE_ANY; break; case RPMTAG_BUILDCONFLICTS: nametag = RPMTAG_CONFLICTNAME; break; case RPMTAG_FILETRIGGERIN: nametag = RPMTAG_FILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERIN; break; case RPMTAG_FILETRIGGERUN: nametag = RPMTAG_FILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERUN; break; case RPMTAG_FILETRIGGERPOSTUN: nametag = RPMTAG_FILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERPOSTUN; break; case RPMTAG_TRANSFILETRIGGERIN: nametag = RPMTAG_TRANSFILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERIN; break; case RPMTAG_TRANSFILETRIGGERUN: nametag = RPMTAG_TRANSFILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERUN; break; case RPMTAG_TRANSFILETRIGGERPOSTUN: nametag = RPMTAG_TRANSFILETRIGGERNAME; tagflags |= RPMSENSE_TRIGGERPOSTUN; break; } for (r = field; *r != '\0'; r = re) { SKIPWHITE(r); if (*r == '\0') break; Flags = (tagflags & ~RPMSENSE_SENSEMASK); if (r[0] == '(') { struct parseRCPOTRichData data; if (nametag != RPMTAG_REQUIRENAME && nametag != RPMTAG_CONFLICTNAME && nametag != RPMTAG_RECOMMENDNAME && nametag != RPMTAG_SUPPLEMENTNAME && nametag != RPMTAG_SUGGESTNAME && nametag != RPMTAG_ENHANCENAME) { rasprintf(&emsg, _("No rich dependencies allowed for this type")); goto exit; } data.spec = spec; data.sb = newStringBuf(); if (rpmrichParse(&r, &emsg, parseRCPOTRichCB, &data) != RPMRC_OK) { freeStringBuf(data.sb); goto exit; } if (addReqProv(pkg, nametag, getStringBuf(data.sb), NULL, Flags | RPMSENSE_RICH, index)) { rasprintf(&emsg, _("invalid dependency")); freeStringBuf(data.sb); goto exit; } freeStringBuf(data.sb); re = r; continue; } re = r; SKIPNONWHITE(re); N = xmalloc((re-r) + 1); rstrlcpy(N, r, (re-r) + 1); /* Parse EVR */ EVR = NULL; v = re; SKIPWHITE(v); ve = v; SKIPNONWHITE(ve); re = v; /* ==> next token (if no EVR found) starts here */ /* Check for possible logical operator */ if (ve > v) { rpmsenseFlags sense = rpmParseDSFlags(v, ve - v); if (sense) { Flags |= sense; /* now parse EVR */ v = ve; SKIPWHITE(v); ve = v; SKIPNONWHITE(ve); if (*v == '\0' || ve == v) { rasprintf(&emsg, _("Version required")); goto exit; } EVR = xmalloc((ve-v) + 1); rstrlcpy(EVR, v, (ve-v) + 1); re = ve; /* ==> next token after EVR string starts here */ } } /* check that dependency is well-formed */ if (checkDep(spec, N, EVR, &emsg)) goto exit; if (nametag == RPMTAG_FILETRIGGERNAME || nametag == RPMTAG_TRANSFILETRIGGERNAME) { if (N[0] != '/') { rasprintf(&emsg, _("Only absolute paths are allowed in " "file triggers")); } } /* Deny more "normal" triggers fired by the same pakage. File triggers are ok */ pdsp = packageDependencies(pkg, nametag); rpmdsInit(*pdsp); if (nametag == RPMTAG_TRIGGERNAME) { while (rpmdsNext(*pdsp) >= 0) { if (rstreq(rpmdsN(*pdsp), N) && ((rpmdsFlags(*pdsp) & tagflags))) { rasprintf(&emsg, _("Trigger fired by the same package " "is already defined in spec file")); goto exit; } } } if (addReqProv(pkg, nametag, N, EVR, Flags, index)) { rasprintf(&emsg, _("invalid dependency")); goto exit; } N = _free(N); EVR = _free(EVR); } rc = RPMRC_OK; exit: if (emsg) { int lvl = (rc == RPMRC_OK) ? RPMLOG_WARNING : RPMLOG_ERR; /* Automatic dependencies don't relate to spec lines */ if (tagflags & (RPMSENSE_FIND_REQUIRES|RPMSENSE_FIND_PROVIDES)) { rpmlog(lvl, "%s: %s\n", emsg, r); } else { rpmlog(lvl, _("line %d: %s: %s\n"), spec->lineNum, emsg, spec->line); } free(emsg); } _free(N); _free(EVR); return rc; }
/* * Run all file triggers in header h * @param searchMode 0 match trigger prefixes against files in te * 1 match trigger prefixes against files in whole ts * 2 match trigger prefixes against files in whole * rpmdb */ static int runHandleTriggersInPkg(rpmts ts, rpmte te, Header h, rpmsenseFlags sense, rpmscriptTriggerModes tm, int searchMode, int ti) { int nerrors = 0; rpmds rpmdsTriggers, rpmdsTrigger; rpmfiles files = NULL; matchFilesIter mfi = NULL; rpmScript script; struct rpmtd_s installPrefixes; char *(*inputFunc)(void *); rpmdsTriggers = rpmdsNew(h, triggerDsTag(tm), 0); rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, ti); /* * Now rpmdsTrigger contains all dependencies belonging to one trigger * with trigger index tix. Have a look at the first one to check flags. */ if ((rpmdsNext(rpmdsTrigger) >= 0) && (rpmdsFlags(rpmdsTrigger) & sense)) { switch (searchMode) { case 0: /* Create iterator over files in te that this trigger matches */ files = rpmteFiles(te); mfi = matchFilesIterator(rpmdsTrigger, files); break; case 1: /* Create iterator over files in ts that this trigger matches */ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 1); break; case 2: /* Create iterator over files in whole rpmd that this trigger matches */ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 0); break; } /* If this trigger matches any file then run trigger script */ if (!matchFilesEmpty(mfi)) { script = rpmScriptFromTriggerTag(h, triggertag(sense), tm, ti); headerGet(h, RPMTAG_INSTPREFIXES, &installPrefixes, HEADERGET_ALLOC|HEADERGET_ARGV); /* * As input function set function to get next file from * matching file iterator. As parameter for this function * set matching file iterator. Input function will be called * during execution of trigger script in order to get data * that will be passed as stdin to trigger script. To get * these data from lua script function rpm.input() can be used. */ inputFunc = (char *(*)(void *)) matchFilesNext; rpmScriptSetNextFileFunc(script, inputFunc, mfi); nerrors += runScript(ts, te, installPrefixes.data, script, 0, 0); rpmtdFreeData(&installPrefixes); rpmScriptFree(script); } rpmfilesFree(files); matchFilesIteratorFree(mfi); } rpmdsFree(rpmdsTrigger); rpmdsFree(rpmdsTriggers); return nerrors; }
int rpmtsCheck(rpmts ts) { rpm_color_t tscolor = rpmtsColor(ts); rpmtsi pi = NULL; rpmte p; int closeatexit = 0; int rc = 0; depCache dcache = NULL; filedepHash confilehash = NULL; /* file conflicts of installed packages */ filedepHash connotfilehash = NULL; /* file conflicts of installed packages */ depexistsHash connothash = NULL; filedepHash reqfilehash = NULL; /* file requires of installed packages */ filedepHash reqnotfilehash = NULL; /* file requires of installed packages */ depexistsHash reqnothash = NULL; fingerPrintCache fpc = NULL; rpmdb rdb = NULL; (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0); /* Do lazy, readonly, open of rpm database. */ rdb = rpmtsGetRdb(ts); if (rdb == NULL && rpmtsGetDBMode(ts) != -1) { if ((rc = rpmtsOpenDB(ts, rpmtsGetDBMode(ts))) != 0) goto exit; rdb = rpmtsGetRdb(ts); closeatexit = 1; } if (rdb) rpmdbCtrl(rdb, RPMDB_CTRL_LOCK_RO); /* XXX FIXME: figure some kind of heuristic for the cache size */ dcache = depCacheCreate(5001, rstrhash, strcmp, (depCacheFreeKey)rfree, NULL); /* build hashes of all confilict sdependencies */ confilehash = filedepHashCreate(257, rstrhash, strcmp, (filedepHashFreeKey)rfree, (filedepHashFreeData)rfree); connothash = depexistsHashCreate(257, rstrhash, strcmp, (filedepHashFreeKey)rfree); connotfilehash = filedepHashCreate(257, rstrhash, strcmp, (filedepHashFreeKey)rfree, (filedepHashFreeData)rfree); addIndexToDepHashes(ts, RPMTAG_CONFLICTNAME, NULL, confilehash, connothash, connotfilehash); if (!filedepHashNumKeys(confilehash)) confilehash = filedepHashFree(confilehash); if (!depexistsHashNumKeys(connothash)) connothash= depexistsHashFree(connothash); if (!filedepHashNumKeys(connotfilehash)) connotfilehash = filedepHashFree(connotfilehash); /* build hashes of all requires dependencies */ reqfilehash = filedepHashCreate(8191, rstrhash, strcmp, (filedepHashFreeKey)rfree, (filedepHashFreeData)rfree); reqnothash = depexistsHashCreate(257, rstrhash, strcmp, (filedepHashFreeKey)rfree); reqnotfilehash = filedepHashCreate(257, rstrhash, strcmp, (filedepHashFreeKey)rfree, (filedepHashFreeData)rfree); addIndexToDepHashes(ts, RPMTAG_REQUIRENAME, NULL, reqfilehash, reqnothash, reqnotfilehash); if (!filedepHashNumKeys(reqfilehash)) reqfilehash = filedepHashFree(reqfilehash); if (!depexistsHashNumKeys(reqnothash)) reqnothash= depexistsHashFree(reqnothash); if (!filedepHashNumKeys(reqnotfilehash)) reqnotfilehash = filedepHashFree(reqnotfilehash); /* * Look at all of the added packages and make sure their dependencies * are satisfied. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) { rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME)); rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_REQUIRENAME), tscolor); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_CONFLICTNAME), tscolor); checkDS(ts, dcache, p, rpmteNEVRA(p), rpmteDS(p, RPMTAG_OBSOLETENAME), tscolor); /* Check provides against conflicts in installed packages. */ while (rpmdsNext(provides) >= 0) { const char *dep = rpmdsN(provides); checkInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep); if (reqnothash && depexistsHashHasEntry(reqnothash, dep)) checkNotInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep); } /* Skip obsoletion checks for source packages (ie build) */ if (rpmteIsSource(p)) continue; /* Check package name (not provides!) against installed obsoletes */ checkInstDeps(ts, dcache, p, RPMTAG_OBSOLETENAME, rpmteN(p)); /* Check filenames against installed conflicts */ if (confilehash || reqnotfilehash) { rpmfiles files = rpmteFiles(p); rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD); while (rpmfiNext(fi) >= 0) { if (confilehash) checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 0, confilehash, &fpc); if (reqnotfilehash) checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 1, reqnotfilehash, &fpc); } rpmfiFree(fi); rpmfilesFree(files); } } rpmtsiFree(pi); /* * Look at the removed packages and make sure they aren't critical. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { rpmds provides = rpmdsInit(rpmteDS(p, RPMTAG_PROVIDENAME)); rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); /* Check provides and filenames against installed dependencies. */ while (rpmdsNext(provides) >= 0) { const char *dep = rpmdsN(provides); checkInstDeps(ts, dcache, p, RPMTAG_REQUIRENAME, dep); if (connothash && depexistsHashHasEntry(connothash, dep)) checkNotInstDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, dep); } if (reqfilehash || connotfilehash) { rpmfiles files = rpmteFiles(p); rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD);; while (rpmfiNext(fi) >= 0) { if (RPMFILE_IS_INSTALLED(rpmfiFState(fi))) { if (reqfilehash) checkInstFileDeps(ts, dcache, p, RPMTAG_REQUIRENAME, fi, 0, reqfilehash, &fpc); if (connotfilehash) checkInstFileDeps(ts, dcache, p, RPMTAG_CONFLICTNAME, fi, 1, connotfilehash, &fpc); } } rpmfiFree(fi); rpmfilesFree(files); } } rpmtsiFree(pi); if (rdb) rpmdbCtrl(rdb, RPMDB_CTRL_UNLOCK_RO); exit: depCacheFree(dcache); filedepHashFree(confilehash); filedepHashFree(connotfilehash); depexistsHashFree(connothash); filedepHashFree(reqfilehash); filedepHashFree(reqnotfilehash); depexistsHashFree(reqnothash); fpCacheFree(fpc); (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0); if (closeatexit) (void) rpmtsCloseDB(ts); return rc; }