/** * Check installed package dependencies for problems. * @param ts transaction set * @param h header * @return number of problems found (0 for no problems) */ static int verifyDependencies(rpmts ts, Header h) { rpmps ps; rpmte te; int rc; rpmtsEmpty(ts); (void) rpmtsAddInstallElement(ts, h, NULL, 0, NULL); (void) rpmtsCheck(ts); te = rpmtsElement(ts, 0); ps = rpmteProblems(te); rc = rpmpsNumProblems(ps); if (rc > 0) { rpmlog(RPMLOG_NOTICE, _("Unsatisfied dependencies for %s:\n"), rpmteNEVRA(te)); rpmpsi psi = rpmpsInitIterator(ps); rpmProblem p; while ((p = rpmpsiNext(psi)) != NULL) { char * ps = rpmProblemString(p); rpmlog(RPMLOG_NOTICE, "\t%s\n", ps); free(ps); } rpmpsFreeIterator(psi); } rpmpsFree(ps); rpmtsEmpty(ts); return rc; }
/** * Ensure that current package is newer than installed package. * @param ts transaction set * @param p current transaction element * @param h installed header * @return 0 if not newer, 1 if okay */ static int ensureOlder(rpmts ts, const rpmte p, const Header h) { rpmsenseFlags reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL); rpmds req; int rc; if (p == NULL || h == NULL) return 1; req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), rpmteEVR(p), reqFlags); rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote); req = rpmdsFree(req); if (rc == 0) { rpmps ps = rpmtsProblems(ts); char * altNEVR = headerGetNEVRA(h, NULL); rpmpsAppend(ps, RPMPROB_OLDPACKAGE, rpmteNEVRA(p), rpmteKey(p), NULL, NULL, altNEVR, 0); altNEVR = _free(altNEVR); ps = rpmpsFree(ps); rc = 1; } else rc = 0; return rc; }
/* * Transaction main loop: install and remove packages */ static int rpmtsProcess(rpmts ts) { rpmtsi pi; rpmte p; int rc = 0; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int failed = 1; rpmElementType tetype = rpmteType(p); rpmtsOpX op = (tetype == TR_ADDED) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE; rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); if (rpmteFailed(p)) { /* XXX this should be a warning, need a better message though */ rpmlog(RPMLOG_DEBUG, "element %s marked as failed, skipping\n", rpmteNEVRA(p)); rc++; continue; } if (rpmteOpen(p, ts, 1)) { rpmpsm psm = NULL; pkgStage stage = PSM_UNKNOWN; int async = (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1)) ? 1 : 0; switch (tetype) { case TR_ADDED: stage = PSM_PKGINSTALL; break; case TR_REMOVED: stage = PSM_PKGERASE; break; } psm = rpmpsmNew(ts, p); rpmpsmSetAsync(psm, async); (void) rpmswEnter(rpmtsOp(ts, op), 0); failed = rpmpsmStage(psm, stage); (void) rpmswExit(rpmtsOp(ts, op), 0); psm = rpmpsmFree(psm); rpmteClose(p, ts, 1); } if (failed) { rpmteMarkFailed(p, ts); rc++; } (void) rpmdbSync(rpmtsGetRdb(ts)); } pi = rpmtsiFree(pi); return rc; }
static rpmpsm rpmpsmNew(rpmts ts, rpmte te, pkgGoal goal) { rpmpsm psm = xcalloc(1, sizeof(*psm)); psm->ts = rpmtsLink(ts); psm->files = rpmteFiles(te); psm->te = te; /* XXX rpmte not refcounted yet */ if (!rpmteIsSource(te)) { /* * When we run scripts, we pass an argument which is the number of * versions of this package that will be installed when we are * finished. */ int npkgs_installed = rpmdbCountPackages(rpmtsGetRdb(ts), rpmteN(te)); switch (goal) { case PKG_INSTALL: case PKG_PRETRANS: psm->scriptArg = npkgs_installed + 1; psm->countCorrection = 0; break; case PKG_ERASE: psm->scriptArg = npkgs_installed - 1; psm->countCorrection = -1; break; case PKG_VERIFY: case PKG_POSTTRANS: psm->scriptArg = npkgs_installed; psm->countCorrection = 0; break; default: break; } } if (goal == PKG_INSTALL) { Header h = rpmteHeader(te); psm->total = headerGetNumber(h, RPMTAG_LONGARCHIVESIZE); headerFree(h); } else if (goal == PKG_ERASE) { psm->total = rpmfilesFC(psm->files); } /* Fake up something for packages with no files */ if (psm->total == 0) psm->total = 100; rpmlog(RPMLOG_DEBUG, "%s: %s has %d files\n", pkgGoalString(goal), rpmteNEVRA(psm->te), rpmfilesFC(psm->files)); return psm; }
static rpmRC sepolAddTE(rpmte te) { sepol *pol; sepol *polTail; if (!rpmteHasCollection(te, name)) { return RPMRC_OK; } pol = sepolNew(te); if (!pol) { /* something's wrong with the policy information, either missing or * corrupt. abort */ rpmlog(RPMLOG_ERR, _("Failed to extract policy from %s\n"), rpmteNEVRA(te)); return RPMRC_FAIL; } /* find the tail of pol */ polTail = pol; while (polTail->next) { polTail = polTail->next; } /* add the new policy to the list */ if (!policiesHead) { policiesHead = pol; policiesTail = polTail; } else { if (rpmteType(te) == TR_ADDED) { /* add to the end of the list */ policiesTail->next = pol; policiesTail = polTail; } else { /* add to the beginning of the list */ polTail->next = policiesHead; policiesHead = pol; } } return RPMRC_OK; }
/* * Transaction main loop: install and remove packages */ static int rpmtsProcess(rpmts ts) { rpmtsi pi; rpmte p; int rc = 0; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int failed; rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); failed = rpmteProcess(p, rpmteType(p)); if (failed) { rpmlog(RPMLOG_ERR, "%s: %s %s\n", rpmteNEVRA(p), rpmteTypeString(p), failed > 1 ? _("skipped") : _("failed")); rc++; } } rpmtsiFree(pi); return rc; }
/* XXX only ts->{probs,di} modified */ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfiles fi) { rpm_loff_t fixupSize = 0; int i, j; rpmfs fs = rpmteGetFileStates(p); rpmfs otherFs; rpm_count_t fc = rpmfilesFC(fi); int reportConflicts = !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES); fingerPrint * fpList = rpmfilesFps(fi); for (i = 0; i < fc; i++) { struct fingerPrint_s * fiFps; int otherPkgNum, otherFileNum; rpmfiles otherFi; rpmte otherTe; rpmfileAttrs FFlags; struct rpmffi_s * recs; int numRecs; if (XFA_SKIPPING(rpmfsGetAction(fs, i))) continue; FFlags = rpmfilesFFlags(fi, i); fixupSize = 0; /* * Retrieve all records that apply to this file. Note that the * file info records were built in the same order as the packages * will be installed and removed so the records for an overlapped * files will be sorted in exactly the same order. */ fiFps = fpCacheGetByFp(fpc, fpList, i, &recs, &numRecs); /* * If this package is being added, look only at other packages * being added -- removed packages dance to a different tune. * * If both this and the other package are being added, overlapped * files must be identical (or marked as a conflict). The * disposition of already installed config files leads to * a small amount of extra complexity. * * If this package is being removed, then there are two cases that * need to be worried about: * If the other package is being added, then skip any overlapped files * so that this package removal doesn't nuke the overlapped files * that were just installed. * If both this and the other package are being removed, then each * file removal from preceding packages needs to be skipped so that * the file removal occurs only on the last occurrence of an overlapped * file in the transaction set. * */ /* * Locate this overlapped file in the set of added/removed packages, * including the package owning it: a package can have self-conflicting * files when directory symlinks are present. Don't compare a file * with itself though... */ for (j = 0; j < numRecs && !(recs[j].p == p && recs[j].fileno == i); j++) {}; /* Find what the previous disposition of this file was. */ otherFileNum = -1; /* keep gcc quiet */ otherFi = NULL; otherTe = NULL; otherFs = NULL; for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) { otherTe = recs[otherPkgNum].p; otherFileNum = recs[otherPkgNum].fileno; otherFs = rpmteGetFileStates(otherTe); /* Added packages need only look at other added packages. */ if (rpmteType(p) == TR_ADDED && rpmteType(otherTe) != TR_ADDED) continue; /* XXX Happens iff fingerprint for incomplete package install. */ if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN) { otherFi = rpmteFiles(otherTe); break; } } switch (rpmteType(p)) { case TR_ADDED: if (otherPkgNum < 0) { /* XXX is this test still necessary? */ rpmFileAction action; if (rpmfsGetAction(fs, i) != FA_UNKNOWN) break; if (rpmfilesConfigConflict(fi, i)) { /* Here is a non-overlapped pre-existing config file. */ action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_BACKUP; } else { action = FA_CREATE; } rpmfsSetAction(fs, i, action); break; } assert(otherFi != NULL); /* Mark added overlapped non-identical files as a conflict. */ if (rpmfilesCompare(otherFi, otherFileNum, fi, i)) { int rConflicts; /* If enabled, resolve colored conflicts to preferred type */ rConflicts = handleColorConflict(ts, fs, fi, i, otherFs, otherFi, otherFileNum); if (rConflicts && reportConflicts) { char *fn = rpmfilesFN(fi, i); rpmteAddProblem(p, RPMPROB_NEW_FILE_CONFLICT, rpmteNEVRA(otherTe), fn, 0); free(fn); } } else { /* Skip create on all but the first instance of a shared file */ rpmFileAction oaction = rpmfsGetAction(otherFs, otherFileNum); if (oaction != FA_UNKNOWN && !XFA_SKIPPING(oaction)) { rpmfileAttrs oflags; /* ...but ghosts aren't really created so... */ oflags = rpmfilesFFlags(otherFi, otherFileNum); if (!(oflags & RPMFILE_GHOST)) { rpmfsSetAction(fs, i, FA_SKIP); } /* if the other file is color skipped then skip this file too */ } else if (oaction == FA_SKIPCOLOR) { rpmfsSetAction(fs, i, FA_SKIPCOLOR); } } /* Skipped files dont need fixup size or backups, %config or not */ if (XFA_SKIPPING(rpmfsGetAction(fs, i))) break; /* Try to get the disk accounting correct even if a conflict. */ fixupSize = rpmfilesFSize(otherFi, otherFileNum); if (rpmfilesConfigConflict(fi, i)) { /* Here is an overlapped pre-existing config file. */ rpmFileAction action; action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP; rpmfsSetAction(fs, i, action); } else { /* If not decided yet, create it */ if (rpmfsGetAction(fs, i) == FA_UNKNOWN) rpmfsSetAction(fs, i, FA_CREATE); } break; case TR_REMOVED: if (otherPkgNum >= 0) { assert(otherFi != NULL); /* Here is an overlapped added file we don't want to nuke. */ if (rpmfsGetAction(otherFs, otherFileNum) != FA_ERASE) { /* On updates, don't remove files. */ rpmfsSetAction(fs, i, FA_SKIP); break; } /* Here is an overlapped removed file: skip in previous. */ rpmfsSetAction(otherFs, otherFileNum, FA_SKIP); } if (XFA_SKIPPING(rpmfsGetAction(fs, i))) break; if (rpmfilesFState(fi, i) != RPMFILE_STATE_NORMAL) break; /* Pre-existing modified config files need to be saved. */ if (rpmfilesConfigConflict(fi, i)) { rpmfsSetAction(fs, i, FA_SAVE); break; } /* Otherwise, we can just erase. */ rpmfsSetAction(fs, i, FA_ERASE); break; } rpmfilesFree(otherFi); /* Update disk space info for a file. */ rpmtsUpdateDSI(ts, fpEntryDev(fpc, fiFps), fpEntryDir(fpc, fiFps), rpmfilesFSize(fi, i), rpmfilesFReplacedSize(fi, i), fixupSize, rpmfsGetAction(fs, i)); } }
int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) { rpm_color_t tscolor = rpmtsColor(ts); int i; int rc = 0; int totalFileCount = 0; rpmfi fi; fingerPrintCache fpc; rpmps ps; rpmtsi pi; rpmte p; int numAdded; int numRemoved; void * lock = NULL; int xx; /* XXX programmer error segfault avoidance. */ if (rpmtsNElements(ts) <= 0) return -1; /* If we are in test mode, then there's no need for transaction lock. */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { lock = rpmtsAcquireLock(ts); if (lock == NULL) return -1; /* XXX W2DO? */ } if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers)); if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers)); if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers)); /* if SELinux isn't enabled or init fails, don't bother... */ if (!rpmtsSELinuxEnabled(ts)) { rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { char *fn = rpmGetPath("%{?_install_file_context_path}", NULL); if (matchpathcon_init(fn) == -1) { rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); } free(fn); } ts->probs = rpmpsFree(ts->probs); ts->probs = rpmpsCreate(); /* XXX Make sure the database is open RDWR for package install/erase. */ { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) ? O_RDONLY : (O_RDWR|O_CREAT); /* Open database RDWR for installing packages. */ if (rpmtsOpenDB(ts, dbmode)) { rpmtsFreeLock(lock); return -1; /* XXX W2DO? */ } } ts->ignoreSet = ignoreSet; { char * currDir = rpmGetCwd(); rpmtsSetCurrDir(ts, currDir); currDir = _free(currDir); } (void) rpmtsSetChrootDone(ts, 0); { rpm_tid_t tid = (rpm_tid_t) time(NULL); (void) rpmtsSetTid(ts, tid); } /* Get available space on mounted file systems. */ xx = rpmtsInitDSI(ts); /* =============================================== * For packages being installed: * - verify package arch/os. * - verify package epoch:version-release is newer. * - count files. * For packages being removed: * - count files. */ rpmlog(RPMLOG_DEBUG, "sanity checking %d elements\n", rpmtsNElements(ts)); ps = rpmtsProblems(ts); /* The ordering doesn't matter here */ pi = rpmtsiInit(ts); /* XXX Only added packages need be checked. */ while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) { rpmdbMatchIterator mi; int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH)) if (!archOkay(rpmteA(p))) rpmpsAppend(ps, RPMPROB_BADARCH, rpmteNEVRA(p), rpmteKey(p), rpmteA(p), NULL, NULL, 0); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS)) if (!osOkay(rpmteO(p))) rpmpsAppend(ps, RPMPROB_BADOS, rpmteNEVRA(p), rpmteKey(p), rpmteO(p), NULL, NULL, 0); if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) { Header h; mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0); while ((h = rpmdbNextIterator(mi)) != NULL) xx = ensureOlder(ts, p, h); mi = rpmdbFreeIterator(mi); } if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) { mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0); xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p)); if (tscolor) { xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(p)); xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(p)); } while (rpmdbNextIterator(mi) != NULL) { rpmpsAppend(ps, RPMPROB_PKG_INSTALLED, rpmteNEVRA(p), rpmteKey(p), NULL, NULL, NULL, 0); break; } mi = rpmdbFreeIterator(mi); } /* Count no. of files (if any). */ totalFileCount += fc; } pi = rpmtsiFree(pi); ps = rpmpsFree(ps); /* The ordering doesn't matter here */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); totalFileCount += fc; } pi = rpmtsiFree(pi); /* Run pre-transaction scripts, but only if there are no known * problems up to this point and not disabled otherwise. */ if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPRE)) || (rpmpsNumProblems(ts->probs) && (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) { rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n"); runTransScripts(ts, RPMTAG_PRETRANS); } /* =============================================== * Initialize transaction element file info for package: */ /* * FIXME?: we'd be better off assembling one very large file list and * calling fpLookupList only once. I'm not sure that the speedup is * worth the trouble though. */ rpmlog(RPMLOG_DEBUG, "computing %d file fingerprints\n", totalFileCount); numAdded = numRemoved = 0; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int fc; if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); switch (rpmteType(p)) { case TR_ADDED: numAdded++; /* Skip netshared paths, not our i18n files, and excluded docs */ if (fc > 0) skipFiles(ts, p); break; case TR_REMOVED: numRemoved++; break; } } pi = rpmtsiFree(pi); if (!rpmtsChrootDone(ts)) { const char * rootDir = rpmtsRootDir(ts); xx = chdir("/"); if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') { /* opening db before chroot not optimal, see rhbz#103852 c#3 */ xx = rpmdbOpenAll(ts->rdb); if (chroot(rootDir) == -1) { rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n")); return -1; } } (void) rpmtsSetChrootDone(ts, 1); } ts->ht = rpmFpHashCreate(totalFileCount/2+1, fpHashFunction, fpEqual, NULL, NULL); rpmFpHash symlinks = rpmFpHashCreate(totalFileCount/16+16, fpHashFunction, fpEqual, NULL, NULL); fpc = fpCacheCreate(totalFileCount/2 + 10001); /* =============================================== * Add fingerprint for each file not skipped. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { int fc; (void) rpmdbCheckSignals(); if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fc = rpmfiFC(fi); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); rpmfiFpLookup(fi, fpc); /* collect symbolic links */ fi = rpmfiInit(fi, 0); if (fi != NULL) /* XXX lclint */ while ((i = rpmfiNext(fi)) >= 0) { struct rpmffi_s ffi; char const *linktarget; linktarget = rpmfiFLink(fi); if (!(linktarget && *linktarget != '\0')) continue; if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; ffi.p = p; ffi.fileno = i; rpmFpHashAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc); } pi = rpmtsiFree(pi); /* =============================================== * Check fingerprints if they contain symlinks * and add them to the ts->ht hash table */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { (void) rpmdbCheckSignals(); if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ fi = rpmfiInit(fi, 0); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); if (fi != NULL) /* XXX lclint */ while ((i = rpmfiNext(fi)) >= 0) { if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i))) continue; fpLookupSubdir(symlinks, ts->ht, fpc, p, i); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); } pi = rpmtsiFree(pi); rpmFpHashFree(symlinks); /* =============================================== * Compute file disposition for each package in transaction set. */ rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount); /* check against files in the rpmdb */ checkInstalledFiles(ts, fpc); pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { if ((fi = rpmteFI(p)) == NULL) continue; /* XXX can't happen */ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); /* check files in ts against each other and update disk space needs on each partition for this package. */ handleOverlappedFiles(ts, p, fi); /* Check added package has sufficient space on each partition used. */ if (rpmteType(p) == TR_ADDED) { rpmtsCheckDSIProblems(ts, p); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); } pi = rpmtsiFree(pi); if (rpmtsChrootDone(ts)) { const char * rootDir = rpmtsRootDir(ts); const char * currDir = rpmtsCurrDir(ts); if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') xx = chroot("."); (void) rpmtsSetChrootDone(ts, 0); if (currDir != NULL) xx = chdir(currDir); } rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount); /* =============================================== * Free unused memory as soon as possible. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmteSetFI(p, NULL); } pi = rpmtsiFree(pi); fpc = fpCacheFree(fpc); ts->ht = rpmFpHashFree(ts->ht); /* =============================================== * If unfiltered problems exist, free memory and return. */ if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS) || (rpmpsNumProblems(ts->probs) && (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))) ) { rpmtsFreeLock(lock); return ts->orderCount; } /* Actually install and remove packages */ rc = rpmtsProcess(ts); if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPOST))) { rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n"); runTransScripts(ts, RPMTAG_POSTTRANS); } if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { matchpathcon_fini(); } rpmtsFreeLock(lock); /* FIX: ts->flList may be NULL */ if (rc) return -1; else return 0; }
/* XXX only ts->{probs,rpmdb} modified */ static int handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, Header otherHeader, rpmfi otherFi, int beingRemoved) { rpm_color_t tscolor = rpmtsColor(ts); rpm_color_t prefcolor = rpmtsPrefColor(ts); rpm_color_t oFColor, FColor; char * altNEVR = NULL; rpmps ps; unsigned int fx = rpmfiFX(fi); rpmfs fs = rpmteGetFileStates(p); altNEVR = headerGetNEVRA(otherHeader, NULL); ps = rpmtsProblems(ts); int isCfgFile; oFColor = rpmfiFColor(otherFi); oFColor &= tscolor; FColor = rpmfiFColor(fi); FColor &= tscolor; isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG); if (XFA_SKIPPING(rpmfsGetAction(fs, fx))) return 0; if (rpmfiCompare(otherFi, fi)) { int rConflicts; rConflicts = !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)); /* Resolve file conflicts to prefer Elf64 (if not forced). */ if (tscolor != 0 && FColor != 0 && FColor != oFColor) { if (oFColor & prefcolor) { rpmfsSetAction(fs, fx, FA_SKIPCOLOR); rConflicts = 0; } else if (FColor & prefcolor) { rpmfsSetAction(fs, fx, FA_CREATE); rConflicts = 0; } } if (rConflicts) { rpmpsAppend(ps, RPMPROB_FILE_CONFLICT, rpmteNEVRA(p), rpmteKey(p), rpmfiDN(fi), rpmfiBN(fi), altNEVR, 0); } /* Save file identifier to mark as state REPLACED. */ if ( !(isCfgFile || XFA_SKIPPING(rpmfsGetAction(fs, fx))) ) { if (!beingRemoved) rpmfsAddReplaced(rpmteGetFileStates(p), rpmfiFX(fi), headerGetInstance(otherHeader), rpmfiFX(otherFi)); } } /* Determine config file dispostion, skipping missing files (if any). */ if (isCfgFile) { int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1); rpmFileAction action = rpmfiDecideFate(otherFi, fi, skipMissing); rpmfsSetAction(fs, fx, action); } rpmfiSetFReplacedSize(fi, rpmfiFSize(otherFi)); ps = rpmpsFree(ps); altNEVR = _free(altNEVR); return 0; }
/* XXX only ts->{probs,di} modified */ static void handleOverlappedFiles(const rpmts ts, const rpmte p, rpmfi fi) { rpm_loff_t fixupSize = 0; rpmps ps; const char * fn; int i, j; rpm_color_t tscolor = rpmtsColor(ts); rpm_color_t prefcolor = rpmtsPrefColor(ts); rpmfs fs = rpmteGetFileStates(p); rpmfs otherFs; ps = rpmtsProblems(ts); fi = rpmfiInit(fi, 0); if (fi != NULL) while ((i = rpmfiNext(fi)) >= 0) { rpm_color_t oFColor, FColor; struct fingerPrint_s * fiFps; int otherPkgNum, otherFileNum; rpmfi otherFi; rpmte otherTe; rpmfileAttrs FFlags; rpm_mode_t FMode; struct rpmffi_s * recs; int numRecs; if (XFA_SKIPPING(rpmfsGetAction(fs, i))) continue; fn = rpmfiFN(fi); fiFps = rpmfiFpsIndex(fi, i); FFlags = rpmfiFFlags(fi); FMode = rpmfiFMode(fi); FColor = rpmfiFColor(fi); FColor &= tscolor; fixupSize = 0; /* * Retrieve all records that apply to this file. Note that the * file info records were built in the same order as the packages * will be installed and removed so the records for an overlapped * files will be sorted in exactly the same order. */ (void) rpmFpHashGetEntry(ts->ht, fiFps, &recs, &numRecs, NULL); /* * If this package is being added, look only at other packages * being added -- removed packages dance to a different tune. * * If both this and the other package are being added, overlapped * files must be identical (or marked as a conflict). The * disposition of already installed config files leads to * a small amount of extra complexity. * * If this package is being removed, then there are two cases that * need to be worried about: * If the other package is being added, then skip any overlapped files * so that this package removal doesn't nuke the overlapped files * that were just installed. * If both this and the other package are being removed, then each * file removal from preceding packages needs to be skipped so that * the file removal occurs only on the last occurence of an overlapped * file in the transaction set. * */ /* Locate this overlapped file in the set of added/removed packages. */ for (j = 0; j < numRecs && recs[j].p != p; j++) {}; /* Find what the previous disposition of this file was. */ otherFileNum = -1; /* keep gcc quiet */ otherFi = NULL; otherTe = NULL; otherFs = NULL; for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) { otherTe = recs[otherPkgNum].p; otherFi = rpmteFI(otherTe); otherFileNum = recs[otherPkgNum].fileno; otherFs = rpmteGetFileStates(otherTe); /* Added packages need only look at other added packages. */ if (rpmteType(p) == TR_ADDED && rpmteType(otherTe) != TR_ADDED) continue; (void) rpmfiSetFX(otherFi, otherFileNum); /* XXX Happens iff fingerprint for incomplete package install. */ if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN); break; } oFColor = rpmfiFColor(otherFi); oFColor &= tscolor; switch (rpmteType(p)) { case TR_ADDED: { int reportConflicts = !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES); int done = 0; if (otherPkgNum < 0) { /* XXX is this test still necessary? */ rpmFileAction action; if (rpmfsGetAction(fs, i) != FA_UNKNOWN) break; if (rpmfiConfigConflict(fi)) { /* Here is a non-overlapped pre-existing config file. */ action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_BACKUP; } else { action = FA_CREATE; } rpmfsSetAction(fs, i, action); break; } assert(otherFi != NULL); /* Mark added overlapped non-identical files as a conflict. */ if (rpmfiCompare(otherFi, fi)) { int rConflicts; rConflicts = reportConflicts; /* Resolve file conflicts to prefer Elf64 (if not forced) ... */ if (tscolor != 0) { if (FColor & prefcolor) { /* ... last file of preferred colour is installed ... */ if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) { /* XXX static helpers are order dependent. Ick. */ if (strcmp(fn, "/usr/sbin/libgcc_post_upgrade") && strcmp(fn, "/usr/sbin/glibc_post_upgrade")) rpmfsSetAction(otherFs, otherFileNum, FA_SKIPCOLOR); } rpmfsSetAction(fs, i, FA_CREATE); rConflicts = 0; } else if (oFColor & prefcolor) { /* ... first file of preferred colour is installed ... */ if (XFA_SKIPPING(rpmfsGetAction(fs, i))) rpmfsSetAction(otherFs, otherFileNum, FA_CREATE); rpmfsSetAction(fs, i, FA_SKIPCOLOR); rConflicts = 0; } done = 1; } if (rConflicts) { rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT, rpmteNEVRA(p), rpmteKey(p), fn, NULL, rpmteNEVRA(otherTe), 0); } } /* Try to get the disk accounting correct even if a conflict. */ fixupSize = rpmfiFSize(otherFi); if (rpmfiConfigConflict(fi)) { /* Here is an overlapped pre-existing config file. */ rpmFileAction action; action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP; rpmfsSetAction(fs, i, action); } else { if (!done) rpmfsSetAction(fs, i, FA_CREATE); } } break; case TR_REMOVED: if (otherPkgNum >= 0) { assert(otherFi != NULL); /* Here is an overlapped added file we don't want to nuke. */ if (rpmfsGetAction(otherFs, otherFileNum) != FA_ERASE) { /* On updates, don't remove files. */ rpmfsSetAction(fs, i, FA_SKIP); break; } /* Here is an overlapped removed file: skip in previous. */ rpmfsSetAction(otherFs, otherFileNum, FA_SKIP); } if (XFA_SKIPPING(rpmfsGetAction(fs, i))) break; if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL) break; if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) { rpmfsSetAction(fs, i, FA_ERASE); break; } /* Here is a pre-existing modified config file that needs saving. */ { pgpHashAlgo algo = 0; size_t diglen = 0; const unsigned char *digest; if ((digest = rpmfiFDigest(fi, &algo, &diglen))) { unsigned char fdigest[diglen]; if (!rpmDoDigest(algo, fn, 0, fdigest, NULL) && memcmp(digest, fdigest, diglen)) { rpmfsSetAction(fs, i, FA_BACKUP); break; } } } rpmfsSetAction(fs, i, FA_ERASE); break; } /* Update disk space info for a file. */ rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi), rpmfiFReplacedSize(fi), fixupSize, rpmfsGetAction(fs, i)); } ps = rpmpsFree(ps); }
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; }
/* * 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; }
static JSBool rpmte_getprop(JSContext *cx, JSObject *obj, jsval id, jsval *vp) { void * ptr = JS_GetInstancePrivate(cx, obj, &rpmteClass, NULL); rpmte te = ptr; jsint tiny = JSVAL_TO_INT(id); /* XXX the class has ptr == NULL, instances have ptr != NULL. */ if (ptr == NULL) return JS_TRUE; switch (tiny) { case _DEBUG: *vp = INT_TO_JSVAL(_debug); break; case _TYPE: *vp = INT_TO_JSVAL(rpmteType(te)); /* XXX should be string */ break; case _N: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteN(te))); break; case _E: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteE(te))); break; case _V: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteV(te))); break; case _R: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteR(te))); break; case _A: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteA(te))); break; case _O: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteO(te))); break; case _NEVR: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteNEVR(te))); break; case _NEVRA: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteNEVRA(te))); break; case _PKGID: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmtePkgid(te))); break; case _HDRID: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteHdrid(te))); break; case _COLOR: *vp = INT_TO_JSVAL(rpmteColor(te)); break; case _PKGFSIZE: *vp = INT_TO_JSVAL(rpmtePkgFileSize(te)); break; case _BREADTH: *vp = INT_TO_JSVAL(rpmteBreadth(te)); break; case _DEPTH: *vp = INT_TO_JSVAL(rpmteDepth(te)); break; case _NPREDS: *vp = INT_TO_JSVAL(rpmteNpreds(te)); break; case _DEGREE: *vp = INT_TO_JSVAL(rpmteDegree(te)); break; case _PARENT: #ifdef DYING *vp = INT_TO_JSVAL(rpmteColor(te)); #else *vp = JSVAL_VOID; #endif break; case _TREE: *vp = INT_TO_JSVAL(rpmteTree(te)); break; case _ADDEDKEY: /* XXX FIXME */ *vp = INT_TO_JSVAL((int)((long)rpmteAddedKey(te))); break; case _DBOFFSET: *vp = INT_TO_JSVAL(rpmteDBOffset(te)); break; #ifdef NOTYET case _KEY: *vp = INT_TO_JSVAL(rpmteColor(te)); break; #endif case _SOURCERPM: *vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, rpmteSourcerpm(te))); break; default: break; } return JS_TRUE; }
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; }