3 * Routine(s) to handle a "rpmts" transaction sets.
7 #include <rpm/rpmtag.h>
8 #include <rpm/rpmlib.h> /* rpmReadPackage etc */
9 #include <rpm/rpmurl.h>
10 #include "rpmio/digest.h"
11 #include <rpm/rpmmacro.h>
12 #include <rpm/rpmfileutil.h> /* rpmtsOpenDB() needs rpmGetPath */
13 #include <rpm/rpmstring.h>
15 #include <rpm/rpmdb.h>
16 #include <rpm/rpmal.h>
17 #include <rpm/rpmds.h>
18 #include <rpm/rpmfi.h>
19 #include <rpm/rpmlog.h>
20 #include <rpm/rpmte.h>
22 #include "lib/rpmlock.h"
23 #include "lib/rpmts_internal.h"
25 /* XXX FIXME: merge with existing (broken?) tests in system.h */
26 /* portability fiddles */
27 #if STATFS_IN_SYS_STATVFS
28 #include <sys/statvfs.h>
31 # if STATFS_IN_SYS_VFS
34 # if STATFS_IN_SYS_MOUNT
35 # include <sys/mount.h>
37 # if STATFS_IN_SYS_STATFS
38 # include <sys/statfs.h>
50 rpmts rpmtsUnlink(rpmts ts, const char * msg)
53 fprintf(stderr, "--> ts %p -- %d %s\n", ts, ts->nrefs, msg);
58 rpmts rpmtsLink(rpmts ts, const char * msg)
62 fprintf(stderr, "--> ts %p ++ %d %s\n", ts, ts->nrefs, msg);
66 int rpmtsCloseDB(rpmts ts)
70 if (ts->rdb != NULL) {
71 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
72 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
73 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
74 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
75 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
76 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
77 rc = rpmdbClose(ts->rdb);
83 int rpmtsOpenDB(rpmts ts, int dbmode)
87 if (ts->rdb != NULL && ts->dbmode == dbmode)
90 (void) rpmtsCloseDB(ts);
92 /* XXX there's a potential db lock race here. */
95 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
97 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
99 _("cannot open Packages database in %s\n"), dn);
105 int rpmtsInitDB(rpmts ts, int dbmode)
107 void *lock = rpmtsAcquireLock(ts);
110 rc = rpmdbInit(ts->rootDir, dbmode);
115 int rpmtsGetDBMode(rpmts ts)
121 int rpmtsSetDBMode(rpmts ts, int dbmode)
124 /* mode setting only permitted on non-open db */
125 if (ts != NULL && rpmtsGetRdb(ts) == NULL) {
133 int rpmtsRebuildDB(rpmts ts)
136 void *lock = rpmtsAcquireLock(ts);
137 if (!lock) return -1;
138 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
139 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
141 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
146 int rpmtsVerifyDB(rpmts ts)
148 return rpmdbVerify(ts->rootDir);
151 static int isArch(const char * arch)
153 const char * const * av;
154 static const char * const arches[] = {
155 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", "x86_64", "amd64", "ia32e", "geode",
156 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
157 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
158 "sparc64", "sparc64v", "sun4u",
159 "mips", "mipsel", "IP",
160 "ppc", "ppciseries", "ppcpseries",
161 "ppc64", "ppc64iseries", "ppc64pseries",
165 "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
166 "s390", "i370", "s390x",
172 for (av = arches; *av != NULL; av++) {
173 if (!strcmp(arch, *av))
179 /* keyp might no be defined. */
180 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
181 const void * keyp, size_t keylen)
183 rpmdbMatchIterator mi;
184 const char * arch = NULL;
187 if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
190 /* Parse out "N(EVR).A" tokens from a label key. */
191 if (rpmtag == RPMDBI_LABEL && keyp != NULL) {
192 const char * s = keyp;
194 size_t slen = strlen(s);
195 char *t = alloca(slen+1);
200 while ((c = *s++) != '\0') {
206 /* XXX Fail if nested parens. */
208 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), (const char*)keyp);
211 /* Parse explicit epoch. */
212 for (se = s; *se && xisdigit(*se); se++)
215 /* XXX skip explicit epoch's (for now) */
219 /* No Epoch: found. Convert '(' to '-' and chug. */
224 /* XXX Fail if nested parens. */
226 rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), (const char*)keyp);
229 /* Don't copy trailing ')' */
234 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), (const char*)keyp);
240 /* Is this a valid ".arch" suffix? */
241 if (t != NULL && isArch(t+1)) {
247 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
249 /* Verify header signature/digest during retrieve (if not disabled). */
250 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
251 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
253 /* Select specified arch only. */
255 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch);
259 rpmRC rpmtsFindPubkey(rpmts ts)
261 const void * sig = rpmtsSig(ts);
262 pgpDig dig = rpmtsDig(ts);
263 pgpDigParams sigp = rpmtsSignature(ts);
264 pgpDigParams pubp = rpmtsPubkey(ts);
265 rpmRC res = RPMRC_NOKEY;
266 char * pubkeysource = NULL;
269 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
273 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
274 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
275 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
278 /* Lazy free of previous pubkey if pubkey does not match this signature. */
279 if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
281 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
283 ts->pkpkt = _free(ts->pkpkt);
285 memset(ts->pksignid, 0, sizeof(ts->pksignid));
288 /* Try rpmdb keyring lookup. */
289 if (ts->pkpkt == NULL) {
292 rpmdbMatchIterator mi;
295 /* Retrieve the pubkey that matches the signature. */
296 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
297 while ((h = rpmdbNextIterator(mi)) != NULL) {
298 const char ** pubkeys;
302 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (rpm_data_t *)&pubkeys, &pc))
304 hx = rpmdbGetIteratorOffset(mi);
305 ix = rpmdbGetIteratorFileNum(mi);
307 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
309 pubkeys = headerFreeData(pubkeys, pt);
312 mi = rpmdbFreeIterator(mi);
316 sprintf(hnum, "h#%d", hx);
317 pubkeysource = xstrdup(hnum);
319 ts->pkpkt = _free(ts->pkpkt);
324 /* Try keyserver lookup. */
325 if (ts->pkpkt == NULL) {
326 char * fn = rpmExpand("%{_hkp_keyserver_query}",
327 pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
330 if (fn && *fn != '%') {
331 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
335 ts->pkpkt = _free(ts->pkpkt);
338 /* Save new pubkey in local ts keyring for delayed import. */
339 pubkeysource = xstrdup("keyserver");
344 /* Try filename from macro lookup. */
345 if (ts->pkpkt == NULL) {
346 const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
349 if (fn && *fn != '%')
350 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
353 ts->pkpkt = _free(ts->pkpkt);
356 pubkeysource = xstrdup("macro");
361 /* Was a matching pubkey found? */
362 if (ts->pkpkt == NULL || ts->pkpktlen == 0)
365 /* Retrieve parameters from pubkey packet(s). */
366 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
368 /* Do the parameters match the signature? */
369 if (sigp->pubkey_algo == pubp->pubkey_algo
371 && sigp->hash_algo == pubp->hash_algo
373 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
376 /* XXX Verify any pubkey signatures. */
378 /* Pubkey packet looks good, save the signer id. */
379 memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
382 rpmlog(RPMLOG_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
383 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
384 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
385 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
392 pubkeysource = _free(pubkeysource);
393 if (res != RPMRC_OK) {
394 ts->pkpkt = _free(ts->pkpkt);
400 rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
402 static unsigned char zeros[] =
403 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
404 const char * afmt = "%{pubkeys:armor}";
405 const char * group = "Public Keys";
406 const char * license = "pubkey";
407 const char * buildhost = "localhost";
408 rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
411 pgpDigParams pubp = NULL;
420 rpmRC rc = RPMRC_FAIL; /* assume failure */
424 if (pkt == NULL || pktlen == 0)
426 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
429 if ((enc = b64encode(pkt, pktlen, -1)) == NULL)
434 /* Build header elements. */
435 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
438 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
439 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
440 || pubp->userid == NULL)
443 v = t = xmalloc(16+1);
444 t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
446 r = t = xmalloc(8+1);
447 t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
449 n = t = xmalloc(sizeof("gpg()")+8);
450 t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
452 /* FIX: pubp->userid may be NULL */
453 u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
454 t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
456 evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
457 t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
458 t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
460 /* Check for pre-existing header. */
462 /* Build pubkey header. */
465 xx = headerAddOrAppendEntry(h, RPMTAG_PUBKEYS,
466 RPM_STRING_ARRAY_TYPE, &enc, 1);
468 d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
472 xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
473 xx = headerAddEntry(h, RPMTAG_VERSION, RPM_STRING_TYPE, v+8, 1);
474 xx = headerAddEntry(h, RPMTAG_RELEASE, RPM_STRING_TYPE, r, 1);
475 xx = headerAddEntry(h, RPMTAG_DESCRIPTION, RPM_STRING_TYPE, d, 1);
476 xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
477 xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
478 xx = headerAddEntry(h, RPMTAG_SUMMARY, RPM_STRING_TYPE, u, 1);
480 xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
482 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
483 RPM_STRING_ARRAY_TYPE, &u, 1);
484 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
485 RPM_STRING_ARRAY_TYPE, &evr, 1);
486 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
487 RPM_INT32_TYPE, &pflags, 1);
489 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
490 RPM_STRING_ARRAY_TYPE, &n, 1);
491 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
492 RPM_STRING_ARRAY_TYPE, &evr, 1);
493 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
494 RPM_INT32_TYPE, &pflags, 1);
496 xx = headerAddEntry(h, RPMTAG_RPMVERSION, RPM_STRING_TYPE, RPMVERSION, 1);
498 /* XXX W2DO: tag value inheirited from parent? */
499 xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
500 { rpm_tid_t tid = rpmtsGetTid(ts);
501 xx = headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &tid, 1);
502 /* XXX W2DO: tag value inheirited from parent? */
503 xx = headerAddEntry(h, RPMTAG_BUILDTIME, RPM_INT32_TYPE, &tid, 1);
507 /* XXX W2DO: tag value inheirited from parent? */
508 xx = headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, fn, 1);
511 /* Add header to database. */
512 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
520 dig = pgpFreeDig(dig);
532 int rpmtsCloseSDB(rpmts ts)
536 if (ts->sdb != NULL) {
537 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
538 rpmdbOp(ts->sdb, RPMDB_OP_DBGET));
539 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
540 rpmdbOp(ts->sdb, RPMDB_OP_DBPUT));
541 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
542 rpmdbOp(ts->sdb, RPMDB_OP_DBDEL));
543 rc = rpmdbClose(ts->sdb);
549 int rpmtsOpenSDB(rpmts ts, int dbmode)
551 static int has_sdbpath = -1;
554 if (ts->sdb != NULL && ts->sdbmode == dbmode)
558 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
560 /* If not configured, don't try to open. */
561 if (has_sdbpath <= 0)
564 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
566 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
568 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
569 rpmlog(RPMLOG_WARNING,
570 _("cannot open Solve database in %s\n"), dn);
573 delMacro(NULL, "_dbpath");
579 * Compare suggested package resolutions (qsort/bsearch).
580 * @param a 1st instance address
581 * @param b 2nd instance address
582 * @return result of comparison
584 static int sugcmp(const void * a, const void * b)
586 const char * astr = *(const char **)a;
587 const char * bstr = *(const char **)b;
588 return strcmp(astr, bstr);
591 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
596 rpmdbMatchIterator mi;
604 int rc = 1; /* assume not found */
607 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
614 if (ts->sdb == NULL) {
615 xx = rpmtsOpenSDB(ts, ts->sdbmode);
619 /* Look for a matching Provides: in suggested universe. */
620 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
622 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
626 while ((h = rpmdbNextIterator(mi)) != NULL) {
632 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
635 /* XXX Prefer the shortest name if given alternatives. */
638 if (headerGetEntry(h, RPMTAG_NAME, NULL, (rpm_data_t *)&hname, NULL)) {
640 hnamelen = strlen(hname);
642 if (bhnamelen > 0 && hnamelen > bhnamelen)
645 /* XXX Prefer the newest build if given alternatives. */
647 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (rpm_data_t *)&ip, NULL))
656 bhnamelen = hnamelen;
658 mi = rpmdbFreeIterator(mi);
660 /* Is there a suggested resolution? */
664 /* Format the suggestion. */
665 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
666 if (qfmt == NULL || *qfmt == '\0')
668 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
672 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
676 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
681 fd = Fopen(str, "r.ufdio");
682 if (fd == NULL || Ferror(fd)) {
683 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
692 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
698 case RPMRC_NOTTRUSTED:
702 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
704 rpmlog(RPMLOG_DEBUG, _("Adding: %s\n"), str);
706 /* XXX str memory leak */
716 rpmlog(RPMLOG_DEBUG, _("Suggesting: %s\n"), str);
717 /* If suggestion is already present, don't bother. */
718 if (ts->suggests != NULL && ts->nsuggests > 0) {
719 if (bsearch(&str, ts->suggests, ts->nsuggests,
720 sizeof(*ts->suggests), sugcmp))
724 /* Add a new (unique) suggestion. */
725 ts->suggests = xrealloc(ts->suggests,
726 sizeof(*ts->suggests) * (ts->nsuggests + 2));
727 ts->suggests[ts->nsuggests] = str;
729 ts->suggests[ts->nsuggests] = NULL;
731 if (ts->nsuggests > 1)
732 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
735 /* FIX: ts->suggests[] may be NULL */
739 int rpmtsAvailable(rpmts ts, const rpmds ds)
742 int rc = 1; /* assume not found */
744 if (ts->availablePackages == NULL)
746 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
750 /* XXX no alternatives yet */
751 if (sugkey[0] != NULL) {
752 ts->suggests = xrealloc(ts->suggests,
753 sizeof(*ts->suggests) * (ts->nsuggests + 2));
754 ts->suggests[ts->nsuggests] = sugkey[0];
757 ts->suggests[ts->nsuggests] = NULL;
759 sugkey = _free(sugkey);
760 /* FIX: ts->suggests[] may be NULL */
764 int rpmtsSetSolveCallback(rpmts ts,
765 int (*solve) (rpmts ts, rpmds key, const void * data),
766 const void * solveData)
772 ts->solveData = solveData;
777 void rpmtsPrintSuggests(rpmts ts)
779 if (ts->suggests != NULL && ts->nsuggests > 0) {
781 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
782 for (i = 0; i < ts->nsuggests; i++) {
783 const char * str = ts->suggests[i];
788 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
794 rpmps rpmtsProblems(rpmts ts)
799 ps = rpmpsLink(ts->probs, RPMDBG_M("rpmtsProblems"));
804 void rpmtsCleanProblems(rpmts ts)
806 if (ts && ts->probs) {
807 ts->probs = rpmpsFree(ts->probs);
811 void rpmtsCleanDig(rpmts ts)
813 ts->sig = headerFreeData(ts->sig, ts->sigtype);
814 ts->dig = pgpFreeDig(ts->dig);
817 void rpmtsClean(rpmts ts)
825 /* Clean up after dependency checks. */
827 while ((p = rpmtsiNext(pi, 0)) != NULL)
831 ts->addedPackages = rpmalFree(ts->addedPackages);
832 ts->numAddedPackages = 0;
834 for (i = 0; i < ts->nsuggests; i++) {
835 const char * str = ts->suggests[i];
836 ts->suggests[i] = NULL;
839 ts->suggests = _free(ts->suggests);
842 rpmtsCleanProblems(ts);
847 void rpmtsEmpty(rpmts ts)
857 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
858 ts->order[oc] = rpmteFree(ts->order[oc]);
866 ts->numRemovedPackages = 0;
870 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
872 static const unsigned int scale = (1000 * 1000);
873 if (op != NULL && op->count > 0)
874 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
876 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
877 op->usecs/scale, op->usecs%scale);
880 static void rpmtsPrintStats(rpmts ts)
882 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
884 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
885 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
886 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
887 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
888 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
889 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
890 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
891 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
892 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
893 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
894 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
895 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
896 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
897 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
898 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
899 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
900 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
903 rpmts rpmtsFree(rpmts ts)
909 return rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
913 (void) rpmtsCloseDB(ts);
915 (void) rpmtsCloseSDB(ts);
917 ts->removedPackages = _free(ts->removedPackages);
919 ts->availablePackages = rpmalFree(ts->availablePackages);
920 ts->numAvailablePackages = 0;
922 ts->dsi = _free(ts->dsi);
924 if (ts->scriptFd != NULL) {
925 ts->scriptFd = fdFree(ts->scriptFd, RPMDBG_M("rpmtsFree"));
928 ts->rootDir = _free(ts->rootDir);
929 ts->currDir = _free(ts->currDir);
931 ts->order = _free(ts->order);
932 ts->orderAlloced = 0;
934 if (ts->pkpkt != NULL)
935 ts->pkpkt = _free(ts->pkpkt);
937 memset(ts->pksignid, 0, sizeof(ts->pksignid));
942 /* Free up the memory used by the rpmtsScore */
943 ts->score = rpmtsScoreFree(ts->score);
945 (void) rpmtsUnlink(ts, RPMDBG_M("tsCreate"));
952 rpmVSFlags rpmtsVSFlags(rpmts ts)
954 rpmVSFlags vsflags = 0;
956 vsflags = ts->vsflags;
960 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
962 rpmVSFlags ovsflags = 0;
964 ovsflags = ts->vsflags;
965 ts->vsflags = vsflags;
971 * This allows us to mark transactions as being of a certain type.
972 * The three types are:
976 * RPM_TRANS_AUTOROLLBACK
978 * ROLLBACK and AUTOROLLBACK transactions should always be ran as
979 * a best effort. In particular this is important to the autorollback
980 * feature to avoid rolling back a rollback (otherwise known as
981 * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
982 * counts passed to scriptlets to be altered.
984 void rpmtsSetType(rpmts ts, rpmtsType type)
991 /* Let them know what type of transaction we are */
992 rpmtsType rpmtsGetType(rpmts ts)
1000 int rpmtsUnorderedSuccessors(rpmts ts, int first)
1002 int unorderedSuccessors = 0;
1004 unorderedSuccessors = ts->unorderedSuccessors;
1006 ts->unorderedSuccessors = first;
1008 return unorderedSuccessors;
1011 const char * rpmtsRootDir(rpmts ts)
1013 const char * rootDir = NULL;
1015 if (ts != NULL && ts->rootDir != NULL) {
1016 urltype ut = urlPath(ts->rootDir, &rootDir);
1018 case URL_IS_UNKNOWN:
1021 /* XXX these shouldn't be allowed as rootdir! */
1035 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
1040 ts->rootDir = _free(ts->rootDir);
1042 if (rootDir == NULL) {
1044 ts->rootDir = xstrdup("");
1048 rootLen = strlen(rootDir);
1050 /* Make sure that rootDir has trailing / */
1051 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
1052 char * t = alloca(rootLen + 2);
1054 (void) stpcpy( stpcpy(t, rootDir), "/");
1057 ts->rootDir = xstrdup(rootDir);
1061 const char * rpmtsCurrDir(rpmts ts)
1063 const char * currDir = NULL;
1065 currDir = ts->currDir;
1070 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
1073 ts->currDir = _free(ts->currDir);
1075 ts->currDir = xstrdup(currDir);
1079 FD_t rpmtsScriptFd(rpmts ts)
1081 FD_t scriptFd = NULL;
1083 scriptFd = ts->scriptFd;
1088 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1092 if (ts->scriptFd != NULL) {
1093 ts->scriptFd = fdFree(ts->scriptFd,
1094 RPMDBG_M("rpmtsSetScriptFd"));
1095 ts->scriptFd = NULL;
1097 if (scriptFd != NULL)
1098 ts->scriptFd = fdLink((void *)scriptFd,
1099 RPMDBG_M("rpmtsSetScriptFd"));
1103 int rpmtsSELinuxEnabled(rpmts ts)
1105 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1108 int rpmtsChrootDone(rpmts ts)
1110 return (ts != NULL ? ts->chrootDone : 0);
1113 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1115 int ochrootDone = 0;
1117 ochrootDone = ts->chrootDone;
1118 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1119 ts->chrootDone = chrootDone;
1124 rpm_tid_t rpmtsGetTid(rpmts ts)
1126 rpm_tid_t tid = -1; /* XXX -1 is time(2) error return. */
1133 rpm_tid_t rpmtsSetTid(rpmts ts, rpm_tid_t tid)
1135 rpm_tid_t otid = -1; /* XXX -1 is time(2) error return. */
1143 rpmSigTag rpmtsSigtag(const rpmts ts)
1145 rpmSigTag sigtag = 0;
1147 sigtag = ts->sigtag;
1151 rpmTagType rpmtsSigtype(const rpmts ts)
1153 rpmTagType sigtype = 0;
1155 sigtype = ts->sigtype;
1159 rpm_constdata_t rpmtsSig(const rpmts ts)
1161 rpm_constdata_t sig = NULL;
1167 size_t rpmtsSiglen(const rpmts ts)
1171 siglen = ts->siglen;
1175 int rpmtsSetSig(rpmts ts, rpmSigTag sigtag, rpmTagType sigtype,
1176 rpm_data_t sig, size_t siglen)
1179 if (ts->sig && ts->sigtype)
1180 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1181 ts->sigtag = sigtag;
1182 ts->sigtype = (sig ? sigtype : 0);
1184 ts->siglen = siglen;
1189 pgpDig rpmtsDig(rpmts ts)
1191 /* FIX: hide lazy malloc for now */
1192 if (ts->dig == NULL)
1193 ts->dig = pgpNewDig();
1194 if (ts->dig == NULL)
1199 pgpDigParams rpmtsSignature(const rpmts ts)
1201 pgpDig dig = rpmtsDig(ts);
1202 if (dig == NULL) return NULL;
1203 return &dig->signature;
1206 pgpDigParams rpmtsPubkey(const rpmts ts)
1208 pgpDig dig = rpmtsDig(ts);
1209 if (dig == NULL) return NULL;
1210 return &dig->pubkey;
1213 rpmdb rpmtsGetRdb(rpmts ts)
1222 int rpmtsInitDSI(const rpmts ts)
1224 rpmDiskSpaceInfo dsi;
1229 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1232 rpmlog(RPMLOG_DEBUG, _("mounted filesystems:\n"));
1233 rpmlog(RPMLOG_DEBUG,
1234 _(" i dev bsize bavail iavail mount point\n"));
1236 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1237 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1240 /* Get available space on mounted file systems. */
1242 ts->dsi = _free(ts->dsi);
1243 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1248 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1249 #if STATFS_IN_SYS_STATVFS
1251 memset(&sfb, 0, sizeof(sfb));
1252 rc = statvfs(ts->filesystems[i], &sfb);
1255 memset(&sfb, 0, sizeof(sfb));
1257 /* This platform has the 4-argument version of the statfs call. The last two
1258 * should be the size of struct statfs and 0, respectively. The 0 is the
1259 * filesystem type, and is always 0 when statfs is called on a mounted
1260 * filesystem, as we're doing.
1262 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1264 rc = statfs(ts->filesystems[i], &sfb);
1270 rc = stat(ts->filesystems[i], &sb);
1273 dsi->dev = sb.st_dev;
1275 dsi->bsize = sfb.f_bsize;
1278 #ifdef STATFS_HAS_F_BAVAIL
1279 dsi->bavail = sfb.f_bavail;
1281 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1282 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1283 * it's about all we can do.
1285 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1287 /* XXX Avoid FAT and other file systems that have not inodes. */
1288 /* XXX assigning negative value to unsigned type */
1289 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1291 rpmlog(RPMLOG_DEBUG, _("%5d 0x%08x %8u %12ld %12ld %s\n"),
1292 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1293 (signed long) dsi->bavail, (signed long) dsi->iavail,
1294 ts->filesystems[i]);
1299 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1300 rpm_off_t fileSize, rpm_off_t prevSize, rpm_off_t fixupSize,
1301 rpmFileAction action)
1303 rpmDiskSpaceInfo dsi;
1308 while (dsi->bsize && dsi->dev != dev)
1310 if (dsi->bsize == 0)
1316 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1323 dsi->bneeded += bneeded;
1327 * FIXME: If two packages share a file (same md5sum), and
1328 * that file is being replaced on disk, will dsi->bneeded get
1329 * adjusted twice? Quite probably!
1332 dsi->bneeded += bneeded;
1333 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1338 dsi->bneeded -= bneeded;
1346 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1349 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1351 rpmDiskSpaceInfo dsi;
1356 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1362 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1366 ps = rpmtsProblems(ts);
1367 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1369 if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1370 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1371 rpmteNEVRA(te), rpmteKey(te),
1372 ts->filesystems[i], NULL, NULL,
1373 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1376 if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1377 rpmpsAppend(ps, RPMPROB_DISKNODES,
1378 rpmteNEVRA(te), rpmteKey(te),
1379 ts->filesystems[i], NULL, NULL,
1380 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1386 void * rpmtsNotify(rpmts ts, rpmte te,
1387 rpmCallbackType what, rpm_off_t amount, rpm_off_t total)
1390 if (ts && ts->notify && te) {
1391 Header h = rpmteHeader(te);
1392 assert(!(rpmteType(te) == TR_ADDED && h == NULL));
1395 ptr = ts->notify(h, what, amount, total,
1396 rpmteKey(te), ts->notifyData);
1397 headerUnlink(h); /* undo rpmteHeader() ref */
1402 int rpmtsNElements(rpmts ts)
1405 if (ts != NULL && ts->order != NULL) {
1406 nelements = ts->orderCount;
1411 rpmte rpmtsElement(rpmts ts, int ix)
1414 if (ts != NULL && ts->order != NULL) {
1415 if (ix >= 0 && ix < ts->orderCount)
1421 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1423 return (ts != NULL ? ts->ignoreSet : 0);
1426 rpmtransFlags rpmtsFlags(rpmts ts)
1428 return (ts != NULL ? ts->transFlags : 0);
1431 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1433 rpmtransFlags otransFlags = 0;
1435 otransFlags = ts->transFlags;
1436 ts->transFlags = transFlags;
1441 rpmSpec rpmtsSpec(rpmts ts)
1446 rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
1448 rpmSpec ospec = ts->spec;
1453 rpmte rpmtsRelocateElement(rpmts ts)
1455 return ts->relocateElement;
1458 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1460 rpmte orelocateElement = ts->relocateElement;
1461 ts->relocateElement = relocateElement;
1462 return orelocateElement;
1465 rpm_color_t rpmtsColor(rpmts ts)
1467 return (ts != NULL ? ts->color : 0);
1470 rpm_color_t rpmtsSetColor(rpmts ts, rpm_color_t color)
1472 rpm_color_t ocolor = 0;
1480 rpm_color_t rpmtsPrefColor(rpmts ts)
1482 return (ts != NULL ? ts->prefcolor : 0);
1485 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1489 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1494 int rpmtsSetNotifyCallback(rpmts ts,
1495 rpmCallbackFunction notify, rpmCallbackData notifyData)
1498 ts->notify = notify;
1499 ts->notifyData = notifyData;
1504 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1508 if (nep) *nep = ts->orderCount;
1513 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1514 pi = rpmtsiInit(ts);
1515 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1516 switch (rpmteType(p)) {
1527 pi = rpmtsiFree(pi);
1532 rpmts rpmtsCreate(void)
1536 ts = xcalloc(1, sizeof(*ts));
1537 memset(&ts->ops, 0, sizeof(ts->ops));
1538 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1539 ts->type = RPMTRANS_TYPE_NORMAL;
1540 ts->filesystemCount = 0;
1541 ts->filesystems = NULL;
1544 ts->solve = rpmtsSolve;
1545 ts->solveData = NULL;
1547 ts->suggests = NULL;
1549 ts->sdbmode = O_RDONLY;
1552 ts->dbmode = O_RDONLY;
1554 ts->scriptFd = NULL;
1555 ts->tid = (rpm_tid_t) time(NULL);
1558 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1559 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1561 ts->numRemovedPackages = 0;
1562 ts->allocedRemovedPackages = ts->delta;
1563 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1564 sizeof(*ts->removedPackages));
1570 ts->selinuxEnabled = is_selinux_enabled();
1572 ts->numAddedPackages = 0;
1573 ts->addedPackages = NULL;
1575 ts->numAvailablePackages = 0;
1576 ts->availablePackages = NULL;
1578 ts->orderAlloced = 0;
1589 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1593 * We only use the score in an autorollback. So set this to
1600 return rpmtsLink(ts, RPMDBG_M("tsCreate"));
1603 /**********************
1604 * Transaction Scores *
1605 **********************/
1608 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
1614 int tranElements; /* Number of transaction elements in runningTS */
1616 rpmRC rc = RPMRC_OK; /* Assume success */
1619 rpmlog(RPMLOG_DEBUG, _("Creating transaction score board(%p, %p)\n"),
1620 runningTS, rollbackTS);
1622 /* Allocate space for score board */
1623 score = xcalloc(1, sizeof(*score));
1624 rpmlog(RPMLOG_DEBUG, _("\tScore board address: %p\n"), score);
1627 * Determine the maximum size needed for the entry list.
1628 * XXX: Today, I just get the count of rpmts elements, and allocate
1629 * an array that big. Yes this is guaranteed to waste memory.
1630 * Future updates will hopefully make this more efficient,
1631 * but for now it will work.
1633 tranElements = rpmtsNElements(runningTS);
1634 rpmlog(RPMLOG_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
1635 score->scores = xcalloc(tranElements, sizeof(score->scores));
1637 /* Initialize score entry count */
1642 * Increment through transaction elements and make sure for every
1643 * N there is an rpmtsScoreEntry.
1645 pi = rpmtsiInit(runningTS);
1646 while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
1649 /* Try to find the entry in the score list */
1650 for(i = 0; i < score->entries; i++) {
1651 se = score->scores[i];
1652 if (strcmp(rpmteN(p), se->N) == 0) {
1658 /* If we did not find the entry then allocate space for it */
1660 /* XXX p->fi->te undefined. */
1661 rpmlog(RPMLOG_DEBUG, _("\tAdding entry for %s to score board.\n"),
1663 se = xcalloc(1, sizeof(*(*(score->scores))));
1664 rpmlog(RPMLOG_DEBUG, _("\t\tEntry address: %p\n"), se);
1665 se->N = xstrdup(rpmteN(p));
1666 se->te_types = rpmteType(p);
1669 score->scores[score->entries] = se;
1672 /* We found this one, so just add the element type to the one
1675 rpmlog(RPMLOG_DEBUG, _("\tUpdating entry for %s in score board.\n"),
1677 score->scores[i]->te_types |= rpmteType(p);
1681 pi = rpmtsiFree(pi);
1684 * Attach the score to the running transaction and the autorollback
1687 runningTS->score = score;
1689 rollbackTS->score = score;
1695 rpmtsScore rpmtsScoreFree(rpmtsScore score)
1697 rpmtsScoreEntry se = NULL;
1700 rpmlog(RPMLOG_DEBUG, _("May free Score board(%p)\n"), score);
1702 /* If score is not initialized, then just return.
1703 * This is likely the case if autorollbacks are not enabled.
1705 if (score == NULL) return NULL;
1707 /* Decrement the reference count */
1710 /* Do we have any more references? If so
1713 if (score->nrefs > 0) return NULL;
1715 rpmlog(RPMLOG_DEBUG, _("\tRefcount is zero...will free\n"));
1716 /* No more references, lets clean up */
1717 /* First deallocate the score entries */
1718 for(i = 0; i < score->entries; i++) {
1719 /* Get the score for the ith entry */
1720 se = score->scores[i];
1722 /* Deallocate the score entries name */
1723 se->N = _free(se->N);
1725 /* Deallocate the score entry itself */
1729 /* Next deallocate the score entry table */
1730 score->scores = _free(score->scores);
1732 /* Finally deallocate the score itself */
1733 score = _free(score);
1739 * XXX: Do not get the score and then store it aside for later use.
1740 * we will delete it out from under you. There is no rpmtsScoreLink()
1741 * as this may be a very temporary fix for autorollbacks.
1743 rpmtsScore rpmtsGetScore(rpmts ts)
1745 if (ts == NULL) return NULL;
1750 * XXX: Do not get the score entry and then store it aside for later use.
1751 * we will delete it out from under you. There is no
1752 * rpmtsScoreEntryLink() as this may be a very temporary fix
1753 * for autorollbacks.
1754 * XXX: The scores are not sorted. This should be fixed at earliest
1755 * opportunity (i.e. when we have the whole autorollback working).
1757 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
1761 rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
1763 rpmlog(RPMLOG_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
1765 /* Try to find the entry in the score list */
1766 for(i = 0; i < score->entries; i++) {
1767 se = score->scores[i];
1768 if (strcmp(N, se->N) == 0) {
1769 rpmlog(RPMLOG_DEBUG, _("\tFound entry at address: %p\n"), se);
1775 /* XXX score->scores undefined. */