2 * \file lib/transaction.c
7 #include <rpmmacro.h> /* XXX for rpmExpand */
10 #define _NEED_TEITERATOR 1
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 @*/
65 /*@access teIterator @*/
66 /*@access transactionElement @*/
67 /*@access rpmTransactionSet @*/
71 struct diskspaceInfo {
72 dev_t dev; /*!< File system device number. */
73 signed long bneeded; /*!< No. of blocks needed. */
74 signed long ineeded; /*!< No. of inodes needed. */
75 int bsize; /*!< File system block size. */
76 signed long bavail; /*!< No. of blocks available. */
77 signed long iavail; /*!< No. of inodes available. */
81 * Adjust for root only reserved space. On linux e2fs, this is 5%.
83 #define adj_fs_blocks(_nb) (((_nb) * 21) / 20)
85 /* argon thought a shift optimization here was a waste of time... he's
87 #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block))
89 void rpmtransSetScriptFd(rpmTransactionSet ts, FD_t fd)
91 ts->scriptFd = (fd ? fdLink(fd, "rpmtransSetScriptFd") : NULL);
94 int rpmtransGetKeys(const rpmTransactionSet ts, fnpyKey ** ep, int * nep)
98 if (nep) *nep = ts->orderCount;
100 teIterator pi; transactionElement p;
103 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
104 pi = teInitIterator(ts);
105 while ((p = teNextIterator(pi)) != NULL) {
108 /*@-dependenttrans@*/
110 /*@=dependenttrans@*/
111 /*@switchbreak@*/ break;
114 /*@-mods@*/ /* FIX: double indirection. */
117 /*@switchbreak@*/ break;
121 pi = teFreeIterator(pi);
128 static int archOkay(/*@null@*/ const char * pkgArch)
131 if (pkgArch == NULL) return 0;
132 return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
137 static int osOkay(/*@null@*/ const char * pkgOs)
140 if (pkgOs == NULL) return 0;
141 return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
146 static int sharedCmp(const void * one, const void * two)
149 sharedFileInfo a = (sharedFileInfo) one;
150 sharedFileInfo b = (sharedFileInfo) two;
152 if (a->otherPkg < b->otherPkg)
154 else if (a->otherPkg > b->otherPkg)
162 static fileAction decideFileFate(const char * dirName,
163 const char * baseName, short dbMode,
164 const char * dbMd5, const char * dbLink, short newMode,
165 const char * newMd5, const char * newLink, int newFlags,
166 rpmtransFlags transFlags)
167 /*@globals fileSystem @*/
168 /*@modifies fileSystem @*/
171 const char * dbAttr, * newAttr;
172 fileTypes dbWhat, newWhat, diskWhat;
175 int save = (newFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SAVE;
176 char * filespec = alloca(strlen(dirName) + strlen(baseName) + 1);
178 (void) stpcpy( stpcpy(filespec, dirName), baseName);
180 if (lstat(filespec, &sb)) {
182 * The file doesn't exist on the disk. Create it unless the new
183 * package has marked it as missingok, or allfiles is requested.
185 if (!(transFlags & RPMTRANS_FLAG_ALLFILES) &&
186 (newFlags & RPMFILE_MISSINGOK)) {
187 rpmMessage(RPMMESS_DEBUG, _("%s skipped due to missingok flag\n"),
195 diskWhat = whatis(sb.st_mode);
196 dbWhat = whatis(dbMode);
197 newWhat = whatis(newMode);
199 /* RPM >= 2.3.10 shouldn't create config directories -- we'll ignore
200 them in older packages as well */
201 if (newWhat == XDIR) {
205 if (diskWhat != newWhat) {
207 } else if (newWhat != dbWhat && diskWhat != dbWhat) {
209 } else if (dbWhat != newWhat) {
211 } else if (dbWhat != LINK && dbWhat != REG) {
216 rc = mdfile(filespec, buffer);
219 /* assume the file has been removed, don't freak */
224 } else /* dbWhat == LINK */ {
225 memset(buffer, 0, sizeof(buffer));
226 i = readlink(filespec, buffer, sizeof(buffer) - 1);
228 /* assume the file has been removed, don't freak */
235 /* this order matters - we'd prefer to CREATE the file if at all
236 possible in case something else (like the timestamp) has changed */
238 if (!strcmp(dbAttr, buffer)) {
239 /* this config file has never been modified, so just replace it */
243 if (!strcmp(dbAttr, newAttr)) {
244 /* this file is the same in all versions of this package */
249 * The config file on the disk has been modified, but
250 * the ones in the two packages are different. It would
251 * be nice if RPM was smart enough to at least try and
252 * merge the difference ala CVS, but...
259 static int filecmp(short mode1, const char * md51, const char * link1,
260 short mode2, const char * md52, const char * link2)
263 fileTypes what1 = whatis(mode1);
264 fileTypes what2 = whatis(mode2);
266 if (what1 != what2) return 1;
269 return strcmp(link1, link2);
270 else if (what1 == REG)
271 return strcmp(md51, md52);
278 /* XXX only ts->{probs,rpmdb} modified */
279 static int handleInstInstalledFiles(const rpmTransactionSet ts,
280 transactionElement p, TFI_t fi,
281 sharedFileInfo shared,
282 int sharedCount, int reportConflicts)
283 /*@globals fileSystem @*/
284 /*@modifies ts, fi, fileSystem @*/
287 HFD_t hfd = (fi->hfd ? fi->hfd : headerFreeData);
288 rpmtransFlags transFlags = ts->transFlags;
289 rpmTagType oltype, omtype;
292 const char ** otherMd5s;
293 const char ** otherLinks;
294 const char * otherStates;
295 uint_32 * otherFlags;
296 uint_32 * otherSizes;
297 uint_16 * otherModes;
301 rpmdbMatchIterator mi;
303 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
304 &shared->otherPkg, sizeof(shared->otherPkg));
305 h = rpmdbNextIterator(mi);
307 mi = rpmdbFreeIterator(mi);
311 xx = hge(h, RPMTAG_FILEMD5S, &omtype, (void **) &otherMd5s, NULL);
312 xx = hge(h, RPMTAG_FILELINKTOS, &oltype, (void **) &otherLinks, NULL);
313 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
314 xx = hge(h, RPMTAG_FILEMODES, NULL, (void **) &otherModes, NULL);
315 xx = hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &otherFlags, NULL);
316 xx = hge(h, RPMTAG_FILESIZES, NULL, (void **) &otherSizes, NULL);
318 fi->replaced = xmalloc(sharedCount * sizeof(*fi->replaced));
320 for (i = 0; i < sharedCount; i++, shared++) {
321 int otherFileNum, fileNum;
322 otherFileNum = shared->otherFileNum;
323 fileNum = shared->pkgFileNum;
325 /* XXX another tedious segfault, assume file state normal. */
326 if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
329 if (XFA_SKIPPING(fi->actions[fileNum]))
332 if (filecmp(otherModes[otherFileNum],
333 otherMd5s[otherFileNum],
334 otherLinks[otherFileNum],
337 fi->flinks[fileNum])) {
338 /*@-compdef@*/ /* FIX: *fi->replaced undefined */
339 if (reportConflicts) {
340 const char * altNEVR = hGetNEVR(h, NULL);
341 rpmProblemSetAppend(ts->probs, RPMPROB_FILE_CONFLICT,
343 fi->dnl[fi->dil[fileNum]], fi->bnl[fileNum],
346 altNEVR = _free(altNEVR);
349 if (!(otherFlags[otherFileNum] | fi->fflags[fileNum])
352 if (!shared->isRemoved)
353 fi->replaced[numReplaced++] = *shared;
358 if ((otherFlags[otherFileNum] | fi->fflags[fileNum]) & RPMFILE_CONFIG) {
359 fi->actions[fileNum] = decideFileFate(
360 fi->dnl[fi->dil[fileNum]],
362 otherModes[otherFileNum],
363 otherMd5s[otherFileNum],
364 otherLinks[otherFileNum],
372 fi->replacedSizes[fileNum] = otherSizes[otherFileNum];
375 otherMd5s = hfd(otherMd5s, omtype);
376 otherLinks = hfd(otherLinks, oltype);
377 mi = rpmdbFreeIterator(mi);
379 fi->replaced = xrealloc(fi->replaced, /* XXX memory leak */
380 sizeof(*fi->replaced) * (numReplaced + 1));
381 fi->replaced[numReplaced].otherPkg = 0;
388 /* XXX only ts->rpmdb modified */
389 static int handleRmvdInstalledFiles(const rpmTransactionSet ts, TFI_t fi,
390 sharedFileInfo shared, int sharedCount)
391 /*@globals fileSystem @*/
392 /*@modifies ts, fi, fileSystem @*/
396 const char * otherStates;
399 rpmdbMatchIterator mi;
401 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
402 &shared->otherPkg, sizeof(shared->otherPkg));
403 h = rpmdbNextIterator(mi);
405 mi = rpmdbFreeIterator(mi);
409 xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
411 for (i = 0; i < sharedCount; i++, shared++) {
412 int otherFileNum, fileNum;
413 otherFileNum = shared->otherFileNum;
414 fileNum = shared->pkgFileNum;
416 if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
419 fi->actions[fileNum] = FA_SKIP;
422 mi = rpmdbFreeIterator(mi);
428 * Update disk space needs on each partition for this package.
430 /* XXX only ts->{probs,di} modified */
431 static void handleOverlappedFiles(const rpmTransactionSet ts,
432 const transactionElement p, TFI_t fi)
433 /*@globals fileSystem @*/
434 /*@modifies ts, fi, fileSystem @*/
436 struct diskspaceInfo * ds = NULL;
437 uint_32 fixupSize = 0;
438 char * filespec = NULL;
439 int fileSpecAlloced = 0;
442 for (i = 0; i < fi->fc; i++) {
443 int otherPkgNum, otherFileNum;
447 if (XFA_SKIPPING(fi->actions[i]))
450 j = strlen(fi->dnl[fi->dil[i]]) + strlen(fi->bnl[i]) + 1;
452 if (j > fileSpecAlloced) {
453 fileSpecAlloced = j * 2;
454 filespec = xrealloc(filespec, fileSpecAlloced);
458 (void) stpcpy( stpcpy( filespec, fi->dnl[fi->dil[i]]), fi->bnl[i]);
462 while (ds->bsize && ds->dev != fi->fps[i].entry->dev) ds++;
463 if (!ds->bsize) ds = NULL;
468 * Retrieve all records that apply to this file. Note that the
469 * file info records were built in the same order as the packages
470 * will be installed and removed so the records for an overlapped
471 * files will be sorted in exactly the same order.
473 (void) htGetEntry(ts->ht, &fi->fps[i],
474 (const void ***) &recs, &numRecs, NULL);
477 * If this package is being added, look only at other packages
478 * being added -- removed packages dance to a different tune.
479 * If both this and the other package are being added, overlapped
480 * files must be identical (or marked as a conflict). The
481 * disposition of already installed config files leads to
482 * a small amount of extra complexity.
484 * If this package is being removed, then there are two cases that
485 * need to be worried about:
486 * If the other package is being added, then skip any overlapped files
487 * so that this package removal doesn't nuke the overlapped files
488 * that were just installed.
489 * If both this and the other package are being removed, then each
490 * file removal from preceding packages needs to be skipped so that
491 * the file removal occurs only on the last occurence of an overlapped
492 * file in the transaction set.
496 /* Locate this overlapped file in the set of added/removed packages. */
497 for (j = 0; j < numRecs && recs[j] != fi; j++)
500 /* Find what the previous disposition of this file was. */
501 otherFileNum = -1; /* keep gcc quiet */
502 for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
503 /* Added packages need only look at other added packages. */
504 if (p->type == TR_ADDED && recs[otherPkgNum]->te->type != TR_ADDED)
505 /*@innercontinue@*/ continue;
507 /* TESTME: there are more efficient searches in the world... */
508 for (otherFileNum = 0;
509 otherFileNum < recs[otherPkgNum]->fc;
513 /* If the addresses are the same, so are the values. */
514 if ((fi->fps + i) == (recs[otherPkgNum]->fps + otherFileNum))
515 /*@innerbreak@*/ break;
517 /* Otherwise, compare fingerprints by value. */
518 /*@-nullpass@*/ /* LCL: looks good to me */
519 if (FP_EQUAL(fi->fps[i], recs[otherPkgNum]->fps[otherFileNum]))
520 /*@innerbreak@*/ break;
524 /* XXX is this test still necessary? */
525 if (recs[otherPkgNum]->actions[otherFileNum] != FA_UNKNOWN)
526 /*@innerbreak@*/ break;
532 if (otherPkgNum < 0) {
533 /* XXX is this test still necessary? */
534 if (fi->actions[i] != FA_UNKNOWN)
535 /*@switchbreak@*/ break;
536 if ((fi->fflags[i] & RPMFILE_CONFIG) &&
537 !lstat(filespec, &sb)) {
538 /* Here is a non-overlapped pre-existing config file. */
539 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
540 ? FA_ALTNAME : FA_BACKUP;
542 fi->actions[i] = FA_CREATE;
544 /*@switchbreak@*/ break;
547 /* Mark added overlapped non-identical files as a conflict. */
548 /*@-branchstate@*/ /* FIX: p->key ??? */
549 if ((ts->ignoreSet & RPMPROB_FILTER_REPLACENEWFILES)
550 && filecmp(recs[otherPkgNum]->fmodes[otherFileNum],
551 recs[otherPkgNum]->fmd5s[otherFileNum],
552 recs[otherPkgNum]->flinks[otherFileNum],
557 const char * altNEVR = recs[otherPkgNum]->te->NEVR;
558 rpmProblemSetAppend(ts->probs, RPMPROB_NEW_FILE_CONFLICT,
566 /* Try to get the disk accounting correct even if a conflict. */
567 fixupSize = recs[otherPkgNum]->fsizes[otherFileNum];
569 if ((fi->fflags[i] & RPMFILE_CONFIG) && !lstat(filespec, &sb)) {
570 /* Here is an overlapped pre-existing config file. */
571 fi->actions[i] = (fi->fflags[i] & RPMFILE_NOREPLACE)
572 ? FA_ALTNAME : FA_SKIP;
574 fi->actions[i] = FA_CREATE;
576 } /*@switchbreak@*/ break;
578 if (otherPkgNum >= 0) {
579 /* Here is an overlapped added file we don't want to nuke. */
580 if (recs[otherPkgNum]->actions[otherFileNum] != FA_ERASE) {
581 /* On updates, don't remove files. */
582 fi->actions[i] = FA_SKIP;
583 /*@switchbreak@*/ break;
585 /* Here is an overlapped removed file: skip in previous. */
586 recs[otherPkgNum]->actions[otherFileNum] = FA_SKIP;
588 if (XFA_SKIPPING(fi->actions[i]))
589 /*@switchbreak@*/ break;
590 if (fi->fstates && fi->fstates[i] != RPMFILE_STATE_NORMAL)
591 /*@switchbreak@*/ break;
592 if (!(S_ISREG(fi->fmodes[i]) && (fi->fflags[i] & RPMFILE_CONFIG))) {
593 fi->actions[i] = FA_ERASE;
594 /*@switchbreak@*/ break;
597 /* Here is a pre-existing modified config file that needs saving. */
599 if (!mdfile(filespec, mdsum) && strcmp(fi->fmd5s[i], mdsum)) {
600 fi->actions[i] = FA_BACKUP;
601 /*@switchbreak@*/ break;
604 fi->actions[i] = FA_ERASE;
605 /*@switchbreak@*/ break;
609 uint_32 s = BLOCK_ROUND(fi->fsizes[i], ds->bsize);
611 switch (fi->actions[i]) {
617 /*@switchbreak@*/ break;
620 * FIXME: If two packages share a file (same md5sum), and
621 * that file is being replaced on disk, will ds->bneeded get
622 * decremented twice? Quite probably!
626 ds->bneeded -= BLOCK_ROUND(fi->replacedSizes[i], ds->bsize);
627 /*@switchbreak@*/ break;
632 /*@switchbreak@*/ break;
635 /*@switchbreak@*/ break;
638 ds->bneeded -= BLOCK_ROUND(fixupSize, ds->bsize);
641 filespec = _free(filespec);
645 * Ensure that current package is newer than installed package.
646 * @param ts transaction set
647 * @param p current transaction element
648 * @param h installed header
649 * @return 0 if not newer, 1 if okay
651 static int ensureOlder(rpmTransactionSet ts,
652 const transactionElement p, const Header h)
655 int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
661 if (p == NULL || h == NULL)
664 t = alloca(strlen(p->NEVR) + (p->epoch != NULL ? strlen(p->epoch) : 0) + 1);
667 if (p->epoch != NULL) t = stpcpy( stpcpy(t, p->epoch), ":");
668 if (p->version != NULL) t = stpcpy(t, p->version);
670 if (p->release != NULL) t = stpcpy(t, p->release);
672 req = dsSingle(RPMTAG_REQUIRENAME, p->name, reqEVR, reqFlags);
673 rc = headerMatchesDepFlags(h, req);
676 /*@-branchstate@*/ /* FIX: p->key ??? */
678 const char * altNEVR = hGetNEVR(h, NULL);
679 rpmProblemSetAppend(ts->probs, RPMPROB_OLDPACKAGE,
684 altNEVR = _free(altNEVR);
695 static void skipFiles(const rpmTransactionSet ts, TFI_t fi)
696 /*@globals rpmGlobalMacroContext @*/
697 /*@modifies fi, rpmGlobalMacroContext @*/
699 int noDocs = (ts->transFlags & RPMTRANS_FLAG_NODOCS);
700 char ** netsharedPaths = NULL;
701 const char ** languages;
702 const char * dn, * bn;
703 int dnlen, bnlen, ix;
710 noDocs = rpmExpandNumeric("%{_excludedocs}");
712 { const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
714 if (tmpPath && *tmpPath != '%')
715 netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
717 tmpPath = _free(tmpPath);
720 s = rpmExpand("%{_install_langs}", NULL);
722 if (!(s && *s != '%'))
725 languages = (const char **) splitString(s, strlen(s), ':');
731 /* Compute directory refcount, skip directory if now empty. */
732 drc = alloca(fi->dc * sizeof(*drc));
733 memset(drc, 0, fi->dc * sizeof(*drc));
734 dff = alloca(fi->dc * sizeof(*dff));
735 memset(dff, 0, fi->dc * sizeof(*dff));
737 for (i = 0; i < fi->fc; i++) {
748 /* Don't bother with skipped files */
749 if (XFA_SKIPPING(fi->actions[i])) {
755 * Skip net shared paths.
756 * Net shared paths are not relative to the current root (though
757 * they do need to take package relocations into account).
759 for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
764 if (strncmp(dn, *nsp, len))
765 /*@innercontinue@*/ continue;
766 /* Only directories or complete file paths can be net shared */
767 if (!(dn[len] == '/' || dn[len] == '\0'))
768 /*@innercontinue@*/ continue;
770 if (len < (dnlen + bnlen))
771 /*@innercontinue@*/ continue;
772 if (strncmp(dn, *nsp, dnlen))
773 /*@innercontinue@*/ continue;
774 if (strncmp(bn, (*nsp) + dnlen, bnlen))
775 /*@innercontinue@*/ continue;
777 /* Only directories or complete file paths can be net shared */
778 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
779 /*@innercontinue@*/ continue;
782 /*@innerbreak@*/ break;
786 drc[ix]--; dff[ix] = 1;
787 fi->actions[i] = FA_SKIPNETSHARED;
792 * Skip i18n language specific files.
794 if (fi->flangs && languages && *fi->flangs[i]) {
795 const char **lang, *l, *le;
796 for (lang = languages; *lang != NULL; lang++) {
797 if (!strcmp(*lang, "all"))
798 /*@innerbreak@*/ break;
799 for (l = fi->flangs[i]; *l != '\0'; l = le) {
800 for (le = l; *le != '\0' && *le != '|'; le++)
802 if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
803 /*@innerbreak@*/ break;
804 if (*le == '|') le++; /* skip over | */
807 /*@innerbreak@*/ break;
810 drc[ix]--; dff[ix] = 1;
811 fi->actions[i] = FA_SKIPNSTATE;
817 * Skip documentation if requested.
819 if (noDocs && (fi->fflags[i] & RPMFILE_DOC)) {
820 drc[ix]--; dff[ix] = 1;
821 fi->actions[i] = FA_SKIPNSTATE;
826 /* Skip (now empty) directories that had skipped files. */
827 for (j = 0; j < fi->dc; j++) {
829 if (drc[j]) continue; /* dir still has files. */
830 if (!dff[j]) continue; /* dir was not emptied here. */
832 /* Find parent directory and basename. */
833 dn = fi->dnl[j]; dnlen = strlen(dn) - 1;
834 bn = dn + dnlen; bnlen = 0;
835 while (bn > dn && bn[-1] != '/') {
841 /* If explicitly included in the package, skip the directory. */
842 for (i = 0; i < fi->fc; i++) {
845 if (XFA_SKIPPING(fi->actions[i]))
846 /*@innercontinue@*/ continue;
847 if (whatis(fi->fmodes[i]) != XDIR)
848 /*@innercontinue@*/ continue;
849 dir = fi->dnl[fi->dil[i]];
850 if (strlen(dir) != dnlen)
851 /*@innercontinue@*/ continue;
852 if (strncmp(dir, dn, dnlen))
853 /*@innercontinue@*/ continue;
854 if (strlen(fi->bnl[i]) != bnlen)
855 /*@innercontinue@*/ continue;
856 if (strncmp(fi->bnl[i], bn, bnlen))
857 /*@innercontinue@*/ continue;
858 rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
859 fi->actions[i] = FA_SKIPNSTATE;
860 /*@innerbreak@*/ break;
864 if (netsharedPaths) freeSplitString(netsharedPaths);
865 #ifdef DYING /* XXX freeFi will deal with this later. */
866 fi->flangs = _free(fi->flangs);
868 if (languages) freeSplitString((char **)languages);
871 #define NOTIFY(_ts, _al) if ((_ts)->notify) (void) (_ts)->notify _al
873 int rpmRunTransactions( rpmTransactionSet ts,
874 rpmCallbackFunction notify, rpmCallbackData notifyData,
875 rpmProblemSet okProbs, rpmProblemSet * newProbs,
876 rpmtransFlags transFlags, rpmprobFilterFlags ignoreSet)
880 int totalFileCount = 0;
882 struct diskspaceInfo * dip;
883 sharedFileInfo shared, sharedList;
887 fingerPrintCache fpc;
888 PSM_t psm = memset(alloca(sizeof(*psm)), 0, sizeof(*psm));
889 teIterator pi; transactionElement p;
890 teIterator qi; transactionElement q;
893 /* FIXME: what if the same package is included in ts twice? */
895 ts->transFlags = transFlags;
896 if (ts->transFlags & RPMTRANS_FLAG_NOSCRIPTS)
897 ts->transFlags |= (_noTransScripts | _noTransTriggers);
898 if (ts->transFlags & RPMTRANS_FLAG_NOTRIGGERS)
899 ts->transFlags |= _noTransTriggers;
901 /* XXX MULTILIB is broken, as packages can and do execute /sbin/ldconfig. */
902 if (ts->transFlags & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_MULTILIB))
903 ts->transFlags |= (_noTransScripts | _noTransTriggers);
906 ts->notifyData = notifyData;
908 ts->probs = *newProbs = rpmProblemSetCreate();
909 *newProbs = rpmpsLink(ts->probs, "RunTransactions");
911 ts->ignoreSet = ignoreSet;
912 ts->currDir = _free(ts->currDir);
913 ts->currDir = currentDirectory();
915 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
916 ts->id = (int_32) time(NULL);
918 memset(psm, 0, sizeof(*psm));
920 psm->ts = rpmtsLink(ts, "tsRun");
923 /* Get available space on mounted file systems. */
924 if (!(ts->ignoreSet & RPMPROB_FILTER_DISKSPACE) &&
925 !rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount))
929 rpmMessage(RPMMESS_DEBUG, _("getting list of mounted filesystems\n"));
931 ts->di = _free(ts->di);
932 dip = ts->di = xcalloc((ts->filesystemCount + 1), sizeof(*ts->di));
934 for (i = 0; (i < ts->filesystemCount) && dip; i++) {
935 #if STATFS_IN_SYS_STATVFS
937 memset(&sfb, 0, sizeof(sfb));
938 if (statvfs(ts->filesystems[i], &sfb))
942 /* This platform has the 4-argument version of the statfs call. The last two
943 * should be the size of struct statfs and 0, respectively. The 0 is the
944 * filesystem type, and is always 0 when statfs is called on a mounted
945 * filesystem, as we're doing.
947 memset(&sfb, 0, sizeof(sfb));
948 if (statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0))
950 memset(&sfb, 0, sizeof(sfb));
951 if (statfs(ts->filesystems[i], &sfb))
957 ts->di[i].bsize = sfb.f_bsize;
958 ts->di[i].bneeded = 0;
959 ts->di[i].ineeded = 0;
960 #ifdef STATFS_HAS_F_BAVAIL
961 ts->di[i].bavail = sfb.f_bavail;
963 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
964 * available for non-superusers. f_blocks - f_bfree is probably too big, but
965 * it's about all we can do.
967 ts->di[i].bavail = sfb.f_blocks - sfb.f_bfree;
969 /* XXX Avoid FAT and other file systems that have not inodes. */
970 ts->di[i].iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
973 xx = stat(ts->filesystems[i], &sb);
974 ts->di[i].dev = sb.st_dev;
978 if (dip) ts->di[i].bsize = 0;
981 /* ===============================================
982 * For packages being installed:
983 * - verify package arch/os.
984 * - verify package epoch:version-release is newer.
986 * For packages being removed:
989 /* The ordering doesn't matter here */
990 pi = teInitIterator(ts);
991 while ((p = teNext(pi, TR_ADDED)) != NULL) {
992 rpmdbMatchIterator mi;
994 /*@-branchstate@*/ /* FIX: p->key ??? */
995 if (!archOkay(p->arch) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREARCH))
996 rpmProblemSetAppend(ts->probs, RPMPROB_BADARCH,
1001 if (!osOkay(p->os) && !(ts->ignoreSet & RPMPROB_FILTER_IGNOREOS))
1002 rpmProblemSetAppend(ts->probs, RPMPROB_BADOS,
1008 if (!(ts->ignoreSet & RPMPROB_FILTER_OLDPACKAGE)) {
1010 mi = rpmtsInitIterator(ts, RPMTAG_NAME, p->name, 0);
1011 while ((h = rpmdbNextIterator(mi)) != NULL)
1012 xx = ensureOlder(ts, p, h);
1013 mi = rpmdbFreeIterator(mi);
1016 /* XXX multilib should not display "already installed" problems */
1017 if (!(ts->ignoreSet & RPMPROB_FILTER_REPLACEPKG) && !p->multiLib) {
1018 mi = rpmtsInitIterator(ts, RPMTAG_NAME, p->name, 0);
1019 xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT,
1021 xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT,
1024 while (rpmdbNextIterator(mi) != NULL) {
1025 rpmProblemSetAppend(ts->probs, RPMPROB_PKG_INSTALLED,
1029 /*@innerbreak@*/ break;
1031 mi = rpmdbFreeIterator(mi);
1034 /* Count no. of files (if any). */
1036 totalFileCount += p->fi->fc;
1039 pi = teFreeIterator(pi);
1041 /* The ordering doesn't matter here */
1042 pi = teInitIterator(ts);
1043 while ((p = teNext(pi, TR_REMOVED)) != NULL) {
1047 if (fi->bnl == NULL)
1048 continue; /* XXX can't happen */
1049 if (fi->dnl == NULL)
1050 continue; /* XXX can't happen */
1051 if (fi->dil == NULL)
1052 continue; /* XXX can't happen */
1053 totalFileCount += fi->fc;
1055 pi = teFreeIterator(pi);
1057 /* ===============================================
1058 * Initialize transaction element file info for package:
1062 * FIXME?: we'd be better off assembling one very large file list and
1063 * calling fpLookupList only once. I'm not sure that the speedup is
1064 * worth the trouble though.
1066 pi = teInitIterator(ts);
1067 while ((p = teNextIterator(pi)) != NULL) {
1070 if ((fi = teGetFi(pi)) == NULL)
1071 continue; /* XXX can't happen */
1073 #ifdef DYING /* XXX W2DO? this is now done teGetFi, okay ??? */
1074 fi->magic = TFIMAGIC;
1082 /* Skip netshared paths, not our i18n files, and excluded docs */
1085 /*@switchbreak@*/ break;
1087 fi->record = p->u.removed.dboffset;
1088 /*@switchbreak@*/ break;
1092 fi->fps = (fi->fc > 0 ? xmalloc(fi->fc * sizeof(*fi->fps)) : NULL);
1094 pi = teFreeIterator(pi);
1096 if (!ts->chrootDone) {
1098 /*@-superuser -noeffect @*/
1099 xx = chroot(ts->rootDir);
1100 /*@=superuser =noeffect @*/
1102 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 1;
1105 chroot_prefix = ts->rootDir;
1110 ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
1111 fpc = fpCacheCreate(totalFileCount);
1113 /* ===============================================
1114 * Add fingerprint for each file not skipped.
1116 pi = teInitIterator(ts);
1117 while ((p = teNextIterator(pi)) != NULL) {
1119 if ((fi = teGetFi(pi)) == NULL)
1120 continue; /* XXX can't happen */
1122 fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fi->fc, fi->fps);
1124 for (i = 0; i < fi->fc; i++) {
1125 if (XFA_SKIPPING(fi->actions[i]))
1126 /*@innercontinue@*/ continue;
1127 /*@-dependenttrans@*/
1128 htAddEntry(ts->ht, fi->fps + i, fi);
1129 /*@=dependenttrans@*/
1133 pi = teFreeIterator(pi);
1135 /*@-noeffectuncon @*/ /* FIX: check rc */
1136 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
1137 NULL, ts->notifyData));
1138 /*@=noeffectuncon@*/
1140 /* ===============================================
1141 * Compute file disposition for each package in transaction set.
1143 pi = teInitIterator(ts);
1144 while ((p = teNextIterator(pi)) != NULL) {
1145 dbiIndexSet * matches;
1148 if ((fi = teGetFi(pi)) == NULL)
1149 continue; /* XXX can't happen */
1151 /*@-noeffectuncon @*/ /* FIX: check rc */
1152 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, teGetOc(pi),
1153 ts->orderCount, NULL, ts->notifyData));
1154 /*@=noeffectuncon@*/
1156 if (fi->fc == 0) continue;
1158 /* Extract file info for all files in this package from the database. */
1159 matches = xcalloc(fi->fc, sizeof(*matches));
1160 if (rpmdbFindFpList(ts->rpmdb, fi->fps, matches, fi->fc)) {
1161 psm->ts = rpmtsUnlink(ts, "tsRun (rpmFindFpList fail)");
1162 return 1; /* XXX WTFO? */
1166 for (i = 0; i < fi->fc; i++)
1167 numShared += dbiIndexSetCount(matches[i]);
1169 /* Build sorted file info list for this package. */
1170 shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
1171 for (i = 0; i < fi->fc; i++) {
1173 * Take care not to mark files as replaced in packages that will
1174 * have been removed before we will get here.
1176 for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
1178 ro = dbiIndexRecordOffset(matches[i], j);
1180 qi = teInitIterator(ts);
1181 while ((q = teNext(qi, TR_REMOVED)) != NULL) {
1183 /*@innerbreak@*/ break;
1184 if (q->u.removed.dboffset == ro)
1187 qi = teFreeIterator(qi);
1189 shared->pkgFileNum = i;
1190 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
1191 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
1192 shared->isRemoved = (knownBad == ro);
1195 matches[i] = dbiFreeIndexSet(matches[i]);
1197 numShared = shared - sharedList;
1198 shared->otherPkg = -1;
1199 matches = _free(matches);
1201 /* Sort file info by other package index (otherPkg) */
1202 qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
1204 /* For all files from this package that are in the database ... */
1205 for (i = 0; i < numShared; i = nexti) {
1208 shared = sharedList + i;
1210 /* Find the end of the files in the other package. */
1211 for (nexti = i + 1; nexti < numShared; nexti++) {
1212 if (sharedList[nexti].otherPkg != shared->otherPkg)
1213 /*@innerbreak@*/ break;
1216 /* Is this file from a package being removed? */
1218 if (ts->removedPackages != NULL)
1219 for (j = 0; j < ts->numRemovedPackages; j++) {
1220 if (ts->removedPackages[j] != shared->otherPkg)
1221 /*@innercontinue@*/ continue;
1223 /*@innerbreak@*/ break;
1226 /* Determine the fate of each file. */
1229 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
1230 !(beingRemoved || (ts->ignoreSet & RPMPROB_FILTER_REPLACEOLDFILES)));
1231 /*@switchbreak@*/ break;
1234 xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
1235 /*@switchbreak@*/ break;
1241 /* Update disk space needs on each partition for this package. */
1242 handleOverlappedFiles(ts, p, fi);
1244 /* Check added package has sufficient space on each partition used. */
1247 if (!(ts->di && fi->fc))
1248 /*@switchbreak@*/ break;
1249 for (i = 0; i < ts->filesystemCount; i++) {
1253 /* XXX Avoid FAT and other file systems that have not inodes. */
1254 if (dip->iavail <= 0)
1255 /*@innercontinue@*/ continue;
1257 if (adj_fs_blocks(dip->bneeded) > dip->bavail) {
1258 rpmProblemSetAppend(ts->probs, RPMPROB_DISKSPACE,
1260 ts->filesystems[i], NULL, NULL,
1261 (adj_fs_blocks(dip->bneeded) - dip->bavail) * dip->bsize);
1264 if (adj_fs_blocks(dip->ineeded) > dip->iavail) {
1265 rpmProblemSetAppend(ts->probs, RPMPROB_DISKNODES,
1267 ts->filesystems[i], NULL, NULL,
1268 (adj_fs_blocks(dip->ineeded) - dip->iavail));
1271 /*@switchbreak@*/ break;
1273 /*@switchbreak@*/ break;
1276 pi = teFreeIterator(pi);
1278 if (ts->chrootDone) {
1279 /*@-superuser -noeffect @*/
1281 /*@=superuser =noeffect @*/
1283 if (ts->rpmdb) ts->rpmdb->db_chrootDone = 0;
1285 chroot_prefix = NULL;
1287 xx = chdir(ts->currDir);
1290 /*@-noeffectuncon @*/ /* FIX: check rc */
1291 NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
1292 NULL, ts->notifyData));
1293 /*@=noeffectuncon @*/
1295 /* ===============================================
1296 * Free unused memory as soon as possible.
1298 pi = teInitIterator(ts);
1299 while ((p = teNextIterator(pi)) != NULL) {
1300 if ((fi = teGetFi(pi)) == NULL)
1301 continue; /* XXX can't happen */
1304 fi->fps = _free(fi->fps);
1306 pi = teFreeIterator(pi);
1312 /* ===============================================
1313 * If unfiltered problems exist, free memory and return.
1315 if ((ts->transFlags & RPMTRANS_FLAG_BUILD_PROBS)
1316 || (ts->probs->numProblems &&
1317 (okProbs != NULL || rpmProblemSetTrim(ts->probs, okProbs)))
1320 if (psm->ts != NULL)
1321 psm->ts = rpmtsUnlink(psm->ts, "tsRun (problems)");
1322 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
1323 return ts->orderCount;
1327 /* ===============================================
1328 * Save removed files before erasing.
1330 if (ts->transFlags & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
1331 pi = teInitIterator(ts);
1332 while ((p = teNextIterator(pi)) != NULL) {
1336 /*@switchbreak@*/ break;
1338 if (!(ts->transFlags & RPMTRANS_FLAG_REPACKAGE))
1339 /*@switchbreak@*/ break;
1341 psm->fi = rpmfiLink(fi, "tsRepackage");
1342 xx = psmStage(psm, PSM_PKGSAVE);
1343 (void) rpmfiUnlink(fi, "tsRepackage");
1346 /*@switchbreak@*/ break;
1349 pi = teFreeIterator(pi);
1352 /* ===============================================
1353 * Install and remove packages.
1355 lastKey = (alKey)-2; /* erased packages have -1 */
1356 pi = teInitIterator(ts);
1357 /*@-branchstate@*/ /* FIX: fi reload needs work */
1358 while ((p = teNextIterator(pi)) != NULL) {
1364 if ((fi = teGetFi(pi)) == NULL)
1365 continue; /* XXX can't happen */
1368 psm->fi = rpmfiLink(fi, "tsInstall");
1372 pkgKey = p->u.addedKey;
1374 rpmMessage(RPMMESS_DEBUG, "========== +++ %s\n", p->NEVR);
1377 /*@-noeffectuncon @*/ /* FIX: ??? */
1378 p->fd = ts->notify(fi->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
1379 p->key, ts->notifyData);
1380 /*@=noeffectuncon @*/
1381 if (p->fd != NULL) {
1384 /*@-mustmod@*/ /* LCL: segfault */
1385 rpmrc = rpmReadPackageFile(ts, p->fd,
1386 "rpmRunTransactions", &h);
1389 if (!(rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE)) {
1390 /*@-noeffectuncon @*/ /* FIX: check rc */
1391 (void) ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE,
1393 p->key, ts->notifyData);
1394 /*@=noeffectuncon @*/
1398 if (p->fd != NULL) gotfd = 1;
1404 if (p->fd != NULL) {
1406 char * fstates = fi->fstates;
1407 fileAction * actions = fi->actions;
1411 (void) fiFree(fi, 0);
1413 fi->magic = TFIMAGIC;
1416 (void) fiNew(ts, fi, h, RPMTAG_BASENAMES, 1);
1417 fi->fstates = _free(fi->fstates);
1418 fi->fstates = fstates;
1419 fi->actions = _free(fi->actions);
1420 fi->actions = actions;
1425 ts->transFlags |= RPMTRANS_FLAG_MULTILIB;
1427 if (psmStage(psm, PSM_PKGINSTALL)) {
1431 fi->h = headerFree(fi->h, "TR_ADDED fi->h free");
1438 h = headerFree(h, "TR_ADDED h free");
1441 /*@-noeffectuncon @*/ /* FIX: check rc */
1442 (void)ts->notify(fi->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
1443 p->key, ts->notifyData);
1444 /*@=noeffectuncon @*/
1447 (void) fiFree(fi, 0);
1448 /*@switchbreak@*/ break;
1450 rpmMessage(RPMMESS_DEBUG, "========== --- %s\n", p->NEVR);
1451 /* If install failed, then we shouldn't erase. */
1452 if (p->u.removed.dependsOnKey != lastKey) {
1453 if (psmStage(psm, PSM_PKGERASE))
1456 (void) fiFree(fi, 0);
1457 /*@switchbreak@*/ break;
1459 xx = rpmdbSync(ts->rpmdb);
1460 (void) rpmfiUnlink(psm->fi, "tsInstall");
1465 pi = teFreeIterator(pi);
1467 psm->ts = rpmtsUnlink(psm->ts, "tsRun");
1469 /*@-nullstate@*/ /* FIX: ts->flList may be NULL */