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