2 * \file lib/transaction.c
7 #define _NEED_TEITERATOR 1
11 #include <rpmmacro.h> /* XXX for rpmExpand */
14 #include "legacy.h" /* XXX mdfile */
15 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
18 /*@-redecl -exportheadervar@*/
20 extern const char * chroot_prefix;
21 /*@=redecl =exportheadervar@*/
23 /* XXX FIXME: merge with existing (broken?) tests in system.h */
24 /* portability fiddles */
25 #if STATFS_IN_SYS_STATVFS
27 # include <sys/statvfs.h>
28 #if defined(__LCLINT__)
29 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
30 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
31 /*@globals fileSystem @*/
32 /*@modifies *buf, fileSystem @*/;
33 /*@=declundef =exportheader =protoparammatch @*/
37 # if STATFS_IN_SYS_VFS
40 # if STATFS_IN_SYS_MOUNT
41 # include <sys/mount.h>
43 # if STATFS_IN_SYS_STATFS
44 # include <sys/statfs.h>
52 /*@access FD_t@*/ /* XXX compared with NULL */
53 /*@access Header@*/ /* XXX compared with NULL */
54 /*@access rpmProblemSet@*/ /* XXX need rpmProblemSetOK() */
55 /*@access dbiIndexSet@*/
63 /*@access teIterator@*/
64 /*@access transactionElement@*/
65 /*@access rpmTransactionSet@*/
69 struct diskspaceInfo {
70 dev_t dev; /*!< file system device number. */
71 signed long bneeded; /*!< no. of blocks needed. */
72 signed long ineeded; /*!< no. of inodes needed. */
73 int bsize; /*!< file system block size. */
74 signed long bavail; /*!< no. of blocks available. */
75 signed long iavail; /*!< no. of inodes available. */
79 * Adjust for root only reserved space. On linux e2fs, this is 5%.
81 #define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
83 /* argon thought a shift optimization here was a waste of time... he's
85 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
89 static /*@null@*/ void * freeFl(rpmTransactionSet ts,
90 /*@only@*/ /*@null@*/ TFI_t flList)
97 /*@-usereleased -onlytrans @*/ /* FIX: fi needs to be only */
98 for (oc = 0, fi = flList; oc < ts->orderCount; oc++, fi++)
100 flList = _free(flList);
101 /*@=usereleased =onlytrans @*/
106 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
108 /*@-type@*/ /* FIX: cast? */
109 ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
113 int rpmtransGetKeys(const rpmTransactionSet ts, const void *** ep, int * nep)
117 if (nep) *nep = ts->orderCount;
122 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
123 for (oc = 0; oc < ts->orderCount; oc++, e++) {
124 switch (ts->order[oc].type) {
127 *e = alGetKey(ts->addedPackages, ts->order[oc].u.addedKey);
129 *e = ts->order[oc].key;
131 /*@switchbreak@*/ break;
134 /*@-mods@*/ /* FIX: double indirection. */
137 /*@switchbreak@*/ break;
146 static int archOkay(Header h)
152 /* make sure we're trying to install this on the proper architecture */
153 (void) headerGetEntry(h, RPMTAG_ARCH, &type, (void **) &pkgArch, &count);
155 if (type == RPM_INT8_TYPE) {
159 /* old arch handling */
160 rpmGetArchInfo(NULL, &archNum);
161 pkgArchNum = pkgArch;
162 if (archNum != *pkgArchNum) {
168 /* new arch handling */
169 if (!rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch)) {
179 static int osOkay(Header h)
185 /* make sure we're trying to install this on the proper os */
186 (void) headerGetEntry(h, RPMTAG_OS, &type, (void **) &pkgOs, &count);
188 if (type == RPM_INT8_TYPE) {
189 /* v1 packages and v2 packages both used improper OS numbers, so just
190 deal with it hope things work */
195 /* new os handling */
196 if (!rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs)) {
206 static int sharedCmp(const void * one, const void * two)
209 const struct sharedFileInfo * a = one;
210 const struct sharedFileInfo * b = two;
212 if (a->otherPkg < b->otherPkg)
214 else if (a->otherPkg > b->otherPkg)
222 static fileAction decideFileFate(const char * dirName,
223 const char * baseName, short dbMode,
224 const char * dbMd5, const char * dbLink, short newMode,
225 const char * newMd5, const char * newLink, int newFlags,
226 rpmtransFlags transFlags)
227 /*@globals fileSystem @*/
228 /*@modifies fileSystem @*/
231 const char * dbAttr, * newAttr;
232 fileTypes dbWhat, newWhat, diskWhat;
235 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
236 char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
238 (void) stpcpy( stpcpy(filespec, dirName), baseName);
240 if (lstat(filespec, &sb)) {
242 * The file doesn't exist on the disk. Create it unless the new
243 * package has marked it as missingok, or allfiles is requested.
245 if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
246 (newFlags & RPMFILE_MISSINGOK)) {
247 rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
255 diskWhat = whatis(sb.st_mode);
256 dbWhat = whatis(dbMode);
257 newWhat = whatis(newMode);
259 /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
260 them in older packages as well */
261 if (newWhat == XDIR) {
265 if (diskWhat != newWhat) {
267 } else if (newWhat != dbWhat && diskWhat != dbWhat) {
269 } else if (dbWhat != newWhat) {
271 } else if (dbWhat != LINK && dbWhat != REG) {
276 rc = mdfile(filespec, buffer);
279 /* assume the file has been removed, don't freak */
284 } else /* dbWhat == LINK */ {
285 memset(buffer, 0, sizeof(buffer));
286 i = readlink(filespec, buffer, sizeof(buffer) - 1);
288 /* assume the file has been removed, don't freak */
295 /* this order matters - we'd prefer to CREATE the file if at all
296 possible in case something else (like the timestamp) has changed */
298 if (!strcmp(dbAttr, buffer)) {
299 /* this config file has never been modified, so just replace it */
303 if (!strcmp(dbAttr, newAttr)) {
304 /* this file is the same in all versions of this package */
309 * The config file on the disk has been modified, but
310 * the ones in the two packages are different. It would
311 * be nice if RPM was smart enough to at least try and
312 * merge the difference ala CVS, but...
319 static int filecmp(short mode1, const char * md51, const char * link1,
320 short mode2, const char * md52, const char * link2)
323 fileTypes what1 = whatis(mode1);
324 fileTypes what2 = whatis(mode2);
326 if (what1 != what2) return 1;
329 return strcmp(link1, link2);
330 else if (what1 == REG)
331 return strcmp(md51, md52);
338 /* XXX only ts->{probs,rpmdb} modified */
339 static int handleInstInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
340 struct sharedFileInfo * shared,
341 int sharedCount, int reportConflicts)
342 /*@globals fileSystem @*/
343 /*@modifies ts, fi, fileSystem @*/
346 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
347 rpmtransFlags transFlags = ts->transFlags;
348 rpmTagType oltype, omtype;
351 const char ** otherMd5s;
352 const char ** otherLinks;
353 const char * otherStates;
354 uint_32 * otherFlags;
355 uint_32 * otherSizes;
356 uint_16 * otherModes;
360 rpmdbMatchIterator mi;
362 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, &shared->otherPkg, sizeof(shared->otherPkg));
363 h = rpmdbNextIterator(mi);
365 mi = rpmdbFreeIterator(mi);
369 xx = hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
370 xx = hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
371 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
372 xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
373 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
374 xx = hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
376 fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
378 for (i = 0; i < sharedCount; i++, shared++) {
379 int otherFileNum, fileNum;
380 otherFileNum = shared->otherFileNum;
381 fileNum = shared->pkgFileNum;
383 /* XXX another tedious segfault, assume file state normal. */
384 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
387 if (XFA_SKIPPING(fi->actions[fileNum]))
390 if (filecmp(otherModes[otherFileNum],
391 otherMd5s[otherFileNum],
392 otherLinks[otherFileNum],
395 fi->flinks[fileNum])) {
396 /*@-compdef@*/ /* FIX: *fi->replaced undefined */
398 rpmProblemSetAppend(ts->probs, RPMPROB_FILE_CONFLICT,
399 fiGetNVR(fi), fi->key,
400 fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum],
404 if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
407 if (!shared->isRemoved)
408 fi->replaced[numReplaced++] = *shared;
413 if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
414 fi->actions[fileNum] = decideFileFate(
415 fi->dnl[fi->dil[fileNum]],
417 otherModes[otherFileNum],
418 otherMd5s[otherFileNum],
419 otherLinks[otherFileNum],
427 fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
430 otherMd5s = hfd(otherMd5s, omtype);
431 otherLinks = hfd(otherLinks, oltype);
432 mi = rpmdbFreeIterator(mi);
434 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
435 sizeof(*fi->replaced) * (numReplaced + 1));
436 fi->replaced[numReplaced].otherPkg = 0;
443 /* XXX only ts->rpmdb modified */
444 static int handleRmvdInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
445 struct sharedFileInfo * shared, int sharedCount)
446 /*@globals fileSystem @*/
447 /*@modifies fi, fileSystem @*/
451 const char * otherStates;
454 rpmdbMatchIterator mi;
456 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
457 &shared->otherPkg, sizeof(shared->otherPkg));
458 h = rpmdbNextIterator(mi);
460 mi = rpmdbFreeIterator(mi);
464 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
466 for (i = 0; i < sharedCount; i++, shared++) {
467 int otherFileNum, fileNum;
468 otherFileNum = shared->otherFileNum;
469 fileNum = shared->pkgFileNum;
471 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
474 fi->actions[fileNum] = FA_SKIP;
477 mi = rpmdbFreeIterator(mi);
483 * Update disk space needs on each partition for this package.
485 /* XXX only ts->{probs,di} modified */
486 static void handleOverlappedFiles(const rpmTransactionSet ts, TFI_t fi)
487 /*@globals fileSystem @*/
488 /*@modifies ts, fi, fileSystem @*/
490 struct diskspaceInfo * ds = NULL;
491 uint_32 fixupSize = 0;
492 char * filespec = NULL;
493 int fileSpecAlloced = 0;
496 for (i = 0; i < fi->fc; i++) {
497 int otherPkgNum, otherFileNum;
501 if (XFA_SKIPPING(fi->actions[i]))
504 j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
506 if (j > fileSpecAlloced) {
507 fileSpecAlloced = j * 2;
508 filespec = xrealloc(filespec, fileSpecAlloced);
512 (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
516 while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
517 if (!ds->bsize) ds = NULL;
522 * Retrieve all records that apply to this file. Note that the
523 * file info records were built in the same order as the packages
524 * will be installed and removed so the records for an overlapped
525 * files will be sorted in exactly the same order.
527 (void) htGetEntry(ts->ht, &fi->fps[i],
528 (const void ***) &recs, &numRecs, NULL);
531 * If this package is being added, look only at other packages
532 * being added -- removed packages dance to a different tune.
533 * If both this and the other package are being added, overlapped
534 * files must be identical (or marked as a conflict). The
535 * disposition of already installed config files leads to
536 * a small amount of extra complexity.
538 * If this package is being removed, then there are two cases that
539 * need to be worried about:
540 * If the other package is being added, then skip any overlapped files
541 * so that this package removal doesn't nuke the overlapped files
542 * that were just installed.
543 * If both this and the other package are being removed, then each
544 * file removal from preceding packages needs to be skipped so that
545 * the file removal occurs only on the last occurence of an overlapped
546 * file in the transaction set.
550 /* Locate this overlapped file in the set of added/removed packages. */
551 for (j = 0; j < numRecs && recs[j] != fi; j++)
554 /* Find what the previous disposition of this file was. */
555 otherFileNum = -1; /* keep gcc quiet */
556 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
557 /* Added packages need only look at other added packages. */
558 if (fi->type == TR_ADDED && recs[otherPkgNum]->type != TR_ADDED)
559 /*@innercontinue@*/ continue;
561 /* TESTME: there are more efficient searches in the world... */
562 for (otherFileNum = 0; otherFileNum < recs[otherPkgNum]->fc;
565 /* If the addresses are the same, so are the values. */
566 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
567 /*@innerbreak@*/ break;
569 /* Otherwise, compare fingerprints by value. */
570 /*@-nullpass@*/ /* LCL: looks good to me */
571 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
572 /*@innerbreak@*/ break;
576 /* XXX is this test still necessary? */
577 if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
578 /*@innerbreak@*/ break;
584 if (otherPkgNum < 0) {
585 /* XXX is this test still necessary? */
586 if (fi->actions[i] != FA_UNKNOWN)
587 /*@switchbreak@*/ break;
588 if ((fi->fflags[i] & RPMFILE_CONFIG) &&
589 !lstat(filespec, &sb)) {
590 /* Here is a non-overlapped pre-existing config file. */
591 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
592 ? FA_ALTNAME : FA_BACKUP;
594 fi->actions[i] = FA_CREATE;
596 /*@switchbreak@*/ break;
599 /* Mark added overlapped non-identical files as a conflict. */
600 if ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
601 && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
602 recs[otherPkgNum]->fmd5s[otherFileNum],
603 recs[otherPkgNum]->flinks[otherFileNum],
608 rpmProblemSetAppend(ts->probs, RPMPROB_NEW_FILE_CONFLICT,
609 fiGetNVR(fi), fi->key,
611 fiGetNVR(recs[otherPkgNum]),
615 /* Try to get the disk accounting correct even if a conflict. */
616 fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
618 if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
619 /* Here is an overlapped pre-existing config file. */
620 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
621 ? FA_ALTNAME : FA_SKIP;
623 fi->actions[i] = FA_CREATE;
625 } /*@switchbreak@*/ break;
627 if (otherPkgNum >= 0) {
628 /* Here is an overlapped added file we don't want to nuke. */
629 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
630 /* On updates, don't remove files. */
631 fi->actions[i] = FA_SKIP;
632 /*@switchbreak@*/ break;
634 /* Here is an overlapped removed file: skip in previous. */
635 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
637 if (XFA_SKIPPING(fi->actions[i]))
638 /*@switchbreak@*/ break;
639 if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
640 /*@switchbreak@*/ break;
641 if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
642 fi->actions[i] = FA_ERASE;
643 /*@switchbreak@*/ break;
646 /* Here is a pre-existing modified config file that needs saving. */
648 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
649 fi->actions[i] = FA_BACKUP;
650 /*@switchbreak@*/ break;
653 fi->actions[i] = FA_ERASE;
654 /*@switchbreak@*/ break;
658 uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
660 switch (fi->actions[i]) {
666 /*@switchbreak@*/ break;
669 * FIXME: If two packages share a file (same md5sum), and
670 * that file is being replaced on disk, will ds->bneeded get
671 * decremented twice? Quite probably!
675 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
676 /*@switchbreak@*/ break;
681 /*@switchbreak@*/ break;
684 /*@switchbreak@*/ break;
687 ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
690 filespec = _free(filespec);
695 static int ensureOlder(rpmTransactionSet ts,
696 const Header h, /*@null@*/ const Header old,
697 /*@dependent@*/ /*@null@*/ const void * key)
702 if (old == NULL) return 1;
704 result = rpmVersionCompare(old, h);
707 else if (result > 0) {
709 /*@-evalorder@*/ /* LCL: is confused */
710 rpmProblemSetAppend(ts->probs, RPMPROB_OLDPACKAGE,
711 hGetNVR(h, NULL), key,
723 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
724 /*@globals rpmGlobalMacroContext @*/
725 /*@modifies fi, rpmGlobalMacroContext @*/
727 int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
728 char ** netsharedPaths = NULL;
729 const char ** languages;
730 const char * dn, * bn;
731 int dnlen, bnlen, ix;
738 noDocs = rpmExpandNumeric("%{_excludedocs}");
740 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
742 if (tmpPath && *tmpPath != '%')
743 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
745 tmpPath = _free(tmpPath);
748 s = rpmExpand("%{_install_langs}", NULL);
750 if (!(s && *s != '%'))
753 languages = (const char **) splitString(s, strlen(s), ':');
759 /* Compute directory refcount, skip directory if now empty. */
760 drc = alloca(fi->dc * sizeof(*drc));
761 memset(drc, 0, fi->dc * sizeof(*drc));
762 dff = alloca(fi->dc * sizeof(*dff));
763 memset(dff, 0, fi->dc * sizeof(*dff));
765 for (i = 0; i < fi->fc; i++) {
776 /* Don't bother with skipped files */
777 if (XFA_SKIPPING(fi->actions[i])) {
783 * Skip net shared paths.
784 * Net shared paths are not relative to the current root (though
785 * they do need to take package relocations into account).
787 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
792 if (strncmp(dn, *nsp, len))
793 /*@innercontinue@*/ continue;
794 /* Only directories or complete file paths can be net shared */
795 if (!(dn[len] == '/' || dn[len] == '\0'))
796 /*@innercontinue@*/ continue;
798 if (len < (dnlen + bnlen))
799 /*@innercontinue@*/ continue;
800 if (strncmp(dn, *nsp, dnlen))
801 /*@innercontinue@*/ continue;
802 if (strncmp(bn, (*nsp) + dnlen, bnlen))
803 /*@innercontinue@*/ continue;
805 /* Only directories or complete file paths can be net shared */
806 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
807 /*@innercontinue@*/ continue;
810 /*@innerbreak@*/ break;
814 drc[ix]--; dff[ix] = 1;
815 fi->actions[i] = FA_SKIPNETSHARED;
820 * Skip i18n language specific files.
822 if (fi->flangs && languages && *fi->flangs[i]) {
823 const char **lang, *l, *le;
824 for (lang = languages; *lang != NULL; lang++) {
825 if (!strcmp(*lang, "all"))
826 /*@innerbreak@*/ break;
827 for (l = fi->flangs[i]; *l != '\0'; l = le) {
828 for (le = l; *le != '\0' && *le != '|'; le++)
830 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
831 /*@innerbreak@*/ break;
832 if (*le == '|') le++; /* skip over | */
835 /*@innerbreak@*/ break;
838 drc[ix]--; dff[ix] = 1;
839 fi->actions[i] = FA_SKIPNSTATE;
845 * Skip documentation if requested.
847 if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
848 drc[ix]--; dff[ix] = 1;
849 fi->actions[i] = FA_SKIPNSTATE;
854 /* Skip (now empty) directories that had skipped files. */
855 for (j = 0; j < fi->dc; j++) {
857 if (drc[j]) continue; /* dir still has files. */
858 if (!dff[j]) continue; /* dir was not emptied here. */
860 /* Find parent directory and basename. */
861 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
862 bn = dn + dnlen; bnlen = 0;
863 while (bn > dn && bn[-1] != '/') {
869 /* If explicitly included in the package, skip the directory. */
870 for (i = 0; i < fi->fc; i++) {
873 if (XFA_SKIPPING(fi->actions[i]))
874 /*@innercontinue@*/ continue;
875 if (whatis(fi->fmodes[i]) != XDIR)
876 /*@innercontinue@*/ continue;
877 dir = fi->dnl[fi->dil[i]];
878 if (strlen(dir) != dnlen)
879 /*@innercontinue@*/ continue;
880 if (strncmp(dir, dn, dnlen))
881 /*@innercontinue@*/ continue;
882 if (strlen(fi->bnl[i]) != bnlen)
883 /*@innercontinue@*/ continue;
884 if (strncmp(fi->bnl[i], bn, bnlen))
885 /*@innercontinue@*/ continue;
886 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
887 fi->actions[i] = FA_SKIPNSTATE;
888 /*@innerbreak@*/ break;
892 if (netsharedPaths) freeSplitString(netsharedPaths);
893 #ifdef DYING /* XXX freeFi will deal with this later. */
894 fi->flangs = _free(fi->flangs);
896 if (languages) freeSplitString((char **)languages);
900 * Return next transaction element's file info.
901 * @param tei transaction element iterator
902 * @return nest transaction element file info, NULL on termination
904 /*@unused@*/ static inline
905 TFI_t teNextFi(teIterator tei)
910 if (teNextIterator(tei) != NULL && tei->ocsave != -1)
911 fi = tei->ts->flList + tei->ocsave;
912 /*@-compdef -onlytrans -usereleased@*/ /* FIX: ts->flList may be released */
914 /*@=compdef =onlytrans =usereleased@*/
917 #define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
919 int rpmRunTransactions( rpmTransactionSet ts,
920 rpmCallbackFunction notify, rpmCallbackData notifyData,
921 rpmProblemSet okProbs, rpmProblemSet * newProbs,
922 rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
926 int totalFileCount = 0;
928 struct diskspaceInfo * dip;
929 struct sharedFileInfo * shared, * sharedList;
932 alKey pkgKey, lastKey;
934 transactionElement p;
935 fingerPrintCache fpc;
941 int keep_header = 1; /* XXX rpmProblemSetAppend prevents dumping headers. */
943 /* FIXME: what if the same package is included in ts twice? */
945 ts->transFlags = transFlags;
946 if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
947 ts->transFlags |= (_noTransScripts | _noTransTriggers);
948 if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
949 ts->transFlags |= _noTransTriggers;
951 /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
952 if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
953 ts->transFlags |= (_noTransScripts | _noTransTriggers);
956 ts->notifyData = notifyData;
958 ts->probs = *newProbs = rpmProblemSetCreate();
960 ts->ignoreSet = ignoreSet;
961 ts->currDir = _free(ts->currDir);
962 ts->currDir = currentDirectory();
964 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
965 ts->id = (int_32) time(NULL);
967 memset(psm, 0, sizeof(*psm));
969 psm->ts = rpmtsLink(ts, "tsRun");
972 /* Get available space on mounted file systems. */
973 if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
974 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount)) {
977 ts->di = _free(ts->di);
978 dip = ts->di = xcalloc((ts->filesystemCount + 1), sizeof(*ts->di));
980 for (i = 0; (i < ts->filesystemCount) && dip; i++) {
981 #if STATFS_IN_SYS_STATVFS
983 memset(&sfb, 0, sizeof(sfb));
984 if (statvfs(ts->filesystems[i], &sfb))
988 /* This platform has the 4-argument version of the statfs call. The last two
989 * should be the size of struct statfs and 0, respectively. The 0 is the
990 * filesystem type, and is always 0 when statfs is called on a mounted
991 * filesystem, as we're doing.
993 memset(&sfb, 0, sizeof(sfb));
994 if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
996 memset(&sfb, 0, sizeof(sfb));
997 if (statfs(ts->filesystems[i], &sfb))
1003 ts->di[i].bsize = sfb.f_bsize;
1004 ts->di[i].bneeded = 0;
1005 ts->di[i].ineeded = 0;
1006 #ifdef STATFS_HAS_F_BAVAIL
1007 ts->di[i].bavail = sfb.f_bavail;
1009 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1010 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1011 * it's about all we can do.
1013 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
1015 /* XXX Avoid FAT and other file systems that have not inodes. */
1016 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1019 xx = stat(ts->filesystems[i], &sb);
1020 ts->di[i].dev = sb.st_dev;
1024 if (dip) ts->di[i].bsize = 0;
1027 /* ===============================================
1028 * For packages being installed:
1029 * - verify package arch/os.
1030 * - verify package epoch:version-release is newer.
1032 * For packages being removed:
1035 /* The ordering doesn't matter here */
1037 for (i = 0; i < alGetSize(ts->addedPackages); i++)
1039 tei = teInitIterator(ts);
1040 while ((p = teNext(tei, TR_ADDED)) != NULL)
1043 const char * n, * v, * r;
1045 rpmdbMatchIterator mi;
1048 pkgKey = p->u.addedKey;
1050 h = alGetHeader(ts->addedPackages, pkgKey, 0);
1051 if (h == NULL) /* XXX can't happen */
1054 (void) headerNVR(h, &n, &v, &r);
1056 key = alGetKey(ts->addedPackages, pkgKey);
1061 if (!archOkay(h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
1062 rpmProblemSetAppend(ts->probs, RPMPROB_BADARCH,
1063 hGetNVR(h, NULL), key,
1064 NULL, NULL, NULL, 0);
1066 if (!osOkay(h) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
1067 rpmProblemSetAppend(ts->probs, RPMPROB_BADOS,
1068 hGetNVR(h, NULL), key,
1069 NULL, NULL, NULL, 0);
1071 if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1073 mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1074 while ((oldH = rpmdbNextIterator(mi)) != NULL)
1075 xx = ensureOlder(ts, h, oldH, key);
1076 mi = rpmdbFreeIterator(mi);
1079 /* XXX multilib should not display "already installed" problems */
1080 if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG)
1081 #ifdef DYING /* XXX MULTILIB multiLib from transactionElement */
1082 && !alGetMultiLib(ts->addedPackages, i)
1085 mi = rpmtsInitIterator(ts, RPMTAG_NAME, n, 0);
1086 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, v);
1087 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, r);
1089 while (rpmdbNextIterator(mi) != NULL) {
1090 rpmProblemSetAppend(ts->probs, RPMPROB_PKG_INSTALLED,
1091 hGetNVR(h, NULL), key,
1092 NULL, NULL, NULL, 0);
1093 /*@innerbreak@*/ break;
1095 mi = rpmdbFreeIterator(mi);
1098 totalFileCount += alGetFilesCount(ts->addedPackages, pkgKey);
1100 h = headerFree(h, "alGetHeader (rpmtsRun sanity)");
1103 tei = teFreeIterator(tei);
1105 /* FIXME: it seems a bit silly to read in all of these headers twice */
1106 /* The ordering doesn't matter here */
1107 if (ts->numRemovedPackages > 0) {
1108 rpmdbMatchIterator mi;
1112 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
1113 xx = rpmdbAppendIterator(mi, ts->removedPackages, ts->numRemovedPackages);
1114 while ((h = rpmdbNextIterator(mi)) != NULL) {
1115 if (headerGetEntry(h, RPMTAG_BASENAMES, NULL, NULL, &fileCount))
1116 totalFileCount += fileCount;
1118 mi = rpmdbFreeIterator(mi);
1121 /* ===============================================
1122 * Initialize transaction element file info for package:
1124 ts->flEntries = alGetSize(ts->addedPackages) + ts->numRemovedPackages;
1125 ts->flList = xcalloc(ts->flEntries, sizeof(*ts->flList));
1128 * FIXME?: we'd be better off assembling one very large file list and
1129 * calling fpLookupList only once. I'm not sure that the speedup is
1130 * worth the trouble though.
1132 tei = teInitIterator(ts);
1133 while ((fi = teNextFi(tei)) != NULL) {
1136 fi->magic = TFIMAGIC;
1138 fi->type = ts->order[oc].type;
1145 pkgKey = ts->order[oc].u.addedKey;
1147 fi->h = alGetHeader(ts->addedPackages, pkgKey, 1);
1148 #ifdef DYING /* XXX MULTILIB multiLib from transactionElement */
1149 fi->multiLib = alGetMultiLib(ts->addedPackages, i);
1151 fi->multiLib = ts->order[oc].multiLib;
1156 fi->key = alGetKey(ts->addedPackages, pkgKey);
1158 fi->relocs = alGetRelocs(ts->addedPackages, pkgKey);
1159 fi->fd = alGetFd(ts->addedPackages, pkgKey);
1161 /*@i@*/ fi->key = ts->order[oc].key;
1162 fi->relocs = ts->order[oc].relocs;
1163 /*@i@*/ fi->fd = ts->order[oc].fd;
1166 /* XXX availablePackage can be dumped here XXX */
1168 /* XXX header arg unused. */
1169 loadFi(ts, fi, fi->h, keep_header);
1174 /* Skip netshared paths, not our i18n files, and excluded docs */
1176 /*@switchbreak@*/ break;
1178 fi->record = ts->order[oc].u.removed.dboffset;
1179 /* Retrieve erased package header from the database. */
1180 { rpmdbMatchIterator mi;
1182 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
1183 &fi->record, sizeof(fi->record));
1184 if ((fi->h = rpmdbNextIterator(mi)) != NULL)
1185 fi->h = headerLink(fi->h, "TR_REMOVED loadFi");
1186 mi = rpmdbFreeIterator(mi);
1188 if (fi->h == NULL) {
1192 /* XXX header arg unused. */
1193 loadFi(ts, fi, fi->h, 0);
1194 /*@switchbreak@*/ break;
1199 fi->fps = xmalloc(fi->fc * sizeof(*fi->fps));
1201 tei = teFreeIterator(tei);
1203 if (!ts->chrootDone) {
1205 /*@-superuser -noeffect @*/
1206 xx = chroot(ts->rootDir);
1207 /*@=superuser =noeffect @*/
1209 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1212 chroot_prefix = ts->rootDir;
1217 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1218 fpc = fpCacheCreate(totalFileCount);
1220 /* ===============================================
1221 * Add fingerprint for each file not skipped.
1223 tei = teInitIterator(ts);
1224 while ((fi = teNextFi(tei)) != NULL) {
1225 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1226 for (i = 0; i < fi->fc; i++) {
1227 if (XFA_SKIPPING(fi->actions[i]))
1228 /*@innercontinue@*/ continue;
1229 /*@-dependenttrans@*/
1230 htAddEntry(ts->ht, fi->fps + i, fi);
1231 /*@=dependenttrans@*/
1234 tei = teFreeIterator(tei);
1236 /*@-noeffectuncon @*/ /* FIX: check rc */
1237 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->flEntries,
1238 NULL, ts->notifyData));
1239 /*@=noeffectuncon@*/
1241 /* ===============================================
1242 * Compute file disposition for each package in transaction set.
1244 tei = teInitIterator(ts);
1245 while ((fi = teNextFi(tei)) != NULL) {
1246 dbiIndexSet * matches;
1249 /*@-noeffectuncon @*/ /* FIX: check rc */
1250 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, (fi - ts->flList),
1251 ts->flEntries, NULL, ts->notifyData));
1252 /*@=noeffectuncon@*/
1254 if (fi->fc == 0) continue;
1256 /* Extract file info for all files in this package from the database. */
1257 matches = xcalloc(fi->fc, sizeof(*matches));
1258 if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc)) {
1259 psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1260 return 1; /* XXX WTFO? */
1264 for (i = 0; i < fi->fc; i++)
1265 numShared += dbiIndexSetCount(matches[i]);
1267 /* Build sorted file info list for this package. */
1268 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1269 for (i = 0; i < fi->fc; i++) {
1271 * Take care not to mark files as replaced in packages that will
1272 * have been removed before we will get here.
1274 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1276 ro = dbiIndexRecordOffset(matches[i], j);
1278 for (k = 0; ro != knownBad && k < ts->orderCount; k++) {
1279 switch (ts->order[k].type) {
1281 if (ts->order[k].u.removed.dboffset == ro)
1283 /*@switchbreak@*/ break;
1285 /*@switchbreak@*/ break;
1289 shared->pkgFileNum = i;
1290 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1291 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1292 shared->isRemoved = (knownBad == ro);
1295 matches[i] = dbiFreeIndexSet(matches[i]);
1297 numShared = shared - sharedList;
1298 shared->otherPkg = -1;
1299 matches = _free(matches);
1301 /* Sort file info by other package index (otherPkg) */
1302 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1304 /* For all files from this package that are in the database ... */
1305 for (i = 0; i < numShared; i = nexti) {
1308 shared = sharedList + i;
1310 /* Find the end of the files in the other package. */
1311 for (nexti = i + 1; nexti < numShared; nexti++) {
1312 if (sharedList[nexti].otherPkg != shared->otherPkg)
1313 /*@innerbreak@*/ break;
1316 /* Is this file from a package being removed? */
1318 for (j = 0; j < ts->numRemovedPackages; j++) {
1319 if (ts->removedPackages[j] != shared->otherPkg)
1320 /*@innercontinue@*/ continue;
1322 /*@innerbreak@*/ break;
1325 /* Determine the fate of each file. */
1328 xx = handleInstInstalledFiles(ts, fi, shared, nexti - i,
1329 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)));
1330 /*@switchbreak@*/ break;
1333 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1334 /*@switchbreak@*/ break;
1340 /* Update disk space needs on each partition for this package. */
1341 handleOverlappedFiles(ts, fi);
1343 /* Check added package has sufficient space on each partition used. */
1346 if (!(ts->di && fi->fc))
1347 /*@switchbreak@*/ break;
1348 for (i = 0; i < ts->filesystemCount; i++) {
1352 /* XXX Avoid FAT and other file systems that have not inodes. */
1353 if (dip->iavail <= 0)
1354 /*@innercontinue@*/ continue;
1356 if (adj_fs_blocks(dip->bneeded) > dip->bavail)
1357 rpmProblemSetAppend(ts->probs, RPMPROB_DISKSPACE,
1358 fiGetNVR(fi), fi->key,
1359 ts->filesystems[i], NULL, NULL,
1360 (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1362 if (adj_fs_blocks(dip->ineeded) > dip->iavail)
1363 rpmProblemSetAppend(ts->probs, RPMPROB_DISKNODES,
1364 fiGetNVR(fi), fi->key,
1365 ts->filesystems[i], NULL, NULL,
1366 (adj_fs_blocks(dip->ineeded) - dip->iavail));
1368 /*@switchbreak@*/ break;
1370 /*@switchbreak@*/ break;
1373 tei = teFreeIterator(tei);
1375 if (ts->chrootDone) {
1376 /*@-superuser -noeffect @*/
1378 /*@=superuser =noeffect @*/
1380 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1382 chroot_prefix = NULL;
1384 xx = chdir(ts->currDir);
1387 /*@-noeffectuncon @*/ /* FIX: check rc */
1388 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->flEntries,
1389 NULL, ts->notifyData));
1390 /*@=noeffectuncon @*/
1392 /* ===============================================
1393 * Free unused memory as soon as possible.
1396 tei = teInitIterator(ts);
1397 while ((fi = teNextFi(tei)) != NULL) {
1400 fi->fps = _free(fi->fps);
1402 tei = teFreeIterator(tei);
1408 /* ===============================================
1409 * If unfiltered problems exist, free memory and return.
1411 if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS)
1412 || (ts->probs->numProblems &&
1413 (okProbs != NULL || rpmProblemSetTrim(ts->probs, okProbs)))
1416 *newProbs = ts->probs;
1418 ts->flList = freeFl(ts, ts->flList);
1420 if (psm->ts != NULL)
1421 psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1422 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1423 return ts->orderCount;
1427 /* ===============================================
1428 * Save removed files before erasing.
1430 if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1431 tei = teInitIterator(ts);
1432 while ((fi = teNextFi(tei)) != NULL) {
1435 /*@switchbreak@*/ break;
1437 if (ts->transFlags & RPMTRANS_FLAG_REPACKAGE) {
1438 psm->fi = rpmfiLink(fi, "tsRepackage");
1439 xx = psmStage(psm, PSM_PKGSAVE);
1440 (void) rpmfiUnlink(fi, "tsRepackage");
1443 /*@switchbreak@*/ break;
1446 tei = teFreeIterator(tei);
1449 /* ===============================================
1450 * Install and remove packages.
1453 lastKey = (alKey)-2; /* erased packages have -1 */
1454 tei = teInitIterator(ts);
1455 /*@-branchstate@*/ /* FIX: fi reload needs work */
1456 while ((fi = teNextFi(tei)) != NULL) {
1462 psm->fi = rpmfiLink(fi, "tsInstall");
1466 pkgKey = ts->order[oc].u.addedKey;
1468 rpmMessage(RPMMESS_DEBUG, "========== +++ %s-%s-%s\n",
1469 fi->name, fi->version, fi->release);
1470 h = (fi->h ? headerLink(fi->h, "TR_ADDED install") : NULL);
1472 if (fi->fd == NULL) {
1473 /*@-noeffectuncon @*/ /* FIX: ??? */
1474 fi->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1475 fi->key, ts->notifyData);
1476 /*@=noeffectuncon @*/
1477 if (fi->fd != NULL) {
1480 h = headerFree(h, "TR_ADDED install");
1482 /*@-mustmod@*/ /* LCL: segfault */
1483 rpmrc = rpmReadPackageFile(ts, fi->fd,
1484 "rpmRunTransactions", &h);
1487 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1488 /*@-noeffectuncon @*/ /* FIX: check rc */
1489 (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1491 fi->key, ts->notifyData);
1492 /*@=noeffectuncon @*/
1495 } else if (fi->h != NULL) {
1496 Header foo = relocateFileList(ts, fi, h, NULL);
1497 h = headerFree(h, "TR_ADDED read free");
1498 h = headerLink(foo, "TR_ADDED relocate xfer");
1499 foo = headerFree(foo, "TR_ADDED relocate");
1501 if (fi->fd != NULL) gotfd = 1;
1506 if (fi->fd != NULL) {
1507 Header hsave = NULL;
1510 hsave = headerLink(fi->h, "TR_ADDED fi->h hsave");
1511 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1512 fi->h = headerLink(h, "TR_ADDED fi->h link");
1514 char * fstates = fi->fstates;
1515 fileAction * actions = fi->actions;
1516 uint_32 multiLib = fi->multiLib;
1517 const void * key = fi->key;
1518 rpmRelocation * relocs = fi->relocs;
1528 fi->magic = TFIMAGIC;
1529 fi->type = ts->order[oc].type;
1531 loadFi(ts, fi, h, 1);
1532 fi->fstates = _free(fi->fstates);
1533 fi->fstates = fstates;
1534 fi->actions = _free(fi->actions);
1535 fi->actions = actions;
1536 fi->multiLib = multiLib;
1538 fi->relocs = relocs;
1540 /*@i@*/ fi->fd = fd;
1545 ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
1547 if (psmStage(psm, PSM_PKGINSTALL)) {
1551 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1553 fi->h = headerLink(hsave, "TR_ADDED fi->h restore");
1554 hsave = headerFree(hsave, "TR_ADDED hsave free");
1561 h = headerFree(h, "TR_ADDED h free");
1564 /*@-noeffectuncon @*/ /* FIX: check rc */
1565 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1566 fi->key, ts->notifyData);
1567 /*@=noeffectuncon @*/
1571 /*@switchbreak@*/ break;
1573 rpmMessage(RPMMESS_DEBUG, "========== --- %s-%s-%s\n",
1574 fi->name, fi->version, fi->release);
1576 /* If install failed, then we shouldn't erase. */
1577 if (ts->order[oc].u.removed.dependsOnKey != lastKey) {
1578 if (psmStage(psm, PSM_PKGERASE))
1582 /*@switchbreak@*/ break;
1584 xx = rpmdbSync(ts->rpmdb);
1585 (void) rpmfiUnlink(fi, "tsInstall");
1589 tei = teFreeIterator(tei);
1591 ts->flList = freeFl(ts, ts->flList);
1594 psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1596 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */