2 * \file lib/transaction.c
7 #define _NEED_TEITERATOR 1
12 #include <rpmmacro.h> /* XXX for rpmExpand */
15 #include "legacy.h" /* XXX mdfile */
16 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
19 /*@-redecl -exportheadervar@*/
21 extern const char * chroot_prefix;
22 /*@=redecl =exportheadervar@*/
24 /* XXX FIXME: merge with existing (broken?) tests in system.h */
25 /* portability fiddles */
26 #if STATFS_IN_SYS_STATVFS
28 # include <sys/statvfs.h>
29 #if defined(__LCLINT__)
30 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
31 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
32 /*@globals fileSystem @*/
33 /*@modifies *buf, fileSystem @*/;
34 /*@=declundef =exportheader =protoparammatch @*/
38 # if STATFS_IN_SYS_VFS
41 # if STATFS_IN_SYS_MOUNT
42 # include <sys/mount.h>
44 # if STATFS_IN_SYS_STATFS
45 # include <sys/statfs.h>
53 /*@access FD_t @*/ /* XXX compared with NULL */
54 /*@access Header @*/ /* XXX compared with NULL */
55 /*@access rpmProblemSet @*/ /* XXX need rpmProblemSetOK() */
56 /*@access dbiIndexSet @*/
64 /*@access rpmFNSet @*/
67 /*@access teIterator @*/
68 /*@access transactionElement @*/
69 /*@access rpmTransactionSet @*/
73 struct diskspaceInfo {
74 dev_t dev; /*!< file system device number. */
75 signed long bneeded; /*!< no. of blocks needed. */
76 signed long ineeded; /*!< no. of inodes needed. */
77 int bsize; /*!< file system block size. */
78 signed long bavail; /*!< no. of blocks available. */
79 signed long iavail; /*!< no. of inodes available. */
83 * Adjust for root only reserved space. On linux e2fs, this is 5%.
85 #define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
87 /* argon thought a shift optimization here was a waste of time... he's
89 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
93 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
94 /*@only@*/ /*@null@*/ TFI_t flList)
101 /*@-usereleased -onlytrans @*/ /* FIX: fi needs to be only */
102 for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
104 flList = _free(flList);
105 /*@=usereleased =onlytrans @*/
110 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
112 /*@-type@*/ /* FIX: cast? */
113 ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
117 int rpmtransGetKeys(const rpmTransactionSet ts, fnpyKey ** ep, int * nep)
121 if (nep) *nep = ts->orderCount;
126 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
127 for (oc = 0; oc < ts->orderCount; oc++, e++) {
128 switch (ts->order[oc].type) {
130 *e = ts->order[oc].key;
131 /*@switchbreak@*/ break;
134 /*@-mods@*/ /* FIX: double indirection. */
137 /*@switchbreak@*/ break;
146 static int archOkay(Header h, /*@out@*/ const char ** pkgArchPtr)
147 /*@modifies *pkgArchPtr @*/
149 const char * pkgArch;
151 int rc = 1; /* assume AOK */
153 if (pkgArchPtr != NULL) *pkgArchPtr = pkgArch = NULL;
155 /* make sure we're trying to install this on the proper architecture */
156 (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
159 if (type == RPM_INT8_TYPE) {
163 /* old arch handling */
164 rpmGetArchInfo(NULL, &archNum);
165 pkgArchNum = pkgArch;
166 if (archNum != *pkgArchNum)
171 if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
173 if (pkgArchPtr != NULL) *pkgArchPtr = pkgArch;
181 static int osOkay(Header h, /*@out@*/ const char ** pkgOsPtr)
182 /*@modifies *pkgOsPtr @*/
186 int rc = 1; /* assume AOK */
188 if (pkgOsPtr != NULL) *pkgOsPtr = pkgOs = NULL;
190 /* make sure we're trying to install this on the proper os */
191 (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
194 if (type == RPM_INT8_TYPE) {
195 /* v1 packages and v2 packages both used improper OS numbers, so just
196 deal with it hope things work */
201 if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
203 if (pkgOsPtr != NULL) *pkgOsPtr = pkgOs;
211 static int sharedCmp(const void * one, const void * two)
214 const struct sharedFileInfo * a = one;
215 const struct sharedFileInfo * b = two;
217 if (a->otherPkg < b->otherPkg)
219 else if (a->otherPkg > b->otherPkg)
227 static fileAction decideFileFate(const char * dirName,
228 const char * baseName, short dbMode,
229 const char * dbMd5, const char * dbLink, short newMode,
230 const char * newMd5, const char * newLink, int newFlags,
231 rpmtransFlags transFlags)
232 /*@globals fileSystem @*/
233 /*@modifies fileSystem @*/
236 const char * dbAttr, * newAttr;
237 fileTypes dbWhat, newWhat, diskWhat;
240 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
241 char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
243 (void) stpcpy( stpcpy(filespec, dirName), baseName);
245 if (lstat(filespec, &sb)) {
247 * The file doesn't exist on the disk. Create it unless the new
248 * package has marked it as missingok, or allfiles is requested.
250 if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
251 (newFlags & RPMFILE_MISSINGOK)) {
252 rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
260 diskWhat = whatis(sb.st_mode);
261 dbWhat = whatis(dbMode);
262 newWhat = whatis(newMode);
264 /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
265 them in older packages as well */
266 if (newWhat == XDIR) {
270 if (diskWhat != newWhat) {
272 } else if (newWhat != dbWhat && diskWhat != dbWhat) {
274 } else if (dbWhat != newWhat) {
276 } else if (dbWhat != LINK && dbWhat != REG) {
281 rc = mdfile(filespec, buffer);
284 /* assume the file has been removed, don't freak */
289 } else /* dbWhat == LINK */ {
290 memset(buffer, 0, sizeof(buffer));
291 i = readlink(filespec, buffer, sizeof(buffer) - 1);
293 /* assume the file has been removed, don't freak */
300 /* this order matters - we'd prefer to CREATE the file if at all
301 possible in case something else (like the timestamp) has changed */
303 if (!strcmp(dbAttr, buffer)) {
304 /* this config file has never been modified, so just replace it */
308 if (!strcmp(dbAttr, newAttr)) {
309 /* this file is the same in all versions of this package */
314 * The config file on the disk has been modified, but
315 * the ones in the two packages are different. It would
316 * be nice if RPM was smart enough to at least try and
317 * merge the difference ala CVS, but...
324 static int filecmp(short mode1, const char * md51, const char * link1,
325 short mode2, const char * md52, const char * link2)
328 fileTypes what1 = whatis(mode1);
329 fileTypes what2 = whatis(mode2);
331 if (what1 != what2) return 1;
334 return strcmp(link1, link2);
335 else if (what1 == REG)
336 return strcmp(md51, md52);
343 /* XXX only ts->{probs,rpmdb} modified */
344 static int handleInstInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
345 struct sharedFileInfo * shared,
346 int sharedCount, int reportConflicts)
347 /*@globals fileSystem @*/
348 /*@modifies ts, fi, fileSystem @*/
351 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
352 rpmtransFlags transFlags = ts->transFlags;
353 rpmTagType oltype, omtype;
356 const char ** otherMd5s;
357 const char ** otherLinks;
358 const char * otherStates;
359 uint_32 * otherFlags;
360 uint_32 * otherSizes;
361 uint_16 * otherModes;
365 rpmdbMatchIterator mi;
367 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
368 &shared->otherPkg, sizeof(shared->otherPkg));
369 h = rpmdbNextIterator(mi);
371 mi = rpmdbFreeIterator(mi);
375 xx = hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
376 xx = hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
377 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
378 xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
379 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
380 xx = hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
382 fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
384 for (i = 0; i < sharedCount; i++, shared++) {
385 int otherFileNum, fileNum;
386 otherFileNum = shared->otherFileNum;
387 fileNum = shared->pkgFileNum;
389 /* XXX another tedious segfault, assume file state normal. */
390 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
393 if (XFA_SKIPPING(fi->actions[fileNum]))
396 if (filecmp(otherModes[otherFileNum],
397 otherMd5s[otherFileNum],
398 otherLinks[otherFileNum],
401 fi->flinks[fileNum])) {
402 /*@-compdef@*/ /* FIX: *fi->replaced undefined */
403 if (reportConflicts) {
404 const char * pkgNEVR = fiGetNEVR(fi);
405 const char * altNEVR = hGetNEVR(h, NULL);
406 rpmProblemSetAppend(ts->probs, RPMPROB_FILE_CONFLICT,
408 fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum],
411 pkgNEVR = _free(pkgNEVR);
412 altNEVR = _free(altNEVR);
415 if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
418 if (!shared->isRemoved)
419 fi->replaced[numReplaced++] = *shared;
424 if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
425 fi->actions[fileNum] = decideFileFate(
426 fi->dnl[fi->dil[fileNum]],
428 otherModes[otherFileNum],
429 otherMd5s[otherFileNum],
430 otherLinks[otherFileNum],
438 fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
441 otherMd5s = hfd(otherMd5s, omtype);
442 otherLinks = hfd(otherLinks, oltype);
443 mi = rpmdbFreeIterator(mi);
445 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
446 sizeof(*fi->replaced) * (numReplaced + 1));
447 fi->replaced[numReplaced].otherPkg = 0;
454 /* XXX only ts->rpmdb modified */
455 static int handleRmvdInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
456 struct sharedFileInfo * shared, int sharedCount)
457 /*@globals fileSystem @*/
458 /*@modifies fi, fileSystem @*/
462 const char * otherStates;
465 rpmdbMatchIterator mi;
467 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
468 &shared->otherPkg, sizeof(shared->otherPkg));
469 h = rpmdbNextIterator(mi);
471 mi = rpmdbFreeIterator(mi);
475 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
477 for (i = 0; i < sharedCount; i++, shared++) {
478 int otherFileNum, fileNum;
479 otherFileNum = shared->otherFileNum;
480 fileNum = shared->pkgFileNum;
482 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
485 fi->actions[fileNum] = FA_SKIP;
488 mi = rpmdbFreeIterator(mi);
494 * Update disk space needs on each partition for this package.
496 /* XXX only ts->{probs,di} modified */
497 static void handleOverlappedFiles(const rpmTransactionSet ts, TFI_t fi)
498 /*@globals fileSystem @*/
499 /*@modifies ts, fi, fileSystem @*/
501 struct diskspaceInfo * ds = NULL;
502 uint_32 fixupSize = 0;
503 char * filespec = NULL;
504 int fileSpecAlloced = 0;
507 for (i = 0; i < fi->fc; i++) {
508 int otherPkgNum, otherFileNum;
512 if (XFA_SKIPPING(fi->actions[i]))
515 j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
517 if (j > fileSpecAlloced) {
518 fileSpecAlloced = j * 2;
519 filespec = xrealloc(filespec, fileSpecAlloced);
523 (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
527 while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
528 if (!ds->bsize) ds = NULL;
533 * Retrieve all records that apply to this file. Note that the
534 * file info records were built in the same order as the packages
535 * will be installed and removed so the records for an overlapped
536 * files will be sorted in exactly the same order.
538 (void) htGetEntry(ts->ht, &fi->fps[i],
539 (const void ***) &recs, &numRecs, NULL);
542 * If this package is being added, look only at other packages
543 * being added -- removed packages dance to a different tune.
544 * If both this and the other package are being added, overlapped
545 * files must be identical (or marked as a conflict). The
546 * disposition of already installed config files leads to
547 * a small amount of extra complexity.
549 * If this package is being removed, then there are two cases that
550 * need to be worried about:
551 * If the other package is being added, then skip any overlapped files
552 * so that this package removal doesn't nuke the overlapped files
553 * that were just installed.
554 * If both this and the other package are being removed, then each
555 * file removal from preceding packages needs to be skipped so that
556 * the file removal occurs only on the last occurence of an overlapped
557 * file in the transaction set.
561 /* Locate this overlapped file in the set of added/removed packages. */
562 for (j = 0; j < numRecs && recs[j] != fi; j++)
565 /* Find what the previous disposition of this file was. */
566 otherFileNum = -1; /* keep gcc quiet */
567 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
568 /* Added packages need only look at other added packages. */
569 if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
570 /*@innercontinue@*/ continue;
572 /* TESTME: there are more efficient searches in the world... */
573 for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
576 /* If the addresses are the same, so are the values. */
577 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
578 /*@innerbreak@*/ break;
580 /* Otherwise, compare fingerprints by value. */
581 /*@-nullpass@*/ /* LCL: looks good to me */
582 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
583 /*@innerbreak@*/ break;
587 /* XXX is this test still necessary? */
588 if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
589 /*@innerbreak@*/ break;
595 if (otherPkgNum < 0) {
596 /* XXX is this test still necessary? */
597 if (fi->actions[i] != FA_UNKNOWN)
598 /*@switchbreak@*/ break;
599 if ((fi->fflags[i] & RPMFILE_CONFIG) &&
600 !lstat(filespec, &sb)) {
601 /* Here is a non-overlapped pre-existing config file. */
602 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
603 ? FA_ALTNAME : FA_BACKUP;
605 fi->actions[i] = FA_CREATE;
607 /*@switchbreak@*/ break;
610 /* Mark added overlapped non-identical files as a conflict. */
611 if ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
612 && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
613 recs[otherPkgNum]->fmd5s[otherFileNum],
614 recs[otherPkgNum]->flinks[otherFileNum],
619 const char * pkgNEVR = fiGetNEVR(fi);
620 const char * altNEVR = fiGetNEVR(recs[otherPkgNum]);
621 rpmProblemSetAppend(ts->probs, RPMPROB_NEW_FILE_CONFLICT,
626 pkgNEVR = _free(pkgNEVR);
627 altNEVR = _free(altNEVR);
630 /* Try to get the disk accounting correct even if a conflict. */
631 fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
633 if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
634 /* Here is an overlapped pre-existing config file. */
635 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
636 ? FA_ALTNAME : FA_SKIP;
638 fi->actions[i] = FA_CREATE;
640 } /*@switchbreak@*/ break;
642 if (otherPkgNum >= 0) {
643 /* Here is an overlapped added file we don't want to nuke. */
644 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
645 /* On updates, don't remove files. */
646 fi->actions[i] = FA_SKIP;
647 /*@switchbreak@*/ break;
649 /* Here is an overlapped removed file: skip in previous. */
650 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
652 if (XFA_SKIPPING(fi->actions[i]))
653 /*@switchbreak@*/ break;
654 if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
655 /*@switchbreak@*/ break;
656 if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
657 fi->actions[i] = FA_ERASE;
658 /*@switchbreak@*/ break;
661 /* Here is a pre-existing modified config file that needs saving. */
663 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
664 fi->actions[i] = FA_BACKUP;
665 /*@switchbreak@*/ break;
668 fi->actions[i] = FA_ERASE;
669 /*@switchbreak@*/ break;
673 uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
675 switch (fi->actions[i]) {
681 /*@switchbreak@*/ break;
684 * FIXME: If two packages share a file (same md5sum), and
685 * that file is being replaced on disk, will ds->bneeded get
686 * decremented twice? Quite probably!
690 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
691 /*@switchbreak@*/ break;
696 /*@switchbreak@*/ break;
699 /*@switchbreak@*/ break;
702 ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
705 filespec = _free(filespec);
710 static int ensureOlder(rpmTransactionSet ts,
711 const Header h, /*@null@*/ const Header old,
712 /*@dependent@*/ /*@null@*/ const void * key)
717 if (old == NULL) return 1;
719 result = rpmVersionCompare(old, h);
722 else if (result > 0) {
723 const char * pkgNEVR = hGetNEVR(h, NULL);
724 const char * altNEVR = hGetNEVR(old, NULL);
725 /*@-evalorder@*/ /* LCL: is confused */
726 rpmProblemSetAppend(ts->probs, RPMPROB_OLDPACKAGE,
732 pkgNEVR = _free(pkgNEVR);
733 altNEVR = _free(altNEVR);
742 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
743 /*@globals rpmGlobalMacroContext @*/
744 /*@modifies fi, rpmGlobalMacroContext @*/
746 int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
747 char ** netsharedPaths = NULL;
748 const char ** languages;
749 const char * dn, * bn;
750 int dnlen, bnlen, ix;
757 noDocs = rpmExpandNumeric("%{_excludedocs}");
759 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
761 if (tmpPath && *tmpPath != '%')
762 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
764 tmpPath = _free(tmpPath);
767 s = rpmExpand("%{_install_langs}", NULL);
769 if (!(s && *s != '%'))
772 languages = (const char **) splitString(s, strlen(s), ':');
778 /* Compute directory refcount, skip directory if now empty. */
779 drc = alloca(fi->dc * sizeof(*drc));
780 memset(drc, 0, fi->dc * sizeof(*drc));
781 dff = alloca(fi->dc * sizeof(*dff));
782 memset(dff, 0, fi->dc * sizeof(*dff));
784 for (i = 0; i < fi->fc; i++) {
795 /* Don't bother with skipped files */
796 if (XFA_SKIPPING(fi->actions[i])) {
802 * Skip net shared paths.
803 * Net shared paths are not relative to the current root (though
804 * they do need to take package relocations into account).
806 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
811 if (strncmp(dn, *nsp, len))
812 /*@innercontinue@*/ continue;
813 /* Only directories or complete file paths can be net shared */
814 if (!(dn[len] == '/' || dn[len] == '\0'))
815 /*@innercontinue@*/ continue;
817 if (len < (dnlen + bnlen))
818 /*@innercontinue@*/ continue;
819 if (strncmp(dn, *nsp, dnlen))
820 /*@innercontinue@*/ continue;
821 if (strncmp(bn, (*nsp) + dnlen, bnlen))
822 /*@innercontinue@*/ continue;
824 /* Only directories or complete file paths can be net shared */
825 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
826 /*@innercontinue@*/ continue;
829 /*@innerbreak@*/ break;
833 drc[ix]--; dff[ix] = 1;
834 fi->actions[i] = FA_SKIPNETSHARED;
839 * Skip i18n language specific files.
841 if (fi->flangs && languages && *fi->flangs[i]) {
842 const char **lang, *l, *le;
843 for (lang = languages; *lang != NULL; lang++) {
844 if (!strcmp(*lang, "all"))
845 /*@innerbreak@*/ break;
846 for (l = fi->flangs[i]; *l != '\0'; l = le) {
847 for (le = l; *le != '\0' && *le != '|'; le++)
849 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
850 /*@innerbreak@*/ break;
851 if (*le == '|') le++; /* skip over | */
854 /*@innerbreak@*/ break;
857 drc[ix]--; dff[ix] = 1;
858 fi->actions[i] = FA_SKIPNSTATE;
864 * Skip documentation if requested.
866 if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
867 drc[ix]--; dff[ix] = 1;
868 fi->actions[i] = FA_SKIPNSTATE;
873 /* Skip (now empty) directories that had skipped files. */
874 for (j = 0; j < fi->dc; j++) {
876 if (drc[j]) continue; /* dir still has files. */
877 if (!dff[j]) continue; /* dir was not emptied here. */
879 /* Find parent directory and basename. */
880 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
881 bn = dn + dnlen; bnlen = 0;
882 while (bn > dn && bn[-1] != '/') {
888 /* If explicitly included in the package, skip the directory. */
889 for (i = 0; i < fi->fc; i++) {
892 if (XFA_SKIPPING(fi->actions[i]))
893 /*@innercontinue@*/ continue;
894 if (whatis(fi->fmodes[i]) != XDIR)
895 /*@innercontinue@*/ continue;
896 dir = fi->dnl[fi->dil[i]];
897 if (strlen(dir) != dnlen)
898 /*@innercontinue@*/ continue;
899 if (strncmp(dir, dn, dnlen))
900 /*@innercontinue@*/ continue;
901 if (strlen(fi->bnl[i]) != bnlen)
902 /*@innercontinue@*/ continue;
903 if (strncmp(fi->bnl[i], bn, bnlen))
904 /*@innercontinue@*/ continue;
905 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
906 fi->actions[i] = FA_SKIPNSTATE;
907 /*@innerbreak@*/ break;
911 if (netsharedPaths) freeSplitString(netsharedPaths);
912 #ifdef DYING /* XXX freeFi will deal with this later. */
913 fi->flangs = _free(fi->flangs);
915 if (languages) freeSplitString((char **)languages);
919 * Return next transaction element's file info.
920 * @param tei transaction element iterator
921 * @return nest transaction element file info, NULL on termination
923 /*@unused@*/ static inline
924 TFI_t teNextFi(teIterator tei)
929 if (teNextIterator(tei) != NULL && tei->ocsave != -1)
930 fi = tei->ts->flList + tei->ocsave;
931 /*@-compdef -onlytrans -usereleased@*/ /* FIX: ts->flList may be released */
933 /*@=compdef =onlytrans =usereleased@*/
936 #define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
938 int rpmRunTransactions( rpmTransactionSet ts,
939 rpmCallbackFunction notify, rpmCallbackData notifyData,
940 rpmProblemSet okProbs, rpmProblemSet * newProbs,
941 rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
945 int totalFileCount = 0;
947 struct diskspaceInfo * dip;
948 struct sharedFileInfo * shared, * sharedList;
951 alKey pkgKey, lastKey;
953 transactionElement p;
954 fingerPrintCache fpc;
960 int keep_header = 1; /* XXX rpmProblemSetAppend prevents dumping headers. */
962 /* FIXME: what if the same package is included in ts twice? */
964 ts->transFlags = transFlags;
965 if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
966 ts->transFlags |= (_noTransScripts | _noTransTriggers);
967 if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
968 ts->transFlags |= _noTransTriggers;
970 /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
971 if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
972 ts->transFlags |= (_noTransScripts | _noTransTriggers);
975 ts->notifyData = notifyData;
977 ts->probs = *newProbs = rpmProblemSetCreate();
978 *newProbs = rpmpsLink(ts->probs, "RunTransactions");
980 ts->ignoreSet = ignoreSet;
981 ts->currDir = _free(ts->currDir);
982 ts->currDir = currentDirectory();
984 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
985 ts->id = (int_32) time(NULL);
987 memset(psm, 0, sizeof(*psm));
989 psm->ts = rpmtsLink(ts, "tsRun");
992 /* Get available space on mounted file systems. */
993 if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
994 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
997 ts->di = _free(ts->di);
998 dip = ts->di = xcalloc((ts->filesystemCount + 1), sizeof(*ts->di));
1000 for (i = 0; (i < ts->filesystemCount) && dip; i++) {
1001 #if STATFS_IN_SYS_STATVFS
1003 memset(&sfb, 0, sizeof(sfb));
1004 if (statvfs(ts->filesystems[i], &sfb))
1008 /* This platform has the 4-argument version of the statfs call. The last two
1009 * should be the size of struct statfs and 0, respectively. The 0 is the
1010 * filesystem type, and is always 0 when statfs is called on a mounted
1011 * filesystem, as we're doing.
1013 memset(&sfb, 0, sizeof(sfb));
1014 if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
1016 memset(&sfb, 0, sizeof(sfb));
1017 if (statfs(ts->filesystems[i], &sfb))
1023 ts->di[i].bsize = sfb.f_bsize;
1024 ts->di[i].bneeded = 0;
1025 ts->di[i].ineeded = 0;
1026 #ifdef STATFS_HAS_F_BAVAIL
1027 ts->di[i].bavail = sfb.f_bavail;
1029 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1030 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1031 * it's about all we can do.
1033 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
1035 /* XXX Avoid FAT and other file systems that have not inodes. */
1036 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1039 xx = stat(ts->filesystems[i], &sb);
1040 ts->di[i].dev = sb.st_dev;
1044 if (dip) ts->di[i].bsize = 0;
1047 /* ===============================================
1048 * For packages being installed:
1049 * - verify package arch/os.
1050 * - verify package epoch:version-release is newer.
1052 * For packages being removed:
1055 /* The ordering doesn't matter here */
1056 tei = teInitIterator(ts);
1057 while ((p = teNext(tei, TR_ADDED)) != NULL) {
1058 const char * n, * v, * r;
1060 rpmdbMatchIterator mi;
1064 pkgKey = p->u.addedKey;
1066 h = alGetHeader(ts->addedPackages, pkgKey, 0);
1067 if (h == NULL) /* XXX can't happen */
1070 (void) headerNVR(h, &n, &v, &r);
1074 if (!archOkay(h, &str1) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH)) {
1075 const char * pkgNEVR = hGetNEVR(h, NULL);
1076 rpmProblemSetAppend(ts->probs, RPMPROB_BADARCH,
1080 pkgNEVR = _free(pkgNEVR);
1084 if (!osOkay(h, &str1) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS)) {
1085 const char * pkgNEVR = hGetNEVR(h, NULL);
1086 rpmProblemSetAppend(ts->probs, RPMPROB_BADOS,
1090 pkgNEVR = _free(pkgNEVR);
1093 if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1095 mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1096 while ((oldH = rpmdbNextIterator(mi)) != NULL)
1097 xx = ensureOlder(ts, h, oldH, key);
1098 mi = rpmdbFreeIterator(mi);
1101 /* XXX multilib should not display "already installed" problems */
1102 if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG)
1103 #ifdef DYING /* XXX MULTILIB multiLib from transactionElement */
1104 && !alGetMultiLib(ts->addedPackages, i)
1107 mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1108 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, v);
1109 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, r);
1111 while (rpmdbNextIterator(mi) != NULL) {
1112 const char * pkgNEVR = hGetNEVR(h, NULL);
1113 rpmProblemSetAppend(ts->probs, RPMPROB_PKG_INSTALLED,
1117 pkgNEVR = _free(pkgNEVR);
1118 /*@innerbreak@*/ break;
1120 mi = rpmdbFreeIterator(mi);
1123 /* Count no. of files (if any). */
1125 totalFileCount += p->fns->fc;
1127 h = headerFree(h, "alGetHeader (rpmtsRun sanity)");
1130 tei = teFreeIterator(tei);
1132 /* FIXME: it seems a bit silly to read in all of these headers twice */
1133 /* The ordering doesn't matter here */
1134 if (ts->numRemovedPackages > 0) {
1135 rpmdbMatchIterator mi;
1139 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1140 xx = rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
1141 while ((h = rpmdbNextIterator(mi)) != NULL) {
1142 if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
1143 totalFileCount += fileCount;
1145 mi = rpmdbFreeIterator(mi);
1148 /* ===============================================
1149 * Initialize transaction element file info for package:
1151 ts->flEntries = alGetSize(ts->addedPackages) + ts->numRemovedPackages;
1152 ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
1155 * FIXME?: we'd be better off assembling one very large file list and
1156 * calling fpLookupList only once. I'm not sure that the speedup is
1157 * worth the trouble though.
1159 tei = teInitIterator(ts);
1160 while ((fi = teNextFi(tei)) != NULL) {
1163 fi->magic = TFIMAGIC;
1165 fi->type = ts->order[oc].type;
1172 pkgKey = ts->order[oc].u.addedKey;
1174 fi->h = alGetHeader(ts->addedPackages, pkgKey, 1);
1175 #ifdef DYING /* XXX MULTILIB multiLib from transactionElement */
1176 fi->multiLib = alGetMultiLib(ts->addedPackages, i);
1178 fi->multiLib = ts->order[oc].multiLib;
1181 /*@i@*/ fi->key = ts->order[oc].key;
1182 fi->relocs = ts->order[oc].relocs;
1183 /*@i@*/ fi->fd = ts->order[oc].fd;
1185 /* XXX availablePackage can be dumped here XXX */
1187 /* XXX header arg unused. */
1188 loadFi(ts, fi, fi->h, keep_header);
1193 /* Skip netshared paths, not our i18n files, and excluded docs */
1195 /*@switchbreak@*/ break;
1197 fi->record = ts->order[oc].u.removed.dboffset;
1198 /* Retrieve erased package header from the database. */
1199 { rpmdbMatchIterator mi;
1201 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
1202 &fi->record, sizeof(fi->record));
1203 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
1204 fi->h = headerLink(fi->h, "TR_REMOVED loadFi");
1205 mi = rpmdbFreeIterator(mi);
1207 if (fi->h == NULL) {
1211 /* XXX header arg unused. */
1212 loadFi(ts, fi, fi->h, 0);
1213 /*@switchbreak@*/ break;
1218 fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
1220 tei = teFreeIterator(tei);
1222 if (!ts->chrootDone) {
1224 /*@-superuser -noeffect @*/
1225 xx = chroot(ts->rootDir);
1226 /*@=superuser =noeffect @*/
1228 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1231 chroot_prefix = ts->rootDir;
1236 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1237 fpc = fpCacheCreate(totalFileCount);
1239 /* ===============================================
1240 * Add fingerprint for each file not skipped.
1242 tei = teInitIterator(ts);
1243 while ((fi = teNextFi(tei)) != NULL) {
1244 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1245 for (i = 0; i < fi->fc; i++) {
1246 if (XFA_SKIPPING(fi->actions[i]))
1247 /*@innercontinue@*/ continue;
1248 /*@-dependenttrans@*/
1249 htAddEntry(ts->ht, fi->fps + i, fi);
1250 /*@=dependenttrans@*/
1253 tei = teFreeIterator(tei);
1255 /*@-noeffectuncon @*/ /* FIX: check rc */
1256 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
1257 NULL, ts->notifyData));
1258 /*@=noeffectuncon@*/
1260 /* ===============================================
1261 * Compute file disposition for each package in transaction set.
1263 tei = teInitIterator(ts);
1264 while ((fi = teNextFi(tei)) != NULL) {
1265 dbiIndexSet * matches;
1268 /*@-noeffectuncon @*/ /* FIX: check rc */
1269 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
1270 ts->flEntries, NULL, ts->notifyData));
1271 /*@=noeffectuncon@*/
1273 if (fi->fc == 0) continue;
1275 /* Extract file info for all files in this package from the database. */
1276 matches = xcalloc(fi->fc, sizeof(*matches));
1277 if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc)) {
1278 psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1279 return 1; /* XXX WTFO? */
1283 for (i = 0; i < fi->fc; i++)
1284 numShared += dbiIndexSetCount(matches[i]);
1286 /* Build sorted file info list for this package. */
1287 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1288 for (i = 0; i < fi->fc; i++) {
1290 * Take care not to mark files as replaced in packages that will
1291 * have been removed before we will get here.
1293 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1295 ro = dbiIndexRecordOffset(matches[i], j);
1297 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
1298 switch (ts->order[k].type) {
1300 if (ts->order[k].u.removed.dboffset == ro)
1302 /*@switchbreak@*/ break;
1304 /*@switchbreak@*/ break;
1308 shared->pkgFileNum = i;
1309 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1310 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1311 shared->isRemoved = (knownBad == ro);
1314 matches[i] = dbiFreeIndexSet(matches[i]);
1316 numShared = shared - sharedList;
1317 shared->otherPkg = -1;
1318 matches = _free(matches);
1320 /* Sort file info by other package index (otherPkg) */
1321 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1323 /* For all files from this package that are in the database ... */
1324 for (i = 0; i < numShared; i = nexti) {
1327 shared = sharedList + i;
1329 /* Find the end of the files in the other package. */
1330 for (nexti = i + 1; nexti < numShared; nexti++) {
1331 if (sharedList[nexti].otherPkg != shared->otherPkg)
1332 /*@innerbreak@*/ break;
1335 /* Is this file from a package being removed? */
1337 for (j = 0; j < ts->numRemovedPackages; j++) {
1338 if (ts->removedPackages[j] != shared->otherPkg)
1339 /*@innercontinue@*/ continue;
1341 /*@innerbreak@*/ break;
1344 /* Determine the fate of each file. */
1347 xx = handleInstInstalledFiles(ts, fi, shared, nexti - i,
1348 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)));
1349 /*@switchbreak@*/ break;
1352 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1353 /*@switchbreak@*/ break;
1359 /* Update disk space needs on each partition for this package. */
1360 handleOverlappedFiles(ts, fi);
1362 /* Check added package has sufficient space on each partition used. */
1365 if (!(ts->di && fi->fc))
1366 /*@switchbreak@*/ break;
1367 for (i = 0; i < ts->filesystemCount; i++) {
1371 /* XXX Avoid FAT and other file systems that have not inodes. */
1372 if (dip->iavail <= 0)
1373 /*@innercontinue@*/ continue;
1375 if (adj_fs_blocks(dip->bneeded) > dip->bavail) {
1376 const char * pkgNEVR = fiGetNEVR(fi);
1377 rpmProblemSetAppend(ts->probs, RPMPROB_DISKSPACE,
1379 ts->filesystems[i], NULL, NULL,
1380 (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1381 pkgNEVR = _free(pkgNEVR);
1384 if (adj_fs_blocks(dip->ineeded) > dip->iavail) {
1385 const char * pkgNEVR = fiGetNEVR(fi);
1386 rpmProblemSetAppend(ts->probs, RPMPROB_DISKNODES,
1388 ts->filesystems[i], NULL, NULL,
1389 (adj_fs_blocks(dip->ineeded) - dip->iavail));
1390 pkgNEVR = _free(pkgNEVR);
1393 /*@switchbreak@*/ break;
1395 /*@switchbreak@*/ break;
1398 tei = teFreeIterator(tei);
1400 if (ts->chrootDone) {
1401 /*@-superuser -noeffect @*/
1403 /*@=superuser =noeffect @*/
1405 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1407 chroot_prefix = NULL;
1409 xx = chdir(ts->currDir);
1412 /*@-noeffectuncon @*/ /* FIX: check rc */
1413 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
1414 NULL, ts->notifyData));
1415 /*@=noeffectuncon @*/
1417 /* ===============================================
1418 * Free unused memory as soon as possible.
1421 tei = teInitIterator(ts);
1422 while ((fi = teNextFi(tei)) != NULL) {
1425 fi->fps = _free(fi->fps);
1427 tei = teFreeIterator(tei);
1433 /* ===============================================
1434 * If unfiltered problems exist, free memory and return.
1436 if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS)
1437 || (ts->probs->numProblems &&
1438 (okProbs != NULL || rpmProblemSetTrim(ts->probs, okProbs)))
1441 ts->flList = freeFl(ts, ts->flList);
1443 if (psm->ts != NULL)
1444 psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1445 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1446 return ts->orderCount;
1450 /* ===============================================
1451 * Save removed files before erasing.
1453 if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1454 tei = teInitIterator(ts);
1455 while ((fi = teNextFi(tei)) != NULL) {
1458 /*@switchbreak@*/ break;
1460 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE) {
1461 psm->fi = rpmfiLink(fi, "tsRepackage");
1462 xx = psmStage(psm, PSM_PKGSAVE);
1463 (void) rpmfiUnlink(fi, "tsRepackage");
1466 /*@switchbreak@*/ break;
1469 tei = teFreeIterator(tei);
1472 /* ===============================================
1473 * Install and remove packages.
1476 lastKey = (alKey)-2; /* erased packages have -1 */
1477 tei = teInitIterator(ts);
1478 /*@-branchstate@*/ /* FIX: fi reload needs work */
1479 while ((fi = teNextFi(tei)) != NULL) {
1485 psm->fi = rpmfiLink(fi, "tsInstall");
1489 pkgKey = ts->order[oc].u.addedKey;
1491 rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n",
1492 fi->name, fi->version, fi->release);
1493 h = (fi->h ? headerLink(fi->h, "TR_ADDED install") : NULL);
1495 if (fi->fd == NULL) {
1496 /*@-noeffectuncon @*/ /* FIX: ??? */
1497 fi->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1498 fi->key, ts->notifyData);
1499 /*@=noeffectuncon @*/
1500 if (fi->fd != NULL) {
1503 h = headerFree(h, "TR_ADDED install");
1505 /*@-mustmod@*/ /* LCL: segfault */
1506 rpmrc = rpmReadPackageFile(ts, fi->fd,
1507 "rpmRunTransactions", &h);
1510 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1511 /*@-noeffectuncon @*/ /* FIX: check rc */
1512 (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1514 fi->key, ts->notifyData);
1515 /*@=noeffectuncon @*/
1518 } else if (fi->h != NULL) {
1519 Header foo = relocateFileList(ts, fi, h, NULL);
1520 h = headerFree(h, "TR_ADDED read free");
1521 h = headerLink(foo, "TR_ADDED relocate xfer");
1522 foo = headerFree(foo, "TR_ADDED relocate");
1524 if (fi->fd != NULL) gotfd = 1;
1529 if (fi->fd != NULL) {
1530 Header hsave = NULL;
1533 hsave = headerLink(fi->h, "TR_ADDED fi->h hsave");
1534 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1535 fi->h = headerLink(h, "TR_ADDED fi->h link");
1537 char * fstates = fi->fstates;
1538 fileAction * actions = fi->actions;
1539 uint_32 multiLib = fi->multiLib;
1540 const void * key = fi->key;
1541 rpmRelocation * relocs = fi->relocs;
1551 fi->magic = TFIMAGIC;
1552 fi->type = ts->order[oc].type;
1554 loadFi(ts, fi, h, 1);
1555 fi->fstates = _free(fi->fstates);
1556 fi->fstates = fstates;
1557 fi->actions = _free(fi->actions);
1558 fi->actions = actions;
1559 fi->multiLib = multiLib;
1561 fi->relocs = relocs;
1563 /*@i@*/ fi->fd = fd;
1568 ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
1570 if (psmStage(psm, PSM_PKGINSTALL)) {
1574 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1576 fi->h = headerLink(hsave, "TR_ADDED fi->h restore");
1577 hsave = headerFree(hsave, "TR_ADDED hsave free");
1584 h = headerFree(h, "TR_ADDED h free");
1587 /*@-noeffectuncon @*/ /* FIX: check rc */
1588 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1589 fi->key, ts->notifyData);
1590 /*@=noeffectuncon @*/
1594 /*@switchbreak@*/ break;
1596 rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n",
1597 fi->name, fi->version, fi->release);
1599 /* If install failed, then we shouldn't erase. */
1600 if (ts->order[oc].u.removed.dependsOnKey != lastKey) {
1601 if (psmStage(psm, PSM_PKGERASE))
1605 /*@switchbreak@*/ break;
1607 xx = rpmdbSync(ts->rpmdb);
1608 (void) rpmfiUnlink(fi, "tsInstall");
1612 tei = teFreeIterator(tei);
1614 ts->flList = freeFl(ts, ts->flList);
1617 psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1619 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */