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>
17 #include <rpm/rpmal.h>
18 #include <rpm/rpmds.h>
19 #include <rpm/rpmfi.h>
20 #include "lib/rpmlock.h"
21 #include <rpm/rpmlog.h>
23 #include <rpm/rpmte.h>
25 #include "lib/rpmts_internal.h"
27 /* XXX FIXME: merge with existing (broken?) tests in system.h */
28 /* portability fiddles */
29 #if STATFS_IN_SYS_STATVFS
30 #include <sys/statvfs.h>
33 # if STATFS_IN_SYS_VFS
36 # if STATFS_IN_SYS_MOUNT
37 # include <sys/mount.h>
39 # if STATFS_IN_SYS_STATFS
40 # include <sys/statfs.h>
52 rpmts rpmtsUnlink(rpmts ts, const char * msg)
55 fprintf(stderr, "--> ts %p -- %d %s\n", ts, ts->nrefs, msg);
60 rpmts rpmtsLink(rpmts ts, const char * msg)
64 fprintf(stderr, "--> ts %p ++ %d %s\n", ts, ts->nrefs, msg);
68 int rpmtsCloseDB(rpmts ts)
72 if (ts->rdb != NULL) {
73 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
74 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
75 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
76 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
77 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
78 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
79 rc = rpmdbClose(ts->rdb);
85 int rpmtsOpenDB(rpmts ts, int dbmode)
89 if (ts->rdb != NULL && ts->dbmode == dbmode)
92 (void) rpmtsCloseDB(ts);
94 /* XXX there's a potential db lock race here. */
97 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
99 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
101 _("cannot open Packages database in %s\n"), dn);
107 int rpmtsInitDB(rpmts ts, int dbmode)
109 void *lock = rpmtsAcquireLock(ts);
112 rc = rpmdbInit(ts->rootDir, dbmode);
117 int rpmtsGetDBMode(rpmts ts)
123 int rpmtsSetDBMode(rpmts ts, int dbmode)
126 /* mode setting only permitted on non-open db */
127 if (ts != NULL && rpmtsGetRdb(ts) == NULL) {
135 int rpmtsRebuildDB(rpmts ts)
138 void *lock = rpmtsAcquireLock(ts);
139 if (!lock) return -1;
140 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
141 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
143 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
148 int rpmtsVerifyDB(rpmts ts)
150 return rpmdbVerify(ts->rootDir);
153 static int isArch(const char * arch)
156 static const char *arches[] = {
157 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", "x86_64", "amd64", "ia32e", "geode",
158 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
159 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
160 "sparc64", "sparc64v", "sun4u",
161 "mips", "mipsel", "IP",
162 "ppc", "ppciseries", "ppcpseries",
163 "ppc64", "ppc64iseries", "ppc64pseries",
167 "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
168 "s390", "i370", "s390x",
174 for (av = arches; *av != NULL; av++) {
175 if (!strcmp(arch, *av))
181 /* keyp might no be defined. */
182 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpm_tag_t rpmtag,
183 const void * keyp, size_t keylen)
185 rpmdbMatchIterator mi;
186 const char * arch = NULL;
189 if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
192 /* Parse out "N(EVR).A" tokens from a label key. */
193 if (rpmtag == RPMDBI_LABEL && keyp != NULL) {
194 const char * s = keyp;
196 size_t slen = strlen(s);
197 char *t = alloca(slen+1);
202 while ((c = *s++) != '\0') {
208 /* XXX Fail if nested parens. */
210 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), keyp);
213 /* Parse explicit epoch. */
214 for (se = s; *se && xisdigit(*se); se++)
217 /* XXX skip explicit epoch's (for now) */
221 /* No Epoch: found. Convert '(' to '-' and chug. */
226 /* XXX Fail if nested parens. */
228 rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), keyp);
231 /* Don't copy trailing ')' */
236 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), keyp);
242 /* Is this a valid ".arch" suffix? */
243 if (t != NULL && isArch(t+1)) {
249 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
251 /* Verify header signature/digest during retrieve (if not disabled). */
252 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
253 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
255 /* Select specified arch only. */
257 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch);
261 rpmRC rpmtsFindPubkey(rpmts ts)
263 const void * sig = rpmtsSig(ts);
264 pgpDig dig = rpmtsDig(ts);
265 pgpDigParams sigp = rpmtsSignature(ts);
266 pgpDigParams pubp = rpmtsPubkey(ts);
267 rpmRC res = RPMRC_NOKEY;
268 char * pubkeysource = NULL;
271 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
275 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
276 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
277 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
280 /* Lazy free of previous pubkey if pubkey does not match this signature. */
281 if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
283 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
285 ts->pkpkt = _free(ts->pkpkt);
287 memset(ts->pksignid, 0, sizeof(ts->pksignid));
290 /* Try rpmdb keyring lookup. */
291 if (ts->pkpkt == NULL) {
294 rpmdbMatchIterator mi;
297 /* Retrieve the pubkey that matches the signature. */
298 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
299 while ((h = rpmdbNextIterator(mi)) != NULL) {
300 const char ** pubkeys;
304 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (rpm_data_t *)&pubkeys, &pc))
306 hx = rpmdbGetIteratorOffset(mi);
307 ix = rpmdbGetIteratorFileNum(mi);
309 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
311 pubkeys = headerFreeData(pubkeys, pt);
314 mi = rpmdbFreeIterator(mi);
318 sprintf(hnum, "h#%d", hx);
319 pubkeysource = xstrdup(hnum);
321 ts->pkpkt = _free(ts->pkpkt);
326 /* Try keyserver lookup. */
327 if (ts->pkpkt == NULL) {
328 char * fn = rpmExpand("%{_hkp_keyserver_query}",
329 pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
332 if (fn && *fn != '%') {
333 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
337 ts->pkpkt = _free(ts->pkpkt);
340 /* Save new pubkey in local ts keyring for delayed import. */
341 pubkeysource = xstrdup("keyserver");
346 /* Try filename from macro lookup. */
347 if (ts->pkpkt == NULL) {
348 const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
351 if (fn && *fn != '%')
352 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
355 ts->pkpkt = _free(ts->pkpkt);
358 pubkeysource = xstrdup("macro");
363 /* Was a matching pubkey found? */
364 if (ts->pkpkt == NULL || ts->pkpktlen == 0)
367 /* Retrieve parameters from pubkey packet(s). */
368 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
370 /* Do the parameters match the signature? */
371 if (sigp->pubkey_algo == pubp->pubkey_algo
373 && sigp->hash_algo == pubp->hash_algo
375 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
378 /* XXX Verify any pubkey signatures. */
380 /* Pubkey packet looks good, save the signer id. */
381 memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
384 rpmlog(RPMLOG_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
385 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
386 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
387 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
394 pubkeysource = _free(pubkeysource);
395 if (res != RPMRC_OK) {
396 ts->pkpkt = _free(ts->pkpkt);
402 rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
404 static unsigned char zeros[] =
405 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
406 const char * afmt = "%{pubkeys:armor}";
407 const char * group = "Public Keys";
408 const char * license = "pubkey";
409 const char * buildhost = "localhost";
410 int32_t pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
413 pgpDigParams pubp = NULL;
422 rpmRC rc = RPMRC_FAIL; /* assume failure */
426 if (pkt == NULL || pktlen == 0)
428 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
431 if ((enc = b64encode(pkt, pktlen, -1)) == NULL)
436 /* Build header elements. */
437 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
440 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
441 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
442 || pubp->userid == NULL)
445 v = t = xmalloc(16+1);
446 t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
448 r = t = xmalloc(8+1);
449 t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
451 n = t = xmalloc(sizeof("gpg()")+8);
452 t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
454 /* FIX: pubp->userid may be NULL */
455 u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
456 t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
458 evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
459 t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
460 t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
462 /* Check for pre-existing header. */
464 /* Build pubkey header. */
467 xx = headerAddOrAppendEntry(h, RPMTAG_PUBKEYS,
468 RPM_STRING_ARRAY_TYPE, &enc, 1);
470 d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
474 xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
475 xx = headerAddEntry(h, RPMTAG_VERSION, RPM_STRING_TYPE, v+8, 1);
476 xx = headerAddEntry(h, RPMTAG_RELEASE, RPM_STRING_TYPE, r, 1);
477 xx = headerAddEntry(h, RPMTAG_DESCRIPTION, RPM_STRING_TYPE, d, 1);
478 xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
479 xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
480 xx = headerAddEntry(h, RPMTAG_SUMMARY, RPM_STRING_TYPE, u, 1);
482 xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
484 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
485 RPM_STRING_ARRAY_TYPE, &u, 1);
486 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
487 RPM_STRING_ARRAY_TYPE, &evr, 1);
488 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
489 RPM_INT32_TYPE, &pflags, 1);
491 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
492 RPM_STRING_ARRAY_TYPE, &n, 1);
493 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
494 RPM_STRING_ARRAY_TYPE, &evr, 1);
495 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
496 RPM_INT32_TYPE, &pflags, 1);
498 xx = headerAddEntry(h, RPMTAG_RPMVERSION, RPM_STRING_TYPE, RPMVERSION, 1);
500 /* XXX W2DO: tag value inheirited from parent? */
501 xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
502 { int32_t tid = rpmtsGetTid(ts);
503 xx = headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &tid, 1);
504 /* XXX W2DO: tag value inheirited from parent? */
505 xx = headerAddEntry(h, RPMTAG_BUILDTIME, RPM_INT32_TYPE, &tid, 1);
509 /* XXX W2DO: tag value inheirited from parent? */
510 xx = headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, fn, 1);
513 /* Add header to database. */
514 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
522 dig = pgpFreeDig(dig);
534 int rpmtsCloseSDB(rpmts ts)
538 if (ts->sdb != NULL) {
539 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
540 rpmdbOp(ts->sdb, RPMDB_OP_DBGET));
541 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
542 rpmdbOp(ts->sdb, RPMDB_OP_DBPUT));
543 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
544 rpmdbOp(ts->sdb, RPMDB_OP_DBDEL));
545 rc = rpmdbClose(ts->sdb);
551 int rpmtsOpenSDB(rpmts ts, int dbmode)
553 static int has_sdbpath = -1;
556 if (ts->sdb != NULL && ts->sdbmode == dbmode)
560 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
562 /* If not configured, don't try to open. */
563 if (has_sdbpath <= 0)
566 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
568 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
570 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
571 rpmlog(RPMLOG_WARNING,
572 _("cannot open Solve database in %s\n"), dn);
575 delMacro(NULL, "_dbpath");
581 * Compare suggested package resolutions (qsort/bsearch).
582 * @param a 1st instance address
583 * @param b 2nd instance address
584 * @return result of comparison
586 static int sugcmp(const void * a, const void * b)
588 const char * astr = *(const char **)a;
589 const char * bstr = *(const char **)b;
590 return strcmp(astr, bstr);
593 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
598 rpmdbMatchIterator mi;
606 int rc = 1; /* assume not found */
609 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
616 if (ts->sdb == NULL) {
617 xx = rpmtsOpenSDB(ts, ts->sdbmode);
621 /* Look for a matching Provides: in suggested universe. */
622 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
624 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
628 while ((h = rpmdbNextIterator(mi)) != NULL) {
634 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
637 /* XXX Prefer the shortest name if given alternatives. */
640 if (headerGetEntry(h, RPMTAG_NAME, NULL, (rpm_data_t *)&hname, NULL)) {
642 hnamelen = strlen(hname);
644 if (bhnamelen > 0 && hnamelen > bhnamelen)
647 /* XXX Prefer the newest build if given alternatives. */
649 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (rpm_data_t *)&ip, NULL))
658 bhnamelen = hnamelen;
660 mi = rpmdbFreeIterator(mi);
662 /* Is there a suggested resolution? */
666 /* Format the suggestion. */
667 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
668 if (qfmt == NULL || *qfmt == '\0')
670 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
674 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
678 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
683 fd = Fopen(str, "r.ufdio");
684 if (fd == NULL || Ferror(fd)) {
685 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
694 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
700 case RPMRC_NOTTRUSTED:
704 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
706 rpmlog(RPMLOG_DEBUG, _("Adding: %s\n"), str);
708 /* XXX str memory leak */
718 rpmlog(RPMLOG_DEBUG, _("Suggesting: %s\n"), str);
719 /* If suggestion is already present, don't bother. */
720 if (ts->suggests != NULL && ts->nsuggests > 0) {
721 if (bsearch(&str, ts->suggests, ts->nsuggests,
722 sizeof(*ts->suggests), sugcmp))
726 /* Add a new (unique) suggestion. */
727 ts->suggests = xrealloc(ts->suggests,
728 sizeof(*ts->suggests) * (ts->nsuggests + 2));
729 ts->suggests[ts->nsuggests] = str;
731 ts->suggests[ts->nsuggests] = NULL;
733 if (ts->nsuggests > 1)
734 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
737 /* FIX: ts->suggests[] may be NULL */
741 int rpmtsAvailable(rpmts ts, const rpmds ds)
744 int rc = 1; /* assume not found */
746 if (ts->availablePackages == NULL)
748 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
752 /* XXX no alternatives yet */
753 if (sugkey[0] != NULL) {
754 ts->suggests = xrealloc(ts->suggests,
755 sizeof(*ts->suggests) * (ts->nsuggests + 2));
756 ts->suggests[ts->nsuggests] = sugkey[0];
759 ts->suggests[ts->nsuggests] = NULL;
761 sugkey = _free(sugkey);
762 /* FIX: ts->suggests[] may be NULL */
766 int rpmtsSetSolveCallback(rpmts ts,
767 int (*solve) (rpmts ts, rpmds key, const void * data),
768 const void * solveData)
774 ts->solveData = solveData;
779 void rpmtsPrintSuggests(rpmts ts)
781 if (ts->suggests != NULL && ts->nsuggests > 0) {
783 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
784 for (i = 0; i < ts->nsuggests; i++) {
785 const char * str = ts->suggests[i];
790 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
796 rpmps rpmtsProblems(rpmts ts)
801 ps = rpmpsLink(ts->probs, RPMDBG_M("rpmtsProblems"));
806 void rpmtsCleanProblems(rpmts ts)
808 if (ts && ts->probs) {
809 ts->probs = rpmpsFree(ts->probs);
813 void rpmtsCleanDig(rpmts ts)
815 ts->sig = headerFreeData(ts->sig, ts->sigtype);
816 ts->dig = pgpFreeDig(ts->dig);
819 void rpmtsClean(rpmts ts)
827 /* Clean up after dependency checks. */
829 while ((p = rpmtsiNext(pi, 0)) != NULL)
833 ts->addedPackages = rpmalFree(ts->addedPackages);
834 ts->numAddedPackages = 0;
836 for (i = 0; i < ts->nsuggests; i++) {
837 const char * str = ts->suggests[i];
838 ts->suggests[i] = NULL;
841 ts->suggests = _free(ts->suggests);
844 rpmtsCleanProblems(ts);
849 void rpmtsEmpty(rpmts ts)
859 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
860 ts->order[oc] = rpmteFree(ts->order[oc]);
868 ts->numRemovedPackages = 0;
872 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
874 static unsigned int scale = (1000 * 1000);
875 if (op != NULL && op->count > 0)
876 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
878 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
879 op->usecs/scale, op->usecs%scale);
882 static void rpmtsPrintStats(rpmts ts)
884 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
886 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
887 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
888 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
889 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
890 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
891 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
892 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
893 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
894 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
895 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
896 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
897 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
898 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
899 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
900 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
901 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
902 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
905 rpmts rpmtsFree(rpmts ts)
911 return rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
915 (void) rpmtsCloseDB(ts);
917 (void) rpmtsCloseSDB(ts);
919 ts->removedPackages = _free(ts->removedPackages);
921 ts->availablePackages = rpmalFree(ts->availablePackages);
922 ts->numAvailablePackages = 0;
924 ts->dsi = _free(ts->dsi);
926 if (ts->scriptFd != NULL) {
927 ts->scriptFd = fdFree(ts->scriptFd, RPMDBG_M("rpmtsFree"));
930 ts->rootDir = _free(ts->rootDir);
931 ts->currDir = _free(ts->currDir);
933 ts->order = _free(ts->order);
934 ts->orderAlloced = 0;
936 if (ts->pkpkt != NULL)
937 ts->pkpkt = _free(ts->pkpkt);
939 memset(ts->pksignid, 0, sizeof(ts->pksignid));
944 /* Free up the memory used by the rpmtsScore */
945 ts->score = rpmtsScoreFree(ts->score);
947 (void) rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
954 rpmVSFlags rpmtsVSFlags(rpmts ts)
956 rpmVSFlags vsflags = 0;
958 vsflags = ts->vsflags;
962 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
964 rpmVSFlags ovsflags = 0;
966 ovsflags = ts->vsflags;
967 ts->vsflags = vsflags;
973 * This allows us to mark transactions as being of a certain type.
974 * The three types are:
978 * RPM_TRANS_AUTOROLLBACK
980 * ROLLBACK and AUTOROLLBACK transactions should always be ran as
981 * a best effort. In particular this is important to the autorollback
982 * feature to avoid rolling back a rollback (otherwise known as
983 * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
984 * counts passed to scriptlets to be altered.
986 void rpmtsSetType(rpmts ts, rpmtsType type)
993 /* Let them know what type of transaction we are */
994 rpmtsType rpmtsGetType(rpmts ts)
1002 int rpmtsUnorderedSuccessors(rpmts ts, int first)
1004 int unorderedSuccessors = 0;
1006 unorderedSuccessors = ts->unorderedSuccessors;
1008 ts->unorderedSuccessors = first;
1010 return unorderedSuccessors;
1013 const char * rpmtsRootDir(rpmts ts)
1015 const char * rootDir = NULL;
1017 if (ts != NULL && ts->rootDir != NULL) {
1018 urltype ut = urlPath(ts->rootDir, &rootDir);
1020 case URL_IS_UNKNOWN:
1023 /* XXX these shouldn't be allowed as rootdir! */
1037 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
1042 ts->rootDir = _free(ts->rootDir);
1044 if (rootDir == NULL) {
1046 ts->rootDir = xstrdup("");
1050 rootLen = strlen(rootDir);
1052 /* Make sure that rootDir has trailing / */
1053 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
1054 char * t = alloca(rootLen + 2);
1056 (void) stpcpy( stpcpy(t, rootDir), "/");
1059 ts->rootDir = xstrdup(rootDir);
1063 const char * rpmtsCurrDir(rpmts ts)
1065 const char * currDir = NULL;
1067 currDir = ts->currDir;
1072 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
1075 ts->currDir = _free(ts->currDir);
1077 ts->currDir = xstrdup(currDir);
1081 FD_t rpmtsScriptFd(rpmts ts)
1083 FD_t scriptFd = NULL;
1085 scriptFd = ts->scriptFd;
1090 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1094 if (ts->scriptFd != NULL) {
1095 ts->scriptFd = fdFree(ts->scriptFd,
1096 RPMDBG_M("rpmtsSetScriptFd"));
1097 ts->scriptFd = NULL;
1099 if (scriptFd != NULL)
1100 ts->scriptFd = fdLink((void *)scriptFd,
1101 RPMDBG_M("rpmtsSetScriptFd"));
1105 int rpmtsSELinuxEnabled(rpmts ts)
1107 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1110 int rpmtsChrootDone(rpmts ts)
1112 return (ts != NULL ? ts->chrootDone : 0);
1115 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1117 int ochrootDone = 0;
1119 ochrootDone = ts->chrootDone;
1120 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1121 ts->chrootDone = chrootDone;
1126 int32_t rpmtsGetTid(rpmts ts)
1128 int32_t tid = -1; /* XXX -1 is time(2) error return. */
1135 int32_t rpmtsSetTid(rpmts ts, int32_t tid)
1137 int32_t otid = -1; /* XXX -1 is time(2) error return. */
1145 rpm_tag_t rpmtsSigtag(const rpmts ts)
1147 rpm_tag_t sigtag = 0;
1149 sigtag = ts->sigtag;
1153 rpm_tagtype_t rpmtsSigtype(const rpmts ts)
1155 rpm_tagtype_t sigtype = 0;
1157 sigtype = ts->sigtype;
1161 rpm_constdata_t rpmtsSig(const rpmts ts)
1163 rpm_constdata_t sig = NULL;
1169 size_t rpmtsSiglen(const rpmts ts)
1173 siglen = ts->siglen;
1177 int rpmtsSetSig(rpmts ts, rpm_tag_t sigtag, rpm_tagtype_t sigtype,
1178 rpm_data_t sig, size_t siglen)
1181 if (ts->sig && ts->sigtype)
1182 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1183 ts->sigtag = sigtag;
1184 ts->sigtype = (sig ? sigtype : 0);
1186 ts->siglen = siglen;
1191 pgpDig rpmtsDig(rpmts ts)
1193 /* FIX: hide lazy malloc for now */
1194 if (ts->dig == NULL)
1195 ts->dig = pgpNewDig();
1196 if (ts->dig == NULL)
1201 pgpDigParams rpmtsSignature(const rpmts ts)
1203 pgpDig dig = rpmtsDig(ts);
1204 if (dig == NULL) return NULL;
1205 return &dig->signature;
1208 pgpDigParams rpmtsPubkey(const rpmts ts)
1210 pgpDig dig = rpmtsDig(ts);
1211 if (dig == NULL) return NULL;
1212 return &dig->pubkey;
1215 rpmdb rpmtsGetRdb(rpmts ts)
1224 int rpmtsInitDSI(const rpmts ts)
1226 rpmDiskSpaceInfo dsi;
1231 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1234 rpmlog(RPMLOG_DEBUG, _("mounted filesystems:\n"));
1235 rpmlog(RPMLOG_DEBUG,
1236 _(" i dev bsize bavail iavail mount point\n"));
1238 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1239 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1242 /* Get available space on mounted file systems. */
1244 ts->dsi = _free(ts->dsi);
1245 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1250 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1251 #if STATFS_IN_SYS_STATVFS
1253 memset(&sfb, 0, sizeof(sfb));
1254 rc = statvfs(ts->filesystems[i], &sfb);
1257 memset(&sfb, 0, sizeof(sfb));
1259 /* This platform has the 4-argument version of the statfs call. The last two
1260 * should be the size of struct statfs and 0, respectively. The 0 is the
1261 * filesystem type, and is always 0 when statfs is called on a mounted
1262 * filesystem, as we're doing.
1264 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1266 rc = statfs(ts->filesystems[i], &sfb);
1272 rc = stat(ts->filesystems[i], &sb);
1275 dsi->dev = sb.st_dev;
1277 dsi->bsize = sfb.f_bsize;
1280 #ifdef STATFS_HAS_F_BAVAIL
1281 dsi->bavail = sfb.f_bavail;
1283 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1284 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1285 * it's about all we can do.
1287 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1289 /* XXX Avoid FAT and other file systems that have not inodes. */
1290 /* XXX assigning negative value to unsigned type */
1291 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1293 rpmlog(RPMLOG_DEBUG, _("%5d 0x%08x %8u %12ld %12ld %s\n"),
1294 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1295 (signed long) dsi->bavail, (signed long) dsi->iavail,
1296 ts->filesystems[i]);
1301 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1302 uint32_t fileSize, uint32_t prevSize, uint32_t fixupSize,
1303 rpmFileAction action)
1305 rpmDiskSpaceInfo dsi;
1310 while (dsi->bsize && dsi->dev != dev)
1312 if (dsi->bsize == 0)
1318 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1325 dsi->bneeded += bneeded;
1329 * FIXME: If two packages share a file (same md5sum), and
1330 * that file is being replaced on disk, will dsi->bneeded get
1331 * adjusted twice? Quite probably!
1334 dsi->bneeded += bneeded;
1335 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1340 dsi->bneeded -= bneeded;
1348 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1351 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1353 rpmDiskSpaceInfo dsi;
1358 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1364 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1368 ps = rpmtsProblems(ts);
1369 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1371 if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1372 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1373 rpmteNEVRA(te), rpmteKey(te),
1374 ts->filesystems[i], NULL, NULL,
1375 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1378 if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1379 rpmpsAppend(ps, RPMPROB_DISKNODES,
1380 rpmteNEVRA(te), rpmteKey(te),
1381 ts->filesystems[i], NULL, NULL,
1382 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1388 void * rpmtsNotify(rpmts ts, rpmte te,
1389 rpmCallbackType what, unsigned long amount, unsigned long total)
1392 if (ts && ts->notify && te) {
1393 Header h = rpmteHeader(te);
1394 assert(!(rpmteType(te) == TR_ADDED && h == NULL));
1397 ptr = ts->notify(h, what, amount, total,
1398 rpmteKey(te), ts->notifyData);
1399 headerUnlink(h); /* undo rpmteHeader() ref */
1404 int rpmtsNElements(rpmts ts)
1407 if (ts != NULL && ts->order != NULL) {
1408 nelements = ts->orderCount;
1413 rpmte rpmtsElement(rpmts ts, int ix)
1416 if (ts != NULL && ts->order != NULL) {
1417 if (ix >= 0 && ix < ts->orderCount)
1423 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1425 return (ts != NULL ? ts->ignoreSet : 0);
1428 rpmtransFlags rpmtsFlags(rpmts ts)
1430 return (ts != NULL ? ts->transFlags : 0);
1433 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1435 rpmtransFlags otransFlags = 0;
1437 otransFlags = ts->transFlags;
1438 ts->transFlags = transFlags;
1443 rpmSpec rpmtsSpec(rpmts ts)
1448 rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
1450 rpmSpec ospec = ts->spec;
1455 rpmte rpmtsRelocateElement(rpmts ts)
1457 return ts->relocateElement;
1460 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1462 rpmte orelocateElement = ts->relocateElement;
1463 ts->relocateElement = relocateElement;
1464 return orelocateElement;
1467 uint32_t rpmtsColor(rpmts ts)
1469 return (ts != NULL ? ts->color : 0);
1472 uint32_t rpmtsSetColor(rpmts ts, uint32_t color)
1474 uint32_t ocolor = 0;
1482 uint32_t rpmtsPrefColor(rpmts ts)
1484 return (ts != NULL ? ts->prefcolor : 0);
1487 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1491 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1496 int rpmtsSetNotifyCallback(rpmts ts,
1497 rpmCallbackFunction notify, rpmCallbackData notifyData)
1500 ts->notify = notify;
1501 ts->notifyData = notifyData;
1506 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1510 if (nep) *nep = ts->orderCount;
1515 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1516 pi = rpmtsiInit(ts);
1517 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1518 switch (rpmteType(p)) {
1529 pi = rpmtsiFree(pi);
1534 rpmts rpmtsCreate(void)
1538 ts = xcalloc(1, sizeof(*ts));
1539 memset(&ts->ops, 0, sizeof(ts->ops));
1540 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1541 ts->type = RPMTRANS_TYPE_NORMAL;
1542 ts->filesystemCount = 0;
1543 ts->filesystems = NULL;
1546 ts->solve = rpmtsSolve;
1547 ts->solveData = NULL;
1549 ts->suggests = NULL;
1551 ts->sdbmode = O_RDONLY;
1554 ts->dbmode = O_RDONLY;
1556 ts->scriptFd = NULL;
1557 ts->tid = (int32_t) time(NULL);
1560 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1561 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1563 ts->numRemovedPackages = 0;
1564 ts->allocedRemovedPackages = ts->delta;
1565 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1566 sizeof(*ts->removedPackages));
1572 ts->selinuxEnabled = is_selinux_enabled();
1574 ts->numAddedPackages = 0;
1575 ts->addedPackages = NULL;
1577 ts->numAvailablePackages = 0;
1578 ts->availablePackages = NULL;
1580 ts->orderAlloced = 0;
1591 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1595 * We only use the score in an autorollback. So set this to
1602 return rpmtsLink(ts, RPMDBG_M("tsCreate"));
1605 /**********************
1606 * Transaction Scores *
1607 **********************/
1610 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
1616 int tranElements; /* Number of transaction elements in runningTS */
1618 rpmRC rc = RPMRC_OK; /* Assume success */
1621 rpmlog(RPMLOG_DEBUG, _("Creating transaction score board(%p, %p)\n"),
1622 runningTS, rollbackTS);
1624 /* Allocate space for score board */
1625 score = xcalloc(1, sizeof(*score));
1626 rpmlog(RPMLOG_DEBUG, _("\tScore board address: %p\n"), score);
1629 * Determine the maximum size needed for the entry list.
1630 * XXX: Today, I just get the count of rpmts elements, and allocate
1631 * an array that big. Yes this is guaranteed to waste memory.
1632 * Future updates will hopefully make this more efficient,
1633 * but for now it will work.
1635 tranElements = rpmtsNElements(runningTS);
1636 rpmlog(RPMLOG_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
1637 score->scores = xcalloc(tranElements, sizeof(score->scores));
1639 /* Initialize score entry count */
1644 * Increment through transaction elements and make sure for every
1645 * N there is an rpmtsScoreEntry.
1647 pi = rpmtsiInit(runningTS);
1648 while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
1651 /* Try to find the entry in the score list */
1652 for(i = 0; i < score->entries; i++) {
1653 se = score->scores[i];
1654 if (strcmp(rpmteN(p), se->N) == 0) {
1660 /* If we did not find the entry then allocate space for it */
1662 /* XXX p->fi->te undefined. */
1663 rpmlog(RPMLOG_DEBUG, _("\tAdding entry for %s to score board.\n"),
1665 se = xcalloc(1, sizeof(*(*(score->scores))));
1666 rpmlog(RPMLOG_DEBUG, _("\t\tEntry address: %p\n"), se);
1667 se->N = xstrdup(rpmteN(p));
1668 se->te_types = rpmteType(p);
1671 score->scores[score->entries] = se;
1674 /* We found this one, so just add the element type to the one
1677 rpmlog(RPMLOG_DEBUG, _("\tUpdating entry for %s in score board.\n"),
1679 score->scores[i]->te_types |= rpmteType(p);
1683 pi = rpmtsiFree(pi);
1686 * Attach the score to the running transaction and the autorollback
1689 runningTS->score = score;
1691 rollbackTS->score = score;
1697 rpmtsScore rpmtsScoreFree(rpmtsScore score)
1699 rpmtsScoreEntry se = NULL;
1702 rpmlog(RPMLOG_DEBUG, _("May free Score board(%p)\n"), score);
1704 /* If score is not initialized, then just return.
1705 * This is likely the case if autorollbacks are not enabled.
1707 if (score == NULL) return NULL;
1709 /* Decrement the reference count */
1712 /* Do we have any more references? If so
1715 if (score->nrefs > 0) return NULL;
1717 rpmlog(RPMLOG_DEBUG, _("\tRefcount is zero...will free\n"));
1718 /* No more references, lets clean up */
1719 /* First deallocate the score entries */
1720 for(i = 0; i < score->entries; i++) {
1721 /* Get the score for the ith entry */
1722 se = score->scores[i];
1724 /* Deallocate the score entries name */
1725 se->N = _free(se->N);
1727 /* Deallocate the score entry itself */
1731 /* Next deallocate the score entry table */
1732 score->scores = _free(score->scores);
1734 /* Finally deallocate the score itself */
1735 score = _free(score);
1741 * XXX: Do not get the score and then store it aside for later use.
1742 * we will delete it out from under you. There is no rpmtsScoreLink()
1743 * as this may be a very temporary fix for autorollbacks.
1745 rpmtsScore rpmtsGetScore(rpmts ts)
1747 if (ts == NULL) return NULL;
1752 * XXX: Do not get the score entry and then store it aside for later use.
1753 * we will delete it out from under you. There is no
1754 * rpmtsScoreEntryLink() as this may be a very temporary fix
1755 * for autorollbacks.
1756 * XXX: The scores are not sorted. This should be fixed at earliest
1757 * opportunity (i.e. when we have the whole autorollback working).
1759 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
1763 rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
1765 rpmlog(RPMLOG_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
1767 /* Try to find the entry in the score list */
1768 for(i = 0; i < score->entries; i++) {
1769 se = score->scores[i];
1770 if (strcmp(N, se->N) == 0) {
1771 rpmlog(RPMLOG_DEBUG, _("\tFound entry at address: %p\n"), se);
1777 /* XXX score->scores undefined. */