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 #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", "pentium3", "pentium4", "x86_64", "amd64", "ia32e",
00230         "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
00231         "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
00232         "sparc64", "sparc64v", "sun4u",
00233         "mips", "mipsel", "IP",
00234         "ppc", "ppciseries", "ppcpseries",
00235         "ppc64", "ppc64iseries", "ppc64pseries",
00236         "m68k",
00237         "rs6000",
00238         "ia64",
00239         "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
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 = rpmtsPubkey(ts);
00344     rpmRC res = RPMRC_NOKEY;
00345     const char * pubkeysource = NULL;
00346     int xx;
00347 
00348     if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
00349         goto exit;
00350 
00351 #if 0
00352 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
00353 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
00354 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
00355 #endif
00356 
00357     /* Lazy free of previous pubkey if pubkey does not match this signature. */
00358     if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
00359 #if 0
00360 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
00361 #endif
00362         ts->pkpkt = _free(ts->pkpkt);
00363         ts->pkpktlen = 0;
00364         memset(ts->pksignid, 0, sizeof(ts->pksignid));
00365     }
00366 
00367     /* Try rpmdb keyring lookup. */
00368     if (ts->pkpkt == NULL) {
00369         int hx = -1;
00370         int ix = -1;
00371         rpmdbMatchIterator mi;
00372         Header h;
00373 
00374         /* Retrieve the pubkey that matches the signature. */
00375         mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
00376         while ((h = rpmdbNextIterator(mi)) != NULL) {
00377             const char ** pubkeys;
00378             int_32 pt, pc;
00379 
00380             if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
00381                 continue;
00382             hx = rpmdbGetIteratorOffset(mi);
00383             ix = rpmdbGetIteratorFileNum(mi);
00384 /*@-boundsread@*/
00385             if (ix >= pc
00386              || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
00387                 ix = -1;
00388 /*@=boundsread@*/
00389             pubkeys = headerFreeData(pubkeys, pt);
00390             break;
00391         }
00392         mi = rpmdbFreeIterator(mi);
00393 
00394 /*@-branchstate@*/
00395         if (ix >= 0) {
00396             char hnum[32];
00397             sprintf(hnum, "h#%d", hx);
00398             pubkeysource = xstrdup(hnum);
00399         } else {
00400             ts->pkpkt = _free(ts->pkpkt);
00401             ts->pkpktlen = 0;
00402         }
00403 /*@=branchstate@*/
00404     }
00405 
00406     /* Try keyserver lookup. */
00407     if (ts->pkpkt == NULL) {
00408         const char * fn = rpmExpand("%{_hkp_keyserver_query}",
00409                         pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
00410 
00411         xx = 0;
00412         if (fn && *fn != '%') {
00413             xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
00414         }
00415         fn = _free(fn);
00416 /*@-branchstate@*/
00417         if (xx) {
00418             ts->pkpkt = _free(ts->pkpkt);
00419             ts->pkpktlen = 0;
00420         } else {
00421             /* Save new pubkey in local ts keyring for delayed import. */
00422             pubkeysource = xstrdup("keyserver");
00423         }
00424 /*@=branchstate@*/
00425     }
00426 
00427 #ifdef  NOTNOW
00428     /* Try filename from macro lookup. */
00429     if (ts->pkpkt == NULL) {
00430         const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
00431 
00432         xx = 0;
00433         if (fn && *fn != '%')
00434             xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
00435         fn = _free(fn);
00436         if (xx) {
00437             ts->pkpkt = _free(ts->pkpkt);
00438             ts->pkpktlen = 0;
00439         } else {
00440             pubkeysource = xstrdup("macro");
00441         }
00442     }
00443 #endif
00444 
00445     /* Was a matching pubkey found? */
00446     if (ts->pkpkt == NULL || ts->pkpktlen == 0)
00447         goto exit;
00448 
00449     /* Retrieve parameters from pubkey packet(s). */
00450     xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
00451 
00452     /* Do the parameters match the signature? */
00453     if (sigp->pubkey_algo == pubp->pubkey_algo
00454 #ifdef  NOTYET
00455      && sigp->hash_algo == pubp->hash_algo
00456 #endif
00457      && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
00458     {
00459 
00460         /* XXX Verify any pubkey signatures. */
00461 
00462         /* Pubkey packet looks good, save the signer id. */
00463 /*@-boundsread@*/
00464         memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
00465 /*@=boundsread@*/
00466 
00467         if (pubkeysource)
00468             rpmMessage(RPMMESS_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
00469                 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
00470                 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
00471                 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
00472                 pubkeysource);
00473 
00474         res = RPMRC_OK;
00475     }
00476 
00477 exit:
00478     pubkeysource = _free(pubkeysource);
00479     if (res != RPMRC_OK) {
00480         ts->pkpkt = _free(ts->pkpkt);
00481         ts->pkpktlen = 0;
00482     }
00483     return res;
00484 }
00485 
00486 int rpmtsCloseSDB(rpmts ts)
00487 {
00488     int rc = 0;
00489 
00490     if (ts->sdb != NULL) {
00491         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), &ts->sdb->db_getops);
00492         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), &ts->sdb->db_putops);
00493         (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), &ts->sdb->db_delops);
00494         rc = rpmdbClose(ts->sdb);
00495         ts->sdb = NULL;
00496     }
00497     return rc;
00498 }
00499 
00500 int rpmtsOpenSDB(rpmts ts, int dbmode)
00501 {
00502     static int has_sdbpath = -1;
00503     int rc = 0;
00504 
00505     if (ts->sdb != NULL && ts->sdbmode == dbmode)
00506         return 0;
00507 
00508     if (has_sdbpath < 0)
00509         has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
00510 
00511     /* If not configured, don't try to open. */
00512     if (has_sdbpath <= 0)
00513         return 1;
00514 
00515     addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
00516 
00517     rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
00518     if (rc) {
00519         const char * dn;
00520         dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
00521         rpmMessage(RPMMESS_WARNING,
00522                         _("cannot open Solve database in %s\n"), dn);
00523         dn = _free(dn);
00524     }
00525     delMacro(NULL, "_dbpath");
00526 
00527     return rc;
00528 }
00529 
00536 static int sugcmp(const void * a, const void * b)
00537         /*@*/
00538 {
00539 /*@-boundsread@*/
00540     const char * astr = *(const char **)a;
00541     const char * bstr = *(const char **)b;
00542 /*@=boundsread@*/
00543     return strcmp(astr, bstr);
00544 }
00545 
00546 /*@-bounds@*/
00547 int rpmtsSolve(rpmts ts, rpmds ds, /*@unused@*/ const void * data)
00548 {
00549     const char * errstr;
00550     const char * str;
00551     const char * qfmt;
00552     rpmdbMatchIterator mi;
00553     Header bh;
00554     Header h;
00555     size_t bhnamelen;
00556     time_t bhtime;
00557     rpmTag rpmtag;
00558     const char * keyp;
00559     size_t keylen;
00560     int rc = 1; /* assume not found */
00561     int xx;
00562 
00563     /* Make suggestions only for install Requires: */
00564     if (ts->goal != TSM_INSTALL)
00565         return rc;
00566 
00567     if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
00568         return rc;
00569 
00570     keyp = rpmdsN(ds);
00571     if (keyp == NULL)
00572         return rc;
00573 
00574     if (ts->sdb == NULL) {
00575         xx = rpmtsOpenSDB(ts, ts->sdbmode);
00576         if (xx) return rc;
00577     }
00578 
00579     /* Look for a matching Provides: in suggested universe. */
00580     rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
00581     keylen = 0;
00582     mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
00583     bhnamelen = 0;
00584     bhtime = 0;
00585     bh = NULL;
00586     while ((h = rpmdbNextIterator(mi)) != NULL) {
00587         const char * hname;
00588         size_t hnamelen;
00589         time_t htime;
00590         int_32 * ip;
00591 
00592         if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
00593             continue;
00594 
00595         /* XXX Prefer the shortest name if given alternatives. */
00596         hname = NULL;
00597         hnamelen = 0;
00598         if (headerGetEntry(h, RPMTAG_NAME, NULL, (void **)&hname, NULL)) {
00599             if (hname)
00600                 hnamelen = strlen(hname);
00601         }
00602         if (bhnamelen > 0 && hnamelen > bhnamelen)
00603             continue;
00604 
00605         /* XXX Prefer the newest build if given alternatives. */
00606         htime = 0;
00607         if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (void **)&ip, NULL))
00608             htime = (time_t)*ip;
00609 
00610         if (htime <= bhtime)
00611             continue;
00612 
00613         bh = headerFree(bh);
00614         bh = headerLink(h);
00615         bhtime = htime;
00616         bhnamelen = hnamelen;
00617     }
00618     mi = rpmdbFreeIterator(mi);
00619 
00620     /* Is there a suggested resolution? */
00621     if (bh == NULL)
00622         goto exit;
00623 
00624     /* Format the suggestion. */
00625     qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
00626     if (qfmt == NULL || *qfmt == '\0')
00627         goto exit;
00628     str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
00629     bh = headerFree(bh);
00630     qfmt = _free(qfmt);
00631     if (str == NULL) {
00632         rpmError(RPMERR_QFMT, _("incorrect format: %s\n"), errstr);
00633         goto exit;
00634     }
00635 
00636     if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
00637         FD_t fd;
00638         rpmRC rpmrc;
00639 
00640         h = headerFree(h);
00641         fd = Fopen(str, "r.ufdio");
00642         if (fd == NULL || Ferror(fd)) {
00643             rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), str,
00644                         Fstrerror(fd));
00645             if (fd != NULL) {
00646                 xx = Fclose(fd);
00647                 fd = NULL;
00648             }
00649             str = _free(str);
00650             goto exit;
00651         }
00652         rpmrc = rpmReadPackageFile(ts, fd, str, &h);
00653         xx = Fclose(fd);
00654         switch (rpmrc) {
00655         default:
00656             str = _free(str);
00657             break;
00658         case RPMRC_NOTTRUSTED:
00659         case RPMRC_NOKEY:
00660         case RPMRC_OK:
00661             if (h != NULL &&
00662                 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
00663             {
00664                 rpmMessage(RPMMESS_DEBUG, _("Adding: %s\n"), str);
00665                 rc = -1;
00666                 /* XXX str memory leak */
00667                 break;
00668             }
00669             str = _free(str);
00670             break;
00671         }
00672         h = headerFree(h);
00673         goto exit;
00674     }
00675 
00676     rpmMessage(RPMMESS_DEBUG, _("Suggesting: %s\n"), str);
00677     /* If suggestion is already present, don't bother. */
00678     if (ts->suggests != NULL && ts->nsuggests > 0) {
00679         if (bsearch(&str, ts->suggests, ts->nsuggests,
00680                         sizeof(*ts->suggests), sugcmp))
00681             goto exit;
00682     }
00683 
00684     /* Add a new (unique) suggestion. */
00685     ts->suggests = xrealloc(ts->suggests,
00686                         sizeof(*ts->suggests) * (ts->nsuggests + 2));
00687     ts->suggests[ts->nsuggests] = str;
00688     ts->nsuggests++;
00689     ts->suggests[ts->nsuggests] = NULL;
00690 
00691     if (ts->nsuggests > 1)
00692         qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
00693 
00694 exit:
00695 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
00696     return rc;
00697 /*@=nullstate@*/
00698 }
00699 /*@=bounds@*/
00700 
00701 int rpmtsAvailable(rpmts ts, const rpmds ds)
00702 {
00703     fnpyKey * sugkey;
00704     int rc = 1; /* assume not found */
00705 
00706     if (ts->availablePackages == NULL)
00707         return rc;
00708     sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
00709     if (sugkey == NULL)
00710         return rc;
00711 
00712     /* XXX no alternatives yet */
00713     if (sugkey[0] != NULL) {
00714         ts->suggests = xrealloc(ts->suggests,
00715                         sizeof(*ts->suggests) * (ts->nsuggests + 2));
00716         ts->suggests[ts->nsuggests] = sugkey[0];
00717         sugkey[0] = NULL;
00718         ts->nsuggests++;
00719         ts->suggests[ts->nsuggests] = NULL;
00720     }
00721     sugkey = _free(sugkey);
00722 /*@-nullstate@*/ /* FIX: ts->suggests[] may be NULL */
00723     return rc;
00724 /*@=nullstate@*/
00725 }
00726 
00727 int rpmtsSetSolveCallback(rpmts ts,
00728                 int (*solve) (rpmts ts, rpmds key, const void * data),
00729                 const void * solveData)
00730 {
00731     int rc = 0;
00732 
00733 /*@-branchstate@*/
00734     if (ts) {
00735 /*@-assignexpose -temptrans @*/
00736         ts->solve = solve;
00737         ts->solveData = solveData;
00738 /*@=assignexpose =temptrans @*/
00739     }
00740 /*@=branchstate@*/
00741     return rc;
00742 }
00743 
00744 rpmps rpmtsProblems(rpmts ts)
00745 {
00746     rpmps ps = NULL;
00747     if (ts) {
00748         if (ts->probs)
00749             ps = rpmpsLink(ts->probs, NULL);
00750     }
00751     return ps;
00752 }
00753 
00754 void rpmtsCleanDig(rpmts ts)
00755 {
00756     ts->sig = headerFreeData(ts->sig, ts->sigtype);
00757     ts->dig = pgpFreeDig(ts->dig);
00758 }
00759 
00760 void rpmtsClean(rpmts ts)
00761 {
00762     rpmtsi pi; rpmte p;
00763 
00764     if (ts == NULL)
00765         return;
00766 
00767     /* Clean up after dependency checks. */
00768     pi = rpmtsiInit(ts);
00769     while ((p = rpmtsiNext(pi, 0)) != NULL)
00770         rpmteCleanDS(p);
00771     pi = rpmtsiFree(pi);
00772 
00773     ts->addedPackages = rpmalFree(ts->addedPackages);
00774     ts->numAddedPackages = 0;
00775 
00776     ts->suggests = _free(ts->suggests);
00777     ts->nsuggests = 0;
00778 
00779     ts->probs = rpmpsFree(ts->probs);
00780 
00781     rpmtsCleanDig(ts);
00782 }
00783 
00784 void rpmtsEmpty(rpmts ts)
00785 {
00786     rpmtsi pi; rpmte p;
00787     int oc;
00788 
00789     if (ts == NULL)
00790         return;
00791 
00792 /*@-nullstate@*/        /* FIX: partial annotations */
00793     rpmtsClean(ts);
00794 /*@=nullstate@*/
00795 
00796     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00797 /*@-type -unqualifiedtrans @*/
00798         ts->order[oc] = rpmteFree(ts->order[oc]);
00799 /*@=type =unqualifiedtrans @*/
00800     }
00801     pi = rpmtsiFree(pi);
00802 
00803     ts->orderCount = 0;
00804     ts->ntrees = 0;
00805     ts->maxDepth = 0;
00806 
00807     ts->numRemovedPackages = 0;
00808 /*@-nullstate@*/        /* FIX: partial annotations */
00809     return;
00810 /*@=nullstate@*/
00811 }
00812 
00813 static void rpmtsPrintStat(const char * name, /*@null@*/ struct rpmop_s * op)
00814         /*@globals fileSystem @*/
00815         /*@modifies fileSystem @*/
00816 {
00817     static unsigned int scale = (1000 * 1000);
00818     if (op != NULL && op->count > 0)
00819         fprintf(stderr, "   %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
00820                 name, op->count,
00821                 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
00822                 op->usecs/scale, op->usecs%scale);
00823 }
00824 
00825 static void rpmtsPrintStats(rpmts ts)
00826         /*@globals fileSystem, internalState @*/
00827         /*@modifies fileSystem, internalState @*/
00828 {
00829     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
00830 
00831     rpmtsPrintStat("total:       ", rpmtsOp(ts, RPMTS_OP_TOTAL));
00832     rpmtsPrintStat("check:       ", rpmtsOp(ts, RPMTS_OP_CHECK));
00833     rpmtsPrintStat("order:       ", rpmtsOp(ts, RPMTS_OP_ORDER));
00834     rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
00835     rpmtsPrintStat("repackage:   ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
00836     rpmtsPrintStat("install:     ", rpmtsOp(ts, RPMTS_OP_INSTALL));
00837     rpmtsPrintStat("erase:       ", rpmtsOp(ts, RPMTS_OP_ERASE));
00838     rpmtsPrintStat("scriptlets:  ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
00839     rpmtsPrintStat("compress:    ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
00840     rpmtsPrintStat("uncompress:  ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
00841     rpmtsPrintStat("digest:      ", rpmtsOp(ts, RPMTS_OP_DIGEST));
00842     rpmtsPrintStat("signature:   ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
00843     rpmtsPrintStat("dbadd:       ", rpmtsOp(ts, RPMTS_OP_DBADD));
00844     rpmtsPrintStat("dbremove:    ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
00845     rpmtsPrintStat("dbget:       ", rpmtsOp(ts, RPMTS_OP_DBGET));
00846     rpmtsPrintStat("dbput:       ", rpmtsOp(ts, RPMTS_OP_DBPUT));
00847     rpmtsPrintStat("dbdel:       ", rpmtsOp(ts, RPMTS_OP_DBDEL));
00848 }
00849 
00850 rpmts rpmtsFree(rpmts ts)
00851 {
00852     if (ts == NULL)
00853         return NULL;
00854 
00855     if (ts->nrefs > 1)
00856         return rpmtsUnlink(ts, "tsCreate");
00857 
00858 /*@-nullstate@*/        /* FIX: partial annotations */
00859     rpmtsEmpty(ts);
00860 /*@=nullstate@*/
00861 
00862     (void) rpmtsCloseDB(ts);
00863 
00864     (void) rpmtsCloseSDB(ts);
00865 
00866     ts->sx = rpmsxFree(ts->sx);
00867 
00868     ts->removedPackages = _free(ts->removedPackages);
00869 
00870     ts->availablePackages = rpmalFree(ts->availablePackages);
00871     ts->numAvailablePackages = 0;
00872 
00873     ts->dsi = _free(ts->dsi);
00874 
00875     if (ts->scriptFd != NULL) {
00876         ts->scriptFd = fdFree(ts->scriptFd, "rpmtsFree");
00877         ts->scriptFd = NULL;
00878     }
00879     ts->rootDir = _free(ts->rootDir);
00880     ts->currDir = _free(ts->currDir);
00881 
00882 /*@-type +voidabstract @*/      /* FIX: double indirection */
00883     ts->order = _free(ts->order);
00884 /*@=type =voidabstract @*/
00885     ts->orderAlloced = 0;
00886 
00887     if (ts->pkpkt != NULL)
00888         ts->pkpkt = _free(ts->pkpkt);
00889     ts->pkpktlen = 0;
00890     memset(ts->pksignid, 0, sizeof(ts->pksignid));
00891 
00892     if (_rpmts_stats)
00893         rpmtsPrintStats(ts);
00894 
00895     /* Free up the memory used by the rpmtsScore */
00896 /*@-kepttrans -onlytrans @*/
00897     ts->score = rpmtsScoreFree(ts->score);
00898 /*@=kepttrans =onlytrans @*/
00899 
00900     (void) rpmtsUnlink(ts, "tsCreate");
00901 
00902     /*@-refcounttrans -usereleased @*/
00903     ts = _free(ts);
00904     /*@=refcounttrans =usereleased @*/
00905 
00906     return NULL;
00907 }
00908 
00909 rpmVSFlags rpmtsVSFlags(rpmts ts)
00910 {
00911     rpmVSFlags vsflags = 0;
00912     if (ts != NULL)
00913         vsflags = ts->vsflags;
00914     return vsflags;
00915 }
00916 
00917 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
00918 {
00919     rpmVSFlags ovsflags = 0;
00920     if (ts != NULL) {
00921         ovsflags = ts->vsflags;
00922         ts->vsflags = vsflags;
00923     }
00924     return ovsflags;
00925 }
00926 
00927 /* 
00928  * This allows us to mark transactions as being of a certain type.
00929  * The three types are:
00930  * 
00931  *     RPM_TRANS_NORMAL         
00932  *     RPM_TRANS_ROLLBACK
00933  *     RPM_TRANS_AUTOROLLBACK
00934  * 
00935  * ROLLBACK and AUTOROLLBACK transactions should always be ran as
00936  * a best effort.  In particular this is important to the autorollback 
00937  * feature to avoid rolling back a rollback (otherwise known as 
00938  * dueling rollbacks (-;).  AUTOROLLBACK's additionally need instance 
00939  * counts passed to scriptlets to be altered.
00940  */
00941 void rpmtsSetType(rpmts ts, rpmtsType type)
00942 {
00943     if (ts != NULL) {
00944         ts->type = type;
00945     }    
00946 }
00947 
00948 /* Let them know what type of transaction we are */
00949 rpmtsType rpmtsGetType(rpmts ts) 
00950 {
00951     if (ts != NULL) 
00952         return ts->type;
00953     else
00954         return 0;
00955 }
00956 
00957 int rpmtsUnorderedSuccessors(rpmts ts, int first)
00958 {
00959     int unorderedSuccessors = 0;
00960     if (ts != NULL) {
00961         unorderedSuccessors = ts->unorderedSuccessors;
00962         if (first >= 0)
00963             ts->unorderedSuccessors = first;
00964     }
00965     return unorderedSuccessors;
00966 }
00967 
00968 const char * rpmtsRootDir(rpmts ts)
00969 {
00970     const char * rootDir = NULL;
00971 
00972 /*@-branchstate@*/
00973     if (ts != NULL && ts->rootDir != NULL) {
00974         urltype ut = urlPath(ts->rootDir, &rootDir);
00975         switch (ut) {
00976         case URL_IS_UNKNOWN:
00977         case URL_IS_PATH:
00978             break;
00979         case URL_IS_HTTPS:
00980         case URL_IS_HTTP:
00981         case URL_IS_HKP:
00982         case URL_IS_FTP:
00983         case URL_IS_DASH:
00984         default:
00985             rootDir = "/";
00986             break;
00987         }
00988     }
00989 /*@=branchstate@*/
00990     return rootDir;
00991 }
00992 
00993 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
00994 {
00995     if (ts != NULL) {
00996         size_t rootLen;
00997 
00998         ts->rootDir = _free(ts->rootDir);
00999 
01000         if (rootDir == NULL) {
01001 #ifndef DYING
01002             ts->rootDir = xstrdup("");
01003 #endif
01004             return;
01005         }
01006         rootLen = strlen(rootDir);
01007 
01008 /*@-branchstate@*/
01009         /* Make sure that rootDir has trailing / */
01010         if (!(rootLen && rootDir[rootLen - 1] == '/')) {
01011             char * t = alloca(rootLen + 2);
01012             *t = '\0';
01013             (void) stpcpy( stpcpy(t, rootDir), "/");
01014             rootDir = t;
01015         }
01016 /*@=branchstate@*/
01017         ts->rootDir = xstrdup(rootDir);
01018     }
01019 }
01020 
01021 const char * rpmtsCurrDir(rpmts ts)
01022 {
01023     const char * currDir = NULL;
01024     if (ts != NULL) {
01025         currDir = ts->currDir;
01026     }
01027     return currDir;
01028 }
01029 
01030 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
01031 {
01032     if (ts != NULL) {
01033         ts->currDir = _free(ts->currDir);
01034         if (currDir)
01035             ts->currDir = xstrdup(currDir);
01036     }
01037 }
01038 
01039 FD_t rpmtsScriptFd(rpmts ts)
01040 {
01041     FD_t scriptFd = NULL;
01042     if (ts != NULL) {
01043         scriptFd = ts->scriptFd;
01044     }
01045 /*@-compdef -refcounttrans -usereleased@*/
01046     return scriptFd;
01047 /*@=compdef =refcounttrans =usereleased@*/
01048 }
01049 
01050 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
01051 {
01052 
01053     if (ts != NULL) {
01054         if (ts->scriptFd != NULL) {
01055             ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
01056             ts->scriptFd = NULL;
01057         }
01058 /*@+voidabstract@*/
01059         if (scriptFd != NULL)
01060             ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
01061 /*@=voidabstract@*/
01062     }
01063 }
01064 
01065 int rpmtsSELinuxEnabled(rpmts ts)
01066 {
01067     return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
01068 }
01069 
01070 int rpmtsChrootDone(rpmts ts)
01071 {
01072     return (ts != NULL ? ts->chrootDone : 0);
01073 }
01074 
01075 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
01076 {
01077     int ochrootDone = 0;
01078     if (ts != NULL) {
01079         ochrootDone = ts->chrootDone;
01080         if (ts->rdb != NULL)
01081             ts->rdb->db_chrootDone = chrootDone;
01082         ts->chrootDone = chrootDone;
01083     }
01084     return ochrootDone;
01085 }
01086 
01087 rpmsx rpmtsREContext(rpmts ts)
01088 {
01089     return ( (ts && ts->sx ? rpmsxLink(ts->sx, __func__) : NULL) );
01090 }
01091 
01092 int rpmtsSetREContext(rpmts ts, rpmsx sx)
01093 {
01094     int rc = -1;
01095     if (ts != NULL) {
01096         ts->sx = rpmsxFree(ts->sx);
01097         ts->sx = rpmsxLink(sx, __func__);
01098         if (ts->sx != NULL)
01099             rc = 0;
01100     }
01101     return rc;
01102 }
01103 
01104 int_32 rpmtsGetTid(rpmts ts)
01105 {
01106     int_32 tid = 0;
01107     if (ts != NULL) {
01108         tid = ts->tid;
01109     }
01110     return tid;
01111 }
01112 
01113 int_32 rpmtsSetTid(rpmts ts, int_32 tid)
01114 {
01115     int_32 otid = 0;
01116     if (ts != NULL) {
01117         otid = ts->tid;
01118         ts->tid = tid;
01119     }
01120     return otid;
01121 }
01122 
01123 int_32 rpmtsSigtag(const rpmts ts)
01124 {
01125     int_32 sigtag = 0;
01126     if (ts != NULL)
01127         sigtag = ts->sigtag;
01128     return sigtag;
01129 }
01130 
01131 int_32 rpmtsSigtype(const rpmts ts)
01132 {
01133     int_32 sigtype = 0;
01134     if (ts != NULL)
01135         sigtype = ts->sigtype;
01136     return sigtype;
01137 }
01138 
01139 const void * rpmtsSig(const rpmts ts)
01140 {
01141     const void * sig = NULL;
01142     if (ts != NULL)
01143         sig = ts->sig;
01144     return sig;
01145 }
01146 
01147 int_32 rpmtsSiglen(const rpmts ts)
01148 {
01149     int_32 siglen = 0;
01150     if (ts != NULL)
01151         siglen = ts->siglen;
01152     return siglen;
01153 }
01154 
01155 int rpmtsSetSig(rpmts ts,
01156                 int_32 sigtag, int_32 sigtype, const void * sig, int_32 siglen)
01157 {
01158     if (ts != NULL) {
01159         if (ts->sig && ts->sigtype)
01160             ts->sig = headerFreeData(ts->sig, ts->sigtype);
01161         ts->sigtag = sigtag;
01162         ts->sigtype = (sig ? sigtype : 0);
01163 /*@-assignexpose -kepttrans@*/
01164         ts->sig = sig;
01165 /*@=assignexpose =kepttrans@*/
01166         ts->siglen = siglen;
01167     }
01168     return 0;
01169 }
01170 
01171 pgpDig rpmtsDig(rpmts ts)
01172 {
01173 /*@-mods@*/ /* FIX: hide lazy malloc for now */
01174     if (ts->dig == NULL)
01175         ts->dig = pgpNewDig();
01176 /*@=mods@*/
01177     if (ts->dig == NULL)
01178         return NULL;
01179     return ts->dig;
01180 }
01181 
01182 pgpDigParams rpmtsSignature(const rpmts ts)
01183 {
01184     pgpDig dig = rpmtsDig(ts);
01185     if (dig == NULL) return NULL;
01186 /*@-immediatetrans@*/
01187     return &dig->signature;
01188 /*@=immediatetrans@*/
01189 }
01190 
01191 pgpDigParams rpmtsPubkey(const rpmts ts)
01192 {
01193     pgpDig dig = rpmtsDig(ts);
01194     if (dig == NULL) return NULL;
01195 /*@-immediatetrans@*/
01196     return &dig->pubkey;
01197 /*@=immediatetrans@*/
01198 }
01199 
01200 rpmdb rpmtsGetRdb(rpmts ts)
01201 {
01202     rpmdb rdb = NULL;
01203     if (ts != NULL) {
01204         rdb = ts->rdb;
01205     }
01206 /*@-compdef -refcounttrans -usereleased @*/
01207     return rdb;
01208 /*@=compdef =refcounttrans =usereleased @*/
01209 }
01210 
01211 int rpmtsInitDSI(const rpmts ts)
01212 {
01213     rpmDiskSpaceInfo dsi;
01214     struct stat sb;
01215     int rc;
01216     int i;
01217 
01218     if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
01219         return 0;
01220 
01221     rpmMessage(RPMMESS_DEBUG, _("mounted filesystems:\n"));
01222     rpmMessage(RPMMESS_DEBUG,
01223         _("    i        dev    bsize       bavail       iavail mount point\n"));
01224 
01225     rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
01226     if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
01227         return rc;
01228 
01229     /* Get available space on mounted file systems. */
01230 
01231     ts->dsi = _free(ts->dsi);
01232     ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
01233 
01234     dsi = ts->dsi;
01235 
01236     if (dsi != NULL)
01237     for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
01238 #if STATFS_IN_SYS_STATVFS
01239         struct statvfs sfb;
01240         memset(&sfb, 0, sizeof(sfb));
01241         rc = statvfs(ts->filesystems[i], &sfb);
01242 #else
01243         struct statfs sfb;
01244         memset(&sfb, 0, sizeof(sfb));
01245 #  if STAT_STATFS4
01246 /* This platform has the 4-argument version of the statfs call.  The last two
01247  * should be the size of struct statfs and 0, respectively.  The 0 is the
01248  * filesystem type, and is always 0 when statfs is called on a mounted
01249  * filesystem, as we're doing.
01250  */
01251         rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
01252 #  else
01253         rc = statfs(ts->filesystems[i], &sfb);
01254 #  endif
01255 #endif
01256         if (rc)
01257             break;
01258 
01259         rc = stat(ts->filesystems[i], &sb);
01260         if (rc)
01261             break;
01262         dsi->dev = sb.st_dev;
01263 
01264         dsi->bsize = sfb.f_bsize;
01265         dsi->bneeded = 0;
01266         dsi->ineeded = 0;
01267 #ifdef STATFS_HAS_F_BAVAIL
01268         dsi->bavail = sfb.f_bavail;
01269 #else
01270 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
01271  * available for non-superusers.  f_blocks - f_bfree is probably too big, but
01272  * it's about all we can do.
01273  */
01274         dsi->bavail = sfb.f_blocks - sfb.f_bfree;
01275 #endif
01276         /* XXX Avoid FAT and other file systems that have not inodes. */
01277         dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
01278                                 ? sfb.f_ffree : -1;
01279         rpmMessage(RPMMESS_DEBUG, _("%5d 0x%08x %8u %12ld %12ld %s\n"),
01280                 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
01281                 (signed long) dsi->bavail, (signed long) dsi->iavail,
01282                 ts->filesystems[i]);
01283     }
01284     return rc;
01285 }
01286 
01287 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
01288                 uint_32 fileSize, uint_32 prevSize, uint_32 fixupSize,
01289                 fileAction action)
01290 {
01291     rpmDiskSpaceInfo dsi;
01292     uint_32 bneeded;
01293 
01294     dsi = ts->dsi;
01295     if (dsi) {
01296         while (dsi->bsize && dsi->dev != dev)
01297             dsi++;
01298         if (dsi->bsize == 0)
01299             dsi = NULL;
01300     }
01301     if (dsi == NULL)
01302         return;
01303 
01304     bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
01305 
01306     switch (action) {
01307     case FA_BACKUP:
01308     case FA_SAVE:
01309     case FA_ALTNAME:
01310         dsi->ineeded++;
01311         dsi->bneeded += bneeded;
01312         /*@switchbreak@*/ break;
01313 
01314     /*
01315      * FIXME: If two packages share a file (same md5sum), and
01316      * that file is being replaced on disk, will dsi->bneeded get
01317      * adjusted twice? Quite probably!
01318      */
01319     case FA_CREATE:
01320         dsi->bneeded += bneeded;
01321         dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
01322         /*@switchbreak@*/ break;
01323 
01324     case FA_ERASE:
01325         dsi->ineeded--;
01326         dsi->bneeded -= bneeded;
01327         /*@switchbreak@*/ break;
01328 
01329     default:
01330         /*@switchbreak@*/ break;
01331     }
01332 
01333     if (fixupSize)
01334         dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
01335 }
01336 
01337 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
01338 {
01339     rpmDiskSpaceInfo dsi;
01340     rpmps ps;
01341     int fc;
01342     int i;
01343 
01344     if (ts->filesystems == NULL || ts->filesystemCount <= 0)
01345         return;
01346 
01347     dsi = ts->dsi;
01348     if (dsi == NULL)
01349         return;
01350     fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
01351     if (fc <= 0)
01352         return;
01353 
01354     ps = rpmtsProblems(ts);
01355     for (i = 0; i < ts->filesystemCount; i++, dsi++) {
01356 
01357         if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
01358             rpmpsAppend(ps, RPMPROB_DISKSPACE,
01359                         rpmteNEVR(te), rpmteKey(te),
01360                         ts->filesystems[i], NULL, NULL,
01361            (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
01362         }
01363 
01364         if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
01365             rpmpsAppend(ps, RPMPROB_DISKNODES,
01366                         rpmteNEVR(te), rpmteKey(te),
01367                         ts->filesystems[i], NULL, NULL,
01368             (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
01369         }
01370     }
01371     ps = rpmpsFree(ps);
01372 }
01373 
01374 void * rpmtsNotify(rpmts ts, rpmte te,
01375                 rpmCallbackType what, unsigned long amount, unsigned long total)
01376 {
01377     void * ptr = NULL;
01378     if (ts && ts->notify && te) {
01379 assert(!(te->type == TR_ADDED && te->h == NULL));
01380         /*@-type@*/ /* FIX: cast? */
01381         /*@-noeffectuncon @*/ /* FIX: check rc */
01382         ptr = ts->notify(te->h, what, amount, total,
01383                         rpmteKey(te), ts->notifyData);
01384         /*@=noeffectuncon @*/
01385         /*@=type@*/
01386     }
01387     return ptr;
01388 }
01389 
01390 int rpmtsNElements(rpmts ts)
01391 {
01392     int nelements = 0;
01393     if (ts != NULL && ts->order != NULL) {
01394         nelements = ts->orderCount;
01395     }
01396     return nelements;
01397 }
01398 
01399 rpmte rpmtsElement(rpmts ts, int ix)
01400 {
01401     rpmte te = NULL;
01402     if (ts != NULL && ts->order != NULL) {
01403         if (ix >= 0 && ix < ts->orderCount)
01404             te = ts->order[ix];
01405     }
01406     /*@-compdef@*/
01407     return te;
01408     /*@=compdef@*/
01409 }
01410 
01411 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
01412 {
01413     return (ts != NULL ? ts->ignoreSet : 0);
01414 }
01415 
01416 rpmtransFlags rpmtsFlags(rpmts ts)
01417 {
01418     return (ts != NULL ? ts->transFlags : 0);
01419 }
01420 
01421 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
01422 {
01423     rpmtransFlags otransFlags = 0;
01424     if (ts != NULL) {
01425         otransFlags = ts->transFlags;
01426         ts->transFlags = transFlags;
01427     }
01428     return otransFlags;
01429 }
01430 
01431 Spec rpmtsSpec(rpmts ts)
01432 {
01433 /*@-compdef -retexpose -usereleased@*/
01434     return ts->spec;
01435 /*@=compdef =retexpose =usereleased@*/
01436 }
01437 
01438 Spec rpmtsSetSpec(rpmts ts, Spec spec)
01439 {
01440     Spec ospec = ts->spec;
01441 /*@-assignexpose -temptrans@*/
01442     ts->spec = spec;
01443 /*@=assignexpose =temptrans@*/
01444     return ospec;
01445 }
01446 
01447 rpmte rpmtsRelocateElement(rpmts ts)
01448 {
01449 /*@-compdef -retexpose -usereleased@*/
01450     return ts->relocateElement;
01451 /*@=compdef =retexpose =usereleased@*/
01452 }
01453 
01454 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
01455 {
01456     rpmte orelocateElement = ts->relocateElement;
01457 /*@-assignexpose -temptrans@*/
01458     ts->relocateElement = relocateElement;
01459 /*@=assignexpose =temptrans@*/
01460     return orelocateElement;
01461 }
01462 
01463 uint_32 rpmtsColor(rpmts ts)
01464 {
01465     return (ts != NULL ? ts->color : 0);
01466 }
01467 
01468 uint_32 rpmtsSetColor(rpmts ts, uint_32 color)
01469 {
01470     uint_32 ocolor = 0;
01471     if (ts != NULL) {
01472         ocolor = ts->color;
01473         ts->color = color;
01474     }
01475     return ocolor;
01476 }
01477 
01478 uint_32 rpmtsPrefColor(rpmts ts)
01479 {
01480     return (ts != NULL ? ts->prefcolor : 0);
01481 }
01482 
01483 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
01484 {
01485     rpmop op = NULL;
01486 
01487     if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
01488         op = ts->ops + opx;
01489 /*@-usereleased -compdef @*/
01490     return op;
01491 /*@=usereleased =compdef @*/
01492 }
01493 
01494 int rpmtsSetNotifyCallback(rpmts ts,
01495                 rpmCallbackFunction notify, rpmCallbackData notifyData)
01496 {
01497     if (ts != NULL) {
01498         ts->notify = notify;
01499         ts->notifyData = notifyData;
01500     }
01501     return 0;
01502 }
01503 
01504 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
01505 {
01506     int rc = 0;
01507 
01508     if (nep) *nep = ts->orderCount;
01509     if (ep) {
01510         rpmtsi pi;      rpmte p;
01511         fnpyKey * e;
01512 
01513         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
01514         pi = rpmtsiInit(ts);
01515         while ((p = rpmtsiNext(pi, 0)) != NULL) {
01516             switch (rpmteType(p)) {
01517             case TR_ADDED:
01518                 /*@-dependenttrans@*/
01519                 *e = rpmteKey(p);
01520                 /*@=dependenttrans@*/
01521                 /*@switchbreak@*/ break;
01522             case TR_REMOVED:
01523             default:
01524                 *e = NULL;
01525                 /*@switchbreak@*/ break;
01526             }
01527             e++;
01528         }
01529         pi = rpmtsiFree(pi);
01530     }
01531     return rc;
01532 }
01533 
01534 rpmts rpmtsCreate(void)
01535 {
01536     rpmts ts;
01537 
01538     ts = xcalloc(1, sizeof(*ts));
01539     memset(&ts->ops, 0, sizeof(ts->ops));
01540     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
01541     ts->type = RPMTRANS_TYPE_NORMAL;
01542     ts->goal = TSM_UNKNOWN;
01543     ts->filesystemCount = 0;
01544     ts->filesystems = NULL;
01545     ts->dsi = NULL;
01546 
01547     ts->solve = rpmtsSolve;
01548     ts->solveData = NULL;
01549     ts->nsuggests = 0;
01550     ts->suggests = NULL;
01551     ts->sdb = NULL;
01552     ts->sdbmode = O_RDONLY;
01553 
01554     ts->rdb = NULL;
01555     ts->dbmode = O_RDONLY;
01556 
01557     ts->scriptFd = NULL;
01558     ts->tid = (int_32) time(NULL);
01559     ts->delta = 5;
01560 
01561     ts->color = rpmExpandNumeric("%{?_transaction_color}");
01562     ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
01563 
01564     ts->numRemovedPackages = 0;
01565     ts->allocedRemovedPackages = ts->delta;
01566     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
01567                         sizeof(*ts->removedPackages));
01568 
01569     ts->rootDir = NULL;
01570     ts->currDir = NULL;
01571     ts->chrootDone = 0;
01572 
01573     ts->selinuxEnabled = is_selinux_enabled();
01574 
01575     ts->numAddedPackages = 0;
01576     ts->addedPackages = NULL;
01577 
01578     ts->numAvailablePackages = 0;
01579     ts->availablePackages = NULL;
01580 
01581     ts->orderAlloced = 0;
01582     ts->orderCount = 0;
01583     ts->order = NULL;
01584     ts->ntrees = 0;
01585     ts->maxDepth = 0;
01586 
01587     ts->probs = NULL;
01588 
01589     ts->sig = NULL;
01590     ts->pkpkt = NULL;
01591     ts->pkpktlen = 0;
01592     memset(ts->pksignid, 0, sizeof(ts->pksignid));
01593     ts->dig = NULL;
01594 
01595     /* 
01596      * We only use the score in an autorollback.  So set this to
01597      * NULL by default.
01598      */
01599     ts->score = NULL;
01600 
01601     ts->nrefs = 0;
01602 
01603     return rpmtsLink(ts, "tsCreate");
01604 }
01605 
01606 /**********************
01607  * Transaction Scores *
01608  **********************/
01609 
01610 
01611 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS) 
01612 {
01613     rpmtsScore score;
01614     rpmtsi     pi;
01615     rpmte      p;
01616     int        i;
01617     int        tranElements;  /* Number of transaction elements in runningTS */
01618     int        found = 0;
01619     rpmRC      rc = RPMRC_OK; /* Assume success */
01620     rpmtsScoreEntry se;
01621 
01622     rpmMessage(RPMMESS_DEBUG, _("Creating transaction score board(%p, %p)\n"),
01623         runningTS, rollbackTS); 
01624 
01625     /* Allocate space for score board */
01626     score = xcalloc(1, sizeof(*score));
01627     rpmMessage(RPMMESS_DEBUG, _("\tScore board address:  %p\n"), score);
01628 
01629     /* 
01630      * Determine the maximum size needed for the entry list.
01631      * XXX: Today, I just get the count of rpmts elements, and allocate
01632      *      an array that big.  Yes this is guaranteed to waste memory.
01633      *      Future updates will hopefully make this more efficient,
01634      *      but for now it will work.
01635      */
01636     tranElements  = rpmtsNElements(runningTS);
01637     rpmMessage(RPMMESS_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
01638     score->scores = xcalloc(tranElements, sizeof(score->scores));
01639 
01640     /* Initialize score entry count */
01641     score->entries = 0;
01642     score->nrefs   = 0;
01643 
01644     /*
01645      * Increment through transaction elements and make sure for every 
01646      * N there is an rpmtsScoreEntry.
01647      */
01648     pi = rpmtsiInit(runningTS); 
01649     while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
01650         found  = 0;
01651 
01652         /* Try to find the entry in the score list */
01653         for(i = 0; i < score->entries; i++) {
01654             se = score->scores[i]; 
01655             if (strcmp(rpmteN(p), se->N) == 0) {
01656                 found = 1;
01657                 /*@innerbreak@*/ break;
01658             }
01659         }
01660 
01661         /* If we did not find the entry then allocate space for it */
01662         if (!found) {
01663 /*@-compdef -usereleased@*/ /* XXX p->fi->te undefined. */
01664             rpmMessage(RPMMESS_DEBUG, _("\tAdding entry for %s to score board.\n"),
01665                 rpmteN(p));
01666 /*@=compdef =usereleased@*/
01667             se = xcalloc(1, sizeof(*(*(score->scores))));
01668             rpmMessage(RPMMESS_DEBUG, _("\t\tEntry address:  %p\n"), se);
01669             se->N         = xstrdup(rpmteN(p));
01670             se->te_types  = rpmteType(p); 
01671             se->installed = 0;
01672             se->erased    = 0; 
01673             score->scores[score->entries] = se;
01674             score->entries++;
01675         } else {
01676             /* We found this one, so just add the element type to the one 
01677              * already there.
01678              */
01679             rpmMessage(RPMMESS_DEBUG, _("\tUpdating entry for %s in score board.\n"),
01680                 rpmteN(p));
01681             score->scores[i]->te_types |= rpmteType(p);
01682         }
01683          
01684     }
01685     pi = rpmtsiFree(pi);
01686  
01687     /* 
01688      * Attach the score to the running transaction and the autorollback
01689      * transaction.
01690      */
01691     runningTS->score  = score;
01692     score->nrefs++;
01693     rollbackTS->score = score;
01694     score->nrefs++;
01695 
01696     return rc;
01697 }
01698 
01699 rpmtsScore rpmtsScoreFree(rpmtsScore score) 
01700 {
01701     rpmtsScoreEntry se = NULL;
01702     int i;
01703 
01704     rpmMessage(RPMMESS_DEBUG, _("May free Score board(%p)\n"), score);
01705 
01706     /* If score is not initialized, then just return.
01707      * This is likely the case if autorollbacks are not enabled.
01708      */
01709     if (score == NULL) return NULL;
01710 
01711     /* Decrement the reference count */
01712     score->nrefs--;
01713 
01714     /* Do we have any more references?  If so
01715      * just return.
01716      */
01717     if (score->nrefs > 0) return NULL;
01718 
01719     rpmMessage(RPMMESS_DEBUG, _("\tRefcount is zero...will free\n"));
01720     /* No more references, lets clean up  */
01721     /* First deallocate the score entries */
01722 /*@-branchstate@*/
01723     for(i = 0; i < score->entries; i++) {
01724         /* Get the score for the ith entry */
01725         se = score->scores[i]; 
01726         
01727         /* Deallocate the score entries name */
01728         se->N = _free(se->N);
01729 
01730         /* Deallocate the score entry itself */
01731         se = _free(se);
01732     }
01733 /*@=branchstate@*/
01734 
01735     /* Next deallocate the score entry table */
01736     score->scores = _free(score->scores);
01737 
01738     /* Finally deallocate the score itself */
01739     score = _free(score);
01740 
01741     return NULL;
01742 }
01743 
01744 /* 
01745  * XXX: Do not get the score and then store it aside for later use.
01746  *      we will delete it out from under you.  There is no rpmtsScoreLink()
01747  *      as this may be a very temporary fix for autorollbacks.
01748  */
01749 rpmtsScore rpmtsGetScore(rpmts ts) 
01750 {
01751     if (ts == NULL) return NULL;
01752     return ts->score;
01753 }
01754 
01755 /* 
01756  * XXX: Do not get the score entry and then store it aside for later use.
01757  *      we will delete it out from under you.  There is no 
01758  *      rpmtsScoreEntryLink() as this may be a very temporary fix 
01759  *      for autorollbacks.
01760  * XXX: The scores are not sorted.  This should be fixed at earliest
01761  *      opportunity (i.e. when we have the whole autorollback working).
01762  */
01763 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N) 
01764 {
01765     int i;
01766     rpmtsScoreEntry se;
01767     rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
01768 
01769     rpmMessage(RPMMESS_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
01770 
01771     /* Try to find the entry in the score list */
01772     for(i = 0; i < score->entries; i++) {
01773         se = score->scores[i]; 
01774         if (strcmp(N, se->N) == 0) {
01775             rpmMessage(RPMMESS_DEBUG, _("\tFound entry at address:  %p\n"), se);
01776             ret = se;
01777             break;
01778         }
01779     }
01780         
01781 /*@-compdef@*/ /* XXX score->scores undefined. */
01782     return ret; 
01783 /*@=compdef@*/
01784 }

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2