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" /* fi->replaced, fi->actions... */
21 #include "lib/rpmte_internal.h" /* XXX te->h, te->fd, te->h */
22 #include "lib/rpmts_internal.h"
30 static int archOkay(const char * pkgArch)
32 if (pkgArch == NULL) return 0;
33 return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
38 static int osOkay(const char * pkgOs)
40 if (pkgOs == NULL) return 0;
41 return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
46 static int sharedCmp(const void * one, const void * two)
48 sharedFileInfo a = (sharedFileInfo) one;
49 sharedFileInfo b = (sharedFileInfo) two;
51 if (a->otherPkg < b->otherPkg)
53 else if (a->otherPkg > b->otherPkg)
60 * handleInstInstalledFiles.
61 * @param ts transaction set
62 * @param p current transaction element
63 * @param fi file info set
64 * @param shared shared file info
65 * @param sharedCount no. of shared elements
66 * @param reportConflicts
68 /* XXX only ts->{probs,rpmdb} modified */
69 static int handleInstInstalledFiles(const rpmts ts,
71 sharedFileInfo shared,
72 int sharedCount, int reportConflicts)
74 rpm_color_t tscolor = rpmtsColor(ts);
75 rpm_color_t prefcolor = rpmtsPrefColor(ts);
76 rpm_color_t otecolor, tecolor;
77 rpm_color_t oFColor, FColor;
78 char * altNEVR = NULL;
84 { rpmdbMatchIterator mi;
88 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
89 &shared->otherPkg, sizeof(shared->otherPkg));
90 while ((h = rpmdbNextIterator(mi)) != NULL) {
91 altNEVR = headerGetNEVRA(h, NULL);
92 otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
95 mi = rpmdbFreeIterator(mi);
98 /* Compute package color. */
99 tecolor = rpmteColor(p);
102 /* Compute other pkg color. */
104 otherFi = rpmfiInit(otherFi, 0);
106 while (rpmfiNext(otherFi) >= 0)
107 otecolor |= rpmfiFColor(otherFi);
113 fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
115 ps = rpmtsProblems(ts);
116 for (i = 0; i < sharedCount; i++, shared++) {
117 int otherFileNum, fileNum;
120 otherFileNum = shared->otherFileNum;
121 (void) rpmfiSetFX(otherFi, otherFileNum);
122 oFColor = rpmfiFColor(otherFi);
125 fileNum = shared->pkgFileNum;
126 (void) rpmfiSetFX(fi, fileNum);
127 FColor = rpmfiFColor(fi);
130 isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
133 /* XXX another tedious segfault, assume file state normal. */
134 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
138 if (XFA_SKIPPING(fi->actions[fileNum]))
141 if (!(fi->mapflags & CPIO_SBIT_CHECK)) {
142 rpm_mode_t omode = rpmfiFMode(otherFi);
143 if (S_ISREG(omode) && (omode & 06000) != 0) {
144 fi->mapflags |= CPIO_SBIT_CHECK;
148 if (rpmfiCompare(otherFi, fi)) {
151 rConflicts = reportConflicts;
152 /* Resolve file conflicts to prefer Elf64 (if not forced). */
153 if (tscolor != 0 && FColor != 0 && FColor != oFColor)
155 if (oFColor & prefcolor) {
156 fi->actions[fileNum] = FA_SKIPCOLOR;
159 if (FColor & prefcolor) {
160 fi->actions[fileNum] = FA_CREATE;
166 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
167 rpmteNEVRA(p), rpmteKey(p),
168 rpmfiDN(fi), rpmfiBN(fi),
172 /* Save file identifier to mark as state REPLACED. */
173 if ( !(isCfgFile || XFA_SKIPPING(fi->actions[fileNum])) ) {
174 /* FIX: p->replaced, not fi */
175 if (!shared->isRemoved)
176 fi->replaced[numReplaced++] = *shared;
180 /* Determine config file dispostion, skipping missing files (if any). */
183 ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
184 rpmFileAction action = rpmfiDecideFate(otherFi, fi, skipMissing);
185 fi->actions[fileNum] = action;
187 fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
191 altNEVR = _free(altNEVR);
192 otherFi = rpmfiFree(otherFi);
194 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
195 sizeof(*fi->replaced) * (numReplaced + 1));
196 fi->replaced[numReplaced].otherPkg = 0;
203 /* XXX only ts->rpmdb modified */
204 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
205 sharedFileInfo shared, int sharedCount)
209 const char * otherStates;
212 rpmdbMatchIterator mi;
214 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
215 &shared->otherPkg, sizeof(shared->otherPkg));
216 h = rpmdbNextIterator(mi);
218 mi = rpmdbFreeIterator(mi);
222 xx = hge(h, RPMTAG_FILESTATES, NULL, (rpm_data_t *) &otherStates, NULL);
224 for (i = 0; i < sharedCount; i++, shared++) {
225 int otherFileNum, fileNum;
226 otherFileNum = shared->otherFileNum;
227 fileNum = shared->pkgFileNum;
229 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
232 fi->actions[fileNum] = FA_SKIP;
235 mi = rpmdbFreeIterator(mi);
240 #define ISROOT(_d) (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
244 static int fpsCompare (const void * one, const void * two)
246 const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
247 const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
248 size_t adnlen = strlen(a->entry->dirName);
249 size_t asnlen = (a->subDir ? strlen(a->subDir) : 0);
250 size_t abnlen = strlen(a->baseName);
251 size_t bdnlen = strlen(b->entry->dirName);
252 size_t bsnlen = (b->subDir ? strlen(b->subDir) : 0);
253 size_t bbnlen = strlen(b->baseName);
254 char *afn = NULL, *bfn = NULL;
257 if (adnlen == 1 && asnlen != 0) adnlen = 0;
258 if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
260 if (adnlen) rstrcat(&afn, a->entry->dirName);
262 if (a->subDir && asnlen) rstrcat(&afn, a->subDir);
263 if (abnlen) rstrcat(&afn, a->baseName);
264 if (afn[0] == '/' && afn[1] == '/') {
265 memmove(afn, afn+1, strlen(afn+1)+1);
268 if (bdnlen) rstrcat(&bfn, b->entry->dirName);
270 if (b->subDir && bsnlen) rstrcat(&bfn, b->subDir);
271 if (bbnlen) rstrcat(&bfn, b->baseName);
272 if (bfn[0] == '/' && bfn[1] == '/') {
273 memmove(bfn, bfn+1, strlen(bfn+1)+1);
276 rc = strcmp(afn, bfn);
278 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
281 fprintf(stderr, "\t%s/%s%s\trc %d\n",
282 ISROOT(b->entry->dirName),
283 (b->subDir ? b->subDir : ""),
293 static int _linear_fps_search = 0;
295 static int findFps(const struct fingerPrint_s * fiFps,
296 const struct fingerPrint_s * otherFps,
302 fprintf(stderr, "==> %s/%s%s\n",
303 ISROOT(fiFps->entry->dirName),
304 (fiFps->subDir ? fiFps->subDir : ""),
307 if (_linear_fps_search) {
310 for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
313 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
314 ISROOT(otherFps->entry->dirName),
315 (otherFps->subDir ? otherFps->subDir : ""),
318 /* If the addresses are the same, so are the values. */
319 if (fiFps == otherFps)
322 /* Otherwise, compare fingerprints by value. */
323 if (FP_EQUAL((*fiFps), (*otherFps)))
327 if (otherFileNum == otherFc) {
329 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
330 ISROOT(fiFps->entry->dirName),
331 (fiFps->subDir ? fiFps->subDir : ""),
339 const struct fingerPrint_s * bingoFps;
341 bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
342 if (bingoFps == NULL) {
344 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
345 ISROOT(fiFps->entry->dirName),
346 (fiFps->subDir ? fiFps->subDir : ""),
351 /* If the addresses are the same, so are the values. */
352 /* LCL: looks good to me */
353 if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
355 fprintf(stderr, "*** BAD %s/%s%s\n",
356 ISROOT(bingoFps->entry->dirName),
357 (bingoFps->subDir ? bingoFps->subDir : ""),
362 otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
370 * Update disk space needs on each partition for this package's files.
372 /* XXX only ts->{probs,di} modified */
373 static void handleOverlappedFiles(const rpmts ts,
374 const rpmte p, rpmfi fi)
376 uint32_t fixupSize = 0;
381 ps = rpmtsProblems(ts);
382 fi = rpmfiInit(fi, 0);
384 while ((i = rpmfiNext(fi)) >= 0) {
385 rpm_color_t tscolor = rpmtsColor(ts);
386 rpm_color_t prefcolor = rpmtsPrefColor(ts);
387 rpm_color_t oFColor, FColor;
388 struct fingerPrint_s * fiFps;
389 int otherPkgNum, otherFileNum;
396 if (XFA_SKIPPING(fi->actions[i]))
401 FFlags = rpmfiFFlags(fi);
402 FMode = rpmfiFMode(fi);
403 FColor = rpmfiFColor(fi);
409 * Retrieve all records that apply to this file. Note that the
410 * file info records were built in the same order as the packages
411 * will be installed and removed so the records for an overlapped
412 * files will be sorted in exactly the same order.
414 (void) htGetEntry(ts->ht, fiFps,
415 (const void ***) &recs, &numRecs, NULL);
418 * If this package is being added, look only at other packages
419 * being added -- removed packages dance to a different tune.
421 * If both this and the other package are being added, overlapped
422 * files must be identical (or marked as a conflict). The
423 * disposition of already installed config files leads to
424 * a small amount of extra complexity.
426 * If this package is being removed, then there are two cases that
427 * need to be worried about:
428 * If the other package is being added, then skip any overlapped files
429 * so that this package removal doesn't nuke the overlapped files
430 * that were just installed.
431 * If both this and the other package are being removed, then each
432 * file removal from preceding packages needs to be skipped so that
433 * the file removal occurs only on the last occurence of an overlapped
434 * file in the transaction set.
438 /* Locate this overlapped file in the set of added/removed packages. */
439 for (j = 0; j < numRecs && recs[j] != fi; j++)
442 /* Find what the previous disposition of this file was. */
443 otherFileNum = -1; /* keep gcc quiet */
445 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
446 struct fingerPrint_s * otherFps;
449 otherFi = recs[otherPkgNum];
451 /* Added packages need only look at other added packages. */
452 if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
455 otherFps = otherFi->fps;
456 otherFc = rpmfiFC(otherFi);
458 otherFileNum = findFps(fiFps, otherFps, otherFc);
459 (void) rpmfiSetFX(otherFi, otherFileNum);
461 /* XXX Happens iff fingerprint for incomplete package install. */
462 if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
466 oFColor = rpmfiFColor(otherFi);
469 switch (rpmteType(p)) {
472 int reportConflicts =
473 !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
476 if (otherPkgNum < 0) {
477 /* XXX is this test still necessary? */
478 if (fi->actions[i] != FA_UNKNOWN)
480 if (rpmfiConfigConflict(fi)) {
481 /* Here is a non-overlapped pre-existing config file. */
482 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
483 ? FA_ALTNAME : FA_BACKUP;
485 fi->actions[i] = FA_CREATE;
490 assert(otherFi != NULL);
491 /* Mark added overlapped non-identical files as a conflict. */
492 if (rpmfiCompare(otherFi, fi)) {
495 rConflicts = reportConflicts;
496 /* Resolve file conflicts to prefer Elf64 (if not forced) ... */
498 if (FColor & prefcolor) {
499 /* ... last file of preferred colour is installed ... */
500 if (!XFA_SKIPPING(fi->actions[i])) {
501 /* XXX static helpers are order dependent. Ick. */
502 if (strcmp(fn, "/usr/sbin/libgcc_post_upgrade")
503 && strcmp(fn, "/usr/sbin/glibc_post_upgrade"))
504 otherFi->actions[otherFileNum] = FA_SKIPCOLOR;
506 fi->actions[i] = FA_CREATE;
509 if (oFColor & prefcolor) {
510 /* ... first file of preferred colour is installed ... */
511 if (XFA_SKIPPING(fi->actions[i]))
512 otherFi->actions[otherFileNum] = FA_CREATE;
513 fi->actions[i] = FA_SKIPCOLOR;
516 if (FColor == 0 && oFColor == 0) {
517 /* ... otherwise, do both, last in wins. */
518 otherFi->actions[otherFileNum] = FA_CREATE;
519 fi->actions[i] = FA_CREATE;
526 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
527 rpmteNEVRA(p), rpmteKey(p),
529 rpmteNEVRA(otherFi->te),
534 /* Try to get the disk accounting correct even if a conflict. */
535 fixupSize = rpmfiFSize(otherFi);
537 if (rpmfiConfigConflict(fi)) {
538 /* Here is an overlapped pre-existing config file. */
539 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
540 ? FA_ALTNAME : FA_SKIP;
543 fi->actions[i] = FA_CREATE;
548 if (otherPkgNum >= 0) {
549 assert(otherFi != NULL);
550 /* Here is an overlapped added file we don't want to nuke. */
551 if (otherFi->actions[otherFileNum] != FA_ERASE) {
552 /* On updates, don't remove files. */
553 fi->actions[i] = FA_SKIP;
556 /* Here is an overlapped removed file: skip in previous. */
557 otherFi->actions[otherFileNum] = FA_SKIP;
559 if (XFA_SKIPPING(fi->actions[i]))
561 if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
563 if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
564 fi->actions[i] = FA_ERASE;
568 /* Here is a pre-existing modified config file that needs saving. */
569 { pgpHashAlgo algo = 0;
571 const unsigned char *digest;
572 if ((digest = rpmfiFDigest(fi, &algo, &diglen))) {
573 unsigned char fdigest[diglen];
574 if (!rpmDoDigest(algo, fn, 0, fdigest, NULL) &&
575 memcmp(digest, fdigest, diglen)) {
576 fi->actions[i] = FA_BACKUP;
581 fi->actions[i] = FA_ERASE;
585 /* Update disk space info for a file. */
586 rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
587 fi->replacedSizes[i], fixupSize, fi->actions[i]);
594 * Ensure that current package is newer than installed package.
595 * @param ts transaction set
596 * @param p current transaction element
597 * @param h installed header
598 * @return 0 if not newer, 1 if okay
600 static int ensureOlder(rpmts ts,
601 const rpmte p, const Header h)
603 rpmsenseFlags reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
607 if (p == NULL || h == NULL)
610 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), rpmteEVR(p), reqFlags);
611 rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
612 req = rpmdsFree(req);
615 rpmps ps = rpmtsProblems(ts);
616 char * altNEVR = headerGetNEVRA(h, NULL);
617 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
618 rpmteNEVRA(p), rpmteKey(p),
622 altNEVR = _free(altNEVR);
632 * Skip any files that do not match install policies.
633 * @param ts transaction set
634 * @param fi file info set
636 /* FIX: fi->actions is modified. */
637 static void skipFiles(const rpmts ts, rpmfi fi)
639 rpm_color_t tscolor = rpmtsColor(ts);
641 int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
642 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
643 ARGV_t netsharedPaths = NULL;
644 ARGV_t languages = NULL;
645 const char * dn, * bn;
654 noDocs = rpmExpandNumeric("%{_excludedocs}");
656 { char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
657 if (tmpPath && *tmpPath != '%') {
658 argvSplit(&netsharedPaths, tmpPath, ":");
660 tmpPath = _free(tmpPath);
663 s = rpmExpand("%{_install_langs}", NULL);
664 if (!(s && *s != '%'))
667 argvSplit(&languages, s, ":");
672 /* Compute directory refcount, skip directory if now empty. */
674 drc = xcalloc(dc, sizeof(*drc));
675 dff = xcalloc(dc, sizeof(*dff));
677 fi = rpmfiInit(fi, 0);
678 if (fi != NULL) /* XXX lclint */
679 while ((i = rpmfiNext(fi)) >= 0)
689 continue; /* XXX can't happen */
693 /* Don't bother with skipped files */
694 if (XFA_SKIPPING(fi->actions[i])) {
695 drc[ix]--; dff[ix] = 1;
699 /* Ignore colored files not in our rainbow. */
700 FColor = rpmfiFColor(fi);
701 if (tscolor && FColor && !(tscolor & FColor)) {
702 drc[ix]--; dff[ix] = 1;
703 fi->actions[i] = FA_SKIPCOLOR;
708 * Skip net shared paths.
709 * Net shared paths are not relative to the current root (though
710 * they do need to take package relocations into account).
712 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
717 if (strncmp(dn, *nsp, len))
719 /* Only directories or complete file paths can be net shared */
720 if (!(dn[len] == '/' || dn[len] == '\0'))
723 if (len < (dnlen + bnlen))
725 if (strncmp(dn, *nsp, dnlen))
727 /* Insure that only the netsharedpath basename is compared. */
728 if ((s = strchr((*nsp) + dnlen, '/')) != NULL && s[1] != '\0')
730 if (strncmp(bn, (*nsp) + dnlen, bnlen))
733 /* Only directories or complete file paths can be net shared */
734 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
742 drc[ix]--; dff[ix] = 1;
743 fi->actions[i] = FA_SKIPNETSHARED;
748 * Skip i18n language specific files.
750 if (languages != NULL && fi->flangs != NULL && *fi->flangs[i]) {
753 for (lang = languages; *lang != NULL; lang++) {
754 if (!strcmp(*lang, "all"))
756 for (l = fi->flangs[i]; *l != '\0'; l = le) {
757 for (le = l; *le != '\0' && *le != '|'; le++)
759 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
761 if (*le == '|') le++; /* skip over | */
767 drc[ix]--; dff[ix] = 1;
768 fi->actions[i] = FA_SKIPNSTATE;
774 * Skip config files if requested.
776 if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
777 drc[ix]--; dff[ix] = 1;
778 fi->actions[i] = FA_SKIPNSTATE;
783 * Skip documentation if requested.
785 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
786 drc[ix]--; dff[ix] = 1;
787 fi->actions[i] = FA_SKIPNSTATE;
792 /* Skip (now empty) directories that had skipped files. */
794 if (fi != NULL) /* XXX can't happen */
795 for (j = 0; j < dc; j++)
797 if ((fi = rpmfiInitD(fi)) != NULL)
798 while (j = rpmfiNextD(fi) >= 0)
802 if (drc[j]) continue; /* dir still has files. */
803 if (!dff[j]) continue; /* dir was not emptied here. */
805 /* Find parent directory and basename. */
806 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
807 bn = dn + dnlen; bnlen = 0;
808 while (bn > dn && bn[-1] != '/') {
814 /* If explicitly included in the package, skip the directory. */
815 fi = rpmfiInit(fi, 0);
816 if (fi != NULL) /* XXX lclint */
817 while ((i = rpmfiNext(fi)) >= 0) {
818 const char * fdn, * fbn;
821 if (XFA_SKIPPING(fi->actions[i]))
824 fFMode = rpmfiFMode(fi);
826 if (rpmfiWhatis(fFMode) != XDIR)
829 if (strlen(fdn) != dnlen)
831 if (strncmp(fdn, dn, dnlen))
834 if (strlen(fbn) != bnlen)
836 if (strncmp(fbn, bn, bnlen))
838 rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn);
839 fi->actions[i] = FA_SKIPNSTATE;
844 if (netsharedPaths) argvFree(netsharedPaths);
845 #ifdef DYING /* XXX freeFi will deal with this later. */
846 fi->flangs = _free(fi->flangs);
848 if (languages) argvFree(languages);
854 * Return transaction element's file info.
855 * @todo Take a rpmfi refcount here.
856 * @param tsi transaction element iterator
857 * @return transaction element file info
860 rpmfi rpmtsiFi(const rpmtsi tsi)
864 if (tsi != NULL && tsi->ocsave != -1) {
865 /* FIX: rpmte not opaque */
866 rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
867 if (te != NULL && (fi = te->fi) != NULL)
874 * Run pre/post transaction scripts for transaction set
875 * param ts Transaction set
876 * param stag RPMTAG_PRETRANS or RPMTAG_POSTTRANS
877 * return 0 on success, -1 on error (invalid script tag)
879 static int runTransScripts(rpmts ts, rpmTag stag)
888 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
889 const char * script = NULL, * scriptprog = NULL;
890 rpmTag progtag = RPMTAG_NOT_FOUND;
892 if ((fi = rpmtsiFi(pi)) == NULL)
893 continue; /* XXX can't happen */
896 case RPMTAG_PRETRANS:
897 script = fi->pretrans;
898 scriptprog = fi->pretransprog;
899 progtag = RPMTAG_PRETRANSPROG;
901 case RPMTAG_POSTTRANS:
902 script = fi->posttrans;
903 scriptprog = fi->posttransprog;
904 progtag = RPMTAG_POSTTRANSPROG;
905 p->fi = rpmfiFree(p->fi);
908 /* programmer error, blow up */
909 assert(progtag != RPMTAG_NOT_FOUND);
913 /* If no pre/post-transaction script, then don't bother. */
917 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
918 rpmteKey(p), ts->notifyData);
920 if (rpmteFd(p) != NULL) {
921 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
922 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
924 ovsflags = rpmtsSetVSFlags(ts, vsflags);
925 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
926 rpmteNEVR(p), &p->h);
927 vsflags = rpmtsSetVSFlags(ts, ovsflags);
930 /* FIX: notify annotations */
931 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
932 0, 0, rpmteKey(p), ts->notifyData);
935 case RPMRC_NOTTRUSTED:
942 if (rpmteFd(p) != NULL) {
943 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
944 if (fi != NULL) { /* XXX can't happen */
945 if (stag == RPMTAG_PRETRANS) {
953 psm = rpmpsmNew(ts, p, p->fi);
955 xx = rpmpsmScriptStage(psm, stag, progtag);
956 psm = rpmpsmFree(psm);
958 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
959 rpmteKey(p), ts->notifyData);
961 p->h = headerFree(p->h);
968 #define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
970 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
972 rpm_color_t tscolor = rpmtsColor(ts);
975 int totalFileCount = 0;
977 sharedFileInfo shared, sharedList;
980 rpmalKey lastFailKey;
981 fingerPrintCache fpc;
991 /* XXX programmer error segfault avoidance. */
992 if (rpmtsNElements(ts) <= 0)
995 /* If we are in test mode, then there's no need for transaction lock. */
996 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
997 lock = rpmtsAcquireLock(ts);
999 return -1; /* XXX W2DO? */
1002 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
1003 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1004 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1005 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1007 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1008 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1010 /* if SELinux isn't enabled or init fails, don't bother... */
1011 if (!rpmtsSELinuxEnabled(ts)) {
1012 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
1015 if (!rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS) {
1016 char *fn = rpmGetPath("%{?_install_file_context_path}", NULL);
1017 if (matchpathcon_init(fn) == -1) {
1018 rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS));
1023 ts->probs = rpmpsFree(ts->probs);
1024 ts->probs = rpmpsCreate();
1026 /* XXX Make sure the database is open RDWR for package install/erase. */
1027 { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1028 ? O_RDONLY : (O_RDWR|O_CREAT);
1030 /* Open database RDWR for installing packages. */
1031 if (rpmtsOpenDB(ts, dbmode)) {
1032 rpmtsFreeLock(lock);
1033 return -1; /* XXX W2DO? */
1037 ts->ignoreSet = ignoreSet;
1038 { char * currDir = rpmGetCwd();
1039 rpmtsSetCurrDir(ts, currDir);
1040 currDir = _free(currDir);
1043 (void) rpmtsSetChrootDone(ts, 0);
1045 { rpm_tid_t tid = (rpm_tid_t) time(NULL);
1046 (void) rpmtsSetTid(ts, tid);
1049 /* Get available space on mounted file systems. */
1050 xx = rpmtsInitDSI(ts);
1052 /* ===============================================
1053 * For packages being installed:
1054 * - verify package arch/os.
1055 * - verify package epoch:version-release is newer.
1057 * For packages being removed:
1061 rpmlog(RPMLOG_DEBUG, "sanity checking %d elements\n", rpmtsNElements(ts));
1062 ps = rpmtsProblems(ts);
1063 /* The ordering doesn't matter here */
1064 pi = rpmtsiInit(ts);
1065 /* XXX Only added packages need be checked. */
1066 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1067 rpmdbMatchIterator mi;
1070 if ((fi = rpmtsiFi(pi)) == NULL)
1071 continue; /* XXX can't happen */
1074 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
1075 if (!archOkay(rpmteA(p)))
1076 rpmpsAppend(ps, RPMPROB_BADARCH,
1077 rpmteNEVRA(p), rpmteKey(p),
1081 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1082 if (!osOkay(rpmteO(p)))
1083 rpmpsAppend(ps, RPMPROB_BADOS,
1084 rpmteNEVRA(p), rpmteKey(p),
1088 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1090 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1091 while ((h = rpmdbNextIterator(mi)) != NULL)
1092 xx = ensureOlder(ts, p, h);
1093 mi = rpmdbFreeIterator(mi);
1096 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1097 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1098 xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
1100 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
1102 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
1105 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP,
1107 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP,
1111 while (rpmdbNextIterator(mi) != NULL) {
1112 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1113 rpmteNEVRA(p), rpmteKey(p),
1118 mi = rpmdbFreeIterator(mi);
1121 /* Count no. of files (if any). */
1122 totalFileCount += fc;
1125 pi = rpmtsiFree(pi);
1128 /* The ordering doesn't matter here */
1129 pi = rpmtsiInit(ts);
1130 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1133 if ((fi = rpmtsiFi(pi)) == NULL)
1134 continue; /* XXX can't happen */
1137 totalFileCount += fc;
1139 pi = rpmtsiFree(pi);
1142 /* Run pre-transaction scripts, but only if there are no known
1143 * problems up to this point. */
1144 if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST))
1145 || (rpmpsNumProblems(ts->probs) &&
1146 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
1147 rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n");
1148 runTransScripts(ts, RPMTAG_PRETRANS);
1151 /* ===============================================
1152 * Initialize transaction element file info for package:
1156 * FIXME?: we'd be better off assembling one very large file list and
1157 * calling fpLookupList only once. I'm not sure that the speedup is
1158 * worth the trouble though.
1160 rpmlog(RPMLOG_DEBUG, "computing %d file fingerprints\n", totalFileCount);
1162 numAdded = numRemoved = 0;
1163 pi = rpmtsiInit(ts);
1164 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1167 if ((fi = rpmtsiFi(pi)) == NULL)
1168 continue; /* XXX can't happen */
1171 switch (rpmteType(p)) {
1175 /* Skip netshared paths, not our i18n files, and excluded docs */
1181 fi->record = rpmteDBOffset(p);
1185 fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1187 pi = rpmtsiFree(pi);
1189 if (!rpmtsChrootDone(ts)) {
1190 const char * rootDir = rpmtsRootDir(ts);
1192 if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
1193 /* opening db before chroot not optimal, see rhbz#103852 c#3 */
1194 xx = rpmdbOpenAll(ts->rdb);
1195 if (chroot(rootDir) == -1) {
1196 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
1200 (void) rpmtsSetChrootDone(ts, 1);
1203 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1204 fpc = fpCacheCreate(totalFileCount);
1206 /* ===============================================
1207 * Add fingerprint for each file not skipped.
1209 pi = rpmtsiInit(ts);
1210 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1213 (void) rpmdbCheckSignals();
1215 if ((fi = rpmtsiFi(pi)) == NULL)
1216 continue; /* XXX can't happen */
1219 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1220 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1221 fi = rpmfiInit(fi, 0);
1222 if (fi != NULL) /* XXX lclint */
1223 while ((i = rpmfiNext(fi)) >= 0) {
1224 if (XFA_SKIPPING(fi->actions[i]))
1226 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1228 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1231 pi = rpmtsiFree(pi);
1233 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1234 NULL, ts->notifyData));
1236 /* ===============================================
1237 * Compute file disposition for each package in transaction set.
1239 rpmlog(RPMLOG_DEBUG, "computing file dispositions\n");
1240 ps = rpmtsProblems(ts);
1241 pi = rpmtsiInit(ts);
1242 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1243 dbiIndexSet * matches;
1247 (void) rpmdbCheckSignals();
1249 if ((fi = rpmtsiFi(pi)) == NULL)
1250 continue; /* XXX can't happen */
1253 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1254 ts->orderCount, NULL, ts->notifyData));
1256 if (fc == 0) continue;
1258 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1259 /* Extract file info for all files in this package from the database. */
1260 matches = xcalloc(fc, sizeof(*matches));
1261 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1263 rpmtsFreeLock(lock);
1264 return 1; /* XXX WTFO? */
1268 fi = rpmfiInit(fi, 0);
1269 while ((i = rpmfiNext(fi)) >= 0)
1270 numShared += dbiIndexSetCount(matches[i]);
1272 /* Build sorted file info list for this package. */
1273 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1275 fi = rpmfiInit(fi, 0);
1276 while ((i = rpmfiNext(fi)) >= 0) {
1278 * Take care not to mark files as replaced in packages that will
1279 * have been removed before we will get here.
1281 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1283 ro = dbiIndexRecordOffset(matches[i], j);
1285 qi = rpmtsiInit(ts);
1286 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1289 if (rpmteDBOffset(q) == ro)
1292 qi = rpmtsiFree(qi);
1294 shared->pkgFileNum = i;
1295 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1296 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1297 shared->isRemoved = (knownBad == ro);
1300 matches[i] = dbiFreeIndexSet(matches[i]);
1302 numShared = shared - sharedList;
1303 shared->otherPkg = -1;
1304 matches = _free(matches);
1306 /* Sort file info by other package index (otherPkg) */
1307 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1309 /* For all files from this package that are in the database ... */
1310 for (i = 0; i < numShared; i = nexti) {
1313 shared = sharedList + i;
1315 /* Find the end of the files in the other package. */
1316 for (nexti = i + 1; nexti < numShared; nexti++) {
1317 if (sharedList[nexti].otherPkg != shared->otherPkg)
1321 /* Is this file from a package being removed? */
1323 if (ts->removedPackages != NULL)
1324 for (j = 0; j < ts->numRemovedPackages; j++) {
1325 if (ts->removedPackages[j] != shared->otherPkg)
1331 /* Determine the fate of each file. */
1332 switch (rpmteType(p)) {
1334 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1335 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1339 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1346 /* Update disk space needs on each partition for this package. */
1347 handleOverlappedFiles(ts, p, fi);
1349 /* Check added package has sufficient space on each partition used. */
1350 switch (rpmteType(p)) {
1352 rpmtsCheckDSIProblems(ts, p);
1357 /* check for s-bit files to be removed */
1358 if (rpmteType(p) == TR_REMOVED) {
1359 fi = rpmfiInit(fi, 0);
1360 while ((i = rpmfiNext(fi)) >= 0) {
1362 if (XFA_SKIPPING(fi->actions[i]))
1364 (void) rpmfiSetFX(fi, i);
1365 mode = rpmfiFMode(fi);
1366 if (S_ISREG(mode) && (mode & 06000) != 0) {
1367 fi->mapflags |= CPIO_SBIT_CHECK;
1371 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1373 pi = rpmtsiFree(pi);
1376 if (rpmtsChrootDone(ts)) {
1377 const char * rootDir = rpmtsRootDir(ts);
1378 const char * currDir = rpmtsCurrDir(ts);
1379 if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
1381 (void) rpmtsSetChrootDone(ts, 0);
1382 if (currDir != NULL)
1383 xx = chdir(currDir);
1386 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1387 NULL, ts->notifyData));
1389 /* ===============================================
1390 * Free unused memory as soon as possible.
1392 pi = rpmtsiInit(ts);
1393 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1394 if ((fi = rpmtsiFi(pi)) == NULL)
1395 continue; /* XXX can't happen */
1396 if (rpmfiFC(fi) == 0)
1398 fi->fps = _free(fi->fps);
1400 pi = rpmtsiFree(pi);
1402 fpc = fpCacheFree(fpc);
1403 ts->ht = htFree(ts->ht);
1405 /* ===============================================
1406 * If unfiltered problems exist, free memory and return.
1408 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1409 || (rpmpsNumProblems(ts->probs) &&
1410 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
1413 rpmtsFreeLock(lock);
1414 return ts->orderCount;
1417 /* ===============================================
1418 * Install and remove packages.
1420 lastFailKey = (rpmalKey)-2; /* erased packages have -1 */
1421 pi = rpmtsiInit(ts);
1422 /* FIX: fi reload needs work */
1423 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1428 if ((fi = rpmtsiFi(pi)) == NULL)
1429 continue; /* XXX can't happen */
1431 psm = rpmpsmNew(ts, p, fi);
1432 async = (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1433 rpmpsmSetAsync(psm, async);
1435 switch (rpmteType(p)) {
1437 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1439 pkgKey = rpmteAddedKey(p);
1441 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
1442 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1445 /* FIX: rpmte not opaque */
1447 /* FIX: notify annotations */
1448 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1449 rpmteKey(p), ts->notifyData);
1450 if (rpmteFd(p) != NULL) {
1451 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1452 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1455 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1456 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1457 rpmteNEVR(p), &p->h);
1458 vsflags = rpmtsSetVSFlags(ts, ovsflags);
1462 /* FIX: notify annotations */
1463 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1465 rpmteKey(p), ts->notifyData);
1469 case RPMRC_NOTTRUSTED:
1474 if (rpmteFd(p) != NULL) gotfd = 1;
1478 if (rpmteFd(p) != NULL) {
1480 * XXX Sludge necessary to tranfer existing fstates/actions
1481 * XXX around a recreated file info set.
1483 rpmpsmSetFI(psm, NULL);
1485 char * fstates = fi->fstates;
1486 rpmFileAction * actions = fi->actions;
1487 sharedFileInfo replaced = fi->replaced;
1488 int mapflags = fi->mapflags;
1492 if (replaced != NULL) {
1493 for (; replaced->otherPkg; replaced++) {
1496 if (numShared > 0) {
1497 replaced = xcalloc(numShared + 1,
1498 sizeof(*fi->replaced));
1499 memcpy(replaced, fi->replaced,
1500 sizeof(*fi->replaced) * (numShared + 1));
1506 fi->replaced = NULL;
1507 /* FIX: fi->actions is NULL */
1510 savep = rpmtsSetRelocateElement(ts, p);
1511 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1512 (void) rpmtsSetRelocateElement(ts, savep);
1514 if (fi != NULL) { /* XXX can't happen */
1516 fi->fstates = _free(fi->fstates);
1517 fi->fstates = fstates;
1518 fi->actions = _free(fi->actions);
1519 fi->actions = actions;
1520 if (replaced != NULL)
1521 fi->replaced = replaced;
1522 if (mapflags & CPIO_SBIT_CHECK)
1523 fi->mapflags |= CPIO_SBIT_CHECK;
1527 rpmpsmSetFI(psm, p->fi);
1529 /* FIX: psm->fi may be NULL */
1530 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1532 lastFailKey = pkgKey;
1537 lastFailKey = pkgKey;
1542 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1543 rpmteKey(p), ts->notifyData);
1547 p->h = headerFree(p->h);
1549 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1554 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1556 rpmlog(RPMLOG_DEBUG, "========== --- %s %s-%s 0x%x\n",
1557 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
1560 * XXX This has always been a hack, now mostly broken.
1561 * If install failed, then we shouldn't erase.
1563 if (rpmteDependsOnKey(p) != lastFailKey) {
1564 if (rpmpsmStage(psm, PSM_PKGERASE)) {
1569 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1573 xx = rpmdbSync(rpmtsGetRdb(ts));
1575 /* FIX: psm->fi may be NULL */
1576 psm = rpmpsmFree(psm);
1579 /* FIX: p is almost opaque */
1580 p->fi = rpmfiFree(p->fi);
1584 pi = rpmtsiFree(pi);
1586 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
1587 rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n");
1588 runTransScripts(ts, RPMTAG_POSTTRANS);
1591 rpmtsFreeLock(lock);
1593 /* FIX: ts->flList may be NULL */