rpm 5.3.12
lib/rpmts.c
Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>         /* XXX fnpyKey */
00009 #include <rpmlog.h>
00010 #include <iosm.h>               /* XXX iosmFileAction */
00011 #include <rpmurl.h>
00012 #include <rpmpgp.h>
00013 #include <rpmmacro.h>           /* XXX rpmtsOpenDB() needs rpmGetPath */
00014 #include <rpmkeyring.h>
00015 #include <rpmhkp.h>
00016 #include <rpmsx.h>
00017 
00018 #include <rpmtypes.h>
00019 #define _RPMTAG_INTERNAL        /* XXX tagStore_s */
00020 #include <rpmtag.h>
00021 #include <pkgio.h>
00022 
00023 #define _RPMDB_INTERNAL         /* XXX almost opaque sigh */
00024 #include "rpmdb.h"              /* XXX stealing db->db_mode. */
00025 
00026 #include "rpmal.h"
00027 #include "rpmds.h"
00028 #include "rpmfi.h"
00029 #include "rpmlock.h"
00030 #include "rpmns.h"
00031 
00032 #define _RPMTE_INTERNAL         /* XXX te->h */
00033 #include "rpmte.h"
00034 
00035 #define _RPMTS_INTERNAL
00036 #define _RPMBAG_INTERNAL
00037 #include "rpmts.h"
00038 
00039 #include <rpmcli.h>
00040 
00041 #include "fs.h"
00042 
00043 /* XXX FIXME: merge with existing (broken?) tests in system.h */
00044 /* portability fiddles */
00045 #if STATFS_IN_SYS_STATVFS
00046 /*@-incondefs@*/
00047 #if defined(__LCLINT__)
00048 /*@-declundef -exportheader -protoparammatch @*/ /* LCL: missing annotation */
00049 extern int statvfs (const char * file, /*@out@*/ struct statvfs * buf)
00050         /*@globals fileSystem @*/
00051         /*@modifies *buf, fileSystem @*/;
00052 /*@=declundef =exportheader =protoparammatch @*/
00053 /*@=incondefs@*/
00054 #else
00055 # include <sys/statvfs.h>
00056 #endif
00057 #else
00058 # if STATFS_IN_SYS_VFS
00059 #  include <sys/vfs.h>
00060 # else
00061 #  if STATFS_IN_SYS_MOUNT
00062 #   include <sys/mount.h>
00063 #  else
00064 #   if STATFS_IN_SYS_STATFS
00065 #    include <sys/statfs.h>
00066 #   endif
00067 #  endif
00068 # endif
00069 #endif
00070 
00071 #include "debug.h"
00072 
00073 /*@access FD_t @*/              /* XXX void * arg */
00074 /*@access rpmdb @*/             /* XXX db->db_chrootDone, NULL */
00075 
00076 /*@access rpmDiskSpaceInfo @*/
00077 /*@access rpmKeyring @*/
00078 /*@access rpmps @*/
00079 /*@access rpmte @*/
00080 /*@access rpmtsi @*/
00081 /*@access fnpyKey @*/
00082 /*@access pgpDig @*/
00083 /*@access pgpDigParams @*/
00084 
00085 /*@unchecked@*/
00086 int _rpmts_debug = 0;
00087 
00088 /*@unchecked@*/
00089 int _rpmts_stats = 0;
00090 
00091 /*@unchecked@*/
00092 int _rpmts_macros = 0;
00093 
00094 int rpmtsCloseDB(rpmts ts)
00095 {
00096     int rc = 0;
00097 
00098     if (ts->rdb != NULL) {
00099         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->rdb->db_getops);
00100         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->rdb->db_putops);
00101         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->rdb->db_delops);
00102         rc = rpmdbClose(ts->rdb);
00103         ts->rdb = NULL;
00104     }
00105     return rc;
00106 }
00107 
00108 int rpmtsOpenDB(rpmts ts, int dbmode)
00109 {
00110     int rc = 0;
00111 
00112     if (ts->rdb != NULL && ts->dbmode == dbmode)
00113         return 0;
00114 
00115     (void) rpmtsCloseDB(ts);
00116 
00117     /* XXX there's a db lock race here that is the callers responsibility. */
00118 
00119     ts->dbmode = dbmode;
00120     rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, (mode_t)0644);
00121     if (rc) {
00122         const char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
00123         rpmlog(RPMLOG_ERR, _("cannot open Packages database in %s\n"), dn);
00124         dn = _free(dn);
00125     }
00126     return rc;
00127 }
00128 
00129 int rpmtsRebuildDB(rpmts ts)
00130 {
00131     void * lock = rpmtsAcquireLock(ts);
00132     rpmdb db = NULL;
00133     const char * fn;
00134     struct stat sb;
00135     int rc;
00136     int xx;
00137 
00138     /* XXX Seqno update needs O_RDWR. */
00139     rc = rpmtsOpenDB(ts, O_RDWR);
00140     if (rc) goto exit;
00141     db = rpmtsGetRdb(ts);
00142 
00143     if (!(db->db_api == 3 || db->db_api == 4))
00144         goto exit;
00145 
00146     rc = rpmtxnCheckpoint(db);
00147     if (rc) goto exit;
00148 
00149   { size_t dbix;
00150     for (dbix = 0; dbix < db->db_ndbi; dbix++) {
00151         tagStore_t dbiTags = &db->db_tags[dbix];
00152 
00153         /* Remove configured secondary indices. */
00154         switch (dbiTags->tag) {
00155         case RPMDBI_PACKAGES:
00156         case RPMDBI_AVAILABLE:
00157         case RPMDBI_ADDED:
00158         case RPMDBI_REMOVED:
00159         case RPMDBI_DEPENDS:
00160         case RPMDBI_SEQNO:
00161         case RPMDBI_BTREE:
00162         case RPMDBI_HASH:
00163         case RPMDBI_QUEUE:
00164         case RPMDBI_RECNO:
00165             continue;
00166             /*@notreached@*/ /*@switchbreak@*/ break;
00167         default:
00168             fn = rpmGetPath(db->db_root, db->db_home, "/",
00169                 (dbiTags->str != NULL ? dbiTags->str : tagName(dbiTags->tag)),
00170                 NULL);
00171             if (!Stat(fn, &sb))
00172                 xx = Unlink(fn);
00173             fn = _free(fn);
00174             /*@switchbreak@*/ break;
00175         }
00176 
00177         /* Open (and re-create) each index. */
00178         (void) dbiOpen(db, dbiTags->tag, db->db_flags);
00179     }
00180   }
00181 
00182     /* Unreference header used by associated secondary index callbacks. */
00183     (void) headerFree(db->db_h);
00184     db->db_h = NULL;
00185 
00186     /* Reset the Seqno counter to the maximum primary key */
00187     rpmlog(RPMLOG_DEBUG, D_("rpmdb: max. primary key %u\n"),
00188                 (unsigned)db->db_maxkey);
00189     fn = rpmGetPath(db->db_root, db->db_home, "/Seqno", NULL);
00190     if (!Stat(fn, &sb))
00191         xx = Unlink(fn);
00192     (void) dbiOpen(db, RPMDBI_SEQNO, db->db_flags);
00193     fn = _free(fn);
00194 
00195     rc = rpmtxnCheckpoint(db);
00196 
00197     xx = rpmtsCloseDB(ts);
00198 
00199 exit:
00200     lock = rpmtsFreeLock(lock);
00201     return rc;
00202 }
00203 
00204 /*@-compdef@*/ /* keyp might not be defined. */
00205 rpmmi rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
00206                         const void * keyp, size_t keylen)
00207 {
00208     rpmmi mi = (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
00209         ? NULL
00210         : rpmmiInit(ts->rdb, rpmtag, keyp, keylen);
00211     return mi;
00212 }
00213 /*@=compdef@*/
00214 
00215 int rpmtsCloseSDB(rpmts ts)
00216 {
00217     rpmbag bag = ts->bag;
00218     int rc = 0;
00219 
00220     if (bag != NULL) {
00221         rpmsdb * sdbp = bag->sdbp;
00222         int i = bag->nsdbp;
00223         if (sdbp)
00224         while (--i >= 0) {
00225             rpmdb sdb;
00226             if (sdbp[i] == NULL)
00227                 continue;
00228             sdb = sdbp[i]->_db;
00229             if (sdb) {
00230                 int xx;
00231                 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &sdb->db_getops);
00232                 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &sdb->db_putops);
00233                 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &sdb->db_delops);
00234                 xx = rpmdbClose(sdb);
00235                 if (xx && rc == 0)
00236                     rc = xx;
00237             }
00238             (void) rpmbagDel(bag, i);
00239         }
00240         ts->bag = rpmbagFree(ts->bag);
00241     }
00242     return rc;
00243 }
00244 
00245 int rpmtsOpenSDB(rpmts ts, int dbmode)
00246 {
00247     static int has_sdbpath = -1;
00248     rpmbag bag = ts->bag;
00249     rpmsdb * sdbp = NULL;
00250     rpmdb sdb = NULL;
00251     int sdbmode = O_RDONLY;
00252     const char * s = NULL;
00253 #ifdef  DYING   /* XXX solevedb's never need chroot prefix. */
00254     const char * rootDir = ts->rootDir;
00255 #else
00256     const char * rootDir = "/";
00257 #endif
00258     ARGV_t av = NULL;
00259     int ac = 0;
00260     int rc = 0;
00261     int xx;
00262     int i;
00263 
00264     if (bag == NULL) {
00265         bag = ts->bag = rpmbagNew(NULL, 0);
00266         if (bag == NULL)
00267             goto exit;
00268     }
00269     sdbp = bag->sdbp;
00270     sdb = (sdbp[0] ? sdbp[0]->_db : NULL);
00271     sdbmode = (sdbp[0] ? sdbp[0]->dbmode : O_RDONLY);
00272 
00273     if (sdb != NULL && sdbmode == dbmode) {
00274         rc = 0;
00275         goto exit;
00276     }
00277 
00278     if (has_sdbpath < 0)
00279         has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
00280 
00281     /* If not configured, don't try to open. */
00282     if (has_sdbpath <= 0) {
00283         rc = 1;
00284         goto exit;
00285     }
00286 
00287     s = rpmExpand("%{?_solve_dbpath}", NULL);
00288     xx = argvSplit(&av, s, ":");
00289     ac = argvCount(av);
00290 
00291     for (i = 0; i < ac; i++) {
00292         const char * fn;
00293         urltype ut;
00294 
00295         if (av[i] == NULL || *av[i] == '\0')
00296             continue;
00297 
00298         fn = NULL;
00299         ut = urlPath(av[i], &fn);
00300 
00301         /* XXX Lstat(fn, &sb) to ensure a directory? */
00302         addMacro(NULL, "_dbpath", NULL, fn, RMIL_DEFAULT);
00303         xx = rpmdbOpen(rootDir, &sdb, dbmode, (mode_t)0644);
00304         delMacro(NULL, "_dbpath");
00305 
00306         if (xx) {
00307             const char * dn = rpmGetPath(rootDir, "/", fn, NULL);
00308             rpmlog(RPMLOG_WARNING, _("cannot open Solve database in %s\n"), dn);
00309             dn = _free(dn);
00310             if (rc == 0)
00311                 rc = xx;
00312 
00313             /* XXX only try to open the solvedb once. */
00314             has_sdbpath = 0;
00315             continue;
00316         }
00317 
00318         xx = rpmbagAdd(bag, sdb, dbmode);
00319     }
00320 
00321     av = argvFree(av);
00322     s = _free(s);
00323 
00324 exit:
00325 if (_rpmts_debug)
00326 fprintf(stderr, "<-- %s(%p, 0%o) rc %d\n", __FUNCTION__, ts, dbmode, rc);
00327     return rc;
00328 }
00329 
00336 static int sugcmp(const void * a, const void * b)
00337         /*@*/
00338 {
00339     const char * astr = *(const char **)a;
00340     const char * bstr = *(const char **)b;
00341     return strcmp(astr, bstr);
00342 }
00343 
00344 int rpmtsSolve(rpmts ts, rpmds ds, /*@unused@*/ const void * data)
00345 {
00346     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00347     rpmbag bag = ts->bag;
00348     rpmsdb * sdbp = NULL;
00349     const char * errstr = NULL;
00350     const char * str = NULL;
00351     rpmmi mi;
00352     Header bh = NULL;
00353     Header h = NULL;
00354     size_t bhnamelen = 0;
00355     time_t bhtime = 0;
00356     rpmTag rpmtag;
00357     const char * keyp;
00358     size_t keylen = 0;
00359     int rc = 1;         /* assume not found */
00360     int xx;
00361     int i;
00362 
00363 if (_rpmts_debug)
00364 fprintf(stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, ts, ds, data);
00365 
00366     /* Make suggestions only for installing Requires: */
00367     if (ts->goal != TSM_INSTALL)
00368         goto exit;
00369 
00370     switch (rpmdsTagN(ds)) {
00371     case RPMTAG_CONFLICTNAME:
00372     default:
00373         goto exit;
00374         /*@notreached@*/ break;
00375     case RPMTAG_DIRNAMES:       /* XXX perhaps too many wrong answers? */
00376     case RPMTAG_REQUIRENAME:
00377     case RPMTAG_FILELINKTOS:
00378         break;
00379     }
00380 
00381     keyp = rpmdsN(ds);
00382     if (keyp == NULL)
00383         goto exit;
00384 
00385     if (bag == NULL) {
00386         xx = rpmtsOpenSDB(ts, O_RDONLY);
00387         if (xx)
00388             goto exit;
00389         bag = ts->bag;
00390         if (bag == NULL)
00391             goto exit;
00392     }
00393 
00394     sdbp = bag->sdbp;
00395 
00396     if (sdbp)
00397     for (i = 0; i < (int)bag->nsdbp; i++) {
00398         rpmdb sdb = NULL;
00399 
00400         if (sdbp[i] == NULL)
00401             continue;
00402         sdb = sdbp[i]->_db;
00403         if (sdb == NULL)
00404             continue;
00405 
00406         /* Look for a matching Provides: in suggested universe. */
00407         rpmtag = (*keyp == '/' ? RPMTAG_FILEPATHS : RPMTAG_PROVIDENAME);
00408         mi = rpmmiInit(sdb, rpmtag, keyp, keylen);
00409         while ((h = rpmmiNext(mi)) != NULL) {
00410             size_t hnamelen;
00411             time_t htime;
00412 
00413             if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
00414                 continue;
00415 
00416             he->tag = RPMTAG_NAME;
00417             xx = headerGet(h, he, 0);
00418             hnamelen = ((xx && he->p.str) ? strlen(he->p.str) : 0);
00419             he->p.ptr = _free(he->p.ptr);
00420 
00421             /* XXX Prefer the shortest pkg N for basenames/provides resp. */
00422             if (bhnamelen > 0 && hnamelen > bhnamelen)
00423                 continue;
00424 
00425             /* XXX Prefer the newest build if given alternatives. */
00426             he->tag = RPMTAG_BUILDTIME;
00427             xx = headerGet(h, he, 0);
00428             htime = (xx && he->p.ui32p ? he->p.ui32p[0] : 0);
00429             he->p.ptr = _free(he->p.ptr);
00430 
00431             if (htime <= bhtime)
00432                 continue;
00433 
00434             /* Save new "best" candidate. */
00435             (void)headerFree(bh);
00436             bh = NULL;
00437             bh = headerLink(h);
00438             bhtime = htime;
00439             bhnamelen = hnamelen;
00440         }
00441         mi = rpmmiFree(mi);
00442     }
00443 
00444     /* Is there a suggested resolution? */
00445     if (bh == NULL)
00446         goto exit;
00447 
00448     /* Get the path to the package file. */
00449     he->tag = RPMTAG_PACKAGEORIGIN;
00450     he->p.ptr = NULL;
00451     xx = headerGet(bh, he, 0);
00452     if (he->p.str) {
00453         str = he->p.str;
00454         he->p.str = NULL;
00455     } else {
00456         /* Format the suggested resolution path. */
00457         const char * qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
00458         if (qfmt == NULL || *qfmt == '\0')
00459             goto exit;
00460         str = headerSprintf(bh, qfmt, NULL, rpmHeaderFormats, &errstr);
00461         qfmt = _free(qfmt);
00462     }
00463 
00464     (void) headerFree(bh);
00465     bh = NULL;
00466     if (errstr) {
00467         rpmlog(RPMLOG_ERR, _("incorrect solve path format: %s\n"), errstr);
00468         goto exit;
00469     }
00470 
00471     if (ts->depFlags & RPMDEPS_FLAG_ADDINDEPS) {
00472         FD_t fd;
00473         rpmRC rpmrc;
00474 
00475         fd = Fopen(str, "r.fdio");
00476         if (fd == NULL || Ferror(fd)) {
00477             rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
00478                         Fstrerror(fd));
00479             if (fd != NULL) {
00480                 xx = Fclose(fd);
00481                 fd = NULL;
00482             }
00483             str = _free(str);
00484             goto exit;
00485         }
00486         rpmrc = rpmReadPackageFile(ts, fd, str, &h);
00487         xx = Fclose(fd);
00488         switch (rpmrc) {
00489         default:
00490             str = _free(str);
00491             break;
00492         case RPMRC_NOTTRUSTED:
00493         case RPMRC_NOKEY:
00494         case RPMRC_OK:
00495             if (h != NULL &&
00496                 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
00497             {
00498                 rpmlog(RPMLOG_DEBUG, D_("Adding: %s\n"), str);
00499                 rc = -1;        /* XXX restart unsatisfiedDepends() */
00500                 break;
00501             }
00502             break;
00503         }
00504         (void)headerFree(h);
00505         h = NULL;
00506         goto exit;
00507     }
00508 
00509     rpmlog(RPMLOG_DEBUG, D_("Suggesting: %s\n"), str);
00510     /* If suggestion is already present, don't bother. */
00511     if (ts->suggests != NULL && ts->nsuggests > 0) {
00512         if (bsearch(&str, ts->suggests, ts->nsuggests,
00513                         sizeof(*ts->suggests), sugcmp))
00514         {
00515             str = _free(str);
00516             goto exit;
00517         }
00518     }
00519 
00520     /* Add a new (unique) suggestion. */
00521     ts->suggests = xrealloc(ts->suggests,
00522                         sizeof(*ts->suggests) * (ts->nsuggests + 2));
00523     ts->suggests[ts->nsuggests] = str;
00524     ts->nsuggests++;
00525     ts->suggests[ts->nsuggests] = NULL;
00526 
00527     if (ts->nsuggests > 1)
00528         qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
00529 
00530 exit:
00531 if (_rpmts_debug)
00532 fprintf(stderr, "<-- %s(%p,%p,%p) rc %d N %s EVR %s F 0x%x\n", __FUNCTION__, ts, ds, data, rc, rpmdsN(ds), rpmdsEVR(ds), rpmdsFlags(ds));
00533     return rc;
00534 }
00535 
00536 int rpmtsAvailable(rpmts ts, const rpmds ds)
00537 {
00538     fnpyKey * sugkey;
00539     int rc = 1; /* assume not found */
00540 
00541     if (ts->availablePackages == NULL)
00542         return rc;
00543     sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
00544     if (sugkey == NULL)
00545         return rc;
00546 
00547     /* XXX no alternatives yet */
00548     if (sugkey[0] != NULL) {
00549         ts->suggests = xrealloc(ts->suggests,
00550                         sizeof(*ts->suggests) * (ts->nsuggests + 2));
00551         ts->suggests[ts->nsuggests] = sugkey[0];
00552         sugkey[0] = NULL;
00553         ts->nsuggests++;
00554         ts->suggests[ts->nsuggests] = NULL;
00555     }
00556     sugkey = _free(sugkey);
00557     return rc;
00558 }
00559 
00560 int rpmtsSetSolveCallback(rpmts ts,
00561                 int (*solve) (rpmts ts, rpmds key, const void * data),
00562                 const void * solveData)
00563 {
00564     int rc = 0;
00565 
00566     if (ts) {
00567 /*@-assignexpose -temptrans @*/
00568         ts->solve = solve;
00569         ts->solveData = solveData;
00570 /*@=assignexpose =temptrans @*/
00571     }
00572     return rc;
00573 }
00574 
00575 rpmps rpmtsProblems(rpmts ts)
00576 {
00577     static const char msg[] = "rpmtsProblems";
00578     rpmps ps = NULL;
00579     if (ts) {
00580         if (ts->probs == NULL)
00581             ts->probs = rpmpsCreate();
00582 /*@-castexpose@*/
00583         ps = rpmpsLink(ts->probs, msg);
00584 /*@=castexpose@*/
00585     }
00586     return ps;
00587 }
00588 
00589 void rpmtsClean(rpmts ts)
00590 {
00591     rpmtsi pi; rpmte p;
00592 
00593     if (ts == NULL)
00594         return;
00595 
00596     /* Clean up after dependency checks. */
00597     pi = rpmtsiInit(ts);
00598     while ((p = rpmtsiNext(pi, 0)) != NULL)
00599         rpmteCleanDS(p);
00600     pi = rpmtsiFree(pi);
00601 
00602     ts->addedPackages = rpmalFree(ts->addedPackages);
00603     ts->numAddedPackages = 0;
00604 
00605     ts->erasedPackages = rpmalFree(ts->erasedPackages);
00606     ts->numErasedPackages = 0;
00607 
00608     ts->suggests = _free(ts->suggests);
00609     ts->nsuggests = 0;
00610 
00611     ts->probs = rpmpsFree(ts->probs);
00612 
00613     rpmtsCleanDig(ts);
00614 }
00615 
00616 void rpmtsEmpty(rpmts ts)
00617 {
00618     rpmtsi pi; rpmte p;
00619     int oc;
00620 
00621     if (ts == NULL)
00622         return;
00623 
00624 /*@-nullstate@*/        /* FIX: partial annotations */
00625     rpmtsClean(ts);
00626 /*@=nullstate@*/
00627 
00628     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00629 /*@-type -unqualifiedtrans @*/
00630         ts->order[oc] = rpmteFree(ts->order[oc]);
00631 /*@=type =unqualifiedtrans @*/
00632     }
00633     pi = rpmtsiFree(pi);
00634     ts->numAddedFiles = 0;
00635     ts->numErasedFiles = 0;
00636 
00637     ts->orderCount = 0;
00638     ts->ntrees = 0;
00639     ts->maxDepth = 0;
00640 
00641     ts->numRemovedPackages = 0;
00642 /*@-nullstate@*/        /* FIX: partial annotations */
00643     return;
00644 /*@=nullstate@*/
00645 }
00646 
00647 static void rpmtsPrintStat(const char * name, /*@null@*/ struct rpmop_s * op)
00648         /*@globals fileSystem @*/
00649         /*@modifies fileSystem @*/
00650 {
00651     static unsigned int scale = (1000 * 1000);
00652     if (op != NULL && op->count > 0)
00653         fprintf(stderr, "   %s %8d %6lu.%06lu MB %6lu.%06lu secs\n",
00654                 name, op->count,
00655                 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
00656                 op->usecs/scale, op->usecs%scale);
00657 }
00658 
00659 /*@unchecked@*/ /*@relnull@*/
00660 extern rpmop _hdr_loadops;
00661 /*@unchecked@*/ /*@relnull@*/
00662 extern rpmop _hdr_getops;
00663 
00664 static void rpmtsPrintStats(rpmts ts)
00665         /*@globals fileSystem, internalState @*/
00666         /*@modifies fileSystem, internalState @*/
00667 {
00668     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
00669 
00670     if (_hdr_loadops)
00671         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_HDRLOAD), _hdr_loadops);
00672     if (_hdr_getops)
00673         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_HDRGET), _hdr_getops);
00674 
00675     rpmtsPrintStat("total:       ", rpmtsOp(ts, RPMTS_OP_TOTAL));
00676     rpmtsPrintStat("check:       ", rpmtsOp(ts, RPMTS_OP_CHECK));
00677     rpmtsPrintStat("order:       ", rpmtsOp(ts, RPMTS_OP_ORDER));
00678     rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
00679     rpmtsPrintStat("repackage:   ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
00680     rpmtsPrintStat("install:     ", rpmtsOp(ts, RPMTS_OP_INSTALL));
00681     rpmtsPrintStat("erase:       ", rpmtsOp(ts, RPMTS_OP_ERASE));
00682     rpmtsPrintStat("scriptlets:  ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
00683     rpmtsPrintStat("compress:    ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
00684     rpmtsPrintStat("uncompress:  ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
00685     rpmtsPrintStat("digest:      ", rpmtsOp(ts, RPMTS_OP_DIGEST));
00686     rpmtsPrintStat("signature:   ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
00687     rpmtsPrintStat("dbadd:       ", rpmtsOp(ts, RPMTS_OP_DBADD));
00688     rpmtsPrintStat("dbremove:    ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
00689     rpmtsPrintStat("dbget:       ", rpmtsOp(ts, RPMTS_OP_DBGET));
00690     rpmtsPrintStat("dbput:       ", rpmtsOp(ts, RPMTS_OP_DBPUT));
00691     rpmtsPrintStat("dbdel:       ", rpmtsOp(ts, RPMTS_OP_DBDEL));
00692     rpmtsPrintStat("readhdr:     ", rpmtsOp(ts, RPMTS_OP_READHDR));
00693     rpmtsPrintStat("hdrload:     ", rpmtsOp(ts, RPMTS_OP_HDRLOAD));
00694     rpmtsPrintStat("hdrget:      ", rpmtsOp(ts, RPMTS_OP_HDRGET));
00695 /*@-globstate@*/
00696     return;
00697 /*@=globstate@*/
00698 }
00699 
00700 static void rpmtsFini(void * _ts)
00701         /*@modifies _ts @*/
00702 {
00703     rpmts ts = _ts;
00704 
00705 /*@-nullstate@*/        /* FIX: partial annotations */
00706     /* XXX there's a recursion here ... release and reacquire the lock */
00707 #ifndef BUGGY
00708     yarnRelease(ts->_item.use); /* XXX hack-o-round */
00709 #endif
00710     rpmtsEmpty(ts);
00711 #ifndef BUGGY
00712     yarnPossess(ts->_item.use); /* XXX hack-o-round */
00713 #endif
00714 /*@=nullstate@*/
00715 
00716     ts->PRCO = rpmdsFreePRCO(ts->PRCO);
00717 
00718     (void) rpmtsCloseDB(ts);
00719 assert(ts->txn == NULL);        /* XXX FIXME */
00720     ts->txn = NULL;
00721 
00722     (void) rpmtsCloseSDB(ts);
00723 
00724     (void) rpmbfFree(ts->rbf);
00725     ts->rbf = NULL;
00726     ts->removedPackages = _free(ts->removedPackages);
00727 
00728     ts->availablePackages = rpmalFree(ts->availablePackages);
00729     ts->numAvailablePackages = 0;
00730 
00731     ts->dsi = _free(ts->dsi);
00732 
00733     if (ts->scriptFd != NULL) {
00734 /*@-refcounttrans@*/    /* FIX: XfdFree annotation */
00735         ts->scriptFd = fdFree(ts->scriptFd, __FUNCTION__);
00736 /*@=refcounttrans@*/
00737         ts->scriptFd = NULL;
00738     }
00739     ts->rootDir = _free(ts->rootDir);
00740     ts->currDir = _free(ts->currDir);
00741 
00742 /*@-type +voidabstract @*/      /* FIX: double indirection */
00743     ts->order = _free(ts->order);
00744 /*@=type =voidabstract @*/
00745     ts->orderAlloced = 0;
00746 
00747     ts->keyring = rpmKeyringFree(ts->keyring);
00748     (void) rpmhkpFree(ts->hkp);
00749     ts->hkp = NULL;
00750 
00751     if (_rpmts_stats)
00752         rpmtsPrintStats(ts);
00753 
00754     if (_rpmts_macros) {
00755         const char ** av = NULL;
00756 /*@-globs@*/    /* Avoid rpmGlobalMcroContext et al. */
00757         (void)rpmGetMacroEntries(NULL, NULL, 1, &av);
00758 /*@=globs@*/
00759         argvPrint("macros used", av, NULL);
00760         av = argvFree(av);
00761     }
00762 }
00763 
00764 /*@unchecked@*/ /*@only@*/ /*@null@*/
00765 rpmioPool _rpmtsPool;
00766 
00767 static rpmts rpmtsGetPool(/*@null@*/ rpmioPool pool)
00768         /*@globals _rpmtsPool, fileSystem, internalState @*/
00769         /*@modifies pool, _rpmtsPool, fileSystem, internalState @*/
00770 {
00771     rpmts ts;
00772 
00773     if (_rpmtsPool == NULL) {
00774         _rpmtsPool = rpmioNewPool("ts", sizeof(*ts), -1, _rpmts_debug,
00775                         NULL, NULL, rpmtsFini);
00776         pool = _rpmtsPool;
00777     }
00778     ts = (rpmts) rpmioGetPool(pool, sizeof(*ts));
00779     memset(((char *)ts)+sizeof(ts->_item), 0, sizeof(*ts)-sizeof(ts->_item));
00780     return ts;
00781 }
00782 
00783 void * rpmtsGetKeyring(rpmts ts, /*@unused@*/ int autoload)
00784 {
00785     rpmKeyring keyring = NULL;
00786     if (ts) {
00787 #ifdef  NOTYET
00788         if (ts->keyring == NULL && autoload)
00789             loadKeyring(ts);
00790         keyring = rpmKeyringLink(ts->keyring);
00791 #else
00792         keyring = ts->keyring;
00793 #endif
00794     }
00795 /*@-refcounttrans@*/
00796     return (void *)keyring;
00797 /*@=refcounttrans@*/
00798 }
00799 
00800 int rpmtsSetKeyring(rpmts ts, void * _keyring)
00801 {
00802     rpmKeyring keyring = _keyring;
00803 
00804     if (ts == NULL)
00805        return -1;
00806 
00807 #ifdef  NOTYET
00808     /*
00809      * Should we permit switching keyring on the fly? For now, require
00810      * rpmdb isn't open yet (fairly arbitrary limitation)...
00811      */
00812     if (rpmtsGetRdb(ts) != NULL)
00813         return -1;
00814 #endif
00815 
00816 /*@-modnomods@*/
00817     ts->keyring = rpmKeyringFree(ts->keyring);
00818 /*@=modnomods@*/
00819 
00820 #ifdef  NOTYET
00821     ts->keyring = rpmKeyringLink(keyring);
00822 #else
00823 /*@-assignexpose -newreftrans @*/
00824 /*@i@*/    ts->keyring = keyring;
00825 /*@=assignexpose =newreftrans @*/
00826 #endif
00827 
00828     return 0;
00829 }
00830 
00831 rpmVSFlags rpmtsVSFlags(/*@unused@*/ rpmts ts)
00832 {
00833     return pgpDigVSFlags;
00834 }
00835 
00836 rpmVSFlags rpmtsSetVSFlags(/*@unused@*/ rpmts ts, rpmVSFlags vsflags)
00837         /*@globals pgpDigVSFlags @*/
00838         /*@modifies pgpDigVSFlags @*/
00839 {
00840     rpmVSFlags ovsflags;
00841     ovsflags = pgpDigVSFlags;
00842     pgpDigVSFlags = vsflags;
00843     return ovsflags;
00844 }
00845 
00846 /*
00847  * This allows us to mark transactions as being of a certain type.
00848  * The three types are:
00849  *
00850  *     RPM_TRANS_NORMAL         
00851  *     RPM_TRANS_ROLLBACK
00852  *     RPM_TRANS_AUTOROLLBACK
00853  *
00854  * ROLLBACK and AUTOROLLBACK transactions should always be ran as
00855  * a best effort.  In particular this is important to the autorollback
00856  * feature to avoid rolling back a rollback (otherwise known as
00857  * dueling rollbacks (-;).  AUTOROLLBACK's additionally need instance
00858  * counts passed to scriptlets to be altered.
00859  */
00860 /* Let them know what type of transaction we are */
00861 rpmTSType rpmtsType(rpmts ts)
00862 {
00863     return ((ts != NULL) ? ts->type : 0);
00864 }
00865 
00866 void rpmtsSetType(rpmts ts, rpmTSType type)
00867 {
00868     if (ts != NULL)
00869         ts->type = type;
00870 }
00871 
00872 rpmuint32_t rpmtsARBGoal(rpmts ts)
00873 {
00874     return ((ts != NULL) ?  ts->arbgoal : 0);
00875 }
00876 
00877 void rpmtsSetARBGoal(rpmts ts, rpmuint32_t goal)
00878 {
00879     if (ts != NULL)
00880         ts->arbgoal = goal;
00881 }
00882 
00883 int rpmtsUnorderedSuccessors(rpmts ts, int first)
00884 {
00885     int unorderedSuccessors = 0;
00886     if (ts != NULL) {
00887         unorderedSuccessors = ts->unorderedSuccessors;
00888         if (first >= 0)
00889             ts->unorderedSuccessors = first;
00890     }
00891     return unorderedSuccessors;
00892 }
00893 
00894 const char * rpmtsRootDir(rpmts ts)
00895 {
00896     const char * rootDir = NULL;
00897 
00898     if (ts != NULL && ts->rootDir != NULL) {
00899         urltype ut = urlPath(ts->rootDir, &rootDir);
00900         switch (ut) {
00901         case URL_IS_UNKNOWN:
00902         case URL_IS_PATH:
00903             break;
00904         case URL_IS_HTTPS:
00905         case URL_IS_HTTP:
00906         case URL_IS_HKP:
00907         case URL_IS_FTP:
00908         case URL_IS_DASH:
00909         default:
00910             rootDir = "/";
00911             break;
00912         }
00913     }
00914     return rootDir;
00915 }
00916 
00917 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
00918 {
00919     if (ts != NULL) {
00920         size_t rootLen;
00921 
00922         ts->rootDir = _free(ts->rootDir);
00923 
00924         if (rootDir == NULL) {
00925 #ifdef  DYING
00926             ts->rootDir = xstrdup("");
00927 #endif
00928             return;
00929         }
00930         rootLen = strlen(rootDir);
00931 
00932         /* Make sure that rootDir has trailing / */
00933         if (!(rootLen && rootDir[rootLen - 1] == '/')) {
00934             char * t = alloca(rootLen + 2);
00935             *t = '\0';
00936             (void) stpcpy( stpcpy(t, rootDir), "/");
00937             rootDir = t;
00938         }
00939         ts->rootDir = xstrdup(rootDir);
00940     }
00941 }
00942 
00943 const char * rpmtsCurrDir(rpmts ts)
00944 {
00945     const char * currDir = NULL;
00946     if (ts != NULL) {
00947         currDir = ts->currDir;
00948     }
00949     return currDir;
00950 }
00951 
00952 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
00953 {
00954     if (ts != NULL) {
00955         ts->currDir = _free(ts->currDir);
00956         if (currDir)
00957             ts->currDir = xstrdup(currDir);
00958     }
00959 }
00960 
00961 FD_t rpmtsScriptFd(rpmts ts)
00962 {
00963     FD_t scriptFd = NULL;
00964     if (ts != NULL) {
00965         scriptFd = ts->scriptFd;
00966     }
00967 /*@-compdef -refcounttrans -usereleased@*/
00968     return scriptFd;
00969 /*@=compdef =refcounttrans =usereleased@*/
00970 }
00971 
00972 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
00973 {
00974 
00975     if (ts != NULL) {
00976         if (ts->scriptFd != NULL) {
00977 /*@-assignexpose@*/
00978             ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
00979 /*@=assignexpose@*/
00980             ts->scriptFd = NULL;
00981         }
00982 /*@-assignexpose -castexpose @*/
00983         if (scriptFd != NULL)
00984             ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
00985 /*@=assignexpose =castexpose @*/
00986     }
00987 }
00988 
00989 int rpmtsSELinuxEnabled(rpmts ts)
00990 {
00991     int selinuxEnabled = 0;
00992     if (ts)
00993         selinuxEnabled = (ts->selinuxEnabled > 0);
00994     return selinuxEnabled;
00995 }
00996 
00997 int rpmtsChrootDone(rpmts ts)
00998 {
00999     return (ts != NULL ? ts->chrootDone : 0);
01000 }
01001 
01002 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
01003 {
01004     int ochrootDone = 0;
01005     if (ts != NULL) {
01006         ochrootDone = ts->chrootDone;
01007         if (ts->rdb != NULL)
01008             ts->rdb->db_chrootDone = chrootDone;
01009         ts->chrootDone = chrootDone;
01010     }
01011     return ochrootDone;
01012 }
01013 
01014 rpmuint32_t rpmtsGetTid(rpmts ts)
01015 {
01016     rpmuint32_t tid = 0;        /* XXX -1 is time(2) error return. */
01017     if (ts != NULL) {
01018         tid = ts->tid[0];
01019     }
01020     return tid;
01021 }
01022 
01023 rpmuint32_t rpmtsSetTid(rpmts ts, rpmuint32_t tid)
01024 {
01025     rpmuint32_t otid = 0;       /* XXX -1 is time(2) error return. */
01026     if (ts != NULL) {
01027         otid = ts->tid[0];
01028         ts->tid[0] = tid;
01029         ts->tid[1] = 0;
01030     }
01031     return otid;
01032 }
01033 
01034 rpmPRCO rpmtsPRCO(rpmts ts)
01035 {
01036     rpmPRCO PRCO = NULL;
01037 
01038     if (ts != NULL) {
01039         static int oneshot = 0;
01040         if (!oneshot) {
01041             const char * fn = rpmGetPath("%{?_rpmds_sysinfo_path}", NULL);
01042             int xx;
01043 
01044             ts->PRCO = rpmdsNewPRCO(NULL);
01045             if (fn && *fn != '\0' && !rpmioAccess(fn, NULL, R_OK))
01046                 xx = rpmdsSysinfo(ts->PRCO, NULL);
01047             fn = _free(fn);
01048             oneshot++;
01049         }
01050         PRCO = ts->PRCO;
01051     }
01052 /*@-compdef -retexpose -usereleased @*/
01053     return PRCO;
01054 /*@=compdef =retexpose =usereleased @*/
01055 }
01056 
01057 int rpmtsInitDSI(const rpmts ts)
01058 {
01059     rpmDiskSpaceInfo dsi;
01060     struct stat sb;
01061     int rc;
01062     size_t i;
01063 
01064     if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
01065         return 0;
01066     if (ts->filesystems != NULL)
01067         return 0;
01068 
01069     rpmlog(RPMLOG_DEBUG, D_("mounted filesystems:\n"));
01070     rpmlog(RPMLOG_DEBUG,
01071         D_("    i        dev    bsize       bavail       iavail mount point\n"));
01072 
01073     rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
01074     if (rc || ts->filesystems == NULL || ts->filesystemCount == 0)
01075         return rc;
01076 
01077     /* Get available space on mounted file systems. */
01078 
01079     ts->dsi = _free(ts->dsi);
01080     ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
01081 
01082     dsi = ts->dsi;
01083 
01084     if (dsi != NULL)
01085     for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
01086 #if STATFS_IN_SYS_STATVFS
01087         struct statvfs sfb;
01088         memset(&sfb, 0, sizeof(sfb));
01089         rc = statvfs(ts->filesystems[i], &sfb);
01090 #else
01091         struct statfs sfb;
01092         memset(&sfb, 0, sizeof(sfb));
01093 #  if STAT_STATFS4
01094 /* This platform has the 4-argument version of the statfs call.  The last two
01095  * should be the size of struct statfs and 0, respectively.  The 0 is the
01096  * filesystem type, and is always 0 when statfs is called on a mounted
01097  * filesystem, as we're doing.
01098  */
01099         rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
01100 #  else
01101         rc = statfs(ts->filesystems[i], &sfb);
01102 #  endif
01103 #endif
01104         if (rc)
01105             break;
01106 
01107         rc = stat(ts->filesystems[i], &sb);
01108         if (rc)
01109             break;
01110         dsi->dev = sb.st_dev;
01111 /* XXX figger out how to get this info for non-statvfs systems. */
01112 #if STATFS_IN_SYS_STATVFS
01113         dsi->f_frsize = sfb.f_frsize;
01114 #if defined(RPM_OS_AIX)
01115         dsi->f_fsid = 0; /* sfb.f_fsid is a structure on AIX */
01116 #else
01117         dsi->f_fsid = sfb.f_fsid;
01118 #endif
01119         dsi->f_flag = sfb.f_flag;
01120         dsi->f_favail = (long long) sfb.f_favail;
01121         dsi->f_namemax = sfb.f_namemax;
01122 #elif defined(__APPLE__) && defined(__MACH__) && !defined(_SYS_STATVFS_H_)
01123         dsi->f_fsid = 0; /* "Not meaningful in this implementation." */
01124         dsi->f_namemax = pathconf(ts->filesystems[i], _PC_NAME_MAX);
01125 #elif defined(__OpenBSD__)
01126         dsi->f_fsid = 0; /* sfb.f_fsid is a structure on OpenBSD */
01127         dsi->f_namemax = pathconf(ts->filesystems[i], _PC_NAME_MAX);
01128 #else
01129         dsi->f_fsid = sfb.f_fsid;
01130         dsi->f_namemax = sfb.f_namelen;
01131 #endif
01132 
01133         dsi->f_bsize = sfb.f_bsize;
01134         dsi->f_blocks = (unsigned long long)sfb.f_blocks;
01135         dsi->f_bfree = (unsigned long long)sfb.f_bfree;
01136         dsi->f_files = (unsigned long long)sfb.f_files;
01137         dsi->f_ffree = (unsigned long long)sfb.f_ffree;
01138 
01139         dsi->bneeded = 0;
01140         dsi->ineeded = 0;
01141 #ifdef STATFS_HAS_F_BAVAIL
01142         dsi->f_bavail = (long long)(sfb.f_bavail ? sfb.f_bavail : 1);
01143         if (sfb.f_ffree > 0 && sfb.f_files > 0 && sfb.f_favail > 0)
01144             dsi->f_favail = (long long)sfb.f_favail;
01145         else    /* XXX who knows what evil lurks here? */
01146             dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
01147                                 ?  (signed long long) sfb.f_ffree : -1;
01148 #else
01149 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
01150  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
01151  * it's about all we can do.
01152  */
01153         dsi->f_bavail = sfb.f_blocks - sfb.f_bfree;
01154         /* XXX Avoid FAT and other file systems that have not inodes. */
01155         dsi->f_favail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
01156                                 ? sfb.f_ffree : -1;
01157 #endif
01158 
01159 #if !defined(ST_RDONLY)
01160 #define ST_RDONLY       1
01161 #endif
01162         rpmlog(RPMLOG_DEBUG, "%5u 0x%08x %8u %12ld %12ld %s %s\n",
01163                 (unsigned)i, (unsigned) dsi->dev, (unsigned) dsi->f_bsize,
01164                 (signed long) dsi->f_bavail, (signed long) dsi->f_favail,
01165                 ((dsi->f_flag & ST_RDONLY) ? "ro" : "rw"),
01166                 ts->filesystems[i]);
01167     }
01168     return rc;
01169 }
01170 
01171 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
01172                 rpmuint32_t fileSize, rpmuint32_t prevSize, rpmuint32_t fixupSize,
01173                 int _action)
01174 {
01175     iosmFileAction action = _action;
01176     rpmDiskSpaceInfo dsi;
01177     rpmuint64_t bneeded;
01178 
01179     dsi = ts->dsi;
01180     if (dsi) {
01181         while (dsi->f_bsize && dsi->dev != dev)
01182             dsi++;
01183         if (dsi->f_bsize == 0)
01184             dsi = NULL;
01185     }
01186     if (dsi == NULL)
01187         return;
01188 
01189     bneeded = BLOCK_ROUND(fileSize, dsi->f_bsize);
01190 
01191     switch (action) {
01192     case FA_BACKUP:
01193     case FA_SAVE:
01194     case FA_ALTNAME:
01195         dsi->ineeded++;
01196         dsi->bneeded += bneeded;
01197         /*@switchbreak@*/ break;
01198 
01199     /*
01200      * FIXME: If two packages share a file (same md5sum), and
01201      * that file is being replaced on disk, will dsi->bneeded get
01202      * adjusted twice? Quite probably!
01203      */
01204     case FA_CREATE:
01205         dsi->bneeded += bneeded;
01206         dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->f_bsize);
01207         /*@switchbreak@*/ break;
01208 
01209     case FA_ERASE:
01210         dsi->ineeded--;
01211         dsi->bneeded -= bneeded;
01212         /*@switchbreak@*/ break;
01213 
01214     default:
01215         /*@switchbreak@*/ break;
01216     }
01217 
01218     if (fixupSize)
01219         dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->f_bsize);
01220 }
01221 
01222 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
01223 {
01224     rpmDiskSpaceInfo dsi;
01225     rpmps ps;
01226     int fc;
01227     size_t i;
01228 
01229     if (ts->filesystems == NULL || ts->filesystemCount == 0)
01230         return;
01231 
01232     dsi = ts->dsi;
01233     if (dsi == NULL)
01234         return;
01235     fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
01236     if (fc <= 0)
01237         return;
01238 
01239     ps = rpmtsProblems(ts);
01240     for (i = 0; i < ts->filesystemCount; i++, dsi++) {
01241 
01242         if (dsi->f_bavail > 0 && adj_fs_blocks(dsi->bneeded) > dsi->f_bavail) {
01243             if (dsi->bneeded != dsi->obneeded) {
01244                 rpmpsAppend(ps, RPMPROB_DISKSPACE,
01245                         rpmteNEVR(te), rpmteKey(te),
01246                         ts->filesystems[i], NULL, NULL,
01247                   (adj_fs_blocks(dsi->bneeded) - dsi->f_bavail) * dsi->f_bsize);
01248                 dsi->obneeded = dsi->bneeded;
01249             }
01250         }
01251 
01252         if (dsi->f_favail > 0 && adj_fs_blocks(dsi->ineeded) > dsi->f_favail) {
01253             if (dsi->ineeded != dsi->oineeded) {
01254                 rpmpsAppend(ps, RPMPROB_DISKNODES,
01255                         rpmteNEVR(te), rpmteKey(te),
01256                         ts->filesystems[i], NULL, NULL,
01257                         (adj_fs_blocks(dsi->ineeded) - dsi->f_favail));
01258                 dsi->oineeded = dsi->ineeded;
01259             }
01260         }
01261 
01262         if ((dsi->bneeded || dsi->ineeded) && (dsi->f_flag & ST_RDONLY)) {
01263             rpmpsAppend(ps, RPMPROB_RDONLY,
01264                         rpmteNEVR(te), rpmteKey(te),
01265                         ts->filesystems[i], NULL, NULL, 0);
01266         }
01267     }
01268     ps = rpmpsFree(ps);
01269 }
01270 
01271 void * rpmtsNotify(rpmts ts, rpmte te,
01272                 rpmCallbackType what, rpmuint64_t amount, rpmuint64_t total)
01273 {
01274     void * ptr = NULL;
01275     if (ts && ts->notify) {
01276         Header h;
01277         fnpyKey cbkey;
01278         /*@-type@*/ /* FIX: cast? */
01279         /*@-noeffectuncon @*/ /* FIX: check rc */
01280         if (te) {
01281 /*@-castexpose -mods@*/ /* XXX noisy in transaction.c */
01282             h = headerLink(te->h);
01283 /*@=castexpose =mods@*/
01284             cbkey = rpmteKey(te);
01285         } else {
01286             h = NULL;
01287             cbkey = NULL;
01288         }
01289         ptr = ts->notify(h, what, amount, total, cbkey, ts->notifyData);
01290         (void)headerFree(h);
01291         h = NULL;
01292         /*@=noeffectuncon @*/
01293         /*@=type@*/
01294     }
01295     return ptr;
01296 }
01297 
01298 int rpmtsNElements(rpmts ts)
01299 {
01300     int nelements = 0;
01301     if (ts != NULL && ts->order != NULL) {
01302         nelements = ts->orderCount;
01303     }
01304     return nelements;
01305 }
01306 
01307 rpmte rpmtsElement(rpmts ts, int ix)
01308 {
01309     rpmte te = NULL;
01310     if (ts != NULL && ts->order != NULL) {
01311         if (ix >= 0 && ix < ts->orderCount)
01312             te = ts->order[ix];
01313     }
01314     /*@-compdef@*/
01315     return te;
01316     /*@=compdef@*/
01317 }
01318 
01319 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
01320 {
01321     return (ts != NULL ? ts->ignoreSet : 0);
01322 }
01323 
01324 rpmtransFlags rpmtsFlags(rpmts ts)
01325 {
01326     rpmtransFlags transFlags = 0;
01327     if (ts != NULL) {
01328         transFlags = ts->transFlags;
01329         if (rpmtsSELinuxEnabled(ts) > 0)
01330             transFlags &= ~RPMTRANS_FLAG_NOCONTEXTS;
01331         else
01332             transFlags |= RPMTRANS_FLAG_NOCONTEXTS;
01333     }
01334     return transFlags;
01335 }
01336 
01337 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
01338 {
01339     rpmtransFlags otransFlags = 0;
01340     if (ts != NULL) {
01341         otransFlags = ts->transFlags;
01342         if (rpmtsSELinuxEnabled(ts) > 0)
01343             transFlags &= ~RPMTRANS_FLAG_NOCONTEXTS;
01344         else
01345             transFlags |= RPMTRANS_FLAG_NOCONTEXTS;
01346         ts->transFlags = transFlags;
01347     }
01348     return otransFlags;
01349 }
01350 
01351 rpmdepFlags rpmtsDFlags(rpmts ts)
01352 {
01353     return (ts != NULL ? ts->depFlags : 0);
01354 }
01355 
01356 rpmdepFlags rpmtsSetDFlags(rpmts ts, rpmdepFlags depFlags)
01357 {
01358     rpmdepFlags odepFlags = 0;
01359     if (ts != NULL) {
01360         odepFlags = ts->depFlags;
01361         ts->depFlags = depFlags;
01362     }
01363     return odepFlags;
01364 }
01365 
01366 Spec rpmtsSpec(rpmts ts)
01367 {
01368 /*@-compdef -retexpose -usereleased@*/
01369     return ts->spec;
01370 /*@=compdef =retexpose =usereleased@*/
01371 }
01372 
01373 Spec rpmtsSetSpec(rpmts ts, Spec spec)
01374 {
01375     Spec ospec = ts->spec;
01376 /*@-assignexpose -temptrans@*/
01377     ts->spec = spec;
01378 /*@=assignexpose =temptrans@*/
01379     return ospec;
01380 }
01381 
01382 rpmte rpmtsRelocateElement(rpmts ts)
01383 {
01384 /*@-compdef -retexpose -usereleased@*/
01385     return ts->relocateElement;
01386 /*@=compdef =retexpose =usereleased@*/
01387 }
01388 
01389 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
01390 {
01391     rpmte orelocateElement = ts->relocateElement;
01392 /*@-assignexpose -temptrans@*/
01393     ts->relocateElement = relocateElement;
01394 /*@=assignexpose =temptrans@*/
01395     return orelocateElement;
01396 }
01397 
01398 tsmStage rpmtsGoal(rpmts ts)
01399 {
01400     return (ts != NULL ? ts->goal : TSM_UNKNOWN);
01401 }
01402 
01403 tsmStage rpmtsSetGoal(rpmts ts, tsmStage goal)
01404 {
01405     tsmStage ogoal = TSM_UNKNOWN;
01406     if (ts != NULL) {
01407         ogoal = ts->goal;
01408         ts->goal = goal;
01409     }
01410     return ogoal;
01411 }
01412 
01413 int rpmtsDBMode(rpmts ts)
01414 {
01415     return (ts != NULL ? ts->dbmode : 0);
01416 }
01417 
01418 int rpmtsSetDBMode(rpmts ts, int dbmode)
01419 {
01420     int odbmode = 0;
01421     if (ts != NULL) {
01422         odbmode = ts->dbmode;
01423         ts->dbmode = dbmode;
01424     }
01425     return odbmode;
01426 }
01427 
01428 rpmuint32_t rpmtsColor(rpmts ts)
01429 {
01430     return (ts != NULL ? ts->color : 0);
01431 }
01432 
01433 rpmuint32_t rpmtsSetColor(rpmts ts, rpmuint32_t color)
01434 {
01435     rpmuint32_t ocolor = 0;
01436     if (ts != NULL) {
01437         ocolor = ts->color;
01438         ts->color = color;
01439     }
01440     return ocolor;
01441 }
01442 
01443 rpmuint32_t rpmtsPrefColor(rpmts ts)
01444 {
01445     return (ts != NULL ? ts->prefcolor : 0);
01446 }
01447 
01448 int rpmtsSetNotifyCallback(rpmts ts,
01449                 rpmCallbackFunction notify, rpmCallbackData notifyData)
01450 {
01451     if (ts != NULL) {
01452         ts->notify = notify;
01453         ts->notifyData = notifyData;
01454     }
01455     return 0;
01456 }
01457 
01458 rpmts rpmtsCreate(void)
01459 {
01460     rpmts ts = rpmtsGetPool(_rpmtsPool);
01461     int xx;
01462 
01463     memset(&ts->ops, 0, sizeof(ts->ops));
01464     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
01465     ts->type = RPMTRANS_TYPE_NORMAL;
01466     ts->goal = TSM_UNKNOWN;
01467     ts->filesystemCount = 0;
01468     ts->filesystems = NULL;
01469     ts->dsi = NULL;
01470 
01471     ts->solve = rpmtsSolve;
01472     ts->solveData = NULL;
01473     ts->nsuggests = 0;
01474     ts->suggests = NULL;
01475 
01476     ts->PRCO = NULL;
01477 
01478     ts->bag = NULL;
01479 
01480     ts->rdb = NULL;
01481     ts->dbmode = O_RDONLY;
01482     ts->txn = NULL;
01483 
01484     ts->scriptFd = NULL;
01485     {   struct timeval tv;
01486         xx = gettimeofday(&tv, NULL);
01487         ts->tid[0] = (rpmuint32_t) tv.tv_sec;
01488         ts->tid[1] = (rpmuint32_t) tv.tv_usec;
01489     }
01490     ts->delta = 5;
01491 
01492     ts->color = rpmExpandNumeric("%{?_transaction_color}");
01493     ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}");
01494     if (!ts->prefcolor) ts->prefcolor = 0x2;
01495 
01496     ts->rbf = NULL;
01497     ts->numRemovedPackages = 0;
01498     ts->allocedRemovedPackages = ts->delta;
01499     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
01500                         sizeof(*ts->removedPackages));
01501 
01502     ts->rootDir = NULL;
01503     ts->currDir = NULL;
01504     ts->chrootDone = 0;
01505 
01506     ts->selinuxEnabled = rpmsxEnabled(NULL);
01507 
01508     ts->numAddedPackages = 0;
01509     ts->addedPackages = NULL;
01510 
01511     ts->numErasedPackages = 0;
01512     ts->erasedPackages = NULL;
01513 
01514     ts->numAvailablePackages = 0;
01515     ts->availablePackages = NULL;
01516 
01517     ts->orderAlloced = 0;
01518     ts->orderCount = 0;
01519     ts->order = NULL;
01520     ts->ntrees = 0;
01521     ts->maxDepth = 0;
01522 
01523     ts->probs = NULL;
01524 
01525     ts->keyring = NULL;
01526     ts->hkp = NULL;
01527     ts->dig = NULL;
01528 
01529     /* Set autorollback goal to the end of time. */
01530     ts->arbgoal = 0xffffffff;
01531 
01532     return rpmtsLink(ts, "tsCreate");
01533 }