2 * \file lib/transaction.c
8 #include <rpmmacro.h> /* XXX for rpmExpand */
17 #define _RPMFI_INTERNAL
20 #define _RPMTE_INTERNAL
23 #define _RPMTS_INTERNAL
28 #include "legacy.h" /* XXX domd5 */
29 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
33 /*@access FD_t @*/ /* XXX compared with NULL */
34 /*@access Header @*/ /* XXX compared with NULL */
35 /*@access rpmps @*/ /* XXX need rpmProblemSetOK() */
36 /*@access dbiIndexSet @*/
52 static int archOkay(/*@null@*/ const char * pkgArch)
55 if (pkgArch == NULL) return 0;
56 return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
61 static int osOkay(/*@null@*/ const char * pkgOs)
64 if (pkgOs == NULL) return 0;
65 return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
70 static int sharedCmp(const void * one, const void * two)
73 sharedFileInfo a = (sharedFileInfo) one;
74 sharedFileInfo b = (sharedFileInfo) two;
76 if (a->otherPkg < b->otherPkg)
78 else if (a->otherPkg > b->otherPkg)
87 static fileAction decideFileFate(const rpmts ts,
88 const rpmfi ofi, rpmfi nfi)
89 /*@globals fileSystem, internalState @*/
90 /*@modifies nfi, fileSystem, internalState @*/
92 const char * fn = rpmfiFN(nfi);
93 int newFlags = rpmfiFFlags(nfi);
95 fileTypes dbWhat, newWhat, diskWhat;
97 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
101 * The file doesn't exist on the disk. Create it unless the new
102 * package has marked it as missingok, or allfiles is requested.
104 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES)
105 && (newFlags & RPMFILE_MISSINGOK))
107 rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
115 diskWhat = whatis((int_16)sb.st_mode);
116 dbWhat = whatis(rpmfiFMode(ofi));
117 newWhat = whatis(rpmfiFMode(nfi));
120 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
121 * them in older packages as well.
126 if (diskWhat != newWhat)
128 else if (newWhat != dbWhat && diskWhat != dbWhat)
130 else if (dbWhat != newWhat)
132 else if (dbWhat != LINK && dbWhat != REG)
136 * This order matters - we'd prefer to CREATE the file if at all
137 * possible in case something else (like the timestamp) has changed.
140 const unsigned char * omd5, * nmd5;
141 if (domd5(fn, buffer, 0, NULL))
142 return FA_CREATE; /* assume file has been removed */
143 omd5 = rpmfiMD5(ofi);
144 if (omd5 && !memcmp(omd5, buffer, 16))
145 return FA_CREATE; /* unmodified config file, replace. */
146 nmd5 = rpmfiMD5(nfi);
148 if (omd5 && nmd5 && !memcmp(omd5, nmd5, 16))
149 return FA_SKIP; /* identical file, don't bother. */
151 } else /* dbWhat == LINK */ {
152 const char * oFLink, * nFLink;
153 memset(buffer, 0, sizeof(buffer));
154 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
155 return FA_CREATE; /* assume file has been removed */
156 oFLink = rpmfiFLink(ofi);
157 if (oFLink && !strcmp(oFLink, buffer))
158 return FA_CREATE; /* unmodified config file, replace. */
159 nFLink = rpmfiFLink(nfi);
161 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
162 return FA_SKIP; /* identical file, don't bother. */
167 * The config file on the disk has been modified, but
168 * the ones in the two packages are different. It would
169 * be nice if RPM was smart enough to at least try and
170 * merge the difference ala CVS, but...
179 static int filecmp(rpmfi afi, rpmfi bfi)
182 fileTypes awhat = whatis(rpmfiFMode(afi));
183 fileTypes bwhat = whatis(rpmfiFMode(bfi));
185 if (awhat != bwhat) return 1;
188 const char * alink = rpmfiFLink(afi);
189 const char * blink = rpmfiFLink(bfi);
190 if (alink == blink) return 0;
191 if (alink == NULL) return 1;
192 if (blink == NULL) return -1;
193 return strcmp(alink, blink);
194 } else if (awhat == REG) {
195 const unsigned char * amd5 = rpmfiMD5(afi);
196 const unsigned char * bmd5 = rpmfiMD5(bfi);
197 if (amd5 == bmd5) return 0;
198 if (amd5 == NULL) return 1;
199 if (bmd5 == NULL) return -1;
200 return memcmp(amd5, bmd5, 16);
209 /* XXX only ts->{probs,rpmdb} modified */
211 static int handleInstInstalledFiles(const rpmts ts,
213 sharedFileInfo shared,
214 int sharedCount, int reportConflicts)
215 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
216 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
218 uint_32 tscolor = rpmtsColor(ts);
219 uint_32 otecolor, tecolor;
220 uint_32 oficolor, ficolor;
221 const char * altNEVR = NULL;
222 rpmfi otherFi = NULL;
227 { rpmdbMatchIterator mi;
231 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
232 &shared->otherPkg, sizeof(shared->otherPkg));
233 while ((h = rpmdbNextIterator(mi)) != NULL) {
234 altNEVR = hGetNEVR(h, NULL);
235 otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
238 mi = rpmdbFreeIterator(mi);
244 /* Compute package color. */
245 tecolor = rpmteColor(p);
248 /* Compute other pkg color. */
250 otherFi = rpmfiInit(otherFi, 0);
252 while (rpmfiNext(otherFi) >= 0)
253 otecolor |= rpmfiFColor(otherFi);
256 fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
258 ps = rpmtsProblems(ts);
259 for (i = 0; i < sharedCount; i++, shared++) {
260 int otherFileNum, fileNum;
263 otherFileNum = shared->otherFileNum;
264 (void) rpmfiSetFX(otherFi, otherFileNum);
265 oficolor = rpmfiFColor(otherFi);
268 fileNum = shared->pkgFileNum;
269 (void) rpmfiSetFX(fi, fileNum);
270 ficolor = rpmfiFColor(fi);
273 isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
276 /* XXX another tedious segfault, assume file state normal. */
277 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
281 if (XFA_SKIPPING(fi->actions[fileNum]))
284 if (filecmp(otherFi, fi)) {
285 /* Report conflicts only for packages/files of same color. */
286 if (tscolor == 0 || (tecolor == otecolor && ficolor == oficolor))
287 if (reportConflicts) {
288 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
289 rpmteNEVR(p), rpmteKey(p),
290 rpmfiDN(fi), rpmfiBN(fi),
295 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
296 if (!shared->isRemoved)
297 fi->replaced[numReplaced++] = *shared;
304 action = decideFileFate(ts, otherFi, fi);
305 fi->actions[fileNum] = action;
307 fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
311 altNEVR = _free(altNEVR);
312 otherFi = rpmfiFree(otherFi);
314 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
315 sizeof(*fi->replaced) * (numReplaced + 1));
316 fi->replaced[numReplaced].otherPkg = 0;
324 /* XXX only ts->rpmdb modified */
325 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
326 sharedFileInfo shared, int sharedCount)
327 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
328 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
332 const char * otherStates;
335 rpmdbMatchIterator mi;
337 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
338 &shared->otherPkg, sizeof(shared->otherPkg));
339 h = rpmdbNextIterator(mi);
341 mi = rpmdbFreeIterator(mi);
345 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
348 for (i = 0; i < sharedCount; i++, shared++) {
349 int otherFileNum, fileNum;
350 otherFileNum = shared->otherFileNum;
351 fileNum = shared->pkgFileNum;
353 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
356 fi->actions[fileNum] = FA_SKIP;
360 mi = rpmdbFreeIterator(mi);
365 #define ISROOT(_d) (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
370 static int fpsCompare (const void * one, const void * two)
373 const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
374 const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
375 int adnlen = strlen(a->entry->dirName);
376 int asnlen = (a->subDir ? strlen(a->subDir) : 0);
377 int abnlen = strlen(a->baseName);
378 int bdnlen = strlen(b->entry->dirName);
379 int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
380 int bbnlen = strlen(b->baseName);
381 char * afn, * bfn, * t;
384 if (adnlen == 1 && asnlen != 0) adnlen = 0;
385 if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
388 afn = t = alloca(adnlen+asnlen+abnlen+2);
389 if (adnlen) t = stpcpy(t, a->entry->dirName);
391 if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
392 if (abnlen) t = stpcpy(t, a->baseName);
393 if (afn[0] == '/' && afn[1] == '/') afn++;
395 bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
396 if (bdnlen) t = stpcpy(t, b->entry->dirName);
398 if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
399 if (bbnlen) t = stpcpy(t, b->baseName);
400 if (bfn[0] == '/' && bfn[1] == '/') bfn++;
403 rc = strcmp(afn, bfn);
406 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
411 fprintf(stderr, "\t%s/%s%s\trc %d\n",
412 ISROOT(b->entry->dirName),
413 (b->subDir ? b->subDir : ""),
423 static int _linear_fps_search = 0;
425 static int findFps(const struct fingerPrint_s * fiFps,
426 const struct fingerPrint_s * otherFps,
434 fprintf(stderr, "==> %s/%s%s\n",
435 ISROOT(fiFps->entry->dirName),
436 (fiFps->subDir ? fiFps->subDir : ""),
440 if (_linear_fps_search) {
443 for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
447 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
448 ISROOT(otherFps->entry->dirName),
449 (otherFps->subDir ? otherFps->subDir : ""),
453 /* If the addresses are the same, so are the values. */
454 if (fiFps == otherFps)
457 /* Otherwise, compare fingerprints by value. */
458 /*@-nullpass@*/ /* LCL: looks good to me */
459 if (FP_EQUAL((*fiFps), (*otherFps)))
464 if (otherFileNum == otherFc) {
467 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
468 ISROOT(fiFps->entry->dirName),
469 (fiFps->subDir ? fiFps->subDir : ""),
478 const struct fingerPrint_s * bingoFps;
481 bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
483 if (bingoFps == NULL) {
486 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
487 ISROOT(fiFps->entry->dirName),
488 (fiFps->subDir ? fiFps->subDir : ""),
494 /* If the addresses are the same, so are the values. */
495 /*@-nullpass@*/ /* LCL: looks good to me */
496 if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
499 fprintf(stderr, "*** BAD %s/%s%s\n",
500 ISROOT(bingoFps->entry->dirName),
501 (bingoFps->subDir ? bingoFps->subDir : ""),
507 otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
515 * Update disk space needs on each partition for this package's files.
517 /* XXX only ts->{probs,di} modified */
518 static void handleOverlappedFiles(const rpmts ts,
519 const rpmte p, rpmfi fi)
520 /*@globals fileSystem, internalState @*/
521 /*@modifies ts, fi, fileSystem, internalState @*/
523 uint_32 fixupSize = 0;
528 ps = rpmtsProblems(ts);
529 fi = rpmfiInit(fi, 0);
531 while ((i = rpmfiNext(fi)) >= 0) {
532 struct fingerPrint_s * fiFps;
533 int otherPkgNum, otherFileNum;
540 if (XFA_SKIPPING(fi->actions[i]))
545 FFlags = rpmfiFFlags(fi);
546 FMode = rpmfiFMode(fi);
551 * Retrieve all records that apply to this file. Note that the
552 * file info records were built in the same order as the packages
553 * will be installed and removed so the records for an overlapped
554 * files will be sorted in exactly the same order.
556 (void) htGetEntry(ts->ht, fiFps,
557 (const void ***) &recs, &numRecs, NULL);
560 * If this package is being added, look only at other packages
561 * being added -- removed packages dance to a different tune.
563 * If both this and the other package are being added, overlapped
564 * files must be identical (or marked as a conflict). The
565 * disposition of already installed config files leads to
566 * a small amount of extra complexity.
568 * If this package is being removed, then there are two cases that
569 * need to be worried about:
570 * If the other package is being added, then skip any overlapped files
571 * so that this package removal doesn't nuke the overlapped files
572 * that were just installed.
573 * If both this and the other package are being removed, then each
574 * file removal from preceding packages needs to be skipped so that
575 * the file removal occurs only on the last occurence of an overlapped
576 * file in the transaction set.
580 /* Locate this overlapped file in the set of added/removed packages. */
581 for (j = 0; j < numRecs && recs[j] != fi; j++)
584 /* Find what the previous disposition of this file was. */
585 otherFileNum = -1; /* keep gcc quiet */
587 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
588 struct fingerPrint_s * otherFps;
591 otherFi = recs[otherPkgNum];
593 /* Added packages need only look at other added packages. */
594 if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
595 /*@innercontinue@*/ continue;
597 otherFps = otherFi->fps;
598 otherFc = rpmfiFC(otherFi);
600 otherFileNum = findFps(fiFps, otherFps, otherFc);
601 (void) rpmfiSetFX(otherFi, otherFileNum);
603 /* XXX Happens iff fingerprint for incomplete package install. */
604 if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
605 /*@innerbreak@*/ break;
609 switch (rpmteType(p)) {
612 if (otherPkgNum < 0) {
613 /* XXX is this test still necessary? */
614 if (fi->actions[i] != FA_UNKNOWN)
615 /*@switchbreak@*/ break;
616 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
617 /* Here is a non-overlapped pre-existing config file. */
618 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
619 ? FA_ALTNAME : FA_BACKUP;
621 fi->actions[i] = FA_CREATE;
623 /*@switchbreak@*/ break;
626 assert(otherFi != NULL);
627 /* Mark added overlapped non-identical files as a conflict. */
628 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES)
629 && filecmp(otherFi, fi))
631 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
632 rpmteNEVR(p), rpmteKey(p),
634 rpmteNEVR(otherFi->te),
638 /* Try to get the disk accounting correct even if a conflict. */
639 fixupSize = rpmfiFSize(otherFi);
641 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
642 /* Here is an overlapped pre-existing config file. */
643 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
644 ? FA_ALTNAME : FA_SKIP;
646 fi->actions[i] = FA_CREATE;
648 } /*@switchbreak@*/ break;
651 if (otherPkgNum >= 0) {
652 assert(otherFi != NULL);
653 /* Here is an overlapped added file we don't want to nuke. */
654 if (otherFi->actions[otherFileNum] != FA_ERASE) {
655 /* On updates, don't remove files. */
656 fi->actions[i] = FA_SKIP;
657 /*@switchbreak@*/ break;
659 /* Here is an overlapped removed file: skip in previous. */
660 otherFi->actions[otherFileNum] = FA_SKIP;
662 if (XFA_SKIPPING(fi->actions[i]))
663 /*@switchbreak@*/ break;
664 if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
665 /*@switchbreak@*/ break;
666 if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
667 fi->actions[i] = FA_ERASE;
668 /*@switchbreak@*/ break;
671 /* Here is a pre-existing modified config file that needs saving. */
673 const unsigned char * MD5 = rpmfiMD5(fi);
674 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
675 fi->actions[i] = FA_BACKUP;
676 /*@switchbreak@*/ break;
679 fi->actions[i] = FA_ERASE;
680 /*@switchbreak@*/ break;
684 /* Update disk space info for a file. */
685 rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
686 fi->replacedSizes[i], fixupSize, fi->actions[i]);
693 * Ensure that current package is newer than installed package.
694 * @param ts transaction set
695 * @param p current transaction element
696 * @param h installed header
697 * @return 0 if not newer, 1 if okay
699 static int ensureOlder(rpmts ts,
700 const rpmte p, const Header h)
703 int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
710 if (p == NULL || h == NULL)
714 nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
718 if (rpmteE(p) != NULL) t = stpcpy( stpcpy(t, rpmteE(p)), ":");
719 if (rpmteV(p) != NULL) t = stpcpy(t, rpmteV(p));
721 if (rpmteR(p) != NULL) t = stpcpy(t, rpmteR(p));
724 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
725 rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
726 req = rpmdsFree(req);
729 rpmps ps = rpmtsProblems(ts);
730 const char * altNEVR = hGetNEVR(h, NULL);
731 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
732 rpmteNEVR(p), rpmteKey(p),
736 altNEVR = _free(altNEVR);
746 * Skip any files that do not match install policies.
747 * @param ts transaction set
748 * @param fi file info set
750 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
752 static void skipFiles(const rpmts ts, rpmfi fi)
753 /*@globals rpmGlobalMacroContext @*/
754 /*@modifies fi, rpmGlobalMacroContext @*/
756 uint_32 tscolor = rpmtsColor(ts);
758 int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
759 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
760 char ** netsharedPaths = NULL;
761 const char ** languages;
762 const char * dn, * bn;
763 int dnlen, bnlen, ix;
771 noDocs = rpmExpandNumeric("%{_excludedocs}");
773 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
775 if (tmpPath && *tmpPath != '%')
776 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
778 tmpPath = _free(tmpPath);
781 s = rpmExpand("%{_install_langs}", NULL);
783 if (!(s && *s != '%'))
786 languages = (const char **) splitString(s, strlen(s), ':');
792 /* Compute directory refcount, skip directory if now empty. */
794 drc = alloca(dc * sizeof(*drc));
795 memset(drc, 0, dc * sizeof(*drc));
796 dff = alloca(dc * sizeof(*dff));
797 memset(dff, 0, dc * sizeof(*dff));
799 fi = rpmfiInit(fi, 0);
800 if (fi != NULL) /* XXX lclint */
801 while ((i = rpmfiNext(fi)) >= 0)
811 continue; /* XXX can't happen */
815 /* Don't bother with skipped files */
816 if (XFA_SKIPPING(fi->actions[i])) {
817 drc[ix]--; dff[ix] = 1;
821 /* Ignore colored files not in our rainbow. */
822 ficolor = rpmfiFColor(fi);
823 if (tscolor && ficolor && !(tscolor & ficolor)) {
824 drc[ix]--; dff[ix] = 1;
825 fi->actions[i] = FA_SKIPCOLOR;
830 * Skip net shared paths.
831 * Net shared paths are not relative to the current root (though
832 * they do need to take package relocations into account).
834 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
839 if (strncmp(dn, *nsp, len))
840 /*@innercontinue@*/ continue;
841 /* Only directories or complete file paths can be net shared */
842 if (!(dn[len] == '/' || dn[len] == '\0'))
843 /*@innercontinue@*/ continue;
845 if (len < (dnlen + bnlen))
846 /*@innercontinue@*/ continue;
847 if (strncmp(dn, *nsp, dnlen))
848 /*@innercontinue@*/ continue;
849 if (strncmp(bn, (*nsp) + dnlen, bnlen))
850 /*@innercontinue@*/ continue;
852 /* Only directories or complete file paths can be net shared */
853 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
854 /*@innercontinue@*/ continue;
857 /*@innerbreak@*/ break;
861 drc[ix]--; dff[ix] = 1;
862 fi->actions[i] = FA_SKIPNETSHARED;
867 * Skip i18n language specific files.
869 if (fi->flangs && languages && *fi->flangs[i]) {
870 const char **lang, *l, *le;
871 for (lang = languages; *lang != NULL; lang++) {
872 if (!strcmp(*lang, "all"))
873 /*@innerbreak@*/ break;
874 for (l = fi->flangs[i]; *l != '\0'; l = le) {
875 for (le = l; *le != '\0' && *le != '|'; le++)
877 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
878 /*@innerbreak@*/ break;
879 if (*le == '|') le++; /* skip over | */
882 /*@innerbreak@*/ break;
885 drc[ix]--; dff[ix] = 1;
886 fi->actions[i] = FA_SKIPNSTATE;
892 * Skip config files if requested.
894 if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
895 drc[ix]--; dff[ix] = 1;
896 fi->actions[i] = FA_SKIPNSTATE;
901 * Skip documentation if requested.
903 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
904 drc[ix]--; dff[ix] = 1;
905 fi->actions[i] = FA_SKIPNSTATE;
910 /* Skip (now empty) directories that had skipped files. */
912 if (fi != NULL) /* XXX can't happen */
913 for (j = 0; j < dc; j++)
915 if ((fi = rpmfiInitD(fi)) != NULL)
916 while (j = rpmfiNextD(fi) >= 0)
920 if (drc[j]) continue; /* dir still has files. */
921 if (!dff[j]) continue; /* dir was not emptied here. */
923 /* Find parent directory and basename. */
924 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
925 bn = dn + dnlen; bnlen = 0;
926 while (bn > dn && bn[-1] != '/') {
932 /* If explicitly included in the package, skip the directory. */
933 fi = rpmfiInit(fi, 0);
934 if (fi != NULL) /* XXX lclint */
935 while ((i = rpmfiNext(fi)) >= 0) {
936 const char * fdn, * fbn;
939 if (XFA_SKIPPING(fi->actions[i]))
940 /*@innercontinue@*/ continue;
942 fFMode = rpmfiFMode(fi);
944 if (whatis(fFMode) != XDIR)
945 /*@innercontinue@*/ continue;
947 if (strlen(fdn) != dnlen)
948 /*@innercontinue@*/ continue;
949 if (strncmp(fdn, dn, dnlen))
950 /*@innercontinue@*/ continue;
952 if (strlen(fbn) != bnlen)
953 /*@innercontinue@*/ continue;
954 if (strncmp(fbn, bn, bnlen))
955 /*@innercontinue@*/ continue;
956 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
957 fi->actions[i] = FA_SKIPNSTATE;
958 /*@innerbreak@*/ break;
962 if (netsharedPaths) freeSplitString(netsharedPaths);
963 #ifdef DYING /* XXX freeFi will deal with this later. */
964 fi->flangs = _free(fi->flangs);
966 if (languages) freeSplitString((char **)languages);
972 * Return transaction element's file info.
973 * @todo Take a rpmfi refcount here.
974 * @param tsi transaction element iterator
975 * @return transaction element file info
978 rpmfi rpmtsiFi(const rpmtsi tsi)
983 if (tsi != NULL && tsi->ocsave != -1) {
984 /*@-type -abstract@*/ /* FIX: rpmte not opaque */
985 rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
987 if (te != NULL && (fi = te->fi) != NULL)
990 /*@=type =abstract@*/
992 /*@-compdef -refcounttrans -usereleased @*/
994 /*@=compdef =refcounttrans =usereleased @*/
997 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
999 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
1001 uint_32 tscolor = rpmtsColor(ts);
1004 int totalFileCount = 0;
1006 sharedFileInfo shared, sharedList;
1010 fingerPrintCache fpc;
1019 /* XXX programmer error segfault avoidance. */
1020 if (rpmtsNElements(ts) <= 0)
1023 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
1024 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1025 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1026 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1028 /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
1029 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1030 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1032 ts->probs = rpmpsFree(ts->probs);
1033 ts->probs = rpmpsCreate();
1035 /* XXX Make sure the database is open RDWR for package install/erase. */
1036 { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1037 ? O_RDONLY : (O_RDWR|O_CREAT);
1039 /* Open database RDWR for installing packages. */
1040 if (rpmtsOpenDB(ts, dbmode))
1041 return -1; /* XXX W2DO? */
1044 ts->ignoreSet = ignoreSet;
1045 { const char * currDir = currentDirectory();
1046 rpmtsSetCurrDir(ts, currDir);
1047 currDir = _free(currDir);
1050 (void) rpmtsSetChrootDone(ts, 0);
1052 { int_32 tid = (int_32) time(NULL);
1053 (void) rpmtsSetTid(ts, tid);
1056 /* Get available space on mounted file systems. */
1057 xx = rpmtsInitDSI(ts);
1059 /* ===============================================
1060 * For packages being installed:
1061 * - verify package arch/os.
1062 * - verify package epoch:version-release is newer.
1064 * For packages being removed:
1068 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
1069 ps = rpmtsProblems(ts);
1070 /* The ordering doesn't matter here */
1071 pi = rpmtsiInit(ts);
1072 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1073 rpmdbMatchIterator mi;
1076 if ((fi = rpmtsiFi(pi)) == NULL)
1077 continue; /* XXX can't happen */
1080 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
1081 if (!archOkay(rpmteA(p)))
1082 rpmpsAppend(ps, RPMPROB_BADARCH,
1083 rpmteNEVR(p), rpmteKey(p),
1087 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1088 if (!osOkay(rpmteO(p)))
1089 rpmpsAppend(ps, RPMPROB_BADOS,
1090 rpmteNEVR(p), rpmteKey(p),
1094 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1096 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1097 while ((h = rpmdbNextIterator(mi)) != NULL)
1098 xx = ensureOlder(ts, p, h);
1099 mi = rpmdbFreeIterator(mi);
1102 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1103 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1104 xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1106 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1108 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1111 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1113 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1117 while (rpmdbNextIterator(mi) != NULL) {
1118 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1119 rpmteNEVR(p), rpmteKey(p),
1122 /*@innerbreak@*/ break;
1124 mi = rpmdbFreeIterator(mi);
1127 /* Count no. of files (if any). */
1128 totalFileCount += fc;
1131 pi = rpmtsiFree(pi);
1134 /* The ordering doesn't matter here */
1135 pi = rpmtsiInit(ts);
1136 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1139 if ((fi = rpmtsiFi(pi)) == NULL)
1140 continue; /* XXX can't happen */
1143 totalFileCount += fc;
1145 pi = rpmtsiFree(pi);
1147 /* ===============================================
1148 * Initialize transaction element file info for package:
1152 * FIXME?: we'd be better off assembling one very large file list and
1153 * calling fpLookupList only once. I'm not sure that the speedup is
1154 * worth the trouble though.
1156 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
1157 numAdded = numRemoved = 0;
1158 pi = rpmtsiInit(ts);
1159 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1162 if ((fi = rpmtsiFi(pi)) == NULL)
1163 continue; /* XXX can't happen */
1167 switch (rpmteType(p)) {
1171 /* Skip netshared paths, not our i18n files, and excluded docs */
1174 /*@switchbreak@*/ break;
1177 fi->record = rpmteDBOffset(p);
1178 /*@switchbreak@*/ break;
1182 fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1184 pi = rpmtsiFree(pi);
1186 if (!rpmtsChrootDone(ts)) {
1187 const char * rootDir = rpmtsRootDir(ts);
1189 /*@-superuser -noeffect @*/
1190 if (rootDir != NULL)
1191 xx = chroot(rootDir);
1192 /*@=superuser =noeffect @*/
1193 (void) rpmtsSetChrootDone(ts, 1);
1196 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1197 fpc = fpCacheCreate(totalFileCount);
1199 /* ===============================================
1200 * Add fingerprint for each file not skipped.
1202 pi = rpmtsiInit(ts);
1203 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1206 (void) rpmdbCheckSignals();
1208 if ((fi = rpmtsiFi(pi)) == NULL)
1209 continue; /* XXX can't happen */
1212 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1214 fi = rpmfiInit(fi, 0);
1215 if (fi != NULL) /* XXX lclint */
1216 while ((i = rpmfiNext(fi)) >= 0) {
1217 if (XFA_SKIPPING(fi->actions[i]))
1218 /*@innercontinue@*/ continue;
1219 /*@-dependenttrans@*/
1220 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1221 /*@=dependenttrans@*/
1225 pi = rpmtsiFree(pi);
1227 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1228 NULL, ts->notifyData));
1230 /* ===============================================
1231 * Compute file disposition for each package in transaction set.
1233 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1234 ps = rpmtsProblems(ts);
1235 pi = rpmtsiInit(ts);
1236 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1237 dbiIndexSet * matches;
1241 (void) rpmdbCheckSignals();
1243 if ((fi = rpmtsiFi(pi)) == NULL)
1244 continue; /* XXX can't happen */
1247 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1248 ts->orderCount, NULL, ts->notifyData));
1250 if (fc == 0) continue;
1252 /* Extract file info for all files in this package from the database. */
1253 matches = xcalloc(fc, sizeof(*matches));
1254 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1256 return 1; /* XXX WTFO? */
1260 fi = rpmfiInit(fi, 0);
1261 while ((i = rpmfiNext(fi)) >= 0)
1262 numShared += dbiIndexSetCount(matches[i]);
1264 /* Build sorted file info list for this package. */
1265 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1267 fi = rpmfiInit(fi, 0);
1268 while ((i = rpmfiNext(fi)) >= 0) {
1270 * Take care not to mark files as replaced in packages that will
1271 * have been removed before we will get here.
1273 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1275 ro = dbiIndexRecordOffset(matches[i], j);
1277 qi = rpmtsiInit(ts);
1278 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1280 /*@innerbreak@*/ break;
1281 if (rpmteDBOffset(q) == ro)
1284 qi = rpmtsiFree(qi);
1286 shared->pkgFileNum = i;
1287 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1288 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1289 shared->isRemoved = (knownBad == ro);
1292 matches[i] = dbiFreeIndexSet(matches[i]);
1294 numShared = shared - sharedList;
1295 shared->otherPkg = -1;
1296 matches = _free(matches);
1298 /* Sort file info by other package index (otherPkg) */
1299 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1301 /* For all files from this package that are in the database ... */
1303 for (i = 0; i < numShared; i = nexti) {
1306 shared = sharedList + i;
1308 /* Find the end of the files in the other package. */
1309 for (nexti = i + 1; nexti < numShared; nexti++) {
1310 if (sharedList[nexti].otherPkg != shared->otherPkg)
1311 /*@innerbreak@*/ break;
1314 /* Is this file from a package being removed? */
1316 if (ts->removedPackages != NULL)
1317 for (j = 0; j < ts->numRemovedPackages; j++) {
1318 if (ts->removedPackages[j] != shared->otherPkg)
1319 /*@innercontinue@*/ continue;
1321 /*@innerbreak@*/ break;
1324 /* Determine the fate of each file. */
1325 switch (rpmteType(p)) {
1327 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1328 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1329 /*@switchbreak@*/ break;
1332 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1333 /*@switchbreak@*/ break;
1340 /* Update disk space needs on each partition for this package. */
1341 handleOverlappedFiles(ts, p, fi);
1343 /* Check added package has sufficient space on each partition used. */
1344 switch (rpmteType(p)) {
1346 rpmtsCheckDSIProblems(ts, p);
1347 /*@switchbreak@*/ break;
1349 /*@switchbreak@*/ break;
1352 pi = rpmtsiFree(pi);
1355 if (rpmtsChrootDone(ts)) {
1356 const char * currDir = rpmtsCurrDir(ts);
1357 /*@-superuser -noeffect @*/
1359 /*@=superuser =noeffect @*/
1360 (void) rpmtsSetChrootDone(ts, 0);
1361 if (currDir != NULL)
1362 xx = chdir(currDir);
1365 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1366 NULL, ts->notifyData));
1368 /* ===============================================
1369 * Free unused memory as soon as possible.
1371 pi = rpmtsiInit(ts);
1372 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1373 if ((fi = rpmtsiFi(pi)) == NULL)
1374 continue; /* XXX can't happen */
1375 if (rpmfiFC(fi) == 0)
1377 fi->fps = _free(fi->fps);
1379 pi = rpmtsiFree(pi);
1381 fpc = fpCacheFree(fpc);
1382 ts->ht = htFree(ts->ht);
1384 /* ===============================================
1385 * If unfiltered problems exist, free memory and return.
1387 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1388 || (ts->probs->numProblems &&
1389 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1392 return ts->orderCount;
1395 /* ===============================================
1396 * Save removed files before erasing.
1398 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1401 pi = rpmtsiInit(ts);
1402 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1404 (void) rpmdbCheckSignals();
1406 if ((fi = rpmtsiFi(pi)) == NULL)
1407 continue; /* XXX can't happen */
1408 switch (rpmteType(p)) {
1410 /*@switchbreak@*/ break;
1412 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1413 /*@switchbreak@*/ break;
1415 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1416 7, numRemoved, NULL, ts->notifyData));
1418 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1419 numRemoved, NULL, ts->notifyData));
1422 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1423 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1424 fi->mapflags |= CPIO_MAP_ADDDOT;
1425 fi->mapflags |= CPIO_ALL_HARDLINKS;
1426 psm = rpmpsmNew(ts, p, fi);
1427 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1428 psm = rpmpsmFree(psm);
1429 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1430 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1431 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1433 /*@switchbreak@*/ break;
1436 pi = rpmtsiFree(pi);
1438 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1439 NULL, ts->notifyData));
1443 /* ===============================================
1444 * Install and remove packages.
1446 lastFailKey = (alKey)-2; /* erased packages have -1 */
1447 pi = rpmtsiInit(ts);
1448 /*@-branchstate@*/ /* FIX: fi reload needs work */
1449 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1453 (void) rpmdbCheckSignals();
1456 if ((fi = rpmtsiFi(pi)) == NULL)
1457 continue; /* XXX can't happen */
1459 psm = rpmpsmNew(ts, p, fi);
1460 psm->unorderedSuccessor =
1461 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1463 switch (rpmteType(p)) {
1466 pkgKey = rpmteAddedKey(p);
1468 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1470 /*@-type@*/ /* FIX: rpmte not opaque */
1472 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1473 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1474 rpmteKey(p), ts->notifyData);
1475 /*@=noeffectuncon@*/
1476 if (rpmteFd(p) != NULL) {
1477 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1478 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1481 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1482 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1483 rpmteNEVR(p), &p->h);
1484 vsflags = rpmtsSetVSFlags(ts, ovsflags);
1488 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1489 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1491 rpmteKey(p), ts->notifyData);
1492 /*@=noeffectuncon@*/
1495 /*@innerbreak@*/ break;
1496 case RPMRC_NOTTRUSTED:
1499 /*@innerbreak@*/ break;
1501 if (rpmteFd(p) != NULL) gotfd = 1;
1506 if (rpmteFd(p) != NULL) {
1508 * XXX Sludge necessary to tranfer existing fstates/actions
1509 * XXX around a recreated file info set.
1511 psm->fi = rpmfiFree(psm->fi);
1513 char * fstates = fi->fstates;
1514 fileAction * actions = fi->actions;
1521 savep = rpmtsSetRelocateElement(ts, p);
1522 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1523 (void) rpmtsSetRelocateElement(ts, savep);
1525 if (fi != NULL) { /* XXX can't happen */
1527 fi->fstates = _free(fi->fstates);
1528 fi->fstates = fstates;
1529 fi->actions = _free(fi->actions);
1530 fi->actions = actions;
1534 psm->fi = rpmfiLink(p->fi, NULL);
1536 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1537 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1539 lastFailKey = pkgKey;
1544 lastFailKey = pkgKey;
1548 /*@-noeffectuncon @*/ /* FIX: check rc */
1549 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1550 rpmteKey(p), ts->notifyData);
1551 /*@=noeffectuncon @*/
1557 p->h = headerFree(p->h);
1559 /*@switchbreak@*/ break;
1561 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1563 * XXX This has always been a hack, now mostly broken.
1564 * If install failed, then we shouldn't erase.
1566 if (rpmteDependsOnKey(p) != lastFailKey) {
1567 if (rpmpsmStage(psm, PSM_PKGERASE))
1570 /*@switchbreak@*/ break;
1572 xx = rpmdbSync(rpmtsGetRdb(ts));
1574 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1575 psm = rpmpsmFree(psm);
1578 /*@-type@*/ /* FIX: p is almost opaque */
1579 p->fi = rpmfiFree(p->fi);
1584 pi = rpmtsiFree(pi);
1586 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */