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 (void) rpmswEnter(&ts->op, -1);
1159 numAdded = numRemoved = 0;
1160 pi = rpmtsiInit(ts);
1161 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1164 if ((fi = rpmtsiFi(pi)) == NULL)
1165 continue; /* XXX can't happen */
1169 switch (rpmteType(p)) {
1173 /* Skip netshared paths, not our i18n files, and excluded docs */
1176 /*@switchbreak@*/ break;
1179 fi->record = rpmteDBOffset(p);
1180 /*@switchbreak@*/ break;
1184 fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1186 pi = rpmtsiFree(pi);
1188 if (!rpmtsChrootDone(ts)) {
1189 const char * rootDir = rpmtsRootDir(ts);
1191 /*@-superuser -noeffect @*/
1192 if (rootDir != NULL)
1193 xx = chroot(rootDir);
1194 /*@=superuser =noeffect @*/
1195 (void) rpmtsSetChrootDone(ts, 1);
1198 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1199 fpc = fpCacheCreate(totalFileCount);
1201 /* ===============================================
1202 * Add fingerprint for each file not skipped.
1204 pi = rpmtsiInit(ts);
1205 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1208 (void) rpmdbCheckSignals();
1210 if ((fi = rpmtsiFi(pi)) == NULL)
1211 continue; /* XXX can't happen */
1214 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1216 fi = rpmfiInit(fi, 0);
1217 if (fi != NULL) /* XXX lclint */
1218 while ((i = rpmfiNext(fi)) >= 0) {
1219 if (XFA_SKIPPING(fi->actions[i]))
1220 /*@innercontinue@*/ continue;
1221 /*@-dependenttrans@*/
1222 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1223 /*@=dependenttrans@*/
1227 pi = rpmtsiFree(pi);
1229 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1230 NULL, ts->notifyData));
1232 /* ===============================================
1233 * Compute file disposition for each package in transaction set.
1235 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1236 ps = rpmtsProblems(ts);
1237 pi = rpmtsiInit(ts);
1238 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1239 dbiIndexSet * matches;
1243 (void) rpmdbCheckSignals();
1245 if ((fi = rpmtsiFi(pi)) == NULL)
1246 continue; /* XXX can't happen */
1249 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1250 ts->orderCount, NULL, ts->notifyData));
1252 if (fc == 0) continue;
1254 /* Extract file info for all files in this package from the database. */
1255 matches = xcalloc(fc, sizeof(*matches));
1256 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1258 return 1; /* XXX WTFO? */
1262 fi = rpmfiInit(fi, 0);
1263 while ((i = rpmfiNext(fi)) >= 0)
1264 numShared += dbiIndexSetCount(matches[i]);
1266 /* Build sorted file info list for this package. */
1267 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1269 fi = rpmfiInit(fi, 0);
1270 while ((i = rpmfiNext(fi)) >= 0) {
1272 * Take care not to mark files as replaced in packages that will
1273 * have been removed before we will get here.
1275 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1277 ro = dbiIndexRecordOffset(matches[i], j);
1279 qi = rpmtsiInit(ts);
1280 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1282 /*@innerbreak@*/ break;
1283 if (rpmteDBOffset(q) == ro)
1286 qi = rpmtsiFree(qi);
1288 shared->pkgFileNum = i;
1289 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1290 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1291 shared->isRemoved = (knownBad == ro);
1294 matches[i] = dbiFreeIndexSet(matches[i]);
1296 numShared = shared - sharedList;
1297 shared->otherPkg = -1;
1298 matches = _free(matches);
1300 /* Sort file info by other package index (otherPkg) */
1301 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1303 /* For all files from this package that are in the database ... */
1305 for (i = 0; i < numShared; i = nexti) {
1308 shared = sharedList + i;
1310 /* Find the end of the files in the other package. */
1311 for (nexti = i + 1; nexti < numShared; nexti++) {
1312 if (sharedList[nexti].otherPkg != shared->otherPkg)
1313 /*@innerbreak@*/ break;
1316 /* Is this file from a package being removed? */
1318 if (ts->removedPackages != NULL)
1319 for (j = 0; j < ts->numRemovedPackages; j++) {
1320 if (ts->removedPackages[j] != shared->otherPkg)
1321 /*@innercontinue@*/ continue;
1323 /*@innerbreak@*/ break;
1326 /* Determine the fate of each file. */
1327 switch (rpmteType(p)) {
1329 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1330 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1331 /*@switchbreak@*/ break;
1334 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1335 /*@switchbreak@*/ break;
1342 /* Update disk space needs on each partition for this package. */
1343 handleOverlappedFiles(ts, p, fi);
1345 /* Check added package has sufficient space on each partition used. */
1346 switch (rpmteType(p)) {
1348 rpmtsCheckDSIProblems(ts, p);
1349 /*@switchbreak@*/ break;
1351 /*@switchbreak@*/ break;
1354 pi = rpmtsiFree(pi);
1357 if (rpmtsChrootDone(ts)) {
1358 const char * currDir = rpmtsCurrDir(ts);
1359 /*@-superuser -noeffect @*/
1361 /*@=superuser =noeffect @*/
1362 (void) rpmtsSetChrootDone(ts, 0);
1363 if (currDir != NULL)
1364 xx = chdir(currDir);
1367 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1368 NULL, ts->notifyData));
1370 ts->ms_fingerprint += rpmswExit(&ts->op, totalFileCount)/1000;
1372 /* ===============================================
1373 * Free unused memory as soon as possible.
1375 pi = rpmtsiInit(ts);
1376 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1377 if ((fi = rpmtsiFi(pi)) == NULL)
1378 continue; /* XXX can't happen */
1379 if (rpmfiFC(fi) == 0)
1381 fi->fps = _free(fi->fps);
1383 pi = rpmtsiFree(pi);
1385 fpc = fpCacheFree(fpc);
1386 ts->ht = htFree(ts->ht);
1388 /* ===============================================
1389 * If unfiltered problems exist, free memory and return.
1391 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1392 || (ts->probs->numProblems &&
1393 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1396 return ts->orderCount;
1399 /* ===============================================
1400 * Save removed files before erasing.
1402 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1406 pi = rpmtsiInit(ts);
1407 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1409 (void) rpmdbCheckSignals();
1411 if ((fi = rpmtsiFi(pi)) == NULL)
1412 continue; /* XXX can't happen */
1413 switch (rpmteType(p)) {
1415 /*@switchbreak@*/ break;
1417 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1418 /*@switchbreak@*/ break;
1420 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1421 7, numRemoved, NULL, ts->notifyData));
1423 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1424 numRemoved, NULL, ts->notifyData));
1427 (void) rpmswEnter(&ts->op, -1);
1429 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1430 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1431 fi->mapflags |= CPIO_MAP_ADDDOT;
1432 fi->mapflags |= CPIO_ALL_HARDLINKS;
1433 psm = rpmpsmNew(ts, p, fi);
1434 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1435 psm = rpmpsmFree(psm);
1436 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1437 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1438 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1440 ts->ms_repackage += rpmswExit(&ts->op, -1)/1000;
1442 /*@switchbreak@*/ break;
1445 pi = rpmtsiFree(pi);
1447 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1448 NULL, ts->notifyData));
1452 /* ===============================================
1453 * Install and remove packages.
1455 lastFailKey = (alKey)-2; /* erased packages have -1 */
1456 pi = rpmtsiInit(ts);
1457 /*@-branchstate@*/ /* FIX: fi reload needs work */
1458 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1462 (void) rpmdbCheckSignals();
1465 if ((fi = rpmtsiFi(pi)) == NULL)
1466 continue; /* XXX can't happen */
1468 psm = rpmpsmNew(ts, p, fi);
1469 assert(psm != NULL);
1470 psm->unorderedSuccessor =
1471 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1473 switch (rpmteType(p)) {
1475 (void) rpmswEnter(&ts->op, -1);
1477 pkgKey = rpmteAddedKey(p);
1479 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1481 /*@-type@*/ /* FIX: rpmte not opaque */
1483 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1484 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1485 rpmteKey(p), ts->notifyData);
1486 /*@=noeffectuncon@*/
1487 if (rpmteFd(p) != NULL) {
1488 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1489 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1492 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1493 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1494 rpmteNEVR(p), &p->h);
1495 vsflags = rpmtsSetVSFlags(ts, ovsflags);
1499 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1500 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1502 rpmteKey(p), ts->notifyData);
1503 /*@=noeffectuncon@*/
1506 /*@innerbreak@*/ break;
1507 case RPMRC_NOTTRUSTED:
1510 /*@innerbreak@*/ break;
1512 if (rpmteFd(p) != NULL) gotfd = 1;
1517 if (rpmteFd(p) != NULL) {
1519 * XXX Sludge necessary to tranfer existing fstates/actions
1520 * XXX around a recreated file info set.
1522 psm->fi = rpmfiFree(psm->fi);
1524 char * fstates = fi->fstates;
1525 fileAction * actions = fi->actions;
1530 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
1534 savep = rpmtsSetRelocateElement(ts, p);
1535 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1536 (void) rpmtsSetRelocateElement(ts, savep);
1538 if (fi != NULL) { /* XXX can't happen */
1540 fi->fstates = _free(fi->fstates);
1541 fi->fstates = fstates;
1542 fi->actions = _free(fi->actions);
1543 fi->actions = actions;
1547 psm->fi = rpmfiLink(p->fi, NULL);
1549 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1550 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1552 lastFailKey = pkgKey;
1557 lastFailKey = pkgKey;
1561 /*@-noeffectuncon @*/ /* FIX: check rc */
1562 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1563 rpmteKey(p), ts->notifyData);
1564 /*@=noeffectuncon @*/
1570 p->h = headerFree(p->h);
1572 ts->ms_install += rpmswExit(&ts->op, -1)/1000;
1574 /*@switchbreak@*/ break;
1577 (void) rpmswEnter(&ts->op, -1);
1579 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1581 * XXX This has always been a hack, now mostly broken.
1582 * If install failed, then we shouldn't erase.
1584 if (rpmteDependsOnKey(p) != lastFailKey) {
1585 if (rpmpsmStage(psm, PSM_PKGERASE))
1589 ts->ms_erase += rpmswExit(&ts->op, -1)/1000;
1591 /*@switchbreak@*/ break;
1593 xx = rpmdbSync(rpmtsGetRdb(ts));
1595 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1596 psm = rpmpsmFree(psm);
1599 /*@-type@*/ /* FIX: p is almost opaque */
1600 p->fi = rpmfiFree(p->fi);
1605 pi = rpmtsiFree(pi);
1607 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */