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 fileSystem, internalState @*/
225 /*@modifies ts, fi, 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 fileSystem, internalState @*/
314 /*@modifies ts, fi, 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:
1018 ps = rpmtsProblems(ts);
1019 /* The ordering doesn't matter here */
1020 pi = rpmtsiInit(ts);
1021 while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
1022 rpmdbMatchIterator mi;
1025 if ((fi = rpmtsiFi(pi)) == NULL)
1026 continue; /* XXX can't happen */
1029 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
1030 if (!archOkay(rpmteA(p)))
1031 rpmpsAppend(ps, RPMPROB_BADARCH,
1032 rpmteNEVR(p), rpmteKey(p),
1036 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
1037 if (!osOkay(rpmteO(p)))
1038 rpmpsAppend(ps, RPMPROB_BADOS,
1039 rpmteNEVR(p), rpmteKey(p),
1043 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
1045 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1046 while ((h = rpmdbNextIterator(mi)) != NULL)
1047 xx = ensureOlder(ts, p, h);
1048 mi = rpmdbFreeIterator(mi);
1051 /* XXX multilib should not display "already installed" problems */
1052 if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG) && !rpmteMultiLib(p)) {
1053 mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
1054 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1056 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1059 while (rpmdbNextIterator(mi) != NULL) {
1060 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
1061 rpmteNEVR(p), rpmteKey(p),
1064 /*@innerbreak@*/ break;
1066 mi = rpmdbFreeIterator(mi);
1069 /* Count no. of files (if any). */
1070 totalFileCount += fc;
1073 pi = rpmtsiFree(pi);
1076 /* The ordering doesn't matter here */
1077 pi = rpmtsiInit(ts);
1078 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
1081 if ((fi = rpmtsiFi(pi)) == NULL)
1082 continue; /* XXX can't happen */
1085 totalFileCount += fc;
1087 pi = rpmtsiFree(pi);
1089 /* ===============================================
1090 * Initialize transaction element file info for package:
1094 * FIXME?: we'd be better off assembling one very large file list and
1095 * calling fpLookupList only once. I'm not sure that the speedup is
1096 * worth the trouble though.
1098 pi = rpmtsiInit(ts);
1099 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1102 if ((fi = rpmtsiFi(pi)) == NULL)
1103 continue; /* XXX can't happen */
1106 #ifdef DYING /* XXX W2DO? this is now done in rpmtsiFi, okay ??? */
1107 fi->magic = RPMFIMAGIC;
1112 switch (rpmteType(p)) {
1115 /* Skip netshared paths, not our i18n files, and excluded docs */
1118 /*@switchbreak@*/ break;
1120 fi->record = rpmteDBOffset(p);
1121 /*@switchbreak@*/ break;
1125 fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
1127 pi = rpmtsiFree(pi);
1129 if (!rpmtsChrootDone(ts)) {
1130 const char * rootDir = rpmtsRootDir(ts);
1132 /*@-superuser -noeffect @*/
1133 if (rootDir != NULL)
1134 xx = chroot(rootDir);
1135 /*@=superuser =noeffect @*/
1136 (void) rpmtsSetChrootDone(ts, 1);
1139 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1140 fpc = fpCacheCreate(totalFileCount);
1142 /* ===============================================
1143 * Add fingerprint for each file not skipped.
1145 pi = rpmtsiInit(ts);
1146 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1149 if ((fi = rpmtsiFi(pi)) == NULL)
1150 continue; /* XXX can't happen */
1153 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
1155 fi = rpmfiInit(fi, 0);
1156 if (fi != NULL) /* XXX lclint */
1157 while ((i = rpmfiNext(fi)) >= 0) {
1158 if (XFA_SKIPPING(fi->actions[i]))
1159 /*@innercontinue@*/ continue;
1160 /*@-dependenttrans@*/
1161 htAddEntry(ts->ht, fi->fps + i, (void *) fi);
1162 /*@=dependenttrans@*/
1166 pi = rpmtsiFree(pi);
1168 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1169 NULL, ts->notifyData));
1171 /* ===============================================
1172 * Compute file disposition for each package in transaction set.
1174 ps = rpmtsProblems(ts);
1175 pi = rpmtsiInit(ts);
1176 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1177 dbiIndexSet * matches;
1181 if ((fi = rpmtsiFi(pi)) == NULL)
1182 continue; /* XXX can't happen */
1185 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
1186 ts->orderCount, NULL, ts->notifyData));
1188 if (fc == 0) continue;
1190 /* Extract file info for all files in this package from the database. */
1191 matches = xcalloc(fc, sizeof(*matches));
1192 if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
1193 psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1195 return 1; /* XXX WTFO? */
1199 fi = rpmfiInit(fi, 0);
1200 while ((i = rpmfiNext(fi)) >= 0)
1201 numShared += dbiIndexSetCount(matches[i]);
1203 /* Build sorted file info list for this package. */
1204 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1206 fi = rpmfiInit(fi, 0);
1207 while ((i = rpmfiNext(fi)) >= 0) {
1209 * Take care not to mark files as replaced in packages that will
1210 * have been removed before we will get here.
1212 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1214 ro = dbiIndexRecordOffset(matches[i], j);
1216 qi = rpmtsiInit(ts);
1217 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
1219 /*@innerbreak@*/ break;
1220 if (rpmteDBOffset(q) == ro)
1223 qi = rpmtsiFree(qi);
1225 shared->pkgFileNum = i;
1226 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1227 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1228 shared->isRemoved = (knownBad == ro);
1231 matches[i] = dbiFreeIndexSet(matches[i]);
1233 numShared = shared - sharedList;
1234 shared->otherPkg = -1;
1235 matches = _free(matches);
1237 /* Sort file info by other package index (otherPkg) */
1238 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1240 /* For all files from this package that are in the database ... */
1242 for (i = 0; i < numShared; i = nexti) {
1245 shared = sharedList + i;
1247 /* Find the end of the files in the other package. */
1248 for (nexti = i + 1; nexti < numShared; nexti++) {
1249 if (sharedList[nexti].otherPkg != shared->otherPkg)
1250 /*@innerbreak@*/ break;
1253 /* Is this file from a package being removed? */
1255 if (ts->removedPackages != NULL)
1256 for (j = 0; j < ts->numRemovedPackages; j++) {
1257 if (ts->removedPackages[j] != shared->otherPkg)
1258 /*@innercontinue@*/ continue;
1260 /*@innerbreak@*/ break;
1263 /* Determine the fate of each file. */
1264 switch (rpmteType(p)) {
1266 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1267 !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
1268 /*@switchbreak@*/ break;
1271 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1272 /*@switchbreak@*/ break;
1279 /* Update disk space needs on each partition for this package. */
1280 handleOverlappedFiles(ts, p, fi);
1282 /* Check added package has sufficient space on each partition used. */
1283 switch (rpmteType(p)) {
1285 rpmtsCheckDSIProblems(ts, p);
1286 /*@switchbreak@*/ break;
1288 /*@switchbreak@*/ break;
1291 pi = rpmtsiFree(pi);
1294 if (rpmtsChrootDone(ts)) {
1295 const char * currDir = rpmtsCurrDir(ts);
1296 /*@-superuser -noeffect @*/
1298 /*@=superuser =noeffect @*/
1299 (void) rpmtsSetChrootDone(ts, 0);
1300 if (currDir != NULL)
1301 xx = chdir(currDir);
1304 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1305 NULL, ts->notifyData));
1307 /* ===============================================
1308 * Free unused memory as soon as possible.
1310 pi = rpmtsiInit(ts);
1311 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1312 if ((fi = rpmtsiFi(pi)) == NULL)
1313 continue; /* XXX can't happen */
1314 if (rpmfiFC(fi) == 0)
1316 fi->fps = _free(fi->fps);
1318 pi = rpmtsiFree(pi);
1320 fpc = fpCacheFree(fpc);
1321 ts->ht = htFree(ts->ht);
1323 /* ===============================================
1324 * If unfiltered problems exist, free memory and return.
1326 if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
1327 || (ts->probs->numProblems &&
1328 (okProbs != NULL || rpmpsTrim(ts->probs, okProbs)))
1331 if (psm->ts != NULL)
1332 psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1333 return ts->orderCount;
1336 /* ===============================================
1337 * Save removed files before erasing.
1339 if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1340 pi = rpmtsiInit(ts);
1341 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1343 switch (rpmteType(p)) {
1345 /*@switchbreak@*/ break;
1347 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
1348 /*@switchbreak@*/ break;
1350 psm->fi = rpmfiLink(fi, "tsRepackage");
1351 xx = psmStage(psm, PSM_PKGSAVE);
1352 (void) rpmfiUnlink(fi, "tsRepackage");
1355 /*@switchbreak@*/ break;
1358 pi = rpmtsiFree(pi);
1361 /* ===============================================
1362 * Install and remove packages.
1364 lastKey = (alKey)-2; /* erased packages have -1 */
1365 pi = rpmtsiInit(ts);
1366 /*@-branchstate@*/ /* FIX: fi reload needs work */
1367 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1372 if ((fi = rpmtsiFi(pi)) == NULL)
1373 continue; /* XXX can't happen */
1376 psm->fi = rpmfiLink(fi, "tsInstall");
1377 switch (rpmteType(p)) {
1380 pkgKey = rpmteAddedKey(p);
1382 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", rpmteNEVR(p));
1384 /*@-type@*/ /* FIX: rpmte not opaque */
1386 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1387 p->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1388 rpmteKey(p), ts->notifyData);
1389 /*@=noeffectuncon@*/
1390 if (rpmteFd(p) != NULL) {
1393 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
1396 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1397 /*@-noeffectuncon@*/ /* FIX: notify annotations */
1398 p->fd = ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1400 rpmteKey(p), ts->notifyData);
1401 /*@=noeffectuncon@*/
1405 if (rpmteFd(p) != NULL) gotfd = 1;
1410 if (rpmteFd(p) != NULL) {
1412 char * fstates = fi->fstates;
1413 fileAction * actions = fi->actions;
1417 psm->fi = rpmfiFree(psm->fi, 1);
1418 (void) rpmfiFree(fi, 0);
1420 fi->magic = RPMFIMAGIC;
1423 (void) rpmfiNew(ts, fi, p->h, RPMTAG_BASENAMES, 1);
1424 psm->fi = rpmfiLink(fi, "tsInstall");
1425 fi->fstates = _free(fi->fstates);
1426 fi->fstates = fstates;
1427 fi->actions = _free(fi->actions);
1428 fi->actions = actions;
1432 if (rpmteMultiLib(p))
1433 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_MULTILIB));
1435 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) & ~RPMTRANS_FLAG_MULTILIB));
1437 if (psmStage(psm, PSM_PKGINSTALL)) {
1441 fi->h = headerFree(fi->h);
1447 p->h = headerFree(p->h);
1450 /*@-noeffectuncon @*/ /* FIX: check rc */
1451 (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1452 rpmteKey(p), ts->notifyData);
1453 /*@=noeffectuncon @*/
1458 /*@switchbreak@*/ break;
1460 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", rpmteNEVR(p));
1461 /* If install failed, then we shouldn't erase. */
1462 if (rpmteDependsOnKey(p) != lastKey) {
1463 if (psmStage(psm, PSM_PKGERASE))
1466 /*@switchbreak@*/ break;
1468 xx = rpmdbSync(rpmtsGetRdb(ts));
1469 (void) rpmfiUnlink(psm->fi, "tsInstall");
1472 /*@-type@*/ /* FIX: p is almost opaque */
1473 p->fi = rpmfiFree(fi, 1);
1477 pi = rpmtsiFree(pi);
1479 psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1481 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */