rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 }