rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

rpmdb.c
Go to the documentation of this file.
1
5 #include "system.h"
6
7 #include <sys/file.h>
8
9 #include <rpmiotypes.h>
10 #include <rpmlog.h>
11 #include <rpmpgp.h>
12 #include <rpmurl.h>
13 #define _MIRE_INTERNAL
14 #include <rpmmacro.h>
15 #include <rpmsq.h>
16 #include <argv.h>
17
18 #include <rpmtypes.h>
19
20 #define _RPMTAG_INTERNAL
21 #include "header_internal.h" /* XXX for HEADERFLAG_ALLOCATED */
22
23 #define _RPMEVR_INTERNAL /* XXX isInstallPrereq */
24 #include <rpmevr.h>
25
26 /* XXX avoid including <rpmts.h> */
27 /*@-redecl -type @*/
28 extern pgpDig rpmtsDig(void * ts)
29 /*@*/;
30 extern void rpmtsCleanDig(void * ts)
31 /*@modifies ts @*/;
32 /*@=redecl =type @*/
33
34 #define _RPMDB_INTERNAL
35 #include "rpmdb.h"
36 #include "pkgio.h"
37 #include "fprint.h"
38 #include "legacy.h"
39
40 #include "debug.h"
41
42 #if defined(__LCLINT__)
43 #define UINT32_T u_int32_t
44 #else
45 #define UINT32_T rpmuint32_t
46 #endif
47
48 /* XXX retrofit the *BSD typedef for the deprived. */
49 #if defined(__QNXNTO__)
50 typedef rpmuint32_t u_int32_t;
51 #endif
52
53 /*@access dbiIndexSet@*/
54 /*@access dbiIndexItem@*/
55 /*@access miRE@*/
56 /*@access Header@*/ /* XXX compared with NULL */
57 /*@access rpmmi@*/
58 /*@access rpmts@*/ /* XXX compared with NULL */
59
60 /*@unchecked@*/
61 int _rpmdb_debug = 0;
62
63 /*@unchecked@*/
64 static int _rebuildinprogress = 0;
65 /*@unchecked@*/
66 static int _db_filter_dups = 0;
67
68 /* Use a path uniqifier in the upper 16 bits of tagNum? */
69 /* XXX Note: one cannot just choose a value, rpmdb tagNum's need fixing too */
70 #define _DB_TAGGED_FILE_INDICES 1
71 /*@unchecked@*/
72 static int _db_tagged_file_indices = _DB_TAGGED_FILE_INDICES;
73
74 /* Use a path uniqifier while doing -qf? */
75 #define _DB_TAGGED_FINDBYFILE 1
76 /*@unchecked@*/
77 static int _db_tagged_findbyfile = _DB_TAGGED_FINDBYFILE;
78
79 #define _DBI_FLAGS 0
80 #define _DBI_PERMS 0644
81 #define _DBI_MAJOR -1
82
83 /* Bit mask macros. */
84 /*@-exporttype@*/
85 typedef unsigned int __pbm_bits;
86 /*@=exporttype@*/
87 #define __PBM_NBITS /*@-sizeoftype@*/(8 * sizeof(__pbm_bits))/*@=sizeoftype@*/
88 #define __PBM_IX(d) ((d) / __PBM_NBITS)
89 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS))
90 /*@-exporttype@*/
91 typedef struct {
92 __pbm_bits bits[1];
93 } pbm_set;
94 /*@=exporttype@*/
95 #define __PBM_BITS(set) ((set)->bits)
96
97 #define PBM_FREE(s) _free(s);
98 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d))
99 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d))
100 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0)
101
102 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, __PBM_NBITS/8)
103
110 /*@unused@*/
111 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd)
112 /*@modifies *sp, *odp @*/
113 {
114 int i, nb;
115
116 if (nd > (*odp)) {
117 nd *= 2;
118 nb = __PBM_IX(nd) + 1;
119 /*@-unqualifiedtrans@*/
120 *sp = xrealloc(*sp, nb * (__PBM_NBITS/8));
121 /*@=unqualifiedtrans@*/
122 for (i = __PBM_IX(*odp) + 1; i < nb; i++)
123 __PBM_BITS(*sp)[i] = 0;
124 *odp = nd;
125 }
126 /*@-compdef -retalias -usereleased@*/
127 return *sp;
128 /*@=compdef =retalias =usereleased@*/
129 }
130
136 static inline unsigned char nibble(char c)
137 /*@*/
138 {
139 if (c >= '0' && c <= '9')
140 return (unsigned char)(c - '0');
141 if (c >= 'A' && c <= 'F')
142 return (unsigned char)((int)(c - 'A') + 10);
143 if (c >= 'a' && c <= 'f')
144 return (unsigned char)((int)(c - 'a') + 10);
145 return '\0';
146 }
147
154 /*@only@*/
155 static char * bin2hex(const void *data, size_t size)
156 /*@*/
157 {
158 static char hex[] = "0123456789abcdef";
159 const char * s = data;
160 char * t, * val;
161 val = t = xmalloc(size * 2 + 1);
162 while (size-- > 0) {
163 unsigned i;
164 i = (unsigned) *s++;
165 *t++ = hex[ (i >> 4) & 0xf ];
166 *t++ = hex[ (i ) & 0xf ];
167 }
168 *t = '\0';
169
170 return val;
171 }
172
173 #ifdef DYING
174
180 static int printable(const void * ptr, size_t len) /*@*/
181 {
182 const char * s = ptr;
183 int i;
184 for (i = 0; i < len; i++, s++)
185 if (!(*s >= ' ' && *s <= '~')) return 0;
186 return 1;
187 }
188 #endif
189
196 static size_t dbiTagToDbix(rpmdb db, rpmTag tag)
197 /*@*/
198 {
199 size_t dbix;
200
201 if (db->db_tags != NULL)
202 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
203 if (tag != db->db_tags[dbix].tag)
204 continue;
205 return dbix;
206 }
207 return 0xffffffff;
208 }
209
213 /*@-exportheader@*/
214 static void dbiTagsInit(/*@null@*/ tagStore_t * dbiTagsP,
215 /*@null@*/ size_t * dbiNTagsP)
216 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
217 /*@modifies *dbiTagsP, *dbiNTagsP, rpmGlobalMacroContext, internalState @*/
218 {
219 /*@observer@*/
220 static const char * const _dbiTagStr_default =
221 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys";
222 tagStore_t dbiTags = NULL;
223 size_t dbiNTags = 0;
224 char * dbiTagStr = NULL;
225 char * o, * oe;
226 rpmTag tag;
227 size_t dbix;
228 int bingo;
229
230 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL);
231 if (!(dbiTagStr && *dbiTagStr)) {
232 dbiTagStr = _free(dbiTagStr);
233 dbiTagStr = xstrdup(_dbiTagStr_default);
234 }
235
236 /* Always allocate package index */
237 dbiTags = xcalloc(1, sizeof(*dbiTags));
238 dbiTags[dbiNTags].str = xstrdup("Packages");
239 dbiTags[dbiNTags].tag = RPMDBI_PACKAGES;
240 dbiTags[dbiNTags].iob = NULL;
241 dbiNTags++;
242
243 for (o = dbiTagStr; o && *o; o = oe) {
244 while (*o && xisspace((int)*o))
245 o++;
246 if (*o == '\0')
247 break;
248 for (oe = o; oe && *oe; oe++) {
249 if (xisspace((int)*oe))
250 /*@innerbreak@*/ break;
251 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/'))
252 /*@innerbreak@*/ break;
253 }
254 if (oe && *oe)
255 *oe++ = '\0';
256 tag = tagValue(o);
257
258 bingo = 0;
259 if (dbiTags != NULL)
260 for (dbix = 0; dbix < dbiNTags; dbix++) {
261 if (tag == dbiTags[dbix].tag) {
262 bingo = 1;
263 /*@innerbreak@*/ break;
264 }
265 }
266 if (bingo)
267 continue;
268
269 dbiTags = xrealloc(dbiTags, (dbiNTags + 1) * sizeof(*dbiTags));
270 dbiTags[dbiNTags].str = xstrdup(o);
271 dbiTags[dbiNTags].tag = tag;
272 dbiTags[dbiNTags].iob = NULL;
273 dbiNTags++;
274 }
275
276 if (dbiNTagsP != NULL)
277 *dbiNTagsP = dbiNTags;
278 if (dbiTagsP != NULL)
279 *dbiTagsP = dbiTags;
280 else
281 dbiTags = tagStoreFree(dbiTags, dbiNTags);
282 dbiTagStr = _free(dbiTagStr);
283 }
284 /*@=exportheader@*/
285
286 /*@-redecl@*/
287 #define DB1vec NULL
288 #define DB2vec NULL
289
290 #ifdef HAVE_DB_H
291 /*@-exportheadervar -declundef @*/
292 /*@observer@*/ /*@unchecked@*/
293 extern struct _dbiVec db3vec;
294 /*@=exportheadervar =declundef @*/
295 #define DB3vec &db3vec
296 /*@=redecl@*/
297 #else
298 #define DB3vec NULL
299 #endif
300
301 #ifdef HAVE_SQLITE3_H
302 #define SQLITE_HACK
303 /*@-exportheadervar -declundef @*/
304 /*@observer@*/ /*@unchecked@*/
305 extern struct _dbiVec sqlitevec;
306 /*@=exportheadervar =declundef @*/
307 #define SQLITEvec &sqlitevec
308 /*@=redecl@*/
309 #else
310 #define SQLITEvec NULL
311 #endif
312
313 /*@-nullassign@*/
314 /*@observer@*/ /*@unchecked@*/
315 static struct _dbiVec *mydbvecs[] = {
316 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL
317 };
318 /*@=nullassign@*/
319
320 static inline int checkfd(const char * devnull, int fdno, int flags)
321 /*@*/
322 {
323 struct stat sb;
324 int ret = 0;
325
326 if (fstat(fdno, &sb) == -1 && errno == EBADF)
327 ret = (open(devnull, flags) == fdno) ? 1 : 2;
328 return ret;
329 }
330
331 dbiIndex dbiOpen(rpmdb db, rpmTag tag, /*@unused@*/ unsigned int flags)
332 {
333 static int _oneshot = 0;
334 size_t dbix;
335 tagStore_t dbiTag;
336 const char * dbiBN;
337 dbiIndex dbi = NULL;
338 int _dbapi, _dbapi_rebuild, _dbapi_wanted;
339 int rc = 0;
340
341 /* Insure that stdin/stdout/stderr are open, lest stderr end up in rpmdb. */
342 if (!_oneshot) {
343 static const char _devnull[] = "/dev/null";
344 /*@-noeffect@*/
345 #if defined(STDIN_FILENO)
346 (void) checkfd(_devnull, STDIN_FILENO, O_RDONLY);
347 #endif
348 #if defined(STDOUT_FILENO)
349 (void) checkfd(_devnull, STDOUT_FILENO, O_WRONLY);
350 #endif
351 #if defined(STDERR_FILENO)
352 (void) checkfd(_devnull, STDERR_FILENO, O_WRONLY);
353 #endif
354 /*@=noeffect@*/
355 _oneshot++;
356 }
357
358 /*@-modfilesys@*/
359 if (_rpmdb_debug)
360 fprintf(stderr, "==> dbiOpen(%p, %s(%u), 0x%x)\n", db, tagName(tag), tag, flags);
361 /*@=modfilesys@*/
362
363 if (db == NULL)
364 return NULL;
365
366 dbix = dbiTagToDbix(db, tag);
367 if (dbix >= db->db_ndbi)
368 return NULL;
369 dbiTag = db->db_tags + dbix;
370 dbiBN = (dbiTag->str != NULL ? dbiTag->str : tagName(tag));
371
372 /* Is this index already open ? */
373 /*@-compdef@*/ /* FIX: db->_dbi may be NULL */
374 if (db->_dbi != NULL && (dbi = db->_dbi[dbix]) != NULL)
375 return dbi;
376 /*@=compdef@*/
377
378 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
379 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4)
380 _dbapi_rebuild = 4;
381 /* _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api); */
382 _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api);
383
384 switch (_dbapi_wanted) {
385 default:
386 _dbapi = _dbapi_wanted;
387 if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) {
388 rpmlog(RPMLOG_DEBUG, D_("dbiOpen: _dbiapi failed\n"));
389 return NULL;
390 }
391 errno = 0;
392 dbi = NULL;
393 rc = (*mydbvecs[_dbapi]->open) (db, tag, &dbi);
394 if (rc) {
395 static int _printed[32];
396 if (!_printed[dbix & 0x1f]++)
397 rpmlog(RPMLOG_ERR,
398 _("cannot open %s(%u) index using db%d - %s (%d)\n"),
399 dbiBN, tag, _dbapi,
400 (rc > 0 ? strerror(rc) : ""), rc);
401 _dbapi = -1;
402 }
403 break;
404 case -1:
405 _dbapi = 5;
406 while (_dbapi-- > 1) {
407 if (mydbvecs[_dbapi] == NULL)
408 continue;
409 errno = 0;
410 dbi = NULL;
411 rc = (*mydbvecs[_dbapi]->open) (db, tag, &dbi);
412 if (rc == 0 && dbi)
413 /*@loopbreak@*/ break;
414 }
415 if (_dbapi <= 0) {
416 static int _printed[32];
417 if (!_printed[dbix & 0x1f]++)
418 rpmlog(RPMLOG_ERR, _("cannot open %s(%u) index\n"),
419 dbiBN, tag);
420 rc = 1;
421 goto exit;
422 }
423 if (db->db_api == -1 && _dbapi > 0)
424 db->db_api = _dbapi;
425 break;
426 }
427
428 exit:
429 if (dbi != NULL && rc == 0) {
430 if (db->_dbi != NULL)
431 db->_dbi[dbix] = dbi;
432 /*@-sizeoftype@*/
433 if (tag == RPMDBI_PACKAGES && db->db_bits == NULL) {
434 db->db_nbits = 1024;
435 if (!dbiStat(dbi, DB_FAST_STAT)) {
436 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats;
437 if (hash)
438 db->db_nbits += hash->hash_nkeys;
439 }
440 db->db_bits = PBM_ALLOC(db->db_nbits);
441 }
442 /*@=sizeoftype@*/
443 }
444 #ifdef HAVE_DB_H
445 else
446 dbi = db3Free(dbi);
447 #endif
448
449 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */
450 return dbi;
451 /*@=compdef =nullstate@*/
452 }
453
460 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum)
461 /*@*/
462 {
463 dbiIndexItem rec = xcalloc(1, sizeof(*rec));
464 rec->hdrNum = hdrNum;
465 rec->tagNum = tagNum;
466 return rec;
467 }
468
469 union _dbswap {
470 rpmuint32_t ui;
471 unsigned char uc[4];
472 };
473
474 #define _DBSWAP(_a) \
475 { unsigned char _b, *_c = (_a).uc; \
476 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
477 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
478 }
479
487 static int dbt2set(dbiIndex dbi, DBT * data, /*@out@*/ dbiIndexSet * setp)
488 /*@modifies dbi, *setp @*/
489 {
490 int _dbbyteswapped;
491 const char * sdbir;
492 dbiIndexSet set;
493 int i;
494
495 if (dbi == NULL || data == NULL || setp == NULL)
496 return -1;
497 _dbbyteswapped = dbiByteSwapped(dbi);
498
499 if ((sdbir = data->data) == NULL) {
500 *setp = NULL;
501 return 0;
502 }
503
504 set = xmalloc(sizeof(*set));
505 set->count = (int) (data->size / dbi->dbi_jlen);
506 set->recs = xmalloc(set->count * sizeof(*(set->recs)));
507
508 /*@-sizeoftype @*/
509 switch (dbi->dbi_jlen) {
510 default:
511 case 2*sizeof(rpmuint32_t):
512 for (i = 0; i < set->count; i++) {
513 union _dbswap hdrNum, tagNum;
514
515 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
516 sdbir += sizeof(hdrNum.ui);
517 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui));
518 sdbir += sizeof(tagNum.ui);
519 if (_dbbyteswapped) {
520 _DBSWAP(hdrNum);
521 _DBSWAP(tagNum);
522 }
523 set->recs[i].hdrNum = hdrNum.ui;
524 set->recs[i].tagNum = tagNum.ui;
525 set->recs[i].fpNum = 0;
526 }
527 break;
528 case 1*sizeof(rpmuint32_t):
529 for (i = 0; i < set->count; i++) {
530 union _dbswap hdrNum;
531
532 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui));
533 sdbir += sizeof(hdrNum.ui);
534 if (_dbbyteswapped) {
535 _DBSWAP(hdrNum);
536 }
537 set->recs[i].hdrNum = hdrNum.ui;
538 set->recs[i].tagNum = 0;
539 set->recs[i].fpNum = 0;
540 }
541 break;
542 }
543 *setp = set;
544 /*@=sizeoftype @*/
545 /*@-compdef@*/
546 return 0;
547 /*@=compdef@*/
548 }
549
557 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set)
558 /*@modifies dbi, *data @*/
559 {
560 int _dbbyteswapped;
561 char * tdbir;
562 unsigned i;
563
564 if (dbi == NULL || data == NULL || set == NULL)
565 return -1;
566 _dbbyteswapped = dbiByteSwapped(dbi);
567
568 data->size = (UINT32_T)(set->count * (dbi->dbi_jlen));
569 if (data->size == 0) {
570 data->data = NULL;
571 return 0;
572 }
573 tdbir = data->data = xmalloc(data->size);
574
575 /*@-sizeoftype@*/
576 switch (dbi->dbi_jlen) {
577 default:
578 case 2*sizeof(rpmuint32_t):
579 for (i = 0; i < (unsigned)set->count; i++) {
580 union _dbswap hdrNum, tagNum;
581
582 memset(&hdrNum, 0, sizeof(hdrNum));
583 memset(&tagNum, 0, sizeof(tagNum));
584 hdrNum.ui = set->recs[i].hdrNum;
585 tagNum.ui = set->recs[i].tagNum;
586 if (_dbbyteswapped) {
587 _DBSWAP(hdrNum);
588 _DBSWAP(tagNum);
589 }
590 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
591 tdbir += sizeof(hdrNum.ui);
592 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui));
593 tdbir += sizeof(tagNum.ui);
594 }
595 break;
596 case 1*sizeof(rpmuint32_t):
597 for (i = 0; i < (unsigned)set->count; i++) {
598 union _dbswap hdrNum;
599
600 memset(&hdrNum, 0, sizeof(hdrNum));
601 hdrNum.ui = set->recs[i].hdrNum;
602 if (_dbbyteswapped) {
603 _DBSWAP(hdrNum);
604 }
605 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui));
606 tdbir += sizeof(hdrNum.ui);
607 }
608 break;
609 }
610 /*@=sizeoftype@*/
611
612 /*@-compdef@*/
613 return 0;
614 /*@=compdef@*/
615 }
616
617 /* XXX assumes hdrNum is first int in dbiIndexItem */
618 static int hdrNumCmp(const void * one, const void * two)
619 /*@*/
620 {
621 const int * a = one, * b = two;
622 return (*a - *b);
623 }
624
634 static int dbiAppendSet(dbiIndexSet set, const void * recs,
635 int nrecs, size_t recsize, int sortset)
636 /*@modifies *set @*/
637 {
638 const char * rptr = recs;
639 size_t rlen = (recsize < sizeof(*(set->recs)))
640 ? recsize : sizeof(*(set->recs));
641
642 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0)
643 return 1;
644
645 set->recs = xrealloc(set->recs,
646 (set->count + nrecs) * sizeof(*(set->recs)));
647
648 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs)));
649
650 while (nrecs-- > 0) {
651 /*@-mayaliasunique@*/
652 memcpy(set->recs + set->count, rptr, rlen);
653 /*@=mayaliasunique@*/
654 rptr += recsize;
655 set->count++;
656 }
657
658 if (sortset && set->count > 1)
659 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp);
660
661 return 0;
662 }
663
673 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs,
674 size_t recsize, int sorted)
675 /*@modifies set, recs @*/
676 {
677 int from;
678 int to = 0;
679 int num = set->count;
680 int numCopied = 0;
681
682 assert(set->count > 0);
683 if (nrecs > 1 && !sorted)
684 qsort(recs, nrecs, recsize, hdrNumCmp);
685
686 for (from = 0; from < num; from++) {
687 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) {
688 set->count--;
689 continue;
690 }
691 if (from != to)
692 set->recs[to] = set->recs[from]; /* structure assignment */
693 to++;
694 numCopied++;
695 }
696 return (numCopied == num);
697 }
698
699 /* XXX transaction.c */
700 unsigned int dbiIndexSetCount(dbiIndexSet set) {
701 return set->count;
702 }
703
704 /* XXX transaction.c */
705 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) {
706 return (unsigned) set->recs[recno].hdrNum;
707 }
708
709 /* XXX transaction.c */
710 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) {
711 return (unsigned) set->recs[recno].tagNum;
712 }
713
714 /* XXX transaction.c */
715 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) {
716 if (set) {
717 set->recs = _free(set->recs);
718 set = _free(set);
719 }
720 return set;
721 }
722
723 struct rpmmi_s {
724 struct rpmioItem_s _item;
725 /*@dependent@*/ /*@null@*/
726 rpmmi mi_next;
727 /*@refcounted@*/
728 rpmdb mi_db;
729 rpmTag mi_rpmtag;
730 dbiIndexSet mi_set;
731 DBC * mi_dbc;
732 DBT mi_key;
733 DBT mi_data;
734 int mi_setx;
735 /*@refcounted@*/ /*@null@*/
736 Header mi_h;
737 int mi_sorted;
738 int mi_cflags;
739 int mi_modified;
740 unsigned int mi_prevoffset; /* header instance (native endian) */
741 unsigned int mi_offset; /* header instance (native endian) */
742 unsigned int mi_filenum; /* tag element (native endian) */
743 int mi_nre;
744 /*@only@*/ /*@null@*/
745 miRE mi_re;
746 /*@null@*/
747 rpmts mi_ts;
748
749 };
750
751 /*@unchecked@*/
752 static rpmdb rpmdbRock;
753
754 /*@unchecked@*/ /*@exposed@*/ /*@null@*/
755 static rpmmi rpmmiRock;
756
757 int rpmdbCheckTerminate(int terminate)
758 /*@globals rpmdbRock, rpmmiRock @*/
759 /*@modifies rpmdbRock, rpmmiRock @*/
760 {
761 sigset_t newMask, oldMask;
762 static int terminating = 0;
763
764 if (terminating) return 1;
765
766 (void) sigfillset(&newMask); /* block all signals */
767 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask);
768
769 if (sigismember(&rpmsqCaught, SIGINT)
770 || sigismember(&rpmsqCaught, SIGQUIT)
771 || sigismember(&rpmsqCaught, SIGHUP)
772 || sigismember(&rpmsqCaught, SIGTERM)
773 || sigismember(&rpmsqCaught, SIGPIPE)
774 #ifdef NOTYET /* XXX todo++ */
775 || sigismember(&rpmsqCaught, SIGXCPU)
776 || sigismember(&rpmsqCaught, SIGXFSZ)
777 #endif
778 || terminate)
779 terminating = 1;
780
781 if (terminating) {
782 rpmdb db;
783 rpmmi mi;
784
785 while ((mi = rpmmiRock) != NULL) {
786 /*@i@*/ rpmmiRock = mi->mi_next;
787 mi->mi_next = NULL;
788 /*@i@*/ mi = rpmmiFree(mi);
789 }
790
791 /*@-newreftrans@*/
792 while ((db = rpmdbRock) != NULL) {
793 /*@i@*/ rpmdbRock = db->db_next;
794 db->db_next = NULL;
795 (void) rpmdbClose(db);
796 }
797 /*@=newreftrans@*/
798 }
799
800 (void) sigprocmask(SIG_SETMASK, &oldMask, NULL);
801 return terminating;
802 }
803
804 int rpmdbCheckSignals(void)
805 {
806
807 if (rpmdbCheckTerminate(0)) {
808 /*@-abstract@*/ /* sigset_t is abstract type */
809 rpmlog(RPMLOG_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught));
810 /*@=abstract@*/
811 exit(EXIT_FAILURE);
812 }
813 return 0;
814 }
815
822 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask)
823 /*@globals fileSystem @*/
824 /*@modifies *oldMask, fileSystem @*/
825 {
826 sigset_t newMask;
827
828 (void) sigfillset(&newMask); /* block all signals */
829 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask);
830 (void) sigdelset(&newMask, SIGINT);
831 (void) sigdelset(&newMask, SIGQUIT);
832 (void) sigdelset(&newMask, SIGHUP);
833 (void) sigdelset(&newMask, SIGTERM);
834 (void) sigdelset(&newMask, SIGPIPE);
835 return sigprocmask(SIG_BLOCK, &newMask, NULL);
836 }
837
844 /*@mayexit@*/
845 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask)
846 /*@globals fileSystem, internalState @*/
847 /*@modifies fileSystem, internalState @*/
848 {
849 (void) rpmdbCheckSignals();
850 return sigprocmask(SIG_SETMASK, oldMask, NULL);
851 }
852
860 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt)
861 /*@globals headerCompoundFormats, fileSystem, internalState @*/
862 /*@modifies h, fileSystem, internalState @*/
863 {
864 const char * errstr = "(unkown error)";
865 const char * str;
866
867 /*@-modobserver@*/
868 str = headerSprintf(h, qfmt, NULL, headerCompoundFormats, &errstr);
869 /*@=modobserver@*/
870 if (str == NULL)
871 rpmlog(RPMLOG_ERR, _("incorrect format: \"%s\": %s\n"), qfmt, errstr);
872 return str;
873 }
874
882 static int rpmdbExportInfo(/*@unused@*/ rpmdb db, Header h, int adding)
883 /*@globals headerCompoundFormats, rpmGlobalMacroContext, h_errno,
884 fileSystem, internalState @*/
885 /*@modifies h, rpmGlobalMacroContext,
886 fileSystem, internalState @*/
887 {
888 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
889 const char * fn = NULL;
890 int xx;
891
892 { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL);
893 if (fnfmt && *fnfmt)
894 fn = queryHeader(h, fnfmt);
895 fnfmt = _free(fnfmt);
896 }
897
898 if (fn == NULL)
899 goto exit;
900
901 if (adding) {
902 FD_t fd = Fopen(fn, "w.fdio");
903
904 if (fd != NULL) {
905 xx = Fclose(fd);
906 fd = NULL;
907 he->tag = RPMTAG_INSTALLTID;
908 if (headerGet(h, he, 0)) {
909 struct utimbuf stamp;
910 stamp.actime = he->p.ui32p[0];
911 stamp.modtime = he->p.ui32p[0];
912 if (!Utime(fn, &stamp))
913 rpmlog(RPMLOG_DEBUG, " +++ %s\n", fn);
914 }
915 he->p.ptr = _free(he->p.ptr);
916 }
917 } else {
918 if (!Unlink(fn))
919 rpmlog(RPMLOG_DEBUG, " --- %s\n", fn);
920 }
921
922 exit:
923 fn = _free(fn);
924 return 0;
925 }
926
927 /*@unchecked@*/ /*@only@*/ /*@null@*/
928 rpmioPool _rpmdbPool;
929
930 static rpmdb rpmdbGetPool(/*@null@*/ rpmioPool pool)
931 /*@globals _rpmdbPool, fileSystem @*/
932 /*@modifies pool, _rpmdbPool, fileSystem @*/
933 {
934 rpmdb db;
935
936 if (_rpmdbPool == NULL) {
937 _rpmdbPool = rpmioNewPool("db", sizeof(*db), -1, _rpmdb_debug,
938 NULL, NULL, NULL);
939 pool = _rpmdbPool;
940 }
941 return (rpmdb) rpmioGetPool(pool, sizeof(*db));
942 }
943
944 int rpmdbOpenAll(rpmdb db)
945 {
946 size_t dbix;
947 int rc = 0;
948
949 if (db == NULL) return -2;
950
951 if (db->db_tags != NULL && db->_dbi != NULL)
952 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
953 tagStore_t dbiTag = db->db_tags + dbix;
954 int tag = dbiTag->tag;
955 if (tag < 0)
956 continue;
957 if (db->_dbi[dbix] != NULL)
958 continue;
959 switch (tag) {
960 case RPMDBI_AVAILABLE:
961 case RPMDBI_ADDED:
962 case RPMDBI_REMOVED:
963 case RPMDBI_DEPENDS:
964 continue;
965 /*@notreached@*/ /*@switchbreak@*/ break;
966 default:
967 /*@switchbreak@*/ break;
968 }
969 (void) dbiOpen(db, tag, db->db_flags);
970 }
971 return rc;
972 }
973
974 int rpmdbBlockDBI(rpmdb db, int tag)
975 {
976 rpmTag tagn = (rpmTag)(tag >= 0 ? tag : -tag);
977 size_t dbix;
978
979 if (db == NULL || db->_dbi == NULL)
980 return 0;
981
982 if (db->db_tags != NULL)
983 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
984 if (db->db_tags[dbix].tag != tagn)
985 continue;
986 db->db_tags[dbix].tag = tag;
987 return 0;
988 }
989 return 0;
990 }
991
992 int rpmdbCloseDBI(rpmdb db, int tag)
993 {
994 size_t dbix;
995 int rc = 0;
996
997 if (db == NULL || db->_dbi == NULL)
998 return 0;
999
1000 if (db->db_tags != NULL)
1001 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
1002 if (db->db_tags[dbix].tag != (rpmTag)tag)
1003 continue;
1004 if (db->_dbi[dbix] != NULL) {
1005 int xx;
1006 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
1007 xx = dbiClose(db->_dbi[dbix], 0);
1008 if (xx && rc == 0) rc = xx;
1009 db->_dbi[dbix] = NULL;
1010 /*@=unqualifiedtrans@*/
1011 }
1012 break;
1013 }
1014 return rc;
1015 }
1016
1017 /* XXX query.c, rpminstall.c, verify.c */
1018 /*@-incondefs@*/
1019 int rpmdbClose(rpmdb db)
1020 /*@globals rpmdbRock @*/
1021 /*@modifies rpmdbRock @*/
1022 {
1023 static const char msg[] = "rpmdbClose";
1024 rpmdb * prev, next;
1025 size_t dbix;
1026 int rc = 0;
1027
1028 if (db == NULL)
1029 return rc;
1030
1031 yarnPossess(db->_item.use);
1032 /*@-modfilesys@*/
1033 if (_rpmdb_debug)
1034 fprintf(stderr, "--> db %p -- %ld %s at %s:%u\n", db, yarnPeekLock(db->_item.use), msg, __FILE__, __LINE__);
1035
1036 /*@-usereleased@*/
1037 if (yarnPeekLock(db->_item.use) <= 1L) {
1038
1039 if (db->_dbi)
1040 for (dbix = db->db_ndbi; dbix;) {
1041 int xx;
1042 dbix--;
1043 if (db->_dbi[dbix] == NULL)
1044 continue;
1045 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
1046 xx = dbiClose(db->_dbi[dbix], 0);
1047 if (xx && rc == 0) rc = xx;
1048 db->_dbi[dbix] = NULL;
1049 /*@=unqualifiedtrans@*/
1050 }
1051 db->db_errpfx = _free(db->db_errpfx);
1052 db->db_root = _free(db->db_root);
1053 db->db_home = _free(db->db_home);
1054 db->db_bits = PBM_FREE(db->db_bits);
1055 db->db_tags = tagStoreFree(db->db_tags, db->db_ndbi);
1056 db->_dbi = _free(db->_dbi);
1057 db->db_ndbi = 0;
1058
1059 /*@-newreftrans@*/
1060 prev = &rpmdbRock;
1061 while ((next = *prev) != NULL && next != db)
1062 prev = &next->db_next;
1063 if (next) {
1064 /*@i@*/ *prev = next->db_next;
1065 next->db_next = NULL;
1066 }
1067 /*@=newreftrans@*/
1068
1069 if (rpmdbRock == NULL && rpmmiRock == NULL) {
1070 /* Last close uninstalls special signal handling. */
1071 (void) rpmsqEnable(-SIGHUP, NULL);
1072 (void) rpmsqEnable(-SIGINT, NULL);
1073 (void) rpmsqEnable(-SIGTERM, NULL);
1074 (void) rpmsqEnable(-SIGQUIT, NULL);
1075 (void) rpmsqEnable(-SIGPIPE, NULL);
1076 /* Pending signals strike here. */
1077 (void) rpmdbCheckSignals();
1078 }
1079
1080 /*@=usereleased@*/
1081 db = (rpmdb)rpmioPutPool((rpmioItem)db);
1082 } else
1083 yarnTwist(db->_item.use, BY, -1);
1084
1085 return rc;
1086 }
1087 /*@=incondefs@*/
1088
1089 int rpmdbSync(rpmdb db)
1090 {
1091 size_t dbix;
1092 int rc = 0;
1093
1094 if (db == NULL) return 0;
1095 if (db->_dbi != NULL)
1096 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
1097 int xx;
1098 if (db->_dbi[dbix] == NULL)
1099 continue;
1100 if (db->_dbi[dbix]->dbi_no_dbsync)
1101 continue;
1102 xx = dbiSync(db->_dbi[dbix], 0);
1103 if (xx && rc == 0) rc = xx;
1104 }
1105 return rc;
1106 }
1107
1113 static const char * rpmdbURIPath(const char *uri)
1114 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1115 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
1116 {
1117 const char * s = rpmGetPath(uri, NULL);
1118 const char * fn = NULL;
1119 urltype ut = urlPath(s, &fn);
1120
1121 switch (ut) {
1122 case URL_IS_PATH:
1123 case URL_IS_UNKNOWN:
1124 fn = s;
1125 s = NULL;
1126 break;
1127 case URL_IS_HTTPS:
1128 case URL_IS_HTTP:
1129 case URL_IS_FTP:
1130 case URL_IS_HKP:
1131 case URL_IS_DASH:
1132 default:
1133 /* HACK: strip the URI prefix for these schemes. */
1134 fn = rpmGetPath(fn, NULL);
1135 break;
1136 }
1137
1138 /* Convert relative to absolute paths. */
1139 if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */
1140 if (fn && *fn && *fn != '/') {
1141 char dn[PATH_MAX];
1142 char *t;
1143 dn[0] = '\0';
1144 if ((t = Realpath(".", dn)) != NULL) {
1145 t += strlen(dn);
1146 if (t > dn && t[-1] != '/')
1147 *t++ = '/';
1148 t = stpncpy(t, fn, (sizeof(dn) - (t - dn)));
1149 *t = '\0';
1150 fn = _free(fn);
1151 fn = rpmGetPath(dn, NULL);
1152 }
1153 }
1154
1155 s = _free(s);
1156 assert(fn != NULL);
1157 return fn;
1158 }
1159
1160 #define _DB_ROOT "/"
1161 #define _DB_HOME "%{?_dbpath}"
1162 #define _DB_FLAGS 0
1163 #define _DB_MODE 0
1164 #define _DB_PERMS 0644
1165
1166 #define _DB_MAJOR -1
1167 #define _DB_ERRPFX "rpmdb"
1168
1169 /*@-exportheader -globs -mods @*/
1170 /*@only@*/ /*@null@*/
1171 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root,
1172 /*@kept@*/ /*@null@*/ const char * home,
1173 int mode, int perms, int flags)
1174 /*@globals _db_filter_dups @*/
1175 /*@modifies _db_filter_dups @*/
1176 {
1177 rpmdb db = rpmdbGetPool(_rpmdbPool);
1178 const char * epfx = _DB_ERRPFX;
1179 static int oneshot = 0;
1180
1181 /*@-modfilesys@*/ /*@-nullpass@*/
1182 if (_rpmdb_debug)
1183 fprintf(stderr, "==> rpmdbNew(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", root, home, mode, perms, flags, db);
1184 /*@=modfilesys@*/ /*@=nullpass@*/
1185
1186 if (!oneshot) {
1187 _db_filter_dups = rpmExpandNumeric("%{?_filterdbdups}");
1188 oneshot = 1;
1189 }
1190
1191 db->db_api = _DB_MAJOR;
1192
1193 db->_dbi = NULL;
1194
1195 if (!(perms & 0600)) perms = 0644; /* XXX sanity */
1196
1197 db->db_mode = (mode >= 0) ? mode : _DB_MODE;
1198 db->db_perms = (perms >= 0) ? perms : _DB_PERMS;
1199 db->db_flags = (flags >= 0) ? flags : _DB_FLAGS;
1200
1201 db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) );
1202 db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) );
1203
1204 if (!(db->db_home && db->db_home[0] && db->db_home[0] != '%')) {
1205 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n"));
1206 db->db_root = _free(db->db_root);
1207 db->db_home = _free(db->db_home);
1208 db = (rpmdb) rpmioPutPool((rpmioItem)db);
1209 /*@-globstate@*/ return NULL; /*@=globstate@*/
1210 }
1211
1212 db->db_export = rpmdbExportInfo;
1213 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL);
1214 db->db_remove_env = 0;
1215 db->db_filter_dups = _db_filter_dups;
1216 dbiTagsInit(&db->db_tags, &db->db_ndbi);
1217 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi));
1218 /*@-globstate@*/
1219 return rpmdbLink(db, "rpmdbNew");
1220 /*@=globstate@*/
1221 }
1222 /*@=exportheader =globs =mods @*/
1223
1224 /*@-exportheader@*/
1225 int rpmdbOpenDatabase(/*@null@*/ const char * prefix,
1226 /*@null@*/ const char * dbpath,
1227 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp,
1228 int mode, int perms, int flags)
1229 /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno,
1230 fileSystem, internalState @*/
1231 /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext,
1232 fileSystem, internalState @*/
1233 {
1234 rpmdb db;
1235 int rc, xx;
1236 int justCheck = flags & RPMDB_FLAG_JUSTCHECK;
1237 int minimal = flags & RPMDB_FLAG_MINIMAL;
1238
1239 /* Insure that _dbapi has one of -1, 1, 2, or 3 */
1240 if (_dbapi < -1 || _dbapi > 4)
1241 _dbapi = -1;
1242 if (_dbapi == 0)
1243 _dbapi = 1;
1244
1245 if (dbp)
1246 *dbp = NULL;
1247 if (mode & O_WRONLY)
1248 return 1;
1249
1250 db = rpmdbNew(prefix, dbpath, mode, perms, flags);
1251 if (db == NULL)
1252 return 1;
1253
1254 if (rpmdbRock == NULL && rpmmiRock == NULL) {
1255 /* First open installs special signal handling. */
1256 (void) rpmsqEnable(SIGHUP, NULL);
1257 (void) rpmsqEnable(SIGINT, NULL);
1258 (void) rpmsqEnable(SIGTERM, NULL);
1259 (void) rpmsqEnable(SIGQUIT, NULL);
1260 (void) rpmsqEnable(SIGPIPE, NULL);
1261 }
1262
1263 /*@-assignexpose -newreftrans@*/
1264 /*@i@*/ db->db_next = rpmdbRock;
1265 rpmdbRock = db;
1266 /*@=assignexpose =newreftrans@*/
1267
1268 db->db_api = _dbapi;
1269
1270 { size_t dbix;
1271
1272 rc = 0;
1273 if (db->db_tags != NULL)
1274 for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) {
1275 tagStore_t dbiTag = db->db_tags + dbix;
1276 rpmTag tag = dbiTag->tag;
1277 dbiIndex dbi;
1278
1279 /* Filter out temporary databases */
1280 switch (tag) {
1281 case RPMDBI_AVAILABLE:
1282 case RPMDBI_ADDED:
1283 case RPMDBI_REMOVED:
1284 case RPMDBI_DEPENDS:
1285 continue;
1286 /*@notreached@*/ /*@switchbreak@*/ break;
1287 default:
1288 /*@switchbreak@*/ break;
1289 }
1290
1291 dbi = dbiOpen(db, tag, 0);
1292 if (dbi == NULL) {
1293 rc = -2;
1294 break;
1295 }
1296
1297 switch (tag) {
1298 case RPMDBI_PACKAGES:
1299 if (dbi == NULL) rc |= 1;
1300 #if 0
1301 /* XXX open only Packages, indices created on the fly. */
1302 if (db->db_api == 3)
1303 #endif
1304 goto exit;
1305 /*@notreached@*/ /*@switchbreak@*/ break;
1306 case RPMTAG_NAME:
1307 if (dbi == NULL) rc |= 1;
1308 if (minimal)
1309 goto exit;
1310 /*@switchbreak@*/ break;
1311 default:
1312 /*@switchbreak@*/ break;
1313 }
1314 }
1315 }
1316
1317 exit:
1318 if (rc || justCheck || dbp == NULL)
1319 xx = rpmdbClose(db);
1320 else {
1321 /*@-assignexpose -newreftrans@*/
1322 /*@i@*/ *dbp = db;
1323 /*@=assignexpose =newreftrans@*/
1324 }
1325
1326 return rc;
1327 }
1328 /*@=exportheader@*/
1329
1330 /* XXX python/rpmmodule.c */
1331 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms)
1332 {
1333 int _dbapi = rpmExpandNumeric("%{?_dbapi}");
1334 return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0);
1335 }
1336
1337 int rpmdbInit (const char * prefix, int perms)
1338 {
1339 int rc = -1; /* RPMRC_NOTFOUND somewhen */
1340 #ifdef SUPPORT_INITDB
1341 rpmdb db = NULL;
1342 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1343
1344 rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR),
1345 perms, RPMDB_FLAG_JUSTCHECK);
1346 if (db != NULL) {
1347 int xx;
1348 xx = rpmdbOpenAll(db);
1349 if (xx && rc == 0) rc = xx;
1350 xx = rpmdbClose(db);
1351 if (xx && rc == 0) rc = xx;
1352 db = NULL;
1353 }
1354 #endif
1355 return rc;
1356 }
1357
1358 int rpmdbVerifyAllDBI(rpmdb db)
1359 {
1360 int rc = -1; /* RPMRC_NOTFOUND somewhen */
1361
1362 #if defined(SUPPORT_VERIFYDB)
1363 if (db != NULL) {
1364 size_t dbix;
1365 int xx;
1366 rc = rpmdbOpenAll(db);
1367
1368 if (db->_dbi != NULL)
1369 for (dbix = db->db_ndbi; dbix;) {
1370 dbix--;
1371 if (db->_dbi[dbix] == NULL)
1372 continue;
1373 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */
1374 xx = dbiVerify(db->_dbi[dbix], 0);
1375 if (xx && rc == 0) rc = xx;
1376 db->_dbi[dbix] = NULL;
1377 /*@=unqualifiedtrans@*/
1378 }
1379
1380 /*@-nullstate@*/ /* FIX: db->_dbi[] may be NULL. */
1381 xx = rpmdbClose(db);
1382 /*@=nullstate@*/
1383 if (xx && rc == 0) rc = xx;
1384 db = NULL;
1385 }
1386 #endif
1387 return rc;
1388 }
1389
1390 int rpmdbVerify(const char * prefix)
1391 {
1392 int rc = -1; /* RPMRC_NOTFOUND somewhen */
1393 #if defined(SUPPORT_VERIFYDB)
1394 rpmdb db = NULL;
1395 int _dbapi = rpmExpandNumeric("%{_dbapi}");
1396
1397 rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0);
1398 if (!rc && db != NULL)
1399 rc = rpmdbVerifyAllDBI(db);
1400 #endif
1401 return rc;
1402 }
1403
1409 static inline unsigned taghash(const char * s)
1410 /*@*/
1411 {
1412 unsigned int r = 0;
1413 int c;
1414 while ((c = (int) *s++) != 0) {
1415 /* XXX Excluding the '/' character may cause hash collisions. */
1416 if (c != (int) '/')
1417 r += (r << 3) + c;
1418 }
1419 return ((r & 0x7fff) | 0x8000) << 16;
1420 }
1421
1430 static int dbiIntersect(unsigned int tag, dbiIndexSet dnset, dbiIndexSet bnset,
1431 dbiIndexSet *matches)
1432 /*@modifies *matches @*/
1433 {
1434 dbiIndexItem drec = dnset->recs;
1435 dbiIndexItem brec = bnset->recs;
1436 dbiIndexItem rec = alloca(sizeof(*rec));
1437 int i = 0;
1438 int j = 0;
1439 int xx;
1440
1441 *matches = NULL;
1442 while (i < dnset->count) {
1443 while (j < bnset->count && brec->hdrNum <= drec->hdrNum) {
1444 if (brec->hdrNum == drec->hdrNum
1445 && tag == (brec->tagNum & 0xffff0000))
1446 break;
1447 brec++;
1448 j++;
1449 }
1450 if (j >= bnset->count)
1451 break;
1452 if (brec->hdrNum == drec->hdrNum
1453 && tag == (brec->tagNum & 0xffff0000))
1454 {
1455 *rec = *brec; /* structure assignment */
1456 rec->tagNum &= 0x0000ffff;
1457 if (*matches == NULL)
1458 *matches = xcalloc(1, sizeof(**matches));
1459 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1460 brec++;
1461 j++;
1462 }
1463 drec++;
1464 i++;
1465 }
1466 return (*matches ? (*matches)->count : 0);
1467 }
1468
1478 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec,
1479 DBT * key, DBT * data, /*@out@*/ dbiIndexSet * matches)
1480 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1481 /*@modifies db, *key, *data, *matches, rpmGlobalMacroContext,
1482 fileSystem, internalState @*/
1483 /*@requires maxSet(matches) >= 0 @*/
1484 {
1485 const char * dirName;
1486 const char * baseName;
1487 dbiIndex dbi;
1488 DBC * dbcursor;
1489 dbiIndexSet bnset = NULL;
1490 int bingo;
1491 int rc;
1492 int xx;
1493 int i;
1494
1495 *matches = NULL;
1496 if (filespec == NULL) return -2;
1497
1498 if ((baseName = strrchr(filespec, '/')) != NULL) {
1499 size_t len = baseName - filespec + 1;
1500 char * t = strncpy(alloca(len + 1), filespec, len);
1501 t[len] = '\0';
1502 dirName = t;
1503 baseName++;
1504 } else {
1505 dirName = "";
1506 baseName = filespec;
1507 }
1508 assert(*dirName != '\0');
1509 assert(baseName != NULL);
1510
1511 /* Load the basenames index set. */
1512 if ((dbi = dbiOpen(db, RPMTAG_BASENAMES, 0)) == NULL)
1513 return -2;
1514
1515 dbcursor = NULL;
1516 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1517
1518 /*@-temptrans@*/
1519 key->data = (void *) baseName;
1520 /*@=temptrans@*/
1521 key->size = (UINT32_T) strlen(baseName);
1522 if (key->size == 0) key->size++; /* XXX "/" fixup. */
1523
1524 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1525 if (rc > 0) {
1526 rpmlog(RPMLOG_ERR,
1527 _("error(%d) getting records from %s index\n"),
1528 rc, tagName(dbi->dbi_rpmtag));
1529 } else
1530 if (rc == 0)
1531 (void) dbt2set(dbi, data, &bnset);
1532 xx = dbiCclose(dbi, dbcursor, 0);
1533 if (rc)
1534 return rc;
1535 assert(bnset != NULL);
1536 assert(bnset->count > 0);
1537
1538 /* Check that all basenames are dir tagged. */
1539 if (_db_tagged_file_indices) {
1540 bingo = 1;
1541 for (i = 0; i < bnset->count; i++) {
1542 if (bnset->recs[i].tagNum & 0x80000000)
1543 continue;
1544 bingo = 0;
1545 break;
1546 }
1547 } else
1548 bingo = 0;
1549
1550 /* Plan A: Attempt dirName <-> baseName intersection using index keys. */
1551 if (bingo && (dbi = dbiOpen(db, RPMTAG_DIRNAMES, 0)) != NULL) {
1552 dbiIndexSet dnset = NULL;
1553
1554 /* Load the dirnames index set. */
1555 dbcursor = NULL;
1556 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1557
1558 /*@-temptrans@*/
1559 key->data = (void *) dirName;
1560 /*@=temptrans@*/
1561 key->size = (UINT32_T) strlen(dirName);
1562 if (key->size == 0) key->size++; /* XXX "/" fixup. */
1563
1564 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1565 if (rc > 0) {
1566 rpmlog(RPMLOG_ERR,
1567 _("error(%d) getting records from %s index\n"),
1568 rc, tagName(dbi->dbi_rpmtag));
1569 }
1570 if (rc == 0)
1571 (void) dbt2set(dbi, data, &dnset);
1572 xx = dbiCclose(dbi, dbcursor, 0);
1573
1574 /* If dnset is non-empty, then attempt Plan A intersection. */
1575 if (rc == 0 && dnset && dnset->count > 0) {
1576 unsigned int tag = taghash(dirName);
1577 xx = dbiIntersect(tag, dnset, bnset, matches);
1578 bnset = dbiFreeIndexSet(bnset);
1579 dnset = dbiFreeIndexSet(dnset);
1580 return (*matches != NULL ? 0 : 1);
1581 }
1582 dnset = dbiFreeIndexSet(dnset);
1583 }
1584
1585 /* Plan B: Reduce the size of the index set before loading headers. */
1586 if (_db_tagged_file_indices) {
1587 if (_db_tagged_findbyfile && bnset->count > 1 && *dirName != '\0') {
1588 unsigned int tag = taghash(dirName);
1589 int j = 0;
1590
1591 /* Prune the bnset using the directory tag. */
1592 for (i = 0; i < bnset->count; i++) {
1593 if (bnset->recs[i].tagNum & 0x80000000) {
1594 unsigned int ctag = (bnset->recs[i].tagNum & 0xffff0000);
1595 bnset->recs[i].tagNum &= 0x0000ffff;
1596 if (ctag != tag)
1597 continue;
1598 }
1599 if (i > j)
1600 bnset->recs[j] = bnset->recs[i]; /* structure assignment */
1601 j++;
1602 }
1603 /* If bnset was shortened by dir tagging, reset the count. */
1604 if (j > 0 && j < bnset->count)
1605 bnset->count = j;
1606 } else {
1607 /* Strip off directory tags. */
1608 for (i = 0; i < bnset->count; i++) {
1609 if (bnset->recs[i].tagNum & 0x80000000)
1610 bnset->recs[i].tagNum &= 0x0000ffff;
1611 }
1612 }
1613 }
1614
1615 /* OK, find the file using fingerprints and loading headers. */
1616 { HE_t BN = memset(alloca(sizeof(*BN)), 0, sizeof(*BN));
1617 HE_t DN = memset(alloca(sizeof(*DN)), 0, sizeof(*DN));
1618 HE_t DI = memset(alloca(sizeof(*DI)), 0, sizeof(*DI));
1619 fingerPrintCache fpc = fpCacheCreate(20);
1620 fingerPrint fp1 = fpLookup(fpc, dirName, baseName, 1);
1621 rpmmi mi = NULL;
1622 unsigned int prevoff = 0;
1623 Header h;
1624
1625 /* Create an iterator for the matches. */
1626 mi = rpmmiInit(db, RPMDBI_PACKAGES, NULL, 0);
1627 mi->mi_set = bnset;
1628
1629 prevoff = 0;
1630 BN->tag = RPMTAG_BASENAMES;
1631 DN->tag = RPMTAG_DIRNAMES;
1632 DI->tag = RPMTAG_DIRINDEXES;
1633
1634 /* Find the file(s) with the same fingerprint. */
1635 while ((h = rpmmiNext(mi)) != NULL) {
1636 fingerPrint fp2;
1637 int num;
1638
1639 /* Reload tags when header changes. */
1640 if (prevoff != rpmmiInstance(mi)) {
1641 prevoff = rpmmiInstance(mi);
1642 BN->p.ptr = _free(BN->p.ptr);
1643 xx = headerGet(h, BN, 0);
1644 DN->p.ptr = _free(DN->p.ptr);
1645 xx = headerGet(h, DN, 0);
1646 DI->p.ptr = _free(DI->p.ptr);
1647 xx = headerGet(h, DI, 0);
1648 }
1649
1650 num = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx-1);
1651 assert(num >= 0 && num < (int)BN->c);
1652 fp2 = fpLookup(fpc, DN->p.argv[DI->p.ui32p[num]], BN->p.argv[num], 1);
1653
1654 /*@-nullpass@*/
1655 if (FP_EQUAL(fp1, fp2))
1656 /*@=nullpass@*/
1657 {
1658 dbiIndexItem rec = &mi->mi_set->recs[mi->mi_setx-1];
1659 if (*matches == NULL)
1660 *matches = xcalloc(1, sizeof(**matches));
1661 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0);
1662 }
1663 }
1664
1665 BN->p.ptr = _free(BN->p.ptr);
1666 DN->p.ptr = _free(DN->p.ptr);
1667 DI->p.ptr = _free(DI->p.ptr);
1668 mi = rpmmiFree(mi);
1669
1670 fpc = fpCacheFree(fpc);
1671 }
1672
1673 return (*matches != NULL ? 0 : 1);
1674 }
1675
1676 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen)
1677 {
1678 DBC * dbcursor = NULL;
1679 DBT k = DBT_INIT;
1680 DBT v = DBT_INIT;
1681 dbiIndex dbi;
1682 int rc;
1683 int xx;
1684
1685 if (db == NULL || keyp == NULL)
1686 return 0;
1687
1688 dbi = dbiOpen(db, tag, 0);
1689 if (dbi == NULL)
1690 return 0;
1691
1692 if (keylen == 0)
1693 keylen = strlen(keyp);
1694
1695 /*@-temptrans@*/
1696 k.data = (void *) keyp;
1697 /*@=temptrans@*/
1698 k.size = (UINT32_T) keylen;
1699
1700 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
1701 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
1702 #ifndef SQLITE_HACK
1703 xx = dbiCclose(dbi, dbcursor, 0);
1704 dbcursor = NULL;
1705 #endif
1706
1707 if (rc == 0) { /* success */
1708 dbiIndexSet matches;
1709 /*@-nullpass@*/ /* FIX: matches might be NULL */
1710 matches = NULL;
1711 (void) dbt2set(dbi, &v, &matches);
1712 if (matches) {
1713 rc = dbiIndexSetCount(matches);
1714 matches = dbiFreeIndexSet(matches);
1715 }
1716 /*@=nullpass@*/
1717 } else
1718 if (rc == DB_NOTFOUND) { /* not found */
1719 rc = 0;
1720 } else { /* error */
1721 rpmlog(RPMLOG_ERR,
1722 _("error(%d) getting records from %s index\n"),
1723 rc, tagName(dbi->dbi_rpmtag));
1724 rc = -1;
1725 }
1726
1727 #ifdef SQLITE_HACK
1728 xx = dbiCclose(dbi, dbcursor, 0);
1729 dbcursor = NULL;
1730 #endif
1731
1732 return rc;
1733 }
1734
1735 /* XXX python/upgrade.c, install.c, uninstall.c */
1736 int rpmdbCountPackages(rpmdb db, const char * name)
1737 {
1738 return rpmdbCount(db, RPMTAG_NAME, name, 0);
1739 }
1740
1753 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor,
1754 DBT * key, DBT * data,
1755 const char * name,
1756 /*@null@*/ const char * version,
1757 /*@null@*/ const char * release,
1758 /*@out@*/ dbiIndexSet * matches)
1759 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1760 /*@modifies dbi, *dbcursor, *key, *data, *matches,
1761 rpmGlobalMacroContext, fileSystem, internalState @*/
1762 /*@requires maxSet(matches) >= 0 @*/
1763 {
1764 int gotMatches = 0;
1765 int rc;
1766 unsigned i;
1767
1768 /*@-temptrans@*/
1769 key->data = (void *) name;
1770 /*@=temptrans@*/
1771 key->size = (UINT32_T) strlen(name);
1772
1773 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
1774
1775 if (rc == 0) { /* success */
1776 (void) dbt2set(dbi, data, matches);
1777 if (version == NULL && release == NULL)
1778 return RPMRC_OK;
1779 } else
1780 if (rc == DB_NOTFOUND) { /* not found */
1781 return RPMRC_NOTFOUND;
1782 } else { /* error */
1783 rpmlog(RPMLOG_ERR,
1784 _("error(%d) getting records from %s index\n"),
1785 rc, tagName(dbi->dbi_rpmtag));
1786 return RPMRC_FAIL;
1787 }
1788
1789 /* Make sure the version and release match. */
1790 for (i = 0; i < dbiIndexSetCount(*matches); i++) {
1791 unsigned int recoff = dbiIndexRecordOffset(*matches, i);
1792 rpmmi mi;
1793 Header h;
1794
1795 if (recoff == 0)
1796 continue;
1797
1798 mi = rpmmiInit(dbi->dbi_rpmdb,
1799 RPMDBI_PACKAGES, &recoff, sizeof(recoff));
1800
1801 /* Set iterator selectors for version/release if available. */
1802 if (version &&
1803 rpmmiAddPattern(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version))
1804 {
1805 rc = RPMRC_FAIL;
1806 goto exit;
1807 }
1808 if (release &&
1809 rpmmiAddPattern(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release))
1810 {
1811 rc = RPMRC_FAIL;
1812 goto exit;
1813 }
1814
1815 h = rpmmiNext(mi);
1816 if (h)
1817 (*matches)->recs[gotMatches++] = (*matches)->recs[i];
1818 else
1819 (*matches)->recs[i].hdrNum = 0;
1820 mi = rpmmiFree(mi);
1821 }
1822
1823 if (gotMatches) {
1824 (*matches)->count = gotMatches;
1825 rc = RPMRC_OK;
1826 } else
1827 rc = RPMRC_NOTFOUND;
1828
1829 exit:
1830 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1831 if (rc && matches && *matches)
1832 *matches = dbiFreeIndexSet(*matches);
1833 /*@=unqualifiedtrans@*/
1834 return rc;
1835 }
1836
1849 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1850 /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches)
1851 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
1852 /*@modifies dbi, *dbcursor, *key, *data, *matches,
1853 rpmGlobalMacroContext, fileSystem, internalState @*/
1854 /*@requires maxSet(matches) >= 0 @*/
1855 {
1856 const char * release;
1857 char * localarg;
1858 char * s;
1859 char c;
1860 int brackets;
1861 rpmRC rc;
1862
1863 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND;
1864
1865 /* did they give us just a name? */
1866 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches);
1867 if (rc != RPMRC_NOTFOUND) return rc;
1868
1869 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1870 *matches = dbiFreeIndexSet(*matches);
1871 /*@=unqualifiedtrans@*/
1872
1873 /* maybe a name and a release */
1874 localarg = alloca(strlen(arg) + 1);
1875 s = stpcpy(localarg, arg);
1876
1877 c = '\0';
1878 brackets = 0;
1879 for (s -= 1; s > localarg; s--) {
1880 switch (*s) {
1881 case '[':
1882 brackets = 1;
1883 /*@switchbreak@*/ break;
1884 case ']':
1885 if (c != '[') brackets = 0;
1886 /*@switchbreak@*/ break;
1887 }
1888 c = *s;
1889 if (!brackets && *s == '-')
1890 break;
1891 }
1892
1893 /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1894 if (s == localarg) return RPMRC_NOTFOUND;
1895
1896 *s = '\0';
1897 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches);
1898 /*@=nullstate@*/
1899 if (rc != RPMRC_NOTFOUND) return rc;
1900
1901 /*@-unqualifiedtrans@*/ /* FIX: double indirection */
1902 *matches = dbiFreeIndexSet(*matches);
1903 /*@=unqualifiedtrans@*/
1904
1905 /* how about name-version-release? */
1906
1907 release = s + 1;
1908
1909 c = '\0';
1910 brackets = 0;
1911 for (; s > localarg; s--) {
1912 switch (*s) {
1913 case '[':
1914 brackets = 1;
1915 /*@switchbreak@*/ break;
1916 case ']':
1917 if (c != '[') brackets = 0;
1918 /*@switchbreak@*/ break;
1919 }
1920 c = *s;
1921 if (!brackets && *s == '-')
1922 break;
1923 }
1924
1925 if (s == localarg) return RPMRC_NOTFOUND;
1926
1927 *s = '\0';
1928 /*@-nullstate@*/ /* FIX: *matches may be NULL. */
1929 return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches);
1930 /*@=nullstate@*/
1931 }
1932
1933 void * dbiStatsAccumulator(dbiIndex dbi, int opx)
1934 {
1935 void * sw = NULL;
1936 switch (opx) {
1937 case 14: /* RPMTS_OP_DBGET */
1938 sw = &dbi->dbi_rpmdb->db_getops;
1939 break;
1940 case 15: /* RPMTS_OP_DBPUT */
1941 sw = &dbi->dbi_rpmdb->db_putops;
1942 break;
1943 default: /* XXX wrong, but let's not return NULL. */
1944 case 16: /* RPMTS_OP_DBDEL */
1945 sw = &dbi->dbi_rpmdb->db_delops;
1946 break;
1947 }
1948 return sw;
1949 }
1950
1959 static int miFreeHeader(rpmmi mi, dbiIndex dbi)
1960 /*@globals fileSystem, internalState @*/
1961 /*@modifies mi, dbi, fileSystem, internalState @*/
1962 {
1963 int rc = 0;
1964
1965 if (mi == NULL || mi->mi_h == NULL)
1966 return 0;
1967
1968 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) {
1969 DBT k = DBT_INIT;
1970 DBT v = DBT_INIT;
1971 rpmRC rpmrc = RPMRC_NOTFOUND;
1972 int xx;
1973
1974 /*@i@*/ k.data = (void *) &mi->mi_prevoffset;
1975 k.size = (UINT32_T) sizeof(mi->mi_prevoffset);
1976 { size_t len = 0;
1977 v.data = headerUnload(mi->mi_h, &len);
1978 v.size = (UINT32_T) len;
1979 }
1980
1981 /* Check header digest/signature on blob export (if requested). */
1982 if (mi->mi_ts) {
1983 const char * msg = NULL;
1984 int lvl;
1985
1986 assert(v.data != NULL);
1987 rpmrc = headerCheck(rpmtsDig(mi->mi_ts), v.data, v.size, &msg);
1988 rpmtsCleanDig(mi->mi_ts);
1989 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
1990 rpmlog(lvl, "%s h#%8u %s",
1991 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"),
1992 mi->mi_prevoffset, (msg ? msg : "\n"));
1993 msg = _free(msg);
1994 }
1995
1996 if (v.data != NULL && rpmrc != RPMRC_FAIL) {
1997 sigset_t signalMask;
1998 (void) blockSignals(dbi->dbi_rpmdb, &signalMask);
1999 rc = dbiPut(dbi, mi->mi_dbc, &k, &v, DB_KEYLAST);
2000 if (rc) {
2001 rpmlog(RPMLOG_ERR,
2002 _("error(%d) storing record #%d into %s\n"),
2003 rc, mi->mi_prevoffset, tagName(dbi->dbi_rpmtag));
2004 }
2005 xx = dbiSync(dbi, 0);
2006 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask);
2007 }
2008 v.data = _free(v.data); /* headerUnload */
2009 v.size = 0;
2010 }
2011
2012 (void)headerFree(mi->mi_h);
2013 mi->mi_h = NULL;
2014
2015 /*@-nullstate@*/
2016 return rc;
2017 /*@=nullstate@*/
2018 }
2019
2020 static void rpmmiFini(void * _mi)
2021 /*@globals rpmmiRock @*/
2022 /*@modifies _mi, rpmmiRock @*/
2023 {
2024 rpmmi mi = _mi;
2025 rpmmi * prev, next;
2026 dbiIndex dbi;
2027 int xx;
2028
2029 prev = &rpmmiRock;
2030 while ((next = *prev) != NULL && next != mi)
2031 prev = &next->mi_next;
2032 if (next) {
2033 /*@i@*/ *prev = next->mi_next;
2034 next->mi_next = NULL;
2035 }
2036
2037 /* XXX there's code that traverses here w mi->mi_db == NULL. b0rked imho. */
2038 if (mi->mi_db) {
2039 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
2040 assert(dbi != NULL);
2041
2042 xx = miFreeHeader(mi, dbi);
2043
2044 if (mi->mi_dbc)
2045 xx = dbiCclose(dbi, mi->mi_dbc, 0);
2046 mi->mi_dbc = NULL;
2047 /* XXX rpmdbUnlink will not do.
2048 * NB: must be called after rpmmiRock cleanup.
2049 */
2050 (void) rpmdbClose(mi->mi_db);
2051 mi->mi_db = NULL;
2052 }
2053
2054 mi->mi_re = mireFreeAll(mi->mi_re, mi->mi_nre);
2055
2056 mi->mi_set = dbiFreeIndexSet(mi->mi_set);
2057
2058 /* XXX this needs to be done elsewhere, not within destructor. */
2059 (void) rpmdbCheckSignals();
2060 }
2061
2062 /*@unchecked@*/
2063 int _rpmmi_debug = 0;
2064
2065 /*@unchecked@*/ /*@only@*/ /*@null@*/
2066 rpmioPool _rpmmiPool;
2067
2068 static rpmmi rpmmiGetPool(/*@null@*/ rpmioPool pool)
2069 /*@globals _rpmdbPool, fileSystem @*/
2070 /*@modifies pool, _rpmdbPool, fileSystem @*/
2071 {
2072 rpmmi mi;
2073
2074 if (_rpmmiPool == NULL) {
2075 _rpmmiPool = rpmioNewPool("mi", sizeof(*mi), -1, _rpmmi_debug,
2076 NULL, NULL, rpmmiFini);
2077 pool = _rpmmiPool;
2078 }
2079 return (rpmmi) rpmioGetPool(pool, sizeof(*mi));
2080 }
2081
2082 unsigned int rpmmiInstance(rpmmi mi) {
2083 return (mi ? mi->mi_offset : 0);
2084 }
2085
2086 unsigned int rpmmiFilenum(rpmmi mi) {
2087 return (mi ? mi->mi_filenum : 0);
2088 }
2089
2090 int rpmmiCount(rpmmi mi) {
2091 return (mi && mi->mi_set ? mi->mi_set->count : 0);
2092 }
2093
2100 static int mireCmp(const void * a, const void * b)
2101 {
2102 /*@-castexpose @*/
2103 const miRE mireA = (const miRE) a;
2104 const miRE mireB = (const miRE) b;
2105 /*@=castexpose @*/
2106 return (mireA->tag - mireB->tag);
2107 }
2108
2116 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep,
2117 const char * pattern)
2118 /*@modifies *modep @*/
2119 /*@requires maxSet(modep) >= 0 @*/
2120 {
2121 const char * s;
2122 char * pat;
2123 char * t;
2124 int brackets;
2125 size_t nb;
2126 int c;
2127
2128 switch (*modep) {
2129 default:
2130 case RPMMIRE_DEFAULT:
2131 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) {
2132 *modep = RPMMIRE_GLOB;
2133 pat = xstrdup(pattern);
2134 break;
2135 }
2136
2137 nb = strlen(pattern) + sizeof("^$");
2138
2139 /* Find no. of bytes needed for pattern. */
2140 /* periods and plusses are escaped, splats become '.*' */
2141 c = (int) '\0';
2142 brackets = 0;
2143 for (s = pattern; *s != '\0'; s++) {
2144 switch (*s) {
2145 case '.':
2146 case '+':
2147 case '*':
2148 if (!brackets) nb++;
2149 /*@switchbreak@*/ break;
2150 case '\\':
2151 s++;
2152 /*@switchbreak@*/ break;
2153 case '[':
2154 brackets = 1;
2155 /*@switchbreak@*/ break;
2156 case ']':
2157 if (c != (int) '[') brackets = 0;
2158 /*@switchbreak@*/ break;
2159 }
2160 c = (int) *s;
2161 }
2162
2163 pat = t = xmalloc(nb);
2164
2165 if (pattern[0] != '^') *t++ = '^';
2166
2167 /* Copy pattern, escaping periods, prefixing splats with period. */
2168 c = (int) '\0';
2169 brackets = 0;
2170 for (s = pattern; *s != '\0'; s++, t++) {
2171 switch (*s) {
2172 case '.':
2173 case '+':
2174 if (!brackets) *t++ = '\\';
2175 /*@switchbreak@*/ break;
2176 case '*':
2177 if (!brackets) *t++ = '.';
2178 /*@switchbreak@*/ break;
2179 case '\\':
2180 *t++ = *s++;
2181 /*@switchbreak@*/ break;
2182 case '[':
2183 brackets = 1;
2184 /*@switchbreak@*/ break;
2185 case ']':
2186 if (c != (int) '[') brackets = 0;
2187 /*@switchbreak@*/ break;
2188 }
2189 *t = *s;
2190 c = (int) *t;
2191 }
2192
2193 if (s > pattern && s[-1] != '$') *t++ = '$';
2194 *t = '\0';
2195 *modep = RPMMIRE_REGEX;
2196 break;
2197 case RPMMIRE_STRCMP:
2198 case RPMMIRE_REGEX:
2199 case RPMMIRE_GLOB:
2200 pat = xstrdup(pattern);
2201 break;
2202 }
2203
2204 return pat;
2205 }
2206
2207 int rpmmiAddPattern(rpmmi mi, rpmTag tag,
2208 rpmMireMode mode, const char * pattern)
2209 {
2210 static rpmMireMode defmode = (rpmMireMode)-1;
2211 miRE nmire = NULL;
2212 miRE mire = NULL;
2213 const char * allpat = NULL;
2214 int notmatch = 0;
2215 int rc = 0;
2216
2217 if (defmode == (rpmMireMode)-1) {
2218 const char *t = rpmExpand("%{?_query_selector_match}", NULL);
2219
2220 if (*t == '\0' || !strcmp(t, "default"))
2221 defmode = RPMMIRE_DEFAULT;
2222 else if (!strcmp(t, "strcmp"))
2223 defmode = RPMMIRE_STRCMP;
2224 else if (!strcmp(t, "regex"))
2225 defmode = RPMMIRE_REGEX;
2226 else if (!strcmp(t, "glob"))
2227 defmode = RPMMIRE_GLOB;
2228 else
2229 defmode = RPMMIRE_DEFAULT;
2230 t = _free(t);
2231 }
2232
2233 if (mi == NULL || pattern == NULL)
2234 return rc;
2235
2236 /* Leading '!' inverts pattern match sense, like "grep -v". */
2237 if (*pattern == '!') {
2238 notmatch = 1;
2239 pattern++;
2240 }
2241
2242 nmire = mireNew(mode, tag);
2243 assert(nmire != NULL);
2244 allpat = mireDup(nmire->tag, &nmire->mode, pattern);
2245
2246 if (nmire->mode == RPMMIRE_DEFAULT)
2247 nmire->mode = defmode;
2248
2249 rc = mireRegcomp(nmire, allpat);
2250 if (rc)
2251 goto exit;
2252
2253 if (mi->mi_re == NULL) {
2254 mi->mi_re = mireGetPool(_mirePool);
2255 mire = mi->mi_re;
2256 } else {
2257 void *use = mi->mi_re->_item.use;
2258 void *pool = mi->mi_re->_item.pool;
2259 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re));
2260 mire = mi->mi_re + mi->mi_nre;
2261 memset(mire, 0, sizeof(*mire));
2262 /* XXX ensure no segfault, copy the use/pool from 1st item. */
2263 /*@-assignexpose@*/
2264 mire->_item.use = use;
2265 mire->_item.pool = pool;
2266 /*@=assignexpose@*/
2267 }
2268 mi->mi_nre++;
2269
2270 mire->mode = nmire->mode;
2271 mire->pattern = nmire->pattern; nmire->pattern = NULL;
2272 mire->preg = nmire->preg; nmire->preg = NULL;
2273 mire->cflags = nmire->cflags;
2274 mire->eflags = nmire->eflags;
2275 mire->fnflags = nmire->fnflags;
2276 mire->tag = nmire->tag;
2277 mire->notmatch = notmatch;
2278 /* XXX todo: permit PCRE patterns to be used. */
2279 mire->offsets = NULL;
2280 mire->noffsets = 0;
2281
2282 if (mi->mi_nre > 1)
2283 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp);
2284
2285 exit:
2286 allpat = _free(allpat);
2287 nmire = mireFree(nmire);
2288 return rc;
2289 }
2290
2296 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */
2297 static int mireSkip (const rpmmi mi)
2298 /*@globals internalState @*/
2299 /*@modifies mi->mi_re, internalState @*/
2300 {
2301 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2302 char numbuf[32];
2303 miRE mire;
2304 int ntags = 0;
2305 int nmatches = 0;
2306 int i;
2307 int rc;
2308
2309 if (mi->mi_h == NULL) /* XXX can't happen */
2310 return 1;
2311
2312 /*
2313 * Apply tag tests, implicitly "||" for multiple patterns/values of a
2314 * single tag, implicitly "&&" between multiple tag patterns.
2315 */
2316 if ((mire = mi->mi_re) == NULL)
2317 return 0;
2318
2319 for (i = 0; i < mi->mi_nre; i++, mire++) {
2320 int anymatch;
2321
2322 he->tag = mire->tag;
2323
2324 if (!headerGet(mi->mi_h, he, 0)) {
2325 if (he->tag != RPMTAG_EPOCH) {
2326 ntags++;
2327 continue;
2328 }
2329 he->t = RPM_UINT32_TYPE;
2330 he->p.ui32p = xcalloc(1, sizeof(*he->p.ui32p));
2331 he->c = 1;
2332 }
2333
2334 anymatch = 0; /* no matches yet */
2335 while (1) {
2336 unsigned j;
2337 switch (he->t) {
2338 case RPM_UINT8_TYPE:
2339 for (j = 0; j < (unsigned) he->c; j++) {
2340 sprintf(numbuf, "%u", (unsigned) he->p.ui8p[j]);
2341 rc = mireRegexec(mire, numbuf, 0);
2342 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2343 anymatch++;
2344 }
2345 /*@switchbreak@*/ break;
2346 case RPM_UINT16_TYPE:
2347 for (j = 0; j < (unsigned) he->c; j++) {
2348 sprintf(numbuf, "%u", (unsigned) he->p.ui16p[j]);
2349 rc = mireRegexec(mire, numbuf, 0);
2350 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2351 anymatch++;
2352 }
2353 /*@switchbreak@*/ break;
2354 case RPM_UINT32_TYPE:
2355 for (j = 0; j < (unsigned) he->c; j++) {
2356 sprintf(numbuf, "%u", (unsigned) he->p.ui32p[j]);
2357 rc = mireRegexec(mire, numbuf, 0);
2358 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2359 anymatch++;
2360 }
2361 /*@switchbreak@*/ break;
2362 case RPM_UINT64_TYPE:
2363 /*@-duplicatequals@*/
2364 for (j = 0; j < (unsigned) he->c; j++) {
2365 sprintf(numbuf, "%llu", (unsigned long long)he->p.ui64p[j]);
2366 rc = mireRegexec(mire, numbuf, 0);
2367 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2368 anymatch++;
2369 }
2370 /*@=duplicatequals@*/
2371 /*@switchbreak@*/ break;
2372 case RPM_STRING_TYPE:
2373 rc = mireRegexec(mire, he->p.str, 0);
2374 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2375 anymatch++;
2376 /*@switchbreak@*/ break;
2377 case RPM_STRING_ARRAY_TYPE:
2378 for (j = 0; j < (unsigned) he->c; j++) {
2379 rc = mireRegexec(mire, he->p.argv[j], 0);
2380 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) {
2381 anymatch++;
2382 /*@innerbreak@*/ break;
2383 }
2384 }
2385 /*@switchbreak@*/ break;
2386 case RPM_BIN_TYPE:
2387 { const char * s;
2388 assert(he->p.ptr != NULL);
2389 s = bin2hex(he->p.ptr, he->c);
2390 rc = mireRegexec(mire, s, 0);
2391 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch))
2392 anymatch++;
2393 s = _free(s);
2394 } /*@switchbreak@*/ break;
2395 case RPM_I18NSTRING_TYPE:
2396 default:
2397 /*@switchbreak@*/ break;
2398 }
2399 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) {
2400 i++;
2401 mire++;
2402 /*@innercontinue@*/ continue;
2403 }
2404 /*@innerbreak@*/ break;
2405 }
2406
2407 he->p.ptr = _free(he->p.ptr);
2408
2409 if (anymatch)
2410 nmatches++;
2411 ntags++;
2412 }
2413
2414 return (ntags > 0 && ntags == nmatches ? 0 : 1);
2415 }
2416 /*@=onlytrans@*/
2417
2418 int rpmmiSetRewrite(rpmmi mi, int rewrite)
2419 {
2420 int rc;
2421 if (mi == NULL)
2422 return 0;
2423 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0;
2424 if (rewrite)
2425 mi->mi_cflags |= DB_WRITECURSOR;
2426 else
2427 mi->mi_cflags &= ~DB_WRITECURSOR;
2428 return rc;
2429 }
2430
2431 int rpmmiSetModified(rpmmi mi, int modified)
2432 {
2433 int rc;
2434 if (mi == NULL)
2435 return 0;
2436 rc = mi->mi_modified;
2437 mi->mi_modified = modified;
2438 return rc;
2439 }
2440
2441 int rpmmiSetHdrChk(rpmmi mi, rpmts ts)
2442 {
2443 int rc = 0;
2444 if (mi == NULL)
2445 return 0;
2446 /*@-assignexpose -newreftrans @*/ /* XXX forward linkage prevents rpmtsLink */
2447 /*@i@*/ mi->mi_ts = ts;
2448 /*@=assignexpose =newreftrans @*/
2449 return rc;
2450 }
2451
2452 static int _rpmmi_usermem = 1;
2453
2454 static int rpmmiGet(dbiIndex dbi, DBC * dbcursor, DBT * kp, DBT * vp,
2455 unsigned int flags)
2456 {
2457 int map;
2458 int rc;
2459
2460 switch (dbi->dbi_rpmdb->db_api) {
2461 default: map = 0; break;
2462 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */
2463 }
2464
2465 if (map) {
2466 static const int _prot = PROT_READ | PROT_WRITE;
2467 static const int _flags = MAP_PRIVATE| MAP_ANONYMOUS;
2468 static const int _fdno = -1;
2469 static const off_t _off = 0;
2470
2471 vp->flags |= DB_DBT_USERMEM;
2472 rc = dbiGet(dbi, dbcursor, kp, vp, flags);
2473 if (rc == DB_BUFFER_SMALL) {
2474 size_t uhlen = vp->size;
2475 void * uh = mmap(NULL, uhlen, _prot, _flags, _fdno, _off);
2476 if (uh == NULL || uh == (void *)-1)
2477 fprintf(stderr,
2478 "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n",
2479 NULL, uhlen, _prot, _flags, _fdno, (unsigned)_off,
2480 errno, strerror(errno));
2481
2482 vp->ulen = (u_int32_t)uhlen;
2483 vp->data = uh;
2484 rc = dbiGet(dbi, dbcursor, kp, vp, DB_SET);
2485 if (rc == 0) {
2486 if (mprotect(uh, uhlen, PROT_READ) != 0)
2487 fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n",
2488 uh, uhlen, PROT_READ,
2489 errno, strerror(errno));
2490 } else {
2491 if (munmap(uh, uhlen) != 0)
2492 fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n",
2493 uh, uhlen, errno, strerror(errno));
2494 }
2495 }
2496 } else
2497 rc = dbiGet(dbi, dbcursor, kp, vp, flags);
2498 return rc;
2499 }
2500
2501 Header rpmmiNext(rpmmi mi)
2502 {
2503 dbiIndex dbi;
2504 DBT k = DBT_INIT;
2505 DBT v = DBT_INIT;
2506 union _dbswap mi_offset;
2507 void * uh;
2508 size_t uhlen;
2509 int map;
2510 int rc;
2511 int xx;
2512
2513 if (mi == NULL)
2514 return NULL;
2515
2516 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0);
2517 if (dbi == NULL)
2518 return NULL;
2519
2520 switch (dbi->dbi_rpmdb->db_api) {
2521 default: map = 0; break;
2522 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */
2523 }
2524
2525 /*
2526 * Cursors are per-iterator, not per-dbi, so get a cursor for the
2527 * iterator on 1st call. If the iteration is to rewrite headers, and the
2528 * CDB model is used for the database, then the cursor needs to
2529 * marked with DB_WRITECURSOR as well.
2530 */
2531 if (mi->mi_dbc == NULL)
2532 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags);
2533
2534 next:
2535 if (mi->mi_set) {
2536 /* The set of header instances is known in advance. */
2537 if (!(mi->mi_setx < mi->mi_set->count))
2538 return NULL;
2539 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx);
2540 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx);
2541 mi->mi_setx++;
2542 /* If next header is identical, return it now. */
2543 if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL)
2544 return mi->mi_h;
2545 /* Fetch header by offset. */
2546 mi_offset.ui = mi->mi_offset;
2547 if (dbiByteSwapped(dbi) == 1)
2548 _DBSWAP(mi_offset);
2549 /*@-immediatetrans@*/
2550 k.data = &mi_offset.ui;
2551 /*@=immediatetrans@*/
2552 k.size = (u_int32_t)sizeof(mi_offset.ui);
2553 rc = rpmmiGet(dbi, mi->mi_dbc, &k, &v, DB_SET);
2554 }
2555 else {
2556 /* Iterating Packages database. */
2557 assert(mi->mi_rpmtag == RPMDBI_PACKAGES);
2558
2559 /* Fetch header with DB_NEXT. */
2560 /* Instance 0 is the largest header instance in the database,
2561 * and should be skipped. */
2562 do {
2563 rc = rpmmiGet(dbi, mi->mi_dbc, &k, &v, DB_NEXT);
2564 if (rc == 0) {
2565 memcpy(&mi_offset, k.data, sizeof(mi_offset.ui));
2566 if (dbiByteSwapped(dbi) == 1)
2567 _DBSWAP(mi_offset);
2568 mi->mi_offset = mi_offset.ui;
2569 }
2570 } while (rc == 0 && mi_offset.ui == 0);
2571 }
2572
2573 /* Did the header blob load correctly? */
2574 if (rc)
2575 return NULL;
2576
2577 uh = v.data;
2578 uhlen = v.size;
2579
2580 if (uh == NULL)
2581 return NULL;
2582
2583 /* Rewrite current header (if necessary) and unlink. */
2584 xx = miFreeHeader(mi, dbi);
2585
2586 /* Check header digest/signature once (if requested). */
2587 if (mi->mi_ts) {
2588 rpmRC rpmrc = RPMRC_NOTFOUND;
2589
2590 /* Don't bother re-checking a previously read header. */
2591 if (mi->mi_db->db_bits) {
2592 pbm_set * set;
2593
2594 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2595 &mi->mi_db->db_nbits, mi->mi_offset);
2596 if (PBM_ISSET(mi->mi_offset, set))
2597 rpmrc = RPMRC_OK;
2598 }
2599
2600 /* If blob is unchecked, check blob import consistency now. */
2601 if (rpmrc != RPMRC_OK) {
2602 const char * msg = NULL;
2603 int lvl;
2604
2605 rpmrc = headerCheck(rpmtsDig(mi->mi_ts), uh, uhlen, &msg);
2606 rpmtsCleanDig(mi->mi_ts);
2607 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
2608 rpmlog(lvl, "%s h#%8u %s\n",
2609 (rpmrc == RPMRC_FAIL ? _("rpmdb: skipping") : _("rpmdb: read")),
2610 mi->mi_offset, (msg ? msg : ""));
2611 msg = _free(msg);
2612
2613 /* Mark header checked. */
2614 if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) {
2615 pbm_set * set;
2616
2617 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits,
2618 &mi->mi_db->db_nbits, mi->mi_offset);
2619 PBM_SET(mi->mi_offset, set);
2620 }
2621
2622 /* Skip damaged and inconsistent headers. */
2623 if (rpmrc == RPMRC_FAIL)
2624 goto next;
2625 }
2626 }
2627
2628 if (map) {
2629 /*@-onlytrans@*/
2630 mi->mi_h = headerLoad(uh);
2631 /*@=onlytrans@*/
2632 if (mi->mi_h) {
2633 mi->mi_h->flags |= HEADERFLAG_MAPPED;
2634 mi->mi_h->flags |= HEADERFLAG_RDONLY;
2635 }
2636 } else
2637 mi->mi_h = headerCopyLoad(uh);
2638
2639 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) {
2640 rpmlog(RPMLOG_ERR,
2641 _("rpmdb: damaged header #%u retrieved -- skipping.\n"),
2642 mi->mi_offset);
2643 /* damaged header should not be reused */
2644 if (mi->mi_h) {
2645 (void)headerFree(mi->mi_h);
2646 mi->mi_h = NULL;
2647 }
2648 /* TODO: skip more mi_set records */
2649 goto next;
2650 }
2651
2652 /* Skip this header if iterator selector (if any) doesn't match. */
2653 if (mireSkip(mi))
2654 goto next;
2655
2656 /* Mark header with its instance number. */
2657 { char origin[32];
2658 sprintf(origin, "rpmdb (h#%u)", mi->mi_offset);
2659 (void) headerSetOrigin(mi->mi_h, origin);
2660 (void) headerSetInstance(mi->mi_h, mi->mi_offset);
2661 }
2662
2663 mi->mi_prevoffset = mi->mi_offset;
2664 mi->mi_modified = 0;
2665
2666 /*@-compdef -retalias -retexpose -usereleased @*/
2667 return mi->mi_h;
2668 /*@=compdef =retalias =retexpose =usereleased @*/
2669 }
2670
2671 static void rpmdbSortIterator(/*@null@*/ rpmmi mi)
2672 /*@modifies mi @*/
2673 {
2674 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) {
2675 /*
2676 * mergesort is much (~10x with lots of identical basenames) faster
2677 * than pure quicksort, but glibc uses msort_with_tmp() on stack.
2678 */
2679 #if defined(__GLIBC__)
2680 qsort(mi->mi_set->recs, mi->mi_set->count,
2681 sizeof(*mi->mi_set->recs), hdrNumCmp);
2682 #else
2683 rpm_mergesort(mi->mi_set->recs, mi->mi_set->count,
2684 sizeof(*mi->mi_set->recs), hdrNumCmp);
2685 #endif
2686 mi->mi_sorted = 1;
2687 }
2688 }
2689
2690 static int rpmdbGrowIterator(/*@null@*/ rpmmi mi, int fpNum,
2691 unsigned int exclude, unsigned int tag)
2692 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
2693 /*@modifies mi, rpmGlobalMacroContext, fileSystem, internalState @*/
2694 {
2695 DBC * dbcursor;
2696 DBT * key;
2697 DBT * data;
2698 dbiIndex dbi = NULL;
2699 dbiIndexSet set;
2700 int rc;
2701 int xx;
2702 int i, j;
2703
2704 if (mi == NULL)
2705 return 1;
2706
2707 dbcursor = mi->mi_dbc;
2708 key = &mi->mi_key;
2709 data = &mi->mi_data;
2710 if (key->data == NULL)
2711 return 1;
2712
2713 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0);
2714 if (dbi == NULL)
2715 return 1;
2716
2717 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2718 rc = dbiGet(dbi, dbcursor, key, data, DB_SET);
2719 #ifndef SQLITE_HACK
2720 xx = dbiCclose(dbi, dbcursor, 0);
2721 dbcursor = NULL;
2722 #endif
2723
2724 if (rc) { /* error/not found */
2725 if (rc != DB_NOTFOUND)
2726 rpmlog(RPMLOG_ERR,
2727 _("error(%d) getting records from %s index\n"),
2728 rc, tagName(dbi->dbi_rpmtag));
2729 #ifdef SQLITE_HACK
2730 xx = dbiCclose(dbi, dbcursor, 0);
2731 dbcursor = NULL;
2732 #endif
2733 return rc;
2734 }
2735
2736 set = NULL;
2737 (void) dbt2set(dbi, data, &set);
2738
2739 /* prune the set against exclude and tag */
2740 for (i = j = 0; i < set->count; i++) {
2741 if (exclude && set->recs[i].hdrNum == exclude)
2742 continue;
2743 if (_db_tagged_file_indices && set->recs[i].tagNum & 0x80000000) {
2744 /* tagged entry */
2745 if ((set->recs[i].tagNum & 0xffff0000) != tag)
2746 continue;
2747 set->recs[i].tagNum &= 0x0000ffff;
2748 }
2749 if (i > j)
2750 set->recs[j] = set->recs[i];
2751 j++;
2752 }
2753 if (j == 0) {
2754 #ifdef SQLITE_HACK
2755 xx = dbiCclose(dbi, dbcursor, 0);
2756 dbcursor = NULL;
2757 #endif
2758 set = dbiFreeIndexSet(set);
2759 return DB_NOTFOUND;
2760 }
2761 set->count = j;
2762
2763 for (i = 0; i < set->count; i++)
2764 set->recs[i].fpNum = fpNum;
2765
2766 #ifdef SQLITE_HACK
2767 xx = dbiCclose(dbi, dbcursor, 0);
2768 dbcursor = NULL;
2769 #endif
2770
2771 if (mi->mi_set == NULL) {
2772 mi->mi_set = set;
2773 } else {
2774 #if 0
2775 fprintf(stderr, "+++ %d = %d + %d\t\"%s\"\n", (mi->mi_set->count + set->count), mi->mi_set->count, set->count, ((char *)key->data));
2776 #endif
2777 mi->mi_set->recs = xrealloc(mi->mi_set->recs,
2778 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs)));
2779 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs,
2780 set->count * sizeof(*(mi->mi_set->recs)));
2781 mi->mi_set->count += set->count;
2782 set = dbiFreeIndexSet(set);
2783 }
2784
2785 return rc;
2786 }
2787
2788 int rpmmiPrune(rpmmi mi, int * hdrNums, int nHdrNums, int sorted)
2789 {
2790 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2791 return 1;
2792
2793 if (mi->mi_set)
2794 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted);
2795 return 0;
2796 }
2797
2798 int rpmmiGrow(rpmmi mi, const int * hdrNums, int nHdrNums)
2799 {
2800 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0)
2801 return 1;
2802
2803 if (mi->mi_set == NULL)
2804 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set));
2805 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0);
2806 return 0;
2807 }
2808
2809 rpmmi rpmmiInit(rpmdb db, rpmTag tag,
2810 const void * keyp, size_t keylen)
2811 /*@globals rpmmiRock @*/
2812 /*@modifies rpmmiRock @*/
2813 {
2814 rpmmi mi;
2815 dbiIndexSet set = NULL;
2816 dbiIndex dbi;
2817 int isLabel = 0;
2818
2819 if (db == NULL)
2820 return NULL;
2821
2822 (void) rpmdbCheckSignals();
2823
2824 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */
2825 if (tag == RPMDBI_LABEL) {
2826 tag = RPMTAG_NAME;
2827 isLabel = 1;
2828 }
2829
2830 dbi = dbiOpen(db, tag, 0);
2831 if (dbi == NULL)
2832 return NULL;
2833
2834 mi = rpmmiGetPool(_rpmmiPool);
2835 (void)rpmioLinkPoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__);
2836
2837 /* Chain cursors for teardown on abnormal exit. */
2838 mi->mi_next = rpmmiRock;
2839 rpmmiRock = mi;
2840
2841 if (tag == RPMDBI_PACKAGES && keyp == NULL) {
2842 /* Special case #1: will iterate Packages database. */
2843 assert(keylen == 0);
2844 /* This should be the only case when (set == NULL). */
2845 }
2846 else if (tag == RPMDBI_PACKAGES) {
2847 /* Special case #2: will fetch header instance. */
2848 union _dbswap hdrNum;
2849 assert(keylen == sizeof(hdrNum.ui));
2850 memcpy(&hdrNum.ui, keyp, sizeof(hdrNum.ui));
2851 /* The set has only one element, which is hdrNum. */
2852 set = xcalloc(1, sizeof(*set));
2853 set->count = 1;
2854 set->recs = xcalloc(1, sizeof(set->recs[0]));
2855 set->recs[0].hdrNum = hdrNum.ui;
2856 }
2857 else if (keyp == NULL) {
2858 /* XXX Special case #3: they want empty iterator,
2859 * for use with rpmmiGrow(). */
2860 assert(keylen == 0);
2861 }
2862 else {
2863 /* Common case: retrieve join keys. */
2864 DBC * dbcursor = NULL;
2865 DBT k = DBT_INIT;
2866 DBT v = DBT_INIT;
2867 int rc;
2868 int xx;
2869
2870 if (isLabel) {
2871 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2872 rc = dbiFindByLabel(dbi, dbcursor, &k, &v, keyp, &set);
2873 xx = dbiCclose(dbi, dbcursor, 0);
2874 dbcursor = NULL;
2875 } else if (tag == RPMTAG_BASENAMES) {
2876 rc = rpmdbFindByFile(db, keyp, &k, &v, &set);
2877 } else {
2878 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2879
2880 /*@-temptrans@*/
2881 k.data = (void *) keyp;
2882 /*@=temptrans@*/
2883 k.size = (UINT32_T) keylen;
2884 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data);
2885 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */
2886
2887 /*@-nullstate@*/
2888 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
2889 /*@=nullstate@*/
2890 if (rc > 0) {
2891 rpmlog(RPMLOG_ERR,
2892 _("error(%d) getting records from %s index\n"),
2893 rc, tagName(dbi->dbi_rpmtag));
2894 }
2895
2896 /* Join keys need to be native endian internally. */
2897 if (rc == 0)
2898 (void) dbt2set(dbi, &v, &set);
2899
2900 xx = dbiCclose(dbi, dbcursor, 0);
2901 dbcursor = NULL;
2902 }
2903 if (rc || set == NULL || set->count < 1) { /* error/not found */
2904 set = dbiFreeIndexSet(set);
2905 rpmmiRock = mi->mi_next;
2906 mi->mi_next = NULL;
2907 mi = (rpmmi)rpmioFreePoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__);
2908 return NULL;
2909 }
2910 }
2911
2912 /*@-assignexpose@*/
2913 mi->mi_db = rpmdbLink(db, "matchIterator");
2914 /*@=assignexpose@*/
2915 mi->mi_rpmtag = tag;
2916
2917 mi->mi_dbc = NULL;
2918 mi->mi_set = set;
2919 mi->mi_setx = 0;
2920 mi->mi_h = NULL;
2921 mi->mi_sorted = 0;
2922 mi->mi_cflags = 0;
2923 mi->mi_modified = 0;
2924 mi->mi_prevoffset = 0;
2925 mi->mi_offset = 0;
2926 mi->mi_filenum = 0;
2927 mi->mi_nre = 0;
2928 mi->mi_re = NULL;
2929
2930 mi->mi_ts = NULL;
2931
2932 /*@i@*/ return mi;
2933 }
2934
2935 int rpmdbMireApply(rpmdb db, rpmTag tag, rpmMireMode mode, const char * pat,
2936 const char *** argvp)
2937 {
2938 DBC * dbcursor = NULL;
2939 DBT * key = memset(alloca(sizeof(*key)), 0, sizeof(*key));
2940 DBT * data = memset(alloca(sizeof(*data)), 0, sizeof(*data));
2941 dbiIndex dbi;
2942 miRE mire = NULL;
2943 ARGV_t av = NULL;
2944 int ret = 1; /* assume error */
2945 int rc;
2946 int xx;
2947
2948 dbi = dbiOpen(db, tag, 0);
2949 if (dbi == NULL)
2950 goto exit;
2951
2952 if (pat) {
2953 mire = mireNew(mode, 0);
2954 xx = mireRegcomp(mire, pat);
2955 }
2956
2957 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
2958
2959 while ((rc = dbiGet(dbi, dbcursor, key, data, DB_NEXT)) == 0) {
2960 size_t ns = key->size;
2961 char * s = memcpy(xmalloc(ns+1), key->data, ns);
2962
2963 s[ns] = '\0';
2964 if (mire == NULL || mireRegexec(mire, s, ns) >= 0)
2965 xx = argvAdd(&av, s);
2966 s = _free(s);
2967 }
2968
2969 xx = dbiCclose(dbi, dbcursor, 0);
2970 dbcursor = NULL;
2971
2972 if (rc > 0) {
2973 rpmlog(RPMLOG_ERR, _("error(%d) getting keys from %s index\n"),
2974 rc, tagName(dbi->dbi_rpmtag));
2975 goto exit;
2976 }
2977
2978 ret = 0;
2979
2980 exit:
2981 if (argvp != NULL)
2982 xx = argvAppend(argvp, av);
2983 av = argvFree(av);
2984 mire = mireFree(mire);
2985 return ret;
2986 }
2987
2988 /* XXX psm.c */
2989 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum,
2990 /*@unused@*/ rpmts ts)
2991 {
2992 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
2993 Header h;
2994 sigset_t signalMask;
2995 int ret = 0;
2996 int rc = 0;
2997 int xx;
2998
2999 if (db == NULL)
3000 return 0;
3001
3002 { rpmmi mi;
3003 mi = rpmmiInit(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum));
3004 h = rpmmiNext(mi);
3005 if (h)
3006 h = headerLink(h);
3007 mi = rpmmiFree(mi);
3008 }
3009
3010 if (h == NULL) {
3011 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"),
3012 "rpmdbRemove", hdrNum);
3013 return 1;
3014 }
3015
3016 #ifdef DYING
3017 /* Add remove transaction id to header. */
3018 if (rid != 0 && rid != -1) {
3019 rpmuint32_t tid[2];
3020 tid[0] = rid;
3021 tid[1] = 0;
3022 he->tag = RPMTAG_REMOVETID;
3023 he->t = RPM_UINT32_TYPE;
3024 he->p.ui32p = tid;
3025 he->c = 2;
3026 xx = headerPut(h, he, 0);
3027 }
3028 #endif
3029
3030 he->tag = RPMTAG_NVRA;
3031 xx = headerGet(h, he, 0);
3032 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", hdrNum, he->p.str);
3033 he->p.ptr = _free(he->p.ptr);
3034
3035 (void) blockSignals(db, &signalMask);
3036
3037 /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */
3038 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
3039 size_t dbix;
3040
3041 if (db->db_tags != NULL)
3042 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
3043 dbiIndex dbi;
3044 DBC * dbcursor = NULL;
3045 DBT k = DBT_INIT;
3046 DBT v = DBT_INIT;
3047 union _dbswap mi_offset;
3048
3049 tagStore_t dbiTag = db->db_tags + dbix;
3050 rpmTag tag = dbiTag->tag;
3051 const char * dbiBN = (dbiTag->str != NULL
3052 ? dbiTag->str : tagName(tag));
3053 rpmuint8_t * bin = NULL;
3054 int i;
3055
3056 dbi = NULL;
3057 he->tag = tag;
3058 he->t = 0;
3059 he->p.ptr = NULL;
3060 he->c = 0;
3061
3062 switch (he->tag) {
3063 /* Filter out temporary databases */
3064 case RPMDBI_AVAILABLE:
3065 case RPMDBI_ADDED:
3066 case RPMDBI_REMOVED:
3067 case RPMDBI_DEPENDS:
3068 continue;
3069 /*@notreached@*/ /*@switchbreak@*/ break;
3070 case RPMDBI_PACKAGES:
3071 if (db->db_export != NULL)
3072 xx = db->db_export(db, h, 0);
3073 dbi = dbiOpen(db, he->tag, 0);
3074 if (dbi == NULL) /* XXX shouldn't happen */
3075 continue;
3076
3077 /*@-immediatetrans@*/
3078 mi_offset.ui = hdrNum;
3079 if (dbiByteSwapped(dbi) == 1)
3080 _DBSWAP(mi_offset);
3081 k.data = &mi_offset;
3082 /*@=immediatetrans@*/
3083 k.size = (UINT32_T) sizeof(mi_offset.ui);
3084
3085 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3086 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
3087 if (rc) {
3088 rpmlog(RPMLOG_ERR,
3089 _("error(%d) setting header #%d record for %s removal\n"),
3090 rc, hdrNum, dbiBN);
3091 } else
3092 rc = dbiDel(dbi, dbcursor, &k, &v, 0);
3093 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3094 dbcursor = NULL;
3095 if (!dbi->dbi_no_dbsync)
3096 xx = dbiSync(dbi, 0);
3097 continue;
3098 /*@notreached@*/ /*@switchbreak@*/ break;
3099 default:
3100 xx = headerGet(h, he, 0);
3101 if (!xx)
3102 continue;
3103 /*@switchbreak@*/ break;
3104 }
3105
3106 dbi = dbiOpen(db, he->tag, 0);
3107 if (dbi != NULL) {
3108 int printed;
3109
3110 /* XXX Coerce strings into header argv return. */
3111 if (he->t == RPM_STRING_TYPE) {
3112 const char * s = he->p.str;
3113 char * t;
3114 he->c = 1;
3115 he->p.argv = xcalloc(1, sizeof(*he->p.argv)+strlen(s)+1);
3116 he->p.argv[0] = t = (char *) &he->p.argv[1];
3117 (void) strcpy(t, s);
3118 s = _free(s);
3119 }
3120
3121 printed = 0;
3122 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3123 for (i = 0; i < (int) he->c; i++) {
3124 dbiIndexSet set;
3125 int stringvalued;
3126
3127 bin = _free(bin);
3128 switch (dbi->dbi_rpmtag) {
3129 case RPMTAG_FILEDIGESTS:
3130 /* Filter out empty file digests. */
3131 if (!(he->p.argv[i] && *he->p.argv[i] != '\0'))
3132 /*@innercontinue@*/ continue;
3133 /*@switchbreak@*/ break;
3134 default:
3135 /*@switchbreak@*/ break;
3136 }
3137
3138 /* Identify value pointer and length. */
3139 stringvalued = 0;
3140 switch (he->t) {
3141 case RPM_UINT8_TYPE:
3142 k.size = (UINT32_T) sizeof(*he->p.ui8p);
3143 /*@i@*/ k.data = he->p.ui8p + i;
3144 /*@switchbreak@*/ break;
3145 case RPM_UINT16_TYPE:
3146 k.size = (UINT32_T) sizeof(*he->p.ui16p);
3147 /*@i@*/ k.data = he->p.ui16p + i;
3148 /*@switchbreak@*/ break;
3149 case RPM_UINT32_TYPE:
3150 k.size = (UINT32_T) sizeof(*he->p.ui32p);
3151 /*@i@*/ k.data = he->p.ui32p + i;
3152 /*@switchbreak@*/ break;
3153 case RPM_UINT64_TYPE:
3154 k.size = (UINT32_T) sizeof(*he->p.ui64p);
3155 /*@i@*/ k.data = he->p.ui64p + i;
3156 /*@switchbreak@*/ break;
3157 case RPM_BIN_TYPE:
3158 k.size = (UINT32_T) he->c;
3159 /*@i@*/ k.data = he->p.ptr;
3160 he->c = 1; /* XXX break out of loop. */
3161 /*@switchbreak@*/ break;
3162 case RPM_I18NSTRING_TYPE: /* XXX never occurs. */
3163 case RPM_STRING_TYPE:
3164 he->c = 1; /* XXX break out of loop. */
3165 /*@fallthrough@*/
3166 case RPM_STRING_ARRAY_TYPE:
3167 /* Convert from hex to binary. */
3168 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
3169 const char * s = he->p.argv[i];
3170 size_t dlen = strlen(s);
3171 rpmuint8_t * t;
3172 unsigned j;
3173 assert((dlen & 1) == 0);
3174 dlen /= 2;
3175 bin = t = xcalloc(1, dlen);
3176 /*@-type@*/
3177 for (j = 0; j < (unsigned) dlen; j++, t++, s += 2)
3178 *t = (rpmuint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
3179 /*@=type@*/
3180 k.data = bin;
3181 k.size = (UINT32_T) dlen;
3182 /*@switchbreak@*/ break;
3183 }
3184 /* Extract the pubkey id from the base64 blob. */
3185 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
3186 int nbin;
3187 bin = xcalloc(1, 32);
3188 nbin = pgpExtractPubkeyFingerprint(he->p.argv[i], bin);
3189 if (nbin <= 0)
3190 /*@innercontinue@*/ continue;
3191 k.data = bin;
3192 k.size = (UINT32_T) nbin;
3193 /*@switchbreak@*/ break;
3194 }
3195 /*@fallthrough@*/
3196 default:
3197 /*@i@*/ k.data = (void *) he->p.argv[i];
3198 k.size = (UINT32_T) strlen(he->p.argv[i]);
3199 stringvalued = 1;
3200 /*@switchbreak@*/ break;
3201 }
3202
3203 if (!printed) {
3204 if (he->c == 1 && stringvalued) {
3205 rpmlog(RPMLOG_DEBUG,
3206 D_("removing \"%s\" from %s index.\n"),
3207 (char *)k.data, dbiBN);
3208 } else {
3209 rpmlog(RPMLOG_DEBUG,
3210 D_("removing %u entries from %s index.\n"),
3211 (unsigned) he->c, dbiBN);
3212 }
3213 printed++;
3214 }
3215
3216 /* XXX
3217 * This is almost right, but, if there are duplicate tag
3218 * values, there will be duplicate attempts to remove
3219 * the header instance. It's faster to just ignore errors
3220 * than to do things correctly.
3221 */
3222
3223 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
3224
3225 set = NULL;
3226
3227 if (k.size == 0) k.size = (UINT32_T) strlen((char *)k.data);
3228 if (k.size == 0) k.size++; /* XXX "/" fixup. */
3229
3230 /*@-compmempass@*/
3231 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
3232 if (rc == 0) { /* success */
3233 (void) dbt2set(dbi, &v, &set);
3234 } else if (rc == DB_NOTFOUND) { /* not found */
3235 /*@innercontinue@*/ continue;
3236 } else { /* error */
3237 rpmlog(RPMLOG_ERR,
3238 _("error(%d) getting records from %s index\n"),
3239 rc, dbiBN);
3240 ret += 1;
3241 /*@innercontinue@*/ continue;
3242 }
3243 /*@=compmempass@*/
3244
3245 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1);
3246
3247 /* If nothing was pruned, then don't bother updating. */
3248 if (rc) {
3249 set = dbiFreeIndexSet(set);
3250 /*@innercontinue@*/ continue;
3251 }
3252
3253 /*@-compmempass@*/
3254 if (set->count > 0) {
3255 (void) set2dbt(dbi, &v, set);
3256 rc = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST);
3257 if (rc) {
3258 rpmlog(RPMLOG_ERR,
3259 _("error(%d) storing record into %s\n"),
3260 rc, dbiBN);
3261 ret += 1;
3262 }
3263 v.data = _free(v.data);
3264 v.size = 0;
3265 } else {
3266 rc = dbiDel(dbi, dbcursor, &k, &v, 0);
3267 if (rc) {
3268 rpmlog(RPMLOG_ERR,
3269 _("error(%d) removing record from %s\n"),
3270 rc, dbiBN);
3271 ret += 1;
3272 }
3273 }
3274 /*@=compmempass@*/
3275 set = dbiFreeIndexSet(set);
3276 }
3277
3278 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3279 dbcursor = NULL;
3280
3281 if (!dbi->dbi_no_dbsync)
3282 xx = dbiSync(dbi, 0);
3283 }
3284
3285 he->tag = 0;
3286 he->t = 0;
3287 he->p.ptr = _free(he->p.ptr);
3288 he->c = 0;
3289 bin = _free(bin);
3290 }
3291
3292 rec = _free(rec);
3293 }
3294 /*@=nullpass =nullptrarith =nullderef @*/
3295
3296 (void) unblockSignals(db, &signalMask);
3297
3298 (void)headerFree(h);
3299 h = NULL;
3300
3301 /* XXX return ret; */
3302 return 0;
3303 }
3304
3305 /* XXX install.c */
3306 int rpmdbAdd(rpmdb db, int iid, Header h, /*@unused@*/ rpmts ts)
3307 {
3308 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
3309 sigset_t signalMask;
3310 const char ** dirNames;
3311 rpmuint32_t * dirIndexes;
3312 dbiIndex dbi;
3313 size_t dbix;
3314 union _dbswap mi_offset;
3315 unsigned int hdrNum = 0;
3316 int ret = 0;
3317 int rc;
3318 int xx;
3319
3320 /* Initialize the header instance */
3321 (void) headerSetInstance(h, 0);
3322
3323 if (db == NULL)
3324 return 0;
3325
3326 #ifdef NOTYET /* XXX headerRemoveEntry() broken on dribbles. */
3327 he->tag = RPMTAG_REMOVETID;
3328 xx = headerDel(h, he, 0);
3329 #endif
3330 if (iid != 0 && iid != -1) {
3331 rpmuint32_t tid[2];
3332 tid[0] = iid;
3333 tid[1] = 0;
3334 he->tag = RPMTAG_INSTALLTID;
3335 he->t = RPM_UINT32_TYPE;
3336 he->p.ui32p = tid;
3337 he->c = 2;
3338 if (!headerIsEntry(h, he->tag))
3339 /*@-compmempass@*/
3340 xx = headerPut(h, he, 0);
3341 /*@=compmempass@*/
3342 }
3343
3344 /* Add the package color if not present. */
3345 if (!headerIsEntry(h, RPMTAG_PACKAGECOLOR)) {
3346 rpmuint32_t hcolor = hGetColor(h);
3347 he->tag = RPMTAG_PACKAGECOLOR;
3348 he->t = RPM_UINT32_TYPE;
3349 he->p.ui32p = &hcolor;
3350 he->c = 1;
3351 /*@-compmempass@*/
3352 xx = headerPut(h, he, 0);
3353 /*@=compmempass@*/
3354 }
3355
3356 he->tag = RPMTAG_DIRNAMES;
3357 /*@-compmempass@*/
3358 xx = headerGet(h, he, 0);
3359 /*@=compmempass@*/
3360 dirNames = he->p.argv;
3361 he->tag = RPMTAG_DIRINDEXES;
3362 /*@-compmempass@*/
3363 xx = headerGet(h, he, 0);
3364 /*@=compmempass@*/
3365 dirIndexes = he->p.ui32p;
3366
3367 (void) blockSignals(db, &signalMask);
3368
3369 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0);
3370 if (dbi != NULL) {
3371 /* Header indices are monotonically increasing integer instances
3372 * starting with 1. Header instance #0 is where the monotonically
3373 * increasing integer is stored. */
3374 unsigned int idx0 = 0;
3375
3376 DBC * dbcursor = NULL;
3377 DBT k = DBT_INIT;
3378 DBT v = DBT_INIT;
3379
3380 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3381
3382 /* Retrieve join key for next header instance. */
3383 k.data = &idx0;
3384 k.size = (u_int32_t)sizeof(idx0);
3385 ret = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
3386
3387 hdrNum = 0;
3388 if (ret == 0 && v.data) {
3389 memcpy(&mi_offset, v.data, sizeof(mi_offset.ui));
3390 if (dbiByteSwapped(dbi) == 1)
3391 _DBSWAP(mi_offset);
3392 hdrNum = (unsigned) mi_offset.ui;
3393 }
3394 ++hdrNum;
3395 mi_offset.ui = hdrNum;
3396 if (dbiByteSwapped(dbi) == 1)
3397 _DBSWAP(mi_offset);
3398 if (ret == 0 && v.data) {
3399 memcpy(v.data, &mi_offset, sizeof(mi_offset.ui));
3400 } else {
3401 /*@-immediatetrans@*/
3402 v.data = &mi_offset;
3403 /*@=immediatetrans@*/
3404 v.size = (u_int32_t)sizeof(mi_offset.ui);
3405 }
3406
3407 /*@-compmempass@*/
3408 ret = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST);
3409 /*@=compmempass@*/
3410 xx = dbiSync(dbi, 0);
3411
3412 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3413
3414 }
3415
3416 if (ret) {
3417 rpmlog(RPMLOG_ERR,
3418 _("error(%d) allocating new package instance\n"), ret);
3419 goto exit;
3420 }
3421
3422 /* Now update the indexes */
3423
3424 if (hdrNum)
3425 { dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0);
3426
3427 /* Save the header instance. */
3428 (void) headerSetInstance(h, hdrNum);
3429
3430 if (db->db_tags != NULL)
3431 for (dbix = 0; dbix < db->db_ndbi; dbix++) {
3432 DBC * dbcursor = NULL;
3433 DBT k = DBT_INIT;
3434 DBT v = DBT_INIT;
3435
3436 tagStore_t dbiTag = db->db_tags + dbix;
3437 const char * dbiBN = (dbiTag->str != NULL
3438 ? dbiTag->str : tagName(dbiTag->tag));
3439 rpmuint8_t * bin = NULL;
3440 rpmTagData requireFlags;
3441 rpmRC rpmrc;
3442 int i;
3443
3444 rpmrc = RPMRC_NOTFOUND;
3445 requireFlags.ptr = NULL;
3446 dbi = NULL;
3447 he->tag = dbiTag->tag;
3448 he->t = 0;
3449 he->p.ptr = NULL;
3450 he->c = 0;
3451
3452 switch (he->tag) {
3453 /* Filter out temporary databases */
3454 case RPMDBI_AVAILABLE:
3455 case RPMDBI_ADDED:
3456 case RPMDBI_REMOVED:
3457 case RPMDBI_DEPENDS:
3458 continue;
3459 /*@notreached@*/ /*@switchbreak@*/ break;
3460 case RPMDBI_PACKAGES:
3461 if (db->db_export != NULL)
3462 xx = db->db_export(db, h, 1);
3463 dbi = dbiOpen(db, he->tag, 0);
3464 if (dbi == NULL) /* XXX shouldn't happen */
3465 continue;
3466 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3467
3468 mi_offset.ui = hdrNum;
3469 if (dbiByteSwapped(dbi) == 1)
3470 _DBSWAP(mi_offset);
3471 /*@-immediatetrans@*/
3472 k.data = (void *) &mi_offset;
3473 /*@=immediatetrans@*/
3474 k.size = (UINT32_T) sizeof(mi_offset.ui);
3475 { size_t len = 0;
3476 v.data = headerUnload(h, &len);
3477 v.size = (UINT32_T) len;
3478 }
3479
3480 /* Check header digest/signature on blob export. */
3481 if (ts) {
3482 const char * msg = NULL;
3483 int lvl;
3484
3485 assert(v.data != NULL);
3486 rpmrc = headerCheck(rpmtsDig(ts), v.data, v.size, &msg);
3487 rpmtsCleanDig(ts);
3488 lvl = (rpmrc == RPMRC_FAIL ? RPMLOG_ERR : RPMLOG_DEBUG);
3489 rpmlog(lvl, "%s h#%8u %s\n",
3490 (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"),
3491 hdrNum, (msg ? msg : ""));
3492 msg = _free(msg);
3493 }
3494
3495 if (v.data != NULL && rpmrc != RPMRC_FAIL) {
3496 /*@-compmempass@*/
3497 xx = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST);
3498 /*@=compmempass@*/
3499 xx = dbiSync(dbi, 0);
3500 }
3501 v.data = _free(v.data); /* headerUnload */
3502 v.size = 0;
3503 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3504 if (!dbi->dbi_no_dbsync)
3505 xx = dbiSync(dbi, 0);
3506 continue;
3507 /*@notreached@*/ /*@switchbreak@*/ break;
3508 case RPMTAG_REQUIRENAME:
3509 he->tag = RPMTAG_REQUIREFLAGS;
3510 /*@-compmempass@*/
3511 xx = headerGet(h, he, 0);
3512 /*@=compmempass@*/
3513 requireFlags.ptr = he->p.ptr;
3514 he->tag = RPMTAG_REQUIRENAME;
3515 /*@-compmempass@*/
3516 xx = headerGet(h, he, 0);
3517 /*@=compmempass@*/
3518 /*@switchbreak@*/ break;
3519 default:
3520 /*@-compmempass@*/
3521 xx = headerGet(h, he, 0);
3522 /*@=compmempass@*/
3523 /*@switchbreak@*/ break;
3524 }
3525
3526 /* Anything to do? */
3527 if (he->c == 0)
3528 continue;
3529
3530 dbi = dbiOpen(db, he->tag, 0);
3531 if (dbi != NULL) {
3532 int printed;
3533
3534 /* XXX Coerce strings into header argv return. */
3535 if (he->t == RPM_STRING_TYPE) {
3536 const char * s = he->p.str;
3537 char * t;
3538 he->c = 1;
3539 he->p.argv = xcalloc(1, sizeof(*he->p.argv)+strlen(s)+1);
3540 he->p.argv[0] = t = (char *) &he->p.argv[1];
3541 (void) strcpy(t, s);
3542 s = _free(s);
3543 }
3544
3545 printed = 0;
3546 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
3547
3548 for (i = 0; i < (int) he->c; i++) {
3549 dbiIndexSet set;
3550 int stringvalued;
3551
3552 bin = _free(bin);
3553 /*
3554 * Include the tagNum in all indices. rpm-3.0.4 and earlier
3555 * included the tagNum only for files.
3556 */
3557 rec->tagNum = i;
3558 switch (dbi->dbi_rpmtag) {
3559 case RPMTAG_BASENAMES:
3560 /* tag index entry with directory hash */
3561 if (_db_tagged_file_indices && i < 0x010000)
3562 rec->tagNum |= taghash(dirNames[dirIndexes[i]]);
3563 /*@switchbreak@*/ break;
3564 case RPMTAG_PUBKEYS:
3565 /*@switchbreak@*/ break;
3566 case RPMTAG_FILEDIGESTS:
3567 /* Filter out empty MD5 strings. */
3568 if (!(he->p.argv[i] && *he->p.argv[i] != '\0'))
3569 /*@innercontinue@*/ continue;
3570 /*@switchbreak@*/ break;
3571 case RPMTAG_REQUIRENAME:
3572 /* Filter out install prerequisites. */
3573 if (requireFlags.ui32p
3574 && isInstallPreReq(requireFlags.ui32p[i]))
3575 /*@innercontinue@*/ continue;
3576 /*@switchbreak@*/ break;
3577 case RPMTAG_TRIGGERNAME:
3578 if (i) { /* don't add duplicates */
3579 int j;
3580 for (j = 0; j < i; j++) {
3581 if (!strcmp(he->p.argv[i], he->p.argv[j]))
3582 /*@innerbreak@*/ break;
3583 }
3584 if (j < i)
3585 /*@innercontinue@*/ continue;
3586 }
3587 /*@switchbreak@*/ break;
3588 default:
3589 /*@switchbreak@*/ break;
3590 }
3591
3592 /* Identify value pointer and length. */
3593 stringvalued = 0;
3594 switch (he->t) {
3595 case RPM_UINT8_TYPE:
3596 k.size = (UINT32_T) sizeof(*he->p.ui8p);
3597 /*@i@*/ k.data = he->p.ui8p + i;
3598 /*@switchbreak@*/ break;
3599 case RPM_UINT16_TYPE:
3600 k.size = (UINT32_T) sizeof(*he->p.ui16p);
3601 /*@i@*/ k.data = he->p.ui16p + i;
3602 /*@switchbreak@*/ break;
3603 case RPM_UINT32_TYPE:
3604 k.size = (UINT32_T) sizeof(*he->p.ui32p);
3605 /*@i@*/ k.data = he->p.ui32p + i;
3606 /*@switchbreak@*/ break;
3607 case RPM_UINT64_TYPE:
3608 k.size = (UINT32_T) sizeof(*he->p.ui64p);
3609 /*@i@*/ k.data = he->p.ui64p + i;
3610 /*@switchbreak@*/ break;
3611 case RPM_BIN_TYPE:
3612 k.size = (UINT32_T) he->c;
3613 /*@i@*/ k.data = he->p.ptr;
3614 he->c = 1; /* XXX break out of loop. */
3615 /*@switchbreak@*/ break;
3616 case RPM_I18NSTRING_TYPE: /* XXX never occurs */
3617 case RPM_STRING_TYPE:
3618 he->c = 1; /* XXX break out of loop. */
3619 /*@fallthrough@*/
3620 case RPM_STRING_ARRAY_TYPE:
3621 /* Convert from hex to binary. */
3622 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) {
3623 const char * s = he->p.argv[i];
3624 size_t dlen = strlen(s);
3625 rpmuint8_t * t;
3626 unsigned j;
3627 assert((dlen & 1) == 0);
3628 dlen /= 2;
3629 bin = t = xcalloc(1, dlen);
3630 /*@-type@*/
3631 for (j = 0; j < (unsigned) dlen; j++, t++, s += 2)
3632 *t = (rpmuint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
3633 /*@=type@*/
3634 k.data = bin;
3635 k.size = (UINT32_T) dlen;
3636 /*@switchbreak@*/ break;
3637 }
3638 /* Extract the pubkey id from the base64 blob. */
3639 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) {
3640 int nbin;
3641 bin = xcalloc(1, 32);
3642 nbin = pgpExtractPubkeyFingerprint(he->p.argv[i], bin);
3643 if (nbin <= 0)
3644 /*@innercontinue@*/ continue;
3645 k.data = bin;
3646 k.size = (UINT32_T) nbin;
3647 /*@switchbreak@*/ break;
3648 }
3649 /*@fallthrough@*/
3650 default:
3651 /*@i@*/ k.data = (void *) he->p.argv[i];
3652 k.size = (UINT32_T) strlen(he->p.argv[i]);
3653 stringvalued = 1;
3654 /*@switchbreak@*/ break;
3655 }
3656
3657 if (!printed) {
3658 if (he->c == 1 && stringvalued) {
3659 rpmlog(RPMLOG_DEBUG,
3660 D_("adding \"%s\" to %s index.\n"),
3661 (char *)k.data, dbiBN);
3662 } else {
3663 rpmlog(RPMLOG_DEBUG,
3664 D_("adding %u entries to %s index.\n"),
3665 (unsigned)he->c, dbiBN);
3666 }
3667 printed++;
3668 }
3669
3670 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */
3671
3672 set = NULL;
3673
3674 if (k.size == 0) k.size = (UINT32_T) strlen((char *)k.data);
3675 if (k.size == 0) k.size++; /* XXX "/" fixup. */
3676
3677 /*@-compmempass@*/
3678 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET);
3679 if (rc == 0) { /* success */
3680 /* With duplicates, cursor is positioned, discard the record. */
3681 if (!dbi->dbi_permit_dups)
3682 (void) dbt2set(dbi, &v, &set);
3683 } else if (rc != DB_NOTFOUND) { /* error */
3684 rpmlog(RPMLOG_ERR,
3685 _("error(%d) getting records from %s index\n"),
3686 rc, dbiBN);
3687 ret += 1;
3688 /*@innercontinue@*/ continue;
3689 }
3690 /*@=compmempass@*/
3691
3692 if (set == NULL) /* not found or duplicate */
3693 set = xcalloc(1, sizeof(*set));
3694
3695 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0);
3696
3697 /*@-compmempass@*/
3698 (void) set2dbt(dbi, &v, set);
3699 rc = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST);
3700 /*@=compmempass@*/
3701
3702 if (rc) {
3703 rpmlog(RPMLOG_ERR,
3704 _("error(%d) storing record into %s\n"),
3705 rc, dbiBN);
3706 ret += 1;
3707 }
3708 /*@-unqualifiedtrans@*/
3709 v.data = _free(v.data);
3710 /*@=unqualifiedtrans@*/
3711 v.size = 0;
3712 set = dbiFreeIndexSet(set);
3713 }
3714
3715 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
3716
3717 if (!dbi->dbi_no_dbsync)
3718 xx = dbiSync(dbi, 0);
3719 }
3720
3721 he->tag = 0;
3722 he->t = 0;
3723 /*@-kepttrans -onlytrans@*/
3724 he->p.ptr = _free(he->p.ptr);
3725 /*@=kepttrans =onlytrans@*/
3726 he->c = 0;
3727 bin = _free(bin);
3728 requireFlags.ptr = _free(requireFlags.ptr);
3729 }
3730
3731 rec = _free(rec);
3732 }
3733
3734 exit:
3735 (void) unblockSignals(db, &signalMask);
3736 dirIndexes = _free(dirIndexes);
3737 dirNames = _free(dirNames);
3738
3739 return ret;
3740 }
3741
3742 /* XXX transaction.c */
3743 /*@-compmempass@*/
3744 int rpmdbFindFpList(void * _db, fingerPrint * fpList, void * _matchList,
3745 int numItems, unsigned int exclude)
3746 {
3747 rpmdb db = _db;
3748 dbiIndexSet * matchList = _matchList;
3749 DBT * key;
3750 DBT * data;
3751 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
3752 rpmmi mi;
3753 fingerPrintCache fpc;
3754 Header h;
3755 int i, xx;
3756
3757 if (db == NULL) return 0;
3758
3759 mi = rpmmiInit(db, RPMTAG_BASENAMES, NULL, 0);
3760 assert(mi != NULL); /* XXX will never happen. */
3761 if (mi == NULL)
3762 return 2;
3763
3764 key = &mi->mi_key;
3765 data = &mi->mi_data;
3766
3767 /* Gather all installed headers with matching basename's. */
3768 for (i = 0; i < numItems; i++) {
3769 unsigned int tag;
3770
3771 matchList[i] = xcalloc(1, sizeof(*(matchList[i])));
3772
3773 /*@-dependenttrans@*/
3774 key->data = (void *) fpList[i].baseName;
3775 /*@=dependenttrans@*/
3776 key->size = (UINT32_T) strlen((char *)key->data);
3777 if (key->size == 0) key->size++; /* XXX "/" fixup. */
3778
3779 tag = (_db_tagged_file_indices ? taghash(fpList[i].entry->dirName) : 0);
3780 xx = rpmdbGrowIterator(mi, i, exclude, tag);
3781
3782 }
3783
3784 if ((i = rpmmiCount(mi)) == 0) {
3785 mi = rpmmiFree(mi);
3786 return 0;
3787 }
3788 fpc = fpCacheCreate(i);
3789
3790 rpmdbSortIterator(mi);
3791 /* iterator is now sorted by (recnum, filenum) */
3792
3793 /* For all installed headers with matching basename's ... */
3794 if (mi != NULL)
3795 while ((h = rpmmiNext(mi)) != NULL) {
3796 const char ** dirNames;
3797 const char ** baseNames;
3798 const char ** fullBaseNames;
3799 rpmuint32_t * dirIndexes;
3800 rpmuint32_t * fullDirIndexes;
3801 fingerPrint * fps;
3802 dbiIndexItem im;
3803 int start;
3804 int num;
3805 int end;
3806
3807 start = mi->mi_setx - 1;
3808 im = mi->mi_set->recs + start;
3809
3810 /* Find the end of the set of matched basename's in this package. */
3811 for (end = start + 1; end < mi->mi_set->count; end++) {
3812 if (im->hdrNum != mi->mi_set->recs[end].hdrNum)
3813 /*@innerbreak@*/ break;
3814 }
3815 num = end - start;
3816
3817 /* Compute fingerprints for this installed header's matches */
3818 he->tag = RPMTAG_BASENAMES;
3819 xx = headerGet(h, he, 0);
3820 fullBaseNames = he->p.argv;
3821 he->tag = RPMTAG_DIRNAMES;
3822 xx = headerGet(h, he, 0);
3823 dirNames = he->p.argv;
3824 he->tag = RPMTAG_DIRINDEXES;
3825 xx = headerGet(h, he, 0);
3826 fullDirIndexes = he->p.ui32p;
3827
3828 baseNames = xcalloc(num, sizeof(*baseNames));
3829 dirIndexes = xcalloc(num, sizeof(*dirIndexes));
3830 for (i = 0; i < num; i++) {
3831 baseNames[i] = fullBaseNames[im[i].tagNum];
3832 dirIndexes[i] = fullDirIndexes[im[i].tagNum];
3833 }
3834
3835 fps = xcalloc(num, sizeof(*fps));
3836 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps);
3837
3838 /* Add db (recnum,filenum) to list for fingerprint matches. */
3839 for (i = 0; i < num; i++, im++) {
3840 /*@-nullpass@*/ /* FIX: fpList[].subDir may be NULL */
3841 if (!FP_EQUAL(fps[i], fpList[im->fpNum]))
3842 /*@innercontinue@*/ continue;
3843 /*@=nullpass@*/
3844 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0);
3845 }
3846
3847 fps = _free(fps);
3848 fullBaseNames = _free(fullBaseNames);
3849 /*@-usereleased@*/
3850 dirNames = _free(dirNames);
3851 /*@=usereleased@*/
3852 fullDirIndexes = _free(fullDirIndexes);
3853 baseNames = _free(baseNames);
3854 dirIndexes = _free(dirIndexes);
3855
3856 mi->mi_setx = end;
3857 }
3858
3859 mi = rpmmiFree(mi);
3860
3861 fpc = fpCacheFree(fpc);
3862
3863 return 0;
3864
3865 }
3866 /*@=compmempass@*/
3867
3873 static int rpmioFileExists(const char * urlfn)
3874 /*@globals h_errno, fileSystem, internalState @*/
3875 /*@modifies fileSystem, internalState @*/
3876 {
3877 struct stat sb;
3878 const char * fn;
3879 int urltype = urlPath(urlfn, &fn);
3880 int rc = 0; /* assume failure. */
3881
3882 if (*fn == '\0') fn = "/";
3883 switch (urltype) {
3884 case URL_IS_HTTPS:
3885 case URL_IS_HTTP:
3886 case URL_IS_FTP:
3887 case URL_IS_HKP:
3888 rc = Stat(urlfn, &sb) == 0;
3889 break;
3890 case URL_IS_PATH:
3891 case URL_IS_UNKNOWN:
3892 rc = Stat(fn, &sb) == 0;
3893 break;
3894 case URL_IS_DASH:
3895 default:
3896 break;
3897 }
3898
3899 return rc;
3900 }
3901
3902 static int rpmdbRemoveDatabase(const char * prefix,
3903 const char * dbpath, int _dbapi,
3904 /*@null@*/ const tagStore_t dbiTags, size_t dbiNTags)
3905 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3906 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
3907 {
3908 const char * fn;
3909 int xx;
3910
3911 switch (_dbapi) {
3912 default:
3913 case 4:
3914 /*@fallthrough@*/
3915 case 3:
3916 { char * suffix;
3917 size_t i;
3918
3919 if (dbiTags != NULL)
3920 for (i = 0; i < dbiNTags; i++) {
3921 const char * dbiBN = (dbiTags[i].str != NULL
3922 ? dbiTags[i].str : tagName(dbiTags[i].tag));
3923 fn = rpmGetPath(prefix, dbpath, "/", dbiBN, NULL);
3924 if (rpmioFileExists(fn))
3925 xx = Unlink(fn);
3926 fn = _free(fn);
3927 }
3928
3929 fn = rpmGetPath(prefix, dbpath, "/", "__db.000", NULL);
3930 suffix = (char *)(fn + strlen(fn) - (sizeof("000") - 1));
3931 for (i = 0; i < 16; i++) {
3932 (void) snprintf(suffix, sizeof("000"), "%03u", (unsigned)i);
3933 if (rpmioFileExists(fn))
3934 xx = Unlink(fn);
3935 }
3936 fn = _free(fn);
3937
3938 } break;
3939 case 2:
3940 case 1:
3941 case 0:
3942 break;
3943 }
3944
3945 fn = rpmGetPath(prefix, dbpath, NULL);
3946 xx = Rmdir(fn);
3947 fn = _free(fn);
3948
3949 return 0;
3950 }
3951
3952 static int rpmdbMoveDatabase(const char * prefix,
3953 const char * olddbpath, int _olddbapi,
3954 const char * newdbpath, /*@unused@*/ int _newdbapi,
3955 /*@null@*/ const tagStore_t dbiTags, size_t dbiNTags)
3956 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
3957 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
3958 {
3959 struct stat nsb, * nst = &nsb;
3960 const char * ofn, * nfn;
3961 int rc = 0;
3962 int xx;
3963 /*@-moduncon -noeffectuncon@*/
3964 int selinux = is_selinux_enabled() > 0 && (matchpathcon_init(NULL) != -1);
3965 /*@=moduncon =noeffectuncon@*/
3966 sigset_t sigMask;
3967
3968 (void) blockSignals(NULL, &sigMask);
3969 switch (_olddbapi) {
3970 default:
3971 case 4:
3972 /* Fall through */
3973 case 3:
3974 { char *osuffix, *nsuffix;
3975 size_t i;
3976 if (dbiTags != NULL)
3977 for (i = 0; i < dbiNTags; i++) {
3978 rpmTag tag = dbiTags[i].tag;
3979 const char * dbiBN = (dbiTags[i].str != NULL
3980 ? dbiTags[i].str : tagName(tag));
3981
3982 /* Filter out temporary databases */
3983 switch (tag) {
3984 case RPMDBI_AVAILABLE:
3985 case RPMDBI_ADDED:
3986 case RPMDBI_REMOVED:
3987 case RPMDBI_DEPENDS:
3988 continue;
3989 /*@notreached@*/ /*@switchbreak@*/ break;
3990 default:
3991 /*@switchbreak@*/ break;
3992 }
3993
3994 ofn = rpmGetPath(prefix, olddbpath, "/", dbiBN, NULL);
3995 nfn = rpmGetPath(prefix, newdbpath, "/", dbiBN, NULL);
3996
3997 if (!rpmioFileExists(ofn)) {
3998 if (rpmioFileExists(nfn)) {
3999 rpmlog(RPMLOG_DEBUG, D_("removing file \"%s\"\n"), nfn);
4000 xx = Unlink(nfn);
4001 }
4002 goto bottom;
4003 }
4004
4005 /*
4006 * Get uid/gid/mode/mtime. If old doesn't exist, use new.
4007 * XXX Yes, the variable names are backwards.
4008 */
4009 if (Stat(nfn, nst) < 0 && Stat(ofn, nst) < 0)
4010 goto bottom;
4011
4012 rpmlog(RPMLOG_DEBUG, D_("moving file from \"%s\"\n"), ofn);
4013 rpmlog(RPMLOG_DEBUG, D_("moving file to \"%s\"\n"), nfn);
4014 if ((xx = Rename(ofn, nfn)) != 0) {
4015 rc = 1;
4016 goto bottom;
4017 }
4018
4019 /* Restore uid/gid/mode/mtime/security context if possible. */
4020 xx = Chown(nfn, nst->st_uid, nst->st_gid);
4021 xx = Chmod(nfn, (nst->st_mode & 07777));
4022 { struct utimbuf stamp;
4023 /*@-type@*/
4024 stamp.actime = (time_t)nst->st_atime;
4025 stamp.modtime = (time_t)nst->st_mtime;
4026 /*@=type@*/
4027 xx = Utime(nfn, &stamp);
4028 }
4029 /*@-moduncon -noeffectuncon@*/
4030 if (selinux) {
4031 security_context_t scon = NULL;
4032 if (matchpathcon(nfn, nst->st_mode, &scon) != -1)
4033 xx = setfilecon(nfn, scon);
4034 if (scon != NULL)
4035 freecon(scon);
4036 }
4037 /*@=moduncon =noeffectuncon@*/
4038
4039 bottom:
4040 ofn = _free(ofn);
4041 nfn = _free(nfn);
4042 }
4043
4044 ofn = rpmGetPath(prefix, olddbpath, "/", "__db.000", NULL);
4045 osuffix = (char *)(ofn + strlen(ofn) - (sizeof("000") - 1));
4046 nfn = rpmGetPath(prefix, newdbpath, "/", "__db.000", NULL);
4047 nsuffix = (char *)(nfn + strlen(nfn) - (sizeof("000") - 1));
4048
4049 for (i = 0; i < 16; i++) {
4050 (void) snprintf(osuffix, sizeof("000"), "%03u", (unsigned)i);
4051 if (rpmioFileExists(ofn)) {
4052 rpmlog(RPMLOG_DEBUG, D_("removing region file \"%s\"\n"), ofn);
4053 xx = Unlink(ofn);
4054 }
4055 (void) snprintf(nsuffix, sizeof("000"), "%03u", (unsigned)i);
4056 if (rpmioFileExists(nfn)) {
4057 rpmlog(RPMLOG_DEBUG, D_("removing region file \"%s\"\n"), nfn);
4058 xx = Unlink(nfn);
4059 }
4060 }
4061 ofn = _free(ofn);
4062 nfn = _free(ofn);
4063 } break;
4064 case 2:
4065 case 1:
4066 case 0:
4067 break;
4068 }
4069 (void) unblockSignals(NULL, &sigMask);
4070
4071 /*@-moduncon -noeffectuncon@*/
4072 if (selinux)
4073 matchpathcon_fini();
4074 /*@=moduncon =noeffectuncon@*/
4075 return rc;
4076 }
4077
4078 int rpmdbRebuild(const char * prefix, rpmts ts)
4079 /*@globals _rebuildinprogress @*/
4080 /*@modifies _rebuildinprogress @*/
4081 {
4082 const char * myprefix = NULL;
4083 rpmdb olddb;
4084 const char * dbpath = NULL;
4085 const char * rootdbpath = NULL;
4086 rpmdb newdb;
4087 const char * newdbpath = NULL;
4088 const char * newrootdbpath = NULL;
4089 const char * tfn;
4090 int nocleanup = 1;
4091 int failed = 0;
4092 int removedir = 0;
4093 int rc = 0, xx;
4094 int _dbapi;
4095 int _dbapi_rebuild;
4096 tagStore_t dbiTags = NULL;
4097 size_t dbiNTags = 0;
4098
4099 _dbapi = rpmExpandNumeric("%{_dbapi}");
4100 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}");
4101
4102 dbiTagsInit(&dbiTags, &dbiNTags);
4103
4104 /*@-nullpass@*/
4105 tfn = rpmGetPath("%{?_dbpath}", NULL);
4106 /*@=nullpass@*/
4107 if (!(tfn && tfn[0] != '\0'))
4108 {
4109 rpmlog(RPMLOG_DEBUG, D_("no dbpath has been set"));
4110 rc = 1;
4111 goto exit;
4112 }
4113
4114 /* Add --root prefix iff --dbpath is not a URL. */
4115 switch (urlPath(tfn, NULL)) {
4116 default:
4117 myprefix = xstrdup("");
4118 break;
4119 case URL_IS_UNKNOWN:
4120 myprefix = rpmGetPath((prefix ? prefix : "/"), NULL);
4121 break;
4122 }
4123
4124 dbpath = rootdbpath = rpmGetPath(myprefix, tfn, NULL);
4125 if (!(myprefix[0] == '/' && myprefix[1] == '\0'))
4126 dbpath += strlen(myprefix);
4127 tfn = _free(tfn);
4128
4129 /*@-nullpass@*/
4130 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL);
4131 /*@=nullpass@*/
4132 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath)))
4133 {
4134 char pidbuf[20];
4135 char *t;
4136 sprintf(pidbuf, "rebuilddb.%d", (int) getpid());
4137 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1);
4138 (void)stpcpy(stpcpy(t, dbpath), pidbuf);
4139 tfn = _free(tfn);
4140 tfn = t;
4141 nocleanup = 0;
4142 }
4143 newdbpath = newrootdbpath = rpmGetPath(myprefix, tfn, NULL);
4144 if (!(myprefix[0] == '/' && myprefix[1] == '\0'))
4145 newdbpath += strlen(myprefix);
4146 tfn = _free(tfn);
4147
4148 rpmlog(RPMLOG_DEBUG, D_("rebuilding database %s into %s\n"),
4149 rootdbpath, newrootdbpath);
4150
4151 if (!Access(newrootdbpath, F_OK)) {
4152 rpmlog(RPMLOG_ERR, _("temporary database %s already exists\n"),
4153 newrootdbpath);
4154 rc = 1;
4155 goto exit;
4156 }
4157
4158 rpmlog(RPMLOG_DEBUG, D_("creating directory %s\n"), newrootdbpath);
4159 if (Mkdir(newrootdbpath, 0755)) {
4160 rpmlog(RPMLOG_ERR, _("creating directory %s: %s\n"),
4161 newrootdbpath, strerror(errno));
4162 rc = 1;
4163 goto exit;
4164 }
4165 removedir = 1;
4166
4167 _rebuildinprogress = 0;
4168
4169 rpmlog(RPMLOG_DEBUG, D_("opening old database with dbapi %d\n"),
4170 _dbapi);
4171 if (rpmdbOpenDatabase(myprefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644,
4172 RPMDB_FLAG_MINIMAL)) {
4173 rc = 1;
4174 goto exit;
4175 }
4176 _dbapi = olddb->db_api;
4177 _rebuildinprogress = 1;
4178 rpmlog(RPMLOG_DEBUG, D_("opening new database with dbapi %d\n"),
4179 _dbapi_rebuild);
4180 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1);
4181 if (rpmdbOpenDatabase(myprefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) {
4182 rc = 1;
4183 goto exit;
4184 }
4185
4186 _rebuildinprogress = 0;
4187
4188 _dbapi_rebuild = newdb->db_api;
4189
4190 { Header h = NULL;
4191 rpmmi mi;
4192 #define _RECNUM rpmmiInstance(mi)
4193
4194 mi = rpmmiInit(olddb, RPMDBI_PACKAGES, NULL, 0);
4195 if (ts)
4196 (void) rpmmiSetHdrChk(mi, ts);
4197
4198 while ((h = rpmmiNext(mi)) != NULL) {
4199
4200 /* let's sanity check this record a bit, otherwise just skip it */
4201 if (!(headerIsEntry(h, RPMTAG_NAME) &&
4202 headerIsEntry(h, RPMTAG_VERSION) &&
4203 headerIsEntry(h, RPMTAG_RELEASE) &&
4204 headerIsEntry(h, RPMTAG_BUILDTIME)))
4205 {
4206 rpmlog(RPMLOG_WARNING,
4207 _("header #%u in the database is bad -- skipping.\n"),
4208 _RECNUM);
4209 continue;
4210 }
4211 if (!headerIsEntry(h, RPMTAG_SOURCERPM)
4212 && headerIsEntry(h, RPMTAG_ARCH))
4213 {
4214 rpmlog(RPMLOG_WARNING,
4215 _("header #%u in the database is SRPM -- skipping.\n"),
4216 _RECNUM);
4217 continue;
4218 }
4219
4220 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */
4221 if (_db_filter_dups || newdb->db_filter_dups) {
4222 const char * name, * version, * release;
4223 int skip = 0;
4224
4225 (void) headerNEVRA(h, &name, NULL, &version, &release, NULL);
4226
4227 /*@-shadow@*/
4228 { rpmmi mi;
4229 mi = rpmmiInit(newdb, RPMTAG_NAME, name, 0);
4230 (void) rpmmiAddPattern(mi, RPMTAG_VERSION,
4231 RPMMIRE_DEFAULT, version);
4232 (void) rpmmiAddPattern(mi, RPMTAG_RELEASE,
4233 RPMMIRE_DEFAULT, release);
4234 while (rpmmiNext(mi)) {
4235 skip = 1;
4236 /*@innerbreak@*/ break;
4237 }
4238 mi = rpmmiFree(mi);
4239 }
4240 /*@=shadow@*/
4241
4242 if (skip)
4243 continue;
4244 }
4245
4246 /* Deleted entries are eliminated in legacy headers by copy. */
4247 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE)
4248 ? headerCopy(h) : NULL);
4249 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts);
4250 (void)headerFree(nh);
4251 nh = NULL;
4252 }
4253
4254 if (rc) {
4255 rpmlog(RPMLOG_ERR,
4256 _("cannot add record originally at %u\n"), _RECNUM);
4257 failed = 1;
4258 break;
4259 }
4260 }
4261
4262 mi = rpmmiFree(mi);
4263
4264 }
4265
4266 xx = rpmdbClose(olddb);
4267 xx = rpmdbClose(newdb);
4268
4269 if (failed) {
4270 rpmlog(RPMLOG_NOTICE, _("failed to rebuild database: original database "
4271 "remains in place\n"));
4272
4273 xx = rpmdbRemoveDatabase(myprefix, newdbpath, _dbapi_rebuild,
4274 dbiTags, dbiNTags);
4275 rc = 1;
4276 goto exit;
4277 } else if (!nocleanup) {
4278 xx = rpmdbMoveDatabase(myprefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi,
4279 dbiTags, dbiNTags);
4280
4281 if (xx) {
4282 rpmlog(RPMLOG_ERR, _("failed to replace old database with new "
4283 "database!\n"));
4284 rpmlog(RPMLOG_ERR, _("replace files in %s with files from %s "
4285 "to recover"), dbpath, newdbpath);
4286 rc = 1;
4287 goto exit;
4288 }
4289 }
4290 rc = 0;
4291
4292 exit:
4293 if (removedir && !(rc == 0 && nocleanup)) {
4294 rpmlog(RPMLOG_DEBUG, D_("removing directory %s\n"), newrootdbpath);
4295 if (Rmdir(newrootdbpath))
4296 rpmlog(RPMLOG_ERR, _("failed to remove directory %s: %s\n"),
4297 newrootdbpath, strerror(errno));
4298 }
4299 newrootdbpath = _free(newrootdbpath);
4300 rootdbpath = _free(rootdbpath);
4301 dbiTags = tagStoreFree(dbiTags, dbiNTags);
4302 myprefix = _free(myprefix);
4303
4304 return rc;
4305 }