3 * Routine(s) to handle a "rpmts" transaction sets.
8 #include "rpmio/digest.h"
11 #include <rpmfileutil.h> /* rpmtsOpenDB() needs rpmGetPath */
12 #include <rpmstring.h>
19 #include "lib/rpmlock.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 char * hGetNEVR(Header h, const char ** np)
53 const char * n, * v, * r;
56 (void) headerNVR(h, &n, &v, &r);
57 NVR = t = xcalloc(1, strlen(n) + strlen(v) + strlen(r) + sizeof("--"));
68 char * hGetNEVRA(Header h, const char ** np)
70 const char * n, * v, * r, * a;
74 (void) headerNVR(h, &n, &v, &r);
75 xx = headerGetEntry(h, RPMTAG_ARCH, NULL, (void **) &a, NULL);
76 NVRA = t = xcalloc(1, strlen(n) + strlen(v) + strlen(r) + strlen(a) + sizeof("--."));
89 uint32_t hGetColor(Header h)
91 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
99 if (hge(h, RPMTAG_FILECOLORS, NULL, (void **)&fcolors, &ncolors)
100 && fcolors != NULL && ncolors > 0)
102 for (i = 0; i < ncolors; i++)
103 hcolor |= fcolors[i];
110 rpmts XrpmtsUnlink(rpmts ts, const char * msg, const char * fn, unsigned ln)
113 fprintf(stderr, "--> ts %p -- %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
118 rpmts XrpmtsLink(rpmts ts, const char * msg, const char * fn, unsigned ln)
122 fprintf(stderr, "--> ts %p ++ %d %s at %s:%u\n", ts, ts->nrefs, msg, fn, ln);
126 int rpmtsCloseDB(rpmts ts)
130 if (ts->rdb != NULL) {
131 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
132 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
133 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
134 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
135 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
136 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
137 rc = rpmdbClose(ts->rdb);
143 int rpmtsOpenDB(rpmts ts, int dbmode)
147 if (ts->rdb != NULL && ts->dbmode == dbmode)
150 (void) rpmtsCloseDB(ts);
152 /* XXX there's a potential db lock race here. */
155 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
158 dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
160 _("cannot open Packages database in %s\n"), dn);
166 int rpmtsInitDB(rpmts ts, int dbmode)
168 void *lock = rpmtsAcquireLock(ts);
171 rc = rpmdbInit(ts->rootDir, dbmode);
176 int rpmtsGetDBMode(rpmts ts)
182 int rpmtsSetDBMode(rpmts ts, int dbmode)
185 /* mode setting only permitted on non-open db */
186 if (ts != NULL && rpmtsGetRdb(ts) == NULL) {
194 int rpmtsRebuildDB(rpmts ts)
197 void *lock = rpmtsAcquireLock(ts);
198 if (!lock) return -1;
199 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
200 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
202 rc = rpmdbRebuild(ts->rootDir, NULL, NULL);
207 int rpmtsVerifyDB(rpmts ts)
209 return rpmdbVerify(ts->rootDir);
212 static int isArch(const char * arch)
215 static const char *arches[] = {
216 "i386", "i486", "i586", "i686", "athlon", "pentium3", "pentium4", "x86_64", "amd64", "ia32e",
217 "alpha", "alphaev5", "alphaev56", "alphapca56", "alphaev6", "alphaev67",
218 "sparc", "sun4", "sun4m", "sun4c", "sun4d", "sparcv8", "sparcv9", "sparcv9v",
219 "sparc64", "sparc64v", "sun4u",
220 "mips", "mipsel", "IP",
221 "ppc", "ppciseries", "ppcpseries",
222 "ppc64", "ppc64iseries", "ppc64pseries",
226 "armv3l", "armv4b", "armv4l", "armv4tl", "armv5tel", "armv5tejl", "armv6l",
227 "s390", "i370", "s390x",
233 for (av = arches; *av != NULL; av++) {
234 if (!strcmp(arch, *av))
240 /* keyp might no be defined. */
241 rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmTag rpmtag,
242 const void * keyp, size_t keylen)
244 rpmdbMatchIterator mi;
245 const char * arch = NULL;
248 if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode))
251 /* Parse out "N(EVR).A" tokens from a label key. */
252 if (rpmtag == RPMDBI_LABEL && keyp != NULL) {
253 const char * s = keyp;
255 size_t slen = strlen(s);
256 char *t = alloca(slen+1);
261 while ((c = *s++) != '\0') {
267 /* XXX Fail if nested parens. */
269 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), keyp);
272 /* Parse explicit epoch. */
273 for (se = s; *se && xisdigit(*se); se++)
276 /* XXX skip explicit epoch's (for now) */
280 /* No Epoch: found. Convert '(' to '-' and chug. */
285 /* XXX Fail if nested parens. */
287 rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), keyp);
290 /* Don't copy trailing ')' */
295 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), keyp);
301 /* Is this a valid ".arch" suffix? */
302 if (t != NULL && isArch(t+1)) {
308 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
310 /* Verify header signature/digest during retrieve (if not disabled). */
311 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
312 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
314 /* Select specified arch only. */
316 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_DEFAULT, arch);
320 rpmRC rpmtsFindPubkey(rpmts ts)
322 const void * sig = rpmtsSig(ts);
323 pgpDig dig = rpmtsDig(ts);
324 pgpDigParams sigp = rpmtsSignature(ts);
325 pgpDigParams pubp = rpmtsPubkey(ts);
326 rpmRC res = RPMRC_NOKEY;
327 const char * pubkeysource = NULL;
330 if (sig == NULL || dig == NULL || sigp == NULL || pubp == NULL)
334 fprintf(stderr, "==> find sig id %08x %08x ts pubkey id %08x %08x\n",
335 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
336 pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
339 /* Lazy free of previous pubkey if pubkey does not match this signature. */
340 if (memcmp(sigp->signid, ts->pksignid, sizeof(ts->pksignid))) {
342 fprintf(stderr, "*** free pkt %p[%d] id %08x %08x\n", ts->pkpkt, ts->pkpktlen, pgpGrab(ts->pksignid, 4), pgpGrab(ts->pksignid+4, 4));
344 ts->pkpkt = _free(ts->pkpkt);
346 memset(ts->pksignid, 0, sizeof(ts->pksignid));
349 /* Try rpmdb keyring lookup. */
350 if (ts->pkpkt == NULL) {
353 rpmdbMatchIterator mi;
356 /* Retrieve the pubkey that matches the signature. */
357 mi = rpmtsInitIterator(ts, RPMTAG_PUBKEYS, sigp->signid, sizeof(sigp->signid));
358 while ((h = rpmdbNextIterator(mi)) != NULL) {
359 const char ** pubkeys;
362 if (!headerGetEntry(h, RPMTAG_PUBKEYS, &pt, (void **)&pubkeys, &pc))
364 hx = rpmdbGetIteratorOffset(mi);
365 ix = rpmdbGetIteratorFileNum(mi);
367 || b64decode(pubkeys[ix], (void **) &ts->pkpkt, &ts->pkpktlen))
369 pubkeys = headerFreeData(pubkeys, pt);
372 mi = rpmdbFreeIterator(mi);
376 sprintf(hnum, "h#%d", hx);
377 pubkeysource = xstrdup(hnum);
379 ts->pkpkt = _free(ts->pkpkt);
384 /* Try keyserver lookup. */
385 if (ts->pkpkt == NULL) {
386 const char * fn = rpmExpand("%{_hkp_keyserver_query}",
387 pgpHexStr(sigp->signid, sizeof(sigp->signid)), NULL);
390 if (fn && *fn != '%') {
391 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
395 ts->pkpkt = _free(ts->pkpkt);
398 /* Save new pubkey in local ts keyring for delayed import. */
399 pubkeysource = xstrdup("keyserver");
404 /* Try filename from macro lookup. */
405 if (ts->pkpkt == NULL) {
406 const char * fn = rpmExpand("%{_gpg_pubkey}", NULL);
409 if (fn && *fn != '%')
410 xx = (pgpReadPkts(fn,&ts->pkpkt,&ts->pkpktlen) != PGPARMOR_PUBKEY);
413 ts->pkpkt = _free(ts->pkpkt);
416 pubkeysource = xstrdup("macro");
421 /* Was a matching pubkey found? */
422 if (ts->pkpkt == NULL || ts->pkpktlen == 0)
425 /* Retrieve parameters from pubkey packet(s). */
426 xx = pgpPrtPkts(ts->pkpkt, ts->pkpktlen, dig, 0);
428 /* Do the parameters match the signature? */
429 if (sigp->pubkey_algo == pubp->pubkey_algo
431 && sigp->hash_algo == pubp->hash_algo
433 && !memcmp(sigp->signid, pubp->signid, sizeof(sigp->signid)) )
436 /* XXX Verify any pubkey signatures. */
438 /* Pubkey packet looks good, save the signer id. */
439 memcpy(ts->pksignid, pubp->signid, sizeof(ts->pksignid));
442 rpmlog(RPMLOG_DEBUG, "========== %s pubkey id %08x %08x (%s)\n",
443 (sigp->pubkey_algo == PGPPUBKEYALGO_DSA ? "DSA" :
444 (sigp->pubkey_algo == PGPPUBKEYALGO_RSA ? "RSA" : "???")),
445 pgpGrab(sigp->signid, 4), pgpGrab(sigp->signid+4, 4),
452 pubkeysource = _free(pubkeysource);
453 if (res != RPMRC_OK) {
454 ts->pkpkt = _free(ts->pkpkt);
460 rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, ssize_t pktlen)
462 static unsigned char zeros[] =
463 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
464 const char * afmt = "%{pubkeys:armor}";
465 const char * group = "Public Keys";
466 const char * license = "pubkey";
467 const char * buildhost = "localhost";
468 int32_t pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
471 pgpDigParams pubp = NULL;
472 const char * d = NULL;
473 const char * enc = NULL;
474 const char * n = NULL;
475 const char * u = NULL;
476 const char * v = NULL;
477 const char * r = NULL;
478 const char * evr = NULL;
480 rpmRC rc = RPMRC_FAIL; /* assume failure */
484 if (pkt == NULL || pktlen <= 0)
486 if (rpmtsOpenDB(ts, (O_RDWR|O_CREAT)))
489 if ((enc = b64encode(pkt, pktlen, -1)) == NULL)
494 /* Build header elements. */
495 (void) pgpPrtPkts(pkt, pktlen, dig, 0);
498 if (!memcmp(pubp->signid, zeros, sizeof(pubp->signid))
499 || !memcmp(pubp->time, zeros, sizeof(pubp->time))
500 || pubp->userid == NULL)
503 v = t = xmalloc(16+1);
504 t = stpcpy(t, pgpHexStr(pubp->signid, sizeof(pubp->signid)));
506 r = t = xmalloc(8+1);
507 t = stpcpy(t, pgpHexStr(pubp->time, sizeof(pubp->time)));
509 n = t = xmalloc(sizeof("gpg()")+8);
510 t = stpcpy( stpcpy( stpcpy(t, "gpg("), v+8), ")");
512 /* FIX: pubp->userid may be NULL */
513 u = t = xmalloc(sizeof("gpg()")+strlen(pubp->userid));
514 t = stpcpy( stpcpy( stpcpy(t, "gpg("), pubp->userid), ")");
516 evr = t = xmalloc(sizeof("4X:-")+strlen(v)+strlen(r));
517 t = stpcpy(t, (pubp->version == 4 ? "4:" : "3:"));
518 t = stpcpy( stpcpy( stpcpy(t, v), "-"), r);
520 /* Check for pre-existing header. */
522 /* Build pubkey header. */
525 xx = headerAddOrAppendEntry(h, RPMTAG_PUBKEYS,
526 RPM_STRING_ARRAY_TYPE, &enc, 1);
528 d = headerSprintf(h, afmt, rpmTagTable, rpmHeaderFormats, NULL);
532 xx = headerAddEntry(h, RPMTAG_NAME, RPM_STRING_TYPE, "gpg-pubkey", 1);
533 xx = headerAddEntry(h, RPMTAG_VERSION, RPM_STRING_TYPE, v+8, 1);
534 xx = headerAddEntry(h, RPMTAG_RELEASE, RPM_STRING_TYPE, r, 1);
535 xx = headerAddEntry(h, RPMTAG_DESCRIPTION, RPM_STRING_TYPE, d, 1);
536 xx = headerAddEntry(h, RPMTAG_GROUP, RPM_STRING_TYPE, group, 1);
537 xx = headerAddEntry(h, RPMTAG_LICENSE, RPM_STRING_TYPE, license, 1);
538 xx = headerAddEntry(h, RPMTAG_SUMMARY, RPM_STRING_TYPE, u, 1);
540 xx = headerAddEntry(h, RPMTAG_SIZE, RPM_INT32_TYPE, &zero, 1);
542 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
543 RPM_STRING_ARRAY_TYPE, &u, 1);
544 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
545 RPM_STRING_ARRAY_TYPE, &evr, 1);
546 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
547 RPM_INT32_TYPE, &pflags, 1);
549 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDENAME,
550 RPM_STRING_ARRAY_TYPE, &n, 1);
551 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEVERSION,
552 RPM_STRING_ARRAY_TYPE, &evr, 1);
553 xx = headerAddOrAppendEntry(h, RPMTAG_PROVIDEFLAGS,
554 RPM_INT32_TYPE, &pflags, 1);
556 xx = headerAddEntry(h, RPMTAG_RPMVERSION, RPM_STRING_TYPE, RPMVERSION, 1);
558 /* XXX W2DO: tag value inheirited from parent? */
559 xx = headerAddEntry(h, RPMTAG_BUILDHOST, RPM_STRING_TYPE, buildhost, 1);
560 { int32_t tid = rpmtsGetTid(ts);
561 xx = headerAddEntry(h, RPMTAG_INSTALLTIME, RPM_INT32_TYPE, &tid, 1);
562 /* XXX W2DO: tag value inheirited from parent? */
563 xx = headerAddEntry(h, RPMTAG_BUILDTIME, RPM_INT32_TYPE, &tid, 1);
567 /* XXX W2DO: tag value inheirited from parent? */
568 xx = headerAddEntry(h, RPMTAG_SOURCERPM, RPM_STRING_TYPE, fn, 1);
571 /* Add header to database. */
572 xx = rpmdbAdd(rpmtsGetRdb(ts), rpmtsGetTid(ts), h, NULL, NULL);
580 dig = pgpFreeDig(dig);
592 int rpmtsCloseSDB(rpmts ts)
596 if (ts->sdb != NULL) {
597 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
598 rpmdbOp(ts->sdb, RPMDB_OP_DBGET));
599 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
600 rpmdbOp(ts->sdb, RPMDB_OP_DBPUT));
601 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
602 rpmdbOp(ts->sdb, RPMDB_OP_DBDEL));
603 rc = rpmdbClose(ts->sdb);
609 int rpmtsOpenSDB(rpmts ts, int dbmode)
611 static int has_sdbpath = -1;
614 if (ts->sdb != NULL && ts->sdbmode == dbmode)
618 has_sdbpath = rpmExpandNumeric("%{?_solve_dbpath:1}");
620 /* If not configured, don't try to open. */
621 if (has_sdbpath <= 0)
624 addMacro(NULL, "_dbpath", NULL, "%{_solve_dbpath}", RMIL_DEFAULT);
626 rc = rpmdbOpen(ts->rootDir, &ts->sdb, ts->sdbmode, 0644);
629 dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL);
630 rpmlog(RPMLOG_WARNING,
631 _("cannot open Solve database in %s\n"), dn);
634 delMacro(NULL, "_dbpath");
640 * Compare suggested package resolutions (qsort/bsearch).
641 * @param a 1st instance address
642 * @param b 2nd instance address
643 * @return result of comparison
645 static int sugcmp(const void * a, const void * b)
647 const char * astr = *(const char **)a;
648 const char * bstr = *(const char **)b;
649 return strcmp(astr, bstr);
652 int rpmtsSolve(rpmts ts, rpmds ds, const void * data)
657 rpmdbMatchIterator mi;
665 int rc = 1; /* assume not found */
668 if (rpmdsTagN(ds) != RPMTAG_REQUIRENAME)
675 if (ts->sdb == NULL) {
676 xx = rpmtsOpenSDB(ts, ts->sdbmode);
680 /* Look for a matching Provides: in suggested universe. */
681 rpmtag = (*keyp == '/' ? RPMTAG_BASENAMES : RPMTAG_PROVIDENAME);
683 mi = rpmdbInitIterator(ts->sdb, rpmtag, keyp, keylen);
687 while ((h = rpmdbNextIterator(mi)) != NULL) {
693 if (rpmtag == RPMTAG_PROVIDENAME && !rpmdsAnyMatchesDep(h, ds, 1))
696 /* XXX Prefer the shortest name if given alternatives. */
699 if (headerGetEntry(h, RPMTAG_NAME, NULL, (void **)&hname, NULL)) {
701 hnamelen = strlen(hname);
703 if (bhnamelen > 0 && hnamelen > bhnamelen)
706 /* XXX Prefer the newest build if given alternatives. */
708 if (headerGetEntry(h, RPMTAG_BUILDTIME, NULL, (void **)&ip, NULL))
717 bhnamelen = hnamelen;
719 mi = rpmdbFreeIterator(mi);
721 /* Is there a suggested resolution? */
725 /* Format the suggestion. */
726 qfmt = rpmExpand("%{?_solve_name_fmt}", NULL);
727 if (qfmt == NULL || *qfmt == '\0')
729 str = headerSprintf(bh, qfmt, rpmTagTable, rpmHeaderFormats, &errstr);
733 rpmlog(RPMLOG_ERR, _("incorrect format: %s\n"), errstr);
737 if (ts->transFlags & RPMTRANS_FLAG_ADDINDEPS) {
742 fd = Fopen(str, "r.ufdio");
743 if (fd == NULL || Ferror(fd)) {
744 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), str,
753 rpmrc = rpmReadPackageFile(ts, fd, str, &h);
759 case RPMRC_NOTTRUSTED:
763 !rpmtsAddInstallElement(ts, h, (fnpyKey)str, 1, NULL))
765 rpmlog(RPMLOG_DEBUG, _("Adding: %s\n"), str);
767 /* XXX str memory leak */
777 rpmlog(RPMLOG_DEBUG, _("Suggesting: %s\n"), str);
778 /* If suggestion is already present, don't bother. */
779 if (ts->suggests != NULL && ts->nsuggests > 0) {
780 if (bsearch(&str, ts->suggests, ts->nsuggests,
781 sizeof(*ts->suggests), sugcmp))
785 /* Add a new (unique) suggestion. */
786 ts->suggests = xrealloc(ts->suggests,
787 sizeof(*ts->suggests) * (ts->nsuggests + 2));
788 ts->suggests[ts->nsuggests] = str;
790 ts->suggests[ts->nsuggests] = NULL;
792 if (ts->nsuggests > 1)
793 qsort(ts->suggests, ts->nsuggests, sizeof(*ts->suggests), sugcmp);
796 /* FIX: ts->suggests[] may be NULL */
800 int rpmtsAvailable(rpmts ts, const rpmds ds)
803 int rc = 1; /* assume not found */
805 if (ts->availablePackages == NULL)
807 sugkey = rpmalAllSatisfiesDepend(ts->availablePackages, ds, NULL);
811 /* XXX no alternatives yet */
812 if (sugkey[0] != NULL) {
813 ts->suggests = xrealloc(ts->suggests,
814 sizeof(*ts->suggests) * (ts->nsuggests + 2));
815 ts->suggests[ts->nsuggests] = sugkey[0];
818 ts->suggests[ts->nsuggests] = NULL;
820 sugkey = _free(sugkey);
821 /* FIX: ts->suggests[] may be NULL */
825 int rpmtsSetSolveCallback(rpmts ts,
826 int (*solve) (rpmts ts, rpmds key, const void * data),
827 const void * solveData)
833 ts->solveData = solveData;
838 void rpmtsPrintSuggests(rpmts ts)
840 if (ts->suggests != NULL && ts->nsuggests > 0) {
842 rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
843 for (i = 0; i < ts->nsuggests; i++) {
844 const char * str = ts->suggests[i];
849 rpmlog(RPMLOG_NOTICE, "\t%s\n", str);
855 rpmps rpmtsProblems(rpmts ts)
860 ps = rpmpsLink(ts->probs, NULL);
865 void rpmtsCleanProblems(rpmts ts)
867 if (ts && ts->probs) {
868 ts->probs = rpmpsFree(ts->probs);
872 void rpmtsCleanDig(rpmts ts)
874 ts->sig = headerFreeData(ts->sig, ts->sigtype);
875 ts->dig = pgpFreeDig(ts->dig);
878 void rpmtsClean(rpmts ts)
886 /* Clean up after dependency checks. */
888 while ((p = rpmtsiNext(pi, 0)) != NULL)
892 ts->addedPackages = rpmalFree(ts->addedPackages);
893 ts->numAddedPackages = 0;
895 for (i = 0; i < ts->nsuggests; i++) {
896 const char * str = ts->suggests[i];
897 ts->suggests[i] = NULL;
900 ts->suggests = _free(ts->suggests);
903 rpmtsCleanProblems(ts);
908 void rpmtsEmpty(rpmts ts)
918 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
919 ts->order[oc] = rpmteFree(ts->order[oc]);
927 ts->numRemovedPackages = 0;
931 static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
933 static unsigned int scale = (1000 * 1000);
934 if (op != NULL && op->count > 0)
935 fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
937 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
938 op->usecs/scale, op->usecs%scale);
941 static void rpmtsPrintStats(rpmts ts)
943 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
945 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
946 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
947 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
948 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
949 rpmtsPrintStat("repackage: ", rpmtsOp(ts, RPMTS_OP_REPACKAGE));
950 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
951 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
952 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
953 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
954 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
955 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
956 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
957 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
958 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
959 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
960 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
961 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
964 rpmts rpmtsFree(rpmts ts)
970 return rpmtsUnlink(ts, "tsCreate");
974 (void) rpmtsCloseDB(ts);
976 (void) rpmtsCloseSDB(ts);
978 ts->removedPackages = _free(ts->removedPackages);
980 ts->availablePackages = rpmalFree(ts->availablePackages);
981 ts->numAvailablePackages = 0;
983 ts->dsi = _free(ts->dsi);
985 if (ts->scriptFd != NULL) {
986 ts->scriptFd = fdFree(ts->scriptFd, "rpmtsFree");
989 ts->rootDir = _free(ts->rootDir);
990 ts->currDir = _free(ts->currDir);
992 ts->order = _free(ts->order);
993 ts->orderAlloced = 0;
995 if (ts->pkpkt != NULL)
996 ts->pkpkt = _free(ts->pkpkt);
998 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1001 rpmtsPrintStats(ts);
1003 /* Free up the memory used by the rpmtsScore */
1004 ts->score = rpmtsScoreFree(ts->score);
1006 (void) rpmtsUnlink(ts, "tsCreate");
1013 rpmVSFlags rpmtsVSFlags(rpmts ts)
1015 rpmVSFlags vsflags = 0;
1017 vsflags = ts->vsflags;
1021 rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
1023 rpmVSFlags ovsflags = 0;
1025 ovsflags = ts->vsflags;
1026 ts->vsflags = vsflags;
1032 * This allows us to mark transactions as being of a certain type.
1033 * The three types are:
1036 * RPM_TRANS_ROLLBACK
1037 * RPM_TRANS_AUTOROLLBACK
1039 * ROLLBACK and AUTOROLLBACK transactions should always be ran as
1040 * a best effort. In particular this is important to the autorollback
1041 * feature to avoid rolling back a rollback (otherwise known as
1042 * dueling rollbacks (-;). AUTOROLLBACK's additionally need instance
1043 * counts passed to scriptlets to be altered.
1045 void rpmtsSetType(rpmts ts, rpmtsType type)
1052 /* Let them know what type of transaction we are */
1053 rpmtsType rpmtsGetType(rpmts ts)
1061 int rpmtsUnorderedSuccessors(rpmts ts, int first)
1063 int unorderedSuccessors = 0;
1065 unorderedSuccessors = ts->unorderedSuccessors;
1067 ts->unorderedSuccessors = first;
1069 return unorderedSuccessors;
1072 const char * rpmtsRootDir(rpmts ts)
1074 const char * rootDir = NULL;
1076 if (ts != NULL && ts->rootDir != NULL) {
1077 urltype ut = urlPath(ts->rootDir, &rootDir);
1079 case URL_IS_UNKNOWN:
1082 /* XXX these shouldn't be allowed as rootdir! */
1096 void rpmtsSetRootDir(rpmts ts, const char * rootDir)
1101 ts->rootDir = _free(ts->rootDir);
1103 if (rootDir == NULL) {
1105 ts->rootDir = xstrdup("");
1109 rootLen = strlen(rootDir);
1111 /* Make sure that rootDir has trailing / */
1112 if (!(rootLen && rootDir[rootLen - 1] == '/')) {
1113 char * t = alloca(rootLen + 2);
1115 (void) stpcpy( stpcpy(t, rootDir), "/");
1118 ts->rootDir = xstrdup(rootDir);
1122 const char * rpmtsCurrDir(rpmts ts)
1124 const char * currDir = NULL;
1126 currDir = ts->currDir;
1131 void rpmtsSetCurrDir(rpmts ts, const char * currDir)
1134 ts->currDir = _free(ts->currDir);
1136 ts->currDir = xstrdup(currDir);
1140 FD_t rpmtsScriptFd(rpmts ts)
1142 FD_t scriptFd = NULL;
1144 scriptFd = ts->scriptFd;
1149 void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
1153 if (ts->scriptFd != NULL) {
1154 ts->scriptFd = fdFree(ts->scriptFd, "rpmtsSetScriptFd");
1155 ts->scriptFd = NULL;
1157 if (scriptFd != NULL)
1158 ts->scriptFd = fdLink((void *)scriptFd, "rpmtsSetScriptFd");
1162 int rpmtsSELinuxEnabled(rpmts ts)
1164 return (ts != NULL ? (ts->selinuxEnabled > 0) : 0);
1167 int rpmtsChrootDone(rpmts ts)
1169 return (ts != NULL ? ts->chrootDone : 0);
1172 int rpmtsSetChrootDone(rpmts ts, int chrootDone)
1174 int ochrootDone = 0;
1176 ochrootDone = ts->chrootDone;
1177 rpmdbSetChrootDone(rpmtsGetRdb(ts), chrootDone);
1178 ts->chrootDone = chrootDone;
1183 int32_t rpmtsGetTid(rpmts ts)
1192 int32_t rpmtsSetTid(rpmts ts, int32_t tid)
1202 int32_t rpmtsSigtag(const rpmts ts)
1206 sigtag = ts->sigtag;
1210 int32_t rpmtsSigtype(const rpmts ts)
1212 int32_t sigtype = 0;
1214 sigtype = ts->sigtype;
1218 const void * rpmtsSig(const rpmts ts)
1220 const void * sig = NULL;
1226 int32_t rpmtsSiglen(const rpmts ts)
1230 siglen = ts->siglen;
1234 int rpmtsSetSig(rpmts ts,
1235 int32_t sigtag, int32_t sigtype, const void * sig, int32_t siglen)
1238 if (ts->sig && ts->sigtype)
1239 ts->sig = headerFreeData(ts->sig, ts->sigtype);
1240 ts->sigtag = sigtag;
1241 ts->sigtype = (sig ? sigtype : 0);
1243 ts->siglen = siglen;
1248 pgpDig rpmtsDig(rpmts ts)
1250 /* FIX: hide lazy malloc for now */
1251 if (ts->dig == NULL)
1252 ts->dig = pgpNewDig();
1253 if (ts->dig == NULL)
1258 pgpDigParams rpmtsSignature(const rpmts ts)
1260 pgpDig dig = rpmtsDig(ts);
1261 if (dig == NULL) return NULL;
1262 return &dig->signature;
1265 pgpDigParams rpmtsPubkey(const rpmts ts)
1267 pgpDig dig = rpmtsDig(ts);
1268 if (dig == NULL) return NULL;
1269 return &dig->pubkey;
1272 rpmdb rpmtsGetRdb(rpmts ts)
1281 int rpmtsInitDSI(const rpmts ts)
1283 rpmDiskSpaceInfo dsi;
1288 if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE)
1291 rpmlog(RPMLOG_DEBUG, _("mounted filesystems:\n"));
1292 rpmlog(RPMLOG_DEBUG,
1293 _(" i dev bsize bavail iavail mount point\n"));
1295 rc = rpmGetFilesystemList(&ts->filesystems, &ts->filesystemCount);
1296 if (rc || ts->filesystems == NULL || ts->filesystemCount <= 0)
1299 /* Get available space on mounted file systems. */
1301 ts->dsi = _free(ts->dsi);
1302 ts->dsi = xcalloc((ts->filesystemCount + 1), sizeof(*ts->dsi));
1307 for (i = 0; (i < ts->filesystemCount) && dsi; i++, dsi++) {
1308 #if STATFS_IN_SYS_STATVFS
1310 memset(&sfb, 0, sizeof(sfb));
1311 rc = statvfs(ts->filesystems[i], &sfb);
1314 memset(&sfb, 0, sizeof(sfb));
1316 /* This platform has the 4-argument version of the statfs call. The last two
1317 * should be the size of struct statfs and 0, respectively. The 0 is the
1318 * filesystem type, and is always 0 when statfs is called on a mounted
1319 * filesystem, as we're doing.
1321 rc = statfs(ts->filesystems[i], &sfb, sizeof(sfb), 0);
1323 rc = statfs(ts->filesystems[i], &sfb);
1329 rc = stat(ts->filesystems[i], &sb);
1332 dsi->dev = sb.st_dev;
1334 dsi->bsize = sfb.f_bsize;
1337 #ifdef STATFS_HAS_F_BAVAIL
1338 dsi->bavail = sfb.f_bavail;
1340 /* FIXME: the statfs struct doesn't have a member to tell how many blocks are
1341 * available for non-superusers. f_blocks - f_bfree is probably too big, but
1342 * it's about all we can do.
1344 dsi->bavail = sfb.f_blocks - sfb.f_bfree;
1346 /* XXX Avoid FAT and other file systems that have not inodes. */
1347 dsi->iavail = !(sfb.f_ffree == 0 && sfb.f_files == 0)
1349 rpmlog(RPMLOG_DEBUG, _("%5d 0x%08x %8u %12ld %12ld %s\n"),
1350 i, (unsigned) dsi->dev, (unsigned) dsi->bsize,
1351 (signed long) dsi->bavail, (signed long) dsi->iavail,
1352 ts->filesystems[i]);
1357 void rpmtsUpdateDSI(const rpmts ts, dev_t dev,
1358 uint32_t fileSize, uint32_t prevSize, uint32_t fixupSize,
1359 rpmFileAction action)
1361 rpmDiskSpaceInfo dsi;
1366 while (dsi->bsize && dsi->dev != dev)
1368 if (dsi->bsize == 0)
1374 bneeded = BLOCK_ROUND(fileSize, dsi->bsize);
1381 dsi->bneeded += bneeded;
1385 * FIXME: If two packages share a file (same md5sum), and
1386 * that file is being replaced on disk, will dsi->bneeded get
1387 * adjusted twice? Quite probably!
1390 dsi->bneeded += bneeded;
1391 dsi->bneeded -= BLOCK_ROUND(prevSize, dsi->bsize);
1396 dsi->bneeded -= bneeded;
1404 dsi->bneeded -= BLOCK_ROUND(fixupSize, dsi->bsize);
1407 void rpmtsCheckDSIProblems(const rpmts ts, const rpmte te)
1409 rpmDiskSpaceInfo dsi;
1414 if (ts->filesystems == NULL || ts->filesystemCount <= 0)
1420 fc = rpmfiFC( rpmteFI(te, RPMTAG_BASENAMES) );
1424 ps = rpmtsProblems(ts);
1425 for (i = 0; i < ts->filesystemCount; i++, dsi++) {
1427 if (dsi->bavail >= 0 && adj_fs_blocks(dsi->bneeded) > dsi->bavail) {
1428 rpmpsAppend(ps, RPMPROB_DISKSPACE,
1429 rpmteNEVRA(te), rpmteKey(te),
1430 ts->filesystems[i], NULL, NULL,
1431 (adj_fs_blocks(dsi->bneeded) - dsi->bavail) * dsi->bsize);
1434 if (dsi->iavail >= 0 && adj_fs_blocks(dsi->ineeded) > dsi->iavail) {
1435 rpmpsAppend(ps, RPMPROB_DISKNODES,
1436 rpmteNEVRA(te), rpmteKey(te),
1437 ts->filesystems[i], NULL, NULL,
1438 (adj_fs_blocks(dsi->ineeded) - dsi->iavail));
1444 void * rpmtsNotify(rpmts ts, rpmte te,
1445 rpmCallbackType what, unsigned long amount, unsigned long total)
1448 if (ts && ts->notify && te) {
1449 Header h = rpmteHeader(te);
1450 assert(!(rpmteType(te) == TR_ADDED && h == NULL));
1453 ptr = ts->notify(h, what, amount, total,
1454 rpmteKey(te), ts->notifyData);
1455 headerUnlink(h); /* undo rpmteHeader() ref */
1460 int rpmtsNElements(rpmts ts)
1463 if (ts != NULL && ts->order != NULL) {
1464 nelements = ts->orderCount;
1469 rpmte rpmtsElement(rpmts ts, int ix)
1472 if (ts != NULL && ts->order != NULL) {
1473 if (ix >= 0 && ix < ts->orderCount)
1479 rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
1481 return (ts != NULL ? ts->ignoreSet : 0);
1484 rpmtransFlags rpmtsFlags(rpmts ts)
1486 return (ts != NULL ? ts->transFlags : 0);
1489 rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
1491 rpmtransFlags otransFlags = 0;
1493 otransFlags = ts->transFlags;
1494 ts->transFlags = transFlags;
1499 rpmSpec rpmtsSpec(rpmts ts)
1504 rpmSpec rpmtsSetSpec(rpmts ts, rpmSpec spec)
1506 rpmSpec ospec = ts->spec;
1511 rpmte rpmtsRelocateElement(rpmts ts)
1513 return ts->relocateElement;
1516 rpmte rpmtsSetRelocateElement(rpmts ts, rpmte relocateElement)
1518 rpmte orelocateElement = ts->relocateElement;
1519 ts->relocateElement = relocateElement;
1520 return orelocateElement;
1523 uint32_t rpmtsColor(rpmts ts)
1525 return (ts != NULL ? ts->color : 0);
1528 uint32_t rpmtsSetColor(rpmts ts, uint32_t color)
1530 uint32_t ocolor = 0;
1538 uint32_t rpmtsPrefColor(rpmts ts)
1540 return (ts != NULL ? ts->prefcolor : 0);
1543 rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
1547 if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX)
1552 int rpmtsSetNotifyCallback(rpmts ts,
1553 rpmCallbackFunction notify, rpmCallbackData notifyData)
1556 ts->notify = notify;
1557 ts->notifyData = notifyData;
1562 int rpmtsGetKeys(const rpmts ts, fnpyKey ** ep, int * nep)
1566 if (nep) *nep = ts->orderCount;
1571 *ep = e = xmalloc(ts->orderCount * sizeof(*e));
1572 pi = rpmtsiInit(ts);
1573 while ((p = rpmtsiNext(pi, 0)) != NULL) {
1574 switch (rpmteType(p)) {
1585 pi = rpmtsiFree(pi);
1590 rpmts rpmtsCreate(void)
1594 ts = xcalloc(1, sizeof(*ts));
1595 memset(&ts->ops, 0, sizeof(ts->ops));
1596 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1597 ts->type = RPMTRANS_TYPE_NORMAL;
1598 ts->filesystemCount = 0;
1599 ts->filesystems = NULL;
1602 ts->solve = rpmtsSolve;
1603 ts->solveData = NULL;
1605 ts->suggests = NULL;
1607 ts->sdbmode = O_RDONLY;
1610 ts->dbmode = O_RDONLY;
1612 ts->scriptFd = NULL;
1613 ts->tid = (int32_t) time(NULL);
1616 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1617 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1619 ts->numRemovedPackages = 0;
1620 ts->allocedRemovedPackages = ts->delta;
1621 ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
1622 sizeof(*ts->removedPackages));
1628 ts->selinuxEnabled = is_selinux_enabled();
1630 ts->numAddedPackages = 0;
1631 ts->addedPackages = NULL;
1633 ts->numAvailablePackages = 0;
1634 ts->availablePackages = NULL;
1636 ts->orderAlloced = 0;
1647 memset(ts->pksignid, 0, sizeof(ts->pksignid));
1651 * We only use the score in an autorollback. So set this to
1658 return rpmtsLink(ts, "tsCreate");
1661 /**********************
1662 * Transaction Scores *
1663 **********************/
1666 rpmRC rpmtsScoreInit(rpmts runningTS, rpmts rollbackTS)
1672 int tranElements; /* Number of transaction elements in runningTS */
1674 rpmRC rc = RPMRC_OK; /* Assume success */
1677 rpmlog(RPMLOG_DEBUG, _("Creating transaction score board(%p, %p)\n"),
1678 runningTS, rollbackTS);
1680 /* Allocate space for score board */
1681 score = xcalloc(1, sizeof(*score));
1682 rpmlog(RPMLOG_DEBUG, _("\tScore board address: %p\n"), score);
1685 * Determine the maximum size needed for the entry list.
1686 * XXX: Today, I just get the count of rpmts elements, and allocate
1687 * an array that big. Yes this is guaranteed to waste memory.
1688 * Future updates will hopefully make this more efficient,
1689 * but for now it will work.
1691 tranElements = rpmtsNElements(runningTS);
1692 rpmlog(RPMLOG_DEBUG, _("\tAllocating space for %d entries\n"), tranElements);
1693 score->scores = xcalloc(tranElements, sizeof(score->scores));
1695 /* Initialize score entry count */
1700 * Increment through transaction elements and make sure for every
1701 * N there is an rpmtsScoreEntry.
1703 pi = rpmtsiInit(runningTS);
1704 while ((p = rpmtsiNext(pi, TR_ADDED|TR_REMOVED)) != NULL) {
1707 /* Try to find the entry in the score list */
1708 for(i = 0; i < score->entries; i++) {
1709 se = score->scores[i];
1710 if (strcmp(rpmteN(p), se->N) == 0) {
1716 /* If we did not find the entry then allocate space for it */
1718 /* XXX p->fi->te undefined. */
1719 rpmlog(RPMLOG_DEBUG, _("\tAdding entry for %s to score board.\n"),
1721 se = xcalloc(1, sizeof(*(*(score->scores))));
1722 rpmlog(RPMLOG_DEBUG, _("\t\tEntry address: %p\n"), se);
1723 se->N = xstrdup(rpmteN(p));
1724 se->te_types = rpmteType(p);
1727 score->scores[score->entries] = se;
1730 /* We found this one, so just add the element type to the one
1733 rpmlog(RPMLOG_DEBUG, _("\tUpdating entry for %s in score board.\n"),
1735 score->scores[i]->te_types |= rpmteType(p);
1739 pi = rpmtsiFree(pi);
1742 * Attach the score to the running transaction and the autorollback
1745 runningTS->score = score;
1747 rollbackTS->score = score;
1753 rpmtsScore rpmtsScoreFree(rpmtsScore score)
1755 rpmtsScoreEntry se = NULL;
1758 rpmlog(RPMLOG_DEBUG, _("May free Score board(%p)\n"), score);
1760 /* If score is not initialized, then just return.
1761 * This is likely the case if autorollbacks are not enabled.
1763 if (score == NULL) return NULL;
1765 /* Decrement the reference count */
1768 /* Do we have any more references? If so
1771 if (score->nrefs > 0) return NULL;
1773 rpmlog(RPMLOG_DEBUG, _("\tRefcount is zero...will free\n"));
1774 /* No more references, lets clean up */
1775 /* First deallocate the score entries */
1776 for(i = 0; i < score->entries; i++) {
1777 /* Get the score for the ith entry */
1778 se = score->scores[i];
1780 /* Deallocate the score entries name */
1781 se->N = _free(se->N);
1783 /* Deallocate the score entry itself */
1787 /* Next deallocate the score entry table */
1788 score->scores = _free(score->scores);
1790 /* Finally deallocate the score itself */
1791 score = _free(score);
1797 * XXX: Do not get the score and then store it aside for later use.
1798 * we will delete it out from under you. There is no rpmtsScoreLink()
1799 * as this may be a very temporary fix for autorollbacks.
1801 rpmtsScore rpmtsGetScore(rpmts ts)
1803 if (ts == NULL) return NULL;
1808 * XXX: Do not get the score entry and then store it aside for later use.
1809 * we will delete it out from under you. There is no
1810 * rpmtsScoreEntryLink() as this may be a very temporary fix
1811 * for autorollbacks.
1812 * XXX: The scores are not sorted. This should be fixed at earliest
1813 * opportunity (i.e. when we have the whole autorollback working).
1815 rpmtsScoreEntry rpmtsScoreGetEntry(rpmtsScore score, const char *N)
1819 rpmtsScoreEntry ret = NULL; /* Assume we don't find it */
1821 rpmlog(RPMLOG_DEBUG, _("Looking in score board(%p) for %s\n"), score, N);
1823 /* Try to find the entry in the score list */
1824 for(i = 0; i < score->entries; i++) {
1825 se = score->scores[i];
1826 if (strcmp(N, se->N) == 0) {
1827 rpmlog(RPMLOG_DEBUG, _("\tFound entry at address: %p\n"), se);
1833 /* XXX score->scores undefined. */