3 * Routine(s) to handle a "rpmts" transaction sets.
7 #include "rpmio_internal.h" /* XXX for pgp and beecrypt */
9 #include <rpmmacro.h> /* XXX rpmtsOpenDB() needs rpmGetPath */
11 #include "rpmdb.h" /* XXX stealing db->db_mode. */
17 #define _RPMTE_INTERNAL /* XXX te->h */
20 #define _RPMTS_INTERNAL
23 /* XXX FIXME: merge with existing (broken?) tests in system.h */
24 /* portability fiddles */
25 #if STATFS_IN_SYS_STATVFS
27 #if defined(__LCLINT__)
28 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
29 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
30 /*@globals fileSystem @*/
31 /*@modifies *buf, fileSystem @*/;
32 /*@=declundef =exportheader =protoparammatch @*/
35 # include <sys/statvfs.h>
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 rpmdb @*/ /* XXX db->db_chrootDone, NULL */
56 /*@access rpmDiskSpaceInfo @*/
61 /*@access pgpDigParams @*/
69 char * hGetNEVR(Header h, const char ** np)
71 const char * n, * v, * r;
74 (void) headerNVR(h, &n, &v, &r);
75 NVR = t = xcalloc(1, strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
88 uint_32 hGetColor(Header h)
90 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
98 if (hge(h, RPMTAG_FILECOLORS, NULL, (void **)&fcolors, &ncolors)
99 && fcolors != NULL && ncolors > 0)
102 for (i = 0; i < ncolors; i++)
103 hcolor |= fcolors[i];
111 rpmts XrpmtsUnlink(rpmts ts, const char * msg, const char * fn, unsigned ln)
115 fprintf(stderr, "--> ts %p -- %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
121 rpmts XrpmtsLink(rpmts ts, const char * msg, const char * fn, unsigned ln)
126 fprintf(stderr, "--> ts %p ++ %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
128 /*@-refcounttrans@*/ return ts; /*@=refcounttrans@*/
131 int rpmtsCloseDB(rpmts ts)
135 if (ts->rdb != NULL) {
136 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->rdb->db_getops);
137 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->rdb->db_putops);
138 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->rdb->db_delops);
139 rc = rpmdbClose(ts->rdb);
145 int rpmtsOpenDB(rpmts ts, int dbmode)
149 if (ts->rdb != NULL && ts->dbmode == dbmode)
152 (void) rpmtsCloseDB(ts);
154 /* XXX there's a potential db lock race here. */
157 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
160 dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
161 rpmMessage(RPMMESS_ERROR,
162 _("cannot open Packages database in %s\n"), dn);
168 int rpmtsInitDB(rpmts ts, int dbmode)
170 return rpmdbInit(ts->rootDir, dbmode);
173 int rpmtsRebuildDB(rpmts ts)
176 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
177 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
179 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
183 int rpmtsVerifyDB(rpmts ts)
185 return rpmdbVerify(ts->rootDir);
188 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
189 const void * keyp, size_t keylen)
191 rpmdbMatchIterator mi;
192 if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
194 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
195 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
196 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
200 rpmRC rpmtsFindPubkey(rpmts ts)
202 const void * sig = rpmtsSig(ts);
203 pgpDig dig = rpmtsDig(ts);
204 pgpDigParams sigp = rpmtsSignature(ts);
205 pgpDigParams pubp = rpmtsSignature(ts);
209 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL) {
214 if (ts->pkpkt == NULL
215 || memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid)))
218 rpmdbMatchIterator mi;
221 ts->pkpkt = _free(ts->pkpkt);
223 memset(ts->pksignid, 0, sizeof(ts->pksignid));
225 /* Retrieve the pubkey that matches the signature. */
226 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
227 while ((h = rpmdbNextIterator(mi)) != NULL) {
228 const char ** pubkeys;
231 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
233 ix = rpmdbGetIteratorFileNum(mi);
236 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
239 pubkeys = headerFreeData(pubkeys, pt);
242 mi = rpmdbFreeIterator(mi);
244 /* Was a matching pubkey found? */
245 if (ix < 0 || ts->pkpkt == NULL) {
251 * Can the pubkey packets be parsed?
252 * Do the parameters match the signature?
254 if (pgpPrtPkts(ts->pkpkt, ts->pkpktlen, NULL, 0)
255 && sigp->pubkey_algo == pubp->pubkey_algo
257 && sigp->hash_algo == pubp->hash_algo
259 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)))
261 ts->pkpkt = _free(ts->pkpkt);
267 /* XXX Verify the pubkey signature. */
269 /* Packet looks good, save the signer id. */
271 memcpy(ts->pksignid, sigp->signid, sizeof(ts->pksignid));
274 rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %s\n",
275 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
276 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
277 pgpHexStr(sigp->signid, sizeof(sigp->signid)));
283 if (ts->pkpkt == NULL) {
284 const char * pkfn = rpmExpand("%{_gpg_pubkey}", NULL);
285 if (pgpReadPkts(pkfn, &ts->pkpkt, &ts->pkpktlen) != PGPARMOR_PUBKEY) {
295 /* Retrieve parameters from pubkey packet(s). */
296 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
298 /* Do the parameters match the signature? */
299 if (sigp->pubkey_algo == pubp->pubkey_algo
301 && sigp->hash_algo == pubp->hash_algo
303 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
308 /* XXX Verify the signature signature. */
314 int rpmtsCloseSDB(rpmts ts)
318 if (ts->sdb != NULL) {
319 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->sdb->db_getops);
320 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->sdb->db_putops);
321 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->sdb->db_delops);
322 rc = rpmdbClose(ts->sdb);
328 int rpmtsOpenSDB(rpmts ts, int dbmode)
330 static int has_sdbpath = -1;
333 if (ts->sdb != NULL && ts->sdbmode == dbmode)
337 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
339 /* If not configured, don't try to open. */
340 if (has_sdbpath <= 0)
343 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
345 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
348 dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
349 rpmMessage(RPMMESS_WARNING,
350 _("cannot open Solve database in %s\n"), dn);
353 delMacro(NULL, "_dbpath");
359 * Compare suggested package resolutions (qsort/bsearch).
360 * @param a 1st instance address
361 * @param b 2nd instance address
362 * @return result of comparison
364 static int sugcmp(const void * a, const void * b)
368 const char * astr = *(const char **)a;
369 const char * bstr = *(const char **)b;
371 return strcmp(astr, bstr);
375 int rpmtsSolve(rpmts ts, rpmds ds, /*@unused@*/ const void * data)
380 rpmdbMatchIterator mi;
388 int rc = 1; /* assume not found */
391 /* Make suggestions only for install Requires: */
392 if (ts->goal != TSM_INSTALL)
395 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
402 if (ts->sdb == NULL) {
403 xx = rpmtsOpenSDB(ts, ts->sdbmode);
407 /* Look for a matching Provides: in suggested universe. */
408 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
410 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
414 while ((h = rpmdbNextIterator(mi)) != NULL) {
420 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
423 /* XXX Prefer the shortest name if given alternatives. */
426 if (headerGetEntry(h, RPMTAG_NAME, NULL, (void **)&hname, NULL)) {
428 hnamelen = strlen(hname);
430 if (bhnamelen > 0 && hnamelen > bhnamelen)
433 /* XXX Prefer the newest build if given alternatives. */
435 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (void **)&ip, NULL))
444 bhnamelen = hnamelen;
446 mi = rpmdbFreeIterator(mi);
448 /* Is there a suggested resolution? */
452 /* Format the suggestion. */
453 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
454 if (qfmt == NULL || *qfmt == '\0')
456 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
460 rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
464 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
469 fd = Fopen(str, "r.ufdio");
470 if (fd == NULL || Ferror(fd)) {
471 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), str,
480 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
486 case RPMRC_NOTTRUSTED:
490 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
492 rpmMessage(RPMMESS_DEBUG, _("Adding: %s\n"), str);
494 /* XXX str memory leak */
504 rpmMessage(RPMMESS_DEBUG, _("Suggesting: %s\n"), str);
505 /* If suggestion is already present, don't bother. */
506 if (ts->suggests != NULL && ts->nsuggests > 0) {
507 if (bsearch(&str, ts->suggests, ts->nsuggests,
508 sizeof(*ts->suggests), sugcmp))
512 /* Add a new (unique) suggestion. */
513 ts->suggests = xrealloc(ts->suggests,
514 sizeof(*ts->suggests) * (ts->nsuggests + 2));
515 ts->suggests[ts->nsuggests] = str;
517 ts->suggests[ts->nsuggests] = NULL;
519 if (ts->nsuggests > 1)
520 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
523 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
529 int rpmtsAvailable(rpmts ts, const rpmds ds)
532 int rc = 1; /* assume not found */
534 if (ts->availablePackages == NULL)
536 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
540 /* XXX no alternatives yet */
541 if (sugkey[0] != NULL) {
542 ts->suggests = xrealloc(ts->suggests,
543 sizeof(*ts->suggests) * (ts->nsuggests + 2));
544 ts->suggests[ts->nsuggests] = sugkey[0];
547 ts->suggests[ts->nsuggests] = NULL;
549 sugkey = _free(sugkey);
550 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
555 int rpmtsSetSolveCallback(rpmts ts,
556 int (*solve) (rpmts ts, rpmds key, const void * data),
557 const void * solveData)
563 /*@-assignexpose -temptrans @*/
565 ts->solveData = solveData;
566 /*@=assignexpose =temptrans @*/
572 rpmps rpmtsProblems(rpmts ts)
577 ps = rpmpsLink(ts->probs, NULL);
582 void rpmtsCleanDig(rpmts ts)
584 ts->sig = headerFreeData(ts->sig, ts->sigtype);
585 ts->dig = pgpFreeDig(ts->dig);
588 void rpmtsClean(rpmts ts)
595 /* Clean up after dependency checks. */
597 while ((p = rpmtsiNext(pi, 0)) != NULL)
601 ts->addedPackages = rpmalFree(ts->addedPackages);
602 ts->numAddedPackages = 0;
604 ts->suggests = _free(ts->suggests);
607 ts->probs = rpmpsFree(ts->probs);
612 void rpmtsEmpty(rpmts ts)
620 /*@-nullstate@*/ /* FIX: partial annotations */
624 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
625 /*@-type -unqualifiedtrans @*/
626 ts->order[oc] = rpmteFree(ts->order[oc]);
627 /*@=type =unqualifiedtrans @*/
633 ts->numRemovedPackages = 0;
634 /*@-nullstate@*/ /* FIX: partial annotations */
639 static void rpmtsPrintStat(const char * name, /*@null@*/ struct rpmop_s * op)
640 /*@globals fileSystem @*/
641 /*@modifies fileSystem @*/
643 static unsigned int scale = (1000 * 1000);
644 if (op != NULL && op->count > 0)
645 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
647 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
648 op->usecs/scale, op->usecs%scale);
651 static void rpmtsPrintStats(rpmts ts)
652 /*@globals fileSystem, internalState @*/
653 /*@modifies fileSystem, internalState @*/
655 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
657 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
658 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
659 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
660 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
661 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
662 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
663 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
664 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
665 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
666 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
667 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
668 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
669 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
670 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
671 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
672 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
673 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
676 rpmts rpmtsFree(rpmts ts)
682 return rpmtsUnlink(ts, "tsCreate");
684 /*@-nullstate@*/ /* FIX: partial annotations */
688 (void) rpmtsCloseDB(ts);
690 (void) rpmtsCloseSDB(ts);
692 ts->removedPackages = _free(ts->removedPackages);
694 ts->availablePackages = rpmalFree(ts->availablePackages);
695 ts->numAvailablePackages = 0;
697 ts->dsi = _free(ts->dsi);
699 if (ts->scriptFd != NULL) {
700 ts->scriptFd = fdFree(ts->scriptFd, "rpmtsFree");
703 ts->rootDir = _free(ts->rootDir);
704 ts->currDir = _free(ts->currDir);
706 /*@-type +voidabstract @*/ /* FIX: double indirection */
707 ts->order = _free(ts->order);
708 /*@=type =voidabstract @*/
709 ts->orderAlloced = 0;
711 if (ts->pkpkt != NULL)
712 ts->pkpkt = _free(ts->pkpkt);
714 memset(ts->pksignid, 0, sizeof(ts->pksignid));
719 (void) rpmtsUnlink(ts, "tsCreate");
721 /*@-refcounttrans -usereleased @*/
723 /*@=refcounttrans =usereleased @*/
728 rpmVSFlags rpmtsVSFlags(rpmts ts)
730 rpmVSFlags vsflags = 0;
732 vsflags = ts->vsflags;
736 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
738 rpmVSFlags ovsflags = 0;
740 ovsflags = ts->vsflags;
741 ts->vsflags = vsflags;
746 int rpmtsUnorderedSuccessors(rpmts ts, int first)
748 int unorderedSuccessors = 0;
750 unorderedSuccessors = ts->unorderedSuccessors;
752 ts->unorderedSuccessors = first;
754 return unorderedSuccessors;
757 const char * rpmtsRootDir(rpmts ts)
759 return (ts != NULL ? ts->rootDir : NULL);
762 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
767 ts->rootDir = _free(ts->rootDir);
769 if (rootDir == NULL) {
771 ts->rootDir = xstrdup("");
775 rootLen = strlen(rootDir);
778 /* Make sure that rootDir has trailing / */
779 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
780 char * t = alloca(rootLen + 2);
782 (void) stpcpy( stpcpy(t, rootDir), "/");
786 ts->rootDir = xstrdup(rootDir);
790 const char * rpmtsCurrDir(rpmts ts)
792 const char * currDir = NULL;
794 currDir = ts->currDir;
799 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
802 ts->currDir = _free(ts->currDir);
804 ts->currDir = xstrdup(currDir);
808 FD_t rpmtsScriptFd(rpmts ts)
810 FD_t scriptFd = NULL;
812 scriptFd = ts->scriptFd;
814 /*@-compdef -refcounttrans -usereleased@*/
816 /*@=compdef =refcounttrans =usereleased@*/
819 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
823 if (ts->scriptFd != NULL) {
824 ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
828 if (scriptFd != NULL)
829 ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
834 int rpmtsChrootDone(rpmts ts)
838 chrootDone = ts->chrootDone;
843 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
847 ochrootDone = ts->chrootDone;
849 ts->rdb->db_chrootDone = chrootDone;
850 ts->chrootDone = chrootDone;
855 int_32 rpmtsGetTid(rpmts ts)
864 int_32 rpmtsSetTid(rpmts ts, int_32 tid)
874 int_32 rpmtsSigtag(const rpmts ts)
882 int_32 rpmtsSigtype(const rpmts ts)
886 sigtype = ts->sigtype;
890 const void * rpmtsSig(const rpmts ts)
892 const void * sig = NULL;
898 int_32 rpmtsSiglen(const rpmts ts)
906 int rpmtsSetSig(rpmts ts,
907 int_32 sigtag, int_32 sigtype, const void * sig, int_32 siglen)
910 if (ts->sig && ts->sigtype)
911 ts->sig = headerFreeData(ts->sig, ts->sigtype);
913 ts->sigtype = (sig ? sigtype : 0);
914 /*@-assignexpose -kepttrans@*/
916 /*@=assignexpose =kepttrans@*/
922 pgpDig rpmtsDig(rpmts ts)
924 /*@-mods@*/ /* FIX: hide lazy malloc for now */
926 ts->dig = pgpNewDig();
933 pgpDigParams rpmtsSignature(const rpmts ts)
935 pgpDig dig = rpmtsDig(ts);
936 if (dig == NULL) return NULL;
937 /*@-immediatetrans@*/
938 return &dig->signature;
939 /*@=immediatetrans@*/
942 pgpDigParams rpmtsPubkey(const rpmts ts)
944 pgpDig dig = rpmtsDig(ts);
945 if (dig == NULL) return NULL;
946 /*@-immediatetrans@*/
948 /*@=immediatetrans@*/
951 rpmdb rpmtsGetRdb(rpmts ts)
957 /*@-compdef -refcounttrans -usereleased @*/
959 /*@=compdef =refcounttrans =usereleased @*/
962 int rpmtsInitDSI(const rpmts ts)
964 rpmDiskSpaceInfo dsi;
969 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
972 rpmMessage(RPMMESS_DEBUG, _("mounted filesystems:\n"));
973 rpmMessage(RPMMESS_DEBUG,
974 _(" i dev bsize bavail iavail mount point\n"));
976 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
977 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
980 /* Get available space on mounted file systems. */
982 ts->dsi = _free(ts->dsi);
983 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
988 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
989 #if STATFS_IN_SYS_STATVFS
991 memset(&sfb, 0, sizeof(sfb));
992 rc = statvfs(ts->filesystems[i], &sfb);
995 memset(&sfb, 0, sizeof(sfb));
997 /* This platform has the 4-argument version of the statfs call. The last two
998 * should be the size of struct statfs and 0, respectively. The 0 is the
999 * filesystem type, and is always 0 when statfs is called on a mounted
1000 * filesystem, as we're doing.
1002 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1004 rc = statfs(ts->filesystems[i], &sfb);
1010 rc = stat(ts->filesystems[i], &sb);
1013 dsi->dev = sb.st_dev;
1015 dsi->bsize = sfb.f_bsize;
1018 #ifdef STATFS_HAS_F_BAVAIL
1019 dsi->bavail = sfb.f_bavail;
1021 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1022 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1023 * it's about all we can do.
1025 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1027 /* XXX Avoid FAT and other file systems that have not inodes. */
1028 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1030 rpmMessage(RPMMESS_DEBUG, _("%5d 0x%04x %5u %12ld %12ld %s\n"),
1031 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1032 (signed long) dsi->bavail, (signed long) dsi->iavail,
1033 ts->filesystems[i]);
1038 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1039 uint_32 fileSize, uint_32 prevSize, uint_32 fixupSize,
1042 rpmDiskSpaceInfo dsi;
1047 while (dsi->bsize && dsi->dev != dev)
1049 if (dsi->bsize == 0)
1055 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1062 dsi->bneeded += bneeded;
1063 /*@switchbreak@*/ break;
1066 * FIXME: If two packages share a file (same md5sum), and
1067 * that file is being replaced on disk, will dsi->bneeded get
1068 * adjusted twice? Quite probably!
1071 dsi->bneeded += bneeded;
1072 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1073 /*@switchbreak@*/ break;
1077 dsi->bneeded -= bneeded;
1078 /*@switchbreak@*/ break;
1081 /*@switchbreak@*/ break;
1085 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1088 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1090 rpmDiskSpaceInfo dsi;
1095 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1101 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1105 ps = rpmtsProblems(ts);
1106 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1108 if (dsi->bavail > 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1109 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1110 rpmteNEVR(te), rpmteKey(te),
1111 ts->filesystems[i], NULL, NULL,
1112 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1115 if (dsi->iavail > 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1116 rpmpsAppend(ps, RPMPROB_DISKNODES,
1117 rpmteNEVR(te), rpmteKey(te),
1118 ts->filesystems[i], NULL, NULL,
1119 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1125 void * rpmtsNotify(rpmts ts, rpmte te,
1126 rpmCallbackType what, unsigned long amount, unsigned long total)
1129 if (ts && ts->notify && te) {
1130 assert(!(te->type == TR_ADDED && te->h == NULL));
1131 /*@-type@*/ /* FIX: cast? */
1132 /*@-noeffectuncon @*/ /* FIX: check rc */
1133 ptr = ts->notify(te->h, what, amount, total,
1134 rpmteKey(te), ts->notifyData);
1135 /*@=noeffectuncon @*/
1141 int rpmtsNElements(rpmts ts)
1144 if (ts != NULL && ts->order != NULL) {
1145 nelements = ts->orderCount;
1150 rpmte rpmtsElement(rpmts ts, int ix)
1153 if (ts != NULL && ts->order != NULL) {
1154 if (ix >= 0 && ix < ts->orderCount)
1162 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1164 return (ts != NULL ? ts->ignoreSet : 0);
1167 rpmtransFlags rpmtsFlags(rpmts ts)
1169 return (ts != NULL ? ts->transFlags : 0);
1172 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1174 rpmtransFlags otransFlags = 0;
1176 otransFlags = ts->transFlags;
1177 ts->transFlags = transFlags;
1182 Spec rpmtsSpec(rpmts ts)
1184 /*@-compdef -retexpose -usereleased@*/
1186 /*@=compdef =retexpose =usereleased@*/
1189 Spec rpmtsSetSpec(rpmts ts, Spec spec)
1191 Spec ospec = ts->spec;
1192 /*@-assignexpose -temptrans@*/
1194 /*@=assignexpose =temptrans@*/
1198 rpmte rpmtsRelocateElement(rpmts ts)
1200 /*@-compdef -retexpose -usereleased@*/
1201 return ts->relocateElement;
1202 /*@=compdef =retexpose =usereleased@*/
1205 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1207 rpmte orelocateElement = ts->relocateElement;
1208 /*@-assignexpose -temptrans@*/
1209 ts->relocateElement = relocateElement;
1210 /*@=assignexpose =temptrans@*/
1211 return orelocateElement;
1214 uint_32 rpmtsColor(rpmts ts)
1216 return (ts != NULL ? ts->color : 0);
1219 uint_32 rpmtsSetColor(rpmts ts, uint_32 color)
1229 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1233 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1235 /*@-usereleased -compdef @*/
1237 /*@=usereleased =compdef @*/
1240 int rpmtsSetNotifyCallback(rpmts ts,
1241 rpmCallbackFunction notify, rpmCallbackData notifyData)
1244 ts->notify = notify;
1245 ts->notifyData = notifyData;
1250 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1254 if (nep) *nep = ts->orderCount;
1259 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1260 pi = rpmtsiInit(ts);
1261 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1262 switch (rpmteType(p)) {
1264 /*@-dependenttrans@*/
1266 /*@=dependenttrans@*/
1267 /*@switchbreak@*/ break;
1271 /*@switchbreak@*/ break;
1275 pi = rpmtsiFree(pi);
1280 rpmts rpmtsCreate(void)
1284 ts = xcalloc(1, sizeof(*ts));
1285 memset(&ts->ops, 0, sizeof(ts->ops));
1286 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1287 ts->goal = TSM_UNKNOWN;
1288 ts->filesystemCount = 0;
1289 ts->filesystems = NULL;
1292 ts->solve = rpmtsSolve;
1293 ts->solveData = NULL;
1295 ts->suggests = NULL;
1297 ts->sdbmode = O_RDONLY;
1300 ts->dbmode = O_RDONLY;
1302 ts->scriptFd = NULL;
1303 ts->tid = (int_32) time(NULL);
1306 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1308 ts->numRemovedPackages = 0;
1309 ts->allocedRemovedPackages = ts->delta;
1310 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1311 sizeof(*ts->removedPackages));
1317 ts->numAddedPackages = 0;
1318 ts->addedPackages = NULL;
1320 ts->numAvailablePackages = 0;
1321 ts->availablePackages = NULL;
1323 ts->orderAlloced = 0;
1332 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1337 return rpmtsLink(ts, "tsCreate");