/** \ingroup rpmdep * \file lib/rpmts.c * Routine(s) to handle a "rpmts" transaction sets. */ #include "system.h" #include #include #include #include /* rpmReadPackage etc */ #include #include /* rpmtsOpenDB() needs rpmGetPath */ #include #include #include #include #include #include #include #include #include #include "rpmio/digest.h" #include "lib/rpmal.h" #include "lib/rpmchroot.h" #include "lib/rpmplugins.h" #include "lib/rpmts_internal.h" #include "lib/rpmte_internal.h" #include "lib/misc.h" #include "lib/rpmtriggers.h" #include "debug.h" /** * Iterator across transaction elements, forward on install, backward on erase. */ struct rpmtsi_s { rpmts ts; /*!< transaction set. */ int oc; /*!< iterator index. */ }; struct rpmtxn_s { rpmlock lock; /* transaction lock */ rpmtxnFlags flags; /* transaction flags */ rpmts ts; /* parent transaction set reference */ }; static void loadKeyring(rpmts ts); int _rpmts_stats = 0; static rpmts rpmtsUnlink(rpmts ts) { if (ts) ts->nrefs--; return NULL; } rpmts rpmtsLink(rpmts ts) { if (ts) ts->nrefs++; return ts; } int rpmtsCloseDB(rpmts ts) { int rc = 0; if (ts->rdb != NULL) { (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET), rpmdbOp(ts->rdb, RPMDB_OP_DBGET)); (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT), rpmdbOp(ts->rdb, RPMDB_OP_DBPUT)); (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL), rpmdbOp(ts->rdb, RPMDB_OP_DBDEL)); rc = rpmdbClose(ts->rdb); ts->rdb = NULL; } return rc; } int rpmtsOpenDB(rpmts ts, int dbmode) { int rc = 0; if (ts->rdb != NULL && ts->dbmode == dbmode) return 0; (void) rpmtsCloseDB(ts); /* XXX there's a potential db lock race here. */ ts->dbmode = dbmode; rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644); if (rc) { char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL); rpmlog(RPMLOG_ERR, _("cannot open Packages database in %s\n"), dn); free(dn); } return rc; } int rpmtsSuspendResumeDBLock(rpmts ts, int mode) { return 0;//rpmdbSuspendResumeDBLock(ts->rdb, mode); } int rpmtsInitDB(rpmts ts, int dbmode) { rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE); int rc = -1; if (txn) rc = rpmdbInit(ts->rootDir, dbmode); rpmtxnEnd(txn); return rc; } int rpmtsGetDBMode(rpmts ts) { assert(ts != NULL); return (ts->dbmode); } int rpmtsSetDBMode(rpmts ts, int dbmode) { int rc = 1; /* mode setting only permitted on non-open db */ if (ts != NULL && rpmtsGetRdb(ts) == NULL) { ts->dbmode = dbmode; rc = 0; } return rc; } int rpmtsRebuildDB(rpmts ts) { int rc = -1; rpmtxn txn = NULL; /* Cannot do this on a populated transaction set */ if (rpmtsNElements(ts) > 0) return -1; txn = rpmtxnBegin(ts, RPMTXN_WRITE); if (txn) { if (!(ts->vsflags & RPMVSF_NOHDRCHK)) rc = rpmdbRebuild(ts->rootDir, ts, headerCheck); else rc = rpmdbRebuild(ts->rootDir, NULL, NULL); rpmtxnEnd(txn); } return rc; } int rpmtsVerifyDB(rpmts ts) { int rc = -1; rpmtxn txn = rpmtxnBegin(ts, RPMTXN_READ); if (txn) { rc = rpmdbVerify(ts->rootDir); rpmtxnEnd(txn); } return rc; } /* keyp might no be defined. */ rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag, const void * keyp, size_t keylen) { rpmdbMatchIterator mi = NULL; char *tmp = NULL; if (ts == NULL) return NULL; if (ts && ts->keyring == NULL) loadKeyring(ts); if (ts->rdb == NULL && rpmtsOpenDB(ts, ts->dbmode)) return NULL; /* Parse out "N(EVR)" tokens from a label key if present */ if (rpmtag == RPMDBI_LABEL && keyp != NULL && strchr(keyp, '(')) { const char *se, *s = keyp; char *t; size_t slen = strlen(s); int level = 0; int c; tmp = xmalloc(slen+1); keyp = t = tmp; while ((c = *s++) != '\0') { switch (c) { default: *t++ = c; break; case '(': /* XXX Fail if nested parens. */ if (level++ != 0) { rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n"), (const char*)keyp); goto exit; } /* Parse explicit epoch. */ for (se = s; *se && risdigit(*se); se++) {}; if (*se == ':') { /* XXX skip explicit epoch's (for now) */ *t++ = '-'; s = se + 1; } else { /* No Epoch: found. Convert '(' to '-' and chug. */ *t++ = '-'; } break; case ')': /* XXX Fail if nested parens. */ if (--level != 0) { rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n"), (const char*)keyp); goto exit; } /* Don't copy trailing ')' */ break; } } if (level) { rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n"), (const char*)keyp); goto exit; } *t = '\0'; } mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen); /* Verify header signature/digest during retrieve (if not disabled). */ if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK)) (void) rpmdbSetHdrChk(mi, ts, headerCheck); exit: free(tmp); return mi; } rpmKeyring rpmtsGetKeyring(rpmts ts, int autoload) { rpmKeyring keyring = NULL; if (ts) { if (ts->keyring == NULL && autoload) { loadKeyring(ts); } keyring = rpmKeyringLink(ts->keyring); } return keyring; } int rpmtsSetKeyring(rpmts ts, rpmKeyring keyring) { if (ts == NULL) return -1; rpmKeyringFree(ts->keyring); ts->keyring = rpmKeyringLink(keyring); return 0; } static int loadKeyringFromFiles(rpmts ts) { ARGV_t files = NULL; /* XXX TODO: deal with chroot path issues */ char *pkpath = rpmGetPath(ts->rootDir, "%{_keyringpath}/*.key", NULL); int nkeys = 0; rpmlog(RPMLOG_DEBUG, "loading keyring from pubkeys in %s\n", pkpath); if (rpmGlob(pkpath, NULL, &files)) { rpmlog(RPMLOG_DEBUG, "couldn't find any keys in %s\n", pkpath); goto exit; } for (char **f = files; *f; f++) { int subkeysCount, i; rpmPubkey *subkeys; rpmPubkey key = rpmPubkeyRead(*f); if (!key) { rpmlog(RPMLOG_ERR, _("%s: reading of public key failed.\n"), *f); continue; } if (rpmKeyringAddKey(ts->keyring, key) == 0) { nkeys++; rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", *f); } subkeys = rpmGetSubkeys(key, &subkeysCount); rpmPubkeyFree(key); for (i = 0; i < subkeysCount; i++) { rpmPubkey subkey = subkeys[i]; if (rpmKeyringAddKey(ts->keyring, subkey) == 0) { rpmlog(RPMLOG_DEBUG, "added subkey %d of main key %s to keyring\n", i, *f); nkeys++; } rpmPubkeyFree(subkey); } free(subkeys); } exit: free(pkpath); argvFree(files); return nkeys; } static int loadKeyringFromDB(rpmts ts) { Header h; rpmdbMatchIterator mi; int nkeys = 0; rpmlog(RPMLOG_DEBUG, "loading keyring from rpmdb\n"); mi = rpmtsInitIterator(ts, RPMDBI_NAME, "gpg-pubkey", 0); while ((h = rpmdbNextIterator(mi)) != NULL) { struct rpmtd_s pubkeys; const char *key; if (!headerGet(h, RPMTAG_PUBKEYS, &pubkeys, HEADERGET_MINMEM)) continue; while ((key = rpmtdNextString(&pubkeys))) { uint8_t *pkt; size_t pktlen; if (rpmBase64Decode(key, (void **) &pkt, &pktlen) == 0) { rpmPubkey key = rpmPubkeyNew(pkt, pktlen); int subkeysCount, i; rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount); if (rpmKeyringAddKey(ts->keyring, key) == 0) { char *nvr = headerGetAsString(h, RPMTAG_NVR); rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", nvr); free(nvr); nkeys++; } rpmPubkeyFree(key); for (i = 0; i < subkeysCount; i++) { rpmPubkey subkey = subkeys[i]; if (rpmKeyringAddKey(ts->keyring, subkey) == 0) { char *nvr = headerGetAsString(h, RPMTAG_NVR); rpmlog(RPMLOG_DEBUG, "added subkey %d of main key %s to keyring\n", i, nvr); free(nvr); nkeys++; } rpmPubkeyFree(subkey); } free(subkeys); free(pkt); } } rpmtdFreeData(&pubkeys); } rpmdbFreeIterator(mi); return nkeys; } static void loadKeyring(rpmts ts) { /* Never load the keyring if signature checking is disabled */ if ((rpmtsVSFlags(ts) & _RPMVSF_NOSIGNATURES) != _RPMVSF_NOSIGNATURES) { ts->keyring = rpmKeyringNew(); if (loadKeyringFromFiles(ts) == 0) { if (loadKeyringFromDB(ts) > 0) { /* XXX make this a warning someday... */ rpmlog(RPMLOG_DEBUG, "Using legacy gpg-pubkey(s) from rpmdb\n"); } } } } /* Build pubkey header. */ static int makePubkeyHeader(rpmts ts, rpmPubkey key, rpmPubkey *subkeys, int subkeysCount, Header * hdrp) { Header h = headerNew(); const char * afmt = "%{pubkeys:armor}"; const char * group = "Public Keys"; const char * license = "pubkey"; const char * buildhost = "localhost"; const char * userid; rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL); uint32_t zero = 0; uint32_t keytime = 0; pgpDig dig = NULL; pgpDigParams pubp = NULL; char * d = NULL; char * enc = NULL; char * n = NULL; char * u = NULL; char * v = NULL; char * r = NULL; char * evr = NULL; int rc = -1; int i; if ((enc = rpmPubkeyBase64(key)) == NULL) goto exit; if ((dig = rpmPubkeyDig(key)) == NULL) goto exit; if ((pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY)) == NULL) goto exit; /* Build header elements. */ v = pgpHexStr(pubp->signid, sizeof(pubp->signid)); userid = pubp->userid ? pubp->userid : "none"; keytime = pubp->time; rasprintf(&n, "gpg(%s)", v+8); rasprintf(&u, "gpg(%s)", userid); rasprintf(&r, "%x", keytime); rasprintf(&evr, "%d:%s-%s", pubp->version, v, r); headerPutString(h, RPMTAG_PUBKEYS, enc); if ((d = headerFormat(h, afmt, NULL)) == NULL) goto exit; headerPutString(h, RPMTAG_NAME, "gpg-pubkey"); headerPutString(h, RPMTAG_VERSION, v+8); headerPutString(h, RPMTAG_RELEASE, r); headerPutString(h, RPMTAG_DESCRIPTION, d); headerPutString(h, RPMTAG_GROUP, group); headerPutString(h, RPMTAG_LICENSE, license); headerPutString(h, RPMTAG_SUMMARY, u); headerPutString(h, RPMTAG_PACKAGER, userid); headerPutUint32(h, RPMTAG_SIZE, &zero, 1); headerPutString(h, RPMTAG_PROVIDENAME, u); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_PROVIDENAME, n); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION); headerPutString(h, RPMTAG_BUILDHOST, buildhost); headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1); headerPutString(h, RPMTAG_SOURCERPM, "(none)"); for (i = 0; i < subkeysCount; i++) { char *v, *r, *n, *evr; pgpDigParams pgpkey; pgpkey = rpmPubkeyPgpDigParams(subkeys[i]); v = pgpHexStr(pgpkey->signid, sizeof(pgpkey->signid)); rasprintf(&n, "gpg(%s)", v+8); rasprintf(&r, "%x", pgpkey->time); rasprintf(&evr, "%d:%s-%s", pubp->version, v, r); headerPutString(h, RPMTAG_PROVIDENAME, n); headerPutString(h, RPMTAG_PROVIDEVERSION, evr); headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1); free(v); free(r); free(n); free(evr); } /* Reload the lot to immutable region and stomp sha1 digest on it */ h = headerReload(h, RPMTAG_HEADERIMMUTABLE); if (h != NULL) { char *sha1 = NULL; unsigned int blen = 0; const void *blob = headerExport(h, &blen); /* XXX FIXME: bah, this code is repeated in way too many places */ DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE); rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic)); rpmDigestUpdate(ctx, blob, blen); rpmDigestFinal(ctx, (void **)&sha1, NULL, 1); if (sha1) { headerPutString(h, RPMTAG_SHA1HEADER, sha1); *hdrp = headerLink(h); rc = 0; } free(sha1); } exit: headerFree(h); pgpFreeDig(dig); free(n); free(u); free(v); free(r); free(evr); free(enc); free(d); return rc; } rpmRC rpmtsImportHeader(rpmtxn txn, Header h, rpmFlags flags) { rpmRC rc = RPMRC_FAIL; if (txn && h && rpmtsOpenDB(txn->ts, (O_RDWR|O_CREAT)) == 0) { if (rpmdbAdd(rpmtsGetRdb(txn->ts), h) == 0) { rc = RPMRC_OK; } } return rc; } rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen) { Header h = NULL; rpmRC rc = RPMRC_FAIL; /* assume failure */ rpmPubkey pubkey = NULL; rpmPubkey *subkeys = NULL; int subkeysCount = 0; rpmVSFlags oflags = rpmtsVSFlags(ts); rpmKeyring keyring; rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE); int krc, i; if (txn == NULL) return rc; /* XXX keyring wont load if sigcheck disabled, force it temporarily */ rpmtsSetVSFlags(ts, (oflags & ~_RPMVSF_NOSIGNATURES)); keyring = rpmtsGetKeyring(ts, 1); rpmtsSetVSFlags(ts, oflags); if ((pubkey = rpmPubkeyNew(pkt, pktlen)) == NULL) goto exit; if ((subkeys = rpmGetSubkeys(pubkey, &subkeysCount)) == NULL) goto exit; krc = rpmKeyringAddKey(keyring, pubkey); if (krc < 0) goto exit; /* If we dont already have the key, make a persistent record of it */ if (krc == 0) { rpm_tid_t tid = rpmtsGetTid(ts); if (makePubkeyHeader(ts, pubkey, subkeys, subkeysCount, &h) != 0) goto exit; headerPutUint32(h, RPMTAG_INSTALLTIME, &tid, 1); headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1); /* Add header to database. */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { rc = rpmtsImportHeader(txn, h, 0); } } rc = RPMRC_OK; exit: /* Clean up. */ headerFree(h); rpmPubkeyFree(pubkey); for (i = 0; i < subkeysCount; i++) rpmPubkeyFree(subkeys[i]); free(subkeys); rpmKeyringFree(keyring); rpmtxnEnd(txn); return rc; } int rpmtsSetSolveCallback(rpmts ts, int (*solve) (rpmts ts, rpmds key, const void * data), const void * solveData) { int rc = 0; if (ts) { ts->solve = solve; ts->solveData = solveData; } return rc; } int rpmtsSolve(rpmts ts, rpmds key) { int rc = 1; /* assume not found */ if (ts && ts->solve) { rc = (*ts->solve)(ts, key, ts->solveData); } return rc; } rpmps rpmtsProblems(rpmts ts) { rpmps ps = rpmpsCreate(); rpmtsi pi = rpmtsiInit(ts); rpmte p; while ((p = rpmtsiNext(pi, 0)) != NULL) { rpmps teprobs = rpmteProblems(p); rpmpsMerge(ps, teprobs); rpmpsFree(teprobs); } rpmtsiFree(pi); /* Return NULL on no problems instead of an empty set */ if (rpmpsNumProblems(ps) == 0) { ps = rpmpsFree(ps); } return ps; } void rpmtsCleanProblems(rpmts ts) { rpmte p; rpmtsi pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) rpmteCleanProblems(p); rpmtsiFree(pi); } void rpmtsClean(rpmts ts) { rpmtsi pi; rpmte p; tsMembers tsmem = rpmtsMembers(ts); if (ts == NULL) return; /* Clean up after dependency checks. */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) rpmteCleanDS(p); rpmtsiFree(pi); tsmem->addedPackages = rpmalFree(tsmem->addedPackages); tsmem->rpmlib = rpmdsFree(tsmem->rpmlib); rpmtsCleanProblems(ts); } /* hash comparison function */ static int uintCmp(unsigned int a, unsigned int b) { return (a != b); } /* "hash"function*/ static unsigned int uintId(unsigned int a) { return a; } void rpmtsEmpty(rpmts ts) { tsMembers tsmem = rpmtsMembers(ts); if (ts == NULL) return; rpmtsClean(ts); for (int oc = 0; oc < tsmem->orderCount; oc++) { tsmem->order[oc] = rpmteFree(tsmem->order[oc]); } tsmem->orderCount = 0; /* The pool cannot be emptied, there might be references to its contents */ tsmem->pool = rpmstrPoolFree(tsmem->pool); packageHashEmpty(tsmem->removedPackages); return; } static void rpmtsPrintStat(const char * name, struct rpmop_s * op) { static const unsigned int scale = (1000 * 1000); if (op != NULL && op->count > 0) fprintf(stderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n", name, op->count, (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale, op->usecs/scale, op->usecs%scale); } static void rpmtsPrintStats(rpmts ts) { (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0); rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL)); rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK)); rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER)); rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT)); rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL)); rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE)); rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS)); rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS)); rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS)); rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST)); rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE)); rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD)); rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE)); rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET)); rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT)); rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL)); } rpmts rpmtsFree(rpmts ts) { tsMembers tsmem = rpmtsMembers(ts); if (ts == NULL) return NULL; if (ts->nrefs > 1) return rpmtsUnlink(ts); rpmtsEmpty(ts); (void) rpmtsCloseDB(ts); tsmem->removedPackages = packageHashFree(tsmem->removedPackages); tsmem->installedPackages = packageHashFree(tsmem->installedPackages); tsmem->order = _free(tsmem->order); ts->members = _free(ts->members); ts->dsi = _free(ts->dsi); if (ts->scriptFd != NULL) { ts->scriptFd = fdFree(ts->scriptFd); ts->scriptFd = NULL; } ts->rootDir = _free(ts->rootDir); ts->lockPath = _free(ts->lockPath); ts->lock = rpmlockFree(ts->lock); ts->keyring = rpmKeyringFree(ts->keyring); ts->netsharedPaths = argvFree(ts->netsharedPaths); ts->installLangs = argvFree(ts->installLangs); ts->plugins = rpmpluginsFree(ts->plugins); rpmtriggersFree(ts->trigs2run); if (_rpmts_stats) rpmtsPrintStats(ts); (void) rpmtsUnlink(ts); ts = _free(ts); return NULL; } rpmVSFlags rpmtsVSFlags(rpmts ts) { rpmVSFlags vsflags = 0; if (ts != NULL) vsflags = ts->vsflags; return vsflags; } rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags) { rpmVSFlags ovsflags = 0; if (ts != NULL) { ovsflags = ts->vsflags; ts->vsflags = vsflags; } return ovsflags; } const char * rpmtsRootDir(rpmts ts) { return ts ? ts->rootDir : NULL; } int rpmtsSetRootDir(rpmts ts, const char * rootDir) { if (ts == NULL || (rootDir && rootDir[0] != '/')) { return -1; } ts->rootDir = _free(ts->rootDir); /* Ensure clean path with a trailing slash */ ts->rootDir = rootDir ? rpmGetPath(rootDir, NULL) : xstrdup("/"); if (!rstreq(ts->rootDir, "/")) { rstrcat(&ts->rootDir, "/"); } return 0; } FD_t rpmtsScriptFd(rpmts ts) { FD_t scriptFd = NULL; if (ts != NULL) { scriptFd = ts->scriptFd; } return scriptFd; } void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd) { if (ts != NULL) { if (ts->scriptFd != NULL) { ts->scriptFd = fdFree(ts->scriptFd); ts->scriptFd = NULL; } if (scriptFd != NULL) ts->scriptFd = fdLink(scriptFd); } } rpm_tid_t rpmtsGetTid(rpmts ts) { rpm_tid_t tid = (rpm_tid_t)-1; /* XXX -1 is time(2) error return. */ if (ts != NULL) { tid = ts->tid; } return tid; } rpm_tid_t rpmtsSetTid(rpmts ts, rpm_tid_t tid) { rpm_tid_t otid = (rpm_tid_t)-1; /* XXX -1 is time(2) error return. */ if (ts != NULL) { otid = ts->tid; ts->tid = tid; } return otid; } rpmdb rpmtsGetRdb(rpmts ts) { rpmdb rdb = NULL; if (ts != NULL) { rdb = ts->rdb; } return rdb; } void * rpmtsNotify(rpmts ts, rpmte te, rpmCallbackType what, rpm_loff_t amount, rpm_loff_t total) { void * ptr = NULL; if (ts && ts->notify) { Header h = NULL; fnpyKey cbkey = NULL; if (te) { h = rpmteHeader(te); cbkey = rpmteKey(te); } ptr = ts->notify(h, what, amount, total, cbkey, ts->notifyData); if (h) { headerFree(h); /* undo rpmteHeader() ref */ } } return ptr; } int rpmtsNElements(rpmts ts) { int nelements = 0; tsMembers tsmem = rpmtsMembers(ts); if (tsmem != NULL && tsmem->order != NULL) { nelements = tsmem->orderCount; } return nelements; } rpmte rpmtsElement(rpmts ts, int ix) { rpmte te = NULL; tsMembers tsmem = rpmtsMembers(ts); if (tsmem != NULL && tsmem->order != NULL) { if (ix >= 0 && ix < tsmem->orderCount) te = tsmem->order[ix]; } return te; } rpmprobFilterFlags rpmtsFilterFlags(rpmts ts) { return (ts != NULL ? ts->ignoreSet : 0); } rpmtransFlags rpmtsFlags(rpmts ts) { return (ts != NULL ? ts->transFlags : 0); } rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags) { rpmtransFlags otransFlags = 0; if (ts != NULL) { otransFlags = ts->transFlags; ts->transFlags = transFlags; } return otransFlags; } rpm_color_t rpmtsColor(rpmts ts) { return (ts != NULL ? ts->color : 0); } rpm_color_t rpmtsSetColor(rpmts ts, rpm_color_t color) { rpm_color_t ocolor = 0; if (ts != NULL) { ocolor = ts->color; ts->color = color; } return ocolor; } rpm_color_t rpmtsPrefColor(rpmts ts) { return (ts != NULL ? ts->prefcolor : 0); } rpm_color_t rpmtsSetPrefColor(rpmts ts, rpm_color_t color) { rpm_color_t ocolor = 0; if (ts != NULL) { ocolor = ts->prefcolor; ts->prefcolor = color; } return ocolor; } rpmop rpmtsOp(rpmts ts, rpmtsOpX opx) { rpmop op = NULL; if (ts != NULL && opx >= 0 && opx < RPMTS_OP_MAX) op = ts->ops + opx; return op; } rpmPlugins rpmtsPlugins(rpmts ts) { rpmPlugins plugins = NULL; if (ts != NULL) { if (ts->plugins == NULL) ts->plugins = rpmpluginsNew(ts); plugins = ts->plugins; } return plugins; } int rpmtsSetNotifyCallback(rpmts ts, rpmCallbackFunction notify, rpmCallbackData notifyData) { if (ts != NULL) { ts->notify = notify; ts->notifyData = notifyData; } return 0; } tsMembers rpmtsMembers(rpmts ts) { return (ts != NULL) ? ts->members : NULL; } rpmstrPool rpmtsPool(rpmts ts) { tsMembers tsmem = rpmtsMembers(ts); rpmstrPool tspool = NULL; if (tsmem) { if (tsmem->pool == NULL) tsmem->pool = rpmstrPoolCreate(); tspool = tsmem->pool; } return tspool; } rpmts rpmtsCreate(void) { rpmts ts; tsMembers tsmem; ts = xcalloc(1, sizeof(*ts)); memset(&ts->ops, 0, sizeof(ts->ops)); (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1); ts->dsi = NULL; ts->solve = NULL; ts->solveData = NULL; ts->rdb = NULL; ts->dbmode = O_RDONLY; ts->scriptFd = NULL; ts->tid = (rpm_tid_t) time(NULL); ts->color = rpmExpandNumeric("%{?_transaction_color}"); ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2; ts->netsharedPaths = NULL; ts->installLangs = NULL; { char *tmp = rpmExpand("%{_netsharedpath}", NULL); if (tmp && *tmp != '%') { argvSplit(&ts->netsharedPaths, tmp, ":"); } free(tmp); tmp = rpmExpand("%{_install_langs}", NULL); if (tmp && *tmp != '%') { ARGV_t langs = NULL; argvSplit(&langs, tmp, ":"); /* If we'll be installing all languages anyway, don't bother */ for (ARGV_t l = langs; *l; l++) { if (rstreq(*l, "all")) { langs = argvFree(langs); break; } } ts->installLangs = langs; } free(tmp); } tsmem = xcalloc(1, sizeof(*ts->members)); tsmem->pool = NULL; tsmem->delta = 5; tsmem->addedPackages = NULL; tsmem->removedPackages = packageHashCreate(128, uintId, uintCmp, NULL, NULL); tsmem->installedPackages = packageHashCreate(128, uintId, uintCmp, NULL, NULL); tsmem->orderAlloced = 0; tsmem->orderCount = 0; tsmem->order = NULL; ts->members = tsmem; ts->rootDir = NULL; ts->keyring = NULL; ts->nrefs = 0; ts->plugins = NULL; ts->trigs2run = rpmtriggersCreate(10); ts->min_writes = rpmExpandNumeric("%{_minimize_writes}"); return rpmtsLink(ts); } rpmtsi rpmtsiFree(rpmtsi tsi) { /* XXX watchout: a funky recursion segfaults here iff nrefs is wrong. */ if (tsi) { tsi->ts = rpmtsFree(tsi->ts); _free(tsi); } return NULL; } rpmtsi rpmtsiInit(rpmts ts) { rpmtsi tsi = NULL; tsi = xcalloc(1, sizeof(*tsi)); tsi->ts = rpmtsLink(ts); tsi->oc = 0; return tsi; } /** * Return next transaction element. * @param tsi transaction element iterator * @return transaction element, NULL on termination */ static rpmte rpmtsiNextElement(rpmtsi tsi) { rpmte te = NULL; int oc = -1; if (tsi == NULL || tsi->ts == NULL || rpmtsNElements(tsi->ts) <= 0) return te; if (tsi->oc < rpmtsNElements(tsi->ts)) oc = tsi->oc++; if (oc != -1) te = rpmtsElement(tsi->ts, oc); return te; } rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types) { rpmte te; while ((te = rpmtsiNextElement(tsi)) != NULL) { if (types == 0 || (rpmteType(te) & types) != 0) break; } return te; } #define RPMLOCK_PATH LOCALSTATEDIR "/rpm/.rpm.lock" rpmtxn rpmtxnBegin(rpmts ts, rpmtxnFlags flags) { static const char * const rpmlock_path_default = "%{?_rpmlock_path}"; rpmtxn txn = NULL; if (ts == NULL) return NULL; if (ts->lockPath == NULL) { const char *rootDir = rpmtsRootDir(ts); char *t; if (!rootDir || rpmChrootDone()) rootDir = "/"; t = rpmGenPath(rootDir, rpmlock_path_default, NULL); if (t == NULL || *t == '\0' || *t == '%') { free(t); t = xstrdup(RPMLOCK_PATH); } ts->lockPath = xstrdup(t); (void) rpmioMkpath(dirname(t), 0755, getuid(), getgid()); free(t); } if (ts->lock == NULL) ts->lock = rpmlockNew(ts->lockPath, _("transaction")); if (rpmlockAcquire(ts->lock)) { txn = xcalloc(1, sizeof(*txn)); txn->lock = ts->lock; txn->flags = flags; txn->ts = rpmtsLink(ts); if (txn->flags & RPMTXN_WRITE) rpmsqBlock(SIG_BLOCK); } return txn; } rpmtxn rpmtxnEnd(rpmtxn txn) { if (txn) { rpmlockRelease(txn->lock); if (txn->flags & RPMTXN_WRITE) rpmsqBlock(SIG_UNBLOCK); rpmtsFree(txn->ts); free(txn); } return NULL; }