2 * \file lib/transaction.c
7 #include <rpm/rpmlib.h> /* rpmMachineScore, rpmReadPackageFile */
8 #include <rpm/rpmmacro.h> /* XXX for rpmExpand */
9 #include <rpm/rpmlog.h>
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmds.h>
12 #include <rpm/rpmfileutil.h>
13 #include <rpm/rpmstring.h>
16 #include "lib/rpmdb_internal.h" /* XXX for dbiIndexSetCount */
17 #include "lib/fprint.h"
19 #include "lib/rpmlock.h"
20 #include "lib/rpmfi_internal.h" /* only internal apis */
21 #include "lib/rpmte_internal.h" /* only internal apis */
22 #include "lib/rpmts_internal.h"
24 #include "rpmio/rpmhook.h"
31 static int archOkay(const char * pkgArch)
33 if (pkgArch == NULL) return 0;
34 return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
39 static int osOkay(const char * pkgOs)
41 if (pkgOs == NULL) return 0;
42 return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
45 /* Calculate total number of files involved in transaction */
46 static uint64_t countFiles(rpmts ts)
49 rpmtsi pi = rpmtsiInit(ts);
52 while ((p = rpmtsiNext(pi, 0)) != NULL) {
53 if ((fi = rpmteFI(p)) == NULL)
54 continue; /* XXX can't happen */
62 * handleInstInstalledFiles.
63 * @param ts transaction set
64 * @param p current transaction element
65 * @param fi file info set
66 * @param shared shared file info
67 * @param sharedCount no. of shared elements
68 * @param reportConflicts
70 /* XXX only ts->{probs,rpmdb} modified */
71 static int handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi,
72 Header otherHeader, rpmfi otherFi,
75 unsigned int fx = rpmfiFX(fi);
76 rpmfs fs = rpmteGetFileStates(p);
79 isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
81 if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
84 if (rpmfiCompare(otherFi, fi)) {
85 rpm_color_t tscolor = rpmtsColor(ts);
86 rpm_color_t prefcolor = rpmtsPrefColor(ts);
87 rpm_color_t FColor = rpmfiFColor(fi) & tscolor;
88 rpm_color_t oFColor = rpmfiFColor(otherFi) & tscolor;
91 rConflicts = !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES));
92 /* Resolve file conflicts to prefer Elf64 (if not forced). */
93 if (tscolor != 0 && FColor != 0 && FColor != oFColor) {
94 if (oFColor & prefcolor) {
95 rpmfsSetAction(fs, fx, FA_SKIPCOLOR);
97 } else if (FColor & prefcolor) {
98 rpmfsSetAction(fs, fx, FA_CREATE);
104 char *altNEVR = headerGetNEVRA(otherHeader, NULL);
105 rpmps ps = rpmtsProblems(ts);
106 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
107 rpmteNEVRA(p), rpmteKey(p),
108 rpmfiDN(fi), rpmfiBN(fi),
115 /* Save file identifier to mark as state REPLACED. */
116 if ( !(isCfgFile || XFA_SKIPPING(rpmfsGetAction(fs, fx))) ) {
118 rpmfsAddReplaced(rpmteGetFileStates(p), rpmfiFX(fi),
119 headerGetInstance(otherHeader),
124 /* Determine config file dispostion, skipping missing files (if any). */
127 ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
128 rpmFileAction action = rpmfiDecideFate(otherFi, fi, skipMissing);
129 rpmfsSetAction(fs, fx, action);
131 rpmfiSetFReplacedSize(fi, rpmfiFSize(otherFi));
137 * Update disk space needs on each partition for this package's files.
139 /* XXX only ts->{probs,di} modified */
140 static void handleOverlappedFiles(rpmts ts, rpmFpHash ht, rpmte p, rpmfi fi)
142 rpm_loff_t fixupSize = 0;
146 rpm_color_t tscolor = rpmtsColor(ts);
147 rpm_color_t prefcolor = rpmtsPrefColor(ts);
148 rpmfs fs = rpmteGetFileStates(p);
151 ps = rpmtsProblems(ts);
152 fi = rpmfiInit(fi, 0);
154 while ((i = rpmfiNext(fi)) >= 0) {
155 rpm_color_t oFColor, FColor;
156 struct fingerPrint_s * fiFps;
157 int otherPkgNum, otherFileNum;
162 struct rpmffi_s * recs;
165 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
169 fiFps = rpmfiFpsIndex(fi, i);
170 FFlags = rpmfiFFlags(fi);
171 FMode = rpmfiFMode(fi);
172 FColor = rpmfiFColor(fi);
178 * Retrieve all records that apply to this file. Note that the
179 * file info records were built in the same order as the packages
180 * will be installed and removed so the records for an overlapped
181 * files will be sorted in exactly the same order.
183 (void) rpmFpHashGetEntry(ht, fiFps, &recs, &numRecs, NULL);
186 * If this package is being added, look only at other packages
187 * being added -- removed packages dance to a different tune.
189 * If both this and the other package are being added, overlapped
190 * files must be identical (or marked as a conflict). The
191 * disposition of already installed config files leads to
192 * a small amount of extra complexity.
194 * If this package is being removed, then there are two cases that
195 * need to be worried about:
196 * If the other package is being added, then skip any overlapped files
197 * so that this package removal doesn't nuke the overlapped files
198 * that were just installed.
199 * If both this and the other package are being removed, then each
200 * file removal from preceding packages needs to be skipped so that
201 * the file removal occurs only on the last occurence of an overlapped
202 * file in the transaction set.
206 /* Locate this overlapped file in the set of added/removed packages. */
207 for (j = 0; j < numRecs && recs[j].p != p; j++)
210 /* Find what the previous disposition of this file was. */
211 otherFileNum = -1; /* keep gcc quiet */
216 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
217 otherTe = recs[otherPkgNum].p;
218 otherFi = rpmteFI(otherTe);
219 otherFileNum = recs[otherPkgNum].fileno;
220 otherFs = rpmteGetFileStates(otherTe);
222 /* Added packages need only look at other added packages. */
223 if (rpmteType(p) == TR_ADDED && rpmteType(otherTe) != TR_ADDED)
226 (void) rpmfiSetFX(otherFi, otherFileNum);
228 /* XXX Happens iff fingerprint for incomplete package install. */
229 if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN);
233 oFColor = rpmfiFColor(otherFi);
236 switch (rpmteType(p)) {
239 int reportConflicts =
240 !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
243 if (otherPkgNum < 0) {
244 /* XXX is this test still necessary? */
245 rpmFileAction action;
246 if (rpmfsGetAction(fs, i) != FA_UNKNOWN)
248 if (rpmfiConfigConflict(fi)) {
249 /* Here is a non-overlapped pre-existing config file. */
250 action = (FFlags & RPMFILE_NOREPLACE) ?
251 FA_ALTNAME : FA_BACKUP;
255 rpmfsSetAction(fs, i, action);
259 assert(otherFi != NULL);
260 /* Mark added overlapped non-identical files as a conflict. */
261 if (rpmfiCompare(otherFi, fi)) {
264 rConflicts = reportConflicts;
265 /* Resolve file conflicts to prefer Elf64 (if not forced) ... */
267 if (FColor & prefcolor) {
268 /* ... last file of preferred colour is installed ... */
269 if (!XFA_SKIPPING(rpmfsGetAction(fs, i))) {
270 /* XXX static helpers are order dependent. Ick. */
271 if (strcmp(fn, "/usr/sbin/libgcc_post_upgrade")
272 && strcmp(fn, "/usr/sbin/glibc_post_upgrade"))
273 rpmfsSetAction(otherFs, otherFileNum, FA_SKIPCOLOR);
275 rpmfsSetAction(fs, i, FA_CREATE);
278 if (oFColor & prefcolor) {
279 /* ... first file of preferred colour is installed ... */
280 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
281 rpmfsSetAction(otherFs, otherFileNum, FA_CREATE);
282 rpmfsSetAction(fs, i, FA_SKIPCOLOR);
288 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
289 rpmteNEVRA(p), rpmteKey(p),
296 /* Try to get the disk accounting correct even if a conflict. */
297 fixupSize = rpmfiFSize(otherFi);
299 if (rpmfiConfigConflict(fi)) {
300 /* Here is an overlapped pre-existing config file. */
301 rpmFileAction action;
302 action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP;
303 rpmfsSetAction(fs, i, action);
306 rpmfsSetAction(fs, i, FA_CREATE);
311 if (otherPkgNum >= 0) {
312 assert(otherFi != NULL);
313 /* Here is an overlapped added file we don't want to nuke. */
314 if (rpmfsGetAction(otherFs, otherFileNum) != FA_ERASE) {
315 /* On updates, don't remove files. */
316 rpmfsSetAction(fs, i, FA_SKIP);
319 /* Here is an overlapped removed file: skip in previous. */
320 rpmfsSetAction(otherFs, otherFileNum, FA_SKIP);
322 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
324 if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
326 if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
327 rpmfsSetAction(fs, i, FA_ERASE);
331 /* Here is a pre-existing modified config file that needs saving. */
332 { pgpHashAlgo algo = 0;
334 const unsigned char *digest;
335 if ((digest = rpmfiFDigest(fi, &algo, &diglen))) {
336 unsigned char fdigest[diglen];
337 if (!rpmDoDigest(algo, fn, 0, fdigest, NULL) &&
338 memcmp(digest, fdigest, diglen)) {
339 rpmfsSetAction(fs, i, FA_BACKUP);
344 rpmfsSetAction(fs, i, FA_ERASE);
348 /* Update disk space info for a file. */
349 rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
350 rpmfiFReplacedSize(fi), fixupSize, rpmfsGetAction(fs, i));
357 * Ensure that current package is newer than installed package.
358 * @param p current transaction element
359 * @param h installed header
360 * @param ps problem set
361 * @return 0 if not newer, 1 if okay
363 static int ensureOlder(const rpmte p, const Header h, rpmps ps)
365 rpmsenseFlags reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
369 if (p == NULL || h == NULL)
372 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), rpmteEVR(p), reqFlags);
373 rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
374 req = rpmdsFree(req);
377 char * altNEVR = headerGetNEVRA(h, NULL);
378 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
379 rpmteNEVRA(p), rpmteKey(p),
383 altNEVR = _free(altNEVR);
392 * Skip any files that do not match install policies.
393 * @param ts transaction set
394 * @param fi file info set
396 static void skipFiles(const rpmts ts, rpmte p)
398 rpm_color_t tscolor = rpmtsColor(ts);
400 int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
401 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
402 const char * dn, * bn;
409 rpmfi fi = rpmteFI(p);
410 rpmfs fs = rpmteGetFileStates(p);
413 noDocs = rpmExpandNumeric("%{_excludedocs}");
415 /* Compute directory refcount, skip directory if now empty. */
417 drc = xcalloc(dc, sizeof(*drc));
418 dff = xcalloc(dc, sizeof(*dff));
420 fi = rpmfiInit(fi, 0);
421 if (fi != NULL) /* XXX lclint */
422 while ((i = rpmfiNext(fi)) >= 0)
433 continue; /* XXX can't happen */
437 /* Don't bother with skipped files */
438 if (XFA_SKIPPING(rpmfsGetAction(fs, i))) {
439 drc[ix]--; dff[ix] = 1;
443 /* Ignore colored files not in our rainbow. */
444 FColor = rpmfiFColor(fi);
445 if (tscolor && FColor && !(tscolor & FColor)) {
446 drc[ix]--; dff[ix] = 1;
447 rpmfsSetAction(fs, i, FA_SKIPCOLOR);
452 * Skip net shared paths.
453 * Net shared paths are not relative to the current root (though
454 * they do need to take package relocations into account).
456 for (nsp = ts->netsharedPaths; nsp && *nsp; nsp++) {
461 if (strncmp(dn, *nsp, len))
463 /* Only directories or complete file paths can be net shared */
464 if (!(dn[len] == '/' || dn[len] == '\0'))
467 if (len < (dnlen + bnlen))
469 if (strncmp(dn, *nsp, dnlen))
471 /* Insure that only the netsharedpath basename is compared. */
472 if ((s = strchr((*nsp) + dnlen, '/')) != NULL && s[1] != '\0')
474 if (strncmp(bn, (*nsp) + dnlen, bnlen))
477 /* Only directories or complete file paths can be net shared */
478 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
486 drc[ix]--; dff[ix] = 1;
487 rpmfsSetAction(fs, i, FA_SKIPNETSHARED);
492 * Skip i18n language specific files.
494 if (ts->installLangs != NULL && (flangs = rpmfiFLangs(fi)) != NULL) {
497 for (lang = ts->installLangs; *lang != NULL; lang++) {
498 for (l = flangs; *l != '\0'; l = le) {
499 for (le = l; *le != '\0' && *le != '|'; le++)
501 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
503 if (*le == '|') le++; /* skip over | */
509 drc[ix]--; dff[ix] = 1;
510 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
516 * Skip config files if requested.
518 if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
519 drc[ix]--; dff[ix] = 1;
520 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
525 * Skip documentation if requested.
527 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
528 drc[ix]--; dff[ix] = 1;
529 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
534 /* Skip (now empty) directories that had skipped files. */
536 if (fi != NULL) /* XXX can't happen */
537 for (j = 0; j < dc; j++)
539 if ((fi = rpmfiInitD(fi)) != NULL)
540 while (j = rpmfiNextD(fi) >= 0)
544 if (drc[j]) continue; /* dir still has files. */
545 if (!dff[j]) continue; /* dir was not emptied here. */
547 /* Find parent directory and basename. */
548 dn = rpmfiDNIndex(fi, j); dnlen = strlen(dn) - 1;
549 bn = dn + dnlen; bnlen = 0;
550 while (bn > dn && bn[-1] != '/') {
556 /* If explicitly included in the package, skip the directory. */
557 fi = rpmfiInit(fi, 0);
558 if (fi != NULL) /* XXX lclint */
559 while ((i = rpmfiNext(fi)) >= 0) {
560 const char * fdn, * fbn;
563 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
566 fFMode = rpmfiFMode(fi);
568 if (rpmfiWhatis(fFMode) != XDIR)
571 if (strlen(fdn) != dnlen)
573 if (strncmp(fdn, dn, dnlen))
576 if (strlen(fbn) != bnlen)
578 if (strncmp(fbn, bn, bnlen))
580 rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn);
581 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
594 #define HASHTYPE rpmStringSet
595 #define HTKEYTYPE const char *
596 #include "lib/rpmhash.H"
597 #include "lib/rpmhash.C"
599 /* Get a rpmdbMatchIterator containing all files in
600 * the rpmdb that share the basename with one from
602 * @param ts transaction set
603 * @return rpmdbMatchIterator sorted
604 by (package, fileNum)
607 rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount)
611 rpmdbMatchIterator mi;
613 const char * baseName;
615 rpmStringSet baseNames = rpmStringSetCreate(fileCount,
616 hashFunctionString, strcmp, NULL);
618 mi = rpmdbInitIterator(rpmtsGetRdb(ts), RPMTAG_BASENAMES, NULL, 0);
621 while ((p = rpmtsiNext(pi, 0)) != NULL) {
622 (void) rpmdbCheckSignals();
624 if ((fi = rpmteFI(p)) == NULL)
625 continue; /* XXX can't happen */
626 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
629 /* Gather all installed headers with matching basename's. */
630 fi = rpmfiInit(fi, 0);
631 while ((i = rpmfiNext(fi)) >= 0) {
633 baseName = rpmfiBN(fi);
634 if (rpmStringSetHasEntry(baseNames, baseName))
637 keylen = strlen(baseName);
639 keylen++; /* XXX "/" fixup. */
640 xx = rpmdbExtendIterator(mi, baseName, keylen);
641 rpmStringSetAddEntry(baseNames, baseName);
645 rpmStringSetFree(baseNames);
647 rpmdbSortIterator(mi);
648 /* iterator is now sorted by (recnum, filenum) */
652 /* Check files in the transactions against the rpmdb
653 * Lookup all files with the same basename in the rpmdb
654 * and then check for matching finger prints
655 * @param ts transaction set
656 * @param fpc global finger print cache
659 void checkInstalledFiles(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc)
667 unsigned int fileNum;
670 rpmdbMatchIterator mi;
675 rpmlog(RPMLOG_DEBUG, "computing file dispositions\n");
677 mi = rpmFindBaseNamesInDB(ts, fileCount);
679 /* For all installed headers with matching basename's ... */
683 if (rpmdbGetIteratorCount(mi) == 0) {
684 mi = rpmdbFreeIterator(mi);
688 /* Loop over all packages from the rpmdb */
689 h = newheader = rpmdbNextIterator(mi);
691 headerGetFlags hgflags = HEADERGET_MINMEM;
692 struct rpmtd_s bnames, dnames, dindexes, ostates;
694 unsigned int installedPkg;
696 /* Is this package being removed? */
697 installedPkg = rpmdbGetIteratorOffset(mi);
699 if (ts->removedPackages != NULL)
700 for (j = 0; j < ts->numRemovedPackages; j++) {
701 if (ts->removedPackages[j] != installedPkg)
708 headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags);
709 headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags);
710 headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags);
711 headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags);
714 /* loop over all interesting files in that package */
717 struct rpmffi_s * recs;
719 const char * dirName;
720 const char * baseName;
722 fileNum = rpmdbGetIteratorFileNum(mi);
723 rpmtdSetIndex(&bnames, fileNum);
724 rpmtdSetIndex(&dindexes, fileNum);
725 rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes));
726 rpmtdSetIndex(&ostates, fileNum);
728 dirName = rpmtdGetString(&dnames);
729 baseName = rpmtdGetString(&bnames);
731 /* lookup finger print for this file */
732 if ( dirName == oldDir) {
733 /* directory is the same as last round */
734 fp.baseName = baseName;
736 fp = fpLookup(fpc, dirName, baseName, 1);
739 /* search for files in the transaction with same finger print */
740 gotRecs = rpmFpHashGetEntry(ht, &fp, &recs, &numRecs, NULL);
742 for (j=0; (j<numRecs)&&gotRecs; j++) {
745 fs = rpmteGetFileStates(p);
747 /* Determine the fate of each file. */
748 switch (rpmteType(p)) {
751 otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
753 rpmfiSetFX(fi, recs[j].fileno);
754 rpmfiSetFX(otherFi, fileNum);
755 xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved);
759 rpmfiSetFX(fi, recs[j].fileno);
760 if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL)
761 rpmfsSetAction(fs, recs[j].fileno, FA_SKIP);
767 newheader = rpmdbNextIterator(mi);
769 } while (newheader==h);
771 otherFi = rpmfiFree(otherFi);
772 rpmtdFreeData(&ostates);
773 rpmtdFreeData(&bnames);
774 rpmtdFreeData(&dnames);
775 rpmtdFreeData(&dindexes);
780 mi = rpmdbFreeIterator(mi);
784 * For packages being installed:
785 * - verify package arch/os.
786 * - verify package epoch:version-release is newer.
788 static rpmps checkProblems(rpmts ts)
790 rpm_color_t tscolor = rpmtsColor(ts);
791 rpmps ps = rpmpsCreate();
792 rpmtsi pi = rpmtsiInit(ts);
795 /* The ordering doesn't matter here */
796 /* XXX Only added packages need be checked. */
797 rpmlog(RPMLOG_DEBUG, "sanity checking %d elements\n", rpmtsNElements(ts));
798 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
799 rpmdbMatchIterator mi;
801 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
802 if (!archOkay(rpmteA(p)))
803 rpmpsAppend(ps, RPMPROB_BADARCH,
804 rpmteNEVRA(p), rpmteKey(p),
808 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
809 if (!osOkay(rpmteO(p)))
810 rpmpsAppend(ps, RPMPROB_BADOS,
811 rpmteNEVRA(p), rpmteKey(p),
815 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
817 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
818 while ((h = rpmdbNextIterator(mi)) != NULL)
819 ensureOlder(p, h, ps);
820 mi = rpmdbFreeIterator(mi);
823 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
824 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
825 rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p));
826 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p));
827 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p));
829 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(p));
830 rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(p));
833 while (rpmdbNextIterator(mi) != NULL) {
834 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
835 rpmteNEVRA(p), rpmteKey(p),
840 mi = rpmdbFreeIterator(mi);
848 * Run pre/post transaction scripts for transaction set
849 * param ts Transaction set
850 * param stag RPMTAG_PRETRANS or RPMTAG_POSTTRANS
851 * return 0 on success, -1 on error (invalid script tag)
853 static int runTransScripts(rpmts ts, rpmTag stag)
858 rpmTag progtag = RPMTAG_NOT_FOUND;
861 if (stag == RPMTAG_PRETRANS) {
862 progtag = RPMTAG_PRETRANSPROG;
863 } else if (stag == RPMTAG_POSTTRANS) {
864 progtag = RPMTAG_POSTTRANSPROG;
870 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
871 /* If no pre/post-transaction script, then don't bother. */
872 if (!rpmteHaveTransScript(p, stag))
875 if (rpmteOpen(p, ts, 0)) {
876 psm = rpmpsmNew(ts, p);
877 xx = rpmpsmScriptStage(psm, stag, progtag);
878 psm = rpmpsmFree(psm);
879 rpmteClose(p, ts, 0);
886 /* Add fingerprint for each file not skipped. */
887 static void addFingerprints(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc)
894 rpmFpHash symlinks = rpmFpHashCreate(fileCount/16+16, fpHashFunction, fpEqual, NULL, NULL);
897 while ((p = rpmtsiNext(pi, 0)) != NULL) {
898 (void) rpmdbCheckSignals();
900 if ((fi = rpmteFI(p)) == NULL)
901 continue; /* XXX can't happen */
903 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
904 rpmfiFpLookup(fi, fpc);
905 /* collect symbolic links */
906 fi = rpmfiInit(fi, 0);
907 if (fi != NULL) /* XXX lclint */
908 while ((i = rpmfiNext(fi)) >= 0) {
910 char const *linktarget;
911 linktarget = rpmfiFLink(fi);
912 if (!(linktarget && *linktarget != '\0'))
914 if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
918 rpmFpHashAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi);
920 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
925 /* ===============================================
926 * Check fingerprints if they contain symlinks
927 * and add them to the hash table
931 while ((p = rpmtsiNext(pi, 0)) != NULL) {
932 (void) rpmdbCheckSignals();
934 if ((fi = rpmteFI(p)) == NULL)
935 continue; /* XXX can't happen */
936 fi = rpmfiInit(fi, 0);
937 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
938 if (fi != NULL) /* XXX lclint */
939 while ((i = rpmfiNext(fi)) >= 0) {
940 if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
942 fpLookupSubdir(symlinks, ht, fpc, p, i);
944 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
948 rpmFpHashFree(symlinks);
951 static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
953 rpm_tid_t tid = (rpm_tid_t) time(NULL);
954 int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) ? O_RDONLY : (O_RDWR|O_CREAT);
956 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
957 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
958 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
959 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
961 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
962 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
964 /* if SELinux isn't enabled or init fails, don't bother... */
965 if (!rpmtsSELinuxEnabled(ts)) {
966 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
969 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
970 char *fn = rpmGetPath("%{?_install_file_context_path}", NULL);
971 if (matchpathcon_init(fn) == -1) {
972 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
977 /* XXX Make sure the database is open RDWR for package install/erase. */
978 if (rpmtsOpenDB(ts, dbmode)) {
979 return -1; /* XXX W2DO? */
982 ts->ignoreSet = ignoreSet;
983 ts->probs = rpmpsFree(ts->probs);
985 { char * currDir = rpmGetCwd();
986 rpmtsSetCurrDir(ts, currDir);
987 currDir = _free(currDir);
990 (void) rpmtsSetChrootDone(ts, 0);
991 (void) rpmtsSetTid(ts, tid);
993 /* Get available space on mounted file systems. */
994 (void) rpmtsInitDSI(ts);
999 static int rpmtsFinish(rpmts ts)
1001 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
1002 matchpathcon_fini();
1007 static int rpmtsPrepare(rpmts ts)
1013 uint64_t fileCount = countFiles(ts);
1014 const char * rootDir = rpmtsRootDir(ts);
1015 int dochroot = (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/');
1017 fingerPrintCache fpc = fpCacheCreate(fileCount/2 + 10001);
1018 rpmFpHash ht = rpmFpHashCreate(fileCount/2+1, fpHashFunction, fpEqual,
1021 rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount);
1023 /* Skip netshared paths, not our i18n files, and excluded docs */
1024 pi = rpmtsiInit(ts);
1025 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1026 if ((fi = rpmteFI(p)) == NULL)
1027 continue; /* XXX can't happen */
1029 if (rpmfiFC(fi) > 0)
1032 pi = rpmtsiFree(pi);
1034 /* Enter chroot for fingerprinting if necessary */
1035 if (!rpmtsChrootDone(ts)) {
1038 /* opening db before chroot not optimal, see rhbz#103852 c#3 */
1039 xx = rpmdbOpenAll(ts->rdb);
1040 if (chroot(rootDir) == -1) {
1041 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
1046 (void) rpmtsSetChrootDone(ts, 1);
1049 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount);
1050 addFingerprints(ts, fileCount, ht, fpc);
1051 /* check against files in the rpmdb */
1052 checkInstalledFiles(ts, fileCount, ht, fpc);
1054 pi = rpmtsiInit(ts);
1055 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1056 if ((fi = rpmteFI(p)) == NULL)
1057 continue; /* XXX can't happen */
1059 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1060 /* check files in ts against each other and update disk space
1061 needs on each partition for this package. */
1062 handleOverlappedFiles(ts, ht, p, fi);
1064 /* Check added package has sufficient space on each partition used. */
1065 if (rpmteType(p) == TR_ADDED) {
1066 rpmtsCheckDSIProblems(ts, p);
1068 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1070 pi = rpmtsiFree(pi);
1071 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount);
1073 /* return from chroot if done earlier */
1074 if (rpmtsChrootDone(ts)) {
1075 const char * currDir = rpmtsCurrDir(ts);
1078 (void) rpmtsSetChrootDone(ts, 0);
1079 if (currDir != NULL)
1080 xx = chdir(currDir);
1083 /* File info sets, fp caches etc not needed beyond here, free 'em up. */
1084 pi = rpmtsiInit(ts);
1085 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1086 rpmteSetFI(p, NULL);
1088 pi = rpmtsiFree(pi);
1091 ht = rpmFpHashFree(ht);
1092 fpc = fpCacheFree(fpc);
1097 * Transaction main loop: install and remove packages
1099 static int rpmtsProcess(rpmts ts)
1104 pi = rpmtsiInit(ts);
1105 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1107 rpmElementType tetype = rpmteType(p);
1108 rpmtsOpX op = (tetype == TR_ADDED) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
1110 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
1111 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1113 if (rpmteFailed(p)) {
1114 /* XXX this should be a warning, need a better message though */
1115 rpmlog(RPMLOG_DEBUG, "element %s marked as failed, skipping\n",
1121 if (rpmteOpen(p, ts, 1)) {
1123 pkgStage stage = PSM_UNKNOWN;
1124 int async = (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1)) ?
1129 stage = PSM_PKGINSTALL;
1132 stage = PSM_PKGERASE;
1135 psm = rpmpsmNew(ts, p);
1136 rpmpsmSetAsync(psm, async);
1138 (void) rpmswEnter(rpmtsOp(ts, op), 0);
1139 failed = rpmpsmStage(psm, stage);
1140 (void) rpmswExit(rpmtsOp(ts, op), 0);
1141 psm = rpmpsmFree(psm);
1142 rpmteClose(p, ts, 1);
1145 rpmteMarkFailed(p, ts);
1148 (void) rpmdbSync(rpmtsGetRdb(ts));
1150 pi = rpmtsiFree(pi);
1154 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
1156 int rc = -1; /* assume failure */
1159 /* XXX programmer error segfault avoidance. */
1160 if (rpmtsNElements(ts) <= 0) {
1164 /* If we are in test mode, then there's no need for transaction lock. */
1165 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
1166 if (!(lock = rpmtsAcquireLock(ts))) {
1171 /* Setup flags and such, open the DB */
1172 if (rpmtsSetup(ts, ignoreSet)) {
1176 /* Check package set for problems */
1177 ts->probs = checkProblems(ts);
1179 /* Run pre-transaction scripts, but only if there are no known
1180 * problems up to this point and not disabled otherwise. */
1181 if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPRE))
1182 || (rpmpsNumProblems(ts->probs) &&
1183 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
1184 rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n");
1185 runTransScripts(ts, RPMTAG_PRETRANS);
1188 /* Compute file disposition for each package in transaction set. */
1189 if (rpmtsPrepare(ts)) {
1193 /* If unfiltered problems exist, free memory and return. */
1194 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS) ||
1195 (rpmpsNumProblems(ts->probs) &&
1196 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))) {
1197 rc = ts->orderCount;
1201 /* Actually install and remove packages, get final exit code */
1202 rc = rpmtsProcess(ts) ? -1 : 0;
1204 /* Run post-transaction scripts unless disabled */
1205 if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPOST))) {
1206 rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
1207 runTransScripts(ts, RPMTAG_POSTTRANS);
1211 (void) rpmtsFinish(ts);
1214 rpmtsFreeLock(lock);