3 * Routine(s) to handle a "rpmts" transaction sets.
7 #include <rpm/rpmtag.h>
8 #include <rpm/rpmlib.h> /* rpmReadPackage etc */
9 #include <rpm/rpmurl.h>
10 #include "rpmio/digest.h"
11 #include <rpm/rpmmacro.h>
12 #include <rpm/rpmfileutil.h> /* rpmtsOpenDB() needs rpmGetPath */
13 #include <rpm/rpmstring.h>
15 #include <rpm/rpmdb.h>
16 #include <rpm/rpmal.h>
17 #include <rpm/rpmds.h>
18 #include <rpm/rpmfi.h>
19 #include <rpm/rpmlog.h>
20 #include <rpm/rpmte.h>
22 #include "lib/rpmlock.h"
23 #include "lib/rpmts_internal.h"
25 /* XXX FIXME: merge with existing (broken?) tests in system.h */
26 /* portability fiddles */
27 #if STATFS_IN_SYS_STATVFS
28 #include <sys/statvfs.h>
31 # if STATFS_IN_SYS_VFS
34 # if STATFS_IN_SYS_MOUNT
35 # include <sys/mount.h>
37 # if STATFS_IN_SYS_STATFS
38 # include <sys/statfs.h>
50 rpmts rpmtsUnlink(rpmts ts, const char * msg)
53 fprintf(stderr, "--> ts %p -- %d %s\n", ts, ts->nrefs, msg);
58 rpmts rpmtsLink(rpmts ts, const char * msg)
62 fprintf(stderr, "--> ts %p ++ %d %s\n", ts, ts->nrefs, msg);
66 int rpmtsCloseDB(rpmts ts)
70 if (ts->rdb != NULL) {
71 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
72 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
73 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
74 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
75 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
76 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
77 rc = rpmdbClose(ts->rdb);
83 int rpmtsOpenDB(rpmts ts, int dbmode)
87 if (ts->rdb != NULL && ts->dbmode == dbmode)
90 (void) rpmtsCloseDB(ts);
92 /* XXX there's a potential db lock race here. */
95 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
97 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
99 _("cannot open Packages database in %s\n"), dn);
105 int rpmtsInitDB(rpmts ts, int dbmode)
107 void *lock = rpmtsAcquireLock(ts);
110 rc = rpmdbInit(ts->rootDir, dbmode);
115 int rpmtsGetDBMode(rpmts ts)
121 int rpmtsSetDBMode(rpmts ts, int dbmode)
124 /* mode setting only permitted on non-open db */
125 if (ts != NULL && rpmtsGetRdb(ts) == NULL) {
133 int rpmtsRebuildDB(rpmts ts)
136 void *lock = rpmtsAcquireLock(ts);
137 if (!lock) return -1;
138 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
139 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
141 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
146 int rpmtsVerifyDB(rpmts ts)
148 return rpmdbVerify(ts->rootDir);
151 static int isArch(const char * arch)
153 const char * const * av;
154 static const char * const arches[] = {
155 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", "x86_64", "amd64", "ia32e", "geode",
156 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
157 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
158 "sparc64", "sparc64v", "sun4u",
159 "mips", "mipsel", "IP",
160 "ppc", "ppciseries", "ppcpseries",
161 "ppc64", "ppc64iseries", "ppc64pseries",
165 "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
166 "s390", "i370", "s390x",
172 for (av = arches; *av != NULL; av++) {
173 if (!strcmp(arch, *av))
179 /* keyp might no be defined. */
180 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
181 const void * keyp, size_t keylen)
183 rpmdbMatchIterator mi = NULL;
184 const char * arch = NULL;
188 if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
191 /* Parse out "N(EVR).A" tokens from a label key. */
192 if (rpmtag == RPMDBI_LABEL && keyp != NULL) {
193 const char *se, *s = keyp;
195 size_t slen = strlen(s);
199 tmp = xmalloc(slen+1);
201 while ((c = *s++) != '\0') {
207 /* XXX Fail if nested parens. */
209 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), (const char*)keyp);
212 /* Parse explicit epoch. */
213 for (se = s; *se && risdigit(*se); se++)
216 /* XXX skip explicit epoch's (for now) */
220 /* No Epoch: found. Convert '(' to '-' and chug. */
225 /* XXX Fail if nested parens. */
227 rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), (const char*)keyp);
230 /* Don't copy trailing ')' */
235 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), (const char*)keyp);
241 /* Is this a valid ".arch" suffix? */
242 if (t != NULL && isArch(t+1)) {
248 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
250 /* Verify header signature/digest during retrieve (if not disabled). */
251 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
252 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
254 /* Select specified arch only. */
256 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch);
264 rpmRC rpmtsFindPubkey(rpmts ts)
266 const void * sig = rpmtsSig(ts);
267 pgpDig dig = rpmtsDig(ts);
268 pgpDigParams sigp = rpmtsSignature(ts);
269 pgpDigParams pubp = rpmtsPubkey(ts);
270 rpmRC res = RPMRC_NOKEY;
271 char * pubkeysource = NULL;
274 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
278 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
279 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
280 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
283 /* Lazy free of previous pubkey if pubkey does not match this signature. */
284 if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
286 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
288 ts->pkpkt = _free(ts->pkpkt);
290 memset(ts->pksignid, 0, sizeof(ts->pksignid));
293 /* Try rpmdb keyring lookup. */
294 if (ts->pkpkt == NULL) {
297 rpmdbMatchIterator mi;
300 /* Retrieve the pubkey that matches the signature. */
301 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
302 while ((h = rpmdbNextIterator(mi)) != NULL) {
303 const char ** pubkeys;
307 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (rpm_data_t *)&pubkeys, &pc))
309 hx = rpmdbGetIteratorOffset(mi);
310 ix = rpmdbGetIteratorFileNum(mi);
312 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
314 pubkeys = headerFreeData(pubkeys, pt);
317 mi = rpmdbFreeIterator(mi);
320 rasprintf(&pubkeysource, "h#%d", hx);
322 ts->pkpkt = _free(ts->pkpkt);
327 /* Was a matching pubkey found? */
328 if (ts->pkpkt == NULL || ts->pkpktlen == 0)
331 /* Retrieve parameters from pubkey packet(s). */
332 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
334 /* Do the parameters match the signature? */
335 if (sigp->pubkey_algo == pubp->pubkey_algo
337 && sigp->hash_algo == pubp->hash_algo
339 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
342 /* XXX Verify any pubkey signatures. */
344 /* Pubkey packet looks good, save the signer id. */
345 memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
348 rpmlog(RPMLOG_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
349 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
350 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
351 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
358 pubkeysource = _free(pubkeysource);
359 if (res != RPMRC_OK) {
360 ts->pkpkt = _free(ts->pkpkt);
366 rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
368 static unsigned char zeros[] =
369 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
370 const char * afmt = "%{pubkeys:armor}";
371 const char * group = "Public Keys";
372 const char * license = "pubkey";
373 const char * buildhost = "localhost";
374 rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
377 pgpDigParams pubp = NULL;
386 rpmRC rc = RPMRC_FAIL; /* assume failure */
389 if (pkt == NULL || pktlen == 0)
391 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
394 if ((enc = b64encode(pkt, pktlen, -1)) == NULL)
399 /* Build header elements. */
400 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
403 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
404 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
405 || pubp->userid == NULL)
408 v = pgpHexStr(pubp->signid, sizeof(pubp->signid));
409 r = pgpHexStr(pubp->time, sizeof(pubp->time));
411 rasprintf(&n, "gpg(%s)", v+8);
412 rasprintf(&u, "gpg(%s)", pubp->userid ? pubp->userid : "none");
413 rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);
414 /* Check for pre-existing header. */
416 /* Build pubkey header. */
419 xx = headerAddOrAppendEntry(h, RPMTAG_PUBKEYS,
420 RPM_STRING_ARRAY_TYPE, &enc, 1);
422 d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
426 xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
427 xx = headerAddEntry(h, RPMTAG_VERSION, RPM_STRING_TYPE, v+8, 1);
428 xx = headerAddEntry(h, RPMTAG_RELEASE, RPM_STRING_TYPE, r, 1);
429 xx = headerAddEntry(h, RPMTAG_DESCRIPTION, RPM_STRING_TYPE, d, 1);
430 xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
431 xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
432 xx = headerAddEntry(h, RPMTAG_SUMMARY, RPM_STRING_TYPE, u, 1);
434 xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
436 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
437 RPM_STRING_ARRAY_TYPE, &u, 1);
438 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
439 RPM_STRING_ARRAY_TYPE, &evr, 1);
440 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
441 RPM_INT32_TYPE, &pflags, 1);
443 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
444 RPM_STRING_ARRAY_TYPE, &n, 1);
445 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
446 RPM_STRING_ARRAY_TYPE, &evr, 1);
447 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
448 RPM_INT32_TYPE, &pflags, 1);
450 xx = headerAddEntry(h, RPMTAG_RPMVERSION, RPM_STRING_TYPE, RPMVERSION, 1);
452 /* XXX W2DO: tag value inheirited from parent? */
453 xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
454 { rpm_tid_t tid = rpmtsGetTid(ts);
455 xx = headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &tid, 1);
456 /* XXX W2DO: tag value inheirited from parent? */
457 xx = headerAddEntry(h, RPMTAG_BUILDTIME, RPM_INT32_TYPE, &tid, 1);
461 /* XXX W2DO: tag value inheirited from parent? */
462 xx = headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, fn, 1);
465 /* Add header to database. */
466 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
474 dig = pgpFreeDig(dig);
486 int rpmtsCloseSDB(rpmts ts)
490 if (ts->sdb != NULL) {
491 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
492 rpmdbOp(ts->sdb, RPMDB_OP_DBGET));
493 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
494 rpmdbOp(ts->sdb, RPMDB_OP_DBPUT));
495 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
496 rpmdbOp(ts->sdb, RPMDB_OP_DBDEL));
497 rc = rpmdbClose(ts->sdb);
503 int rpmtsOpenSDB(rpmts ts, int dbmode)
505 static int has_sdbpath = -1;
508 if (ts->sdb != NULL && ts->sdbmode == dbmode)
512 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
514 /* If not configured, don't try to open. */
515 if (has_sdbpath <= 0)
518 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
520 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
522 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
523 rpmlog(RPMLOG_WARNING,
524 _("cannot open Solve database in %s\n"), dn);
527 delMacro(NULL, "_dbpath");
533 * Compare suggested package resolutions (qsort/bsearch).
534 * @param a 1st instance address
535 * @param b 2nd instance address
536 * @return result of comparison
538 static int sugcmp(const void * a, const void * b)
540 const char * astr = *(const char **)a;
541 const char * bstr = *(const char **)b;
542 return strcmp(astr, bstr);
545 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
550 rpmdbMatchIterator mi;
558 int rc = 1; /* assume not found */
561 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
568 if (ts->sdb == NULL) {
569 xx = rpmtsOpenSDB(ts, ts->sdbmode);
573 /* Look for a matching Provides: in suggested universe. */
574 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
576 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
580 while ((h = rpmdbNextIterator(mi)) != NULL) {
586 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
589 /* XXX Prefer the shortest name if given alternatives. */
592 if (headerGetEntry(h, RPMTAG_NAME, NULL, (rpm_data_t *)&hname, NULL)) {
594 hnamelen = strlen(hname);
596 if (bhnamelen > 0 && hnamelen > bhnamelen)
599 /* XXX Prefer the newest build if given alternatives. */
601 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (rpm_data_t *)&ip, NULL))
610 bhnamelen = hnamelen;
612 mi = rpmdbFreeIterator(mi);
614 /* Is there a suggested resolution? */
618 /* Format the suggestion. */
619 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
620 if (qfmt == NULL || *qfmt == '\0')
622 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
626 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
630 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
635 fd = Fopen(str, "r.ufdio");
636 if (fd == NULL || Ferror(fd)) {
637 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
646 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
652 case RPMRC_NOTTRUSTED:
656 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
658 rpmlog(RPMLOG_DEBUG, "Adding: %s\n", str);
660 /* XXX str memory leak */
670 rpmlog(RPMLOG_DEBUG, "Suggesting: %s\n", str);
671 /* If suggestion is already present, don't bother. */
672 if (ts->suggests != NULL && ts->nsuggests > 0) {
673 if (bsearch(&str, ts->suggests, ts->nsuggests,
674 sizeof(*ts->suggests), sugcmp))
678 /* Add a new (unique) suggestion. */
679 ts->suggests = xrealloc(ts->suggests,
680 sizeof(*ts->suggests) * (ts->nsuggests + 2));
681 ts->suggests[ts->nsuggests] = str;
683 ts->suggests[ts->nsuggests] = NULL;
685 if (ts->nsuggests > 1)
686 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
689 /* FIX: ts->suggests[] may be NULL */
693 int rpmtsAvailable(rpmts ts, const rpmds ds)
696 int rc = 1; /* assume not found */
698 if (ts->availablePackages == NULL)
700 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
704 /* XXX no alternatives yet */
705 if (sugkey[0] != NULL) {
706 ts->suggests = xrealloc(ts->suggests,
707 sizeof(*ts->suggests) * (ts->nsuggests + 2));
708 ts->suggests[ts->nsuggests] = sugkey[0];
711 ts->suggests[ts->nsuggests] = NULL;
713 sugkey = _free(sugkey);
714 /* FIX: ts->suggests[] may be NULL */
718 int rpmtsSetSolveCallback(rpmts ts,
719 int (*solve) (rpmts ts, rpmds key, const void * data),
720 const void * solveData)
726 ts->solveData = solveData;
731 void rpmtsPrintSuggests(rpmts ts)
733 if (ts->suggests != NULL && ts->nsuggests > 0) {
735 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
736 for (i = 0; i < ts->nsuggests; i++) {
737 const char * str = ts->suggests[i];
742 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
748 rpmps rpmtsProblems(rpmts ts)
753 ps = rpmpsLink(ts->probs, RPMDBG_M("rpmtsProblems"));
758 void rpmtsCleanProblems(rpmts ts)
760 if (ts && ts->probs) {
761 ts->probs = rpmpsFree(ts->probs);
765 void rpmtsCleanDig(rpmts ts)
767 ts->sig = headerFreeData(ts->sig, ts->sigtype);
768 ts->dig = pgpFreeDig(ts->dig);
771 void rpmtsClean(rpmts ts)
779 /* Clean up after dependency checks. */
781 while ((p = rpmtsiNext(pi, 0)) != NULL)
785 ts->addedPackages = rpmalFree(ts->addedPackages);
786 ts->numAddedPackages = 0;
788 for (i = 0; i < ts->nsuggests; i++) {
789 const char * str = ts->suggests[i];
790 ts->suggests[i] = NULL;
793 ts->suggests = _free(ts->suggests);
796 rpmtsCleanProblems(ts);
801 void rpmtsEmpty(rpmts ts)
811 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
812 ts->order[oc] = rpmteFree(ts->order[oc]);
820 ts->numRemovedPackages = 0;
824 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
826 static const unsigned int scale = (1000 * 1000);
827 if (op != NULL && op->count > 0)
828 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
830 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
831 op->usecs/scale, op->usecs%scale);
834 static void rpmtsPrintStats(rpmts ts)
836 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
838 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
839 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
840 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
841 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
842 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
843 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
844 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
845 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
846 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
847 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
848 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
849 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
850 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
851 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
852 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
853 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
856 rpmts rpmtsFree(rpmts ts)
862 return rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
866 (void) rpmtsCloseDB(ts);
868 (void) rpmtsCloseSDB(ts);
870 ts->removedPackages = _free(ts->removedPackages);
872 ts->availablePackages = rpmalFree(ts->availablePackages);
873 ts->numAvailablePackages = 0;
875 ts->dsi = _free(ts->dsi);
877 if (ts->scriptFd != NULL) {
878 ts->scriptFd = fdFree(ts->scriptFd, RPMDBG_M("rpmtsFree"));
881 ts->rootDir = _free(ts->rootDir);
882 ts->currDir = _free(ts->currDir);
884 ts->order = _free(ts->order);
885 ts->orderAlloced = 0;
887 if (ts->pkpkt != NULL)
888 ts->pkpkt = _free(ts->pkpkt);
890 memset(ts->pksignid, 0, sizeof(ts->pksignid));
895 (void) rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
902 rpmVSFlags rpmtsVSFlags(rpmts ts)
904 rpmVSFlags vsflags = 0;
906 vsflags = ts->vsflags;
910 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
912 rpmVSFlags ovsflags = 0;
914 ovsflags = ts->vsflags;
915 ts->vsflags = vsflags;
920 int rpmtsUnorderedSuccessors(rpmts ts, int first)
922 int unorderedSuccessors = 0;
924 unorderedSuccessors = ts->unorderedSuccessors;
926 ts->unorderedSuccessors = first;
928 return unorderedSuccessors;
931 const char * rpmtsRootDir(rpmts ts)
933 const char * rootDir = NULL;
935 if (ts != NULL && ts->rootDir != NULL) {
936 urltype ut = urlPath(ts->rootDir, &rootDir);
941 /* XXX these shouldn't be allowed as rootdir! */
955 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
960 ts->rootDir = _free(ts->rootDir);
962 if (rootDir == NULL) {
964 ts->rootDir = xstrdup("");
968 rootLen = strlen(rootDir);
970 /* Make sure that rootDir has trailing / */
971 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
972 char * t = alloca(rootLen + 2);
974 (void) stpcpy( stpcpy(t, rootDir), "/");
977 ts->rootDir = xstrdup(rootDir);
981 const char * rpmtsCurrDir(rpmts ts)
983 const char * currDir = NULL;
985 currDir = ts->currDir;
990 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
993 ts->currDir = _free(ts->currDir);
995 ts->currDir = xstrdup(currDir);
999 FD_t rpmtsScriptFd(rpmts ts)
1001 FD_t scriptFd = NULL;
1003 scriptFd = ts->scriptFd;
1008 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1012 if (ts->scriptFd != NULL) {
1013 ts->scriptFd = fdFree(ts->scriptFd,
1014 RPMDBG_M("rpmtsSetScriptFd"));
1015 ts->scriptFd = NULL;
1017 if (scriptFd != NULL)
1018 ts->scriptFd = fdLink((void *)scriptFd,
1019 RPMDBG_M("rpmtsSetScriptFd"));
1023 int rpmtsSELinuxEnabled(rpmts ts)
1025 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1028 int rpmtsChrootDone(rpmts ts)
1030 return (ts != NULL ? ts->chrootDone : 0);
1033 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1035 int ochrootDone = 0;
1037 ochrootDone = ts->chrootDone;
1038 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1039 ts->chrootDone = chrootDone;
1044 rpm_tid_t rpmtsGetTid(rpmts ts)
1046 rpm_tid_t tid = -1; /* XXX -1 is time(2) error return. */
1053 rpm_tid_t rpmtsSetTid(rpmts ts, rpm_tid_t tid)
1055 rpm_tid_t otid = -1; /* XXX -1 is time(2) error return. */
1063 rpmSigTag rpmtsSigtag(const rpmts ts)
1065 rpmSigTag sigtag = 0;
1067 sigtag = ts->sigtag;
1071 rpmTagType rpmtsSigtype(const rpmts ts)
1073 rpmTagType sigtype = 0;
1075 sigtype = ts->sigtype;
1079 rpm_constdata_t rpmtsSig(const rpmts ts)
1081 rpm_constdata_t sig = NULL;
1087 size_t rpmtsSiglen(const rpmts ts)
1091 siglen = ts->siglen;
1095 int rpmtsSetSig(rpmts ts, rpmSigTag sigtag, rpmTagType sigtype,
1096 rpm_data_t sig, size_t siglen)
1099 if (ts->sig && ts->sigtype)
1100 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1101 ts->sigtag = sigtag;
1102 ts->sigtype = (sig ? sigtype : 0);
1104 ts->siglen = siglen;
1109 pgpDig rpmtsDig(rpmts ts)
1111 /* FIX: hide lazy malloc for now */
1112 if (ts->dig == NULL)
1113 ts->dig = pgpNewDig();
1114 if (ts->dig == NULL)
1119 pgpDigParams rpmtsSignature(const rpmts ts)
1121 pgpDig dig = rpmtsDig(ts);
1122 if (dig == NULL) return NULL;
1123 return &dig->signature;
1126 pgpDigParams rpmtsPubkey(const rpmts ts)
1128 pgpDig dig = rpmtsDig(ts);
1129 if (dig == NULL) return NULL;
1130 return &dig->pubkey;
1133 rpmdb rpmtsGetRdb(rpmts ts)
1142 int rpmtsInitDSI(const rpmts ts)
1144 rpmDiskSpaceInfo dsi;
1149 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1152 rpmlog(RPMLOG_DEBUG, "mounted filesystems:\n");
1153 rpmlog(RPMLOG_DEBUG,
1154 " i dev bsize bavail iavail mount point\n");
1156 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1157 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1160 /* Get available space on mounted file systems. */
1162 ts->dsi = _free(ts->dsi);
1163 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1168 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1169 #if STATFS_IN_SYS_STATVFS
1171 memset(&sfb, 0, sizeof(sfb));
1172 rc = statvfs(ts->filesystems[i], &sfb);
1175 memset(&sfb, 0, sizeof(sfb));
1177 /* This platform has the 4-argument version of the statfs call. The last two
1178 * should be the size of struct statfs and 0, respectively. The 0 is the
1179 * filesystem type, and is always 0 when statfs is called on a mounted
1180 * filesystem, as we're doing.
1182 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1184 rc = statfs(ts->filesystems[i], &sfb);
1190 rc = stat(ts->filesystems[i], &sb);
1193 dsi->dev = sb.st_dev;
1195 dsi->bsize = sfb.f_bsize;
1198 #ifdef STATFS_HAS_F_BAVAIL
1199 dsi->bavail = sfb.f_bavail;
1201 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1202 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1203 * it's about all we can do.
1205 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1207 /* XXX Avoid FAT and other file systems that have not inodes. */
1208 /* XXX assigning negative value to unsigned type */
1209 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1211 rpmlog(RPMLOG_DEBUG, "%5d 0x%08x %8u %12ld %12ld %s\n",
1212 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1213 (signed long) dsi->bavail, (signed long) dsi->iavail,
1214 ts->filesystems[i]);
1219 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1220 rpm_off_t fileSize, rpm_off_t prevSize, rpm_off_t fixupSize,
1221 rpmFileAction action)
1223 rpmDiskSpaceInfo dsi;
1228 while (dsi->bsize && dsi->dev != dev)
1230 if (dsi->bsize == 0)
1236 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1243 dsi->bneeded += bneeded;
1247 * FIXME: If two packages share a file (same md5sum), and
1248 * that file is being replaced on disk, will dsi->bneeded get
1249 * adjusted twice? Quite probably!
1252 dsi->bneeded += bneeded;
1253 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1258 dsi->bneeded -= bneeded;
1266 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1269 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1271 rpmDiskSpaceInfo dsi;
1276 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1282 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1286 ps = rpmtsProblems(ts);
1287 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1289 if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1290 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1291 rpmteNEVRA(te), rpmteKey(te),
1292 ts->filesystems[i], NULL, NULL,
1293 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1296 if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1297 rpmpsAppend(ps, RPMPROB_DISKNODES,
1298 rpmteNEVRA(te), rpmteKey(te),
1299 ts->filesystems[i], NULL, NULL,
1300 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1306 void * rpmtsNotify(rpmts ts, rpmte te,
1307 rpmCallbackType what, rpm_off_t amount, rpm_off_t total)
1310 if (ts && ts->notify && te) {
1311 Header h = rpmteHeader(te);
1312 assert(!(rpmteType(te) == TR_ADDED && h == NULL));
1315 ptr = ts->notify(h, what, amount, total,
1316 rpmteKey(te), ts->notifyData);
1317 headerUnlink(h); /* undo rpmteHeader() ref */
1322 int rpmtsNElements(rpmts ts)
1325 if (ts != NULL && ts->order != NULL) {
1326 nelements = ts->orderCount;
1331 rpmte rpmtsElement(rpmts ts, int ix)
1334 if (ts != NULL && ts->order != NULL) {
1335 if (ix >= 0 && ix < ts->orderCount)
1341 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1343 return (ts != NULL ? ts->ignoreSet : 0);
1346 rpmtransFlags rpmtsFlags(rpmts ts)
1348 return (ts != NULL ? ts->transFlags : 0);
1351 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1353 rpmtransFlags otransFlags = 0;
1355 otransFlags = ts->transFlags;
1356 ts->transFlags = transFlags;
1361 rpmSpec rpmtsSpec(rpmts ts)
1366 rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
1368 rpmSpec ospec = ts->spec;
1373 rpmte rpmtsRelocateElement(rpmts ts)
1375 return ts->relocateElement;
1378 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1380 rpmte orelocateElement = ts->relocateElement;
1381 ts->relocateElement = relocateElement;
1382 return orelocateElement;
1385 rpm_color_t rpmtsColor(rpmts ts)
1387 return (ts != NULL ? ts->color : 0);
1390 rpm_color_t rpmtsSetColor(rpmts ts, rpm_color_t color)
1392 rpm_color_t ocolor = 0;
1400 rpm_color_t rpmtsPrefColor(rpmts ts)
1402 return (ts != NULL ? ts->prefcolor : 0);
1405 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1409 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1414 int rpmtsSetNotifyCallback(rpmts ts,
1415 rpmCallbackFunction notify, rpmCallbackData notifyData)
1418 ts->notify = notify;
1419 ts->notifyData = notifyData;
1424 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1428 if (nep) *nep = ts->orderCount;
1433 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1434 pi = rpmtsiInit(ts);
1435 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1436 switch (rpmteType(p)) {
1447 pi = rpmtsiFree(pi);
1452 rpmts rpmtsCreate(void)
1456 ts = xcalloc(1, sizeof(*ts));
1457 memset(&ts->ops, 0, sizeof(ts->ops));
1458 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1459 ts->filesystemCount = 0;
1460 ts->filesystems = NULL;
1463 ts->solve = rpmtsSolve;
1464 ts->solveData = NULL;
1466 ts->suggests = NULL;
1468 ts->sdbmode = O_RDONLY;
1471 ts->dbmode = O_RDONLY;
1473 ts->scriptFd = NULL;
1474 ts->tid = (rpm_tid_t) time(NULL);
1477 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1478 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1480 ts->numRemovedPackages = 0;
1481 ts->allocedRemovedPackages = ts->delta;
1482 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1483 sizeof(*ts->removedPackages));
1489 ts->selinuxEnabled = is_selinux_enabled();
1491 ts->numAddedPackages = 0;
1492 ts->addedPackages = NULL;
1494 ts->numAvailablePackages = 0;
1495 ts->availablePackages = NULL;
1497 ts->orderAlloced = 0;
1508 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1513 return rpmtsLink(ts, RPMDBG_M("tsCreate"));