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