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

Generated on Fri Sep 30 02:03:26 2005 for rpm by doxygen1.2.18