rpm  5.4.15
db3.c
Go to the documentation of this file.
1 /*@-type@*/ /* FIX: annotate db3 methods */
6 /*@unchecked@*/
7 static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */
8 
9 #include "system.h"
10 
11 #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H)
12 #include <sys/ipc.h>
13 #endif
14 
15 #include <rpmlog.h>
16 #include <rpmmacro.h>
17 #include <rpmbf.h>
18 #include <rpmpgp.h> /* XXX pgpExtractPubkeyFingerprint */
19 #include <rpmurl.h> /* XXX urlPath proto */
20 
21 #define _RPMTAG_INTERNAL
22 #include <rpmtag.h>
23 
24 #define _RPMEVR_INTERNAL /* XXX isInstallPrereq */
25 #include <rpmevr.h>
26 
27 #define _RPMDB_INTERNAL
28 #include <rpmdb.h>
29 
30 #include "debug.h"
31 
32 #ifdef NOTYET /* XXX syscall ACID needs --with-db=internal */
33 extern int logio_dispatch(DB_ENV * dbenv, DBT * dbt, DB_LSN * lsn, db_recops op)
34  /*@*/;
35 #endif
36 
37 #define DBIDEBUG(_dbi, _list) if ((_dbi)->dbi_debug) fprintf _list
38 
39 /*@access rpmdb @*/
40 /*@access dbiIndex @*/
41 /*@access dbiIndexSet @*/
42 
43 /*@-redef@*/
44 union _dbswap {
45  uint64_t ul;
46  uint32_t ui;
47  uint16_t us;
48  uint8_t uc[8];
49 };
50 /*@=redef@*/
51 /*@unchecked@*/
52 static union _dbswap _endian = { .ui = 0x11223344 };
53 
54 static inline uint64_t _ntoh_ul(uint64_t ul)
55  /*@*/
56 {
57  union _dbswap _a;
58  _a.ul = ul;
59  if (_endian.uc[0] == 0x44) {
60  uint8_t _b, *_c = _a.uc; \
61  _b = _c[7]; _c[7] = _c[0]; _c[0] = _b; \
62  _b = _c[6]; _c[6] = _c[1]; _c[1] = _b; \
63  _b = _c[5]; _c[5] = _c[2]; _c[2] = _b; \
64  _b = _c[4]; _c[4] = _c[3]; _c[3] = _b; \
65  }
66  return _a.ul;
67 }
68 static inline uint64_t _hton_ul(uint64_t ul)
69  /*@*/
70 {
71  return _ntoh_ul(ul);
72 }
73 
74 static inline uint32_t _ntoh_ui(uint32_t ui)
75  /*@*/
76 {
77  union _dbswap _a;
78  _a.ui = ui;
79  if (_endian.uc[0] == 0x44) {
80  uint8_t _b, *_c = _a.uc; \
81  _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \
82  _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \
83  }
84  return _a.ui;
85 }
86 static inline uint32_t _hton_ui(uint32_t ui)
87  /*@*/
88 {
89  return _ntoh_ui(ui);
90 }
91 
92 static inline uint16_t _ntoh_us(uint16_t us)
93  /*@*/
94 {
95  union _dbswap _a;
96  _a.us = us;
97  if (_endian.uc[0] == 0x44) {
98  uint8_t _b, *_c = _a.uc; \
99  _b = _c[1]; _c[1] = _c[0]; _c[0] = _b; \
100  }
101  return _a.us;
102 }
103 static inline uint16_t _hton_us(uint16_t us)
104  /*@*/
105 {
106  return _ntoh_us(us);
107 }
108 
109 #ifdef NOTNOW
110 static const char * bfstring(unsigned int x, const char * xbf)
111 {
112  const char * s = xbf;
113  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
114  static char buf[BUFSIZ];
115  char * t, * te;
116  unsigned radix;
117  unsigned c, i, k;
118 
119  radix = (s != NULL ? *s++ : 16);
120 
121  if (radix <= 1 || radix >= 32)
122  radix = 16;
123 
124  t = buf;
125  switch (radix) {
126  case 8: *t++ = '0'; break;
127  case 16: *t++ = '0'; *t++ = 'x'; break;
128  }
129 
130  i = 0;
131  k = x;
132  do { i++; k /= radix; } while (k);
133 
134  te = t + i;
135 
136  k = x;
137  do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
138 
139  t = te;
140  i = '<';
141  if (s != NULL)
142  while ((c = *s++) != '\0') {
143  if (c > ' ') continue;
144 
145  k = (1 << (c - 1));
146  if (!(x & k)) continue;
147 
148  if (t == te) *t++ = '=';
149 
150  *t++ = i;
151  i = ',';
152  while (*s > ' ')
153  *t++ = *s++;
154  }
155  if (t > te) *t++ = '>';
156  *t = '\0';
157  return buf;
158 }
159 
160 /* XXX checked with db-4.5.20 */
161 static const char * dbtFlags =
162  "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK";
163 
164 static const char * dbenvOpenFlags =
165  "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB\20LOCK\21LOG\22MPOOL\23REP\24TXN\25LOCKDOWN\26PRIVATE\27RECOVER_FATAL\30REGISTER\31SYSTEM_MEM";
166 
167 static const char * dbOpenFlags =
168  "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17EXCL\20FCNTL_LOCKING\21NO_AUTO_COMMIT\22RDWRMASTER\23WRITEOPEN";
169 
170 static const char * dbenvSetFlags =
171  "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CDB_ALLDB\20DIRECT_DB\21DIRECT_LOG\22DSYNC_DB\23DSYNC_LOG\24LOG_AUTOREMOVE\25LOG_INMEMORY\26NOLOCKING\27NOPANIC\30OVERWRITE\31PANIC_ENV\36REGION_INIT\37TIME_NOTGRANTED\40YIELDCPU";
172 
173 static const char * dbSetFlags =
174  "\20\1CREATE\2DURABLE_UNKNOWN\3FORCE\4MULTIVERSION\5NOMMAP\6RDONLY\7RECOVER\10THREAD\11TRUNCATE\12TXN_NOSYNC\13TXN_NOT_DURABLEi\14TXN_WRITE_NOSYNC\15USE_ENVIRON\16USE_ENVIRON_ROOT\17CHKSUM\20DUP\21DUPSORT\22ENCRYPT\23INORDER\24RECNUM\25RENUMBER\26REVSPLITOFF\27SNAPSHOT";
175 
176 static const char * dbiModeFlags =
177  "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW";
178 #endif /* NOTNOW */
179 
180 /*@-redef@*/
181 typedef struct key_s {
182  uint32_t v;
183 /*@observer@*/
184  const char *n;
185 } KEY;
186 /*@=redef@*/
187 
188 /*@observer@*/
189 static const char * tblName(uint32_t v, KEY * tbl, size_t ntbl)
190  /*@*/
191 {
192  const char * n = NULL;
193  static char buf[32];
194  size_t i;
195 
196  for (i = 0; i < ntbl; i++) {
197  if (v != tbl[i].v)
198  continue;
199  n = tbl[i].n;
200  break;
201  }
202  if (n == NULL) {
203  (void) snprintf(buf, sizeof(buf), "0x%x", (unsigned)v);
204  n = buf;
205  }
206  return n;
207 }
208 
209 static const char * fmtBits(uint32_t flags, KEY tbl[], size_t ntbl, char *t)
210  /*@modifies t @*/
211 {
212  char pre = '<';
213  char * te = t;
214  int i;
215 
216  sprintf(t, "0x%x", (unsigned)flags);
217  te = t;
218  te += strlen(te);
219  for (i = 0; i < 32; i++) {
220  uint32_t mask = (1 << i);
221  const char * name;
222 
223  if (!(flags & mask))
224  continue;
225 
226  name = tblName(mask, tbl, ntbl);
227  *te++ = pre;
228  pre = ',';
229  te = stpcpy(te, name);
230  }
231  if (pre == ',') *te++ = '>';
232  *te = '\0';
233  return t;
234 }
235 
236 #define _ENTRY(_v) { DB_##_v, #_v, }
237 
238 /*@unchecked@*/ /*@observer@*/
239 static KEY DBeflags[] = {
240  _ENTRY(INIT_CDB),
241  _ENTRY(INIT_LOCK),
242  _ENTRY(INIT_LOG),
243  _ENTRY(INIT_MPOOL),
244 #if defined(DB_INIT_MUTEX) /* XXX db-6.1.19 breaks "make distcheck" */
245  _ENTRY(INIT_MUTEX), /* XXX not in DBENV->open() doco */
246 #endif
247  _ENTRY(INIT_REP),
248  _ENTRY(INIT_TXN),
249  _ENTRY(RECOVER),
250  _ENTRY(RECOVER_FATAL),
251  _ENTRY(USE_ENVIRON),
252  _ENTRY(USE_ENVIRON_ROOT),
253  _ENTRY(CREATE),
254  _ENTRY(LOCKDOWN),
255 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR >= 5)
256  _ENTRY(FAILCHK),
257 #endif
258  _ENTRY(PRIVATE),
259  _ENTRY(REGISTER),
260  _ENTRY(SYSTEM_MEM),
261  _ENTRY(THREAD),
262 };
263 /*@unchecked@*/
264 static size_t nDBeflags = sizeof(DBeflags) / sizeof(DBeflags[0]);
265 /*@observer@*/
266 static const char * fmtDBeflags(uint32_t flags)
267  /*@*/
268 {
269  static char buf[BUFSIZ];
270  char * te = buf;
271  te = stpcpy(te, "\n\tflags: ");
272  (void) fmtBits(flags, DBeflags, nDBeflags, te);
273  return buf;
274 }
275 #define _EFLAGS(_eflags) fmtDBeflags(_eflags)
276 
277 /*@unchecked@*/ /*@observer@*/
278 static KEY DBoflags[] = {
279  _ENTRY(AUTO_COMMIT),
280  _ENTRY(CREATE),
281  _ENTRY(EXCL),
282  _ENTRY(MULTIVERSION),
283  _ENTRY(NOMMAP),
284  _ENTRY(RDONLY),
285  _ENTRY(READ_UNCOMMITTED),
286  _ENTRY(THREAD),
287  _ENTRY(TRUNCATE),
288 };
289 /*@unchecked@*/
290 static size_t nDBoflags = sizeof(DBoflags) / sizeof(DBoflags[0]);
291 /*@observer@*/
292 static const char * fmtDBoflags(uint32_t flags)
293  /*@*/
294 {
295  static char buf[BUFSIZ];
296  char * te = buf;
297  te = stpcpy(te, "\n\tflags: ");
298  (void) fmtBits(flags, DBoflags, nDBoflags, te);
299  return buf;
300 }
301 #define _OFLAGS(_oflags) fmtDBoflags(_oflags)
302 
303 /*@unchecked@*/ /*@observer@*/
304 static KEY DBaflags[] = {
305  _ENTRY(CREATE),
306  _ENTRY(IMMUTABLE_KEY),
307 };
308 /*@unchecked@*/
309 static size_t nDBaflags = sizeof(DBaflags) / sizeof(DBaflags[0]);
310 /*@observer@*/
311 static const char * fmtDBaflags(uint32_t flags)
312  /*@*/
313 {
314  static char buf[BUFSIZ];
315  char * te = buf;
316  te = stpcpy(te, "\n\tflags: ");
317  (void) fmtBits(flags, DBaflags, nDBaflags, te);
318  return buf;
319 }
320 #define _AFLAGS(_aflags) fmtDBaflags(_aflags)
321 
322 /*@unchecked@*/ /*@observer@*/
323 static KEY DBafflags[] = {
324  _ENTRY(FOREIGN_ABORT),
325  _ENTRY(FOREIGN_CASCADE),
326  _ENTRY(FOREIGN_NULLIFY),
327 };
328 /*@unchecked@*/
329 static size_t nDBafflags = sizeof(DBafflags) / sizeof(DBafflags[0]);
330 /*@observer@*/
331 static const char * fmtDBafflags(uint32_t flags)
332  /*@*/
333 {
334  static char buf[BUFSIZ];
335  char * te = buf;
336  te = stpcpy(te, "\n\tflags: ");
337  (void) fmtBits(flags, DBafflags, nDBafflags, te);
338  return buf;
339 }
340 #define _AFFLAGS(_afflags) fmtDBafflags(_afflags)
341 
342 /*@unchecked@*/ /*@observer@*/
343 static KEY DBCoflags[] = {
344  /* XXX DB->cursor() doco for db-5.1.19 lists, undef'd */
345 #if defined(DB_CURSOR_BULK)
346  _ENTRY(CURSOR_BULK),
347 #endif
348  _ENTRY(READ_COMMITTED),
349  _ENTRY(READ_UNCOMMITTED),
350  _ENTRY(WRITECURSOR),
351  _ENTRY(TXN_SNAPSHOT),
352 };
353 /*@unchecked@*/
354 static size_t nDBCoflags = sizeof(DBCoflags) / sizeof(DBCoflags[0]);
355 /*@observer@*/
356 static const char * fmtDBCoflags(uint32_t flags)
357  /*@*/
358 {
359  static char buf[BUFSIZ];
360  char * te = buf;
361  (void) fmtBits(flags, DBCoflags, nDBCoflags, te);
362  return buf;
363 }
364 #define _DBCOFLAGS(_coflags) fmtDBCoflags(_coflags)
365 
366 /*@unchecked@*/ /*@observer@*/
367 static KEY DBCflags[] = {
368  _ENTRY(AFTER), /* Dbc.put */
369  _ENTRY(APPEND), /* Db.put */
370  _ENTRY(BEFORE), /* Dbc.put */
371  _ENTRY(CONSUME), /* Db.get, Dbc.del */
372  _ENTRY(CONSUME_WAIT), /* Db.get */
373  _ENTRY(CURRENT), /* Dbc.get, Dbc.put, DbLogc.get */
374  _ENTRY(FIRST), /* Dbc.get, DbLogc->get */
375  _ENTRY(GET_BOTH), /* Db.get, Dbc.get */
376  _ENTRY(GET_BOTHC), /* Dbc.get (internal) */
377  _ENTRY(GET_BOTH_RANGE), /* Db.get, Dbc.get */
378  _ENTRY(GET_RECNO), /* Dbc.get */
379  _ENTRY(JOIN_ITEM), /* Dbc.get; don't do primary lookup */
380  _ENTRY(KEYFIRST), /* Dbc.put */
381  _ENTRY(KEYLAST), /* Dbc.put */
382  _ENTRY(LAST), /* Dbc.get, DbLogc->get */
383  _ENTRY(NEXT), /* Dbc.get, DbLogc->get */
384  _ENTRY(NEXT_DUP), /* Dbc.get */
385  _ENTRY(NEXT_NODUP), /* Dbc.get */
386  _ENTRY(NODUPDATA), /* Db.put, Dbc.put */
387  _ENTRY(NOOVERWRITE), /* Db.put */
388  _ENTRY(NOSYNC), /* Db.close */
389 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR >= 5)
390  _ENTRY(OVERWRITE_DUP), /* Dbc.put, Db.put; no DB_KEYEXIST */
391 #endif
392  _ENTRY(POSITION), /* Dbc.dup */
393  _ENTRY(PREV), /* Dbc.get, DbLogc->get */
394  _ENTRY(PREV_DUP), /* Dbc.get */
395  _ENTRY(PREV_NODUP), /* Dbc.get */
396  _ENTRY(SET), /* Dbc.get, DbLogc->get */
397  _ENTRY(SET_RANGE), /* Dbc.get */
398  _ENTRY(SET_RECNO), /* Db.get, Dbc.get */
399  _ENTRY(UPDATE_SECONDARY), /* Dbc.get, Dbc.del (internal) */
400 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR >= 5)
401  _ENTRY(SET_LTE), /* Dbc.get (internal) */
402  _ENTRY(GET_BOTH_LTE), /* Dbc.get (internal) */
403 #endif
404 
405  _ENTRY(IGNORE_LEASE),
406  _ENTRY(READ_COMMITTED),
407  _ENTRY(READ_UNCOMMITTED),
408  _ENTRY(MULTIPLE),
409  _ENTRY(MULTIPLE_KEY),
410  _ENTRY(RMW),
411 };
412 #undef _ENTRY
413 /*@unchecked@*/
414 static size_t nDBCflags = sizeof(DBCflags) / sizeof(DBCflags[0]);
415 
416 /*@observer@*/
417 static const char * fmtDBCflags(uint32_t flags)
418  /*@*/
419 {
420  static char buf[BUFSIZ];
421  char * te = buf;
422  uint32_t op = (flags & DB_OPFLAGS_MASK);
423  flags &= ~DB_OPFLAGS_MASK;
424 
425  te = stpcpy(te, "\n\tflags: ");
426  if (op) {
427  te = stpcpy( stpcpy(te, "DB_"), tblName(op, DBCflags, nDBCflags));
428  *te++ = ' ';
429  *te = '\0';
430  }
431  if (flags)
432  (void) fmtBits(flags, DBCflags, nDBCflags, te);
433  return buf;
434 }
435 #define _DBCFLAGS(_flags) fmtDBCflags(_flags)
436 
437 #define _DBT_ENTRY(_v) { DB_DBT_##_v, #_v, }
438 /*@unchecked@*/ /*@observer@*/
439 static KEY DBTflags[] = {
440  _DBT_ENTRY(MALLOC),
441  _DBT_ENTRY(REALLOC),
442  _DBT_ENTRY(USERMEM),
443  _DBT_ENTRY(PARTIAL),
444  _DBT_ENTRY(APPMALLOC),
445  _DBT_ENTRY(MULTIPLE),
446 #if defined(DB_DBT_READONLY) /* XXX db-5.2.28 */
447  _DBT_ENTRY(READONLY),
448 #endif
449 #if defined(DB_DBT_ISSET)
450  _DBT_ENTRY(ISSET),
451 #endif
452 #if defined(DB_DBT_USERCOPY)
453  _DBT_ENTRY(USERCOPY),
454 #endif
455 #if defined(DB_DBT_USERMEM)
456  _DBT_ENTRY(USERMEM),
457 #endif
458 #if defined(DB_DBT_BLOB)
459  _DBT_ENTRY(BLOB),
460 #endif
461 #if defined(DB_DBT_BLOB_REC) /* internal */
462  _DBT_ENTRY(BLOB_REC),
463 #endif
464 #if defined(DB_DBT_STREAMING) /* internal */
465  _DBT_ENTRY(STREAMING),
466 #endif
467 #if defined(DB_DBT_BULK) /* internal */
468  _DBT_ENTRY(BULK),
469 #endif
470 #if defined(DB_DBT_DUPOK) /* internal */
471  _DBT_ENTRY(DUPOK),
472 #endif
473 };
474 #undef _DBT_ENTRY
475 /*@unchecked@*/
476 static size_t nDBTflags = sizeof(DBTflags) / sizeof(DBTflags[0]);
477 
478 /*@observer@*/
479 static char * fmtDBT(const DBT * K, char * te)
480  /*@modifies te @*/
481 {
482  static size_t keymax = 35;
483  int unprintable;
484  uint32_t i;
485 
486  sprintf(te, "%p[%u]\t", K->data, (unsigned)K->size);
487  te += strlen(te);
488  (void) fmtBits(K->flags, DBTflags, nDBTflags, te);
489  te += strlen(te);
490  if (K->data && K->size > 0) {
491  uint8_t * _u;
492  size_t _nu;
493 
494  /* Grab the key data/size. */
495  if (K->flags & DB_DBT_MULTIPLE) {
496  DBT * _K = K->data;
497  _u = _K->data;
498  _nu = _K->size;
499  } else {
500  _u = K->data;
501  _nu = K->size;
502  }
503  /* Verify if data is a string. */
504  unprintable = 0;
505  for (i = 0; i < _nu; i++)
506  unprintable |= !xisprint(_u[i]);
507 
508  /* Display the data. */
509  if (!unprintable) {
510  size_t nb = (_nu < keymax ? _nu : keymax);
511  char * ellipsis = (_nu < keymax ? "" : "...");
512  sprintf(te, "\t\"%.*s%s\"", (int)nb, (char *)_u, ellipsis);
513  } else {
514  switch (_nu) {
515  default: break;
516  case 4: sprintf(te, "\t0x%08x", (unsigned)*(uint32_t *)_u); break;
517  }
518  }
519 
520  te += strlen(te);
521  *te = '\0';
522  }
523  return te;
524 }
525 /*@observer@*/
526 static const char * fmtKDR(const DBT * K, const DBT * P, const DBT * D, const DBT * R)
527  /*@*/
528 {
529  static char buf[BUFSIZ];
530  char * te = buf;
531 
532  if (K) {
533  te = stpcpy(te, "\n\t key: ");
534  te = fmtDBT(K, te);
535  }
536  if (P) {
537  te = stpcpy(te, "\n\t pkey: ");
538  te = fmtDBT(P, te);
539  }
540  if (D) {
541  te = stpcpy(te, "\n\t data: ");
542  te = fmtDBT(D, te);
543  }
544  if (R) {
545  te = stpcpy(te, "\n\t res: ");
546  te = fmtDBT(R, te);
547  }
548  *te = '\0';
549 
550  return buf;
551 }
552 #define _KEYDATA(_K, _P, _D, _R) fmtKDR(_K, _P, _D, _R)
553 
554 /*@-globuse -mustmod @*/ /* FIX: rpmError not annotated yet. */
555 static int Xcvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg,
556  int error, int printit,
557  const char * func, const char * fn, unsigned ln)
558  /*@globals fileSystem @*/
559  /*@modifies fileSystem @*/
560 {
561  int rc = error;
562 
563  if (printit && rc) {
564 /*@-moduncon@*/ /* FIX: annotate db3 methods */
565  rpmlog(RPMLOG_ERR, "%s:%s:%u: %s(%d): %s\n",
566  func, fn, ln, msg, rc, db_strerror(error));
567 /*@=moduncon@*/
568  }
569 
570  return rc;
571 }
572 /*@=globuse =mustmod @*/
573 #define cvtdberr(_dbi, _msg, _error, _printit) \
574  Xcvtdberr(_dbi, _msg, _error, _printit, __FUNCTION__, __FILE__, __LINE__)
575 
582 /*@observer@*/
583 static const char * mapTagName(rpmdb rpmdb, dbiIndex dbi)
584  /*@*/
585 {
586  tagStore_t dbiTags = rpmdb->db_tags;
587  size_t dbix = 0;
588 
589  if (dbiTags != NULL)
590  while (dbix < rpmdb->db_ndbi) {
591  if (dbi->dbi_rpmtag == dbiTags->tag)
592  return dbiTags->str;
593  dbiTags++;
594  dbix++;
595  }
596  /* XXX should never reach here */
597  return tagName(dbi->dbi_rpmtag);
598 }
599 
600 static int db_fini(dbiIndex dbi, const char * dbhome,
601  /*@null@*/ const char * dbfile,
602  /*@unused@*/ /*@null@*/ const char * dbsubfile)
603  /*@globals fileSystem @*/
604  /*@modifies fileSystem @*/
605 {
606  rpmdb rpmdb = dbi->dbi_rpmdb;
607  DB_ENV * dbenv = rpmdb->db_dbenv;
608  int rc;
609 
610 DBIDEBUG(dbi, (stderr, "--> %s(%p,%s,%s,%s)\n", __FUNCTION__, dbi, dbhome, dbfile, dbsubfile));
611 
612  if (dbenv == NULL)
613  return 0;
614 
615  rc = dbenv->close(dbenv, 0);
616  rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
617  rpmdb->db_dbenv = NULL;
618 
619  if (dbfile)
620  rpmlog(RPMLOG_DEBUG, D_("closed db environment %s/%s\n"),
621  dbhome, dbfile);
622 
623  if (rpmdb->db_remove_env) {
624  int xx;
625 
626  /*@-moduncon@*/ /* FIX: annotate db3 methods */
627  xx = db_env_create(&dbenv, 0);
628  /*@=moduncon@*/
629  if (!xx && dbenv != NULL) {
630  xx = cvtdberr(dbi, "db_env_create", xx, _debug);
631  xx = dbenv->remove(dbenv, dbhome, DB_FORCE);
632  xx = cvtdberr(dbi, "dbenv->remove", xx, _debug);
633 
634  if (dbfile)
635  rpmlog(RPMLOG_DEBUG, D_("removed db environment %s/%s\n"),
636  dbhome, dbfile);
637  }
638 
639  }
640  return rc;
641 }
642 
643 static int db3_fsync_disable(/*@unused@*/ int fd)
644  /*@*/
645 {
646  return 0;
647 }
648 
649 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR >= 5)
650 
658 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid,
659  /*@unused@*/ db_threadid_t tid,
661  /*@*/
662 {
663  int is_alive = 1; /* assume all processes are alive */
664 
665  switch (flags) {
666  case DB_MUTEX_PROCESS_ONLY:
667  case 0:
668  default:
669  is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH));
670  break;
671  }
672  return is_alive;
673 }
674 #endif
675 
676 /*==============================================================*/
677 
678 /* HAVE_SYS_SYSCTL_H */
679 #if defined(HAVE_PHYSMEM_SYSCTL) || defined(HAVE_NCPU_SYSCTL)
680 #include <sys/sysctl.h>
681 #endif
682 
683 static uint64_t physmem(void)
684  /*@*/
685 {
686  static uint64_t _physmem = 0;
687  static int oneshot = 0;
688 
689  if (!oneshot) {
690 #if defined(HAVE_PHYSMEM_SYSCONF)
691  const long _pagesize = sysconf(_SC_PAGESIZE);
692  const long _pages = sysconf(_SC_PHYS_PAGES);
693  if (_pagesize != -1 || _pages != -1)
694  _physmem = (uint64_t)(_pagesize) * (uint64_t)(_pages);
695 #elif defined(HAVE_PHYSMEM_SYSCTL)
696  int name[2] = { CTL_HW, HW_PHYSMEM };
697  unsigned long mem;
698  size_t mem_ptr_size = sizeof(mem);
699  if (!sysctl(name, 2, &mem, &mem_ptr_size, NULL, 0)) {
700  if (mem_ptr_size != sizeof(mem)) {
701  if (mem_ptr_size == sizeof(unsigned int))
702  _physmem = *(unsigned int *)(&mem);
703  } else {
704  _physmem = mem;
705  }
706  }
707 #endif
708  oneshot++;
709  }
710  return _physmem;
711 }
712 
713 static size_t ncores(void)
714  /*@*/
715 {
716  static size_t _ncores = 1;
717  static int oneshot = 0;
718 
719  if (!oneshot) {
720 #if defined(HAVE_NCPU_SYSCONF)
721  const long cpus = sysconf(_SC_NPROCESSORS_ONLN);
722 #elif defined(HAVE_NCPU_SYSCTL)
723  int name[2] = { CTL_HW, HW_NCPU };
724  int cpus = 0;
725  size_t cpus_size = sizeof(cpus);
726  if (sysctl(name, 2, &cpus, &cpus_size, NULL, 0)
727  || cpus_size != sizeof(cpus))
728  cpus = 0;
729 #endif
730  if (cpus > (int)_ncores)
731  _ncores = (size_t)(cpus);
732  oneshot++;
733  }
734  return _ncores;
735 }
736 
737 /*==============================================================*/
738 #define _TABLE(_v) { #_v, DB_EVENT_##_v }
739 static struct _events_s {
740  const char * n;
741  uint32_t v;
742 } _events[] = {
743 #if (DB_VERSION_MAJOR == 6 && DB_VERSION_MINOR >= 1)
744  _TABLE(PANIC), /* 0 */
745  _TABLE(REG_ALIVE), /* 1 */
746  _TABLE(REG_PANIC), /* 2 */
747  _TABLE(REP_AUTOTAKEOVER_FAILED), /* 3 */
748  _TABLE(REP_CLIENT), /* 4 */
749  _TABLE(REP_CONNECT_BROKEN), /* 5 */
750  _TABLE(REP_CONNECT_ESTD), /* 6 */
751  _TABLE(REP_CONNECT_TRY_FAILED), /* 7 */
752  _TABLE(REP_DUPMASTER), /* 8 */
753  _TABLE(REP_ELECTED), /* 9 */
754  _TABLE(REP_ELECTION_FAILED),/* 10 */
755  _TABLE(REP_INQUEUE_FULL), /* 11 */
756  _TABLE(REP_INIT_DONE), /* 12 */
757  _TABLE(REP_JOIN_FAILURE), /* 13 */
758  _TABLE(REP_LOCAL_SITE_REMOVED), /* 14 */
759  _TABLE(REP_MASTER), /* 15 */
760  _TABLE(REP_MASTER_FAILURE), /* 16 */
761  _TABLE(REP_NEWMASTER), /* 17 */
762  _TABLE(REP_PERM_FAILED), /* 18 */
763  _TABLE(REP_SITE_ADDED), /* 19 */
764  _TABLE(REP_SITE_REMOVED), /* 20 */
765  _TABLE(REP_STARTUPDONE), /* 21 */
766  _TABLE(REP_WOULD_ROLLBACK), /* 22 */
767  _TABLE(WRITE_FAILED), /* 23 */
768  _TABLE(MUTEX_DIED), /* 24 */
769  _TABLE(FAILCHK_PANIC), /* 25 */
770  _TABLE(NO_SUCH_EVENT), /* 26 */
771  _TABLE(NO_SUCH_EVENT), /* 27 */
772  _TABLE(NO_SUCH_EVENT), /* 28 */
773  _TABLE(NO_SUCH_EVENT), /* 29 */
774  _TABLE(NO_SUCH_EVENT), /* 30 */
775  _TABLE(NO_SUCH_EVENT), /* 31 */
776 #elif (DB_VERSION_MAJOR == 6 && DB_VERSION_MINOR >= 0)
777  _TABLE(PANIC), /* 0 */
778  _TABLE(REG_ALIVE), /* 1 */
779  _TABLE(REG_PANIC), /* 2 */
780  _TABLE(REP_AUTOTAKEOVER_FAILED), /* 3 */
781  _TABLE(REP_CLIENT), /* 4 */
782  _TABLE(REP_CONNECT_BROKEN), /* 5 */
783  _TABLE(REP_CONNECT_ESTD), /* 6 */
784  _TABLE(REP_CONNECT_TRY_FAILED), /* 7 */
785  _TABLE(REP_DUPMASTER), /* 8 */
786  _TABLE(REP_ELECTED), /* 9 */
787  _TABLE(REP_ELECTION_FAILED),/* 10 */
788  _TABLE(REP_INIT_DONE), /* 11 */
789  _TABLE(REP_JOIN_FAILURE), /* 12 */
790  _TABLE(REP_LOCAL_SITE_REMOVED), /* 13 */
791  _TABLE(REP_MASTER), /* 14 */
792  _TABLE(REP_MASTER_FAILURE), /* 15 */
793  _TABLE(REP_NEWMASTER), /* 16 */
794  _TABLE(REP_PERM_FAILED), /* 17 */
795  _TABLE(REP_SITE_ADDED), /* 18 */
796  _TABLE(REP_SITE_REMOVED), /* 19 */
797  _TABLE(REP_STARTUPDONE), /* 20 */
798  _TABLE(REP_WOULD_ROLLBACK), /* 21 */
799  _TABLE(WRITE_FAILED), /* 22 */
800  _TABLE(NO_SUCH_EVENT), /* 23 */
801  _TABLE(NO_SUCH_EVENT), /* 24 */
802  _TABLE(NO_SUCH_EVENT), /* 25 */
803  _TABLE(NO_SUCH_EVENT), /* 26 */
804  _TABLE(NO_SUCH_EVENT), /* 27 */
805  _TABLE(NO_SUCH_EVENT), /* 28 */
806  _TABLE(NO_SUCH_EVENT), /* 29 */
807  _TABLE(NO_SUCH_EVENT), /* 30 */
808  _TABLE(NO_SUCH_EVENT), /* 31 */
809 #elif (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR >= 2)
810  _TABLE(PANIC), /* 0 */
811  _TABLE(REG_ALIVE), /* 1 */
812  _TABLE(REG_PANIC), /* 2 */
813  _TABLE(REP_CLIENT), /* 3 */
814  _TABLE(REP_CONNECT_BROKEN), /* 4 */
815  _TABLE(REP_CONNECT_ESTD), /* 5 */
816  _TABLE(REP_CONNECT_TRY_FAILED), /* 6 */
817  _TABLE(REP_DUPMASTER), /* 7 */
818  _TABLE(REP_ELECTED), /* 8 */
819  _TABLE(REP_ELECTION_FAILED),/* 9 */
820  _TABLE(REP_INIT_DONE), /* 10 */
821  _TABLE(REP_JOIN_FAILURE), /* 11 */
822  _TABLE(REP_LOCAL_SITE_REMOVED), /* 12 */
823  _TABLE(REP_MASTER), /* 13 */
824  _TABLE(REP_MASTER_FAILURE), /* 14 */
825  _TABLE(REP_NEWMASTER), /* 15 */
826  _TABLE(REP_PERM_FAILED), /* 16 */
827  _TABLE(REP_SITE_ADDED), /* 17 */
828  _TABLE(REP_SITE_REMOVED), /* 18 */
829  _TABLE(REP_STARTUPDONE), /* 19 */
830  _TABLE(REP_WOULD_ROLLBACK), /* 20 */
831  _TABLE(WRITE_FAILED), /* 21 */
832  _TABLE(NO_SUCH_EVENT), /* 22 */
833  _TABLE(NO_SUCH_EVENT), /* 23 */
834  _TABLE(NO_SUCH_EVENT), /* 24 */
835  _TABLE(NO_SUCH_EVENT), /* 25 */
836  _TABLE(NO_SUCH_EVENT), /* 26 */
837  _TABLE(NO_SUCH_EVENT), /* 27 */
838  _TABLE(NO_SUCH_EVENT), /* 28 */
839  _TABLE(NO_SUCH_EVENT), /* 29 */
840  _TABLE(NO_SUCH_EVENT), /* 30 */
841  _TABLE(NO_SUCH_EVENT), /* 31 */
842 #elif (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR < 2) || (DB_VERSION_MAJOR >= 6)
843  /* XXX numbered from db-5.1.19, older versions are different. */
844  _TABLE(PANIC), /* 0 */
845  _TABLE(REG_ALIVE), /* 1 */
846  _TABLE(REG_PANIC), /* 2 */
847  _TABLE(REP_CLIENT), /* 3 */
848  _TABLE(REP_DUPMASTER), /* 4 */
849  _TABLE(REP_ELECTED), /* 5 */
850  _TABLE(REP_ELECTION_FAILED),/* 6 */
851  _TABLE(REP_JOIN_FAILURE), /* 7 */
852  _TABLE(REP_MASTER), /* 8 */
853  _TABLE(REP_MASTER_FAILURE), /* 9 */
854  _TABLE(REP_NEWMASTER), /* 10 */
855  _TABLE(REP_PERM_FAILED), /* 11 */
856  _TABLE(REP_STARTUPDONE), /* 12 */
857  _TABLE(WRITE_FAILED), /* 13 */
858  _TABLE(NO_SUCH_EVENT), /* 14 */
859  _TABLE(NO_SUCH_EVENT), /* 15 */
860  _TABLE(NO_SUCH_EVENT), /* 16 */
861  _TABLE(NO_SUCH_EVENT), /* 17 */
862  _TABLE(NO_SUCH_EVENT), /* 18 */
863  _TABLE(NO_SUCH_EVENT), /* 19 */
864  _TABLE(NO_SUCH_EVENT), /* 20 */
865  _TABLE(NO_SUCH_EVENT), /* 21 */
866  _TABLE(NO_SUCH_EVENT), /* 22 */
867  _TABLE(NO_SUCH_EVENT), /* 23 */
868  _TABLE(NO_SUCH_EVENT), /* 24 */
869  _TABLE(NO_SUCH_EVENT), /* 25 */
870  _TABLE(NO_SUCH_EVENT), /* 26 */
871  _TABLE(NO_SUCH_EVENT), /* 27 */
872  _TABLE(NO_SUCH_EVENT), /* 28 */
873  _TABLE(NO_SUCH_EVENT), /* 29 */
874  _TABLE(NO_SUCH_EVENT), /* 30 */
875  _TABLE(NO_SUCH_EVENT), /* 31 */
876 #else
877  _TABLE(NO_SUCH_EVENT), /* 0 */
878  _TABLE(PANIC), /* 1 */
879 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8)
880  _TABLE(REG_ALIVE), /* 2 */
881  _TABLE(REG_PANIC), /* 3 */
882 #else
883  _TABLE(NO_SUCH_EVENT), /* 2 */
884  _TABLE(NO_SUCH_EVENT), /* 3 */
885 #endif
886  _TABLE(REP_CLIENT), /* 4 */
887  _TABLE(REP_ELECTED), /* 5 */
888  _TABLE(REP_MASTER), /* 6 */
889  _TABLE(REP_NEWMASTER), /* 7 */
890  _TABLE(REP_PERM_FAILED), /* 8 */
891  _TABLE(REP_STARTUPDONE), /* 9 */
892  _TABLE(WRITE_FAILED), /* 10 */
893  _TABLE(NO_SUCH_EVENT), /* 11 */
894  _TABLE(NO_SUCH_EVENT), /* 12 */
895  _TABLE(NO_SUCH_EVENT), /* 13 */
896  _TABLE(NO_SUCH_EVENT), /* 14 */
897  _TABLE(NO_SUCH_EVENT), /* 15 */
898  _TABLE(NO_SUCH_EVENT), /* 16 */
899  _TABLE(NO_SUCH_EVENT), /* 17 */
900  _TABLE(NO_SUCH_EVENT), /* 18 */
901  _TABLE(NO_SUCH_EVENT), /* 19 */
902  _TABLE(NO_SUCH_EVENT), /* 20 */
903  _TABLE(NO_SUCH_EVENT), /* 21 */
904  _TABLE(NO_SUCH_EVENT), /* 22 */
905  _TABLE(NO_SUCH_EVENT), /* 23 */
906  _TABLE(NO_SUCH_EVENT), /* 24 */
907  _TABLE(NO_SUCH_EVENT), /* 25 */
908  _TABLE(NO_SUCH_EVENT), /* 26 */
909  _TABLE(NO_SUCH_EVENT), /* 27 */
910  _TABLE(NO_SUCH_EVENT), /* 28 */
911  _TABLE(NO_SUCH_EVENT), /* 29 */
912  _TABLE(NO_SUCH_EVENT), /* 30 */
913  _TABLE(NO_SUCH_EVENT), /* 31 */
914 #endif
915 };
916 #undef _TABLE
917 
918 static void
919 rpmdbe_event_notify(DB_ENV * dbenv, u_int32_t event, void * event_info)
920 {
921  void * o = (dbenv ? dbenv->app_private : NULL);
922 fprintf(stderr, "==> %s(%p, %s(%u), %p) app_private %p\n", __FUNCTION__, dbenv, _events[event & 0x1f].n, event, event_info, o);
923 }
924 
925 static void
926 rpmdbe_feedback(DB_ENV * dbenv, int opcode, int percent)
927  /*@*/
928 {
929  dbenv = NULL;
930  dbenv = dbenv;
931  switch (opcode) {
932  case DB_RECOVER:
933  fprintf(stderr, "\rrecovery %d%% complete", percent);
934  (void)fflush(stderr); /* XXX unnecessary? */
935  /*@fallthrough@*/
936  default:
937  break;
938  }
939 }
940 
941 /*@-moduncon@*/ /* FIX: annotate db3 methods */
942 static int db_init(dbiIndex dbi, const char * dbhome,
943  /*@null@*/ const char * dbfile,
944  /*@unused@*/ /*@null@*/ const char * dbsubfile,
945  /*@out@*/ DB_ENV ** dbenvp)
946  /*@globals rpmGlobalMacroContext, h_errno,
947  fileSystem, internalState @*/
948  /*@modifies dbi, *dbenvp, fileSystem, internalState @*/
949 {
950  static int oneshot = 0;
951  uint64_t _physmem = physmem();
952  size_t _ncores = ncores();
953  rpmdb rpmdb = dbi->dbi_rpmdb;
954  DB_ENV *dbenv = NULL;
955  int eflags;
956  int rc;
957  int xx;
958 
959  if (!oneshot) {
960  rpmlog(RPMLOG_DEBUG, D_("rpmdb: cpus %u physmem %uMb\n"),
961  (unsigned)_ncores, (unsigned)(_physmem/(1024 * 1024)));
962  xx = db_env_set_func_open((int (*)(const char *, int, ...))Open);
963  xx = cvtdberr(dbi, "db_env_set_func_open", xx, _debug);
964  oneshot++;
965  }
966 
967  if (dbenvp == NULL)
968  return 1;
969 
970  /* XXX HACK */
971  /*@-assignexpose@*/
972  if (rpmdb->db_errfile == NULL)
973  rpmdb->db_errfile = stderr;
974  /*@=assignexpose@*/
975 
976  eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
977  /* Try to join, rather than create, the environment. */
978  /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */
979  if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
980  /* XXX DB_RECOVER needs automagic */
981  if (!(eflags & DB_INIT_TXN)) eflags &= ~DB_RECOVER;
982 
983  if (dbfile)
984  rpmlog(RPMLOG_DEBUG, D_("opening db environment %s/%s %s\n"),
985  dbhome, dbfile, prDbiOpenFlags(eflags, 1));
986 
987  /* XXX Can't do RPC w/o host. */
988 #if defined(DB_RPCCLIENT)
989  if (dbi->dbi_host == NULL)
990  dbi->dbi_ecflags &= ~DB_RPCCLIENT;
991 #endif
992 
993  /* XXX DB_THREAD from dbi->dbi_oeflags? */
994  rc = db_env_create(&dbenv, dbi->dbi_ecflags);
995  rc = cvtdberr(dbi, "db_env_create", rc, _debug);
996  if (dbenv == NULL || rc)
997  goto errxit;
998 
999 /*@-noeffectuncon@*/
1000 /*@-castfcnptr@*/
1001  dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall);
1002 /*@=castfcnptr@*/
1003  dbenv->set_errfile(dbenv, rpmdb->db_errfile);
1004  dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
1005 /*@=noeffectuncon@*/
1006 
1007  /* 4.1: dbenv->set_alloc(???) */
1008  /* 4.1: dbenv->set_data_dir(???) */
1009  /* 4.1: dbenv->set_encrypt(???) */
1010 
1011  /* 5.3: dbenv->backup() */
1012  /* 5.3: dbenv->dbackup() */
1013  /* 5.3: dbenv->set_backup_callbacks() */
1014  /* 5.3: dbenv->set_backup_config() */
1015 
1016  /* 5.3: dbenv->set_metadata_dir() */
1017 
1018  xx = dbenv->set_feedback(dbenv, rpmdbe_feedback);
1019  xx = cvtdberr(dbi, "dbenv->set_feedback", xx, _debug);
1020  xx = dbenv->set_event_notify(dbenv, rpmdbe_event_notify);
1021  xx = cvtdberr(dbi, "dbenv->set_event_notify", xx, _debug);
1022 
1023  /* 4.1: dbenv->set_flags(???) */
1024 
1025  /* dbenv->set_paniccall(???) */
1026 
1027 #if defined(DB_RPCCLIENT)
1028  if ((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) {
1029  const char * home;
1030  int retry = 0;
1031 
1032  if ((home = strrchr(dbhome, '/')) != NULL)
1033  dbhome = ++home;
1034 
1035  while (retry++ < 5) {
1036 /* XXX 3.3.4 change. */
1037  xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
1038  dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
1039  xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
1040  if (!xx)
1041  break;
1042  (void) sleep(15);
1043  }
1044  } else
1045 #endif
1046  {
1047 
1048  { size_t _lo = 16 * 1024 * 1024;
1049  size_t _hi = 512 * 1024 * 1024;
1050  size_t _mp_mmapsize = _physmem; /* XXX default value? */
1051  if (_mp_mmapsize < _lo) _mp_mmapsize = _lo;
1052  if (_mp_mmapsize > _hi) _mp_mmapsize = _hi;
1053  xx = dbenv->set_mp_mmapsize(dbenv, _mp_mmapsize);
1054  xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
1055  }
1056 
1057  if (dbi->dbi_tmpdir) {
1058  const char * root;
1059  const char * tmpdir;
1060 
1061  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
1062  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
1063  root = NULL;
1064 /*@-mods@*/
1065  tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
1066 /*@=mods@*/
1067  xx = dbenv->set_tmp_dir(dbenv, tmpdir);
1068  xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
1069  tmpdir = _free(tmpdir);
1070  }
1071  }
1072 
1073 /* ==== Locking: */
1074 #define _RPMDB_NLOCKS 16384
1075  if (eflags & DB_INIT_LOCK) {
1076  uint32_t _lk_max_lockers = _RPMDB_NLOCKS;
1077  uint32_t _lk_max_locks = _RPMDB_NLOCKS;
1078  uint32_t _lk_max_objects = _RPMDB_NLOCKS;
1079 
1080  xx = dbenv->set_lk_max_lockers(dbenv, _lk_max_lockers);
1081  xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug);
1082  xx = dbenv->set_lk_max_locks(dbenv, _lk_max_locks);
1083  xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug);
1084  xx = dbenv->set_lk_max_objects(dbenv, _lk_max_objects);
1085  xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug);
1086 
1087  { uint32_t _max = 10 * _RPMDB_NLOCKS;
1088  xx = dbenv->mutex_set_max(dbenv, _max);
1089  xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug);
1090  }
1091 
1092  }
1093 
1094 /* ==== Logging: */
1095  const char *logdir;
1096 
1097  logdir = rpmGetPath(dbhome, "/", "log", NULL);
1098  /*
1099  * Create the /var/lib/rpm/log directory if it doesn't exist (root only).
1100  */
1101  rpmioMkpath(logdir, 0755, getuid(), getgid());
1102 
1103  xx = dbenv->set_lg_dir(dbenv, logdir);
1104  xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug);
1105 
1106  _free(logdir);
1107 
1108 /* ==== Memory pool: */
1109  if (eflags & DB_INIT_MPOOL) {
1110  uint32_t _lo = 16 * 1024 * 1024;
1111  uint32_t _hi = 512 * 1024 * 1024;
1112  uint32_t _gb = 0;
1113  uint32_t _bytes = _physmem; /* XXX default value? */
1114  int _ncache = 4;
1115  if (_bytes < _lo) _bytes = _lo;
1116  if (_bytes > _hi) _bytes = _hi;
1117  xx = dbenv->set_cache_max(dbenv, _gb, _hi);
1118  xx = cvtdberr(dbi, "dbenv->set_cache_max", xx, _debug);
1119  if (_ncache > 0)
1120  _bytes /= _ncache;
1121  xx = dbenv->set_cachesize(dbenv, _gb, _bytes, _ncache);
1122  xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
1123  }
1124 
1125 /* ==== Mutexes: */
1126 /* ==== Replication: */
1127 /* ==== Sequences: */
1128 /* ==== Transactions: */
1129 #ifdef NOTYET /* XXX syscall ACID needs --with-db=internal */
1130  if (eflags & DB_INIT_TXN) {
1131  xx = dbenv->set_app_dispatch(dbenv, logio_dispatch);
1132  xx = cvtdberr(dbi, "dbenv->set_app_dispatch", xx, _debug);
1133  }
1134 #endif
1135 
1136 /* ==== Other: */
1137  if (dbi->dbi_no_fsync) {
1138  xx = db_env_set_func_fsync(db3_fsync_disable);
1139  xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
1140  }
1141 
1142  /* XXX Set a default shm_key. */
1143  if ((eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
1144 #if defined(HAVE_FTOK)
1145  dbi->dbi_shmkey = ftok(dbhome, 0);
1146 #else
1147  dbi->dbi_shmkey = 0x44631380;
1148 #endif
1149  }
1150  if (dbi->dbi_shmkey) {
1151  xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
1152  xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
1153  }
1154 
1155 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR >= 5)
1156  /* XXX capture dbenv->falchk output on stderr. */
1157 /*@-noeffectuncon@*/
1158  dbenv->set_msgfile(dbenv, rpmdb->db_errfile);
1159 /*@=noeffectuncon@*/
1160  if (dbi->dbi_thread_count >= 8) {
1161  xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count);
1162  xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug);
1163  }
1164 #endif
1165 
1166  /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */
1167  if (eflags & DB_RECOVER) {
1168  eflags |= DB_CREATE;
1169  xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1);
1170  xx = cvtdberr(dbi, "dbenv->set_verbose", xx, _debug);
1171  }
1172 
1173  rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms);
1174  xx = _debug;
1175 #if defined(DB_VERSION_MISMATCH)
1176  if (rc == DB_VERSION_MISMATCH) xx = 0;
1177 #endif
1178  if (rc == EINVAL) xx = 0;
1179  rc = cvtdberr(dbi, "dbenv->open", rc, xx);
1180  if (rc)
1181  goto errxit;
1182 
1183 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR >= 5)
1184  if (dbi->dbi_thread_count >= 8) {
1185  /* XXX Set pid/tid is_alive probe. */
1186  xx = dbenv->set_isalive(dbenv, db3is_alive);
1187  xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug);
1188  /* XXX Clean out stale shared read locks. */
1189  xx = dbenv->failchk(dbenv, 0);
1190  xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug);
1191  if (xx == DB_RUNRECOVERY) {
1192  rc = xx;
1193  goto errxit;
1194  }
1195  }
1196 #endif
1197 
1198  *dbenvp = dbenv;
1199 
1200 DBIDEBUG(dbi, (stderr, "<-- %s(%p(%s),%s,%s,%s,%p) dbenv %p %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbhome, dbfile, dbsubfile, dbenvp, dbenv, _EFLAGS(eflags)));
1201 
1202  return 0;
1203 
1204 errxit:
1205  if (dbenv) {
1206  xx = dbenv->close(dbenv, 0);
1207  xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
1208  }
1209  return rc;
1210 }
1211 /*@=moduncon@*/
1212 
1213 #ifdef NOTYET
1214 /*@-mustmod@*/
1215 static int db3remove(dbiIndex dbi, /*@null@*/ const char * dbfile,
1216  /*@unused@*/ /*@null@*/ const char * dbsubfile,
1217  unsigned int flags)
1218  /*@globals fileSystem @*/
1219  /*@modifies dbi, fileSystem @*/
1220 {
1221  DB * db = (DB *) dbi->dbi_db;
1222  int rc;
1223 
1224 assert(db != NULL);
1225  rc = db->remove(db, dbfile, dbsubfile, flags);
1226  rc = cvtdberr(dbi, "db->remove", rc, _debug);
1227 
1228 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, dbsubfile, flags, rc));
1229 
1230  return rc;
1231 }
1232 /*@=mustmod@*/
1233 
1234 /*@-mustmod@*/
1235 static int db3rename(dbiIndex dbi, /*@null@*/ const char * dbfile,
1236  /*@unused@*/ /*@null@*/ const char * dbsubfile,
1237  /*@unused@*/ /*@null@*/ const char * newname,
1238  unsigned int flags)
1239  /*@globals fileSystem @*/
1240  /*@modifies dbi, fileSystem @*/
1241 {
1242  DB * db = (DB *) dbi->dbi_db;
1243  int rc;
1244 
1245 assert(db != NULL);
1246  rc = db->rename(db, dbfile, dbsubfile, newname, flags);
1247  rc = cvtdberr(dbi, "db->rename", rc, _debug);
1248 
1249 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,%s,0x%x) rc %d %s\n", __FUNCTION__, dbi, dbfile, dbsubfile, newname, flags, rc, _DBCFLAGS(flags)));
1250 
1251  return rc;
1252 }
1253 /*@=mustmod@*/
1254 
1255 /*@-mustmod@*/
1256 static int db3truncate(dbiIndex dbi, unsigned int * countp, unsigned int flags)
1257  /*@globals fileSystem @*/
1258  /*@modifies *countp, fileSystem @*/
1259 {
1260  DB * db = (DB *) dbi->dbi_db;
1261  DB_TXN * _txnid = dbiTxnid(dbi);
1262  int rc;
1263 
1264 assert(db != NULL);
1265  rc = db->truncate(db, _txnid, countp, flags);
1266  rc = cvtdberr(dbi, "db->truncate", rc, _debug);
1267 
1268 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, countp, flags, rc));
1269 
1270  return rc;
1271 }
1272 /*@=mustmod@*/
1273 
1274 /*@-mustmod@*/
1275 static int db3upgrade(dbiIndex dbi, /*@null@*/ const char * dbfile,
1276  unsigned int flags)
1277  /*@globals fileSystem @*/
1278  /*@modifies fileSystem @*/
1279 {
1280  DB * db = (DB *) dbi->dbi_db;
1281  int rc;
1282 
1283 assert(db != NULL);
1284  rc = db->upgrade(db, dbfile, flags);
1285  rc = cvtdberr(dbi, "db->upgrade", rc, _debug);
1286 
1287 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, flags, rc));
1288 
1289  return rc;
1290 }
1291 /*@=mustmod@*/
1292 #endif /* NOTYET */
1293 
1294 static int db3sync(dbiIndex dbi, unsigned int flags)
1295  /*@globals fileSystem @*/
1296  /*@modifies fileSystem @*/
1297 {
1298  DB * db = (DB *) dbi->dbi_db;
1299  int rc = 0;
1300  int _printit;
1301 
1302  if (db != NULL)
1303  rc = db->sync(db, flags);
1304  _printit = _debug;
1305  rc = cvtdberr(dbi, "db->sync", rc, _printit);
1306 
1307 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
1308 
1309  return rc;
1310 }
1311 
1312 /*@-mustmod@*/
1313 static int db3exists(dbiIndex dbi, DBT * key, unsigned int flags)
1314  /*@globals fileSystem @*/
1315  /*@modifies fileSystem @*/
1316 {
1317  DB * db = (DB *) dbi->dbi_db;
1318  DB_TXN * _txnid = dbiTxnid(dbi);
1319  int _printit;
1320  int rc;
1321 
1322 assert(db != NULL);
1323  rc = db->exists(db, _txnid, key, flags);
1324  /* XXX DB_NOTFOUND can be returned */
1325  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1326  rc = cvtdberr(dbi, "db->exists", rc, _printit);
1327 
1328 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, key, flags, rc, _KEYDATA(key, NULL, NULL, NULL)));
1329 
1330  return rc;
1331 }
1332 /*@=mustmod@*/
1333 
1334 /*@-mustmod@*/
1335 static int db3seqno(dbiIndex dbi, int64_t * seqnop, unsigned int flags)
1336  /*@globals fileSystem @*/
1337  /*@modifies *seqnop, fileSystem @*/
1338 {
1339  DB * db = (DB *) dbi->dbi_db;
1340  DB_TXN * _txnid = dbiTxnid(dbi);
1341  DB_SEQUENCE * seq = (DB_SEQUENCE *) dbi->dbi_seq;
1342  int32_t _delta = 1;
1343  db_seq_t seqno = 0;
1344  int rc;
1345 
1346 assert(db != NULL);
1347 assert(seq != NULL);
1348 
1349  if (seqnop && *seqnop)
1350  _delta = *seqnop;
1351 
1352  rc = seq->get(seq, _txnid, _delta, &seqno, 0);
1353  rc = cvtdberr(dbi, "seq->get", rc, _debug);
1354  if (rc) goto exit;
1355 
1356  if (seqnop)
1357  *seqnop = seqno;
1358 
1359 exit:
1360 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) seqno %lld rc %d\n", __FUNCTION__, dbi, seqnop, flags, (long long)seqno, rc));
1361 
1362  return rc;
1363 }
1364 /*@=mustmod@*/
1365 
1366 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
1367  unsigned int flags)
1368  /*@globals fileSystem @*/
1369  /*@modifies *dbcp, fileSystem @*/
1370 {
1371  int rc;
1372 
1373  if (dbcp) *dbcp = NULL;
1374 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1375  rc = dbcursor->dup(dbcursor, dbcp, flags);
1376  rc = cvtdberr(dbi, "dbcursor->dup", rc, _debug);
1377 #else
1378  rc = dbcursor->c_dup(dbcursor, dbcp, flags);
1379  rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
1380 #endif
1381 
1382 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, dbcp, flags, rc));
1383 
1384  return rc;
1385 }
1386 
1387 /*@-mustmod@*/
1388 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
1389  /*@unused@*/ unsigned int flags)
1390  /*@globals fileSystem @*/
1391  /*@modifies dbi, fileSystem @*/
1392 {
1393  int rc = -2;
1394 
1395  /* XXX db3copen error pathways come through here. */
1396  if (dbcursor != NULL) {
1397 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1398  rc = dbcursor->close(dbcursor);
1399  rc = cvtdberr(dbi, "dbcursor->close", rc, _debug);
1400 #else
1401  rc = dbcursor->c_close(dbcursor);
1402  rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
1403 #endif
1404  }
1405 
1406 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, flags, rc));
1407 
1408  return rc;
1409 }
1410 /*@=mustmod@*/
1411 
1412 static int db3copen(dbiIndex dbi, DB_TXN * txnid,
1413  /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
1414  /*@globals fileSystem @*/
1415  /*@modifies dbi, *dbcp, fileSystem @*/
1416 {
1417  DB * db = (DB *) dbi->dbi_db;
1418  DBC * dbcursor = NULL;
1419  int flags;
1420  int rc;
1421 
1422  /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */
1423  assert(db != NULL);
1424  if ((dbiflags & DB_WRITECURSOR) &&
1425  (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
1426  {
1427  flags = DB_WRITECURSOR;
1428  } else
1429  flags = 0;
1430 
1431  rc = db->cursor(db, txnid, &dbcursor, flags);
1432  rc = cvtdberr(dbi, "db->cursor", rc, _debug);
1433 
1434  if (dbcp)
1435  *dbcp = dbcursor;
1436  else
1437  (void) db3cclose(dbi, dbcursor, 0);
1438 
1439 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) dbc %p %s rc %d\n", __FUNCTION__, dbi, txnid, dbcp, dbiflags, dbcursor, _DBCOFLAGS(flags), rc));
1440  return rc;
1441 }
1442 
1443 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1444  /*@unused@*/ unsigned int flags)
1445  /*@globals fileSystem @*/
1446  /*@modifies fileSystem @*/
1447 {
1448  DB * db = (DB *) dbi->dbi_db;
1449  DB_TXN * _txnid = dbiTxnid(dbi);
1450  int rc;
1451 
1452  assert(db != NULL);
1453  if (dbcursor == NULL) {
1454 flags = 0;
1455  rc = db->put(db, _txnid, key, data, flags);
1456  rc = cvtdberr(dbi, "db->put", rc, _debug);
1457  } else {
1458 flags = DB_KEYLAST;
1459 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1460  rc = dbcursor->put(dbcursor, key, data, flags);
1461  rc = cvtdberr(dbi, "dbcursor->put", rc, _debug);
1462 #else
1463  rc = dbcursor->c_put(dbcursor, key, data, flags);
1464  rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
1465 #endif
1466  }
1467 
1468 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
1469  return rc;
1470 }
1471 
1472 /*@-mustmod@*/
1473 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1474  unsigned int flags)
1475  /*@globals fileSystem @*/
1476  /*@modifies *dbcursor, *key, *data, fileSystem @*/
1477 {
1478  DB * db = (DB *) dbi->dbi_db;
1479  DB_TXN * _txnid = dbiTxnid(dbi);
1480  int _printit;
1481  int rc;
1482 
1483 assert(db != NULL);
1484  if (dbcursor == NULL) {
1485  /* XXX duplicates require cursors. */
1486  rc = db->get(db, _txnid, key, data, flags);
1487  /* XXX DB_NOTFOUND can be returned */
1488  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1489  rc = cvtdberr(dbi, "db->get", rc, _printit);
1490  } else {
1491 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1492  /* XXX db3 does DB_FIRST on uninitialized cursor */
1493  rc = dbcursor->get(dbcursor, key, data, flags);
1494  /* XXX DB_NOTFOUND can be returned */
1495  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1496  /* XXX Permit DB_BUFFER_SMALL to be returned (more restrictive?) */
1497  _printit = (rc == DB_BUFFER_SMALL ? 0 : _printit);
1498  rc = cvtdberr(dbi, "dbcursor->get", rc, _printit);
1499 #else
1500  /* XXX db3 does DB_FIRST on uninitialized cursor */
1501  rc = dbcursor->c_get(dbcursor, key, data, flags);
1502  /* XXX DB_NOTFOUND can be returned */
1503  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1504  rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
1505 #endif
1506  }
1507 
1508 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
1509  return rc;
1510 }
1511 /*@=mustmod@*/
1512 
1513 /*@-mustmod@*/
1514 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
1515  DBT * data, unsigned int flags)
1516  /*@globals fileSystem @*/
1517  /*@modifies *dbcursor, *key, *data, fileSystem @*/
1518 {
1519  DB * db = (DB *) dbi->dbi_db;
1520  DB_TXN * _txnid = dbiTxnid(dbi);
1521  int _printit;
1522  int rc;
1523 
1524 assert(db != NULL);
1525  if (dbcursor == NULL) {
1526  /* XXX duplicates require cursors. */
1527  rc = db->pget(db, _txnid, key, pkey, data, flags);
1528  /* XXX DB_NOTFOUND can be returned */
1529  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1530  rc = cvtdberr(dbi, "db->pget", rc, _printit);
1531  } else {
1532 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1533  /* XXX db3 does DB_FIRST on uninitialized cursor */
1534  rc = dbcursor->pget(dbcursor, key, pkey, data, flags);
1535  /* XXX DB_NOTFOUND can be returned */
1536  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1537  rc = cvtdberr(dbi, "dbcursor->pget", rc, _printit);
1538 #else
1539  /* XXX db3 does DB_FIRST on uninitialized cursor */
1540  rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
1541  /* XXX DB_NOTFOUND can be returned */
1542  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
1543  rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
1544 #endif
1545  }
1546 
1547 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, pkey, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, pkey, data, NULL)));
1548  return rc;
1549 }
1550 /*@=mustmod@*/
1551 
1552 /*@-mustmod@*/
1553 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
1554  unsigned int flags)
1555  /*@globals fileSystem @*/
1556  /*@modifies *dbcursor, fileSystem @*/
1557 {
1558  DB * db = (DB *) dbi->dbi_db;
1559  DB_TXN * _txnid = dbiTxnid(dbi);
1560  int rc;
1561 
1562 assert(db != NULL);
1563  if (dbcursor == NULL) {
1564  rc = db->del(db, _txnid, key, flags);
1565  rc = cvtdberr(dbi, "db->del", rc, _debug);
1566  } else {
1567 
1568  /* XXX TODO: insure that cursor is positioned with duplicates */
1569  rc = db3cget(dbi, dbcursor, key, data, DB_SET);
1570 
1571  if (rc == 0) {
1572 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1573  rc = dbcursor->del(dbcursor, flags);
1574  rc = cvtdberr(dbi, "dbcursor->del", rc, _debug);
1575 #else
1576  rc = dbcursor->c_del(dbcursor, flags);
1577  rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
1578 #endif
1579  }
1580  }
1581 
1582 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL)));
1583  return rc;
1584 }
1585 /*@=mustmod@*/
1586 
1587 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
1588  /*@null@*/ /*@out@*/ unsigned int * countp,
1589  /*@unused@*/ unsigned int flags)
1590  /*@globals fileSystem @*/
1591  /*@modifies *countp, fileSystem @*/
1592 {
1593  db_recno_t count = 0;
1594  int rc = 0;
1595 
1596  flags = 0;
1597 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR >= 5)
1598  rc = dbcursor->count(dbcursor, &count, flags);
1599  rc = cvtdberr(dbi, "dbcursor->count", rc, _debug);
1600 #else
1601  rc = dbcursor->c_count(dbcursor, &count, flags);
1602  rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
1603 #endif
1604  if (countp) *countp = (!rc ? count : 0);
1605 
1606 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) count %d\n", __FUNCTION__, dbi, dbcursor, countp, flags, count));
1607 
1608  return rc;
1609 }
1610 
1611 static int db3byteswapped(dbiIndex dbi) /*@*/
1612 {
1613  DB * db = (DB *) dbi->dbi_db;
1614  int rc = 0;
1615 
1616  if (db != NULL) {
1617  int isswapped = 0;
1618  rc = db->get_byteswapped(db, &isswapped);
1619  if (rc == 0)
1620  rc = isswapped;
1621  }
1622 
1623  return rc;
1624 }
1625 
1626 static int db3stat(dbiIndex dbi, unsigned int flags)
1627  /*@globals fileSystem @*/
1628  /*@modifies dbi, fileSystem @*/
1629 {
1630  DB * db = (DB *) dbi->dbi_db;
1631 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR >= 5)
1632  DB_TXN * _txnid = dbiTxnid(dbi);
1633 #endif
1634  int rc = 0;
1635 
1636  assert(db != NULL);
1637 #if defined(DB_FAST_STAT)
1638  if (flags)
1639  flags = DB_FAST_STAT;
1640  else
1641 #endif
1642  flags = 0;
1643  dbi->dbi_stats = _free(dbi->dbi_stats);
1644 /* XXX 3.3.4 change. */
1645 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR >= 5)
1646  rc = db->stat(db, _txnid, &dbi->dbi_stats, flags);
1647 #else
1648  rc = db->stat(db, &dbi->dbi_stats, flags);
1649 #endif
1650  rc = cvtdberr(dbi, "db->stat", rc, _debug);
1651 
1652 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
1653 
1654  return rc;
1655 }
1656 
1657 /*@-mustmod@*/
1658 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
1659  int (*callback)(DB *, const DBT *, const DBT *, DBT *),
1660  unsigned int flags)
1661  /*@globals fileSystem @*/
1662  /*@modifies dbi, fileSystem @*/
1663 {
1664  DB * db = (DB *) dbi->dbi_db;
1665  DB * secondary = (DB *) dbisecondary->dbi_db;
1666  DB_TXN * _txnid = dbiTxnid(dbi);
1667  int rc;
1668 
1669 assert(db != NULL);
1670 
1671 /*@-moduncon@*/ /* FIX: annotate db3 methods */
1672  rc = db->associate(db, _txnid, secondary, callback, flags);
1673 /*@=moduncon@*/
1674  rc = cvtdberr(dbi, "db->associate", rc, _debug);
1675 
1676  if (dbi->dbi_debug || dbisecondary->dbi_debug) {
1677  const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag));
1678 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, (void *)callback, flags, rc, _AFLAGS(flags));
1679  tag2 = _free(tag2);
1680  }
1681 
1682  return rc;
1683 }
1684 /*@=mustmod@*/
1685 
1686 /*@-mustmod@*/
1687 static int db3associate_foreign(dbiIndex dbi, dbiIndex dbisecondary,
1688  int (*callback)(DB *, const DBT *, DBT *, const DBT *, int *),
1689  unsigned int flags)
1690  /*@globals fileSystem @*/
1691  /*@modifies dbi, fileSystem @*/
1692 {
1693  int rc = ENOTSUP;;
1694 
1695 #if !defined(__LCLINT__)
1696 /*@-moduncon@*/ /* FIX: annotate db3 methods */
1697 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR >= 5)
1698  DB * db = (DB *) dbi->dbi_db;
1699  DB * secondary = (DB *) dbisecondary->dbi_db;
1700 assert(db != NULL);
1701  rc = db->associate_foreign(db, secondary, callback, flags);
1702 #endif
1703 /*@=moduncon@*/
1704 #endif /* !defined(__LCLINT__) */
1705  rc = cvtdberr(dbi, "db->associate_foreign", rc, _debug);
1706 
1707  if (dbi->dbi_debug || dbisecondary->dbi_debug) {
1708  const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag));
1709 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, callback, flags, rc, _AFFLAGS(flags));
1710  tag2 = _free(tag2);
1711  }
1712 
1713  return rc;
1714 }
1715 /*@=mustmod@*/
1716 
1717 /*@-mustmod@*/
1718 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
1719  unsigned int flags)
1720  /*@globals fileSystem @*/
1721  /*@modifies dbi, fileSystem @*/
1722 {
1723  DB * db = (DB *) dbi->dbi_db;
1724  int rc;
1725 
1726 DBIDEBUG(dbi, (stderr, "--> %s(%p,%p,%p,0x%x)\n", __FUNCTION__, dbi, curslist, dbcp, flags));
1727 assert(db != NULL);
1728 /*@-moduncon@*/ /* FIX: annotate db3 methods */
1729  rc = db->join(db, curslist, dbcp, flags);
1730 /*@=moduncon@*/
1731  rc = cvtdberr(dbi, "db->join", rc, _debug);
1732  return rc;
1733 }
1734 /*@=mustmod@*/
1735 
1736 /*@-moduncon@*/ /* FIX: annotate db3 methods */
1737 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
1738  /*@globals rpmGlobalMacroContext, h_errno,
1739  fileSystem, internalState @*/
1740  /*@modifies dbi, fileSystem, internalState @*/
1741 {
1742  rpmdb rpmdb = dbi->dbi_rpmdb;
1743  const char * urlfn = NULL;
1744  const char * root;
1745  const char * home;
1746  const char * dbhome;
1747  const char * dbfile;
1748  const char * dbsubfile;
1749  DB * db = (DB *) dbi->dbi_db;
1750  DB_SEQUENCE * seq = (DB_SEQUENCE *) dbi->dbi_seq;
1751  const char * dbiBN = mapTagName(rpmdb, dbi);
1752  int _printit;
1753  int rc = 0, xx;
1754 
1755  flags = 0; /* XXX unused */
1756 
1757  /*
1758  * Get the prefix/root component and directory path.
1759  */
1760  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
1761  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
1762  root = NULL;
1763  home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
1764 
1765  /*
1766  * Either the root or directory components may be a URL. Concatenate,
1767  * convert the URL to a path, and add the name of the file.
1768  */
1769  /*@-mods@*/
1770  urlfn = rpmGenPath(root, home, NULL);
1771  /*@=mods@*/
1772  (void) urlPath(urlfn, &dbhome);
1773  if (dbi->dbi_temporary) {
1774  dbfile = NULL;
1775  dbsubfile = NULL;
1776  } else {
1777 #ifdef HACK /* XXX necessary to support dbsubfile */
1778  dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
1779  dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN);
1780 #else
1781  dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN);
1782  dbsubfile = NULL;
1783 #endif
1784  }
1785 
1786  if (seq) {
1787  rc = seq->close(seq, 0);
1788  rc = cvtdberr(dbi, "seq->close", rc, _debug);
1789  seq = dbi->dbi_seq = NULL;
1790 
1791  rpmlog(RPMLOG_DEBUG, D_("closed db seqno %s/%s\n"),
1792  dbhome, (dbfile ? dbfile : dbiBN));
1793 
1794  }
1795  if (db) {
1796  rc = db->close(db, 0);
1797  /* XXX ignore not found error messages. */
1798  _printit = (rc == ENOENT ? 0 : _debug);
1799  rc = cvtdberr(dbi, "db->close", rc, _printit);
1800  db = dbi->dbi_db = NULL;
1801 
1802  rpmlog(RPMLOG_DEBUG, D_("closed db index %s/%s\n"),
1803  dbhome, (dbfile ? dbfile : dbiBN));
1804 
1805  }
1806 
1807  /* XXX avoid non-root EPERM ACID PANIC with temp Depcache close. */
1808  if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv && !dbi->dbi_temporary) {
1809  if (rpmdb->db_opens == 1) {
1810  /*@-nullstate@*/
1811  xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
1812  /*@=nullstate@*/
1813  rpmdb->db_dbenv = NULL;
1814  }
1815  rpmdb->db_opens--;
1816  }
1817 
1818 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc));
1819 
1820  dbi->dbi_db = NULL;
1821 
1822  urlfn = _free(urlfn);
1823 
1824  dbi = db3Free(dbi);
1825 
1826  return rc;
1827 }
1828 /*@=moduncon@*/
1829 
1835 static inline unsigned char nibble(char c)
1836  /*@*/
1837 {
1838  if (c >= '0' && c <= '9')
1839  return (unsigned char)(c - '0');
1840  if (c >= 'A' && c <= 'F')
1841  return (unsigned char)((int)(c - 'A') + 10);
1842  if (c >= 'a' && c <= 'f')
1843  return (unsigned char)((int)(c - 'a') + 10);
1844  return '\0';
1845 }
1846 
1847 static int loadDBT(DBT * _r, rpmTag tag, const void * _s, size_t ns)
1848  /*@modifies *_r @*/
1849 {
1850  const char * s = _s;
1851  void * data = NULL;
1852  size_t size = 0;
1853  uint8_t * t = NULL;
1854  uint32_t i;
1855  int xx;
1856 
1857  if (ns == 0) ns = strlen(s);
1858  switch (tag) {
1859  case RPMTAG_FILEDIGESTS:
1860  /* Convert hex to binary, filter out odd hex strings. */
1861  if (ns > 0 && !(ns & 1)) {
1862  ns /= 2;
1863  data = t = xmalloc(ns);
1864  for (i = 0; i < ns; i++, t++, s += 2) {
1865  if (!(isxdigit(s[0]) && isxdigit(s[1])))
1866  /*@loopbreak@*/ break;
1867  *t = (uint8_t) (nibble(s[0]) << 4) | nibble(s[1]);
1868  }
1869  if (i == ns)
1870  size = ns;
1871  else
1872  data = _free(data);
1873  }
1874  break;
1875  case RPMTAG_PUBKEYS:
1876  /* Extract pubkey id from the base64 blob. */
1877  t = xmalloc(32);
1878  if ((xx = pgpExtractPubkeyFingerprint(s, t)) > 0) {
1879  data = t;
1880  size = xx;
1881  } else
1882  t = _free(t);
1883  break;
1884  default:
1885  data = (void *) memcpy(xmalloc(ns), _s, ns);
1886  size = ns;
1887  break;
1888  }
1889  if ((_r->data = data) != NULL) _r->flags |= DB_DBT_APPMALLOC;
1890  return (_r->size = size);
1891 }
1892 
1893 static int uint32Cmp(const void * _a, const void * _b)
1894  /*@*/
1895 {
1896  const uint32_t * a = _a;
1897  const uint32_t * b = _b;
1898  return ((*a < *b) ? -1 :
1899  ((*a > *b) ? 1 : 0));
1900 }
1901 
1902 static int uint64Cmp(const void * _a, const void * _b)
1903  /*@*/
1904 {
1905  const uint64_t * a = _a;
1906  const uint64_t * b = _b;
1907  return ((*a < *b) ? -1 :
1908  ((*a > *b) ? 1 : 0));
1909 }
1910 
1911 static int
1912 db3Acallback(DB * db, const DBT * key, const DBT * data, DBT * _r)
1913  /*@globals internalState @*/
1914  /*@modifies *_r, internalState @*/
1915 {
1916  HE_t he = (HE_t) memset(alloca(sizeof(*he)), 0, sizeof(*he));
1917  HE_t Fhe = (HE_t) memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe));
1918 #ifdef NOTYET
1919  HE_t FMhe = (HE_t) memset(alloca(sizeof(*FMhe)), 0, sizeof(*FMhe));
1920 #endif
1921  dbiIndex dbi = db->app_private;
1922  rpmdb rpmdb = NULL;
1923  Header h = NULL;
1924  uint32_t hdrNum;
1925  DBT * A = NULL;
1926  const char * s = NULL;
1927  size_t ns = 0;
1928  int rc = DB_DONOTINDEX; /* assume no-op */
1929  uint32_t i;
1930  int xx;
1931 
1932 assert(key->size == sizeof(hdrNum));
1933  memcpy(&hdrNum, key->data, key->size);
1934  hdrNum = _ntoh_ui(hdrNum);
1935 
1936  /* XXX Don't index the header instance counter at record 0. */
1937  if (hdrNum == 0)
1938  goto exit;
1939 
1940 assert(dbi);
1941  rpmdb = dbi->dbi_rpmdb;
1942 assert(rpmdb);
1943 
1944  /* XXX Track the maximum primary key value. */
1945  if (hdrNum > rpmdb->db_maxkey)
1946  rpmdb->db_maxkey = hdrNum;
1947 
1948  h = headerLink(rpmdb->db_h);
1949  if (h == NULL) {
1950  /* XXX needs PROT_READ somewhen. */
1951  h = headerLoad(data->data);
1952  if (h == NULL) {
1954  _("db3: header #%u cannot be loaded -- skipping.\n"),
1955  (unsigned)hdrNum);
1956  goto exit;
1957  }
1958  }
1959 
1960  memset(_r, 0, sizeof(*_r));
1961 
1962  he->tag = dbi->dbi_rpmtag;
1963  if (!headerGet(h, he, 0))
1964  goto exit;
1965 
1966  /* XXX catch busted headerGet() rc on RPMTAG_FILEPATHS w empty list. */
1967 assert(he->p.ptr != NULL && he->c > 0);
1968 
1969  /* Retrieve other tags needed for filtering decisions. */
1970  switch (he->tag) {
1971  default:
1972  break;
1973 #ifdef NOTYET
1974  case RPMTAG_BASENAMES:
1975  case RPMTAG_FILEPATHS:
1976  /* XXX Add the pesky trailing '/' to directories. */
1977  FMhe->tag = RPMTAG_FILEMODES;
1978  (void) headerGet(h, FMhe, 0);
1979  break;
1980 #endif
1982  case RPMTAG_REQUIRENAME:
1983  /* The Requires: F is needed to filter install context dependencies. */
1984  Fhe->tag = RPMTAG_REQUIREFLAGS;
1985  (void) headerGet(h, Fhe, 0);
1986  break;
1987  }
1988 
1989  switch (he->t) {
1990  default:
1991 assert(0);
1992  /*@notreached@*/ break;
1993  case RPM_UINT8_TYPE: /* XXX coerce to uint32_t */
1994  { uint8_t * _u = (uint8_t *) he->p.ui8p;
1995  he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p));
1996  for (i = 0; i < he->c; i++)
1997  he->p.ui32p[i] = _u[i];
1998  _u = _free(_u);
1999  goto _ifill;
2000  } /*@notreached@*/ break;
2001  case RPM_UINT16_TYPE: /* XXX coerce to uint32_t */
2002  { uint16_t * _u = (uint16_t *) he->p.ui16p;
2003  he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p));
2004  for (i = 0; i < he->c; i++)
2005  he->p.ui32p[i] = _u[i];
2006  _u = _free(_u);
2007  goto _ifill;
2008  } /*@notreached@*/ break;
2009  case RPM_UINT32_TYPE:
2010 _ifill:
2011  { uint32_t * _u = (uint32_t *) he->p.ui32p;
2012  size_t _ulen = sizeof(*_u);
2013  uint32_t _ube; /* XXX network order integer keys */
2014 
2015  /* Drop the transaction id usecs field (if present) when indexing. */
2016  switch (he->tag) {
2017  case RPMTAG_INSTALLTID:
2018  case RPMTAG_REMOVETID:
2019  he->c = 1;
2020  /*@innerbreak@*/ break;
2021  default:
2022  /*@innerbreak@*/ break;
2023  }
2024  if (he->c == 1) {
2025  _ube = _hton_ui(*_u); /* XXX network order integer keys */
2026  /* XXX is it worth avoiding the realloc here? */
2027  xx = loadDBT(_r, he->tag, &_ube, _ulen);
2028  break;
2029  }
2031  _r->data = A = xcalloc(he->c, sizeof(*A));
2032  _r->size = 0;
2033  if (he->c > 1)
2034  qsort(_u, he->c, _ulen, uint32Cmp);
2035  for (i = 0; i < he->c; i++, _u++) {
2036  /* Don't add identical (key,val) item to secondary. */
2037  if (i > 0 && _u[-1] == _u[0])
2038  continue;
2039  _ube = _hton_ui(*_u); /* XXX network order integer keys */
2040  if (!loadDBT(A, he->tag, &_ube, _ulen))
2041  continue;
2042  A++;
2043  _r->size++;
2044  }
2045  } break;
2046  case RPM_UINT64_TYPE:
2047  { uint64_t * _u = (uint64_t *) he->p.ui64p;
2048  size_t _ulen = sizeof(*_u);
2049  uint64_t _ube; /* XXX network order integer keys */
2050 
2051  if (he->c == 1) {
2052  _ube = _hton_ul(*_u); /* XXX network order integer keys */
2053  /* XXX is it worth avoiding the realloc here? */
2054  xx = loadDBT(_r, he->tag, _u, _ulen);
2055  break;
2056  }
2058  _r->data = A = (DBT *) xcalloc(he->c, sizeof(*A));
2059  _r->size = 0;
2060  if (he->c > 1)
2061  qsort(_u, he->c, _ulen, uint64Cmp);
2062  for (i = 0; i < he->c; i++, _u++) {
2063  /* Don't add identical (key,val) item to secondary. */
2064  if (i > 0 && _u[-1] == _u[0])
2065  continue;
2066  _ube = _hton_ul(*_u); /* XXX network order integer keys */
2067  if (!loadDBT(A, he->tag, &_ube, _ulen))
2068  continue;
2069  A++;
2070  _r->size++;
2071  }
2072  } break;
2073  case RPM_BIN_TYPE:
2074  s = (char *) he->p.ptr; ns = he->c;
2075  /* XXX is it worth avoiding the realloc here? */
2076  if (ns > 0) /* No "" empty keys please. */
2077  xx = loadDBT(_r, he->tag, s, ns);
2078  break;
2079  case RPM_I18NSTRING_TYPE: /* XXX never occurs */
2080  case RPM_STRING_TYPE:
2081  s = he->p.str; ns = strlen(s);
2082  /* XXX is it worth avoiding the realloc here? */
2083  if (ns > 0) /* No "" empty keys please. */
2084  xx = loadDBT(_r, he->tag, s, ns);
2085  break;
2086  case RPM_STRING_ARRAY_TYPE:
2087  if (he->c == 1) {
2088  s = he->p.argv[0]; ns = strlen(s);
2089  if (ns > 0) /* No "" empty keys please. */
2090  xx = loadDBT(_r, he->tag, s, ns);
2091  } else {
2092  static double e = 1.0e-5;
2093  static size_t nmin = 16;
2094  size_t n = 2 * (he->c > nmin ? he->c : nmin);
2095  size_t m = 0;
2096  size_t k = 0;
2097  rpmbf bf;
2098  rpmbfParams(n, e, &m, &k);
2099  bf = rpmbfNew(m, k, 0);
2100 
2102  _r->data = A = (DBT *) xcalloc(he->c, sizeof(*A));
2103  _r->size = 0;
2104  for (i = 0; i < he->c; i++) {
2105  s = he->p.argv[i]; ns = strlen(s);
2106 
2107  /* XXX Skip YAML "- ..." lead-in mark up if present. */
2108  if (s[0] == '-' && s[1] == ' ') {
2109  s += 2, ns -= 2;
2110  }
2111 
2112 #ifdef NOTYET
2113  /* Add the pesky trailing '/' to directories. */
2114  if (FMhe->p.ui16p && !S_ISREG((mode_t)FMhe->p.ui16p[i])) {
2115  continue;
2116  }
2117 #endif
2118 
2119  if (ns == 0) /* No "" empty keys please. */
2120  continue;
2121 
2122  /* Filter install context dependencies. */
2123  if (Fhe->p.ui32p && isInstallPreReq(Fhe->p.ui32p[i]))
2124  continue;
2125 
2126  /* Don't add identical (key,val) item to secondary. */
2127  if (rpmbfChk(bf, s, ns) > 0)
2128  continue;
2129  xx = rpmbfAdd(bf, s, ns);
2130 assert(xx == 0);
2131 
2132  if (!loadDBT(A, he->tag, s, ns))
2133  continue;
2134  A++;
2135  _r->size++;
2136  }
2137  bf = rpmbfFree(bf);
2138  }
2139  break;
2140  }
2141  if (_r->data && _r->size > 0)
2142  rc = 0;
2143  else if (_r->flags & DB_DBT_APPMALLOC) {
2144  _r->data = _free(_r->data);
2145  memset(_r, 0, sizeof(*_r));
2146  }
2147 
2148 exit:
2149  if (!dbi->dbi_no_dbsync && rc != DB_DONOTINDEX)
2150  xx = dbiSync(dbi, 0);
2151 #ifdef NOTYET
2152  FMhe->p.ptr = _free(FMhe->p.ptr);
2153 #endif
2154  Fhe->p.ptr = _free(Fhe->p.ptr);
2155  he->p.ptr = _free(he->p.ptr);
2156  h = headerFree(h);
2157 
2158 DBIDEBUG(dbi, (stderr, "<-- %s(%p, %p, %p, %p) rc %d\n\tdbi %p(%s) rpmdb %p h %p %s\n", __FUNCTION__, db, key, data, _r, rc, dbi, tagName(dbi->dbi_rpmtag), rpmdb, h, _KEYDATA(key, NULL, data, _r)));
2159 
2160  return rc;
2161 }
2162 
2163 static int seqid_init(dbiIndex dbi, const char * keyp, size_t keylen,
2164  DB_SEQUENCE ** seqp)
2165  /*@modifies *seqp @*/
2166 {
2167  DB * db = (DB *) dbi->dbi_db;
2168  DBT k = {0};
2169  DB_TXN * _txnid = dbiTxnid(dbi);
2170  DB_SEQUENCE * seq = NULL;
2171  db_seq_t _rangemin = -922337203685477600LL;
2172  db_seq_t _rangemax = 922337203685477600LL;
2173  db_seq_t _value = 0;
2174  int32_t _cachesize = 0;
2175  uint32_t _flags = DB_SEQ_INC;
2176  uint32_t _oflags = DB_CREATE;
2177  int rc;
2178 
2179 assert(db != NULL);
2180  if (seqp) *seqp = NULL;
2181 
2182 /*@-moduncon@*/
2183  rc = db_sequence_create(&seq, db, 0);
2184 /*@=moduncon@*/
2185  rc = cvtdberr(dbi, "db_sequence_create", rc, _debug);
2186  if (rc) goto exit;
2187 assert(seq != NULL);
2188 
2189  if (dbi->dbi_seq_cachesize) {
2190  _cachesize = dbi->dbi_seq_cachesize;
2191  rc = seq->set_cachesize(seq, _cachesize);
2192  rc = cvtdberr(dbi, "seq->set_cachesize", rc, _debug);
2193  if (rc) goto exit;
2194  }
2195 
2196  if (dbi->dbi_seq_initial)
2197  _value = dbi->dbi_seq_initial;
2198  if (_value <= 0) _value = 1;
2199  rc = seq->initial_value(seq, _value);
2200  rc = cvtdberr(dbi, "seq->initial_value", rc, _debug);
2201  if (rc) goto exit;
2202 
2203  if (dbi->dbi_seq_min)
2204  _rangemin = dbi->dbi_seq_min;
2205  if (dbi->dbi_seq_max)
2206  _rangemax = dbi->dbi_seq_max;
2207  rc = seq->set_range(seq, _rangemin, _rangemax);
2208  rc = cvtdberr(dbi, "seq->set_range", rc, _debug);
2209  if (rc) goto exit;
2210 
2211  if (dbi->dbi_seq_flags)
2212  _flags = dbi->dbi_seq_flags;
2213  rc = seq->set_flags(seq, _flags);
2214  rc = cvtdberr(dbi, "seq->set_flags", rc, _debug);
2215  if (rc) goto exit;
2216 
2217  k.data = (void *)keyp;
2218  k.size = (u_int32_t) (keylen > 0 ? keylen : strlen(keyp));
2219  rc = seq->open(seq, _txnid, &k, _oflags);
2220  rc = cvtdberr(dbi, "seq->open", rc, _debug);
2221  if (rc) goto exit;
2222 
2223 exit:
2224  if (rc == 0 && seqp != NULL)
2225  *seqp = seq;
2226  else {
2227  int xx = seq->close(seq, 0);
2228  xx = cvtdberr(dbi, "seq->close", xx, _debug);
2229  }
2230 
2231 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p[%u],%p) seq %p rc %d %s\n", __FUNCTION__, dbi, keyp, (unsigned)keylen, seqp, (seqp ? *seqp : NULL), rc, _KEYDATA(&k, NULL, NULL, NULL)));
2232 
2233  return rc;
2234 }
2235 
2243 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
2244  /*@globals rpmGlobalMacroContext, h_errno,
2245  fileSystem, internalState @*/
2246  /*@modifies *dbip, fileSystem, internalState @*/
2247 {
2248  /*@-nestedextern -shadow@*/
2249  extern struct _dbiVec db3vec;
2250  /*@=nestedextern =shadow@*/
2251  const char * urlfn = NULL;
2252  const char * root;
2253  const char * home;
2254  const char * dbhome;
2255  const char * dbfile;
2256  const char * dbsubfile;
2257  const char * dbiBN;
2258  dbiIndex dbi = NULL;
2259  int rc = 0;
2260  int xx;
2261 
2262  DB * db = NULL;
2263  DB_ENV * dbenv = NULL;
2264  DB_TXN * _txnid = NULL;
2265  DBTYPE dbi_type = DB_UNKNOWN;
2266  rpmuint32_t oflags;
2267  int _printit;
2268 
2269  if (dbip)
2270  *dbip = NULL;
2271 
2272  /*
2273  * Parse db configuration parameters.
2274  */
2275  /*@-mods@*/
2276  if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
2277  /*@-nullstate@*/
2278  return 1;
2279  /*@=nullstate@*/
2280  /*@=mods@*/
2281  dbi->dbi_api = DB_VERSION_MAJOR;
2282  dbiBN = mapTagName(rpmdb, dbi);
2283  dbi->dbi_txnid = NULL;
2284  _txnid = NULL;
2285 
2286  /*
2287  * Get the prefix/root component and directory path.
2288  */
2289  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
2290  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
2291  root = NULL;
2292  home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
2293 
2294  /*
2295  * Either the root or directory components may be a URL. Concatenate,
2296  * convert the URL to a path, and add the name of the file.
2297  */
2298  /*@-mods@*/
2299  urlfn = rpmGenPath(root, home, NULL);
2300  /*@=mods@*/
2301  (void) urlPath(urlfn, &dbhome);
2302  if (dbi->dbi_temporary) {
2303  dbfile = NULL;
2304  dbsubfile = NULL;
2305  } else {
2306 #ifdef HACK /* XXX necessary to support dbsubfile */
2307  dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
2308  dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN);
2309 #else
2310  dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN);
2311  dbsubfile = NULL;
2312 #endif
2313  }
2314 
2315  oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
2316  /* XXX permit DB_TRUNCATE iff a secondary index. */
2317  if (dbi->dbi_primary) oflags &= ~DB_TRUNCATE;
2318 
2319 #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */
2320  if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
2321 #endif
2322 
2323  /*
2324  * Map open mode flags onto configured database/environment flags.
2325  */
2326  if (dbi->dbi_temporary) {
2327  oflags |= DB_CREATE;
2328  dbi->dbi_oeflags |= DB_CREATE;
2329  oflags &= ~DB_RDONLY;
2330  dbi->dbi_oflags &= ~DB_RDONLY;
2331  } else {
2332  if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
2333  if (dbi->dbi_mode & O_CREAT) {
2334  oflags |= DB_CREATE;
2335  dbi->dbi_oeflags |= DB_CREATE;
2336  }
2337  /* XXX permit DB_TRUNCATE iff a secondary index. */
2338  if (dbi->dbi_primary && (dbi->dbi_mode & O_TRUNC))
2339  oflags |= DB_TRUNCATE;
2340  }
2341 
2342  /*
2343  * Create the /var/lib/rpm directory if it doesn't exist (root only).
2344  */
2345  (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
2346 
2347  /*
2348  * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
2349  */
2350  if (dbi->dbi_use_dbenv) {
2351 
2352  if (access(dbhome, W_OK) == -1) {
2353 
2354  /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
2355  oflags &= ~DB_CREATE;
2356  oflags &= ~DB_AUTO_COMMIT;
2357 
2358  /* ... but DBENV->open might still need DB_CREATE ... */
2359  if (dbi->dbi_eflags & DB_PRIVATE) {
2360  dbi->dbi_eflags &= ~DB_JOINENV;
2361  } else {
2362  dbi->dbi_eflags |= DB_JOINENV;
2363  dbi->dbi_oeflags &= ~DB_CREATE;
2364 #ifdef DYING
2365  dbi->dbi_oeflags &= ~DB_THREAD;
2366 #endif
2367  /* ... but, unless DB_PRIVATE is used, skip DBENV. */
2368  dbi->dbi_use_dbenv = 0;
2369  }
2370 
2371  /* ... DB_RDONLY maps dbhome perms across files ... */
2372  if (dbi->dbi_temporary) {
2373  oflags |= DB_CREATE;
2374  dbi->dbi_oeflags |= DB_CREATE;
2375  oflags &= ~DB_RDONLY;
2376  dbi->dbi_oflags &= ~DB_RDONLY;
2377  } else {
2378  oflags |= DB_RDONLY;
2379  /* ... and DB_WRITECURSOR won't be needed ... */
2380  dbi->dbi_oflags |= DB_RDONLY;
2381  }
2382 
2383  } else { /* dbhome is writable, check for persistent dbenv. */
2384  /*@-mods@*/
2385  const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
2386  /*@=mods@*/
2387 
2388 #if defined(RPM_VENDOR_OPENPKG) /* bdb-allow-zero-sized-files */
2389  /* Make sure RPM passes DB_CREATE to Berkeley-DB also
2390  if file exists, but is (still) zero-sized. */
2391  struct stat sb;
2392  long size = -1;
2393  if (stat(dbf, &sb) == 0)
2394  size = (long)sb.st_size;
2395  if (access(dbf, F_OK) == -1 || size == 0)
2396 #else
2397  if (access(dbf, F_OK) == -1)
2398 #endif
2399  {
2400  /* ... non-existent (or unwritable) DBENV, will create ... */
2401  dbi->dbi_oeflags |= DB_CREATE;
2402  dbi->dbi_eflags &= ~DB_JOINENV;
2403  } else {
2404  /* ... pre-existent (or bogus) DBENV, will join ... */
2405  if (dbi->dbi_eflags & DB_PRIVATE) {
2406  dbi->dbi_eflags &= ~DB_JOINENV;
2407  } else {
2408  dbi->dbi_eflags |= DB_JOINENV;
2409  dbi->dbi_oeflags &= ~DB_CREATE;
2410 #ifdef DYING
2411  dbi->dbi_oeflags &= ~DB_THREAD;
2412 #endif
2413  }
2414  }
2415  /* ... transactionally protected open's need DB_AUTO_COMMIT ... */
2416  if (rpmdb->_dbi[0]
2417  && rpmdb->_dbi[0]->dbi_eflags & DB_INIT_TXN)
2418  oflags |= DB_AUTO_COMMIT;
2419  dbf = _free(dbf);
2420  }
2421  }
2422 
2423  /*
2424  * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
2425  */
2426  if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
2427  /* dbhome is writable, and DB->open flags may conflict. */
2428  const char * dbfn = (dbfile ? dbfile : dbiBN);
2429  /*@-mods@*/
2430  const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
2431  /*@=mods@*/
2432 
2433  if (access(dbf, F_OK) == -1) {
2434  /* File does not exist, DB->open might create ... */
2435  oflags &= ~DB_RDONLY;
2436  } else {
2437  /* File exists, DB->open need not create ... */
2438  oflags &= ~DB_CREATE;
2439  }
2440 
2441  /* Only writers need DB_WRITECURSOR ... */
2442  if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
2443  dbi->dbi_oflags &= ~DB_RDONLY;
2444  } else {
2445  dbi->dbi_oflags |= DB_RDONLY;
2446  }
2447  dbf = _free(dbf);
2448  }
2449 
2450  /*
2451  * Set db type if creating or truncating.
2452  */
2453  if (oflags & (DB_CREATE|DB_TRUNCATE))
2454  dbi_type = (DBTYPE) dbi->dbi_type;
2455 
2456  if (dbi->dbi_use_dbenv) {
2457  /*@-mods@*/
2458  if (rpmdb->db_dbenv == NULL) {
2459  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
2460  switch (rc) {
2461  default:
2462  break;
2463  case DB_RUNRECOVERY:
2464  if (getuid() != 0)
2465  break;
2466  rpmlog(RPMLOG_NOTICE, _("Re-opening dbenv with DB_RECOVER ...\n"));
2467  /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */
2468  dbi->dbi_eflags |= DB_RECOVER;
2469  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
2470  dbi->dbi_eflags &= ~DB_RECOVER;
2471  if (rc) {
2472  rpmlog(RPMLOG_NOTICE, _("\nrecovery failed. Exiting ...\n"));
2473  exit(EXIT_FAILURE);
2474  }
2475  rpmlog(RPMLOG_NOTICE, _(".\nrecovery succeeded.\n"));
2476 assert(dbenv);
2477  rpmdb->db_dbenv = dbenv;
2478  rpmdb->db_opens = 1;
2479  break;
2480 
2481 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */
2482  case DB_VERSION_MISMATCH:
2483 #endif
2484  case EINVAL:
2485  if (getuid() != 0)
2486  break;
2487  { char * filename = (char *) alloca(BUFSIZ);
2488  struct stat st;
2489  int i;
2490 
2491  for (i = 0; i < 16; i++) {
2492  sprintf(filename, "%s/__db.%03d", dbhome, i);
2493  (void)rpmCleanPath(filename);
2494  if (Stat(filename, &st)
2495  && (errno == ENOENT || errno == EINVAL))
2496  continue;
2497  xx = Unlink(filename);
2498  }
2499  }
2500  dbi->dbi_oeflags |= DB_CREATE;
2501  dbi->dbi_eflags &= ~DB_JOINENV;
2502  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
2503  /* XXX db_init EINVAL was masked. */
2504  rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
2505  if (rc)
2506  break;
2507  /*@fallthrough@*/
2508  case 0:
2509 assert(dbenv);
2510  rpmdb->db_dbenv = dbenv;
2511  rpmdb->db_opens = 1;
2512  break;
2513  }
2514  } else {
2515 assert(rpmdb && rpmdb->db_dbenv);
2516  dbenv = (DB_ENV *) rpmdb->db_dbenv;
2517  rpmdb->db_opens++;
2518  }
2519  /*@=mods@*/
2520  }
2521 
2522  rpmlog(RPMLOG_DEBUG, D_("opening db index %s/%s %s mode=0x%x\n"),
2523  dbhome, (dbfile ? dbfile : dbiBN),
2524  prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
2525 
2526  if (rc == 0) {
2527  static int _lockdbfd = 0;
2528 
2529  /*@-moduncon@*/ /* FIX: annotate db3 methods */
2530  rc = db_create(&db, dbenv, dbi->dbi_cflags);
2531  /*@=moduncon@*/
2532  rc = cvtdberr(dbi, "db_create", rc, _debug);
2533  if (rc == 0 && db != NULL) {
2534 
2535 /* XXX 3.3.4 change. */
2536  if (rc == 0 &&
2537  rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
2538  {
2539  rc = db->set_alloc(db,
2540  rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
2541  rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
2542  }
2543 
2544 /* 4.1: db->set_cache_priority(???) */
2545 /* 4.1: db->set_encrypt(???) */
2546 
2547 /* 5.3: db->set_lk_exclusive(???) */
2548 
2549  if (rc == 0 && dbi->dbi_lorder) {
2550  rc = db->set_lorder(db, dbi->dbi_lorder);
2551  rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
2552  }
2553  if (rc == 0 && dbi->dbi_pagesize) {
2554  rc = db->set_pagesize(db, dbi->dbi_pagesize);
2555  rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
2556  }
2557  /* 4.1: db->set_paniccall(???) */
2558  if (rc == 0 && oflags & DB_CREATE) {
2559  switch(dbi->dbi_type) {
2560  default:
2561  case DB_HASH:
2562  if (dbi->dbi_h_ffactor) {
2563  rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
2564  rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
2565  if (rc) break;
2566  }
2567  if (dbi->dbi_h_nelem) {
2568  rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
2569  rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
2570  if (rc) break;
2571  }
2572  if (dbi->dbi_h_flags) {
2573  rc = db->set_flags(db, dbi->dbi_h_flags);
2574  rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
2575  if (rc) break;
2576  }
2577  if (dbi->dbi_h_hash_fcn) {
2578  rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
2579  rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
2580  if (rc) break;
2581  }
2582 #if defined(DB_INIT_MUTEX) /* XXX db-6.1.19 breaks "make distcheck" */
2583  if (dbi->dbi_h_dup_compare_fcn) {
2584  rc = db->set_h_compare(db, dbi->dbi_h_dup_compare_fcn);
2585  rc = cvtdberr(dbi, "db->set_h_compare", rc, _debug);
2586  if (rc) break;
2587  }
2588 #endif
2589  break;
2590  case DB_BTREE:
2591 /* 4.1: db->set_append_recno(???) */
2592  if (dbi->dbi_bt_flags) {
2593  rc = db->set_flags(db, dbi->dbi_bt_flags);
2594  rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
2595  if (rc) break;
2596  }
2597  if (dbi->dbi_bt_minkey) {
2598  rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
2599  rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
2600  if (rc) break;
2601  }
2602 #if defined(DB_INIT_MUTEX) /* XXX db-6.1.19 breaks "make distcheck" */
2603  if (dbi->dbi_bt_compare_fcn) {
2604  rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
2605  rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
2606  if (rc) break;
2607  }
2608  if (dbi->dbi_bt_dup_compare_fcn) {
2609  rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
2610  rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
2611  if (rc) break;
2612  }
2613 #endif
2614  if (dbi->dbi_bt_prefix_fcn) {
2615  rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
2616  rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
2617  if (rc) break;
2618  }
2619  break;
2620  case DB_RECNO:
2621 /* 4.1: db->set_append_recno(???) */
2622  if (dbi->dbi_re_delim) {
2623  rc = db->set_re_delim(db, dbi->dbi_re_delim);
2624  rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
2625  if (rc) break;
2626  }
2627  if (dbi->dbi_re_len) {
2628  rc = db->set_re_len(db, dbi->dbi_re_len);
2629  rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
2630  if (rc) break;
2631  }
2632  if (dbi->dbi_re_pad) {
2633  rc = db->set_re_pad(db, dbi->dbi_re_pad);
2634  rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
2635  if (rc) break;
2636  }
2637  if (dbi->dbi_re_source) {
2638  rc = db->set_re_source(db, dbi->dbi_re_source);
2639  rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
2640  if (rc) break;
2641  }
2642  break;
2643  case DB_QUEUE:
2644  if (dbi->dbi_q_extentsize) {
2645  rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
2646  rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
2647  if (rc) break;
2648  }
2649  break;
2650 #if (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR >= 2) || (DB_VERSION_MAJOR >= 6)
2651  case DB_HEAP:
2652  if (dbi->dbi_heapsize) {
2653  static uint32_t _gbytes = 0;
2654  uint32_t _bytes = dbi->dbi_heapsize;
2655  static uint32_t _flags = 0;
2656 assert(dbi->dbi_heapsize >= (3 * dbi->dbi_pagesize));
2657  rc = db->set_heapsize(db, _gbytes, _bytes, _flags);
2658  rc = cvtdberr(dbi, "db->set_heapsize", rc, _debug);
2659  if (rc) break;
2660  }
2661 #if (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR >= 6)
2662  if (dbi->dbi_heap_regionsize) {
2663  uint32_t _npages = dbi->dbi_heap_regionsize;
2664 /* XXX assert (_npages <= "maximum region size for the database's page size");*/
2665  rc = db->set_heap_regionsize(db, _npages);
2666  rc = cvtdberr(dbi, "db->set_heap_regionsize", rc, _debug);
2667  if (rc) break;
2668  }
2669 #endif
2670  break;
2671 #endif
2672  }
2673  }
2674 
2675  if (rc == 0) {
2676  const char * dbfullpath;
2677  const char * dbpath;
2678  char * t;
2679  int nb;
2680 
2681  nb = strlen(dbhome);
2682  if (dbfile) nb += 1 + strlen(dbfile);
2683  dbfullpath = t = (char *) alloca(nb + 1);
2684 
2685  t = stpcpy(t, dbhome);
2686  if (dbfile)
2687  t = stpcpy( stpcpy( t, "/"), dbfile);
2688 #ifdef HACK /* XXX necessary to support dbsubfile */
2689  dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
2690  ? dbfullpath : dbfile;
2691 #else
2692 #ifdef PLD_CHROOT
2693  /* XXX Make dbpath relative. */
2694  dbpath = (!dbi->dbi_use_dbenv)
2695  ? dbfullpath : dbfile;
2696 #else
2697  dbpath = (!dbi->dbi_temporary)
2698  ? dbfullpath : dbfile;
2699 #endif /* PLD_CHROOT */
2700 #endif /* HACK */
2701 
2702  rc = (db->open)(db, _txnid, dbpath, dbsubfile,
2703  dbi_type, oflags, dbi->dbi_perms);
2704 
2705  if (rc == 0 && dbi_type == DB_UNKNOWN) {
2706  xx = db->get_type(db, &dbi_type);
2707  if (xx == 0)
2708  dbi->dbi_type = dbi_type;
2709  }
2710  }
2711 
2712  /* XXX return rc == errno without printing */
2713  _printit = (rc > 0 ? 0 : _debug);
2714  xx = cvtdberr(dbi, "db->open", rc, _printit);
2715 
2716  /*
2717  * Lock a file using fcntl(2). Traditionally this is Packages,
2718  * the file used to store metadata of installed header(s),
2719  * as Packages is always opened, and should be opened first,
2720  * for any rpmdb access.
2721  *
2722  * If no DBENV is used, then access is protected with a
2723  * shared/exclusive locking scheme, as always.
2724  *
2725  * With a DBENV, the fcntl(2) lock is necessary only to keep
2726  * the riff-raff from playing where they don't belong, as
2727  * the DBENV should provide it's own locking scheme. So try to
2728  * acquire a lock, but permit failures, as some other
2729  * DBENV player may already have acquired the lock.
2730  *
2731  * With NPTL posix mutexes, revert to fcntl lock on non-functioning
2732  * glibc/kernel combinations.
2733  */
2734  if (rc == 0 && dbi->dbi_lockdbfd &&
2735 #if defined(DB_RPCCLIENT)
2736  !((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) &&
2737 #endif
2738  (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
2739  {
2740  int fdno = -1;
2741 
2742  if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
2743  rc = 1;
2744  } else {
2745  struct flock l;
2746  memset(&l, 0, sizeof(l));
2747  l.l_whence = 0;
2748  l.l_start = 0;
2749  l.l_len = 0;
2750  l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
2751  ? F_WRLCK : F_RDLCK;
2752  l.l_pid = 0;
2753 
2754  rc = fcntl(fdno, F_SETLK, (void *) &l);
2755  if (rc) {
2756  /* Warning iff using non-private CDB locking. */
2757  rc = ((dbi->dbi_use_dbenv &&
2758  (dbi->dbi_eflags & DB_INIT_CDB) &&
2759  !(dbi->dbi_eflags & DB_PRIVATE))
2760  ? 0 : 1);
2761  rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING),
2762  _("cannot get %s lock on %s/%s\n"),
2763  ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
2764  ? _("exclusive") : _("shared")),
2765  dbhome, (dbfile ? dbfile : ""));
2766  } else if (dbfile) {
2768  D_("locked db index %s/%s\n"),
2769  dbhome, dbfile);
2770  }
2771  }
2772  }
2773  }
2774  }
2775 
2776  dbi->dbi_db = (void *) db;
2777  if (db)
2778  db->app_private = dbi;
2779 
2780 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%p) dbi %p rc %d %s\n", __FUNCTION__, rpmdb, tagName(rpmtag), dbip, dbi, rc, _OFLAGS(dbi->dbi_oflags)));
2781 
2782  if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
2783  dbi->dbi_vec = &db3vec;
2784  *dbip = dbi;
2785  if (dbi->dbi_primary) {
2786  rpmTag Ptag = tagValue(dbi->dbi_primary);
2787  dbiIndex Pdbi = NULL;
2788  int (*_callback)(DB *, const DBT *, const DBT *, DBT *)
2789  = db3Acallback;
2790 #ifdef NOTYET /* XXX KISS for now */
2791  int _flags = DB_IMMUTABLE_KEY;
2792 #else
2793  int _flags = 0;
2794 #endif
2795 assert(Ptag == RPMDBI_PACKAGES && Ptag != rpmtag);
2796  Pdbi = dbiOpen(rpmdb, Ptag, 0);
2797 assert(Pdbi != NULL);
2798  if (oflags & (DB_CREATE|DB_TRUNCATE)) _flags |= DB_CREATE;
2799  xx = db3associate(Pdbi, dbi, _callback, _flags);
2800  }
2801  if (dbi->dbi_seq_id && !(oflags & DB_RDONLY)) {
2802  char * end = NULL;
2803  uint32_t u = (uint32_t) strtoll(dbi->dbi_seq_id, &end, 0);
2804 
2805  /* Reset the Seqno counter to the next primary key */
2806  if (oflags & (DB_CREATE|DB_TRUNCATE))
2807  dbi->dbi_seq_initial = rpmdb->db_maxkey + 1;
2808 
2809  if (*end == '\0')
2810  xx = seqid_init(dbi,(const char *)&u, sizeof(u), (DB_SEQUENCE **) &dbi->dbi_seq);
2811  else
2812  xx = seqid_init(dbi, dbi->dbi_seq_id, 0, (DB_SEQUENCE **) &dbi->dbi_seq);
2813  if (xx) {
2814  (void) db3close(dbi, 0);
2815  dbi = NULL;
2816  if (dbip) *dbip = dbi;
2817  }
2818  }
2819  } else {
2820  (void) db3close(dbi, 0);
2821  dbi = NULL;
2822  if (dbip) *dbip = dbi;
2823  }
2824 
2825  urlfn = _free(urlfn);
2826 
2827  /*@-nullstate -compmempass@*/
2828  return rc;
2829  /*@=nullstate =compmempass@*/
2830 }
2831 
2834 /*@-exportheadervar@*/
2835 /*@observer@*/ /*@unchecked@*/
2836 struct _dbiVec db3vec = {
2837  DB_VERSION_STRING, DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
2842 };
2843 /*@=exportheadervar@*/
2844 /*@=type@*/
static int db3Acallback(DB *db, const DBT *key, const DBT *data, DBT *_r)
Definition: db3.c:1912
uint32_t v
Definition: db3.c:741
void * app_private
Definition: db_emu.h:18
static int uint32Cmp(const void *_a, const void *_b)
Definition: db3.c:1893
const bson * b
Definition: bson.h:280
rpmTagType t
Definition: rpmtag.h:504
#define ISSET(opt)
Definition: fts.c:196
const char * str
Definition: rpmtag.h:73
rpmTag tag
Definition: rpmtag.h:503
static const char * fmtKDR(const DBT *K, const DBT *P, const DBT *D, const DBT *R)
Definition: db3.c:526
const char ** argv
Definition: rpmtag.h:75
static int db3associate(dbiIndex dbi, dbiIndex dbisecondary, int(*callback)(DB *, const DBT *, const DBT *, DBT *), unsigned int flags)
Definition: db3.c:1658
static uint64_t _ntoh_ul(uint64_t ul)
Definition: db3.c:54
static int db3cpget(dbiIndex dbi, DBC *dbcursor, DBT *key, DBT *pkey, DBT *data, unsigned int flags)
Definition: db3.c:1514
uint64_t ul
Definition: db3.c:45
#define DB_THREAD
Definition: db_emu.h:119
#define cvtdberr(_dbi, _msg, _error, _printit)
Definition: db3.c:573
OpenPGP constants and structures from RFC-2440.
#define DB_VERSION_PATCH
Definition: db_emu.h:102
static int loadDBT(DBT *_r, rpmTag tag, const void *_s, size_t ns)
Definition: db3.c:1847
static int db3join(dbiIndex dbi, DBC **curslist, DBC **dbcp, unsigned int flags)
Definition: db3.c:1718
rpmbf rpmbfNew(size_t m, size_t k, unsigned flags)
Create a Bloom filter.
Definition: rpmbf.c:52
#define EXIT_FAILURE
static const char * fmtDBCoflags(uint32_t flags)
Definition: db3.c:356
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
char * rpmCleanPath(char *path)
Canonicalize file path.
Definition: macro.c:3353
static const char * fmtDBeflags(uint32_t flags)
Definition: db3.c:266
rpmuint32_t * ui32p
Definition: rpmtag.h:70
static KEY DBoflags[]
Definition: db3.c:278
Definition: libsql.c:29
char * rpmGetPath(const char *path,...)
Return (malloc'ed) expanded, canonicalized, file path.
Definition: macro.c:3445
static uint32_t _hton_ui(uint32_t ui)
Definition: db3.c:86
int pgpExtractPubkeyFingerprint(const char *b64pkt, rpmuint8_t *keyid)
Extract OpenPGP public key fingerprint from base64 encoded packet.
Definition: rpmpgp.c:1077
uint8_t uc[8]
Definition: db3.c:48
int headerGet(Header h, HE_t he, unsigned int flags)
Retrieve extension or tag value from a header.
Definition: header.c:2231
static uint16_t _ntoh_us(uint16_t us)
Definition: db3.c:92
struct rpmbf_s * rpmbf
Definition: rpmbf.h:17
static int db3ccount(dbiIndex dbi, DBC *dbcursor, unsigned int *countp, unsigned int flags)
Definition: db3.c:1587
The Header data structure.
int rpmioMkpath(const char *path, mode_t mode, uid_t uid, gid_t gid)
Insure that directories in path exist, creating as needed.
Definition: rpmio.c:3024
#define DB_SET
Definition: db_emu.h:88
static unsigned char nibble(char c)
Convert hex to binary nibble.
Definition: db3.c:1835
void * app_private
Definition: db_emu.h:47
rpmuint16_t * ui16p
Definition: rpmtag.h:69
static size_t nDBCflags
Definition: db3.c:414
static const char * fmtDBaflags(uint32_t flags)
Definition: db3.c:311
int Stat(const char *path, struct stat *st)
stat(2) clone.
Definition: rpmrpc.c:1361
int Open(const char *path, int flags, mode_t mode)
open(2) clone.
Definition: rpmrpc.c:219
#define DB_DBT_MULTIPLE
Definition: db_emu.h:36
static void rpmdbe_event_notify(DB_ENV *dbenv, u_int32_t event, void *event_info)
Definition: db3.c:919
#define _RPMDB_NLOCKS
static int db3_fsync_disable(int fd)
Definition: db3.c:643
int errno
#define DB_VERSION_MINOR
Definition: db_emu.h:101
static size_t ncores(void)
Definition: db3.c:713
#define _AFLAGS(_aflags)
Definition: db3.c:320
static const char * mapTagName(rpmdb rpmdb, dbiIndex dbi)
Return (possibly renamed) tagName.
Definition: db3.c:583
static size_t nDBTflags
Definition: db3.c:476
#define _DBCFLAGS(_flags)
Definition: db3.c:435
#define DB_CREATE
Definition: db_emu.h:113
#define DB_KEYLAST
Definition: db_emu.h:85
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
static int Xcvtdberr(dbiIndex dbi, const char *msg, int error, int printit, const char *func, const char *fn, unsigned ln)
Definition: db3.c:555
static int db3exists(dbiIndex dbi, DBT *key, unsigned int flags)
Definition: db3.c:1313
Definition: db3.c:739
static struct _events_s _events[]
#define DB_NOTFOUND
Definition: db_emu.h:94
static int db3stat(dbiIndex dbi, unsigned int flags)
Definition: db3.c:1626
static const char * fmtDBoflags(uint32_t flags)
Definition: db3.c:292
static int db3cget(dbiIndex dbi, DBC *dbcursor, DBT *key, DBT *data, unsigned int flags)
Definition: db3.c:1473
rpmTag tagValue(const char *tagstr)
Return tag value from name.
Definition: tagname.c:446
static int db3cclose(dbiIndex dbi, DBC *dbcursor, unsigned int flags)
Definition: db3.c:1388
static int db3associate_foreign(dbiIndex dbi, dbiIndex dbisecondary, int(*callback)(DB *, const DBT *, DBT *, const DBT *, int *), unsigned int flags)
Definition: db3.c:1687
#define DBIDEBUG(_dbi, _list)
Definition: db3.c:37
static uint64_t physmem(void)
Definition: db3.c:683
void rpmbfParams(size_t n, double e, size_t *mp, size_t *kp)
Return optimal {m, k} for given n and e.
Definition: rpmbf.c:202
char * alloca()
static const char * fmtBits(uint32_t flags, KEY tbl[], size_t ntbl, char *t)
Definition: db3.c:209
Yet Another syslog(3) API clone.
static int xisprint(int c)
Definition: rpmiotypes.h:564
unsigned int rpmuint32_t
Definition: rpmiotypes.h:28
struct _HE_s * HE_t
Definition: rpmtag.h:59
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
void * data
Definition: db_emu.h:22
void * ptr
Definition: rpmtag.h:67
#define DB_INIT_TXN
Definition: db_emu.h:117
const char const bson_bool_t v
Definition: bson.h:919
static size_t nDBafflags
Definition: db3.c:329
rpmbf rpmbfFree(rpmbf bf)
Destroy a Bloom filter.
DBTYPE
Definition: db_emu.h:105
static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex *dbip)
Return handle for an index database.
Definition: db3.c:2243
static const char * tblName(uint32_t v, KEY *tbl, size_t ntbl)
Definition: db3.c:189
#define DB_WRITECURSOR
Definition: db_emu.h:91
static int db3byteswapped(dbiIndex dbi)
Definition: db3.c:1611
static const char * fmtDBafflags(uint32_t flags)
Definition: db3.c:331
const char const bson * data
Definition: mongo.h:463
rpmTagData p
Definition: rpmtag.h:506
static int db_fini(dbiIndex dbi, const char *dbhome, const char *dbfile, const char *dbsubfile)
Definition: db3.c:600
static int uint64Cmp(const void *_a, const void *_b)
Definition: db3.c:1902
uint32_t v
Definition: libsql.c:31
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
static KEY DBeflags[]
Definition: db3.c:239
uint16_t us
Definition: db3.c:47
struct tagStore_s * tagStore_t
Definition: rpmtag.h:521
Header headerLoad(void *uh)
Convert header to in-memory representation.
Definition: header.c:970
const char * rpmGenPath(const char *urlroot, const char *urlmdir, const char *urlfile)
Merge 3 args into path, any or all of which may be a url.
Definition: macro.c:3491
struct rpmdb_s * rpmdb
Database of headers and tag value indices.
Definition: rpmtypes.h:43
#define _ENTRY(_v)
Definition: db3.c:236
rpmTagCount c
Definition: rpmtag.h:507
static int _debug
Definition: db3.c:7
#define DB_INIT_LOCK
Definition: db_emu.h:114
Header headerFree(Header h)
Dereference a header instance.
static union _dbswap _endian
Definition: db3.c:52
const char const bson const bson * op
Definition: mongo.h:505
static uint64_t _hton_ul(uint64_t ul)
Definition: db3.c:68
static int db3close(dbiIndex dbi, unsigned int flags)
Definition: db3.c:1737
#define DB_VERSION_MAJOR
Definition: db_emu.h:100
rpmuint8_t * ui8p
Definition: rpmtag.h:68
Encapsulation of a "value".
Definition: expression.c:36
static size_t nDBCoflags
Definition: db3.c:354
#define _EFLAGS(_eflags)
Definition: db3.c:275
uint32_t size
Definition: db_emu.h:23
uint32_t flags
Definition: db_emu.h:43
struct __db_sequence DB_SEQUENCE
Definition: db_emu.h:14
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
static KEY DBTflags[]
Definition: db3.c:439
Header headerLink(Header h)
Reference a header instance.
#define DB_BUFFER_SMALL
Definition: db_emu.h:93
static uint16_t _hton_us(uint16_t us)
Definition: db3.c:103
static KEY DBCoflags[]
Definition: db3.c:343
Definition: rpmtag.h:502
#define _DBCOFLAGS(_coflags)
Definition: db3.c:364
#define _DBT_ENTRY(_v)
Definition: db3.c:437
static KEY DBafflags[]
Definition: db3.c:323
const char const int i
Definition: bson.h:778
struct _dbiVec db3vec
Definition: db3.c:2836
#define DB_PRIVATE
Definition: db_emu.h:98
static int db3cput(dbiIndex dbi, DBC *dbcursor, DBT *key, DBT *data, unsigned int flags)
Definition: db3.c:1443
urltype urlPath(const char *url, const char **pathp)
Return path component of URL.
Definition: url.c:430
static int snprintf(char *buf, int nb, const char *fmt,...)
Definition: rpmps.c:220
struct key_s KEY
const char const bson * key
Definition: mongo.h:717
static size_t nDBaflags
Definition: db3.c:309
dbiIndex dbiOpen(rpmdb db, rpmTag tag, unsigned int flags)
Definition: rpmdb.c:223
Definition: db_emu.h:72
static int db3cdel(dbiIndex dbi, DBC *dbcursor, DBT *key, DBT *data, unsigned int flags)
Definition: db3.c:1553
#define DB_EXCL
Definition: db_emu.h:97
char * stpcpy(char *dest, const char *src)
const char const char size_t size
Definition: bson.h:895
#define DB_INIT_MPOOL
Definition: db_emu.h:116
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
static void rpmdbe_feedback(DB_ENV *dbenv, int opcode, int percent)
Definition: db3.c:926
static const char * fmtDBCflags(uint32_t flags)
Definition: db3.c:417
static size_t nDBeflags
Definition: db3.c:264
#define _AFFLAGS(_afflags)
Definition: db3.c:340
Structure(s) and routine(s) used for EVR parsing and comparison.
#define F_OK
Definition: system.h:231
const char * db
Definition: mongo.h:697
static size_t nDBoflags
Definition: db3.c:290
static int db_init(dbiIndex dbi, const char *dbhome, const char *dbfile, const char *dbsubfile, DB_ENV **dbenvp)
Definition: db3.c:942
int rpmbfAdd(rpmbf bf, const void *_s, size_t ns)
Add item to a Bloom filter.
Definition: rpmbf.c:68
#define _OFLAGS(_oflags)
Definition: db3.c:301
#define DB_AUTO_COMMIT
Definition: db_emu.h:118
static int seqid_init(dbiIndex dbi, const char *keyp, size_t keylen, DB_SEQUENCE **seqp)
Definition: db3.c:2163
static int db3seqno(dbiIndex dbi, int64_t *seqnop, unsigned int flags)
Definition: db3.c:1335
uint32_t ui
Definition: db3.c:46
Definition: db_emu.h:17
#define INIT_LOCK()
Definition: rpmsq.c:250
static const char * name
#define _TABLE(_v)
Definition: db3.c:738
#define _(Text)
Definition: system.h:29
#define xmalloc
Definition: system.h:32
#define _KEYDATA(_K, _P, _D, _R)
Definition: db3.c:552
static KEY DBaflags[]
Definition: db3.c:304
Access RPM indices using Berkeley DB interface(s).
enum rpmTag_e rpmTag
Definition: rpmtag.h:470
#define DB_DBT_APPMALLOC
Definition: db_emu.h:31
#define D_(Text)
Definition: system.h:526
static int db3copen(dbiIndex dbi, DB_TXN *txnid, DBC **dbcp, unsigned int dbiflags)
Definition: db3.c:1412
static uint32_t _ntoh_ui(uint32_t ui)
Definition: db3.c:74
Definition: db3.c:44
const char * n
Definition: db3.c:184
static int db3cdup(dbiIndex dbi, DBC *dbcursor, DBC **dbcp, unsigned int flags)
Definition: db3.c:1366
#define RPMDBI_PACKAGES
Pseudo-tags used by the rpmdb and rpmgi iterator API's.
Definition: rpmtag.h:479
#define SET(opt)
Definition: fts.c:197
const char * n
Definition: db3.c:740
static KEY DBCflags[]
Definition: db3.c:367
#define W_OK
Definition: system.h:233
static char * fmtDBT(const DBT *K, char *te)
Definition: db3.c:479
int rpmbfChk(rpmbf bf, const void *_s, size_t ns)
Check for item in a Bloom filter.
Definition: rpmbf.c:90
struct _dbiIndex * dbiIndex
Definition: rpmdb.h:59
static int db3sync(dbiIndex dbi, unsigned int flags)
Definition: db3.c:1294
rpmuint64_t * ui64p
Definition: rpmtag.h:71
const char * ns
Definition: mongo.h:326
int Unlink(const char *path)
unlink(2) clone.
Definition: rpmrpc.c:397