Bug Summary

File:lib/rpmts.c
Warning:line 566, column 6
Value stored to 'rc' is never read

Annotated Source Code

1/** \ingroup rpmdep
2 * \file lib/rpmts.c
3 * Routine(s) to handle a "rpmts" transaction sets.
4 */
5#include "system.h"
6
7#include <inttypes.h>
8#include <libgen.h>
9
10#include <rpm/rpmtypes.h>
11#include <rpm/rpmlib.h> /* rpmReadPackage etc */
12#include <rpm/rpmmacro.h>
13#include <rpm/rpmfileutil.h> /* rpmtsOpenDB() needs rpmGetPath */
14#include <rpm/rpmstring.h>
15#include <rpm/rpmkeyring.h>
16#include <rpm/rpmbase64.h>
17
18#include <rpm/rpmdb.h>
19#include <rpm/rpmds.h>
20#include <rpm/rpmfi.h>
21#include <rpm/rpmlog.h>
22#include <rpm/rpmsq.h>
23#include <rpm/rpmte.h>
24
25#include "rpmio/digest.h"
26#include "lib/rpmal.h"
27#include "lib/rpmchroot.h"
28#include "lib/rpmplugins.h"
29#include "lib/rpmts_internal.h"
30#include "lib/rpmte_internal.h"
31#include "lib/misc.h"
32#include "lib/rpmtriggers.h"
33
34#include "debug.h"
35
36/**
37 * Iterator across transaction elements, forward on install, backward on erase.
38 */
39struct rpmtsi_s {
40 rpmts ts; /*!< transaction set. */
41 int oc; /*!< iterator index. */
42};
43
44struct rpmtxn_s {
45 rpmlock lock; /* transaction lock */
46 rpmtxnFlags flags; /* transaction flags */
47 rpmts ts; /* parent transaction set reference */
48};
49
50static void loadKeyring(rpmts ts);
51
52int _rpmts_stats = 0;
53
54static rpmts rpmtsUnlink(rpmts ts)
55{
56 if (ts)
57 ts->nrefs--;
58 return NULL((void*)0);
59}
60
61rpmts rpmtsLink(rpmts ts)
62{
63 if (ts)
64 ts->nrefs++;
65 return ts;
66}
67
68int rpmtsCloseDB(rpmts ts)
69{
70 int rc = 0;
71
72 if (ts->rdb != NULL((void*)0)) {
73 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBGET),
74 rpmdbOp(ts->rdb, RPMDB_OP_DBGET));
75 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBPUT),
76 rpmdbOp(ts->rdb, RPMDB_OP_DBPUT));
77 (void) rpmswAdd(rpmtsOp(ts, RPMTS_OP_DBDEL),
78 rpmdbOp(ts->rdb, RPMDB_OP_DBDEL));
79 rc = rpmdbClose(ts->rdb);
80 ts->rdb = NULL((void*)0);
81 }
82 return rc;
83}
84
85int rpmtsOpenDB(rpmts ts, int dbmode)
86{
87 int rc = 0;
88
89 if (ts->rdb != NULL((void*)0) && ts->dbmode == dbmode)
90 return 0;
91
92 (void) rpmtsCloseDB(ts);
93
94 /* XXX there's a potential db lock race here. */
95
96 ts->dbmode = dbmode;
97 rc = rpmdbOpen(ts->rootDir, &ts->rdb, ts->dbmode, 0644);
98 if (rc) {
99 char * dn = rpmGetPath(ts->rootDir, "%{_dbpath}", NULL((void*)0));
100 rpmlog(RPMLOG_ERR, _("cannot open Packages database in %s\n")dcgettext ("rpm", "cannot open Packages database in %s\n", 5), dn);
101 free(dn);
102 }
103 return rc;
104}
105
106int rpmtsInitDB(rpmts ts, int dbmode)
107{
108 rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE);
109 int rc = -1;
110 if (txn)
111 rc = rpmdbInit(ts->rootDir, dbmode);
112 rpmtxnEnd(txn);
113 return rc;
114}
115
116int rpmtsGetDBMode(rpmts ts)
117{
118 assert(ts != NULL)({ if (ts != ((void*)0)) ; else __assert_fail ("ts != NULL", "rpmts.c"
, 118, __PRETTY_FUNCTION__); })
;
119 return (ts->dbmode);
120}
121
122int rpmtsSetDBMode(rpmts ts, int dbmode)
123{
124 int rc = 1;
125 /* mode setting only permitted on non-open db */
126 if (ts != NULL((void*)0) && rpmtsGetRdb(ts) == NULL((void*)0)) {
127 ts->dbmode = dbmode;
128 rc = 0;
129 }
130 return rc;
131}
132
133
134int rpmtsRebuildDB(rpmts ts)
135{
136 int rc = -1;
137 rpmtxn txn = NULL((void*)0);
138
139 /* Cannot do this on a populated transaction set */
140 if (rpmtsNElements(ts) > 0)
141 return -1;
142
143 txn = rpmtxnBegin(ts, RPMTXN_WRITE);
144 if (txn) {
145 if (!(ts->vsflags & RPMVSF_NOHDRCHK))
146 rc = rpmdbRebuild(ts->rootDir, ts, headerCheck);
147 else
148 rc = rpmdbRebuild(ts->rootDir, NULL((void*)0), NULL((void*)0));
149 rpmtxnEnd(txn);
150 }
151 return rc;
152}
153
154int rpmtsVerifyDB(rpmts ts)
155{
156 int rc = -1;
157 rpmtxn txn = rpmtxnBegin(ts, RPMTXN_READ);
158 if (txn) {
159 rc = rpmdbVerify(ts->rootDir);
160 rpmtxnEnd(txn);
161 }
162 return rc;
163}
164
165/* keyp might no be defined. */
166rpmdbMatchIterator rpmtsInitIterator(const rpmts ts, rpmDbiTagVal rpmtag,
167 const void * keyp, size_t keylen)
168{
169 rpmdbMatchIterator mi = NULL((void*)0);
170 char *tmp = NULL((void*)0);
171
172 if (ts == NULL((void*)0))
173 return NULL((void*)0);
174
175 if (ts && ts->keyring == NULL((void*)0))
176 loadKeyring(ts);
177
178 if (ts->rdb == NULL((void*)0) && rpmtsOpenDB(ts, ts->dbmode))
179 return NULL((void*)0);
180
181 /* Parse out "N(EVR)" tokens from a label key if present */
182 if (rpmtag == RPMDBI_LABEL && keyp != NULL((void*)0) && strchr(keyp, '(')) {
183 const char *se, *s = keyp;
184 char *t;
185 size_t slen = strlen(s);
186 int level = 0;
187 int c;
188
189 tmp = xmalloc(slen+1)rmalloc((slen+1));
190 keyp = t = tmp;
191 while ((c = *s++) != '\0') {
192 switch (c) {
193 default:
194 *t++ = c;
195 break;
196 case '(':
197 /* XXX Fail if nested parens. */
198 if (level++ != 0) {
199 rpmlog(RPMLOG_ERR, _("extra '(' in package label: %s\n")dcgettext ("rpm", "extra '(' in package label: %s\n", 5), (const char*)keyp);
200 goto exit;
201 }
202 /* Parse explicit epoch. */
203 for (se = s; *se && risdigit(*se); se++)
204 {};
205 if (*se == ':') {
206 /* XXX skip explicit epoch's (for now) */
207 *t++ = '-';
208 s = se + 1;
209 } else {
210 /* No Epoch: found. Convert '(' to '-' and chug. */
211 *t++ = '-';
212 }
213 break;
214 case ')':
215 /* XXX Fail if nested parens. */
216 if (--level != 0) {
217 rpmlog(RPMLOG_ERR, _("missing '(' in package label: %s\n")dcgettext ("rpm", "missing '(' in package label: %s\n", 5), (const char*)keyp);
218 goto exit;
219 }
220 /* Don't copy trailing ')' */
221 break;
222 }
223 }
224 if (level) {
225 rpmlog(RPMLOG_ERR, _("missing ')' in package label: %s\n")dcgettext ("rpm", "missing ')' in package label: %s\n", 5), (const char*)keyp);
226 goto exit;
227 }
228 *t = '\0';
229 }
230
231 mi = rpmdbInitIterator(ts->rdb, rpmtag, keyp, keylen);
232
233 /* Verify header signature/digest during retrieve (if not disabled). */
234 if (mi && !(ts->vsflags & RPMVSF_NOHDRCHK))
235 (void) rpmdbSetHdrChk(mi, ts, headerCheck);
236
237exit:
238 free(tmp);
239
240 return mi;
241}
242
243rpmKeyring rpmtsGetKeyring(rpmts ts, int autoload)
244{
245 rpmKeyring keyring = NULL((void*)0);
246 if (ts) {
247 if (ts->keyring == NULL((void*)0) && autoload) {
248 loadKeyring(ts);
249 }
250 keyring = rpmKeyringLink(ts->keyring);
251 }
252 return keyring;
253}
254
255int rpmtsSetKeyring(rpmts ts, rpmKeyring keyring)
256{
257 if (ts == NULL((void*)0))
258 return -1;
259
260 rpmKeyringFree(ts->keyring);
261 ts->keyring = rpmKeyringLink(keyring);
262 return 0;
263}
264
265static int loadKeyringFromFiles(rpmts ts)
266{
267 ARGV_t files = NULL((void*)0);
268 /* XXX TODO: deal with chroot path issues */
269 char *pkpath = rpmGetPath(ts->rootDir, "%{_keyringpath}/*.key", NULL((void*)0));
270 int nkeys = 0;
271
272 rpmlog(RPMLOG_DEBUG, "loading keyring from pubkeys in %s\n", pkpath);
273 if (rpmGlob(pkpath, NULL((void*)0), &files)) {
274 rpmlog(RPMLOG_DEBUG, "couldn't find any keys in %s\n", pkpath);
275 goto exit;
276 }
277
278 for (char **f = files; *f; f++) {
279 int subkeysCount, i;
280 rpmPubkey *subkeys;
281 rpmPubkey key = rpmPubkeyRead(*f);
282
283 if (!key) {
284 rpmlog(RPMLOG_ERR, _("%s: reading of public key failed.\n")dcgettext ("rpm", "%s: reading of public key failed.\n", 5), *f);
285 continue;
286 }
287 if (rpmKeyringAddKey(ts->keyring, key) == 0) {
288 nkeys++;
289 rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", *f);
290 }
291 subkeys = rpmGetSubkeys(key, &subkeysCount);
292 rpmPubkeyFree(key);
293
294 for (i = 0; i < subkeysCount; i++) {
295 rpmPubkey subkey = subkeys[i];
296
297 if (rpmKeyringAddKey(ts->keyring, subkey) == 0) {
298 rpmlog(RPMLOG_DEBUG,
299 "added subkey %d of main key %s to keyring\n",
300 i, *f);
301
302 nkeys++;
303 }
304 rpmPubkeyFree(subkey);
305 }
306 free(subkeys);
307 }
308exit:
309 free(pkpath);
310 argvFree(files);
311 return nkeys;
312}
313
314static int loadKeyringFromDB(rpmts ts)
315{
316 Header h;
317 rpmdbMatchIterator mi;
318 int nkeys = 0;
319
320 rpmlog(RPMLOG_DEBUG, "loading keyring from rpmdb\n");
321 mi = rpmtsInitIterator(ts, RPMDBI_NAME, "gpg-pubkey", 0);
322 while ((h = rpmdbNextIterator(mi)) != NULL((void*)0)) {
323 struct rpmtd_s pubkeys;
324 const char *key;
325
326 if (!headerGet(h, RPMTAG_PUBKEYS, &pubkeys, HEADERGET_MINMEM))
327 continue;
328
329 while ((key = rpmtdNextString(&pubkeys))) {
330 uint8_t *pkt;
331 size_t pktlen;
332
333 if (rpmBase64Decode(key, (void **) &pkt, &pktlen) == 0) {
334 rpmPubkey key = rpmPubkeyNew(pkt, pktlen);
335 int subkeysCount, i;
336 rpmPubkey *subkeys = rpmGetSubkeys(key, &subkeysCount);
337
338 if (rpmKeyringAddKey(ts->keyring, key) == 0) {
339 char *nvr = headerGetAsString(h, RPMTAG_NVR);
340 rpmlog(RPMLOG_DEBUG, "added key %s to keyring\n", nvr);
341 free(nvr);
342 nkeys++;
343 }
344 rpmPubkeyFree(key);
345
346 for (i = 0; i < subkeysCount; i++) {
347 rpmPubkey subkey = subkeys[i];
348
349 if (rpmKeyringAddKey(ts->keyring, subkey) == 0) {
350 char *nvr = headerGetAsString(h, RPMTAG_NVR);
351 rpmlog(RPMLOG_DEBUG,
352 "added subkey %d of main key %s to keyring\n",
353 i, nvr);
354
355 free(nvr);
356 nkeys++;
357 }
358 rpmPubkeyFree(subkey);
359 }
360 free(subkeys);
361 free(pkt);
362 }
363 }
364 rpmtdFreeData(&pubkeys);
365 }
366 rpmdbFreeIterator(mi);
367
368 return nkeys;
369}
370
371static void loadKeyring(rpmts ts)
372{
373 /* Never load the keyring if signature checking is disabled */
374 if ((rpmtsVSFlags(ts) & _RPMVSF_NOSIGNATURES( RPMVSF_NODSAHEADER | RPMVSF_NORSAHEADER | RPMVSF_NODSA | RPMVSF_NORSA
)
) != _RPMVSF_NOSIGNATURES( RPMVSF_NODSAHEADER | RPMVSF_NORSAHEADER | RPMVSF_NODSA | RPMVSF_NORSA
)
) {
375 ts->keyring = rpmKeyringNew();
376 if (loadKeyringFromFiles(ts) == 0) {
377 if (loadKeyringFromDB(ts) > 0) {
378 /* XXX make this a warning someday... */
379 rpmlog(RPMLOG_DEBUG, "Using legacy gpg-pubkey(s) from rpmdb\n");
380 }
381 }
382 }
383}
384
385/* Build pubkey header. */
386static int makePubkeyHeader(rpmts ts, rpmPubkey key, rpmPubkey *subkeys,
387 int subkeysCount, Header * hdrp)
388{
389 Header h = headerNew();
390 const char * afmt = "%{pubkeys:armor}";
391 const char * group = "Public Keys";
392 const char * license = "pubkey";
393 const char * buildhost = "localhost";
394 const char * userid;
395 rpmsenseFlags pflags = (RPMSENSE_KEYRING|RPMSENSE_EQUAL);
396 uint32_t zero = 0;
397 uint32_t keytime = 0;
398 pgpDig dig = NULL((void*)0);
399 pgpDigParams pubp = NULL((void*)0);
400 char * d = NULL((void*)0);
401 char * enc = NULL((void*)0);
402 char * n = NULL((void*)0);
403 char * u = NULL((void*)0);
404 char * v = NULL((void*)0);
405 char * r = NULL((void*)0);
406 char * evr = NULL((void*)0);
407 int rc = -1;
408 int i;
409
410 if ((enc = rpmPubkeyBase64(key)) == NULL((void*)0))
411 goto exit;
412 if ((dig = rpmPubkeyDig(key)) == NULL((void*)0))
413 goto exit;
414 if ((pubp = pgpDigGetParams(dig, PGPTAG_PUBLIC_KEY)) == NULL((void*)0))
415 goto exit;
416
417 /* Build header elements. */
418 v = pgpHexStr(pubp->signid, sizeof(pubp->signid));
419 userid = pubp->userid ? pubp->userid : "none";
420 keytime = pubp->time;
421
422 rasprintf(&n, "gpg(%s)", v+8);
423 rasprintf(&u, "gpg(%s)", userid);
424 rasprintf(&r, "%x", keytime);
425 rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);
426
427 headerPutString(h, RPMTAG_PUBKEYS, enc);
428
429 if ((d = headerFormat(h, afmt, NULL((void*)0))) == NULL((void*)0))
430 goto exit;
431
432 headerPutString(h, RPMTAG_NAME, "gpg-pubkey");
433 headerPutString(h, RPMTAG_VERSION, v+8);
434 headerPutString(h, RPMTAG_RELEASE, r);
435 headerPutString(h, RPMTAG_DESCRIPTION, d);
436 headerPutString(h, RPMTAG_GROUP, group);
437 headerPutString(h, RPMTAG_LICENSE, license);
438 headerPutString(h, RPMTAG_SUMMARY, u);
439 headerPutString(h, RPMTAG_PACKAGER, userid);
440
441 headerPutUint32(h, RPMTAG_SIZE, &zero, 1);
442
443 headerPutString(h, RPMTAG_PROVIDENAME, u);
444 headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
445 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
446
447 headerPutString(h, RPMTAG_PROVIDENAME, n);
448 headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
449 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
450
451 headerPutString(h, RPMTAG_RPMVERSION, RPMVERSION);
452 headerPutString(h, RPMTAG_BUILDHOST, buildhost);
453 headerPutUint32(h, RPMTAG_BUILDTIME, &keytime, 1);
454 headerPutString(h, RPMTAG_SOURCERPM, "(none)");
455
456 for (i = 0; i < subkeysCount; i++) {
457 char *v, *r, *n, *evr;
458 pgpDigParams pgpkey;
459
460 pgpkey = rpmPubkeyPgpDigParams(subkeys[i]);
461 v = pgpHexStr(pgpkey->signid, sizeof(pgpkey->signid));
462
463 rasprintf(&n, "gpg(%s)", v+8);
464 rasprintf(&r, "%x", pgpkey->time);
465 rasprintf(&evr, "%d:%s-%s", pubp->version, v, r);
466
467 headerPutString(h, RPMTAG_PROVIDENAME, n);
468 headerPutString(h, RPMTAG_PROVIDEVERSION, evr);
469 headerPutUint32(h, RPMTAG_PROVIDEFLAGS, &pflags, 1);
470
471 free(v);
472 free(r);
473 free(n);
474 free(evr);
475 }
476
477 /* Reload the lot to immutable region and stomp sha1 digest on it */
478 h = headerReload(h, RPMTAG_HEADERIMMUTABLE);
479 if (h != NULL((void*)0)) {
480 char *sha1 = NULL((void*)0);
481 unsigned int blen = 0;
482 const void *blob = headerExport(h, &blen);
483
484 /* XXX FIXME: bah, this code is repeated in way too many places */
485 DIGEST_CTX ctx = rpmDigestInit(PGPHASHALGO_SHA1, RPMDIGEST_NONE);
486 rpmDigestUpdate(ctx, rpm_header_magic, sizeof(rpm_header_magic));
487 rpmDigestUpdate(ctx, blob, blen);
488 rpmDigestFinal(ctx, (void **)&sha1, NULL((void*)0), 1);
489
490 if (sha1) {
491 headerPutString(h, RPMTAG_SHA1HEADER, sha1);
492 *hdrp = headerLink(h);
493 rc = 0;
494 }
495 free(sha1);
496 }
497
498exit:
499 headerFree(h);
500 pgpFreeDig(dig);
501 free(n);
502 free(u);
503 free(v);
504 free(r);
505 free(evr);
506 free(enc);
507 free(d);
508
509 return rc;
510}
511
512rpmRC rpmtsImportHeader(rpmtxn txn, Header h, rpmFlags flags)
513{
514 rpmRC rc = RPMRC_FAIL;
515
516 if (txn && h && rpmtsOpenDB(txn->ts, (O_RDWR02|O_CREAT0100)) == 0) {
517 if (rpmdbAdd(rpmtsGetRdb(txn->ts), h) == 0) {
518 rc = RPMRC_OK;
519 }
520 }
521 return rc;
522}
523
524rpmRC rpmtsImportPubkey(const rpmts ts, const unsigned char * pkt, size_t pktlen)
525{
526 Header h = NULL((void*)0);
527 rpmRC rc = RPMRC_FAIL; /* assume failure */
528 rpmPubkey pubkey = NULL((void*)0);
529 rpmPubkey *subkeys = NULL((void*)0);
530 int subkeysCount = 0;
531 rpmVSFlags oflags = rpmtsVSFlags(ts);
532 rpmKeyring keyring;
533 rpmtxn txn = rpmtxnBegin(ts, RPMTXN_WRITE);
534 int krc, i;
535
536 if (txn == NULL((void*)0))
537 return rc;
538
539 /* XXX keyring wont load if sigcheck disabled, force it temporarily */
540 rpmtsSetVSFlags(ts, (oflags & ~_RPMVSF_NOSIGNATURES( RPMVSF_NODSAHEADER | RPMVSF_NORSAHEADER | RPMVSF_NODSA | RPMVSF_NORSA
)
));
541 keyring = rpmtsGetKeyring(ts, 1);
542 rpmtsSetVSFlags(ts, oflags);
543
544 if ((pubkey = rpmPubkeyNew(pkt, pktlen)) == NULL((void*)0))
545 goto exit;
546
547 if ((subkeys = rpmGetSubkeys(pubkey, &subkeysCount)) == NULL((void*)0))
548 goto exit;
549
550 krc = rpmKeyringAddKey(keyring, pubkey);
551 if (krc < 0)
552 goto exit;
553
554 /* If we dont already have the key, make a persistent record of it */
555 if (krc == 0) {
556 rpm_tid_t tid = rpmtsGetTid(ts);
557
558 if (makePubkeyHeader(ts, pubkey, subkeys, subkeysCount, &h) != 0)
559 goto exit;
560
561 headerPutUint32(h, RPMTAG_INSTALLTIME, &tid, 1);
562 headerPutUint32(h, RPMTAG_INSTALLTID, &tid, 1);
563
564 /* Add header to database. */
565 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
566 rc = rpmtsImportHeader(txn, h, 0);
Value stored to 'rc' is never read
567 }
568 }
569 rc = RPMRC_OK;
570
571exit:
572 /* Clean up. */
573 headerFree(h);
574 rpmPubkeyFree(pubkey);
575 for (i = 0; i < subkeysCount; i++)
576 rpmPubkeyFree(subkeys[i]);
577 free(subkeys);
578
579 rpmKeyringFree(keyring);
580 rpmtxnEnd(txn);
581 return rc;
582}
583
584int rpmtsSetSolveCallback(rpmts ts,
585 int (*solve) (rpmts ts, rpmds key, const void * data),
586 const void * solveData)
587{
588 int rc = 0;
589
590 if (ts) {
591 ts->solve = solve;
592 ts->solveData = solveData;
593 }
594 return rc;
595}
596
597int rpmtsSolve(rpmts ts, rpmds key)
598{
599 int rc = 1; /* assume not found */
600 if (ts && ts->solve) {
601 rc = (*ts->solve)(ts, key, ts->solveData);
602 }
603 return rc;
604}
605
606rpmps rpmtsProblems(rpmts ts)
607{
608 rpmps ps = rpmpsCreate();
609 rpmtsi pi = rpmtsiInit(ts);
610 rpmte p;
611
612 while ((p = rpmtsiNext(pi, 0)) != NULL((void*)0)) {
613 rpmps teprobs = rpmteProblems(p);
614 rpmpsMerge(ps, teprobs);
615 rpmpsFree(teprobs);
616 }
617 rpmtsiFree(pi);
618
619 /* Return NULL on no problems instead of an empty set */
620 if (rpmpsNumProblems(ps) == 0) {
621 ps = rpmpsFree(ps);
622 }
623
624 return ps;
625}
626
627void rpmtsCleanProblems(rpmts ts)
628{
629 rpmte p;
630 rpmtsi pi = rpmtsiInit(ts);
631 while ((p = rpmtsiNext(pi, 0)) != NULL((void*)0))
632 rpmteCleanProblems(p);
633 rpmtsiFree(pi);
634}
635
636void rpmtsClean(rpmts ts)
637{
638 rpmtsi pi; rpmte p;
639 tsMembers tsmem = rpmtsMembers(ts);
640
641 if (ts == NULL((void*)0))
642 return;
643
644 /* Clean up after dependency checks. */
645 pi = rpmtsiInit(ts);
646 while ((p = rpmtsiNext(pi, 0)) != NULL((void*)0))
647 rpmteCleanDS(p);
648 rpmtsiFree(pi);
649
650 tsmem->addedPackages = rpmalFree(tsmem->addedPackages);
651 tsmem->rpmlib = rpmdsFree(tsmem->rpmlib);
652
653 rpmtsCleanProblems(ts);
654}
655
656/* hash comparison function */
657static int uintCmp(unsigned int a, unsigned int b)
658{
659 return (a != b);
660}
661
662/* "hash"function*/
663static unsigned int uintId(unsigned int a)
664{
665 return a;
666}
667
668void rpmtsEmpty(rpmts ts)
669{
670 tsMembers tsmem = rpmtsMembers(ts);
671 if (ts == NULL((void*)0))
672 return;
673
674 rpmtsClean(ts);
675
676 for (int oc = 0; oc < tsmem->orderCount; oc++) {
677 tsmem->order[oc] = rpmteFree(tsmem->order[oc]);
678 }
679
680 tsmem->orderCount = 0;
681 /* The pool cannot be emptied, there might be references to its contents */
682 tsmem->pool = rpmstrPoolFree(tsmem->pool);
683 packageHashEmpty(tsmem->removedPackages);
684 return;
685}
686
687static void rpmtsPrintStat(const char * name, struct rpmop_s * op)
688{
689 static const unsigned int scale = (1000 * 1000);
690 if (op != NULL((void*)0) && op->count > 0)
691 fprintf(stderrstderr, " %s %6d %6lu.%06lu MB %6lu.%06lu secs\n",
692 name, op->count,
693 (unsigned long)op->bytes/scale, (unsigned long)op->bytes%scale,
694 op->usecs/scale, op->usecs%scale);
695}
696
697static void rpmtsPrintStats(rpmts ts)
698{
699 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_TOTAL), 0);
700
701 rpmtsPrintStat("total: ", rpmtsOp(ts, RPMTS_OP_TOTAL));
702 rpmtsPrintStat("check: ", rpmtsOp(ts, RPMTS_OP_CHECK));
703 rpmtsPrintStat("order: ", rpmtsOp(ts, RPMTS_OP_ORDER));
704 rpmtsPrintStat("fingerprint: ", rpmtsOp(ts, RPMTS_OP_FINGERPRINT));
705 rpmtsPrintStat("install: ", rpmtsOp(ts, RPMTS_OP_INSTALL));
706 rpmtsPrintStat("erase: ", rpmtsOp(ts, RPMTS_OP_ERASE));
707 rpmtsPrintStat("scriptlets: ", rpmtsOp(ts, RPMTS_OP_SCRIPTLETS));
708 rpmtsPrintStat("compress: ", rpmtsOp(ts, RPMTS_OP_COMPRESS));
709 rpmtsPrintStat("uncompress: ", rpmtsOp(ts, RPMTS_OP_UNCOMPRESS));
710 rpmtsPrintStat("digest: ", rpmtsOp(ts, RPMTS_OP_DIGEST));
711 rpmtsPrintStat("signature: ", rpmtsOp(ts, RPMTS_OP_SIGNATURE));
712 rpmtsPrintStat("dbadd: ", rpmtsOp(ts, RPMTS_OP_DBADD));
713 rpmtsPrintStat("dbremove: ", rpmtsOp(ts, RPMTS_OP_DBREMOVE));
714 rpmtsPrintStat("dbget: ", rpmtsOp(ts, RPMTS_OP_DBGET));
715 rpmtsPrintStat("dbput: ", rpmtsOp(ts, RPMTS_OP_DBPUT));
716 rpmtsPrintStat("dbdel: ", rpmtsOp(ts, RPMTS_OP_DBDEL));
717}
718
719rpmts rpmtsFree(rpmts ts)
720{
721 tsMembers tsmem = rpmtsMembers(ts);
722 if (ts == NULL((void*)0))
723 return NULL((void*)0);
724
725 if (ts->nrefs > 1)
726 return rpmtsUnlink(ts);
727
728 rpmtsEmpty(ts);
729
730 (void) rpmtsCloseDB(ts);
731
732 tsmem->removedPackages = packageHashFree(tsmem->removedPackages);
733 tsmem->installedPackages = packageHashFree(tsmem->installedPackages);
734 tsmem->order = _free(tsmem->order)rfree((tsmem->order));
735 ts->members = _free(ts->members)rfree((ts->members));
736
737 ts->dsi = _free(ts->dsi)rfree((ts->dsi));
738
739 if (ts->scriptFd != NULL((void*)0)) {
740 ts->scriptFd = fdFree(ts->scriptFd);
741 ts->scriptFd = NULL((void*)0);
742 }
743 ts->rootDir = _free(ts->rootDir)rfree((ts->rootDir));
744 ts->lockPath = _free(ts->lockPath)rfree((ts->lockPath));
745 ts->lock = rpmlockFree(ts->lock);
746
747 ts->keyring = rpmKeyringFree(ts->keyring);
748 ts->netsharedPaths = argvFree(ts->netsharedPaths);
749 ts->installLangs = argvFree(ts->installLangs);
750
751 ts->plugins = rpmpluginsFree(ts->plugins);
752
753 rpmtriggersFree(ts->trigs2run);
754
755 if (_rpmts_stats)
756 rpmtsPrintStats(ts);
757
758 (void) rpmtsUnlink(ts);
759
760 ts = _free(ts)rfree((ts));
761
762 return NULL((void*)0);
763}
764
765rpmVSFlags rpmtsVSFlags(rpmts ts)
766{
767 rpmVSFlags vsflags = 0;
768 if (ts != NULL((void*)0))
769 vsflags = ts->vsflags;
770 return vsflags;
771}
772
773rpmVSFlags rpmtsSetVSFlags(rpmts ts, rpmVSFlags vsflags)
774{
775 rpmVSFlags ovsflags = 0;
776 if (ts != NULL((void*)0)) {
777 ovsflags = ts->vsflags;
778 ts->vsflags = vsflags;
779 }
780 return ovsflags;
781}
782
783const char * rpmtsRootDir(rpmts ts)
784{
785 return ts ? ts->rootDir : NULL((void*)0);
786}
787
788int rpmtsSetRootDir(rpmts ts, const char * rootDir)
789{
790 if (ts == NULL((void*)0) || (rootDir && rootDir[0] != '/')) {
791 return -1;
792 }
793
794 ts->rootDir = _free(ts->rootDir)rfree((ts->rootDir));
795 /* Ensure clean path with a trailing slash */
796 ts->rootDir = rootDir ? rpmGetPath(rootDir, NULL((void*)0)) : xstrdup("/")rstrdup(("/"));
797 if (!rstreq(ts->rootDir, "/")) {
798 rstrcat(&ts->rootDir, "/");
799 }
800 return 0;
801}
802
803FD_t rpmtsScriptFd(rpmts ts)
804{
805 FD_t scriptFd = NULL((void*)0);
806 if (ts != NULL((void*)0)) {
807 scriptFd = ts->scriptFd;
808 }
809 return scriptFd;
810}
811
812void rpmtsSetScriptFd(rpmts ts, FD_t scriptFd)
813{
814
815 if (ts != NULL((void*)0)) {
816 if (ts->scriptFd != NULL((void*)0)) {
817 ts->scriptFd = fdFree(ts->scriptFd);
818 ts->scriptFd = NULL((void*)0);
819 }
820 if (scriptFd != NULL((void*)0))
821 ts->scriptFd = fdLink(scriptFd);
822 }
823}
824
825rpm_tid_t rpmtsGetTid(rpmts ts)
826{
827 rpm_tid_t tid = (rpm_tid_t)-1; /* XXX -1 is time(2) error return. */
828 if (ts != NULL((void*)0)) {
829 tid = ts->tid;
830 }
831 return tid;
832}
833
834rpm_tid_t rpmtsSetTid(rpmts ts, rpm_tid_t tid)
835{
836 rpm_tid_t otid = (rpm_tid_t)-1; /* XXX -1 is time(2) error return. */
837 if (ts != NULL((void*)0)) {
838 otid = ts->tid;
839 ts->tid = tid;
840 }
841 return otid;
842}
843
844rpmdb rpmtsGetRdb(rpmts ts)
845{
846 rpmdb rdb = NULL((void*)0);
847 if (ts != NULL((void*)0)) {
848 rdb = ts->rdb;
849 }
850 return rdb;
851}
852
853void * rpmtsNotify(rpmts ts, rpmte te,
854 rpmCallbackType what, rpm_loff_t amount, rpm_loff_t total)
855{
856 void * ptr = NULL((void*)0);
857 if (ts && ts->notify) {
858 Header h = NULL((void*)0);
859 fnpyKey cbkey = NULL((void*)0);
860 if (te) {
861 h = rpmteHeader(te);
862 cbkey = rpmteKey(te);
863 }
864 ptr = ts->notify(h, what, amount, total, cbkey, ts->notifyData);
865
866 if (h) {
867 headerFree(h); /* undo rpmteHeader() ref */
868 }
869 }
870 return ptr;
871}
872
873int rpmtsNElements(rpmts ts)
874{
875 int nelements = 0;
876 tsMembers tsmem = rpmtsMembers(ts);
877 if (tsmem != NULL((void*)0) && tsmem->order != NULL((void*)0)) {
878 nelements = tsmem->orderCount;
879 }
880 return nelements;
881}
882
883rpmte rpmtsElement(rpmts ts, int ix)
884{
885 rpmte te = NULL((void*)0);
886 tsMembers tsmem = rpmtsMembers(ts);
887 if (tsmem != NULL((void*)0) && tsmem->order != NULL((void*)0)) {
888 if (ix >= 0 && ix < tsmem->orderCount)
889 te = tsmem->order[ix];
890 }
891 return te;
892}
893
894rpmprobFilterFlags rpmtsFilterFlags(rpmts ts)
895{
896 return (ts != NULL((void*)0) ? ts->ignoreSet : 0);
897}
898
899rpmtransFlags rpmtsFlags(rpmts ts)
900{
901 return (ts != NULL((void*)0) ? ts->transFlags : 0);
902}
903
904rpmtransFlags rpmtsSetFlags(rpmts ts, rpmtransFlags transFlags)
905{
906 rpmtransFlags otransFlags = 0;
907 if (ts != NULL((void*)0)) {
908 otransFlags = ts->transFlags;
909 ts->transFlags = transFlags;
910 }
911 return otransFlags;
912}
913
914rpm_color_t rpmtsColor(rpmts ts)
915{
916 return (ts != NULL((void*)0) ? ts->color : 0);
917}
918
919rpm_color_t rpmtsSetColor(rpmts ts, rpm_color_t color)
920{
921 rpm_color_t ocolor = 0;
922 if (ts != NULL((void*)0)) {
923 ocolor = ts->color;
924 ts->color = color;
925 }
926 return ocolor;
927}
928
929rpm_color_t rpmtsPrefColor(rpmts ts)
930{
931 return (ts != NULL((void*)0) ? ts->prefcolor : 0);
932}
933
934rpm_color_t rpmtsSetPrefColor(rpmts ts, rpm_color_t color)
935{
936 rpm_color_t ocolor = 0;
937 if (ts != NULL((void*)0)) {
938 ocolor = ts->prefcolor;
939 ts->prefcolor = color;
940 }
941 return ocolor;
942}
943
944rpmop rpmtsOp(rpmts ts, rpmtsOpX opx)
945{
946 rpmop op = NULL((void*)0);
947
948 if (ts != NULL((void*)0) && opx >= 0 && opx < RPMTS_OP_MAX)
949 op = ts->ops + opx;
950 return op;
951}
952
953rpmPlugins rpmtsPlugins(rpmts ts)
954{
955 rpmPlugins plugins = NULL((void*)0);
956
957 if (ts != NULL((void*)0)) {
958 if (ts->plugins == NULL((void*)0))
959 ts->plugins = rpmpluginsNew(ts);
960 plugins = ts->plugins;
961 }
962 return plugins;
963}
964
965int rpmtsSetNotifyCallback(rpmts ts,
966 rpmCallbackFunction notify, rpmCallbackData notifyData)
967{
968 if (ts != NULL((void*)0)) {
969 ts->notify = notify;
970 ts->notifyData = notifyData;
971 }
972 return 0;
973}
974
975tsMembers rpmtsMembers(rpmts ts)
976{
977 return (ts != NULL((void*)0)) ? ts->members : NULL((void*)0);
978}
979
980rpmstrPool rpmtsPool(rpmts ts)
981{
982 tsMembers tsmem = rpmtsMembers(ts);
983 rpmstrPool tspool = NULL((void*)0);
984
985 if (tsmem) {
986 if (tsmem->pool == NULL((void*)0))
987 tsmem->pool = rpmstrPoolCreate();
988 tspool = tsmem->pool;
989 }
990 return tspool;
991}
992
993rpmts rpmtsCreate(void)
994{
995 rpmts ts;
996 tsMembers tsmem;
997
998 ts = xcalloc(1, sizeof(*ts))rcalloc((1), (sizeof(*ts)));
999 memset(&ts->ops, 0, sizeof(ts->ops));
1000 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_TOTAL), -1);
1001 ts->dsi = NULL((void*)0);
1002
1003 ts->solve = NULL((void*)0);
1004 ts->solveData = NULL((void*)0);
1005
1006 ts->rdb = NULL((void*)0);
1007 ts->dbmode = O_RDONLY00;
1008
1009 ts->scriptFd = NULL((void*)0);
1010 ts->tid = (rpm_tid_t) time(NULL((void*)0));
1011
1012 ts->color = rpmExpandNumeric("%{?_transaction_color}");
1013 ts->prefcolor = rpmExpandNumeric("%{?_prefer_color}")?:2;
1014
1015 ts->netsharedPaths = NULL((void*)0);
1016 ts->installLangs = NULL((void*)0);
1017 { char *tmp = rpmExpand("%{_netsharedpath}", NULL((void*)0));
1018 if (tmp && *tmp != '%') {
1019 argvSplit(&ts->netsharedPaths, tmp, ":");
1020 }
1021 free(tmp);
1022
1023 tmp = rpmExpand("%{_install_langs}", NULL((void*)0));
1024 if (tmp && *tmp != '%') {
1025 ARGV_t langs = NULL((void*)0);
1026 argvSplit(&langs, tmp, ":");
1027 /* If we'll be installing all languages anyway, don't bother */
1028 for (ARGV_t l = langs; *l; l++) {
1029 if (rstreq(*l, "all")) {
1030 langs = argvFree(langs);
1031 break;
1032 }
1033 }
1034 ts->installLangs = langs;
1035 }
1036 free(tmp);
1037 }
1038
1039 tsmem = xcalloc(1, sizeof(*ts->members))rcalloc((1), (sizeof(*ts->members)));
1040 tsmem->pool = NULL((void*)0);
1041 tsmem->delta = 5;
1042 tsmem->addedPackages = NULL((void*)0);
1043 tsmem->removedPackages = packageHashCreate(128, uintId, uintCmp, NULL((void*)0), NULL((void*)0));
1044 tsmem->installedPackages = packageHashCreate(128, uintId, uintCmp, NULL((void*)0), NULL((void*)0));
1045 tsmem->orderAlloced = 0;
1046 tsmem->orderCount = 0;
1047 tsmem->order = NULL((void*)0);
1048 ts->members = tsmem;
1049
1050 ts->rootDir = NULL((void*)0);
1051 ts->keyring = NULL((void*)0);
1052
1053 ts->nrefs = 0;
1054
1055 ts->plugins = NULL((void*)0);
1056
1057 ts->trigs2run = rpmtriggersCreate(10);
1058
1059 ts->min_writes = rpmExpandNumeric("%{_minimize_writes}");
1060
1061 return rpmtsLink(ts);
1062}
1063
1064rpmtsi rpmtsiFree(rpmtsi tsi)
1065{
1066 /* XXX watchout: a funky recursion segfaults here iff nrefs is wrong. */
1067 if (tsi) {
1068 tsi->ts = rpmtsFree(tsi->ts);
1069 _free(tsi)rfree((tsi));
1070 }
1071 return NULL((void*)0);
1072}
1073
1074rpmtsi rpmtsiInit(rpmts ts)
1075{
1076 rpmtsi tsi = NULL((void*)0);
1077
1078 tsi = xcalloc(1, sizeof(*tsi))rcalloc((1), (sizeof(*tsi)));
1079 tsi->ts = rpmtsLink(ts);
1080 tsi->oc = 0;
1081 return tsi;
1082}
1083
1084/**
1085 * Return next transaction element.
1086 * @param tsi transaction element iterator
1087 * @return transaction element, NULL on termination
1088 */
1089static
1090rpmte rpmtsiNextElement(rpmtsi tsi)
1091{
1092 rpmte te = NULL((void*)0);
1093 int oc = -1;
1094
1095 if (tsi == NULL((void*)0) || tsi->ts == NULL((void*)0) || rpmtsNElements(tsi->ts) <= 0)
1096 return te;
1097
1098 if (tsi->oc < rpmtsNElements(tsi->ts)) oc = tsi->oc++;
1099 if (oc != -1)
1100 te = rpmtsElement(tsi->ts, oc);
1101 return te;
1102}
1103
1104rpmte rpmtsiNext(rpmtsi tsi, rpmElementTypes types)
1105{
1106 rpmte te;
1107
1108 while ((te = rpmtsiNextElement(tsi)) != NULL((void*)0)) {
1109 if (types == 0 || (rpmteType(te) & types) != 0)
1110 break;
1111 }
1112 return te;
1113}
1114
1115#define RPMLOCK_PATH"/var" "/rpm/.rpm.lock" LOCALSTATEDIR"/var" "/rpm/.rpm.lock"
1116rpmtxn rpmtxnBegin(rpmts ts, rpmtxnFlags flags)
1117{
1118 static const char * const rpmlock_path_default = "%{?_rpmlock_path}";
1119 rpmtxn txn = NULL((void*)0);
1120
1121 if (ts == NULL((void*)0))
1122 return NULL((void*)0);
1123
1124 if (ts->lockPath == NULL((void*)0)) {
1125 const char *rootDir = rpmtsRootDir(ts);
1126 char *t;
1127
1128 if (!rootDir || rpmChrootDone())
1129 rootDir = "/";
1130
1131 t = rpmGenPath(rootDir, rpmlock_path_default, NULL((void*)0));
1132 if (t == NULL((void*)0) || *t == '\0' || *t == '%') {
1133 free(t);
1134 t = xstrdup(RPMLOCK_PATH)rstrdup(("/var" "/rpm/.rpm.lock"));
1135 }
1136 ts->lockPath = xstrdup(t)rstrdup((t));
1137 (void) rpmioMkpath(dirname(t), 0755, getuid(), getgid());
1138 free(t);
1139 }
1140
1141 if (ts->lock == NULL((void*)0))
1142 ts->lock = rpmlockNew(ts->lockPath, _("transaction")dcgettext ("rpm", "transaction", 5));
1143
1144 if (rpmlockAcquire(ts->lock)) {
1145 txn = xcalloc(1, sizeof(*txn))rcalloc((1), (sizeof(*txn)));
1146 txn->lock = ts->lock;
1147 txn->flags = flags;
1148 txn->ts = rpmtsLink(ts);
1149 if (txn->flags & RPMTXN_WRITE)
1150 rpmsqBlock(SIG_BLOCK0);
1151 }
1152
1153 return txn;
1154}
1155
1156rpmtxn rpmtxnEnd(rpmtxn txn)
1157{
1158 if (txn) {
1159 rpmlockRelease(txn->lock);
1160 if (txn->flags & RPMTXN_WRITE)
1161 rpmsqBlock(SIG_UNBLOCK1);
1162 rpmtsFree(txn->ts);
1163 free(txn);
1164 }
1165 return NULL((void*)0);
1166}