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