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

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

Generated on Mon Jun 13 13:40:01 2005 for rpm by  doxygen 1.3.9.1