2 * \file lib/transaction.c
8 #include <rpmmacro.h> /* XXX for rpmExpand */
16 #define _RPMFI_INTERNAL
19 #define _RPMTE_INTERNAL
22 #define _RPMTS_INTERNAL
26 #include "legacy.h" /* XXX domd5 */
27 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
31 /*@access FD_t @*/ /* XXX compared with NULL */
32 /*@access Header @*/ /* XXX compared with NULL */
33 /*@access rpmps @*/ /* XXX need rpmProblemSetOK() */
34 /*@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(sb.st_mode);
114 dbWhat = whatis(ofi->fmodes[ofi->i]);
115 newWhat = whatis(nfi->fmodes[nfi->i]);
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.
139 if (ofi->md5s != NULL && nfi->md5s != NULL) {
141 const unsigned char * omd5 = ofi->md5s + (16 * ofi->i);
142 const unsigned char * nmd5 = nfi->md5s + (16 * nfi->i);
143 if (domd5(fn, buffer, 0, NULL))
144 return FA_CREATE; /* assume file has been removed */
145 if (!memcmp(omd5, buffer, 16))
146 return FA_CREATE; /* unmodified config file, replace. */
147 if (!memcmp(omd5, nmd5, 16))
148 return FA_SKIP; /* identical file, don't bother. */
151 const char * omd5 = ofi->fmd5s[ofi->i];
152 const char * nmd5 = nfi->fmd5s[nfi->i];
153 if (domd5(fn, buffer, 1, NULL))
154 return FA_CREATE; /* assume file has been removed */
155 if (!strcmp(omd5, buffer))
156 return FA_CREATE; /* unmodified config file, replace. */
157 if (!strcmp(omd5, nmd5))
158 return FA_SKIP; /* identical file, don't bother. */
161 } else /* dbWhat == LINK */ {
162 memset(buffer, 0, sizeof(buffer));
163 if (readlink(fn, buffer, sizeof(buffer) - 1) == -1)
164 return FA_CREATE; /* assume file has been removed */
165 if (!strcmp(ofi->flinks[ofi->i], buffer))
166 return FA_CREATE; /* unmodified config file, replace. */
167 if (!strcmp(ofi->flinks[ofi->i], nfi->flinks[nfi->i]))
168 return FA_SKIP; /* identical file, don't bother. */
172 * The config file on the disk has been modified, but
173 * the ones in the two packages are different. It would
174 * be nice if RPM was smart enough to at least try and
175 * merge the difference ala CVS, but...
184 static int filecmp(rpmfi afi, rpmfi bfi)
187 fileTypes awhat = whatis(afi->fmodes[afi->i]);
188 fileTypes bwhat = whatis(bfi->fmodes[bfi->i]);
190 if (awhat != bwhat) return 1;
193 const char * alink = afi->flinks[afi->i];
194 const char * blink = bfi->flinks[bfi->i];
195 return strcmp(alink, blink);
196 } else if (awhat == REG) {
198 if (afi->md5s != NULL && bfi->md5s != NULL) {
200 const unsigned char * amd5 = afi->md5s + (16 * afi->i);
201 const unsigned char * bmd5 = bfi->md5s + (16 * bfi->i);
202 return memcmp(amd5, bmd5, 16);
205 const char * amd5 = afi->fmd5s[afi->i];
206 const char * bmd5 = bfi->fmd5s[bfi->i];
207 return strcmp(amd5, bmd5);
218 /* XXX only ts->{probs,rpmdb} modified */
220 static int handleInstInstalledFiles(const rpmts ts,
222 sharedFileInfo shared,
223 int sharedCount, int reportConflicts)
224 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
225 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
227 const char * altNEVR = NULL;
228 rpmfi otherFi = NULL;
233 { rpmdbMatchIterator mi;
237 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
238 &shared->otherPkg, sizeof(shared->otherPkg));
239 while ((h = rpmdbNextIterator(mi)) != NULL) {
240 altNEVR = hGetNEVR(h, NULL);
241 otherFi = rpmfiNew(ts, NULL, h, RPMTAG_BASENAMES, scareMem);
244 mi = rpmdbFreeIterator(mi);
250 fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
252 ps = rpmtsProblems(ts);
253 for (i = 0; i < sharedCount; i++, shared++) {
254 int otherFileNum, fileNum;
256 otherFileNum = shared->otherFileNum;
257 (void) rpmfiSetFX(otherFi, otherFileNum);
259 fileNum = shared->pkgFileNum;
260 (void) rpmfiSetFX(fi, fileNum);
263 /* XXX another tedious segfault, assume file state normal. */
264 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
268 if (XFA_SKIPPING(fi->actions[fileNum]))
271 if (filecmp(otherFi, fi)) {
272 if (reportConflicts) {
273 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
274 rpmteNEVR(p), rpmteKey(p),
275 rpmfiDN(fi), rpmfiBN(fi),
279 if (!(rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG) {
280 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
281 if (!shared->isRemoved)
282 fi->replaced[numReplaced++] = *shared;
287 if ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG) {
289 action = decideFileFate(ts, otherFi, fi);
290 fi->actions[fileNum] = action;
292 fi->replacedSizes[fileNum] = otherFi->fsizes[otherFi->i];
297 altNEVR = _free(altNEVR);
298 otherFi = rpmfiFree(otherFi, 1);
300 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
301 sizeof(*fi->replaced) * (numReplaced + 1));
302 fi->replaced[numReplaced].otherPkg = 0;
310 /* XXX only ts->rpmdb modified */
311 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
312 sharedFileInfo shared, int sharedCount)
313 /*@globals rpmGlobalMacroContext, fileSystem, internalState @*/
314 /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
318 const char * otherStates;
321 rpmdbMatchIterator mi;
323 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
324 &shared->otherPkg, sizeof(shared->otherPkg));
325 h = rpmdbNextIterator(mi);
327 mi = rpmdbFreeIterator(mi);
331 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
334 for (i = 0; i < sharedCount; i++, shared++) {
335 int otherFileNum, fileNum;
336 otherFileNum = shared->otherFileNum;
337 fileNum = shared->pkgFileNum;
339 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
342 fi->actions[fileNum] = FA_SKIP;
346 mi = rpmdbFreeIterator(mi);
351 #define ISROOT(_d) (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
354 static int _fps_debug = 0;
356 static int fpsCompare (const void * one, const void * two)
359 const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
360 const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
361 int adnlen = strlen(a->entry->dirName);
362 int asnlen = (a->subDir ? strlen(a->subDir) : 0);
363 int abnlen = strlen(a->baseName);
364 int bdnlen = strlen(b->entry->dirName);
365 int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
366 int bbnlen = strlen(b->baseName);
367 char * afn, * bfn, * t;
370 if (adnlen == 1 && asnlen != 0) adnlen = 0;
371 if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
374 afn = t = alloca(adnlen+asnlen+abnlen+2);
375 if (adnlen) t = stpcpy(t, a->entry->dirName);
377 if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
378 if (abnlen) t = stpcpy(t, a->baseName);
379 if (afn[0] == '/' && afn[1] == '/') afn++;
381 bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
382 if (bdnlen) t = stpcpy(t, b->entry->dirName);
384 if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
385 if (bbnlen) t = stpcpy(t, b->baseName);
386 if (bfn[0] == '/' && bfn[1] == '/') bfn++;
389 rc = strcmp(afn, bfn);
392 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
397 fprintf(stderr, "\t%s/%s%s\trc %d\n",
398 ISROOT(b->entry->dirName),
399 (b->subDir ? b->subDir : ""),
409 static int _linear_fps_search = 0;
411 static int findFps(const struct fingerPrint_s * fiFps,
412 const struct fingerPrint_s * otherFps,
420 fprintf(stderr, "==> %s/%s%s\n",
421 ISROOT(fiFps->entry->dirName),
422 (fiFps->subDir ? fiFps->subDir : ""),
426 if (_linear_fps_search) {
429 for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
433 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
434 ISROOT(otherFps->entry->dirName),
435 (otherFps->subDir ? otherFps->subDir : ""),
439 /* If the addresses are the same, so are the values. */
440 if (fiFps == otherFps)
443 /* Otherwise, compare fingerprints by value. */
444 /*@-nullpass@*/ /* LCL: looks good to me */
445 if (FP_EQUAL((*fiFps), (*otherFps)))
450 if (otherFileNum == otherFc) {
453 fprintf(stderr, "*** NULL %s/%s%s\n",
454 ISROOT(fiFps->entry->dirName),
455 (fiFps->subDir ? fiFps->subDir : ""),
464 const struct fingerPrint_s * bingoFps;
467 bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
469 if (bingoFps == NULL) {
471 fprintf(stderr, "*** NULL %s/%s%s\n",
472 ISROOT(fiFps->entry->dirName),
473 (fiFps->subDir ? fiFps->subDir : ""),
479 /* If the addresses are the same, so are the values. */
480 /*@-nullpass@*/ /* LCL: looks good to me */
481 if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
483 fprintf(stderr, "*** BAD %s/%s%s\n",
484 ISROOT(bingoFps->entry->dirName),
485 (bingoFps->subDir ? bingoFps->subDir : ""),
491 otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
499 * Update disk space needs on each partition for this package's files.
501 /* XXX only ts->{probs,di} modified */
502 static void handleOverlappedFiles(const rpmts ts,
503 const rpmte p, rpmfi fi)
504 /*@globals fileSystem, internalState @*/
505 /*@modifies ts, fi, fileSystem, internalState @*/
507 uint_32 fixupSize = 0;
512 ps = rpmtsProblems(ts);
513 fi = rpmfiInit(fi, 0);
515 while ((i = rpmfiNext(fi)) >= 0) {
516 struct fingerPrint_s * fiFps;
517 int otherPkgNum, otherFileNum;
522 if (XFA_SKIPPING(fi->actions[i]))
531 * Retrieve all records that apply to this file. Note that the
532 * file info records were built in the same order as the packages
533 * will be installed and removed so the records for an overlapped
534 * files will be sorted in exactly the same order.
536 (void) htGetEntry(ts->ht, fiFps,
537 (const void ***) &recs, &numRecs, NULL);
540 * If this package is being added, look only at other packages
541 * being added -- removed packages dance to a different tune.
543 * If both this and the other package are being added, overlapped
544 * files must be identical (or marked as a conflict). The
545 * disposition of already installed config files leads to
546 * a small amount of extra complexity.
548 * If this package is being removed, then there are two cases that
549 * need to be worried about:
550 * If the other package is being added, then skip any overlapped files
551 * so that this package removal doesn't nuke the overlapped files
552 * that were just installed.
553 * If both this and the other package are being removed, then each
554 * file removal from preceding packages needs to be skipped so that
555 * the file removal occurs only on the last occurence of an overlapped
556 * file in the transaction set.
560 /* Locate this overlapped file in the set of added/removed packages. */
561 for (j = 0; j < numRecs && recs[j] != fi; j++)
564 /* Find what the previous disposition of this file was. */
565 otherFileNum = -1; /* keep gcc quiet */
567 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
568 struct fingerPrint_s * otherFps;
571 otherFi = recs[otherPkgNum];
573 /* Added packages need only look at other added packages. */
574 if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
575 /*@innercontinue@*/ continue;
577 otherFps = otherFi->fps;
578 otherFc = rpmfiFC(otherFi);
580 otherFileNum = findFps(fiFps, otherFps, otherFc);
581 (void) rpmfiSetFX(otherFi, otherFileNum);
583 /* XXX Happens iff fingerprint for incomplete package install. */
584 if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
585 /*@innerbreak@*/ break;
589 switch (rpmteType(p)) {
592 if (otherPkgNum < 0) {
593 /* XXX is this test still necessary? */
594 if (fi->actions[i] != FA_UNKNOWN)
595 /*@switchbreak@*/ break;
596 if ((rpmfiFFlags(fi) & RPMFILE_CONFIG) &&
598 /* Here is a non-overlapped pre-existing config file. */
599 fi->actions[i] = (rpmfiFFlags(fi) & RPMFILE_NOREPLACE)
600 ? FA_ALTNAME : FA_BACKUP;
602 fi->actions[i] = FA_CREATE;
604 /*@switchbreak@*/ break;
607 assert(otherFi != NULL);
608 /* Mark added overlapped non-identical files as a conflict. */
609 if ((rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES)
610 && filecmp(otherFi, fi))
612 rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
613 rpmteNEVR(p), rpmteKey(p),
615 rpmteNEVR(otherFi->te),
619 /* Try to get the disk accounting correct even if a conflict. */
620 fixupSize = otherFi->fsizes[otherFileNum];
622 if ((rpmfiFFlags(fi) & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
623 /* Here is an overlapped pre-existing config file. */
624 fi->actions[i] = (rpmfiFFlags(fi) & RPMFILE_NOREPLACE)
625 ? FA_ALTNAME : FA_SKIP;
627 fi->actions[i] = FA_CREATE;
629 } /*@switchbreak@*/ break;
632 if (otherPkgNum >= 0) {
633 assert(otherFi != NULL);
634 /* Here is an overlapped added file we don't want to nuke. */
635 if (otherFi->actions[otherFileNum] != FA_ERASE) {
636 /* On updates, don't remove files. */
637 fi->actions[i] = FA_SKIP;
638 /*@switchbreak@*/ break;
640 /* Here is an overlapped removed file: skip in previous. */
641 otherFi->actions[otherFileNum] = FA_SKIP;
643 if (XFA_SKIPPING(fi->actions[i]))
644 /*@switchbreak@*/ break;
645 if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
646 /*@switchbreak@*/ break;
647 if (!(S_ISREG(fi->fmodes[i]) && (rpmfiFFlags(fi) & RPMFILE_CONFIG))) {
648 fi->actions[i] = FA_ERASE;
649 /*@switchbreak@*/ break;
652 /* Here is a pre-existing modified config file that needs saving. */
654 const unsigned char * MD5 = fi->md5s + (16 * i);
655 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
656 fi->actions[i] = FA_BACKUP;
657 /*@switchbreak@*/ break;
660 fi->actions[i] = FA_ERASE;
661 /*@switchbreak@*/ break;
665 /* Update disk space info for a file. */
666 rpmtsUpdateDSI(ts, fi->fps[i].entry->dev,
667 fi->fsizes[i], fi->replacedSizes[i], fixupSize, fi->actions[i]);
674 * Ensure that current package is newer than installed package.
675 * @param ts transaction set
676 * @param p current transaction element
677 * @param h installed header
678 * @return 0 if not newer, 1 if okay
680 static int ensureOlder(rpmts ts,
681 const rpmte p, const Header h)
684 int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
691 if (p == NULL || h == NULL)
695 nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
699 if (rpmteE(p) != NULL) t = stpcpy( stpcpy(t, rpmteE(p)), ":");
700 if (rpmteV(p) != NULL) t = stpcpy(t, rpmteV(p));
702 if (rpmteR(p) != NULL) t = stpcpy(t, rpmteR(p));
705 req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
706 rc = headerMatchesDepFlags(h, req);
707 req = rpmdsFree(req);
710 rpmps ps = rpmtsProblems(ts);
711 const char * altNEVR = hGetNEVR(h, NULL);
712 rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
713 rpmteNEVR(p), rpmteKey(p),
717 altNEVR = _free(altNEVR);
728 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
730 static void skipFiles(const rpmts ts, rpmfi fi)
731 /*@globals rpmGlobalMacroContext @*/
732 /*@modifies fi, rpmGlobalMacroContext @*/
734 int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
735 char ** netsharedPaths = NULL;
736 const char ** languages;
737 const char * dn, * bn;
738 int dnlen, bnlen, ix;
746 noDocs = rpmExpandNumeric("%{_excludedocs}");
748 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
750 if (tmpPath && *tmpPath != '%')
751 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
753 tmpPath = _free(tmpPath);
756 s = rpmExpand("%{_install_langs}", NULL);
758 if (!(s && *s != '%'))
761 languages = (const char **) splitString(s, strlen(s), ':');
767 /* Compute directory refcount, skip directory if now empty. */
769 drc = alloca(dc * sizeof(*drc));
770 memset(drc, 0, dc * sizeof(*drc));
771 dff = alloca(dc * sizeof(*dff));
772 memset(dff, 0, dc * sizeof(*dff));
774 fi = rpmfiInit(fi, 0);
775 if (fi != NULL) /* XXX lclint */
776 while ((i = rpmfiNext(fi)) >= 0)
786 continue; /* XXX can't happen */
790 /* Don't bother with skipped files */
791 if (XFA_SKIPPING(fi->actions[i])) {
797 * Skip net shared paths.
798 * Net shared paths are not relative to the current root (though
799 * they do need to take package relocations into account).
801 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
806 if (strncmp(dn, *nsp, len))
807 /*@innercontinue@*/ continue;
808 /* Only directories or complete file paths can be net shared */
809 if (!(dn[len] == '/' || dn[len] == '\0'))
810 /*@innercontinue@*/ continue;
812 if (len < (dnlen + bnlen))
813 /*@innercontinue@*/ continue;
814 if (strncmp(dn, *nsp, dnlen))
815 /*@innercontinue@*/ continue;
816 if (strncmp(bn, (*nsp) + dnlen, bnlen))
817 /*@innercontinue@*/ continue;
819 /* Only directories or complete file paths can be net shared */
820 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
821 /*@innercontinue@*/ continue;
824 /*@innerbreak@*/ break;
828 drc[ix]--; dff[ix] = 1;
829 fi->actions[i] = FA_SKIPNETSHARED;
834 * Skip i18n language specific files.
836 if (fi->flangs && languages && *fi->flangs[i]) {
837 const char **lang, *l, *le;
838 for (lang = languages; *lang != NULL; lang++) {
839 if (!strcmp(*lang, "all"))
840 /*@innerbreak@*/ break;
841 for (l = fi->flangs[i]; *l != '\0'; l = le) {
842 for (le = l; *le != '\0' && *le != '|'; le++)
844 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
845 /*@innerbreak@*/ break;
846 if (*le == '|') le++; /* skip over | */
849 /*@innerbreak@*/ break;
852 drc[ix]--; dff[ix] = 1;
853 fi->actions[i] = FA_SKIPNSTATE;
859 * Skip documentation if requested.
861 if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
862 drc[ix]--; dff[ix] = 1;
863 fi->actions[i] = FA_SKIPNSTATE;
868 /* Skip (now empty) directories that had skipped files. */
870 if (fi != NULL) /* XXX can't happen */
871 for (j = 0; j < dc; j++)
873 if ((fi = rpmfiInitD(fi)) != NULL)
874 while (j = rpmfiNextD(fi) >= 0)
878 if (drc[j]) continue; /* dir still has files. */
879 if (!dff[j]) continue; /* dir was not emptied here. */
881 /* Find parent directory and basename. */
882 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
883 bn = dn + dnlen; bnlen = 0;
884 while (bn > dn && bn[-1] != '/') {
890 /* If explicitly included in the package, skip the directory. */
891 fi = rpmfiInit(fi, 0);
892 if (fi != NULL) /* XXX lclint */
893 while ((i = rpmfiNext(fi)) >= 0) {
896 if (XFA_SKIPPING(fi->actions[i]))
897 /*@innercontinue@*/ continue;
898 if (whatis(fi->fmodes[i]) != XDIR)
899 /*@innercontinue@*/ continue;
900 dir = fi->dnl[fi->dil[i]];
901 if (strlen(dir) != dnlen)
902 /*@innercontinue@*/ continue;
903 if (strncmp(dir, dn, dnlen))
904 /*@innercontinue@*/ continue;
905 if (strlen(fi->bnl[i]) != bnlen)
906 /*@innercontinue@*/ continue;
907 if (strncmp(fi->bnl[i], bn, bnlen))
908 /*@innercontinue@*/ continue;
909 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
910 fi->actions[i] = FA_SKIPNSTATE;
911 /*@innerbreak@*/ break;
915 if (netsharedPaths) freeSplitString(netsharedPaths);
916 #ifdef DYING /* XXX freeFi will deal with this later. */
917 fi->flangs = _free(fi->flangs);
919 if (languages) freeSplitString((char **)languages);
925 * Return transaction element's file info.
926 * @todo Take a rpmfi refcount here.
927 * @param tsi transaction element iterator
928 * @return transaction element file info
931 rpmfi rpmtsiFi(const rpmtsi tsi)
936 if (tsi != NULL && tsi->ocsave != -1) {
937 /*@-type -abstract@*/ /* FIX: rpmte not opaque */
938 rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
940 if (te != NULL && (fi = te->fi) != NULL)
943 /*@=type =abstract@*/
945 /*@-compdef -refcounttrans -usereleased @*/
947 /*@=compdef =refcounttrans =usereleased @*/
950 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
952 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
956 int totalFileCount = 0;
958 sharedFileInfo shared, sharedList;
962 fingerPrintCache fpc;
964 PSM_t psm = memset(alloca(sizeof(*psm)), 0, sizeof(*psm));
969 /* FIXME: what if the same package is included in ts twice? */
971 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
972 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
973 if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
974 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
976 /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
977 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
978 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
980 ts->probs = rpmpsFree(ts->probs);
981 ts->probs = rpmpsCreate();
983 /* XXX Make sure the database is open RDWR for package install/erase. */
984 { int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
985 ? O_RDONLY : (O_RDWR|O_CREAT);
987 /* Open database RDWR for installing packages. */
988 if (rpmtsOpenDB(ts, dbmode))
989 return -1; /* XXX W2DO? */
992 ts->ignoreSet = ignoreSet;
993 { const char * currDir = currentDirectory();
994 rpmtsSetCurrDir(ts, currDir);
995 currDir = _free(currDir);
998 (void) rpmtsSetChrootDone(ts, 0);
1000 { int_32 tid = (int_32) time(NULL);
1001 (void) rpmtsSetTid(ts, tid);
1004 memset(psm, 0, sizeof(*psm));
1005 psm->ts = rpmtsLink(ts, "tsRun");
1007 /* Get available space on mounted file systems. */
1008 xx = rpmtsInitDSI(ts);
1010 /* ===============================================
1011 * For packages being installed:
1012 * - verify package arch/os.
1013 * - verify package epoch:version-release is newer.
1015 * For packages being removed:
1019 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elments\n"), rpmtsNElements(ts));
1020 ps = rpmtsProblems(ts);
1021 /* The ordering doesn't matter here */
1022 pi = rpmtsiInit(ts);
1023 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1024 rpmdbMatchIterator mi;
1027 if ((fi = rpmtsiFi(pi)) == NULL)
1028 continue; /* XXX can't happen */
1031 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
1032 if (!archOkay(rpmteA(p)))
1033 rpmpsAppend(ps, RPMPROB_BADARCH,
1034 rpmteNEVR(p), rpmteKey(p),
1038 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1039 if (!osOkay(rpmteO(p)))
1040 rpmpsAppend(ps, RPMPROB_BADOS,
1041 rpmteNEVR(p), rpmteKey(p),
1045 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1047 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1048 while ((h = rpmdbNextIterator(mi)) != NULL)
1049 xx = ensureOlder(ts, p, h);
1050 mi = rpmdbFreeIterator(mi);
1053 /* XXX multilib should not display "already installed" problems */
1054 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG) && !rpmteMultiLib(p)) {
1055 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1056 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1058 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1061 while (rpmdbNextIterator(mi) != NULL) {
1062 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1063 rpmteNEVR(p), rpmteKey(p),
1066 /*@innerbreak@*/ break;
1068 mi = rpmdbFreeIterator(mi);
1071 /* Count no. of files (if any). */
1072 totalFileCount += fc;
1075 pi = rpmtsiFree(pi);
1078 /* The ordering doesn't matter here */
1079 pi = rpmtsiInit(ts);
1080 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1083 if ((fi = rpmtsiFi(pi)) == NULL)
1084 continue; /* XXX can't happen */
1087 totalFileCount += fc;
1089 pi = rpmtsiFree(pi);
1091 /* ===============================================
1092 * Initialize transaction element file info for package:
1096 * FIXME?: we'd be better off assembling one very large file list and
1097 * calling fpLookupList only once. I'm not sure that the speedup is
1098 * worth the trouble though.
1100 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
1101 pi = rpmtsiInit(ts);
1102 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1105 if ((fi = rpmtsiFi(pi)) == NULL)
1106 continue; /* XXX can't happen */
1109 #ifdef DYING /* XXX W2DO? this is now done in rpmtsiFi, okay ??? */
1110 fi->magic = RPMFIMAGIC;
1115 switch (rpmteType(p)) {
1118 /* Skip netshared paths, not our i18n files, and excluded docs */
1121 /*@switchbreak@*/ break;
1123 fi->record = rpmteDBOffset(p);
1124 /*@switchbreak@*/ break;
1128 fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1130 pi = rpmtsiFree(pi);
1132 if (!rpmtsChrootDone(ts)) {
1133 const char * rootDir = rpmtsRootDir(ts);
1135 /*@-superuser -noeffect @*/
1136 if (rootDir != NULL)
1137 xx = chroot(rootDir);
1138 /*@=superuser =noeffect @*/
1139 (void) rpmtsSetChrootDone(ts, 1);
1142 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1143 fpc = fpCacheCreate(totalFileCount);
1145 /* ===============================================
1146 * Add fingerprint for each file not skipped.
1148 pi = rpmtsiInit(ts);
1149 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1152 if ((fi = rpmtsiFi(pi)) == NULL)
1153 continue; /* XXX can't happen */
1156 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1158 fi = rpmfiInit(fi, 0);
1159 if (fi != NULL) /* XXX lclint */
1160 while ((i = rpmfiNext(fi)) >= 0) {
1161 if (XFA_SKIPPING(fi->actions[i]))
1162 /*@innercontinue@*/ continue;
1163 /*@-dependenttrans@*/
1164 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1165 /*@=dependenttrans@*/
1169 pi = rpmtsiFree(pi);
1171 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1172 NULL, ts->notifyData));
1174 /* ===============================================
1175 * Compute file disposition for each package in transaction set.
1177 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
1178 ps = rpmtsProblems(ts);
1179 pi = rpmtsiInit(ts);
1180 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1181 dbiIndexSet * matches;
1185 if ((fi = rpmtsiFi(pi)) == NULL)
1186 continue; /* XXX can't happen */
1189 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1190 ts->orderCount, NULL, ts->notifyData));
1192 if (fc == 0) continue;
1194 /* Extract file info for all files in this package from the database. */
1195 matches = xcalloc(fc, sizeof(*matches));
1196 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1197 psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1199 return 1; /* XXX WTFO? */
1203 fi = rpmfiInit(fi, 0);
1204 while ((i = rpmfiNext(fi)) >= 0)
1205 numShared += dbiIndexSetCount(matches[i]);
1207 /* Build sorted file info list for this package. */
1208 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1210 fi = rpmfiInit(fi, 0);
1211 while ((i = rpmfiNext(fi)) >= 0) {
1213 * Take care not to mark files as replaced in packages that will
1214 * have been removed before we will get here.
1216 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1218 ro = dbiIndexRecordOffset(matches[i], j);
1220 qi = rpmtsiInit(ts);
1221 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1223 /*@innerbreak@*/ break;
1224 if (rpmteDBOffset(q) == ro)
1227 qi = rpmtsiFree(qi);
1229 shared->pkgFileNum = i;
1230 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1231 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1232 shared->isRemoved = (knownBad == ro);
1235 matches[i] = dbiFreeIndexSet(matches[i]);
1237 numShared = shared - sharedList;
1238 shared->otherPkg = -1;
1239 matches = _free(matches);
1241 /* Sort file info by other package index (otherPkg) */
1242 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1244 /* For all files from this package that are in the database ... */
1246 for (i = 0; i < numShared; i = nexti) {
1249 shared = sharedList + i;
1251 /* Find the end of the files in the other package. */
1252 for (nexti = i + 1; nexti < numShared; nexti++) {
1253 if (sharedList[nexti].otherPkg != shared->otherPkg)
1254 /*@innerbreak@*/ break;
1257 /* Is this file from a package being removed? */
1259 if (ts->removedPackages != NULL)
1260 for (j = 0; j < ts->numRemovedPackages; j++) {
1261 if (ts->removedPackages[j] != shared->otherPkg)
1262 /*@innercontinue@*/ continue;
1264 /*@innerbreak@*/ break;
1267 /* Determine the fate of each file. */
1268 switch (rpmteType(p)) {
1270 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1271 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1272 /*@switchbreak@*/ break;
1275 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1276 /*@switchbreak@*/ break;
1283 /* Update disk space needs on each partition for this package. */
1284 handleOverlappedFiles(ts, p, fi);
1286 /* Check added package has sufficient space on each partition used. */
1287 switch (rpmteType(p)) {
1289 rpmtsCheckDSIProblems(ts, p);
1290 /*@switchbreak@*/ break;
1292 /*@switchbreak@*/ break;
1295 pi = rpmtsiFree(pi);
1298 if (rpmtsChrootDone(ts)) {
1299 const char * currDir = rpmtsCurrDir(ts);
1300 /*@-superuser -noeffect @*/
1302 /*@=superuser =noeffect @*/
1303 (void) rpmtsSetChrootDone(ts, 0);
1304 if (currDir != NULL)
1305 xx = chdir(currDir);
1308 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1309 NULL, ts->notifyData));
1311 /* ===============================================
1312 * Free unused memory as soon as possible.
1314 pi = rpmtsiInit(ts);
1315 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1316 if ((fi = rpmtsiFi(pi)) == NULL)
1317 continue; /* XXX can't happen */
1318 if (rpmfiFC(fi) == 0)
1320 fi->fps = _free(fi->fps);
1322 pi = rpmtsiFree(pi);
1324 fpc = fpCacheFree(fpc);
1325 ts->ht = htFree(ts->ht);
1327 /* ===============================================
1328 * If unfiltered problems exist, free memory and return.
1330 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1331 || (ts->probs->numProblems &&
1332 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1335 if (psm->ts != NULL)
1336 psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1337 return ts->orderCount;
1340 /* ===============================================
1341 * Save removed files before erasing.
1343 rpmMessage(RPMMESS_DEBUG, _("repackage about-to-be-erased packages\n"));
1344 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1345 pi = rpmtsiInit(ts);
1346 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1348 switch (rpmteType(p)) {
1350 /*@switchbreak@*/ break;
1352 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1353 /*@switchbreak@*/ break;
1355 psm->fi = rpmfiLink(fi, "tsRepackage");
1356 xx = psmStage(psm, PSM_PKGSAVE);
1357 (void) rpmfiUnlink(fi, "tsRepackage");
1360 /*@switchbreak@*/ break;
1363 pi = rpmtsiFree(pi);
1366 /* ===============================================
1367 * Install and remove packages.
1369 rpmMessage(RPMMESS_DEBUG, _("install/erase %d elements\n"), rpmtsNElements(ts));
1370 lastKey = (alKey)-2; /* erased packages have -1 */
1371 pi = rpmtsiInit(ts);
1372 /*@-branchstate@*/ /* FIX: fi reload needs work */
1373 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1378 if ((fi = rpmtsiFi(pi)) == NULL)
1379 continue; /* XXX can't happen */
1382 psm->fi = rpmfiLink(fi, "tsInstall");
1383 switch (rpmteType(p)) {
1386 pkgKey = rpmteAddedKey(p);
1388 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1390 /*@-type@*/ /* FIX: rpmte not opaque */
1392 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1393 p->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1394 rpmteKey(p), ts->notifyData);
1395 /*@=noeffectuncon@*/
1396 if (rpmteFd(p) != NULL) {
1399 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1402 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1403 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1404 p->fd = ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1406 rpmteKey(p), ts->notifyData);
1407 /*@=noeffectuncon@*/
1411 if (rpmteFd(p) != NULL) gotfd = 1;
1416 if (rpmteFd(p) != NULL) {
1418 char * fstates = fi->fstates;
1419 fileAction * actions = fi->actions;
1423 psm->fi = rpmfiFree(psm->fi, 1);
1424 (void) rpmfiFree(fi, 0);
1426 fi->magic = RPMFIMAGIC;
1429 (void) rpmfiNew(ts, fi, p->h, RPMTAG_BASENAMES, 1);
1430 psm->fi = rpmfiLink(fi, "tsInstall");
1431 fi->fstates = _free(fi->fstates);
1432 fi->fstates = fstates;
1433 fi->actions = _free(fi->actions);
1434 fi->actions = actions;
1438 if (rpmteMultiLib(p))
1439 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_MULTILIB));
1441 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) & ~RPMTRANS_FLAG_MULTILIB));
1443 if (psmStage(psm, PSM_PKGINSTALL)) {
1447 fi->h = headerFree(fi->h);
1453 p->h = headerFree(p->h);
1456 /*@-noeffectuncon @*/ /* FIX: check rc */
1457 (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1458 rpmteKey(p), ts->notifyData);
1459 /*@=noeffectuncon @*/
1464 /*@switchbreak@*/ break;
1466 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1467 /* If install failed, then we shouldn't erase. */
1468 if (rpmteDependsOnKey(p) != lastKey) {
1469 if (psmStage(psm, PSM_PKGERASE))
1472 /*@switchbreak@*/ break;
1474 xx = rpmdbSync(rpmtsGetRdb(ts));
1475 (void) rpmfiUnlink(psm->fi, "tsInstall");
1478 /*@-type@*/ /* FIX: p is almost opaque */
1479 p->fi = rpmfiFree(fi, 1);
1483 pi = rpmtsiFree(pi);
1485 psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1487 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */