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 (fi->flangs && languages && *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 if (netsharedPaths) freeSplitString(netsharedPaths);
961 #ifdef DYING /* XXX freeFi will deal with this later. */
962 fi->flangs = _free(fi->flangs);
964 if (languages) freeSplitString((char **)languages);
970 * Return transaction element's file info.
971 * @todo Take a rpmfi refcount here.
972 * @param tsi transaction element iterator
973 * @return transaction element file info
976 rpmfi rpmtsiFi(const rpmtsi tsi)
981 if (tsi != NULL && tsi->ocsave != -1) {
982 /*@-type -abstract@*/ /* FIX: rpmte not opaque */
983 rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
985 if (te != NULL && (fi = te->fi) != NULL)
988 /*@=type =abstract@*/
990 /*@-compdef -refcounttrans -usereleased @*/
992 /*@=compdef =refcounttrans =usereleased @*/
995 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
997 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
999 uint_32 tscolor = rpmtsColor(ts);
1002 int totalFileCount = 0;
1004 sharedFileInfo shared, sharedList;
1008 fingerPrintCache fpc;
1017 /* XXX programmer error segfault avoidance. */
1018 if (rpmtsNElements(ts) <= 0)
1021 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
1022 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1023 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
1024 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
1026 if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
1027 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
1029 ts->probs = rpmpsFree(ts->probs);
1030 ts->probs = rpmpsCreate();
1032 /* XXX Make sure the database is open RDWR for package install/erase. */
1033 { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
1034 ? O_RDONLY : (O_RDWR|O_CREAT);
1036 /* Open database RDWR for installing packages. */
1037 if (rpmtsOpenDB(ts, dbmode))
1038 return -1; /* XXX W2DO? */
1041 ts->ignoreSet = ignoreSet;
1042 { const char * currDir = currentDirectory();
1043 rpmtsSetCurrDir(ts, currDir);
1044 currDir = _free(currDir);
1047 (void) rpmtsSetChrootDone(ts, 0);
1049 { int_32 tid = (int_32) time(NULL);
1050 (void) rpmtsSetTid(ts, tid);
1053 /* Get available space on mounted file systems. */
1054 xx = rpmtsInitDSI(ts);
1056 /* ===============================================
1057 * For packages being installed:
1058 * - verify package arch/os.
1059 * - verify package epoch:version-release is newer.
1061 * For packages being removed:
1065 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
1066 ps = rpmtsProblems(ts);
1067 /* The ordering doesn't matter here */
1068 pi = rpmtsiInit(ts);
1069 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1070 rpmdbMatchIterator mi;
1073 if ((fi = rpmtsiFi(pi)) == NULL)
1074 continue; /* XXX can't happen */
1077 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
1078 if (!archOkay(rpmteA(p)))
1079 rpmpsAppend(ps, RPMPROB_BADARCH,
1080 rpmteNEVR(p), rpmteKey(p),
1084 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1085 if (!osOkay(rpmteO(p)))
1086 rpmpsAppend(ps, RPMPROB_BADOS,
1087 rpmteNEVR(p), rpmteKey(p),
1091 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1093 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1094 while ((h = rpmdbNextIterator(mi)) != NULL)
1095 xx = ensureOlder(ts, p, h);
1096 mi = rpmdbFreeIterator(mi);
1099 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
1100 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1101 xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_DEFAULT,
1103 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1105 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1108 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT,
1110 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_DEFAULT,
1114 while (rpmdbNextIterator(mi) != NULL) {
1115 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1116 rpmteNEVR(p), rpmteKey(p),
1119 /*@innerbreak@*/ break;
1121 mi = rpmdbFreeIterator(mi);
1124 /* Count no. of files (if any). */
1125 totalFileCount += fc;
1128 pi = rpmtsiFree(pi);
1131 /* The ordering doesn't matter here */
1132 pi = rpmtsiInit(ts);
1133 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1136 if ((fi = rpmtsiFi(pi)) == NULL)
1137 continue; /* XXX can't happen */
1140 totalFileCount += fc;
1142 pi = rpmtsiFree(pi);
1144 /* ===============================================
1145 * Initialize transaction element file info for package:
1149 * FIXME?: we'd be better off assembling one very large file list and
1150 * calling fpLookupList only once. I'm not sure that the speedup is
1151 * worth the trouble though.
1153 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
1155 (void) rpmswNow(&ts->begin);
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 ts->ms_fingerprint += rpmswDiff(rpmswNow(&ts->end), &ts->begin)/1000;
1370 /* ===============================================
1371 * Free unused memory as soon as possible.
1373 pi = rpmtsiInit(ts);
1374 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1375 if ((fi = rpmtsiFi(pi)) == NULL)
1376 continue; /* XXX can't happen */
1377 if (rpmfiFC(fi) == 0)
1379 fi->fps = _free(fi->fps);
1381 pi = rpmtsiFree(pi);
1383 fpc = fpCacheFree(fpc);
1384 ts->ht = htFree(ts->ht);
1386 /* ===============================================
1387 * If unfiltered problems exist, free memory and return.
1389 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1390 || (ts->probs->numProblems &&
1391 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1394 return ts->orderCount;
1397 /* ===============================================
1398 * Save removed files before erasing.
1400 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1404 pi = rpmtsiInit(ts);
1405 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1407 (void) rpmdbCheckSignals();
1409 if ((fi = rpmtsiFi(pi)) == NULL)
1410 continue; /* XXX can't happen */
1411 switch (rpmteType(p)) {
1413 /*@switchbreak@*/ break;
1415 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1416 /*@switchbreak@*/ break;
1418 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
1419 7, numRemoved, NULL, ts->notifyData));
1421 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
1422 numRemoved, NULL, ts->notifyData));
1425 (void) rpmswNow(&ts->begin);
1427 /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
1428 fi->mapflags |= CPIO_MAP_ABSOLUTE;
1429 fi->mapflags |= CPIO_MAP_ADDDOT;
1430 fi->mapflags |= CPIO_ALL_HARDLINKS;
1431 psm = rpmpsmNew(ts, p, fi);
1432 xx = rpmpsmStage(psm, PSM_PKGSAVE);
1433 psm = rpmpsmFree(psm);
1434 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
1435 fi->mapflags &= ~CPIO_MAP_ADDDOT;
1436 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
1438 ts->ms_repackage += rpmswDiff(rpmswNow(&ts->end), &ts->begin)/1000;
1440 /*@switchbreak@*/ break;
1443 pi = rpmtsiFree(pi);
1445 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
1446 NULL, ts->notifyData));
1450 /* ===============================================
1451 * Install and remove packages.
1453 lastFailKey = (alKey)-2; /* erased packages have -1 */
1454 pi = rpmtsiInit(ts);
1455 /*@-branchstate@*/ /* FIX: fi reload needs work */
1456 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1460 (void) rpmdbCheckSignals();
1463 if ((fi = rpmtsiFi(pi)) == NULL)
1464 continue; /* XXX can't happen */
1466 psm = rpmpsmNew(ts, p, fi);
1467 psm->unorderedSuccessor =
1468 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
1470 switch (rpmteType(p)) {
1472 (void) rpmswNow(&ts->begin);
1474 pkgKey = rpmteAddedKey(p);
1476 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1478 /*@-type@*/ /* FIX: rpmte not opaque */
1480 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1481 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1482 rpmteKey(p), ts->notifyData);
1483 /*@=noeffectuncon@*/
1484 if (rpmteFd(p) != NULL) {
1485 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
1486 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
1489 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1490 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1491 rpmteNEVR(p), &p->h);
1492 vsflags = rpmtsSetVSFlags(ts, ovsflags);
1496 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1497 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
1499 rpmteKey(p), ts->notifyData);
1500 /*@=noeffectuncon@*/
1503 /*@innerbreak@*/ break;
1504 case RPMRC_NOTTRUSTED:
1507 /*@innerbreak@*/ break;
1509 if (rpmteFd(p) != NULL) gotfd = 1;
1514 if (rpmteFd(p) != NULL) {
1516 * XXX Sludge necessary to tranfer existing fstates/actions
1517 * XXX around a recreated file info set.
1519 psm->fi = rpmfiFree(psm->fi);
1521 char * fstates = fi->fstates;
1522 fileAction * actions = fi->actions;
1529 savep = rpmtsSetRelocateElement(ts, p);
1530 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
1531 (void) rpmtsSetRelocateElement(ts, savep);
1533 if (fi != NULL) { /* XXX can't happen */
1535 fi->fstates = _free(fi->fstates);
1536 fi->fstates = fstates;
1537 fi->actions = _free(fi->actions);
1538 fi->actions = actions;
1542 psm->fi = rpmfiLink(p->fi, NULL);
1544 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1545 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
1547 lastFailKey = pkgKey;
1552 lastFailKey = pkgKey;
1556 /*@-noeffectuncon @*/ /* FIX: check rc */
1557 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1558 rpmteKey(p), ts->notifyData);
1559 /*@=noeffectuncon @*/
1565 p->h = headerFree(p->h);
1567 ts->ms_install += rpmswDiff(rpmswNow(&ts->end), &ts->begin)/1000;
1569 /*@switchbreak@*/ break;
1572 (void) rpmswNow(&ts->begin);
1574 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1576 * XXX This has always been a hack, now mostly broken.
1577 * If install failed, then we shouldn't erase.
1579 if (rpmteDependsOnKey(p) != lastFailKey) {
1580 if (rpmpsmStage(psm, PSM_PKGERASE))
1584 ts->ms_erase += rpmswDiff(rpmswNow(&ts->end), &ts->begin)/1000;
1586 /*@switchbreak@*/ break;
1588 xx = rpmdbSync(rpmtsGetRdb(ts));
1590 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
1591 psm = rpmpsmFree(psm);
1594 /*@-type@*/ /* FIX: p is almost opaque */
1595 p->fi = rpmfiFree(p->fi);
1600 pi = rpmtsiFree(pi);
1602 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */