rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types) { rpmte te; while ((te = rpmtsiNextElement(tsi)) != NULL) { if (types == 0 || (rpmteType(te) & types) != 0) break; } return te; }
/* * 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; }
/* Update DSI for changing size of the rpmdb */ static void rpmtsUpdateDSIrpmDBSize(const rpmte p, rpmDiskSpaceInfo dsi) { rpm_loff_t headerSize; int64_t bneeded; /* XXX somehow we can end up here with bsize 0 (RhBug:671056) */ if (dsi == NULL || dsi->bsize == 0) return; headerSize = rpmteHeaderSize(p); bneeded = BLOCK_ROUND(headerSize, dsi->bsize); /* REMOVE doesn't neccessarily shrink the database */ if (rpmteType(p) == TR_ADDED) { /* guessing that db grows 4 times more than the header size */ dsi->bneeded += (bneeded * 4); } }
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; }
/* Check files in the transactions against the rpmdb * Lookup all files with the same basename in the rpmdb * and then check for matching finger prints * @param ts transaction set * @param fpc global finger print cache */ static void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) { tsMembers tsmem = rpmtsMembers(ts); rpmte p; rpmfiles fi; rpmfs fs; int j; unsigned int fileNum; rpmdbMatchIterator mi; Header h, newheader; rpmlog(RPMLOG_DEBUG, "computing file dispositions\n"); mi = rpmFindBaseNamesInDB(ts, fileCount); /* For all installed headers with matching basename's ... */ if (mi == NULL) return; if (rpmdbGetIteratorCount(mi) == 0) { mi = rpmdbFreeIterator(mi); return; } /* Loop over all packages from the rpmdb */ h = newheader = rpmdbNextIterator(mi); while (h != NULL) { headerGetFlags hgflags = HEADERGET_MINMEM; struct rpmtd_s bnames, dnames, dindexes, ostates; fingerPrint *fpp = NULL; unsigned int installedPkg; int beingRemoved = 0; rpmfiles otherFi = NULL; rpmte *removedPkg = NULL; /* Is this package being removed? */ installedPkg = rpmdbGetIteratorOffset(mi); if (packageHashGetEntry(tsmem->removedPackages, installedPkg, &removedPkg, NULL, NULL)) { beingRemoved = 1; otherFi = rpmteFiles(removedPkg[0]); } h = headerLink(h); /* For packages being removed we can use its rpmfi to avoid all this */ if (!beingRemoved) { headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags); headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags); headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags); } /* loop over all interesting files in that package */ do { int fpIx; struct rpmffi_s * recs; int numRecs; const char * dirName; const char * baseName; /* lookup finger print for this file */ fileNum = rpmdbGetIteratorFileNum(mi); if (!beingRemoved) { rpmtdSetIndex(&bnames, fileNum); rpmtdSetIndex(&dindexes, fileNum); rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes)); rpmtdSetIndex(&ostates, fileNum); dirName = rpmtdGetString(&dnames); baseName = rpmtdGetString(&bnames); fpLookup(fpc, dirName, baseName, &fpp); fpIx = 0; } else { fpp = rpmfilesFps(otherFi); fpIx = fileNum; } /* search for files in the transaction with same finger print */ fpCacheGetByFp(fpc, fpp, fpIx, &recs, &numRecs); for (j = 0; j < numRecs; j++) { p = recs[j].p; fi = rpmteFiles(p); fs = rpmteGetFileStates(p); /* Determine the fate of each file. */ switch (rpmteType(p)) { case TR_ADDED: if (!otherFi) { /* XXX What to do if this fails? */ otherFi = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); } handleInstInstalledFile(ts, p, fi, recs[j].fileno, h, otherFi, fileNum, beingRemoved); break; case TR_REMOVED: if (!beingRemoved) { if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) rpmfsSetAction(fs, recs[j].fileno, FA_SKIP); } break; } rpmfilesFree(fi); } newheader = rpmdbNextIterator(mi); } while (newheader==h); otherFi = rpmfilesFree(otherFi); if (!beingRemoved) { rpmtdFreeData(&ostates); rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); free(fpp); } headerFree(h); h = newheader; } rpmdbFreeIterator(mi); }
/* 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)); } }
static int rpmtsPrepare(rpmts ts) { tsMembers tsmem = rpmtsMembers(ts); rpmtsi pi; rpmte p; int rc = 0; uint64_t fileCount = countFiles(ts); const char *dbhome = NULL; struct stat dbstat; fingerPrintCache fpc = fpCacheCreate(fileCount/2 + 10001, rpmtsPool(ts)); rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount); /* Reset actions, set skip for netshared paths and excluded files */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmfiles files = rpmteFiles(p); if (rpmfilesFC(files) > 0) { rpmfs fs = rpmteGetFileStates(p); /* Ensure clean state, this could get called more than once. */ rpmfsResetActions(fs); if (rpmteType(p) == TR_ADDED) { skipInstallFiles(ts, files, fs); } else { skipEraseFiles(ts, files, fs); } } rpmfilesFree(files); } rpmtsiFree(pi); /* Open rpmdb & enter chroot for fingerprinting if necessary */ if (rpmdbOpenAll(ts->rdb) || rpmChrootIn()) { rc = -1; goto exit; } rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, tsmem->orderCount); /* Add fingerprint for each file not skipped. */ fpCachePopulate(fpc, ts, fileCount); /* check against files in the rpmdb */ checkInstalledFiles(ts, fileCount, fpc); dbhome = rpmdbHome(rpmtsGetRdb(ts)); /* If we can't stat, ignore db growth. Probably not right but... */ if (dbhome && stat(dbhome, &dbstat)) dbhome = NULL; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmfiles files = rpmteFiles(p);; if (files == 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, fpc, p, files); /* Check added package has sufficient space on each partition used. */ if (rpmteType(p) == TR_ADDED) { /* * Try to estimate space needed for rpmdb growth: guess that the * db grows 4 times the header size (indexes and all). */ if (dbhome) { int64_t hsize = rpmteHeaderSize(p) * 4; rpmtsUpdateDSI(ts, dbstat.st_dev, dbhome, hsize, 0, 0, FA_CREATE); } rpmtsCheckDSIProblems(ts, p); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); rpmfilesFree(files); } rpmtsiFree(pi); rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, tsmem->orderCount); /* return from chroot if done earlier */ if (rpmChrootOut()) rc = -1; /* On actual transaction, file info sets are not needed after this */ if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) { pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmteCleanFiles(p); } rpmtsiFree(pi); } exit: fpCacheFree(fpc); rpmtsFreeDSI(ts); return rc; }
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; }
static int rpmtsPrepare(rpmts ts) { tsMembers tsmem = rpmtsMembers(ts); rpmtsi pi; rpmte p; rpmfi fi; int rc = 0; uint64_t fileCount = countFiles(ts); fingerPrintCache fpc = fpCacheCreate(fileCount/2 + 10001); rpmFpHash ht = rpmFpHashCreate(fileCount/2+1, fpHashFunction, fpEqual, NULL, NULL); rpmDiskSpaceInfo dsi; rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount); /* Skip netshared paths, not our i18n files, and excluded docs */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { if (rpmfiFC(rpmteFI(p)) == 0) continue; if (rpmteType(p) == TR_ADDED) { skipInstallFiles(ts, p); } else { skipEraseFiles(ts, p); } } rpmtsiFree(pi); /* Open rpmdb & enter chroot for fingerprinting if necessary */ if (rpmdbOpenAll(ts->rdb) || rpmChrootIn()) { rc = -1; goto exit; } rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, tsmem->orderCount); addFingerprints(ts, fileCount, ht, fpc); /* check against files in the rpmdb */ checkInstalledFiles(ts, fileCount, ht, fpc); dsi = rpmtsDbDSI(ts); 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, ht, p, fi); rpmtsUpdateDSIrpmDBSize(p, dsi); /* 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); } rpmtsiFree(pi); rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, tsmem->orderCount); /* return from chroot if done earlier */ if (rpmChrootOut()) rc = -1; /* File info sets, fp caches etc not needed beyond here, free 'em up. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmteSetFI(p, NULL); } rpmtsiFree(pi); exit: rpmFpHashFree(ht); fpCacheFree(fpc); rpmtsFreeDSI(ts); return rc; }
/* 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); }
/* Check file for to be installed symlinks in their path and correct their fp */ static void fpLookupSubdir(rpmFpHash symlinks, fingerPrintCache fpc, rpmte p, int filenr) { rpmfiles fi = rpmteFiles(p); struct fingerPrint_s current_fp; const char *currentsubdir; size_t lensubDir, bnStart, bnEnd; struct rpmffi_s * recs; int numRecs; int i; fingerPrint *fp = rpmfilesFps(fi) + filenr; int symlinkcount = 0; struct rpmffi_s ffi = { p, filenr}; if (fp->subDirId == 0) { rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); current_fp = *fp; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; /* no subDir for now */ current_fp.subDirId = 0; while (bnEnd < lensubDir) { char found = 0; current_fp.baseNameId = rpmstrPoolIdn(fpc->pool, currentsubdir + bnStart, bnEnd - bnStart, 1); rpmFpHashGetEntry(symlinks, ¤t_fp, &recs, &numRecs, NULL); for (i = 0; i < numRecs; i++) { rpmfiles foundfi = rpmteFiles(recs[i].p); char const *linktarget = rpmfilesFLink(foundfi, recs[i].fileno); char *link; /* Ignore already removed (by eg %pretrans) links */ if (linktarget && rpmteType(recs[i].p) == TR_REMOVED) { char *path = rpmfilesFN(foundfi, recs[i].fileno); struct stat sb; if (lstat(path, &sb) == -1) linktarget = NULL; free(path); } foundfi = rpmfilesFree(foundfi); if (linktarget && *linktarget != '\0') { const char *bn; /* this "directory" is a symlink */ link = NULL; if (*linktarget != '/') { const char *dn, *subDir = NULL; dn = rpmstrPoolStr(fpc->pool, current_fp.entry->dirId); if (current_fp.subDirId) { subDir = rpmstrPoolStr(fpc->pool, current_fp.subDirId); } rstrscat(&link, dn, subDir ? subDir : "", "/", NULL); } rstrscat(&link, linktarget, "/", NULL); if (strlen(currentsubdir + bnEnd)) { rstrscat(&link, currentsubdir + bnEnd, NULL); } bn = rpmstrPoolStr(fpc->pool, fp->baseNameId); doLookup(fpc, link, bn, fp); free(link); symlinkcount++; /* setup current_fp for the new path */ found = 1; current_fp = *fp; if (fp->subDirId == 0) { /* directory exists - no need to look for symlinks */ rpmFpHashAddEntry(fpc->fp, fp, ffi); goto exit; } currentsubdir = rpmstrPoolStr(fpc->pool, fp->subDirId); lensubDir = rpmstrPoolStrlen(fpc->pool, fp->subDirId); /* no subDir for now */ current_fp.subDirId = 0; /* Set baseName to the upper most dir */ bnStart = bnEnd = 1; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; break; } } if (symlinkcount > 50) { // found too many symlinks in the path // most likley a symlink cicle // giving up // TODO warning/error break; } if (found) { continue; // restart loop after symlink } /* Set former baseName as subDir */ bnEnd++; current_fp.subDirId = rpmstrPoolIdn(fpc->pool, currentsubdir, bnEnd, 1); /* set baseName to the next lower dir */ bnStart = bnEnd; while (bnEnd < lensubDir && currentsubdir[bnEnd] != '/') bnEnd++; } rpmFpHashAddEntry(fpc->fp, fp, ffi); exit: rpmfilesFree(fi); }
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; }
/************************************************************************* * FUNCTION : RPMTransaction_Set::Show * * ARGUMENTS : Object to look for * * RETURNS : List of packages found * * EXCEPTIONS : none * * PURPOSE : Show the contents of a transaction set * *************************************************************************/ Tcl_Obj *RPMTransaction_Set::Show(Tcl_Obj *item) { Tcl_Obj *sub_obj = Tcl_NewObj(); Tcl_IncrRefCount(sub_obj); // Is this a list? if (item && item->typePtr == listtype) { // OK, go recursive on this int count = 0; if (Tcl_ListObjLength(_interp,item,&count) != TCL_OK) return sub_obj; for (int i = 0; i < count; ++i) { Tcl_Obj *element = 0; if (Tcl_ListObjIndex(_interp,item,i,&element) != TCL_OK) { return sub_obj; } Tcl_ListObjAppendElement(_interp,sub_obj,Show(element)); } return sub_obj; } // OK, not a list. were we given ANYTHING? if not, get everything. void *name = 0; if (item) { if (item->typePtr == &RPMHeader_Obj::mytype) { RPMHeader_Obj *header = ( RPMHeader_Obj *)(item->internalRep.otherValuePtr); int size = 0; int type = 0; if (!header->GetEntry(RPMTAG_NAME,type,name,size)) return sub_obj; } else // Not a header, interp as a string { name = (void *)Tcl_GetStringFromObj(item,0); } } rpmtsi matches = rpmtsiInit(transaction); if (!matches) return sub_obj; // OK, go over the list and create a list of items to return for(;;) { rpmte te = rpmtsiNext(matches,(rpmElementType)0); if (!te) break; Tcl_Obj *results[2]; switch (rpmteType(te)) { case TR_ADDED: { RPMHeader_Obj *hdr = (RPMHeader_Obj *)rpmteKey(te); results[0] = Tcl_NewStringObj("add",-1); results[1] = hdr->Get_obj();; } break; case TR_REMOVED: { results[0] = Tcl_NewStringObj("remove",-1); results[1] = Tcl_NewStringObj(rpmteN(te),-1); } break; } Tcl_Obj *list = Tcl_NewListObj(2,results); Tcl_IncrRefCount(list); Tcl_ListObjAppendElement(_interp,sub_obj,list); } rpmtsiFree(matches); return sub_obj; }
static int rpmtsSetupCollections(rpmts ts) { /* seenCollectionsPost and TEs are basically a key-value pair. each item in * seenCollectionsPost is a collection that has been seen from any package, * and the associated index in the TEs is the last transaction element * where that collection was seen. */ ARGV_t seenCollectionsPost = NULL; rpmte *TEs = NULL; int numSeenPost = 0; /* seenCollectionsPre is a list of collections that have been seen from * only removed packages */ ARGV_t seenCollectionsPre = NULL; int numSeenPre = 0; ARGV_const_t collname; int installing = 1; int i; rpmte p; rpmtsi pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { /* detect when we switch from installing to removing packages, and * update the lastInCollectionAdd lists */ if (installing && rpmteType(p) == TR_REMOVED) { installing = 0; for (i = 0; i < numSeenPost; i++) { rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]); } } rpmteSetupCollectionPlugins(p); for (collname = rpmteCollections(p); collname && *collname; collname++) { /* figure out if we've seen this collection in post before */ for (i = 0; i < numSeenPost && strcmp(*collname, seenCollectionsPost[i]); i++) { } if (i < numSeenPost) { /* we've seen the collection, update the index */ TEs[i] = p; } else { /* haven't seen the collection yet, add it */ argvAdd(&seenCollectionsPost, *collname); TEs = xrealloc(TEs, sizeof(*TEs) * (numSeenPost + 1)); TEs[numSeenPost] = p; numSeenPost++; } /* figure out if we've seen this collection in pre remove before */ if (installing == 0) { for (i = 0; i < numSeenPre && strcmp(*collname, seenCollectionsPre[i]); i++) { } if (i >= numSeenPre) { /* haven't seen this collection, add it */ rpmteAddToFirstInCollectionRemove(p, *collname); argvAdd(&seenCollectionsPre, *collname); numSeenPre++; } } } } rpmtsiFree(pi); /* we've looked at all the rpmte's, update the lastInCollectionAny lists */ for (i = 0; i < numSeenPost; i++) { rpmteAddToLastInCollectionAny(TEs[i], seenCollectionsPost[i]); if (installing == 1) { /* lastInCollectionAdd is only updated above if packages were * removed. if nothing is removed in the transaction, we need to * update that list here */ rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]); } } argvFree(seenCollectionsPost); argvFree(seenCollectionsPre); _free(TEs); return 0; }
/* Check files in the transactions against the rpmdb * Lookup all files with the same basename in the rpmdb * and then check for matching finger prints * @param ts transaction set * @param fpc global finger print cache */ static void checkInstalledFiles(rpmts ts, fingerPrintCache fpc) { rpmps ps; rpmte p; rpmfi fi; rpmfs fs; rpmfi otherFi=NULL; int j; int xx; unsigned int fileNum; const char * oldDir; rpmdbMatchIterator mi; Header h, newheader; int beingRemoved; rpmlog(RPMLOG_DEBUG, "computing file dispositions\n"); mi = rpmFindBaseNamesInDB(ts); /* For all installed headers with matching basename's ... */ if (mi == NULL) return; if (rpmdbGetIteratorCount(mi) == 0) { mi = rpmdbFreeIterator(mi); return; } ps = rpmtsProblems(ts); /* Loop over all packages from the rpmdb */ h = newheader = rpmdbNextIterator(mi); while (h != NULL) { headerGetFlags hgflags = HEADERGET_MINMEM; struct rpmtd_s bnames, dnames, dindexes, ostates; fingerPrint fp; unsigned int installedPkg; /* Is this package being removed? */ installedPkg = rpmdbGetIteratorOffset(mi); beingRemoved = 0; if (ts->removedPackages != NULL) for (j = 0; j < ts->numRemovedPackages; j++) { if (ts->removedPackages[j] != installedPkg) continue; beingRemoved = 1; break; } h = headerLink(h); headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags); headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags); headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags); headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags); oldDir = NULL; /* loop over all interesting files in that package */ do { int gotRecs; struct rpmffi_s * recs; int numRecs; const char * dirName; const char * baseName; fileNum = rpmdbGetIteratorFileNum(mi); rpmtdSetIndex(&bnames, fileNum); rpmtdSetIndex(&dindexes, fileNum); rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes)); rpmtdSetIndex(&ostates, fileNum); dirName = rpmtdGetString(&dnames); baseName = rpmtdGetString(&bnames); /* lookup finger print for this file */ if ( dirName == oldDir) { /* directory is the same as last round */ fp.baseName = baseName; } else { fp = fpLookup(fpc, dirName, baseName, 1); oldDir = dirName; } /* search for files in the transaction with same finger print */ gotRecs = rpmFpHashGetEntry(ts->ht, &fp, &recs, &numRecs, NULL); for (j=0; (j<numRecs)&&gotRecs; j++) { p = recs[j].p; fi = rpmteFI(p); fs = rpmteGetFileStates(p); /* Determine the fate of each file. */ switch (rpmteType(p)) { case TR_ADDED: if (!otherFi) { otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); } rpmfiSetFX(fi, recs[j].fileno); rpmfiSetFX(otherFi, fileNum); xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved); break; case TR_REMOVED: if (!beingRemoved) { rpmfiSetFX(fi, recs[j].fileno); if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) rpmfsSetAction(fs, recs[j].fileno, FA_SKIP); } break; } } newheader = rpmdbNextIterator(mi); } while (newheader==h); otherFi = rpmfiFree(otherFi); rpmtdFreeData(&ostates); rpmtdFreeData(&bnames); rpmtdFreeData(&dnames); rpmtdFreeData(&dindexes); headerFree(h); h = newheader; } mi = rpmdbFreeIterator(mi); }
static sepol *sepolNew(rpmte te) { sepol *head = NULL; sepol *ret = NULL; sepolAction action; Header h; struct rpmtd_s policies, names, types, typesidx, flags; int i, j; int count; rpmtdReset(&policies); rpmtdReset(&names); rpmtdReset(&types); rpmtdReset(&typesidx); rpmtdReset(&flags); h = rpmteHeader(te); if (!h) { goto exit; } if (!headerIsEntry(h, RPMTAG_POLICIES)) { goto exit; } if (!headerGet(h, RPMTAG_POLICIES, &policies, HEADERGET_MINMEM)) { goto exit; } count = rpmtdCount(&policies); if (count <= 0) { goto exit; } if (!headerGet(h, RPMTAG_POLICYNAMES, &names, HEADERGET_MINMEM) || rpmtdCount(&names) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYFLAGS, &flags, HEADERGET_MINMEM) || rpmtdCount(&flags) != count) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPES, &types, HEADERGET_MINMEM)) { goto exit; } if (!headerGet(h, RPMTAG_POLICYTYPESINDEXES, &typesidx, HEADERGET_MINMEM) || rpmtdCount(&types) != rpmtdCount(&typesidx)) { goto exit; } action = (rpmteType(te) == TR_ADDED) ? SEPOL_ACTION_INSTALL : SEPOL_ACTION_REMOVE; for (i = 0; i < count; i++) { sepol *pol = xcalloc(1, sizeof(*pol)); pol->next = head; head = pol; pol->data = xstrdup(rpmtdNextString(&policies)); pol->name = xstrdup(rpmtdNextString(&names)); pol->flags = *rpmtdNextUint32(&flags); pol->action = action; for (j = 0; j < rpmtdCount(&types); j++) { uint32_t index = ((uint32_t *) typesidx.data)[j]; if (index < 0 || index >= count) { goto exit; } if (index != i) { continue; } argvAdd(&pol->types, rpmtdNextString(&types)); } argvSort(pol->types, NULL); } ret = head; exit: headerFree(h); rpmtdFreeData(&policies); rpmtdFreeData(&names); rpmtdFreeData(&types); rpmtdFreeData(&typesidx); rpmtdFreeData(&flags); if (!ret) { sepolFree(head); } return ret; }
rpmRC rpmgiNext(/*@null@*/ rpmgi gi) { char hnum[32]; rpmRC rpmrc = RPMRC_NOTFOUND; int xx; if (gi == NULL) return rpmrc; if (_rpmgi_debug) fprintf(stderr, "--> %s(%p) tag %s\n", __FUNCTION__, gi, tagName(gi->tag)); /* Free header from previous iteration. */ (void)headerFree(gi->h); gi->h = NULL; gi->hdrPath = _free(gi->hdrPath); hnum[0] = '\0'; if (++gi->i >= 0) switch (gi->tag) { default: if (!gi->active) { nextkey: rpmrc = rpmgiLoadNextKey(gi); if (rpmrc != RPMRC_OK) goto enditer; rpmrc = rpmgiInitFilter(gi); if (rpmrc != RPMRC_OK || gi->mi == NULL) { gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */ gi->i++; goto nextkey; } rpmrc = RPMRC_NOTFOUND; /* XXX hack */ gi->active = 1; } if (gi->mi != NULL) { /* XXX unnecessary */ Header h = rpmmiNext(gi->mi); if (h != NULL) { if (!(gi->flags & RPMGI_NOHEADER)) gi->h = headerLink(h); /* XXX use h->origin instead. */ sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi)); gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL); rpmrc = RPMRC_OK; /* XXX header reference held by iterator, so no headerFree */ } } if (rpmrc != RPMRC_OK) { gi->mi = rpmmiFree(gi->mi); goto nextkey; } break; case RPMDBI_PACKAGES: if (!gi->active) { rpmrc = rpmgiInitFilter(gi); if (rpmrc != RPMRC_OK) { gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */ goto enditer; } rpmrc = RPMRC_NOTFOUND; /* XXX hack */ gi->active = 1; } if (gi->mi != NULL) { /* XXX unnecessary */ Header h = rpmmiNext(gi->mi); if (h != NULL) { if (!(gi->flags & RPMGI_NOHEADER)) gi->h = headerLink(h); /* XXX use h->origin instead. */ sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi)); gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL); rpmrc = RPMRC_OK; /* XXX header reference held by iterator, so no headerFree */ } } if (rpmrc != RPMRC_OK) { gi->mi = rpmmiFree(gi->mi); goto enditer; } break; case RPMDBI_REMOVED: case RPMDBI_ADDED: { rpmte p; int teType = 0; const char * teTypeString = NULL; if (!gi->active) { gi->tsi = rpmtsiInit(gi->ts); gi->active = 1; } if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) { Header h = rpmteHeader(p); if (h != NULL) if (!(gi->flags & RPMGI_NOHEADER)) { gi->h = headerLink(h); switch(rpmteType(p)) { case TR_ADDED: teTypeString = "+++"; /*@switchbreak@*/break; case TR_REMOVED: teTypeString = "---"; /*@switchbreak@*/break; } sprintf(hnum, "%u", (unsigned)gi->i); gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL); rpmrc = RPMRC_OK; (void)headerFree(h); h = NULL; } } if (rpmrc != RPMRC_OK) { gi->tsi = rpmtsiFree(gi->tsi); goto enditer; } } break; case RPMDBI_HDLIST: if (!gi->active) { const char * path = rpmExpand("%{?_query_hdlist_path}", NULL); if (path == NULL || *path == '\0') { path = _free(path); path = rpmExpand(_query_hdlist_path, NULL); } gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}"); gi->active = 1; path = _free(path); } if (gi->fd != NULL) { Header h = NULL; const char item[] = "Header"; const char * msg = NULL; /*@+voidabstract@*/ rpmrc = rpmpkgRead(item, gi->fd, &h, &msg); /*@=voidabstract@*/ switch(rpmrc) { default: rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg); case RPMRC_NOTFOUND: h = NULL; case RPMRC_OK: break; } msg = _free(msg); if (h != NULL) { if (!(gi->flags & RPMGI_NOHEADER)) gi->h = headerLink(h); sprintf(hnum, "%u", (unsigned)gi->i); gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL); rpmrc = RPMRC_OK; (void)headerFree(h); h = NULL; } } if (rpmrc != RPMRC_OK) { if (gi->fd != NULL) (void) Fclose(gi->fd); gi->fd = NULL; goto enditer; } break; case RPMDBI_ARGLIST: /* XXX gi->active initialize? */ if (_rpmgi_debug < 0) fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]); /* Read next header, lazily expanding manifests as found. */ rpmrc = rpmgiLoadReadHeader(gi); if (rpmrc != RPMRC_OK) /* XXX check this */ goto enditer; gi->hdrPath = xstrdup(gi->argv[gi->i]); break; case RPMDBI_FTSWALK: if (gi->argv == NULL || gi->argv[0] == NULL) /* HACK */ goto enditer; if (!gi->active) { gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL); /* XXX NULL with open(2)/malloc(3) errno set */ gi->active = 1; } /* Read next header, lazily walking file tree. */ rpmrc = rpmgiWalkReadHeader(gi); if (rpmrc != RPMRC_OK) { xx = Fts_close(gi->ftsp); gi->ftsp = NULL; goto enditer; } if (gi->fts != NULL) gi->hdrPath = xstrdup(gi->fts->fts_path); break; } if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) { /* XXX rpmgi hack: Save header in transaction element. */ if (gi->flags & RPMGI_ERASING) { uint32_t hdrNum = headerGetInstance(gi->h); xx = rpmtsAddEraseElement(gi->ts, gi->h, hdrNum); } else xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL); } goto exit; enditer: if (gi->flags & RPMGI_TSORDER) { rpmts ts = gi->ts; /* Block access to indices used for depsolving. */ if (!(gi->flags & RPMGI_ERASING)) { (void) rpmtsSetGoal(ts, TSM_INSTALL); xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMDBI_DEPCACHE); xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_BASENAMES); xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_PROVIDENAME); } else { (void) rpmtsSetGoal(ts, TSM_ERASE); } /* XXX query/verify will need the glop added to a buffer instead. */ xx = rpmcliInstallCheck(ts); xx = rpmcliInstallSuggests(ts); /* Permit access to indices used for depsolving. */ if (!(gi->flags & RPMGI_ERASING)) { xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_PROVIDENAME); xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_BASENAMES); xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMDBI_DEPCACHE); } /* XXX Display dependency loops with rpm -qvT. */ if (rpmIsVerbose()) (void) rpmtsSetDFlags(ts, (rpmtsDFlags(ts) | RPMDEPS_FLAG_DEPLOOPS)); xx = (*gi->tsOrder) (ts); /* XXX hackery alert! */ gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED); gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER); } (void)headerFree(gi->h); gi->h = NULL; gi->hdrPath = _free(gi->hdrPath); gi->i = -1; gi->active = 0; exit: if (_rpmgi_debug) fprintf(stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, gi, rpmrc); return rpmrc; }