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 Header @*/ /* XXX ts->notify arg1 is void ptr */
34 /*@access rpmps @*/ /* XXX need rpmProblemSetOK() */
35 /*@access dbiIndexSet @*/
50 static int archOkay(/*@null@*/ const char * pkgArch)
53 if (pkgArch == NULL) return 0;
54 return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
59 static int osOkay(/*@null@*/ const char * pkgOs)
62 if (pkgOs == NULL) return 0;
63 return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
68 static int sharedCmp(const void * one, const void * two)
71 sharedFileInfo a = (sharedFileInfo) one;
72 sharedFileInfo b = (sharedFileInfo) two;
74 if (a->otherPkg < b->otherPkg)
76 else if (a->otherPkg > b->otherPkg)
85 static fileAction decideFileFate(const rpmts ts,
86 const rpmfi ofi, rpmfi nfi)
87 /*@globals fileSystem, internalState @*/
88 /*@modifies nfi, fileSystem, internalState @*/
90 const char * fn = rpmfiFN(nfi);
91 int newFlags = rpmfiFFlags(nfi);
93 fileTypes dbWhat, newWhat, diskWhat;
95 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
99 * The file doesn't exist on the disk. Create it unless the new
100 * package has marked it as missingok, or allfiles is requested.
102 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES)
103 && (newFlags & RPMFILE_MISSINGOK))
105 rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
113 diskWhat = whatis((int_16)sb.st_mode);
114 dbWhat = whatis(rpmfiFMode(ofi));
115 newWhat = whatis(rpmfiFMode(nfi));
118 * RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
119 * them in older packages as well.
124 if (diskWhat != newWhat)
126 else if (newWhat != dbWhat && diskWhat != dbWhat)
128 else if (dbWhat != newWhat)
130 else if (dbWhat != LINK && dbWhat != REG)
134 * This order matters - we'd prefer to CREATE the file if at all
135 * possible in case something else (like the timestamp) has changed.
138 const unsigned char * omd5, * nmd5;
139 if (domd5(fn, buffer, 0, NULL))
140 return FA_CREATE; /* assume file has been removed */
141 omd5 = rpmfiMD5(ofi);
142 if (omd5 && !memcmp(omd5, buffer, 16))
143 return FA_CREATE; /* unmodified config file, replace. */
144 nmd5 = rpmfiMD5(nfi);
146 if (omd5 && nmd5 && !memcmp(omd5, nmd5, 16))
147 return FA_SKIP; /* identical file, don't bother. */
149 } else /* dbWhat == LINK */ {
150 const char * oFLink, * nFLink;
151 memset(buffer, 0, sizeof(buffer));
152 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
153 return FA_CREATE; /* assume file has been removed */
154 oFLink = rpmfiFLink(ofi);
155 if (oFLink && !strcmp(oFLink, buffer))
156 return FA_CREATE; /* unmodified config file, replace. */
157 nFLink = rpmfiFLink(nfi);
159 if (oFLink && nFLink && !strcmp(oFLink, nFLink))
160 return FA_SKIP; /* identical file, don't bother. */
165 * The config file on the disk has been modified, but
166 * the ones in the two packages are different. It would
167 * be nice if RPM was smart enough to at least try and
168 * merge the difference ala CVS, but...
177 static int filecmp(rpmfi afi, rpmfi bfi)
180 fileTypes awhat = whatis(rpmfiFMode(afi));
181 fileTypes bwhat = whatis(rpmfiFMode(bfi));
183 if (awhat != bwhat) return 1;
186 const char * alink = rpmfiFLink(afi);
187 const char * blink = rpmfiFLink(bfi);
188 if (alink == blink) return 0;
189 if (alink == NULL) return 1;
190 if (blink == NULL) return -1;
191 return strcmp(alink, blink);
192 } else if (awhat == REG) {
193 const unsigned char * amd5 = rpmfiMD5(afi);
194 const unsigned char * bmd5 = rpmfiMD5(bfi);
195 if (amd5 == bmd5) return 0;
196 if (amd5 == NULL) return 1;
197 if (bmd5 == NULL) return -1;
198 return memcmp(amd5, bmd5, 16);
207 /* XXX only ts->{probs,rpmdb} modified */
209 static int handleInstInstalledFiles(const rpmts ts,
211 sharedFileInfo shared,
212 int sharedCount, int reportConflicts)
213 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
214 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
216 uint_32 tscolor = rpmtsColor(ts);
217 uint_32 otecolor, tecolor;
218 uint_32 oficolor, ficolor;
219 const char * altNEVR = NULL;
220 rpmfi otherFi = NULL;
225 { rpmdbMatchIterator mi;
229 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
230 &shared->otherPkg, sizeof(shared->otherPkg));
231 while ((h = rpmdbNextIterator(mi)) != NULL) {
232 altNEVR = hGetNEVR(h, NULL);
233 otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
236 mi = rpmdbFreeIterator(mi);
239 /* Compute package color. */
240 tecolor = rpmteColor(p);
243 /* Compute other pkg color. */
245 otherFi = rpmfiInit(otherFi, 0);
247 while (rpmfiNext(otherFi) >= 0)
248 otecolor |= rpmfiFColor(otherFi);
254 fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
256 ps = rpmtsProblems(ts);
257 for (i = 0; i < sharedCount; i++, shared++) {
258 int otherFileNum, fileNum;
261 otherFileNum = shared->otherFileNum;
262 (void) rpmfiSetFX(otherFi, otherFileNum);
263 oficolor = rpmfiFColor(otherFi);
266 fileNum = shared->pkgFileNum;
267 (void) rpmfiSetFX(fi, fileNum);
268 ficolor = rpmfiFColor(fi);
271 isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
274 /* XXX another tedious segfault, assume file state normal. */
275 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
279 if (XFA_SKIPPING(fi->actions[fileNum]))
282 if (filecmp(otherFi, fi)) {
283 /* Report conflicts only for packages/files of same color. */
284 if (tscolor == 0 || (tecolor == otecolor && ficolor == oficolor))
285 if (reportConflicts) {
286 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
287 rpmteNEVR(p), rpmteKey(p),
288 rpmfiDN(fi), rpmfiBN(fi),
293 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
294 if (!shared->isRemoved)
295 fi->replaced[numReplaced++] = *shared;
302 action = decideFileFate(ts, otherFi, fi);
303 fi->actions[fileNum] = action;
305 fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
309 altNEVR = _free(altNEVR);
310 otherFi = rpmfiFree(otherFi);
312 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
313 sizeof(*fi->replaced) * (numReplaced + 1));
314 fi->replaced[numReplaced].otherPkg = 0;
322 /* XXX only ts->rpmdb modified */
323 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
324 sharedFileInfo shared, int sharedCount)
325 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
326 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
330 const char * otherStates;
333 rpmdbMatchIterator mi;
335 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
336 &shared->otherPkg, sizeof(shared->otherPkg));
337 h = rpmdbNextIterator(mi);
339 mi = rpmdbFreeIterator(mi);
343 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
346 for (i = 0; i < sharedCount; i++, shared++) {
347 int otherFileNum, fileNum;
348 otherFileNum = shared->otherFileNum;
349 fileNum = shared->pkgFileNum;
351 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
354 fi->actions[fileNum] = FA_SKIP;
358 mi = rpmdbFreeIterator(mi);
363 #define ISROOT(_d) (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
368 static int fpsCompare (const void * one, const void * two)
371 const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
372 const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
373 int adnlen = strlen(a->entry->dirName);
374 int asnlen = (a->subDir ? strlen(a->subDir) : 0);
375 int abnlen = strlen(a->baseName);
376 int bdnlen = strlen(b->entry->dirName);
377 int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
378 int bbnlen = strlen(b->baseName);
379 char * afn, * bfn, * t;
382 if (adnlen == 1 && asnlen != 0) adnlen = 0;
383 if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
386 afn = t = alloca(adnlen+asnlen+abnlen+2);
387 if (adnlen) t = stpcpy(t, a->entry->dirName);
389 if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
390 if (abnlen) t = stpcpy(t, a->baseName);
391 if (afn[0] == '/' && afn[1] == '/') afn++;
393 bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
394 if (bdnlen) t = stpcpy(t, b->entry->dirName);
396 if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
397 if (bbnlen) t = stpcpy(t, b->baseName);
398 if (bfn[0] == '/' && bfn[1] == '/') bfn++;
401 rc = strcmp(afn, bfn);
404 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
409 fprintf(stderr, "\t%s/%s%s\trc %d\n",
410 ISROOT(b->entry->dirName),
411 (b->subDir ? b->subDir : ""),
421 static int _linear_fps_search = 0;
423 static int findFps(const struct fingerPrint_s * fiFps,
424 const struct fingerPrint_s * otherFps,
432 fprintf(stderr, "==> %s/%s%s\n",
433 ISROOT(fiFps->entry->dirName),
434 (fiFps->subDir ? fiFps->subDir : ""),
438 if (_linear_fps_search) {
441 for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
445 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
446 ISROOT(otherFps->entry->dirName),
447 (otherFps->subDir ? otherFps->subDir : ""),
451 /* If the addresses are the same, so are the values. */
452 if (fiFps == otherFps)
455 /* Otherwise, compare fingerprints by value. */
456 /*@-nullpass@*/ /* LCL: looks good to me */
457 if (FP_EQUAL((*fiFps), (*otherFps)))
462 if (otherFileNum == otherFc) {
465 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
466 ISROOT(fiFps->entry->dirName),
467 (fiFps->subDir ? fiFps->subDir : ""),
476 const struct fingerPrint_s * bingoFps;
479 bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
481 if (bingoFps == NULL) {
484 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
485 ISROOT(fiFps->entry->dirName),
486 (fiFps->subDir ? fiFps->subDir : ""),
492 /* If the addresses are the same, so are the values. */
493 /*@-nullpass@*/ /* LCL: looks good to me */
494 if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
497 fprintf(stderr, "*** BAD %s/%s%s\n",
498 ISROOT(bingoFps->entry->dirName),
499 (bingoFps->subDir ? bingoFps->subDir : ""),
505 otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
513 * Update disk space needs on each partition for this package's files.
515 /* XXX only ts->{probs,di} modified */
516 static void handleOverlappedFiles(const rpmts ts,
517 const rpmte p, rpmfi fi)
518 /*@globals fileSystem, internalState @*/
519 /*@modifies ts, fi, fileSystem, internalState @*/
521 uint_32 fixupSize = 0;
526 ps = rpmtsProblems(ts);
527 fi = rpmfiInit(fi, 0);
529 while ((i = rpmfiNext(fi)) >= 0) {
530 struct fingerPrint_s * fiFps;
531 int otherPkgNum, otherFileNum;
538 if (XFA_SKIPPING(fi->actions[i]))
543 FFlags = rpmfiFFlags(fi);
544 FMode = rpmfiFMode(fi);
549 * Retrieve all records that apply to this file. Note that the
550 * file info records were built in the same order as the packages
551 * will be installed and removed so the records for an overlapped
552 * files will be sorted in exactly the same order.
554 (void) htGetEntry(ts->ht, fiFps,
555 (const void ***) &recs, &numRecs, NULL);
558 * If this package is being added, look only at other packages
559 * being added -- removed packages dance to a different tune.
561 * If both this and the other package are being added, overlapped
562 * files must be identical (or marked as a conflict). The
563 * disposition of already installed config files leads to
564 * a small amount of extra complexity.
566 * If this package is being removed, then there are two cases that
567 * need to be worried about:
568 * If the other package is being added, then skip any overlapped files
569 * so that this package removal doesn't nuke the overlapped files
570 * that were just installed.
571 * If both this and the other package are being removed, then each
572 * file removal from preceding packages needs to be skipped so that
573 * the file removal occurs only on the last occurence of an overlapped
574 * file in the transaction set.
578 /* Locate this overlapped file in the set of added/removed packages. */
579 for (j = 0; j < numRecs && recs[j] != fi; j++)
582 /* Find what the previous disposition of this file was. */
583 otherFileNum = -1; /* keep gcc quiet */
585 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
586 struct fingerPrint_s * otherFps;
589 otherFi = recs[otherPkgNum];
591 /* Added packages need only look at other added packages. */
592 if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
593 /*@innercontinue@*/ continue;
595 otherFps = otherFi->fps;
596 otherFc = rpmfiFC(otherFi);
598 otherFileNum = findFps(fiFps, otherFps, otherFc);
599 (void) rpmfiSetFX(otherFi, otherFileNum);
601 /* XXX Happens iff fingerprint for incomplete package install. */
602 if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
603 /*@innerbreak@*/ break;
607 switch (rpmteType(p)) {
610 if (otherPkgNum < 0) {
611 /* XXX is this test still necessary? */
612 if (fi->actions[i] != FA_UNKNOWN)
613 /*@switchbreak@*/ break;
614 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
615 /* Here is a non-overlapped pre-existing config file. */
616 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
617 ? FA_ALTNAME : FA_BACKUP;
619 fi->actions[i] = FA_CREATE;
621 /*@switchbreak@*/ break;
624 assert(otherFi != NULL);
625 /* Mark added overlapped non-identical files as a conflict. */
626 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES)
627 && filecmp(otherFi, fi))
629 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
630 rpmteNEVR(p), rpmteKey(p),
632 rpmteNEVR(otherFi->te),
636 /* Try to get the disk accounting correct even if a conflict. */
637 fixupSize = rpmfiFSize(otherFi);
639 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
640 /* Here is an overlapped pre-existing config file. */
641 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
642 ? FA_ALTNAME : FA_SKIP;
644 fi->actions[i] = FA_CREATE;
646 } /*@switchbreak@*/ break;
649 if (otherPkgNum >= 0) {
650 assert(otherFi != NULL);
651 /* Here is an overlapped added file we don't want to nuke. */
652 if (otherFi->actions[otherFileNum] != FA_ERASE) {
653 /* On updates, don't remove files. */
654 fi->actions[i] = FA_SKIP;
655 /*@switchbreak@*/ break;
657 /* Here is an overlapped removed file: skip in previous. */
658 otherFi->actions[otherFileNum] = FA_SKIP;
660 if (XFA_SKIPPING(fi->actions[i]))
661 /*@switchbreak@*/ break;
662 if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
663 /*@switchbreak@*/ break;
664 if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
665 fi->actions[i] = FA_ERASE;
666 /*@switchbreak@*/ break;
669 /* Here is a pre-existing modified config file that needs saving. */
671 const unsigned char * MD5 = rpmfiMD5(fi);
672 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
673 fi->actions[i] = FA_BACKUP;
674 /*@switchbreak@*/ break;
677 fi->actions[i] = FA_ERASE;
678 /*@switchbreak@*/ break;
682 /* Update disk space info for a file. */
683 rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
684 fi->replacedSizes[i], fixupSize, fi->actions[i]);
691 * Ensure that current package is newer than installed package.
692 * @param ts transaction set
693 * @param p current transaction element
694 * @param h installed header
695 * @return 0 if not newer, 1 if okay
697 static int ensureOlder(rpmts ts,
698 const rpmte p, const Header h)
701 int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
708 if (p == NULL || h == NULL)
712 nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
716 if (rpmteE(p) != NULL) t = stpcpy( stpcpy(t, rpmteE(p)), ":");
717 if (rpmteV(p) != NULL) t = stpcpy(t, rpmteV(p));
719 if (rpmteR(p) != NULL) t = stpcpy(t, rpmteR(p));
722 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
723 rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
724 req = rpmdsFree(req);
727 rpmps ps = rpmtsProblems(ts);
728 const char * altNEVR = hGetNEVR(h, NULL);
729 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
730 rpmteNEVR(p), rpmteKey(p),
734 altNEVR = _free(altNEVR);
744 * Skip any files that do not match install policies.
745 * @param ts transaction set
746 * @param fi file info set
748 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
750 static void skipFiles(const rpmts ts, rpmfi fi)
751 /*@globals rpmGlobalMacroContext @*/
752 /*@modifies fi, rpmGlobalMacroContext @*/
754 uint_32 tscolor = rpmtsColor(ts);
756 int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
757 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
758 char ** netsharedPaths = NULL;
759 const char ** languages;
760 const char * dn, * bn;
761 int dnlen, bnlen, ix;
769 noDocs = rpmExpandNumeric("%{_excludedocs}");
771 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
773 if (tmpPath && *tmpPath != '%')
774 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
776 tmpPath = _free(tmpPath);
779 s = rpmExpand("%{_install_langs}", NULL);
781 if (!(s && *s != '%'))
784 languages = (const char **) splitString(s, strlen(s), ':');
790 /* Compute directory refcount, skip directory if now empty. */
792 drc = alloca(dc * sizeof(*drc));
793 memset(drc, 0, dc * sizeof(*drc));
794 dff = alloca(dc * sizeof(*dff));
795 memset(dff, 0, dc * sizeof(*dff));
797 fi = rpmfiInit(fi, 0);
798 if (fi != NULL) /* XXX lclint */
799 while ((i = rpmfiNext(fi)) >= 0)
809 continue; /* XXX can't happen */
813 /* Don't bother with skipped files */
814 if (XFA_SKIPPING(fi->actions[i])) {
815 drc[ix]--; dff[ix] = 1;
819 /* Ignore colored files not in our rainbow. */
820 ficolor = rpmfiFColor(fi);
821 if (tscolor && ficolor && !(tscolor & ficolor)) {
822 drc[ix]--; dff[ix] = 1;
823 fi->actions[i] = FA_SKIPCOLOR;
828 * Skip net shared paths.
829 * Net shared paths are not relative to the current root (though
830 * they do need to take package relocations into account).
832 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
837 if (strncmp(dn, *nsp, len))
838 /*@innercontinue@*/ continue;
839 /* Only directories or complete file paths can be net shared */
840 if (!(dn[len] == '/' || dn[len] == '\0'))
841 /*@innercontinue@*/ continue;
843 if (len < (dnlen + bnlen))
844 /*@innercontinue@*/ continue;
845 if (strncmp(dn, *nsp, dnlen))
846 /*@innercontinue@*/ continue;
847 if (strncmp(bn, (*nsp) + dnlen, bnlen))
848 /*@innercontinue@*/ continue;
850 /* Only directories or complete file paths can be net shared */
851 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
852 /*@innercontinue@*/ continue;
855 /*@innerbreak@*/ break;
859 drc[ix]--; dff[ix] = 1;
860 fi->actions[i] = FA_SKIPNETSHARED;
865 * Skip i18n language specific files.
867 if (languages != NULL && fi->flangs != NULL && *fi->flangs[i]) {
868 const char **lang, *l, *le;
869 for (lang = languages; *lang != NULL; lang++) {
870 if (!strcmp(*lang, "all"))
871 /*@innerbreak@*/ break;
872 for (l = fi->flangs[i]; *l != '\0'; l = le) {
873 for (le = l; *le != '\0' && *le != '|'; le++)
875 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
876 /*@innerbreak@*/ break;
877 if (*le == '|') le++; /* skip over | */
880 /*@innerbreak@*/ break;
883 drc[ix]--; dff[ix] = 1;
884 fi->actions[i] = FA_SKIPNSTATE;
890 * Skip config files if requested.
892 if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
893 drc[ix]--; dff[ix] = 1;
894 fi->actions[i] = FA_SKIPNSTATE;
899 * Skip documentation if requested.
901 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
902 drc[ix]--; dff[ix] = 1;
903 fi->actions[i] = FA_SKIPNSTATE;
908 /* Skip (now empty) directories that had skipped files. */
910 if (fi != NULL) /* XXX can't happen */
911 for (j = 0; j < dc; j++)
913 if ((fi = rpmfiInitD(fi)) != NULL)
914 while (j = rpmfiNextD(fi) >= 0)
918 if (drc[j]) continue; /* dir still has files. */
919 if (!dff[j]) continue; /* dir was not emptied here. */
921 /* Find parent directory and basename. */
922 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
923 bn = dn + dnlen; bnlen = 0;
924 while (bn > dn && bn[-1] != '/') {
930 /* If explicitly included in the package, skip the directory. */
931 fi = rpmfiInit(fi, 0);
932 if (fi != NULL) /* XXX lclint */
933 while ((i = rpmfiNext(fi)) >= 0) {
934 const char * fdn, * fbn;
937 if (XFA_SKIPPING(fi->actions[i]))
938 /*@innercontinue@*/ continue;
940 fFMode = rpmfiFMode(fi);
942 if (whatis(fFMode) != XDIR)
943 /*@innercontinue@*/ continue;
945 if (strlen(fdn) != dnlen)
946 /*@innercontinue@*/ continue;
947 if (strncmp(fdn, dn, dnlen))
948 /*@innercontinue@*/ continue;
950 if (strlen(fbn) != bnlen)
951 /*@innercontinue@*/ continue;
952 if (strncmp(fbn, bn, bnlen))
953 /*@innercontinue@*/ continue;
954 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
955 fi->actions[i] = FA_SKIPNSTATE;
956 /*@innerbreak@*/ break;
960 /*@-dependenttrans@*/
961 if (netsharedPaths) freeSplitString(netsharedPaths);
962 #ifdef DYING /* XXX freeFi will deal with this later. */
963 fi->flangs = _free(fi->flangs);
965 if (languages) freeSplitString((char **)languages);
966 /*@=dependenttrans@*/
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 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1029 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1031 ts->probs = rpmpsFree(ts->probs);
1032 ts->probs = rpmpsCreate();
1034 /* XXX Make sure the database is open RDWR for package install/erase. */
1035 { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1036 ? O_RDONLY : (O_RDWR|O_CREAT);
1038 /* Open database RDWR for installing packages. */
1039 if (rpmtsOpenDB(ts, dbmode))
1040 return -1; /* XXX W2DO? */
1043 ts->ignoreSet = ignoreSet;
1044 { const char * currDir = currentDirectory();
1045 rpmtsSetCurrDir(ts, currDir);
1046 currDir = _free(currDir);
1049 (void) rpmtsSetChrootDone(ts, 0);
1051 { int_32 tid = (int_32) time(NULL);
1052 (void) rpmtsSetTid(ts, tid);
1055 /* Get available space on mounted file systems. */
1056 xx = rpmtsInitDSI(ts);
1058 /* ===============================================
1059 * For packages being installed:
1060 * - verify package arch/os.
1061 * - verify package epoch:version-release is newer.
1063 * For packages being removed:
1067 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
1068 ps = rpmtsProblems(ts);
1069 /* The ordering doesn't matter here */
1070 pi = rpmtsiInit(ts);
1071 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1072 rpmdbMatchIterator mi;
1075 if ((fi = rpmtsiFi(pi)) == NULL)
1076 continue; /* XXX can't happen */
1079 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
1080 if (!archOkay(rpmteA(p)))
1081 rpmpsAppend(ps, RPMPROB_BADARCH,
1082 rpmteNEVR(p), rpmteKey(p),
1086 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1087 if (!osOkay(rpmteO(p)))
1088 rpmpsAppend(ps, RPMPROB_BADOS,
1089 rpmteNEVR(p), rpmteKey(p),
1093 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1095 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1096 while ((h = rpmdbNextIterator(mi)) != NULL)
1097 xx = ensureOlder(ts, p, h);
1098 mi = rpmdbFreeIterator(mi);
1101 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1102 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1103 xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1105 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1107 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1110 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1112 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1116 while (rpmdbNextIterator(mi) != NULL) {
1117 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1118 rpmteNEVR(p), rpmteKey(p),
1121 /*@innerbreak@*/ break;
1123 mi = rpmdbFreeIterator(mi);
1126 /* Count no. of files (if any). */
1127 totalFileCount += fc;
1130 pi = rpmtsiFree(pi);
1133 /* The ordering doesn't matter here */
1134 pi = rpmtsiInit(ts);
1135 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1138 if ((fi = rpmtsiFi(pi)) == NULL)
1139 continue; /* XXX can't happen */
1142 totalFileCount += fc;
1144 pi = rpmtsiFree(pi);
1146 /* ===============================================
1147 * Initialize transaction element file info for package:
1151 * FIXME?: we'd be better off assembling one very large file list and
1152 * calling fpLookupList only once. I'm not sure that the speedup is
1153 * worth the trouble though.
1155 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 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1213 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1215 fi = rpmfiInit(fi, 0);
1216 if (fi != NULL) /* XXX lclint */
1217 while ((i = rpmfiNext(fi)) >= 0) {
1218 if (XFA_SKIPPING(fi->actions[i]))
1219 /*@innercontinue@*/ continue;
1220 /*@-dependenttrans@*/
1221 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1222 /*@=dependenttrans@*/
1225 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1228 pi = rpmtsiFree(pi);
1230 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1231 NULL, ts->notifyData));
1233 /* ===============================================
1234 * Compute file disposition for each package in transaction set.
1236 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1237 ps = rpmtsProblems(ts);
1238 pi = rpmtsiInit(ts);
1239 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1240 dbiIndexSet * matches;
1244 (void) rpmdbCheckSignals();
1246 if ((fi = rpmtsiFi(pi)) == NULL)
1247 continue; /* XXX can't happen */
1250 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1251 ts->orderCount, NULL, ts->notifyData));
1253 if (fc == 0) continue;
1255 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
1256 /* Extract file info for all files in this package from the database. */
1257 matches = xcalloc(fc, sizeof(*matches));
1258 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1260 return 1; /* XXX WTFO? */
1264 fi = rpmfiInit(fi, 0);
1265 while ((i = rpmfiNext(fi)) >= 0)
1266 numShared += dbiIndexSetCount(matches[i]);
1268 /* Build sorted file info list for this package. */
1269 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1271 fi = rpmfiInit(fi, 0);
1272 while ((i = rpmfiNext(fi)) >= 0) {
1274 * Take care not to mark files as replaced in packages that will
1275 * have been removed before we will get here.
1277 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1279 ro = dbiIndexRecordOffset(matches[i], j);
1281 qi = rpmtsiInit(ts);
1282 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1284 /*@innerbreak@*/ break;
1285 if (rpmteDBOffset(q) == ro)
1288 qi = rpmtsiFree(qi);
1290 shared->pkgFileNum = i;
1291 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1292 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1293 shared->isRemoved = (knownBad == ro);
1296 matches[i] = dbiFreeIndexSet(matches[i]);
1298 numShared = shared - sharedList;
1299 shared->otherPkg = -1;
1300 matches = _free(matches);
1302 /* Sort file info by other package index (otherPkg) */
1303 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1305 /* For all files from this package that are in the database ... */
1307 for (i = 0; i < numShared; i = nexti) {
1310 shared = sharedList + i;
1312 /* Find the end of the files in the other package. */
1313 for (nexti = i + 1; nexti < numShared; nexti++) {
1314 if (sharedList[nexti].otherPkg != shared->otherPkg)
1315 /*@innerbreak@*/ break;
1318 /* Is this file from a package being removed? */
1320 if (ts->removedPackages != NULL)
1321 for (j = 0; j < ts->numRemovedPackages; j++) {
1322 if (ts->removedPackages[j] != shared->otherPkg)
1323 /*@innercontinue@*/ continue;
1325 /*@innerbreak@*/ break;
1328 /* Determine the fate of each file. */
1329 switch (rpmteType(p)) {
1331 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1332 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1333 /*@switchbreak@*/ break;
1336 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1337 /*@switchbreak@*/ break;
1344 /* Update disk space needs on each partition for this package. */
1345 handleOverlappedFiles(ts, p, fi);
1347 /* Check added package has sufficient space on each partition used. */
1348 switch (rpmteType(p)) {
1350 rpmtsCheckDSIProblems(ts, p);
1351 /*@switchbreak@*/ break;
1353 /*@switchbreak@*/ break;
1355 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
1357 pi = rpmtsiFree(pi);
1360 if (rpmtsChrootDone(ts)) {
1361 const char * currDir = rpmtsCurrDir(ts);
1362 /*@-superuser -noeffect @*/
1364 /*@=superuser =noeffect @*/
1365 (void) rpmtsSetChrootDone(ts, 0);
1366 if (currDir != NULL)
1367 xx = chdir(currDir);
1370 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1371 NULL, ts->notifyData));
1373 /* ===============================================
1374 * Free unused memory as soon as possible.
1376 pi = rpmtsiInit(ts);
1377 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1378 if ((fi = rpmtsiFi(pi)) == NULL)
1379 continue; /* XXX can't happen */
1380 if (rpmfiFC(fi) == 0)
1382 fi->fps = _free(fi->fps);
1384 pi = rpmtsiFree(pi);
1386 fpc = fpCacheFree(fpc);
1387 ts->ht = htFree(ts->ht);
1389 /* ===============================================
1390 * If unfiltered problems exist, free memory and return.
1392 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1393 || (ts->probs->numProblems &&
1394 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1397 return ts->orderCount;
1400 /* ===============================================
1401 * Save removed files before erasing.
1403 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1407 pi = rpmtsiInit(ts);
1408 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1410 (void) rpmdbCheckSignals();
1412 if ((fi = rpmtsiFi(pi)) == NULL)
1413 continue; /* XXX can't happen */
1414 switch (rpmteType(p)) {
1416 /*@switchbreak@*/ break;
1418 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1419 /*@switchbreak@*/ break;
1421 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1422 7, numRemoved, NULL, ts->notifyData));
1424 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1425 numRemoved, NULL, ts->notifyData));
1428 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
1430 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1431 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1432 fi->mapflags |= CPIO_MAP_ADDDOT;
1433 fi->mapflags |= CPIO_ALL_HARDLINKS;
1434 psm = rpmpsmNew(ts, p, fi);
1435 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1436 psm = rpmpsmFree(psm);
1437 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1438 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1439 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1441 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
1443 /*@switchbreak@*/ break;
1446 pi = rpmtsiFree(pi);
1448 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1449 NULL, ts->notifyData));
1453 /* ===============================================
1454 * Install and remove packages.
1456 lastFailKey = (alKey)-2; /* erased packages have -1 */
1457 pi = rpmtsiInit(ts);
1458 /*@-branchstate@*/ /* FIX: fi reload needs work */
1459 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1463 (void) rpmdbCheckSignals();
1466 if ((fi = rpmtsiFi(pi)) == NULL)
1467 continue; /* XXX can't happen */
1469 psm = rpmpsmNew(ts, p, fi);
1470 assert(psm != NULL);
1471 psm->unorderedSuccessor =
1472 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1474 switch (rpmteType(p)) {
1476 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1478 pkgKey = rpmteAddedKey(p);
1480 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1482 /*@-type@*/ /* FIX: rpmte not opaque */
1484 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1485 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1486 rpmteKey(p), ts->notifyData);
1487 /*@=noeffectuncon@*/
1488 if (rpmteFd(p) != NULL) {
1489 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1490 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1493 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1494 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1495 rpmteNEVR(p), &p->h);
1496 vsflags = rpmtsSetVSFlags(ts, ovsflags);
1500 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1501 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1503 rpmteKey(p), ts->notifyData);
1504 /*@=noeffectuncon@*/
1507 /*@innerbreak@*/ break;
1508 case RPMRC_NOTTRUSTED:
1511 /*@innerbreak@*/ break;
1513 if (rpmteFd(p) != NULL) gotfd = 1;
1518 if (rpmteFd(p) != NULL) {
1520 * XXX Sludge necessary to tranfer existing fstates/actions
1521 * XXX around a recreated file info set.
1523 psm->fi = rpmfiFree(psm->fi);
1525 char * fstates = fi->fstates;
1526 fileAction * actions = fi->actions;
1531 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
1535 savep = rpmtsSetRelocateElement(ts, p);
1536 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1537 (void) rpmtsSetRelocateElement(ts, savep);
1539 if (fi != NULL) { /* XXX can't happen */
1541 fi->fstates = _free(fi->fstates);
1542 fi->fstates = fstates;
1543 fi->actions = _free(fi->actions);
1544 fi->actions = actions;
1548 psm->fi = rpmfiLink(p->fi, NULL);
1550 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1551 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1553 lastFailKey = pkgKey;
1558 lastFailKey = pkgKey;
1562 /*@-noeffectuncon @*/ /* FIX: check rc */
1563 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1564 rpmteKey(p), ts->notifyData);
1565 /*@=noeffectuncon @*/
1571 p->h = headerFree(p->h);
1573 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
1575 /*@switchbreak@*/ break;
1578 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1580 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1582 * XXX This has always been a hack, now mostly broken.
1583 * If install failed, then we shouldn't erase.
1585 if (rpmteDependsOnKey(p) != lastFailKey) {
1586 if (rpmpsmStage(psm, PSM_PKGERASE))
1590 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
1592 /*@switchbreak@*/ break;
1594 xx = rpmdbSync(rpmtsGetRdb(ts));
1596 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1597 psm = rpmpsmFree(psm);
1600 /*@-type@*/ /* FIX: p is almost opaque */
1601 p->fi = rpmfiFree(p->fi);
1606 pi = rpmtsiFree(pi);
1608 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */