Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

lib/rpmts.c

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

Generated on Sat Oct 1 16:48:19 2011 for rpm by  doxygen 1.4.4