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",
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 = 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 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
01479 {
01480     rpmop op = NULL;
01481 
01482     if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
01483         op = ts->ops + opx;
01484 /*@-usereleased -compdef @*/
01485     return op;
01486 /*@=usereleased =compdef @*/
01487 }
01488 
01489 int rpmtsSetNotifyCallback(rpmts ts,
01490                 rpmCallbackFunction notify, rpmCallbackData notifyData)
01491 {
01492     if (ts != NULL) {
01493         ts->notify = notify;
01494         ts->notifyData = notifyData;
01495     }
01496     return 0;
01497 }
01498 
01499 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
01500 {
01501     int rc = 0;
01502 
01503     if (nep) *nep = ts->orderCount;
01504     if (ep) {
01505         rpmtsi pi;      rpmte p;
01506         fnpyKey * e;
01507 
01508         *ep = e = xmalloc(ts->orderCount * sizeof(*e));
01509         pi = rpmtsiInit(ts);
01510         while ((p = rpmtsiNext(pi, 0)) != NULL) {
01511             switch (rpmteType(p)) {
01512             case TR_ADDED:
01513                 /*@-dependenttrans@*/
01514                 *e = rpmteKey(p);
01515                 /*@=dependenttrans@*/
01516                 /*@switchbreak@*/ break;
01517             case TR_REMOVED:
01518             default:
01519                 *e = NULL;
01520                 /*@switchbreak@*/ break;
01521             }
01522             e++;
01523         }
01524         pi = rpmtsiFree(pi);
01525     }
01526     return rc;
01527 }
01528 
01529 rpmts rpmtsCreate(void)
01530 {
01531     rpmts ts;
01532 
01533     ts = xcalloc(1, sizeof(*ts));
01534     memset(&ts->ops, 0, sizeof(ts->ops));
01535     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
01536     ts->type = RPMTRANS_TYPE_NORMAL;
01537     ts->goal = TSM_UNKNOWN;
01538     ts->filesystemCount = 0;
01539     ts->filesystems = NULL;
01540     ts->dsi = NULL;
01541 
01542     ts->solve = rpmtsSolve;
01543     ts->solveData = NULL;
01544     ts->nsuggests = 0;
01545     ts->suggests = NULL;
01546     ts->sdb = NULL;
01547     ts->sdbmode = O_RDONLY;
01548 
01549     ts->rdb = NULL;
01550     ts->dbmode = O_RDONLY;
01551 
01552     ts->scriptFd = NULL;
01553     ts->tid = (int_32) time(NULL);
01554     ts->delta = 5;
01555 
01556     ts->color = rpmExpandNumeric("%{?_transaction_color}");
01557 
01558     ts->numRemovedPackages = 0;
01559     ts->allocedRemovedPackages = ts->delta;
01560     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
01561                         sizeof(*ts->removedPackages));
01562 
01563     ts->rootDir = NULL;
01564     ts->currDir = NULL;
01565     ts->chrootDone = 0;
01566 
01567     ts->selinuxEnabled = is_selinux_enabled();
01568 
01569     ts->numAddedPackages = 0;
01570     ts->addedPackages = NULL;
01571 
01572     ts->numAvailablePackages = 0;
01573     ts->availablePackages = NULL;
01574 
01575     ts->orderAlloced = 0;
01576     ts->orderCount = 0;
01577     ts->order = NULL;
01578     ts->ntrees = 0;
01579     ts->maxDepth = 0;
01580 
01581     ts->probs = NULL;
01582 
01583     ts->sig = NULL;
01584     ts->pkpkt = NULL;
01585     ts->pkpktlen = 0;
01586     memset(ts->pksignid, 0, sizeof(ts->pksignid));
01587     ts->dig = NULL;
01588 
01589     /* 
01590      * We only use the score in an autorollback.  So set this to
01591      * NULL by default.
01592      */
01593     ts->score = NULL;
01594 
01595     ts->nrefs = 0;
01596 
01597     return rpmtsLink(ts, "tsCreate");
01598 }
01599 
01600 /**********************
01601  * Transaction Scores *
01602  **********************/
01603 
01604 
01605 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS) 
01606 {
01607     rpmtsScore score;
01608     rpmtsi     pi;
01609     rpmte      p;
01610     int        i;
01611     int        tranElements;  /* Number of transaction elements in runningTS */
01612     int        found = 0;
01613     rpmRC      rc = RPMRC_OK; /* Assume success */
01614     rpmtsScoreEntry se;
01615 
01616     rpmMessage(RPMMESS_DEBUG, _("Creating transaction score board(%p, %p)\n"),
01617         runningTS, rollbackTS); 
01618 
01619     /* Allocate space for score board */
01620     score = xcalloc(1, sizeof(*score));
01621     rpmMessage(RPMMESS_DEBUG, _("\tScore board address:  %p\n"), score);
01622 
01623     /* 
01624      * Determine the maximum size needed for the entry list.
01625      * XXX: Today, I just get the count of rpmts elements, and allocate
01626      *      an array that big.  Yes this is guaranteed to waste memory.
01627      *      Future updates will hopefully make this more efficient,
01628      *      but for now it will work.
01629      */
01630     tranElements  = rpmtsNElements(runningTS);
01631     rpmMessage(RPMMESS_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
01632     score->scores = xcalloc(tranElements, sizeof(score->scores));
01633 
01634     /* Initialize score entry count */
01635     score->entries = 0;
01636     score->nrefs   = 0;
01637 
01638     /*
01639      * Increment through transaction elements and make sure for every 
01640      * N there is an rpmtsScoreEntry.
01641      */
01642     pi = rpmtsiInit(runningTS); 
01643     while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
01644         found  = 0;
01645 
01646         /* Try to find the entry in the score list */
01647         for(i = 0; i < score->entries; i++) {
01648             se = score->scores[i]; 
01649             if (strcmp(rpmteN(p), se->N) == 0) {
01650                 found = 1;
01651                 /*@innerbreak@*/ break;
01652             }
01653         }
01654 
01655         /* If we did not find the entry then allocate space for it */
01656         if (!found) {
01657 /*@-compdef -usereleased@*/ /* XXX p->fi->te undefined. */
01658             rpmMessage(RPMMESS_DEBUG, _("\tAdding entry for %s to score board.\n"),
01659                 rpmteN(p));
01660 /*@=compdef =usereleased@*/
01661             se = xcalloc(1, sizeof(*(*(score->scores))));
01662             rpmMessage(RPMMESS_DEBUG, _("\t\tEntry address:  %p\n"), se);
01663             se->N         = xstrdup(rpmteN(p));
01664             se->te_types  = rpmteType(p); 
01665             se->installed = 0;
01666             se->erased    = 0; 
01667             score->scores[score->entries] = se;
01668             score->entries++;
01669         } else {
01670             /* We found this one, so just add the element type to the one 
01671              * already there.
01672              */
01673             rpmMessage(RPMMESS_DEBUG, _("\tUpdating entry for %s in score board.\n"),
01674                 rpmteN(p));
01675             score->scores[i]->te_types |= rpmteType(p);
01676         }
01677          
01678     }
01679     pi = rpmtsiFree(pi);
01680  
01681     /* 
01682      * Attach the score to the running transaction and the autorollback
01683      * transaction.
01684      */
01685     runningTS->score  = score;
01686     score->nrefs++;
01687     rollbackTS->score = score;
01688     score->nrefs++;
01689 
01690     return rc;
01691 }
01692 
01693 rpmtsScore rpmtsScoreFree(rpmtsScore score) 
01694 {
01695     rpmtsScoreEntry se = NULL;
01696     int i;
01697 
01698     rpmMessage(RPMMESS_DEBUG, _("May free Score board(%p)\n"), score);
01699 
01700     /* If score is not initialized, then just return.
01701      * This is likely the case if autorollbacks are not enabled.
01702      */
01703     if (score == NULL) return NULL;
01704 
01705     /* Decrement the reference count */
01706     score->nrefs--;
01707 
01708     /* Do we have any more references?  If so
01709      * just return.
01710      */
01711     if (score->nrefs > 0) return NULL;
01712 
01713     rpmMessage(RPMMESS_DEBUG, _("\tRefcount is zero...will free\n"));
01714     /* No more references, lets clean up  */
01715     /* First deallocate the score entries */
01716 /*@-branchstate@*/
01717     for(i = 0; i < score->entries; i++) {
01718         /* Get the score for the ith entry */
01719         se = score->scores[i]; 
01720         
01721         /* Deallocate the score entries name */
01722         se->N = _free(se->N);
01723 
01724         /* Deallocate the score entry itself */
01725         se = _free(se);
01726     }
01727 /*@=branchstate@*/
01728 
01729     /* Next deallocate the score entry table */
01730     score->scores = _free(score->scores);
01731 
01732     /* Finally deallocate the score itself */
01733     score = _free(score);
01734 
01735     return NULL;
01736 }
01737 
01738 /* 
01739  * XXX: Do not get the score and then store it aside for later use.
01740  *      we will delete it out from under you.  There is no rpmtsScoreLink()
01741  *      as this may be a very temporary fix for autorollbacks.
01742  */
01743 rpmtsScore rpmtsGetScore(rpmts ts) 
01744 {
01745     if (ts == NULL) return NULL;
01746     return ts->score;
01747 }
01748 
01749 /* 
01750  * XXX: Do not get the score entry and then store it aside for later use.
01751  *      we will delete it out from under you.  There is no 
01752  *      rpmtsScoreEntryLink() as this may be a very temporary fix 
01753  *      for autorollbacks.
01754  * XXX: The scores are not sorted.  This should be fixed at earliest
01755  *      opportunity (i.e. when we have the whole autorollback working).
01756  */
01757 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N) 
01758 {
01759     int i;
01760     rpmtsScoreEntry se;
01761     rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
01762 
01763     rpmMessage(RPMMESS_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
01764 
01765     /* Try to find the entry in the score list */
01766     for(i = 0; i < score->entries; i++) {
01767         se = score->scores[i]; 
01768         if (strcmp(N, se->N) == 0) {
01769             rpmMessage(RPMMESS_DEBUG, _("\tFound entry at address:  %p\n"), se);
01770             ret = se;
01771             break;
01772         }
01773     }
01774         
01775 /*@-compdef@*/ /* XXX score->scores undefined. */
01776     return ret; 
01777 /*@=compdef@*/
01778 }

Generated on Wed Jan 28 12:45:24 2009 for rpm by  doxygen 1.4.7