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

# lib/rpmts.c

Go to the documentation of this file.

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