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);
99 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",
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, rpmTag 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 const 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, (void **)&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 const 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, ssize_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;
414 const char * d = NULL;
415 const char * enc = NULL;
416 const char * n = NULL;
417 const char * u = NULL;
418 const char * v = NULL;
419 const char * r = NULL;
420 const char * evr = 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);
571 dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
572 rpmlog(RPMLOG_WARNING,
573 _("cannot open Solve database in %s\n"), dn);
576 delMacro(NULL, "_dbpath");
582 * Compare suggested package resolutions (qsort/bsearch).
583 * @param a 1st instance address
584 * @param b 2nd instance address
585 * @return result of comparison
587 static int sugcmp(const void * a, const void * b)
589 const char * astr = *(const char **)a;
590 const char * bstr = *(const char **)b;
591 return strcmp(astr, bstr);
594 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
599 rpmdbMatchIterator mi;
607 int rc = 1; /* assume not found */
610 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
617 if (ts->sdb == NULL) {
618 xx = rpmtsOpenSDB(ts, ts->sdbmode);
622 /* Look for a matching Provides: in suggested universe. */
623 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
625 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
629 while ((h = rpmdbNextIterator(mi)) != NULL) {
635 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
638 /* XXX Prefer the shortest name if given alternatives. */
641 if (headerGetEntry(h, RPMTAG_NAME, NULL, (void **)&hname, NULL)) {
643 hnamelen = strlen(hname);
645 if (bhnamelen > 0 && hnamelen > bhnamelen)
648 /* XXX Prefer the newest build if given alternatives. */
650 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (void **)&ip, NULL))
659 bhnamelen = hnamelen;
661 mi = rpmdbFreeIterator(mi);
663 /* Is there a suggested resolution? */
667 /* Format the suggestion. */
668 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
669 if (qfmt == NULL || *qfmt == '\0')
671 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
675 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
679 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
684 fd = Fopen(str, "r.ufdio");
685 if (fd == NULL || Ferror(fd)) {
686 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
695 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
701 case RPMRC_NOTTRUSTED:
705 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
707 rpmlog(RPMLOG_DEBUG, _("Adding: %s\n"), str);
709 /* XXX str memory leak */
719 rpmlog(RPMLOG_DEBUG, _("Suggesting: %s\n"), str);
720 /* If suggestion is already present, don't bother. */
721 if (ts->suggests != NULL && ts->nsuggests > 0) {
722 if (bsearch(&str, ts->suggests, ts->nsuggests,
723 sizeof(*ts->suggests), sugcmp))
727 /* Add a new (unique) suggestion. */
728 ts->suggests = xrealloc(ts->suggests,
729 sizeof(*ts->suggests) * (ts->nsuggests + 2));
730 ts->suggests[ts->nsuggests] = str;
732 ts->suggests[ts->nsuggests] = NULL;
734 if (ts->nsuggests > 1)
735 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
738 /* FIX: ts->suggests[] may be NULL */
742 int rpmtsAvailable(rpmts ts, const rpmds ds)
745 int rc = 1; /* assume not found */
747 if (ts->availablePackages == NULL)
749 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
753 /* XXX no alternatives yet */
754 if (sugkey[0] != NULL) {
755 ts->suggests = xrealloc(ts->suggests,
756 sizeof(*ts->suggests) * (ts->nsuggests + 2));
757 ts->suggests[ts->nsuggests] = sugkey[0];
760 ts->suggests[ts->nsuggests] = NULL;
762 sugkey = _free(sugkey);
763 /* FIX: ts->suggests[] may be NULL */
767 int rpmtsSetSolveCallback(rpmts ts,
768 int (*solve) (rpmts ts, rpmds key, const void * data),
769 const void * solveData)
775 ts->solveData = solveData;
780 void rpmtsPrintSuggests(rpmts ts)
782 if (ts->suggests != NULL && ts->nsuggests > 0) {
784 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
785 for (i = 0; i < ts->nsuggests; i++) {
786 const char * str = ts->suggests[i];
791 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
797 rpmps rpmtsProblems(rpmts ts)
802 ps = rpmpsLink(ts->probs, RPMDBG_M("rpmtsProblems"));
807 void rpmtsCleanProblems(rpmts ts)
809 if (ts && ts->probs) {
810 ts->probs = rpmpsFree(ts->probs);
814 void rpmtsCleanDig(rpmts ts)
816 ts->sig = headerFreeData(ts->sig, ts->sigtype);
817 ts->dig = pgpFreeDig(ts->dig);
820 void rpmtsClean(rpmts ts)
828 /* Clean up after dependency checks. */
830 while ((p = rpmtsiNext(pi, 0)) != NULL)
834 ts->addedPackages = rpmalFree(ts->addedPackages);
835 ts->numAddedPackages = 0;
837 for (i = 0; i < ts->nsuggests; i++) {
838 const char * str = ts->suggests[i];
839 ts->suggests[i] = NULL;
842 ts->suggests = _free(ts->suggests);
845 rpmtsCleanProblems(ts);
850 void rpmtsEmpty(rpmts ts)
860 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
861 ts->order[oc] = rpmteFree(ts->order[oc]);
869 ts->numRemovedPackages = 0;
873 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
875 static unsigned int scale = (1000 * 1000);
876 if (op != NULL && op->count > 0)
877 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
879 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
880 op->usecs/scale, op->usecs%scale);
883 static void rpmtsPrintStats(rpmts ts)
885 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
887 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
888 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
889 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
890 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
891 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
892 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
893 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
894 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
895 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
896 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
897 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
898 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
899 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
900 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
901 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
902 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
903 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
906 rpmts rpmtsFree(rpmts ts)
912 return rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
916 (void) rpmtsCloseDB(ts);
918 (void) rpmtsCloseSDB(ts);
920 ts->removedPackages = _free(ts->removedPackages);
922 ts->availablePackages = rpmalFree(ts->availablePackages);
923 ts->numAvailablePackages = 0;
925 ts->dsi = _free(ts->dsi);
927 if (ts->scriptFd != NULL) {
928 ts->scriptFd = fdFree(ts->scriptFd, RPMDBG_M("rpmtsFree"));
931 ts->rootDir = _free(ts->rootDir);
932 ts->currDir = _free(ts->currDir);
934 ts->order = _free(ts->order);
935 ts->orderAlloced = 0;
937 if (ts->pkpkt != NULL)
938 ts->pkpkt = _free(ts->pkpkt);
940 memset(ts->pksignid, 0, sizeof(ts->pksignid));
945 /* Free up the memory used by the rpmtsScore */
946 ts->score = rpmtsScoreFree(ts->score);
948 (void) rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
955 rpmVSFlags rpmtsVSFlags(rpmts ts)
957 rpmVSFlags vsflags = 0;
959 vsflags = ts->vsflags;
963 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
965 rpmVSFlags ovsflags = 0;
967 ovsflags = ts->vsflags;
968 ts->vsflags = vsflags;
974 * This allows us to mark transactions as being of a certain type.
975 * The three types are:
979 * RPM_TRANS_AUTOROLLBACK
981 * ROLLBACK and AUTOROLLBACK transactions should always be ran as
982 * a best effort. In particular this is important to the autorollback
983 * feature to avoid rolling back a rollback (otherwise known as
984 * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
985 * counts passed to scriptlets to be altered.
987 void rpmtsSetType(rpmts ts, rpmtsType type)
994 /* Let them know what type of transaction we are */
995 rpmtsType rpmtsGetType(rpmts ts)
1003 int rpmtsUnorderedSuccessors(rpmts ts, int first)
1005 int unorderedSuccessors = 0;
1007 unorderedSuccessors = ts->unorderedSuccessors;
1009 ts->unorderedSuccessors = first;
1011 return unorderedSuccessors;
1014 const char * rpmtsRootDir(rpmts ts)
1016 const char * rootDir = NULL;
1018 if (ts != NULL && ts->rootDir != NULL) {
1019 urltype ut = urlPath(ts->rootDir, &rootDir);
1021 case URL_IS_UNKNOWN:
1024 /* XXX these shouldn't be allowed as rootdir! */
1038 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
1043 ts->rootDir = _free(ts->rootDir);
1045 if (rootDir == NULL) {
1047 ts->rootDir = xstrdup("");
1051 rootLen = strlen(rootDir);
1053 /* Make sure that rootDir has trailing / */
1054 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
1055 char * t = alloca(rootLen + 2);
1057 (void) stpcpy( stpcpy(t, rootDir), "/");
1060 ts->rootDir = xstrdup(rootDir);
1064 const char * rpmtsCurrDir(rpmts ts)
1066 const char * currDir = NULL;
1068 currDir = ts->currDir;
1073 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
1076 ts->currDir = _free(ts->currDir);
1078 ts->currDir = xstrdup(currDir);
1082 FD_t rpmtsScriptFd(rpmts ts)
1084 FD_t scriptFd = NULL;
1086 scriptFd = ts->scriptFd;
1091 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1095 if (ts->scriptFd != NULL) {
1096 ts->scriptFd = fdFree(ts->scriptFd,
1097 RPMDBG_M("rpmtsSetScriptFd"));
1098 ts->scriptFd = NULL;
1100 if (scriptFd != NULL)
1101 ts->scriptFd = fdLink((void *)scriptFd,
1102 RPMDBG_M("rpmtsSetScriptFd"));
1106 int rpmtsSELinuxEnabled(rpmts ts)
1108 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1111 int rpmtsChrootDone(rpmts ts)
1113 return (ts != NULL ? ts->chrootDone : 0);
1116 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1118 int ochrootDone = 0;
1120 ochrootDone = ts->chrootDone;
1121 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1122 ts->chrootDone = chrootDone;
1127 int32_t rpmtsGetTid(rpmts ts)
1136 int32_t rpmtsSetTid(rpmts ts, int32_t tid)
1146 int32_t rpmtsSigtag(const rpmts ts)
1150 sigtag = ts->sigtag;
1154 int32_t rpmtsSigtype(const rpmts ts)
1156 int32_t sigtype = 0;
1158 sigtype = ts->sigtype;
1162 const void * rpmtsSig(const rpmts ts)
1164 const void * sig = NULL;
1170 size_t rpmtsSiglen(const rpmts ts)
1174 siglen = ts->siglen;
1178 int rpmtsSetSig(rpmts ts,
1179 int32_t sigtag, int32_t sigtype, const void * sig, size_t siglen)
1182 if (ts->sig && ts->sigtype)
1183 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1184 ts->sigtag = sigtag;
1185 ts->sigtype = (sig ? sigtype : 0);
1187 ts->siglen = siglen;
1192 pgpDig rpmtsDig(rpmts ts)
1194 /* FIX: hide lazy malloc for now */
1195 if (ts->dig == NULL)
1196 ts->dig = pgpNewDig();
1197 if (ts->dig == NULL)
1202 pgpDigParams rpmtsSignature(const rpmts ts)
1204 pgpDig dig = rpmtsDig(ts);
1205 if (dig == NULL) return NULL;
1206 return &dig->signature;
1209 pgpDigParams rpmtsPubkey(const rpmts ts)
1211 pgpDig dig = rpmtsDig(ts);
1212 if (dig == NULL) return NULL;
1213 return &dig->pubkey;
1216 rpmdb rpmtsGetRdb(rpmts ts)
1225 int rpmtsInitDSI(const rpmts ts)
1227 rpmDiskSpaceInfo dsi;
1232 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1235 rpmlog(RPMLOG_DEBUG, _("mounted filesystems:\n"));
1236 rpmlog(RPMLOG_DEBUG,
1237 _(" i dev bsize bavail iavail mount point\n"));
1239 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1240 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1243 /* Get available space on mounted file systems. */
1245 ts->dsi = _free(ts->dsi);
1246 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1251 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1252 #if STATFS_IN_SYS_STATVFS
1254 memset(&sfb, 0, sizeof(sfb));
1255 rc = statvfs(ts->filesystems[i], &sfb);
1258 memset(&sfb, 0, sizeof(sfb));
1260 /* This platform has the 4-argument version of the statfs call. The last two
1261 * should be the size of struct statfs and 0, respectively. The 0 is the
1262 * filesystem type, and is always 0 when statfs is called on a mounted
1263 * filesystem, as we're doing.
1265 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1267 rc = statfs(ts->filesystems[i], &sfb);
1273 rc = stat(ts->filesystems[i], &sb);
1276 dsi->dev = sb.st_dev;
1278 dsi->bsize = sfb.f_bsize;
1281 #ifdef STATFS_HAS_F_BAVAIL
1282 dsi->bavail = sfb.f_bavail;
1284 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1285 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1286 * it's about all we can do.
1288 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1290 /* XXX Avoid FAT and other file systems that have not inodes. */
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. */