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);
77 int isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
79 if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
82 if (rpmfiCompare(otherFi, fi)) {
83 rpm_color_t tscolor = rpmtsColor(ts);
84 rpm_color_t prefcolor = rpmtsPrefColor(ts);
85 rpm_color_t FColor = rpmfiFColor(fi) & tscolor;
86 rpm_color_t oFColor = rpmfiFColor(otherFi) & tscolor;
89 rConflicts = !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES));
90 /* Resolve file conflicts to prefer Elf64 (if not forced). */
91 if (tscolor != 0 && FColor != 0 && FColor != oFColor) {
92 if (oFColor & prefcolor) {
93 rpmfsSetAction(fs, fx, FA_SKIPCOLOR);
95 } else if (FColor & prefcolor) {
96 rpmfsSetAction(fs, fx, FA_CREATE);
102 char *altNEVR = headerGetAsString(otherHeader, RPMTAG_NEVRA);
103 rpmps ps = rpmtsProblems(ts);
104 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
105 rpmteNEVRA(p), rpmteKey(p),
106 rpmfiDN(fi), rpmfiBN(fi),
113 /* Save file identifier to mark as state REPLACED. */
114 if ( !(isCfgFile || XFA_SKIPPING(rpmfsGetAction(fs, fx))) ) {
116 rpmfsAddReplaced(rpmteGetFileStates(p), rpmfiFX(fi),
117 headerGetInstance(otherHeader),
122 /* Determine config file dispostion, skipping missing files (if any). */
124 int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
125 rpmFileAction action = rpmfiDecideFate(otherFi, fi, skipMissing);
126 rpmfsSetAction(fs, fx, action);
128 rpmfiSetFReplacedSize(fi, rpmfiFSize(otherFi));
134 * Update disk space needs on each partition for this package's files.
136 /* XXX only ts->{probs,di} modified */
137 static void handleOverlappedFiles(rpmts ts, rpmFpHash ht, rpmte p, rpmfi fi)
139 rpm_loff_t fixupSize = 0;
143 rpm_color_t tscolor = rpmtsColor(ts);
144 rpm_color_t prefcolor = rpmtsPrefColor(ts);
145 rpmfs fs = rpmteGetFileStates(p);
148 ps = rpmtsProblems(ts);
149 fi = rpmfiInit(fi, 0);
151 while ((i = rpmfiNext(fi)) >= 0) {
152 rpm_color_t oFColor, FColor;
153 struct fingerPrint_s * fiFps;
154 int otherPkgNum, otherFileNum;
159 struct rpmffi_s * recs;
162 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
166 fiFps = rpmfiFpsIndex(fi, i);
167 FFlags = rpmfiFFlags(fi);
168 FMode = rpmfiFMode(fi);
169 FColor = rpmfiFColor(fi);
175 * Retrieve all records that apply to this file. Note that the
176 * file info records were built in the same order as the packages
177 * will be installed and removed so the records for an overlapped
178 * files will be sorted in exactly the same order.
180 (void) rpmFpHashGetEntry(ht, fiFps, &recs, &numRecs, NULL);
183 * If this package is being added, look only at other packages
184 * being added -- removed packages dance to a different tune.
186 * If both this and the other package are being added, overlapped
187 * files must be identical (or marked as a conflict). The
188 * disposition of already installed config files leads to
189 * a small amount of extra complexity.
191 * If this package is being removed, then there are two cases that
192 * need to be worried about:
193 * If the other package is being added, then skip any overlapped files
194 * so that this package removal doesn't nuke the overlapped files
195 * that were just installed.
196 * If both this and the other package are being removed, then each
197 * file removal from preceding packages needs to be skipped so that
198 * the file removal occurs only on the last occurence of an overlapped
199 * file in the transaction set.
203 /* Locate this overlapped file in the set of added/removed packages. */
204 for (j = 0; j < numRecs && recs[j].p != p; j++)
207 /* Find what the previous disposition of this file was. */
208 otherFileNum = -1; /* keep gcc quiet */
213 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
214 otherTe = recs[otherPkgNum].p;
215 otherFi = rpmteFI(otherTe);
216 otherFileNum = recs[otherPkgNum].fileno;
217 otherFs = rpmteGetFileStates(otherTe);
219 /* Added packages need only look at other added packages. */
220 if (rpmteType(p) == TR_ADDED && rpmteType(otherTe) != TR_ADDED)
223 (void) rpmfiSetFX(otherFi, otherFileNum);
225 /* XXX Happens iff fingerprint for incomplete package install. */
226 if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN)
230 oFColor = rpmfiFColor(otherFi);
233 switch (rpmteType(p)) {
236 int reportConflicts =
237 !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
240 if (otherPkgNum < 0) {
241 /* XXX is this test still necessary? */
242 rpmFileAction action;
243 if (rpmfsGetAction(fs, i) != FA_UNKNOWN)
245 if (rpmfiConfigConflict(fi)) {
246 /* Here is a non-overlapped pre-existing config file. */
247 action = (FFlags & RPMFILE_NOREPLACE) ?
248 FA_ALTNAME : FA_BACKUP;
252 rpmfsSetAction(fs, i, action);
256 assert(otherFi != NULL);
257 /* Mark added overlapped non-identical files as a conflict. */
258 if (rpmfiCompare(otherFi, fi)) {
261 rConflicts = reportConflicts;
262 /* Resolve file conflicts to prefer Elf64 (if not forced) ... */
264 if (FColor & prefcolor) {
265 /* ... last file of preferred colour is installed ... */
266 if (!XFA_SKIPPING(rpmfsGetAction(fs, i)))
267 rpmfsSetAction(otherFs, otherFileNum, FA_SKIPCOLOR);
268 rpmfsSetAction(fs, i, FA_CREATE);
271 if (oFColor & prefcolor) {
272 /* ... first file of preferred colour is installed ... */
273 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
274 rpmfsSetAction(otherFs, otherFileNum, FA_CREATE);
275 rpmfsSetAction(fs, i, FA_SKIPCOLOR);
281 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
282 rpmteNEVRA(p), rpmteKey(p),
289 /* Try to get the disk accounting correct even if a conflict. */
290 fixupSize = rpmfiFSize(otherFi);
292 if (rpmfiConfigConflict(fi)) {
293 /* Here is an overlapped pre-existing config file. */
294 rpmFileAction action;
295 action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP;
296 rpmfsSetAction(fs, i, action);
299 rpmfsSetAction(fs, i, FA_CREATE);
304 if (otherPkgNum >= 0) {
305 assert(otherFi != NULL);
306 /* Here is an overlapped added file we don't want to nuke. */
307 if (rpmfsGetAction(otherFs, otherFileNum) != FA_ERASE) {
308 /* On updates, don't remove files. */
309 rpmfsSetAction(fs, i, FA_SKIP);
312 /* Here is an overlapped removed file: skip in previous. */
313 rpmfsSetAction(otherFs, otherFileNum, FA_SKIP);
315 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
317 if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
319 if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
320 rpmfsSetAction(fs, i, FA_ERASE);
324 /* Here is a pre-existing modified config file that needs saving. */
325 { pgpHashAlgo algo = 0;
327 const unsigned char *digest;
328 if ((digest = rpmfiFDigest(fi, &algo, &diglen))) {
329 unsigned char fdigest[diglen];
330 if (!rpmDoDigest(algo, fn, 0, fdigest, NULL) &&
331 memcmp(digest, fdigest, diglen)) {
332 rpmfsSetAction(fs, i, FA_BACKUP);
337 rpmfsSetAction(fs, i, FA_ERASE);
341 /* Update disk space info for a file. */
342 rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
343 rpmfiFReplacedSize(fi), fixupSize, rpmfsGetAction(fs, i));
350 * Ensure that current package is newer than installed package.
351 * @param p current transaction element
352 * @param h installed header
353 * @param ps problem set
354 * @return 0 if not newer, 1 if okay
356 static int ensureOlder(const rpmte p, const Header h, rpmps ps)
358 rpmsenseFlags reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
362 if (p == NULL || h == NULL)
365 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), rpmteEVR(p), reqFlags);
366 rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
367 req = rpmdsFree(req);
370 char * altNEVR = headerGetAsString(h, RPMTAG_NEVRA);
371 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
372 rpmteNEVRA(p), rpmteKey(p),
376 altNEVR = _free(altNEVR);
385 * Check if the curent file in the file iterator is in the
386 * netshardpath and though should be excluded.
387 * @param ts transaction set
388 * @param fi file info set
389 * @returns pointer to matching path or NULL
391 static char ** matchNetsharedpath(const rpmts ts, rpmfi fi)
394 const char * dn, * bn;
401 for (nsp = ts->netsharedPaths; nsp && *nsp; nsp++) {
406 if (!rstreqn(dn, *nsp, len))
408 /* Only directories or complete file paths can be net shared */
409 if (!(dn[len] == '/' || dn[len] == '\0'))
412 if (len < (dnlen + bnlen))
414 if (!rstreqn(dn, *nsp, dnlen))
416 /* Insure that only the netsharedpath basename is compared. */
417 if ((s = strchr((*nsp) + dnlen, '/')) != NULL && s[1] != '\0')
419 if (!rstreqn(bn, (*nsp) + dnlen, bnlen))
422 /* Only directories or complete file paths can be net shared */
423 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
432 static void skipEraseFiles(const rpmts ts, rpmte p)
434 rpmfi fi = rpmteFI(p);
435 rpmfs fs = rpmteGetFileStates(p);
439 * Skip net shared paths.
440 * Net shared paths are not relative to the current root (though
441 * they do need to take package relocations into account).
443 fi = rpmfiInit(fi, 0);
444 while ((i = rpmfiNext(fi)) >= 0)
446 nsp = matchNetsharedpath(ts, fi);
448 rpmfsSetAction(fs, i, FA_SKIPNETSHARED);
455 * Skip any files that do not match install policies.
456 * @param ts transaction set
457 * @param fi file info set
459 static void skipInstallFiles(const rpmts ts, rpmte p)
461 rpm_color_t tscolor = rpmtsColor(ts);
463 int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
464 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
465 const char * dn, * bn;
471 rpmfi fi = rpmteFI(p);
472 rpmfs fs = rpmteGetFileStates(p);
475 noDocs = rpmExpandNumeric("%{_excludedocs}");
477 /* Compute directory refcount, skip directory if now empty. */
479 drc = xcalloc(dc, sizeof(*drc));
480 dff = xcalloc(dc, sizeof(*dff));
482 fi = rpmfiInit(fi, 0);
483 while ((i = rpmfiNext(fi)) >= 0)
494 continue; /* XXX can't happen */
498 /* Don't bother with skipped files */
499 if (XFA_SKIPPING(rpmfsGetAction(fs, i))) {
500 drc[ix]--; dff[ix] = 1;
504 /* Ignore colored files not in our rainbow. */
505 FColor = rpmfiFColor(fi);
506 if (tscolor && FColor && !(tscolor & FColor)) {
507 drc[ix]--; dff[ix] = 1;
508 rpmfsSetAction(fs, i, FA_SKIPCOLOR);
513 * Skip net shared paths.
514 * Net shared paths are not relative to the current root (though
515 * they do need to take package relocations into account).
517 nsp = matchNetsharedpath(ts, fi);
519 drc[ix]--; dff[ix] = 1;
520 rpmfsSetAction(fs, i, FA_SKIPNETSHARED);
525 * Skip i18n language specific files.
527 flangs = (ts->installLangs != NULL) ? rpmfiFLangs(fi) : NULL;
528 if (flangs != NULL && *flangs != '\0') {
531 for (lang = ts->installLangs; *lang != NULL; lang++) {
532 for (l = flangs; *l != '\0'; l = le) {
533 for (le = l; *le != '\0' && *le != '|'; le++)
535 if ((le-l) > 0 && rstreqn(*lang, l, (le-l)))
537 if (*le == '|') le++; /* skip over | */
543 drc[ix]--; dff[ix] = 1;
544 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
550 * Skip config files if requested.
552 if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
553 drc[ix]--; dff[ix] = 1;
554 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
559 * Skip documentation if requested.
561 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
562 drc[ix]--; dff[ix] = 1;
563 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
568 /* Skip (now empty) directories that had skipped files. */
570 if (fi != NULL) /* XXX can't happen */
571 for (j = 0; j < dc; j++)
573 if ((fi = rpmfiInitD(fi)) != NULL)
574 while (j = rpmfiNextD(fi) >= 0)
578 if (drc[j]) continue; /* dir still has files. */
579 if (!dff[j]) continue; /* dir was not emptied here. */
581 /* Find parent directory and basename. */
582 dn = rpmfiDNIndex(fi, j); dnlen = strlen(dn) - 1;
583 bn = dn + dnlen; bnlen = 0;
584 while (bn > dn && bn[-1] != '/') {
590 /* If explicitly included in the package, skip the directory. */
591 fi = rpmfiInit(fi, 0);
592 while ((i = rpmfiNext(fi)) >= 0) {
593 const char * fdn, * fbn;
596 if (XFA_SKIPPING(rpmfsGetAction(fs, i)))
599 fFMode = rpmfiFMode(fi);
601 if (rpmfiWhatis(fFMode) != XDIR)
604 if (strlen(fdn) != dnlen)
606 if (!rstreqn(fdn, dn, dnlen))
609 if (strlen(fbn) != bnlen)
611 if (!rstreqn(fbn, bn, bnlen))
613 rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn);
614 rpmfsSetAction(fs, i, FA_SKIPNSTATE);
627 #define HASHTYPE rpmStringSet
628 #define HTKEYTYPE const char *
629 #include "lib/rpmhash.H"
630 #include "lib/rpmhash.C"
632 /* Get a rpmdbMatchIterator containing all files in
633 * the rpmdb that share the basename with one from
635 * @param ts transaction set
636 * @return rpmdbMatchIterator sorted
637 by (package, fileNum)
640 rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount)
644 rpmdbMatchIterator mi;
646 const char * baseName;
648 rpmStringSet baseNames = rpmStringSetCreate(fileCount,
649 hashFunctionString, strcmp, NULL);
651 mi = rpmdbInitIterator(rpmtsGetRdb(ts), RPMTAG_BASENAMES, NULL, 0);
654 while ((p = rpmtsiNext(pi, 0)) != NULL) {
655 (void) rpmdbCheckSignals();
657 if ((fi = rpmteFI(p)) == NULL)
658 continue; /* XXX can't happen */
659 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
662 /* Gather all installed headers with matching basename's. */
663 fi = rpmfiInit(fi, 0);
664 while (rpmfiNext(fi) >= 0) {
666 baseName = rpmfiBN(fi);
667 if (rpmStringSetHasEntry(baseNames, baseName))
670 keylen = strlen(baseName);
672 keylen++; /* XXX "/" fixup. */
673 xx = rpmdbExtendIterator(mi, baseName, keylen);
674 rpmStringSetAddEntry(baseNames, baseName);
678 rpmStringSetFree(baseNames);
680 rpmdbSortIterator(mi);
681 /* iterator is now sorted by (recnum, filenum) */
685 /* Check files in the transactions against the rpmdb
686 * Lookup all files with the same basename in the rpmdb
687 * and then check for matching finger prints
688 * @param ts transaction set
689 * @param fpc global finger print cache
692 void checkInstalledFiles(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc)
700 unsigned int fileNum;
703 rpmdbMatchIterator mi;
708 rpmlog(RPMLOG_DEBUG, "computing file dispositions\n");
710 mi = rpmFindBaseNamesInDB(ts, fileCount);
712 /* For all installed headers with matching basename's ... */
716 if (rpmdbGetIteratorCount(mi) == 0) {
717 mi = rpmdbFreeIterator(mi);
721 /* Loop over all packages from the rpmdb */
722 h = newheader = rpmdbNextIterator(mi);
724 headerGetFlags hgflags = HEADERGET_MINMEM;
725 struct rpmtd_s bnames, dnames, dindexes, ostates;
727 unsigned int installedPkg;
729 /* Is this package being removed? */
730 installedPkg = rpmdbGetIteratorOffset(mi);
732 if (ts->removedPackages != NULL)
733 for (j = 0; j < ts->numRemovedPackages; j++) {
734 if (ts->removedPackages[j] != installedPkg)
741 headerGet(h, RPMTAG_BASENAMES, &bnames, hgflags);
742 headerGet(h, RPMTAG_DIRNAMES, &dnames, hgflags);
743 headerGet(h, RPMTAG_DIRINDEXES, &dindexes, hgflags);
744 headerGet(h, RPMTAG_FILESTATES, &ostates, hgflags);
747 /* loop over all interesting files in that package */
750 struct rpmffi_s * recs;
752 const char * dirName;
753 const char * baseName;
755 fileNum = rpmdbGetIteratorFileNum(mi);
756 rpmtdSetIndex(&bnames, fileNum);
757 rpmtdSetIndex(&dindexes, fileNum);
758 rpmtdSetIndex(&dnames, *rpmtdGetUint32(&dindexes));
759 rpmtdSetIndex(&ostates, fileNum);
761 dirName = rpmtdGetString(&dnames);
762 baseName = rpmtdGetString(&bnames);
764 /* lookup finger print for this file */
765 if ( dirName == oldDir) {
766 /* directory is the same as last round */
767 fp.baseName = baseName;
769 fp = fpLookup(fpc, dirName, baseName, 1);
772 /* search for files in the transaction with same finger print */
773 gotRecs = rpmFpHashGetEntry(ht, &fp, &recs, &numRecs, NULL);
775 for (j=0; (j<numRecs)&&gotRecs; j++) {
778 fs = rpmteGetFileStates(p);
780 /* Determine the fate of each file. */
781 switch (rpmteType(p)) {
784 otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER);
786 rpmfiSetFX(fi, recs[j].fileno);
787 rpmfiSetFX(otherFi, fileNum);
788 xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved);
792 rpmfiSetFX(fi, recs[j].fileno);
793 if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL)
794 rpmfsSetAction(fs, recs[j].fileno, FA_SKIP);
800 newheader = rpmdbNextIterator(mi);
802 } while (newheader==h);
804 otherFi = rpmfiFree(otherFi);
805 rpmtdFreeData(&ostates);
806 rpmtdFreeData(&bnames);
807 rpmtdFreeData(&dnames);
808 rpmtdFreeData(&dindexes);
813 mi = rpmdbFreeIterator(mi);
817 * For packages being installed:
818 * - verify package arch/os.
819 * - verify package epoch:version-release is newer.
821 static rpmps checkProblems(rpmts ts)
823 rpm_color_t tscolor = rpmtsColor(ts);
824 rpmps ps = rpmpsCreate();
825 rpmtsi pi = rpmtsiInit(ts);
828 /* The ordering doesn't matter here */
829 /* XXX Only added packages need be checked. */
830 rpmlog(RPMLOG_DEBUG, "sanity checking %d elements\n", rpmtsNElements(ts));
831 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
832 rpmdbMatchIterator mi;
835 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
836 if (!archOkay(rpmteA(p)))
837 rpmpsAppend(ps, RPMPROB_BADARCH,
838 rpmteNEVRA(p), rpmteKey(p),
842 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
843 if (!osOkay(rpmteO(p)))
844 rpmpsAppend(ps, RPMPROB_BADOS,
845 rpmteNEVRA(p), rpmteKey(p),
849 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
851 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
852 while ((h = rpmdbNextIterator(mi)) != NULL)
853 ensureOlder(p, h, ps);
854 mi = rpmdbFreeIterator(mi);
857 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
858 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
859 rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p));
860 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p));
861 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p));
863 rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP, rpmteA(p));
864 rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP, rpmteO(p));
867 while (rpmdbNextIterator(mi) != NULL) {
868 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
869 rpmteNEVRA(p), rpmteKey(p),
874 mi = rpmdbFreeIterator(mi);
877 /* XXX rpmte problems can only be relocation problems atm */
878 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE)) {
879 psi = rpmpsInitIterator(rpmteProblems(p));
880 while (rpmpsNextIterator(psi) >= 0) {
881 rpmpsAppendProblem(ps, rpmpsGetProblem(psi));
883 rpmpsFreeIterator(psi);
891 * Run pre/post transaction scripts for transaction set
892 * param ts Transaction set
893 * param stag RPMTAG_PRETRANS or RPMTAG_POSTTRANS
894 * return 0 on success, -1 on error (invalid script tag)
896 static int runTransScripts(rpmts ts, rpmTag stag)
901 rpmTag progtag = RPMTAG_NOT_FOUND;
904 if (stag == RPMTAG_PRETRANS) {
905 progtag = RPMTAG_PRETRANSPROG;
906 } else if (stag == RPMTAG_POSTTRANS) {
907 progtag = RPMTAG_POSTTRANSPROG;
913 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
914 /* If no pre/post-transaction script, then don't bother. */
915 if (!rpmteHaveTransScript(p, stag))
918 if (rpmteOpen(p, ts, 0)) {
919 psm = rpmpsmNew(ts, p);
920 xx = rpmpsmScriptStage(psm, stag, progtag);
921 psm = rpmpsmFree(psm);
922 rpmteClose(p, ts, 0);
929 /* Add fingerprint for each file not skipped. */
930 static void addFingerprints(rpmts ts, uint64_t fileCount, rpmFpHash ht, fingerPrintCache fpc)
937 rpmFpHash symlinks = rpmFpHashCreate(fileCount/16+16, fpHashFunction, fpEqual, NULL, NULL);
940 while ((p = rpmtsiNext(pi, 0)) != NULL) {
941 (void) rpmdbCheckSignals();
943 if ((fi = rpmteFI(p)) == NULL)
944 continue; /* XXX can't happen */
946 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
947 rpmfiFpLookup(fi, fpc);
948 /* collect symbolic links */
949 fi = rpmfiInit(fi, 0);
950 while ((i = rpmfiNext(fi)) >= 0) {
952 char const *linktarget;
953 linktarget = rpmfiFLink(fi);
954 if (!(linktarget && *linktarget != '\0'))
956 if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
960 rpmFpHashAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi);
962 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
967 /* ===============================================
968 * Check fingerprints if they contain symlinks
969 * and add them to the hash table
973 while ((p = rpmtsiNext(pi, 0)) != NULL) {
974 (void) rpmdbCheckSignals();
976 if ((fi = rpmteFI(p)) == NULL)
977 continue; /* XXX can't happen */
978 fi = rpmfiInit(fi, 0);
979 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
980 while ((i = rpmfiNext(fi)) >= 0) {
981 if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
983 fpLookupSubdir(symlinks, ht, fpc, p, i);
985 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
989 rpmFpHashFree(symlinks);
992 static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet)
994 rpm_tid_t tid = (rpm_tid_t) time(NULL);
995 int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) ? O_RDONLY : (O_RDWR|O_CREAT);
997 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
998 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
999 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1000 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1002 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1003 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1005 /* if SELinux isn't enabled or init fails, don't bother... */
1006 if (!rpmtsSELinuxEnabled(ts)) {
1007 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
1010 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
1011 char *fn = rpmGetPath("%{?_install_file_context_path}", NULL);
1012 if (matchpathcon_init(fn) == -1) {
1013 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
1018 /* XXX Make sure the database is open RDWR for package install/erase. */
1019 if (rpmtsOpenDB(ts, dbmode)) {
1020 return -1; /* XXX W2DO? */
1023 ts->ignoreSet = ignoreSet;
1024 ts->probs = rpmpsFree(ts->probs);
1026 { char * currDir = rpmGetCwd();
1027 rpmtsSetCurrDir(ts, currDir);
1028 currDir = _free(currDir);
1031 (void) rpmtsSetChrootDone(ts, 0);
1032 (void) rpmtsSetTid(ts, tid);
1034 /* Get available space on mounted file systems. */
1035 (void) rpmtsInitDSI(ts);
1040 static int rpmtsFinish(rpmts ts)
1042 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
1043 matchpathcon_fini();
1048 static int rpmtsPrepare(rpmts ts)
1054 uint64_t fileCount = countFiles(ts);
1055 const char * rootDir = rpmtsRootDir(ts);
1056 int dochroot = (rootDir != NULL && !rstreq(rootDir, "/") && *rootDir == '/');
1058 fingerPrintCache fpc = fpCacheCreate(fileCount/2 + 10001);
1059 rpmFpHash ht = rpmFpHashCreate(fileCount/2+1, fpHashFunction, fpEqual,
1062 rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount);
1064 /* Skip netshared paths, not our i18n files, and excluded docs */
1065 pi = rpmtsiInit(ts);
1066 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1067 if ((fi = rpmteFI(p)) == NULL)
1068 continue; /* XXX can't happen */
1070 if (rpmfiFC(fi) == 0)
1072 if (rpmteType(p) == TR_ADDED) {
1073 skipInstallFiles(ts, p);
1075 skipEraseFiles(ts, p);
1078 pi = rpmtsiFree(pi);
1080 /* Enter chroot for fingerprinting if necessary */
1081 if (!rpmtsChrootDone(ts)) {
1084 /* opening db before chroot not optimal, see rhbz#103852 c#3 */
1085 xx = rpmdbOpenAll(ts->rdb);
1086 if (chroot(rootDir) == -1) {
1087 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
1092 (void) rpmtsSetChrootDone(ts, 1);
1095 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount);
1096 addFingerprints(ts, fileCount, ht, fpc);
1097 /* check against files in the rpmdb */
1098 checkInstalledFiles(ts, fileCount, ht, fpc);
1100 pi = rpmtsiInit(ts);
1101 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1102 if ((fi = rpmteFI(p)) == NULL)
1103 continue; /* XXX can't happen */
1105 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1106 /* check files in ts against each other and update disk space
1107 needs on each partition for this package. */
1108 handleOverlappedFiles(ts, ht, p, fi);
1110 /* Check added package has sufficient space on each partition used. */
1111 if (rpmteType(p) == TR_ADDED) {
1112 rpmtsCheckDSIProblems(ts, p);
1114 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1116 pi = rpmtsiFree(pi);
1117 rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount);
1119 /* return from chroot if done earlier */
1120 if (rpmtsChrootDone(ts)) {
1121 const char * currDir = rpmtsCurrDir(ts);
1124 (void) rpmtsSetChrootDone(ts, 0);
1125 if (currDir != NULL)
1126 xx = chdir(currDir);
1129 /* File info sets, fp caches etc not needed beyond here, free 'em up. */
1130 pi = rpmtsiInit(ts);
1131 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1132 rpmteSetFI(p, NULL);
1134 pi = rpmtsiFree(pi);
1137 ht = rpmFpHashFree(ht);
1138 fpc = fpCacheFree(fpc);
1143 * Transaction main loop: install and remove packages
1145 static int rpmtsProcess(rpmts ts)
1150 pi = rpmtsiInit(ts);
1151 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1153 rpmElementType tetype = rpmteType(p);
1154 rpmtsOpX op = (tetype == TR_ADDED) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
1156 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
1157 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1159 if (rpmteFailed(p)) {
1160 /* XXX this should be a warning, need a better message though */
1161 rpmlog(RPMLOG_DEBUG, "element %s marked as failed, skipping\n",
1167 if (rpmteOpen(p, ts, 1)) {
1169 pkgStage stage = PSM_UNKNOWN;
1173 stage = PSM_PKGINSTALL;
1176 stage = PSM_PKGERASE;
1179 psm = rpmpsmNew(ts, p);
1180 (void) rpmswEnter(rpmtsOp(ts, op), 0);
1181 failed = rpmpsmStage(psm, stage);
1182 (void) rpmswExit(rpmtsOp(ts, op), 0);
1183 psm = rpmpsmFree(psm);
1184 rpmteClose(p, ts, 1);
1187 rpmteMarkFailed(p, ts);
1190 (void) rpmdbSync(rpmtsGetRdb(ts));
1192 pi = rpmtsiFree(pi);
1196 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
1198 int rc = -1; /* assume failure */
1201 /* XXX programmer error segfault avoidance. */
1202 if (rpmtsNElements(ts) <= 0) {
1206 /* If we are in test mode, then there's no need for transaction lock. */
1207 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
1208 if (!(lock = rpmtsAcquireLock(ts))) {
1213 /* Setup flags and such, open the DB */
1214 if (rpmtsSetup(ts, ignoreSet)) {
1218 /* Check package set for problems */
1219 ts->probs = checkProblems(ts);
1221 /* Run pre-transaction scripts, but only if there are no known
1222 * problems up to this point and not disabled otherwise. */
1223 if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPRE))
1224 || (rpmpsNumProblems(ts->probs) &&
1225 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
1226 rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n");
1227 runTransScripts(ts, RPMTAG_PRETRANS);
1230 /* Compute file disposition for each package in transaction set. */
1231 if (rpmtsPrepare(ts)) {
1235 /* If unfiltered problems exist, free memory and return. */
1236 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS) ||
1237 (rpmpsNumProblems(ts->probs) &&
1238 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))) {
1239 rc = ts->orderCount;
1243 /* Actually install and remove packages, get final exit code */
1244 rc = rpmtsProcess(ts) ? -1 : 0;
1246 /* Run post-transaction scripts unless disabled */
1247 if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_NOPOST))) {
1248 rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
1249 runTransScripts(ts, RPMTAG_POSTTRANS);
1253 (void) rpmtsFinish(ts);
1256 rpmtsFreeLock(lock);