3 * Routine(s) to handle a "rpmts" transaction sets.
7 #include <rpm/rpmurl.h>
8 #include "rpmio/digest.h"
9 #include <rpm/rpmlib.h>
10 #include <rpm/rpmmacro.h>
11 #include <rpm/rpmfileutil.h> /* rpmtsOpenDB() needs rpmGetPath */
12 #include <rpm/rpmstring.h>
14 #include <rpm/rpmdb.h>
16 #include <rpm/rpmal.h>
17 #include <rpm/rpmds.h>
18 #include <rpm/rpmfi.h>
19 #include "lib/rpmlock.h"
20 #include <rpm/rpmlog.h>
22 #include <rpm/rpmte.h>
24 #include "lib/rpmts_internal.h"
26 /* XXX FIXME: merge with existing (broken?) tests in system.h */
27 /* portability fiddles */
28 #if STATFS_IN_SYS_STATVFS
29 #include <sys/statvfs.h>
32 # if STATFS_IN_SYS_VFS
35 # if STATFS_IN_SYS_MOUNT
36 # include <sys/mount.h>
38 # if STATFS_IN_SYS_STATFS
39 # include <sys/statfs.h>
51 rpmts rpmtsUnlink(rpmts ts, const char * msg)
54 fprintf(stderr, "--> ts %p -- %d %s\n", ts, ts->nrefs, msg);
59 rpmts rpmtsLink(rpmts ts, const char * msg)
63 fprintf(stderr, "--> ts %p ++ %d %s\n", ts, ts->nrefs, msg);
67 int rpmtsCloseDB(rpmts ts)
71 if (ts->rdb != NULL) {
72 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
73 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
74 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
75 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
76 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
77 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
78 rc = rpmdbClose(ts->rdb);
84 int rpmtsOpenDB(rpmts ts, int dbmode)
88 if (ts->rdb != NULL && ts->dbmode == dbmode)
91 (void) rpmtsCloseDB(ts);
93 /* XXX there's a potential db lock race here. */
96 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
98 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
100 _("cannot open Packages database in %s\n"), dn);
106 int rpmtsInitDB(rpmts ts, int dbmode)
108 void *lock = rpmtsAcquireLock(ts);
111 rc = rpmdbInit(ts->rootDir, dbmode);
116 int rpmtsGetDBMode(rpmts ts)
122 int rpmtsSetDBMode(rpmts ts, int dbmode)
125 /* mode setting only permitted on non-open db */
126 if (ts != NULL && rpmtsGetRdb(ts) == NULL) {
134 int rpmtsRebuildDB(rpmts ts)
137 void *lock = rpmtsAcquireLock(ts);
138 if (!lock) return -1;
139 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
140 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
142 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
147 int rpmtsVerifyDB(rpmts ts)
149 return rpmdbVerify(ts->rootDir);
152 static int isArch(const char * arch)
155 static const char *arches[] = {
156 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", "x86_64", "amd64", "ia32e",
157 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
158 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
159 "sparc64", "sparc64v", "sun4u",
160 "mips", "mipsel", "IP",
161 "ppc", "ppciseries", "ppcpseries",
162 "ppc64", "ppc64iseries", "ppc64pseries",
166 "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
167 "s390", "i370", "s390x",
173 for (av = arches; *av != NULL; av++) {
174 if (!strcmp(arch, *av))
180 /* keyp might no be defined. */
181 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpm_tag_t rpmtag,
182 const void * keyp, size_t keylen)
184 rpmdbMatchIterator mi;
185 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 * s = keyp;
195 size_t slen = strlen(s);
196 char *t = alloca(slen+1);
201 while ((c = *s++) != '\0') {
207 /* XXX Fail if nested parens. */
209 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), keyp);
212 /* Parse explicit epoch. */
213 for (se = s; *se && xisdigit(*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"), keyp);
230 /* Don't copy trailing ')' */
235 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), 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);
260 rpmRC rpmtsFindPubkey(rpmts ts)
262 const void * sig = rpmtsSig(ts);
263 pgpDig dig = rpmtsDig(ts);
264 pgpDigParams sigp = rpmtsSignature(ts);
265 pgpDigParams pubp = rpmtsPubkey(ts);
266 rpmRC res = RPMRC_NOKEY;
267 char * pubkeysource = NULL;
270 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
274 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
275 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
276 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
279 /* Lazy free of previous pubkey if pubkey does not match this signature. */
280 if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
282 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
284 ts->pkpkt = _free(ts->pkpkt);
286 memset(ts->pksignid, 0, sizeof(ts->pksignid));
289 /* Try rpmdb keyring lookup. */
290 if (ts->pkpkt == NULL) {
293 rpmdbMatchIterator mi;
296 /* Retrieve the pubkey that matches the signature. */
297 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
298 while ((h = rpmdbNextIterator(mi)) != NULL) {
299 const char ** pubkeys;
303 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
305 hx = rpmdbGetIteratorOffset(mi);
306 ix = rpmdbGetIteratorFileNum(mi);
308 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
310 pubkeys = headerFreeData(pubkeys, pt);
313 mi = rpmdbFreeIterator(mi);
317 sprintf(hnum, "h#%d", hx);
318 pubkeysource = xstrdup(hnum);
320 ts->pkpkt = _free(ts->pkpkt);
325 /* Try keyserver lookup. */
326 if (ts->pkpkt == NULL) {
327 char * fn = rpmExpand("%{_hkp_keyserver_query}",
328 pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
331 if (fn && *fn != '%') {
332 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
336 ts->pkpkt = _free(ts->pkpkt);
339 /* Save new pubkey in local ts keyring for delayed import. */
340 pubkeysource = xstrdup("keyserver");
345 /* Try filename from macro lookup. */
346 if (ts->pkpkt == NULL) {
347 const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
350 if (fn && *fn != '%')
351 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
354 ts->pkpkt = _free(ts->pkpkt);
357 pubkeysource = xstrdup("macro");
362 /* Was a matching pubkey found? */
363 if (ts->pkpkt == NULL || ts->pkpktlen == 0)
366 /* Retrieve parameters from pubkey packet(s). */
367 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
369 /* Do the parameters match the signature? */
370 if (sigp->pubkey_algo == pubp->pubkey_algo
372 && sigp->hash_algo == pubp->hash_algo
374 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
377 /* XXX Verify any pubkey signatures. */
379 /* Pubkey packet looks good, save the signer id. */
380 memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
383 rpmlog(RPMLOG_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
384 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
385 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
386 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
393 pubkeysource = _free(pubkeysource);
394 if (res != RPMRC_OK) {
395 ts->pkpkt = _free(ts->pkpkt);
401 rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
403 static unsigned char zeros[] =
404 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
405 const char * afmt = "%{pubkeys:armor}";
406 const char * group = "Public Keys";
407 const char * license = "pubkey";
408 const char * buildhost = "localhost";
409 int32_t pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
412 pgpDigParams pubp = NULL;
421 rpmRC rc = RPMRC_FAIL; /* assume failure */
425 if (pkt == NULL || pktlen == 0)
427 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
430 if ((enc = b64encode(pkt, pktlen, -1)) == NULL)
435 /* Build header elements. */
436 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
439 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
440 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
441 || pubp->userid == NULL)
444 v = t = xmalloc(16+1);
445 t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
447 r = t = xmalloc(8+1);
448 t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
450 n = t = xmalloc(sizeof("gpg()")+8);
451 t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
453 /* FIX: pubp->userid may be NULL */
454 u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
455 t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
457 evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
458 t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
459 t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
461 /* Check for pre-existing header. */
463 /* Build pubkey header. */
466 xx = headerAddOrAppendEntry(h, RPMTAG_PUBKEYS,
467 RPM_STRING_ARRAY_TYPE, &enc, 1);
469 d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
473 xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
474 xx = headerAddEntry(h, RPMTAG_VERSION, RPM_STRING_TYPE, v+8, 1);
475 xx = headerAddEntry(h, RPMTAG_RELEASE, RPM_STRING_TYPE, r, 1);
476 xx = headerAddEntry(h, RPMTAG_DESCRIPTION, RPM_STRING_TYPE, d, 1);
477 xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
478 xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
479 xx = headerAddEntry(h, RPMTAG_SUMMARY, RPM_STRING_TYPE, u, 1);
481 xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
483 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
484 RPM_STRING_ARRAY_TYPE, &u, 1);
485 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
486 RPM_STRING_ARRAY_TYPE, &evr, 1);
487 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
488 RPM_INT32_TYPE, &pflags, 1);
490 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
491 RPM_STRING_ARRAY_TYPE, &n, 1);
492 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
493 RPM_STRING_ARRAY_TYPE, &evr, 1);
494 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
495 RPM_INT32_TYPE, &pflags, 1);
497 xx = headerAddEntry(h, RPMTAG_RPMVERSION, RPM_STRING_TYPE, RPMVERSION, 1);
499 /* XXX W2DO: tag value inheirited from parent? */
500 xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
501 { int32_t tid = rpmtsGetTid(ts);
502 xx = headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &tid, 1);
503 /* XXX W2DO: tag value inheirited from parent? */
504 xx = headerAddEntry(h, RPMTAG_BUILDTIME, RPM_INT32_TYPE, &tid, 1);
508 /* XXX W2DO: tag value inheirited from parent? */
509 xx = headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, fn, 1);
512 /* Add header to database. */
513 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
521 dig = pgpFreeDig(dig);
533 int rpmtsCloseSDB(rpmts ts)
537 if (ts->sdb != NULL) {
538 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
539 rpmdbOp(ts->sdb, RPMDB_OP_DBGET));
540 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
541 rpmdbOp(ts->sdb, RPMDB_OP_DBPUT));
542 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
543 rpmdbOp(ts->sdb, RPMDB_OP_DBDEL));
544 rc = rpmdbClose(ts->sdb);
550 int rpmtsOpenSDB(rpmts ts, int dbmode)
552 static int has_sdbpath = -1;
555 if (ts->sdb != NULL && ts->sdbmode == dbmode)
559 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
561 /* If not configured, don't try to open. */
562 if (has_sdbpath <= 0)
565 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
567 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
569 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
570 rpmlog(RPMLOG_WARNING,
571 _("cannot open Solve database in %s\n"), dn);
574 delMacro(NULL, "_dbpath");
580 * Compare suggested package resolutions (qsort/bsearch).
581 * @param a 1st instance address
582 * @param b 2nd instance address
583 * @return result of comparison
585 static int sugcmp(const void * a, const void * b)
587 const char * astr = *(const char **)a;
588 const char * bstr = *(const char **)b;
589 return strcmp(astr, bstr);
592 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
597 rpmdbMatchIterator mi;
605 int rc = 1; /* assume not found */
608 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
615 if (ts->sdb == NULL) {
616 xx = rpmtsOpenSDB(ts, ts->sdbmode);
620 /* Look for a matching Provides: in suggested universe. */
621 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
623 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
627 while ((h = rpmdbNextIterator(mi)) != NULL) {
633 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
636 /* XXX Prefer the shortest name if given alternatives. */
639 if (headerGetEntry(h, RPMTAG_NAME, NULL, (void **)&hname, NULL)) {
641 hnamelen = strlen(hname);
643 if (bhnamelen > 0 && hnamelen > bhnamelen)
646 /* XXX Prefer the newest build if given alternatives. */
648 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (void **)&ip, NULL))
657 bhnamelen = hnamelen;
659 mi = rpmdbFreeIterator(mi);
661 /* Is there a suggested resolution? */
665 /* Format the suggestion. */
666 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
667 if (qfmt == NULL || *qfmt == '\0')
669 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
673 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
677 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
682 fd = Fopen(str, "r.ufdio");
683 if (fd == NULL || Ferror(fd)) {
684 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
693 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
699 case RPMRC_NOTTRUSTED:
703 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
705 rpmlog(RPMLOG_DEBUG, _("Adding: %s\n"), str);
707 /* XXX str memory leak */
717 rpmlog(RPMLOG_DEBUG, _("Suggesting: %s\n"), str);
718 /* If suggestion is already present, don't bother. */
719 if (ts->suggests != NULL && ts->nsuggests > 0) {
720 if (bsearch(&str, ts->suggests, ts->nsuggests,
721 sizeof(*ts->suggests), sugcmp))
725 /* Add a new (unique) suggestion. */
726 ts->suggests = xrealloc(ts->suggests,
727 sizeof(*ts->suggests) * (ts->nsuggests + 2));
728 ts->suggests[ts->nsuggests] = str;
730 ts->suggests[ts->nsuggests] = NULL;
732 if (ts->nsuggests > 1)
733 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
736 /* FIX: ts->suggests[] may be NULL */
740 int rpmtsAvailable(rpmts ts, const rpmds ds)
743 int rc = 1; /* assume not found */
745 if (ts->availablePackages == NULL)
747 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
751 /* XXX no alternatives yet */
752 if (sugkey[0] != NULL) {
753 ts->suggests = xrealloc(ts->suggests,
754 sizeof(*ts->suggests) * (ts->nsuggests + 2));
755 ts->suggests[ts->nsuggests] = sugkey[0];
758 ts->suggests[ts->nsuggests] = NULL;
760 sugkey = _free(sugkey);
761 /* FIX: ts->suggests[] may be NULL */
765 int rpmtsSetSolveCallback(rpmts ts,
766 int (*solve) (rpmts ts, rpmds key, const void * data),
767 const void * solveData)
773 ts->solveData = solveData;
778 void rpmtsPrintSuggests(rpmts ts)
780 if (ts->suggests != NULL && ts->nsuggests > 0) {
782 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
783 for (i = 0; i < ts->nsuggests; i++) {
784 const char * str = ts->suggests[i];
789 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
795 rpmps rpmtsProblems(rpmts ts)
800 ps = rpmpsLink(ts->probs, RPMDBG_M("rpmtsProblems"));
805 void rpmtsCleanProblems(rpmts ts)
807 if (ts && ts->probs) {
808 ts->probs = rpmpsFree(ts->probs);
812 void rpmtsCleanDig(rpmts ts)
814 ts->sig = headerFreeData(ts->sig, ts->sigtype);
815 ts->dig = pgpFreeDig(ts->dig);
818 void rpmtsClean(rpmts ts)
826 /* Clean up after dependency checks. */
828 while ((p = rpmtsiNext(pi, 0)) != NULL)
832 ts->addedPackages = rpmalFree(ts->addedPackages);
833 ts->numAddedPackages = 0;
835 for (i = 0; i < ts->nsuggests; i++) {
836 const char * str = ts->suggests[i];
837 ts->suggests[i] = NULL;
840 ts->suggests = _free(ts->suggests);
843 rpmtsCleanProblems(ts);
848 void rpmtsEmpty(rpmts ts)
858 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
859 ts->order[oc] = rpmteFree(ts->order[oc]);
867 ts->numRemovedPackages = 0;
871 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
873 static unsigned int scale = (1000 * 1000);
874 if (op != NULL && op->count > 0)
875 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
877 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
878 op->usecs/scale, op->usecs%scale);
881 static void rpmtsPrintStats(rpmts ts)
883 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
885 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
886 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
887 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
888 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
889 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
890 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
891 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
892 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
893 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
894 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
895 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
896 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
897 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
898 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
899 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
900 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
901 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
904 rpmts rpmtsFree(rpmts ts)
910 return rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
914 (void) rpmtsCloseDB(ts);
916 (void) rpmtsCloseSDB(ts);
918 ts->removedPackages = _free(ts->removedPackages);
920 ts->availablePackages = rpmalFree(ts->availablePackages);
921 ts->numAvailablePackages = 0;
923 ts->dsi = _free(ts->dsi);
925 if (ts->scriptFd != NULL) {
926 ts->scriptFd = fdFree(ts->scriptFd, RPMDBG_M("rpmtsFree"));
929 ts->rootDir = _free(ts->rootDir);
930 ts->currDir = _free(ts->currDir);
932 ts->order = _free(ts->order);
933 ts->orderAlloced = 0;
935 if (ts->pkpkt != NULL)
936 ts->pkpkt = _free(ts->pkpkt);
938 memset(ts->pksignid, 0, sizeof(ts->pksignid));
943 /* Free up the memory used by the rpmtsScore */
944 ts->score = rpmtsScoreFree(ts->score);
946 (void) rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
953 rpmVSFlags rpmtsVSFlags(rpmts ts)
955 rpmVSFlags vsflags = 0;
957 vsflags = ts->vsflags;
961 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
963 rpmVSFlags ovsflags = 0;
965 ovsflags = ts->vsflags;
966 ts->vsflags = vsflags;
972 * This allows us to mark transactions as being of a certain type.
973 * The three types are:
977 * RPM_TRANS_AUTOROLLBACK
979 * ROLLBACK and AUTOROLLBACK transactions should always be ran as
980 * a best effort. In particular this is important to the autorollback
981 * feature to avoid rolling back a rollback (otherwise known as
982 * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
983 * counts passed to scriptlets to be altered.
985 void rpmtsSetType(rpmts ts, rpmtsType type)
992 /* Let them know what type of transaction we are */
993 rpmtsType rpmtsGetType(rpmts ts)
1001 int rpmtsUnorderedSuccessors(rpmts ts, int first)
1003 int unorderedSuccessors = 0;
1005 unorderedSuccessors = ts->unorderedSuccessors;
1007 ts->unorderedSuccessors = first;
1009 return unorderedSuccessors;
1012 const char * rpmtsRootDir(rpmts ts)
1014 const char * rootDir = NULL;
1016 if (ts != NULL && ts->rootDir != NULL) {
1017 urltype ut = urlPath(ts->rootDir, &rootDir);
1019 case URL_IS_UNKNOWN:
1022 /* XXX these shouldn't be allowed as rootdir! */
1036 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
1041 ts->rootDir = _free(ts->rootDir);
1043 if (rootDir == NULL) {
1045 ts->rootDir = xstrdup("");
1049 rootLen = strlen(rootDir);
1051 /* Make sure that rootDir has trailing / */
1052 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
1053 char * t = alloca(rootLen + 2);
1055 (void) stpcpy( stpcpy(t, rootDir), "/");
1058 ts->rootDir = xstrdup(rootDir);
1062 const char * rpmtsCurrDir(rpmts ts)
1064 const char * currDir = NULL;
1066 currDir = ts->currDir;
1071 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
1074 ts->currDir = _free(ts->currDir);
1076 ts->currDir = xstrdup(currDir);
1080 FD_t rpmtsScriptFd(rpmts ts)
1082 FD_t scriptFd = NULL;
1084 scriptFd = ts->scriptFd;
1089 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1093 if (ts->scriptFd != NULL) {
1094 ts->scriptFd = fdFree(ts->scriptFd,
1095 RPMDBG_M("rpmtsSetScriptFd"));
1096 ts->scriptFd = NULL;
1098 if (scriptFd != NULL)
1099 ts->scriptFd = fdLink((void *)scriptFd,
1100 RPMDBG_M("rpmtsSetScriptFd"));
1104 int rpmtsSELinuxEnabled(rpmts ts)
1106 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1109 int rpmtsChrootDone(rpmts ts)
1111 return (ts != NULL ? ts->chrootDone : 0);
1114 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1116 int ochrootDone = 0;
1118 ochrootDone = ts->chrootDone;
1119 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1120 ts->chrootDone = chrootDone;
1125 int32_t rpmtsGetTid(rpmts ts)
1134 int32_t rpmtsSetTid(rpmts ts, int32_t tid)
1144 rpm_tag_t rpmtsSigtag(const rpmts ts)
1146 rpm_tag_t sigtag = 0;
1148 sigtag = ts->sigtag;
1152 rpm_tagtype_t rpmtsSigtype(const rpmts ts)
1154 rpm_tagtype_t sigtype = 0;
1156 sigtype = ts->sigtype;
1160 const void * rpmtsSig(const rpmts ts)
1162 const void * sig = NULL;
1168 size_t rpmtsSiglen(const rpmts ts)
1172 siglen = ts->siglen;
1176 int rpmtsSetSig(rpmts ts, rpm_tag_t sigtag, rpm_tagtype_t sigtype,
1177 const void * sig, size_t siglen)
1180 if (ts->sig && ts->sigtype)
1181 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1182 ts->sigtag = sigtag;
1183 ts->sigtype = (sig ? sigtype : 0);
1185 ts->siglen = siglen;
1190 pgpDig rpmtsDig(rpmts ts)
1192 /* FIX: hide lazy malloc for now */
1193 if (ts->dig == NULL)
1194 ts->dig = pgpNewDig();
1195 if (ts->dig == NULL)
1200 pgpDigParams rpmtsSignature(const rpmts ts)
1202 pgpDig dig = rpmtsDig(ts);
1203 if (dig == NULL) return NULL;
1204 return &dig->signature;
1207 pgpDigParams rpmtsPubkey(const rpmts ts)
1209 pgpDig dig = rpmtsDig(ts);
1210 if (dig == NULL) return NULL;
1211 return &dig->pubkey;
1214 rpmdb rpmtsGetRdb(rpmts ts)
1223 int rpmtsInitDSI(const rpmts ts)
1225 rpmDiskSpaceInfo dsi;
1230 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1233 rpmlog(RPMLOG_DEBUG, _("mounted filesystems:\n"));
1234 rpmlog(RPMLOG_DEBUG,
1235 _(" i dev bsize bavail iavail mount point\n"));
1237 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1238 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1241 /* Get available space on mounted file systems. */
1243 ts->dsi = _free(ts->dsi);
1244 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1249 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1250 #if STATFS_IN_SYS_STATVFS
1252 memset(&sfb, 0, sizeof(sfb));
1253 rc = statvfs(ts->filesystems[i], &sfb);
1256 memset(&sfb, 0, sizeof(sfb));
1258 /* This platform has the 4-argument version of the statfs call. The last two
1259 * should be the size of struct statfs and 0, respectively. The 0 is the
1260 * filesystem type, and is always 0 when statfs is called on a mounted
1261 * filesystem, as we're doing.
1263 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1265 rc = statfs(ts->filesystems[i], &sfb);
1271 rc = stat(ts->filesystems[i], &sb);
1274 dsi->dev = sb.st_dev;
1276 dsi->bsize = sfb.f_bsize;
1279 #ifdef STATFS_HAS_F_BAVAIL
1280 dsi->bavail = sfb.f_bavail;
1282 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1283 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1284 * it's about all we can do.
1286 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1288 /* XXX Avoid FAT and other file systems that have not inodes. */
1289 /* XXX assigning negative value to unsigned type */
1290 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1292 rpmlog(RPMLOG_DEBUG, _("%5d 0x%08x %8u %12ld %12ld %s\n"),
1293 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1294 (signed long) dsi->bavail, (signed long) dsi->iavail,
1295 ts->filesystems[i]);
1300 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1301 uint32_t fileSize, uint32_t prevSize, uint32_t fixupSize,
1302 rpmFileAction action)
1304 rpmDiskSpaceInfo dsi;
1309 while (dsi->bsize && dsi->dev != dev)
1311 if (dsi->bsize == 0)
1317 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1324 dsi->bneeded += bneeded;
1328 * FIXME: If two packages share a file (same md5sum), and
1329 * that file is being replaced on disk, will dsi->bneeded get
1330 * adjusted twice? Quite probably!
1333 dsi->bneeded += bneeded;
1334 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1339 dsi->bneeded -= bneeded;
1347 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1350 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1352 rpmDiskSpaceInfo dsi;
1357 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1363 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1367 ps = rpmtsProblems(ts);
1368 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1370 if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1371 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1372 rpmteNEVRA(te), rpmteKey(te),
1373 ts->filesystems[i], NULL, NULL,
1374 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1377 if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1378 rpmpsAppend(ps, RPMPROB_DISKNODES,
1379 rpmteNEVRA(te), rpmteKey(te),
1380 ts->filesystems[i], NULL, NULL,
1381 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1387 void * rpmtsNotify(rpmts ts, rpmte te,
1388 rpmCallbackType what, unsigned long amount, unsigned long total)
1391 if (ts && ts->notify && te) {
1392 Header h = rpmteHeader(te);
1393 assert(!(rpmteType(te) == TR_ADDED && h == NULL));
1396 ptr = ts->notify(h, what, amount, total,
1397 rpmteKey(te), ts->notifyData);
1398 headerUnlink(h); /* undo rpmteHeader() ref */
1403 int rpmtsNElements(rpmts ts)
1406 if (ts != NULL && ts->order != NULL) {
1407 nelements = ts->orderCount;
1412 rpmte rpmtsElement(rpmts ts, int ix)
1415 if (ts != NULL && ts->order != NULL) {
1416 if (ix >= 0 && ix < ts->orderCount)
1422 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1424 return (ts != NULL ? ts->ignoreSet : 0);
1427 rpmtransFlags rpmtsFlags(rpmts ts)
1429 return (ts != NULL ? ts->transFlags : 0);
1432 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1434 rpmtransFlags otransFlags = 0;
1436 otransFlags = ts->transFlags;
1437 ts->transFlags = transFlags;
1442 rpmSpec rpmtsSpec(rpmts ts)
1447 rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
1449 rpmSpec ospec = ts->spec;
1454 rpmte rpmtsRelocateElement(rpmts ts)
1456 return ts->relocateElement;
1459 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1461 rpmte orelocateElement = ts->relocateElement;
1462 ts->relocateElement = relocateElement;
1463 return orelocateElement;
1466 uint32_t rpmtsColor(rpmts ts)
1468 return (ts != NULL ? ts->color : 0);
1471 uint32_t rpmtsSetColor(rpmts ts, uint32_t color)
1473 uint32_t ocolor = 0;
1481 uint32_t rpmtsPrefColor(rpmts ts)
1483 return (ts != NULL ? ts->prefcolor : 0);
1486 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1490 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1495 int rpmtsSetNotifyCallback(rpmts ts,
1496 rpmCallbackFunction notify, rpmCallbackData notifyData)
1499 ts->notify = notify;
1500 ts->notifyData = notifyData;
1505 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1509 if (nep) *nep = ts->orderCount;
1514 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1515 pi = rpmtsiInit(ts);
1516 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1517 switch (rpmteType(p)) {
1528 pi = rpmtsiFree(pi);
1533 rpmts rpmtsCreate(void)
1537 ts = xcalloc(1, sizeof(*ts));
1538 memset(&ts->ops, 0, sizeof(ts->ops));
1539 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1540 ts->type = RPMTRANS_TYPE_NORMAL;
1541 ts->filesystemCount = 0;
1542 ts->filesystems = NULL;
1545 ts->solve = rpmtsSolve;
1546 ts->solveData = NULL;
1548 ts->suggests = NULL;
1550 ts->sdbmode = O_RDONLY;
1553 ts->dbmode = O_RDONLY;
1555 ts->scriptFd = NULL;
1556 ts->tid = (int32_t) time(NULL);
1559 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1560 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1562 ts->numRemovedPackages = 0;
1563 ts->allocedRemovedPackages = ts->delta;
1564 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1565 sizeof(*ts->removedPackages));
1571 ts->selinuxEnabled = is_selinux_enabled();
1573 ts->numAddedPackages = 0;
1574 ts->addedPackages = NULL;
1576 ts->numAvailablePackages = 0;
1577 ts->availablePackages = NULL;
1579 ts->orderAlloced = 0;
1590 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1594 * We only use the score in an autorollback. So set this to
1601 return rpmtsLink(ts, RPMDBG_M("tsCreate"));
1604 /**********************
1605 * Transaction Scores *
1606 **********************/
1609 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
1615 int tranElements; /* Number of transaction elements in runningTS */
1617 rpmRC rc = RPMRC_OK; /* Assume success */
1620 rpmlog(RPMLOG_DEBUG, _("Creating transaction score board(%p, %p)\n"),
1621 runningTS, rollbackTS);
1623 /* Allocate space for score board */
1624 score = xcalloc(1, sizeof(*score));
1625 rpmlog(RPMLOG_DEBUG, _("\tScore board address: %p\n"), score);
1628 * Determine the maximum size needed for the entry list.
1629 * XXX: Today, I just get the count of rpmts elements, and allocate
1630 * an array that big. Yes this is guaranteed to waste memory.
1631 * Future updates will hopefully make this more efficient,
1632 * but for now it will work.
1634 tranElements = rpmtsNElements(runningTS);
1635 rpmlog(RPMLOG_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
1636 score->scores = xcalloc(tranElements, sizeof(score->scores));
1638 /* Initialize score entry count */
1643 * Increment through transaction elements and make sure for every
1644 * N there is an rpmtsScoreEntry.
1646 pi = rpmtsiInit(runningTS);
1647 while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
1650 /* Try to find the entry in the score list */
1651 for(i = 0; i < score->entries; i++) {
1652 se = score->scores[i];
1653 if (strcmp(rpmteN(p), se->N) == 0) {
1659 /* If we did not find the entry then allocate space for it */
1661 /* XXX p->fi->te undefined. */
1662 rpmlog(RPMLOG_DEBUG, _("\tAdding entry for %s to score board.\n"),
1664 se = xcalloc(1, sizeof(*(*(score->scores))));
1665 rpmlog(RPMLOG_DEBUG, _("\t\tEntry address: %p\n"), se);
1666 se->N = xstrdup(rpmteN(p));
1667 se->te_types = rpmteType(p);
1670 score->scores[score->entries] = se;
1673 /* We found this one, so just add the element type to the one
1676 rpmlog(RPMLOG_DEBUG, _("\tUpdating entry for %s in score board.\n"),
1678 score->scores[i]->te_types |= rpmteType(p);
1682 pi = rpmtsiFree(pi);
1685 * Attach the score to the running transaction and the autorollback
1688 runningTS->score = score;
1690 rollbackTS->score = score;
1696 rpmtsScore rpmtsScoreFree(rpmtsScore score)
1698 rpmtsScoreEntry se = NULL;
1701 rpmlog(RPMLOG_DEBUG, _("May free Score board(%p)\n"), score);
1703 /* If score is not initialized, then just return.
1704 * This is likely the case if autorollbacks are not enabled.
1706 if (score == NULL) return NULL;
1708 /* Decrement the reference count */
1711 /* Do we have any more references? If so
1714 if (score->nrefs > 0) return NULL;
1716 rpmlog(RPMLOG_DEBUG, _("\tRefcount is zero...will free\n"));
1717 /* No more references, lets clean up */
1718 /* First deallocate the score entries */
1719 for(i = 0; i < score->entries; i++) {
1720 /* Get the score for the ith entry */
1721 se = score->scores[i];
1723 /* Deallocate the score entries name */
1724 se->N = _free(se->N);
1726 /* Deallocate the score entry itself */
1730 /* Next deallocate the score entry table */
1731 score->scores = _free(score->scores);
1733 /* Finally deallocate the score itself */
1734 score = _free(score);
1740 * XXX: Do not get the score and then store it aside for later use.
1741 * we will delete it out from under you. There is no rpmtsScoreLink()
1742 * as this may be a very temporary fix for autorollbacks.
1744 rpmtsScore rpmtsGetScore(rpmts ts)
1746 if (ts == NULL) return NULL;
1751 * XXX: Do not get the score entry and then store it aside for later use.
1752 * we will delete it out from under you. There is no
1753 * rpmtsScoreEntryLink() as this may be a very temporary fix
1754 * for autorollbacks.
1755 * XXX: The scores are not sorted. This should be fixed at earliest
1756 * opportunity (i.e. when we have the whole autorollback working).
1758 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
1762 rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
1764 rpmlog(RPMLOG_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
1766 /* Try to find the entry in the score list */
1767 for(i = 0; i < score->entries; i++) {
1768 se = score->scores[i];
1769 if (strcmp(N, se->N) == 0) {
1770 rpmlog(RPMLOG_DEBUG, _("\tFound entry at address: %p\n"), se);
1776 /* XXX score->scores undefined. */