rpm  4.5
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 <rpmlib.h>
16 #include <rpmmacro.h>
17 #include <rpmurl.h> /* XXX urlPath proto */
18 
19 #define _RPMDB_INTERNAL
20 #include <rpmdb.h>
21 
22 #include "debug.h"
23 
24 #if !defined(DB_CLIENT) /* XXX db-4.2.42 retrofit */
25 #define DB_CLIENT DB_RPCCLIENT
26 #endif
27 
28 /*@access rpmdb @*/
29 /*@access dbiIndex @*/
30 /*@access dbiIndexSet @*/
31 
35 /*@-fielduse@*/
36 struct dbiHStats_s {
37  unsigned int hash_magic;
38  unsigned int hash_version;
39  unsigned int hash_nkeys;
40  unsigned int hash_ndata;
41  unsigned int hash_pagesize;
42  unsigned int hash_nelem;
43  unsigned int hash_ffactor;
44  unsigned int hash_buckets;
45  unsigned int hash_free;
46  unsigned int hash_bfree;
47  unsigned int hash_bigpages;
48  unsigned int hash_big_bfree;
49  unsigned int hash_overflows;
50  unsigned int hash_ovfl_free;
51  unsigned int hash_dup;
52  unsigned int hash_dup_free;
53 };
54 
58 struct dbiBStats_s {
59  unsigned int bt_magic;
60  unsigned int bt_version;
61  unsigned int bt_nkeys;
62  unsigned int bt_ndata;
63  unsigned int bt_pagesize;
64  unsigned int bt_minkey;
65  unsigned int bt_re_len;
66  unsigned int bt_re_pad;
67  unsigned int bt_levels;
68  unsigned int bt_int_pg;
69  unsigned int bt_leaf_pg;
70  unsigned int bt_dup_pg;
71  unsigned int bt_over_pg;
72  unsigned int bt_free;
73  unsigned int bt_int_pgfree;
74  unsigned int bt_leaf_pgfree;
75  unsigned int bt_dup_pgfree;
76  unsigned int bt_over_pgfree;
77 };
78 /*@=fielduse@*/
79 
80 #ifdef NOTNOW
81 static const char * bfstring(unsigned int x, const char * xbf)
82 {
83  const char * s = xbf;
84  static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
85  static char buf[BUFSIZ];
86  char * t, * te;
87  unsigned radix;
88  unsigned c, i, k;
89 
90  radix = (s != NULL ? *s++ : 16);
91 
92  if (radix <= 1 || radix >= 32)
93  radix = 16;
94 
95  t = buf;
96  switch (radix) {
97  case 8: *t++ = '0'; break;
98  case 16: *t++ = '0'; *t++ = 'x'; break;
99  }
100 
101  i = 0;
102  k = x;
103  do { i++; k /= radix; } while (k);
104 
105  te = t + i;
106 
107  k = x;
108  do { --i; t[i] = digits[k % radix]; k /= radix; } while (k);
109 
110  t = te;
111  i = '<';
112  if (s != NULL)
113  while ((c = *s++) != '\0') {
114  if (c > ' ') continue;
115 
116  k = (1 << (c - 1));
117  if (!(x & k)) continue;
118 
119  if (t == te) *t++ = '=';
120 
121  *t++ = i;
122  i = ',';
123  while (*s > ' ')
124  *t++ = *s++;
125  }
126  if (t > te) *t++ = '>';
127  *t = '\0';
128  return buf;
129 }
130 
131 /* XXX checked with db-4.5.20 */
132 static const char * dbtFlags =
133  "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK";
134 
135 static const char * dbenvOpenFlags =
136  "\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";
137 
138 static const char * dbOpenFlags =
139  "\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";
140 
141 static const char * dbenvSetFlags =
142  "\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";
143 
144 static const char * dbSetFlags =
145  "\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";
146 
147 static const char * dbiModeFlags =
148  "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW";
149 #endif /* NOTNOW */
150 
151 
152 /*@-globuse -mustmod @*/ /* FIX: rpmError not annotated yet. */
153 static int cvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg, int error, int printit)
154  /*@globals fileSystem @*/
155  /*@modifies fileSystem @*/
156 {
157  int rc = error;
158 
159  if (printit && rc) {
160  /*@-moduncon@*/ /* FIX: annotate db3 methods */
161  if (msg)
162  rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
163  DB_VERSION_MAJOR, rc, msg, db_strerror(error));
164  else
165  rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
166  DB_VERSION_MAJOR, rc, db_strerror(error));
167  /*@=moduncon@*/
168  }
169 
170  return rc;
171 }
172 /*@=globuse =mustmod @*/
173 
179 static const char * mapTagName(int value)
180  /*@*/
181 {
182  const char * s = tagName(value);
183  if (s == NULL)
184  s = "";
185  else if (!strcmp(s, "Filedigests"))
186  s = "Filemd5s";
187  return s;
188 }
189 
190 static int db_fini(dbiIndex dbi, const char * dbhome,
191  /*@null@*/ const char * dbfile,
192  /*@unused@*/ /*@null@*/ const char * dbsubfile)
193  /*@globals fileSystem @*/
194  /*@modifies fileSystem @*/
195 {
196  rpmdb rpmdb = dbi->dbi_rpmdb;
197  DB_ENV * dbenv = rpmdb->db_dbenv;
198  int rc;
199 
200  if (dbenv == NULL)
201  return 0;
202 
203  rc = dbenv->close(dbenv, 0);
204  rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
205 
206  if (dbfile)
207  rpmMessage(RPMMESS_DEBUG, D_("closed db environment %s/%s\n"),
208  dbhome, dbfile);
209 
210  if (rpmdb->db_remove_env) {
211  int xx;
212 
213  /*@-moduncon@*/ /* FIX: annotate db3 methods */
214  xx = db_env_create(&dbenv, 0);
215  /*@=moduncon@*/
216  if (!xx && dbenv != NULL) {
217  xx = cvtdberr(dbi, "db_env_create", xx, _debug);
218 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
219  xx = dbenv->remove(dbenv, dbhome, DB_FORCE);
220 #else
221  xx = dbenv->remove(dbenv, dbhome, NULL, 0);
222 #endif
223  xx = cvtdberr(dbi, "dbenv->remove", xx, _debug);
224 
225  if (dbfile)
226  rpmMessage(RPMMESS_DEBUG, D_("removed db environment %s/%s\n"),
227  dbhome, dbfile);
228  }
229 
230  }
231  return rc;
232 }
233 
234 static int db3_fsync_disable(/*@unused@*/ int fd)
235  /*@*/
236 {
237  return 0;
238 }
239 
240 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
241 
249 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid, /*@unused@*/ db_threadid_t tid,
250  u_int32_t flags)
251  /*@*/
252 {
253  int is_alive = 1; /* assume all processes are alive */
254 
255  switch (flags) {
256  case DB_MUTEX_PROCESS_ONLY:
257  case 0:
258  default:
259  is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH));
260  break;
261  }
262  return is_alive;
263 }
264 #endif
265 
266 /*@-moduncon@*/ /* FIX: annotate db3 methods */
267 static int db_init(dbiIndex dbi, const char * dbhome,
268  /*@null@*/ const char * dbfile,
269  /*@unused@*/ /*@null@*/ const char * dbsubfile,
270  /*@out@*/ DB_ENV ** dbenvp)
271  /*@globals rpmGlobalMacroContext, h_errno,
272  fileSystem @*/
273  /*@modifies dbi, *dbenvp, fileSystem @*/
274 {
275  static int oneshot = 0;
276  rpmdb rpmdb = dbi->dbi_rpmdb;
277  DB_ENV *dbenv = NULL;
278  int eflags;
279  int rc;
280  int xx;
281 
282  if (!oneshot) {
283 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
284  xx = db_env_set_func_open((int (*)(const char *, int, ...))Open);
285  xx = cvtdberr(dbi, "db_env_set_func_open", xx, _debug);
286 #endif
287  oneshot++;
288  }
289 
290  if (dbenvp == NULL)
291  return 1;
292 
293  /* XXX HACK */
294  /*@-assignexpose@*/
295  if (rpmdb->db_errfile == NULL)
296  rpmdb->db_errfile = stderr;
297  /*@=assignexpose@*/
298 
299  eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
300  /* Try to join, rather than create, the environment. */
301  /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */
302  if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
303 
304  if (dbfile)
305  rpmMessage(RPMMESS_DEBUG, D_("opening db environment %s/%s %s\n"),
306  dbhome, dbfile, prDbiOpenFlags(eflags, 1));
307 
308  /* XXX Can't do RPC w/o host. */
309  if (dbi->dbi_host == NULL)
310  dbi->dbi_ecflags &= ~DB_CLIENT;
311 
312  /* XXX Set a default shm_key. */
313  if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
314 #if defined(HAVE_FTOK)
315  dbi->dbi_shmkey = ftok(dbhome, 0);
316 #else
317  dbi->dbi_shmkey = 0x44631380;
318 #endif
319  }
320 
321  rc = db_env_create(&dbenv, dbi->dbi_ecflags);
322  rc = cvtdberr(dbi, "db_env_create", rc, _debug);
323  if (dbenv == NULL || rc)
324  goto errxit;
325 
326  /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
327 
328  /* 4.1: dbenv->set_app_dispatch(???) */
329  /* 4.1: dbenv->set_alloc(???) */
330  /* 4.1: dbenv->set_data_dir(???) */
331  /* 4.1: dbenv->set_encrypt(???) */
332 
333  dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall);
334  dbenv->set_errfile(dbenv, rpmdb->db_errfile);
335  dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
336  /*@=noeffectuncon@*/
337 
338  /* 4.1: dbenv->set_feedback(???) */
339  /* 4.1: dbenv->set_flags(???) */
340 
341  /* dbenv->set_paniccall(???) */
342 
343  if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
344  const char * home;
345  int retry = 0;
346 
347  if ((home = strrchr(dbhome, '/')) != NULL)
348  dbhome = ++home;
349 
350  while (retry++ < 5) {
351 /* XXX 3.3.4 change. */
352 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
353  xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
354  dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
355  xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
356 #else
357  xx = dbenv->set_server(dbenv, dbi->dbi_host,
358  dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
359  xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
360 #endif
361  if (!xx)
362  break;
363  (void) sleep(15);
364  }
365  } else {
366 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
367  xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
368  (dbi->dbi_verbose & DB_VERB_CHKPOINT));
369 #endif
370  xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
371  (dbi->dbi_verbose & DB_VERB_DEADLOCK));
372  xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
373  (dbi->dbi_verbose & DB_VERB_RECOVERY));
374 #if defined(DB_VERB_REGISTER)
375  xx = dbenv->set_verbose(dbenv, DB_VERB_REGISTER,
376  (dbi->dbi_verbose & DB_VERB_REGISTER));
377 #endif
378 #if defined(DB_VERB_REPLICATION)
379  xx = dbenv->set_verbose(dbenv, DB_VERB_REPLICATION,
380  (dbi->dbi_verbose & DB_VERB_REPLICATION));
381 #endif
382  xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
383  (dbi->dbi_verbose & DB_VERB_WAITSFOR));
384 #if defined(DB_VERB_FILEOPS)
385  xx = dbenv->set_verbose(dbenv, DB_VERB_FILEOPS,
386  (dbi->dbi_verbose & DB_VERB_FILEOPS));
387 #endif
388 #if defined(DB_VERB_FILEOPS_ALL)
389  xx = dbenv->set_verbose(dbenv, DB_VERB_FILEOPS_ALL,
390  (dbi->dbi_verbose & DB_VERB_FILEOPS_ALL));
391 #endif
392 
393  if (dbi->dbi_mmapsize) {
394  xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize);
395  xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
396  }
397  if (dbi->dbi_tmpdir) {
398  const char * root;
399  const char * tmpdir;
400 
401  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
402 /*@-boundsread@*/
403  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
404  root = NULL;
405 /*@=boundsread@*/
406 /*@-mods@*/
407  tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
408 /*@=mods@*/
409  xx = dbenv->set_tmp_dir(dbenv, tmpdir);
410  xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug);
411  tmpdir = _free(tmpdir);
412  }
413  }
414 
415 /* ==== Locking: */
416  /* dbenv->set_lk_conflicts(???) */
417  if (dbi->dbi_lk_detect) {
418  xx = dbenv->set_lk_detect(dbenv, dbi->dbi_lk_detect);
419  xx = cvtdberr(dbi, "dbenv->set_lk_detect", xx, _debug);
420  }
421 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
422  if (dbi->dbi_lk_max_lockers) {
423  xx = dbenv->set_lk_max_lockers(dbenv, dbi->dbi_lk_max_lockers);
424  xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug);
425  }
426  if (dbi->dbi_lk_max_locks) {
427  xx = dbenv->set_lk_max_locks(dbenv, dbi->dbi_lk_max_locks);
428  xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug);
429  }
430  if (dbi->dbi_lk_max_objects) {
431  xx = dbenv->set_lk_max_objects(dbenv, dbi->dbi_lk_max_objects);
432  xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug);
433  }
434 /* ==== Logging: */
435  if (dbi->dbi_lg_bsize) {
436  xx = dbenv->set_lg_bsize(dbenv, dbi->dbi_lg_bsize);
437  xx = cvtdberr(dbi, "dbenv->set_lg_bsize", xx, _debug);
438  }
439  if (dbi->dbi_lg_dir) {
440  xx = dbenv->set_lg_dir(dbenv, dbi->dbi_lg_dir);
441  xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug);
442  }
443  if (dbi->dbi_lg_filemode) {
444  xx = dbenv->set_lg_filemode(dbenv, dbi->dbi_lg_filemode);
445  xx = cvtdberr(dbi, "dbenv->set_lg_filemode", xx, _debug);
446  }
447  if (dbi->dbi_lg_max) {
448  xx = dbenv->set_lg_max(dbenv, dbi->dbi_lg_max);
449  xx = cvtdberr(dbi, "dbenv->set_lg_max", xx, _debug);
450  }
451  if (dbi->dbi_lg_regionmax) {
452  xx = dbenv->set_lg_regionmax(dbenv, dbi->dbi_lg_regionmax);
453  xx = cvtdberr(dbi, "dbenv->set_lg_regionmax", xx, _debug);
454  }
455 #endif
456 
457 /* ==== Memory pool: */
458  if (dbi->dbi_cachesize) {
459  xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0);
460  xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
461  }
462 
463 /* ==== Mutexes: */
464  if (dbi->dbi_mutex_align) {
465  xx = dbenv->mutex_set_align(dbenv, dbi->dbi_mutex_align);
466  xx = cvtdberr(dbi, "dbenv->mutex_set_align", xx, _debug);
467  }
468  if (dbi->dbi_mutex_increment) {
469  xx = dbenv->mutex_set_increment(dbenv, dbi->dbi_mutex_increment);
470  xx = cvtdberr(dbi, "dbenv->mutex_set_increment", xx, _debug);
471  }
472  if (dbi->dbi_mutex_max) {
473  xx = dbenv->mutex_set_max(dbenv, dbi->dbi_mutex_max);
474  xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug);
475  }
476  if (dbi->dbi_mutex_tas_spins) {
477  xx = dbenv->mutex_set_tas_spins(dbenv, dbi->dbi_mutex_tas_spins);
478  xx = cvtdberr(dbi, "dbenv->mutex_set_tas_spins", xx, _debug);
479  }
480 
481 /* ==== Replication: */
482 /* dbenv->rep_set_config */
483 /* dbenv->rep_set_limit */
484 /* dbenv->rep_set_nsites */
485 /* dbenv->rep_set_priority */
486 /* dbenv->rep_set_timeout */
487 /* dbenv->rep_set_transport */
488 
489 /* ==== Sequences: */
490 
491 /* ==== Transactions: */
492  if (dbi->dbi_tx_max) {
493  xx = dbenv->set_tx_max(dbenv, dbi->dbi_tx_max);
494  xx = cvtdberr(dbi, "dbenv->set_tx_max", xx, _debug);
495  }
496 /* XXX dbenv->txn_checkpoint */
497 /* XXX dbenv->txn_recover */
498 /* XXX dbenv->txn_stat */
499  /* 4.1 dbenv->set_timeout(???) */
500  /* 4.1: dbenv->set_tx_timestamp(???) */
501 
502 
503 /* ==== Other: */
504  if (dbi->dbi_no_fsync) {
505 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
506  xx = db_env_set_func_fsync(db3_fsync_disable);
507 #else
508  xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
509 #endif
510  xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
511  }
512 
513  if (dbi->dbi_shmkey) {
514  xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
515  xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
516  }
517 
518 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
519  /* XXX capture dbenv->falchk output on stderr. */
520 /*@-noeffectuncon@*/
521  dbenv->set_msgfile(dbenv, rpmdb->db_errfile);
522 /*@=noeffectuncon@*/
523  /* XXX must be at least 8, and __db* files need nuking to instantiate. */
524  if (dbi->dbi_thread_count >= 8) {
525  xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count);
526  xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug);
527  }
528 #endif
529 
530 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
531  rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms);
532 #else
533  rc = (dbenv->open)(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
534 #endif
535  xx = _debug;
536 #if defined(DB_VERSION_MISMATCH)
537  if (rc == DB_VERSION_MISMATCH) xx = 0;
538 #endif
539  if (rc == EINVAL) xx = 0;
540  rc = cvtdberr(dbi, "dbenv->open", rc, xx);
541  if (rc)
542  goto errxit;
543 
544 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5)
545  if (!rpmdb->db_verifying && dbi->dbi_thread_count >= 8) {
546  /* XXX Set pid/tid is_alive probe. */
547  xx = dbenv->set_isalive(dbenv, db3is_alive);
548  xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug);
549  /* XXX Clean out stale shared read locks. */
550  xx = dbenv->failchk(dbenv, 0);
551  xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug);
552  if (xx == DB_RUNRECOVERY) {
553  rc = xx;
554  goto errxit;
555  }
556  }
557 #endif
558 
559 /*@-boundswrite@*/
560  *dbenvp = dbenv;
561 /*@=boundswrite@*/
562 
563  return 0;
564 
565 errxit:
566  if (dbenv) {
567  xx = dbenv->close(dbenv, 0);
568  xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
569  }
570  return rc;
571 }
572 /*@=moduncon@*/
573 
574 static int db3sync(dbiIndex dbi, unsigned int flags)
575  /*@globals fileSystem @*/
576  /*@modifies fileSystem @*/
577 {
578  DB * db = dbi->dbi_db;
579  int rc = 0;
580  int _printit;
581 
582  if (db != NULL)
583  rc = db->sync(db, flags);
584 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
585  _printit = _debug;
586 #else
587  /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */
588  _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
589 #endif
590  rc = cvtdberr(dbi, "db->sync", rc, _printit);
591  return rc;
592 }
593 
594 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
595  unsigned int flags)
596  /*@globals fileSystem @*/
597  /*@modifies *dbcp, fileSystem @*/
598 {
599  int rc;
600 
601 /*@-boundswrite@*/
602  if (dbcp) *dbcp = NULL;
603 /*@=boundswrite@*/
604 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
605  rc = dbcursor->dup(dbcursor, dbcp, flags);
606  rc = cvtdberr(dbi, "dbcursor->dup", rc, _debug);
607 #else
608  rc = dbcursor->c_dup(dbcursor, dbcp, flags);
609  rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
610 #endif
611  /*@-nullstate @*/ /* FIX: *dbcp can be NULL */
612  return rc;
613  /*@=nullstate @*/
614 }
615 
616 /*@-mustmod@*/
617 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor,
618  /*@unused@*/ unsigned int flags)
619  /*@globals fileSystem @*/
620  /*@modifies dbi, fileSystem @*/
621 {
622  int rc = -2;
623 
624  /* XXX db3copen error pathways come through here. */
625  if (dbcursor != NULL) {
626 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
627  rc = dbcursor->close(dbcursor);
628  rc = cvtdberr(dbi, "dbcursor->close", rc, _debug);
629 #else
630  rc = dbcursor->c_close(dbcursor);
631  rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
632 #endif
633  }
634  return rc;
635 }
636 /*@=mustmod@*/
637 
638 static int db3copen(dbiIndex dbi, DB_TXN * txnid,
639  /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags)
640  /*@globals fileSystem @*/
641  /*@modifies dbi, *dbcp, fileSystem @*/
642 {
643  DB * db = dbi->dbi_db;
644  DBC * dbcursor = NULL;
645  int flags;
646  int rc;
647 
648  /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */
649  assert(db != NULL);
650  if ((dbiflags & DB_WRITECURSOR) &&
651  (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
652  {
653  flags = DB_WRITECURSOR;
654  } else
655  flags = 0;
656 
657  rc = db->cursor(db, txnid, &dbcursor, flags);
658  rc = cvtdberr(dbi, "db->cursor", rc, _debug);
659 
660  if (dbcp)
661  /*@-boundswrite -onlytrans@*/ *dbcp = dbcursor; /*@=boundswrite =onlytrans@*/
662  else
663  (void) db3cclose(dbi, dbcursor, 0);
664 
665  return rc;
666 }
667 
668 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
669  /*@unused@*/ unsigned int flags)
670  /*@globals fileSystem @*/
671  /*@modifies fileSystem @*/
672 {
673  DB * db = dbi->dbi_db;
674  int rc;
675 
676  assert(db != NULL);
677  if (dbcursor == NULL) {
678  rc = db->put(db, dbi->dbi_txnid, key, data, 0);
679  rc = cvtdberr(dbi, "db->put", rc, _debug);
680  } else {
681 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
682  rc = dbcursor->put(dbcursor, key, data, DB_KEYLAST);
683  rc = cvtdberr(dbi, "dbcursor->put", rc, _debug);
684 #else
685  rc = dbcursor->c_put(dbcursor, key, data, DB_KEYLAST);
686  rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
687 #endif
688  }
689 
690  return rc;
691 }
692 
693 /*@-mustmod@*/
694 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
695  unsigned int flags)
696  /*@globals fileSystem @*/
697  /*@modifies *dbcursor, fileSystem @*/
698 {
699  DB * db = dbi->dbi_db;
700  int rc;
701 
702  assert(db != NULL);
703  if (dbcursor == NULL) {
704  rc = db->del(db, dbi->dbi_txnid, key, flags);
705  rc = cvtdberr(dbi, "db->del", rc, _debug);
706  } else {
707  int _printit;
708 
709  /* XXX TODO: insure that cursor is positioned with duplicates */
710 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
711  rc = dbcursor->get(dbcursor, key, data, DB_SET);
712  /* XXX DB_NOTFOUND can be returned */
713  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
714  rc = cvtdberr(dbi, "dbcursor->get", rc, _printit);
715 #else
716  rc = dbcursor->c_get(dbcursor, key, data, DB_SET);
717  /* XXX DB_NOTFOUND can be returned */
718  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
719  rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
720 #endif
721 
722  if (rc == 0) {
723 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
724  rc = dbcursor->del(dbcursor, flags);
725  rc = cvtdberr(dbi, "dbcursor->del", rc, _debug);
726 #else
727  rc = dbcursor->c_del(dbcursor, flags);
728  rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
729 #endif
730  }
731  }
732 
733  return rc;
734 }
735 /*@=mustmod@*/
736 
737 /*@-mustmod@*/
738 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data,
739  unsigned int flags)
740  /*@globals fileSystem @*/
741  /*@modifies *dbcursor, *key, *data, fileSystem @*/
742 {
743  DB * db = dbi->dbi_db;
744  int _printit;
745  int rc;
746 
747  assert(db != NULL);
748  if (dbcursor == NULL) {
749  /* XXX duplicates require cursors. */
750  rc = db->get(db, dbi->dbi_txnid, key, data, 0);
751  /* XXX DB_NOTFOUND can be returned */
752  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
753  rc = cvtdberr(dbi, "db->get", rc, _printit);
754  } else {
755 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
756  /* XXX db3 does DB_FIRST on uninitialized cursor */
757  rc = dbcursor->get(dbcursor, key, data, flags);
758  /* XXX DB_NOTFOUND can be returned */
759  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
760  rc = cvtdberr(dbi, "dbcursor->get", rc, _printit);
761 #else
762  /* XXX db3 does DB_FIRST on uninitialized cursor */
763  rc = dbcursor->c_get(dbcursor, key, data, flags);
764  /* XXX DB_NOTFOUND can be returned */
765  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
766  rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
767 #endif
768  }
769 
770  return rc;
771 }
772 /*@=mustmod@*/
773 
774 /*@-mustmod@*/
775 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey,
776  DBT * data, unsigned int flags)
777  /*@globals fileSystem @*/
778  /*@modifies *dbcursor, *key, *data, fileSystem @*/
779 {
780  DB * db = dbi->dbi_db;
781  int _printit;
782  int rc;
783 
784  assert(db != NULL);
785  assert(dbcursor != NULL);
786 
787 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
788  /* XXX db3 does DB_FIRST on uninitialized cursor */
789  rc = dbcursor->pget(dbcursor, key, pkey, data, flags);
790  /* XXX DB_NOTFOUND can be returned */
791  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
792  rc = cvtdberr(dbi, "dbcursor->pget", rc, _printit);
793 #else
794  /* XXX db3 does DB_FIRST on uninitialized cursor */
795  rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags);
796  /* XXX DB_NOTFOUND can be returned */
797  _printit = (rc == DB_NOTFOUND ? 0 : _debug);
798  rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit);
799 #endif
800 
801  return rc;
802 }
803 /*@=mustmod@*/
804 
805 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
806  /*@null@*/ /*@out@*/ unsigned int * countp,
807  /*@unused@*/ unsigned int flags)
808  /*@globals fileSystem @*/
809  /*@modifies *countp, fileSystem @*/
810 {
811  db_recno_t count = 0;
812  int rc = 0;
813 
814  flags = 0;
815 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6)
816  rc = dbcursor->count(dbcursor, &count, flags);
817  rc = cvtdberr(dbi, "dbcursor->count", rc, _debug);
818 #else
819  rc = dbcursor->c_count(dbcursor, &count, flags);
820  rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
821 #endif
822  if (rc) return rc;
823 /*@-boundswrite@*/
824  if (countp) *countp = count;
825 /*@=boundswrite@*/
826 
827  return rc;
828 }
829 
830 static int db3byteswapped(dbiIndex dbi) /*@*/
831 {
832  DB * db = dbi->dbi_db;
833  int rc = 0;
834 
835  if (db != NULL) {
836 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
837  || (DB_VERSION_MAJOR == 4)
838  int isswapped = 0;
839  rc = db->get_byteswapped(db, &isswapped);
840  if (rc == 0)
841  rc = isswapped;
842 #else
843  rc = db->get_byteswapped(db);
844 #endif
845  }
846 
847  return rc;
848 }
849 
850 static int db3stat(dbiIndex dbi, unsigned int flags)
851  /*@globals fileSystem @*/
852  /*@modifies dbi, fileSystem @*/
853 {
854  DB * db = dbi->dbi_db;
855 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
856  DB_TXN * txnid = NULL;
857 #endif
858  int rc = 0;
859 
860  assert(db != NULL);
861 #if defined(DB_FAST_STAT)
862  if (flags)
863  flags = DB_FAST_STAT;
864  else
865 #endif
866  flags = 0;
867  dbi->dbi_stats = _free(dbi->dbi_stats);
868 /* XXX 3.3.4 change. */
869 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
870 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
871  rc = db->stat(db, txnid, &dbi->dbi_stats, flags);
872 #else
873  rc = db->stat(db, &dbi->dbi_stats, flags);
874 #endif
875 #else
876  rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
877 #endif
878  rc = cvtdberr(dbi, "db->stat", rc, _debug);
879  return rc;
880 }
881 
882 /*@-mustmod@*/
883 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary,
884  int (*callback)(DB *, const DBT *, const DBT *, DBT *),
885  unsigned int flags)
886  /*@globals fileSystem @*/
887  /*@modifies dbi, fileSystem @*/
888 {
889  DB * db = dbi->dbi_db;
890  DB * secondary = dbisecondary->dbi_db;
891  int rc;
892 
893 /*@-moduncon@*/ /* FIX: annotate db3 methods */
894 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
895  DB_TXN * txnid = NULL;
896 
897 assert(db != NULL);
898  rc = db->associate(db, txnid, secondary, callback, flags);
899 #else
900 assert(db != NULL);
901  rc = db->associate(db, secondary, callback, flags);
902 #endif
903 /*@=moduncon@*/
904  rc = cvtdberr(dbi, "db->associate", rc, _debug);
905  return rc;
906 }
907 /*@=mustmod@*/
908 
909 /*@-mustmod@*/
910 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp,
911  unsigned int flags)
912  /*@globals fileSystem @*/
913  /*@modifies dbi, fileSystem @*/
914 {
915  DB * db = dbi->dbi_db;
916  int rc;
917 
918 assert(db != NULL);
919 /*@-moduncon@*/ /* FIX: annotate db3 methods */
920  rc = db->join(db, curslist, dbcp, flags);
921 /*@=moduncon@*/
922  rc = cvtdberr(dbi, "db->join", rc, _debug);
923  return rc;
924 }
925 /*@=mustmod@*/
926 
927 /*@-moduncon@*/ /* FIX: annotate db3 methods */
928 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags)
929  /*@globals rpmGlobalMacroContext, h_errno,
930  fileSystem @*/
931  /*@modifies dbi, fileSystem @*/
932 {
933  rpmdb rpmdb = dbi->dbi_rpmdb;
934  const char * urlfn = NULL;
935  const char * root;
936  const char * home;
937  const char * dbhome;
938  const char * dbfile;
939  const char * dbsubfile;
940  DB * db = dbi->dbi_db;
941  int _printit;
942  int rc = 0, xx;
943 
944  flags = 0; /* XXX unused */
945 
946  /*
947  * Get the prefix/root component and directory path.
948  */
949  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
950 /*@-boundsread@*/
951  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
952  root = NULL;
953 /*@=boundsread@*/
954  home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
955 
956  /*
957  * Either the root or directory components may be a URL. Concatenate,
958  * convert the URL to a path, and add the name of the file.
959  */
960  /*@-mods@*/
961  urlfn = rpmGenPath(root, home, NULL);
962  /*@=mods@*/
963  (void) urlPath(urlfn, &dbhome);
964  if (dbi->dbi_temporary) {
965  dbfile = NULL;
966  dbsubfile = NULL;
967  } else {
968 #ifdef HACK /* XXX necessary to support dbsubfile */
969  dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
970  dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag));
971 #else
972  dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag));
973  dbsubfile = NULL;
974 #endif
975  }
976 
977  if (db) {
978  rc = db->close(db, 0);
979  /* XXX ignore not found error messages. */
980  _printit = (rc == ENOENT ? 0 : _debug);
981  rc = cvtdberr(dbi, "db->close", rc, _printit);
982  db = dbi->dbi_db = NULL;
983 
984  rpmMessage(RPMMESS_DEBUG, D_("closed db index %s/%s\n"),
985  dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)));
986 
987  }
988 
989  if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
990  if (rpmdb->db_opens == 1) {
991  /*@-nullstate@*/
992  xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
993  /*@=nullstate@*/
994  rpmdb->db_dbenv = NULL;
995  }
996  rpmdb->db_opens--;
997  }
998 
999  if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
1000  DB_ENV * dbenv = NULL;
1001  int eflags;
1002 
1003  /*@-moduncon@*/ /* FIX: annotate db3 methods */
1004  rc = db_env_create(&dbenv, 0);
1005  /*@=moduncon@*/
1006  rc = cvtdberr(dbi, "db_env_create", rc, _debug);
1007  if (rc || dbenv == NULL) goto exit;
1008 
1009  /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */
1010  dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall);
1011  dbenv->set_errfile(dbenv, rpmdb->db_errfile);
1012  dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
1013  /* dbenv->set_paniccall(???) */
1014  /*@=noeffectuncon@*/
1015 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3)
1016  xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
1017  (dbi->dbi_verbose & DB_VERB_CHKPOINT));
1018 #endif
1019  xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
1020  (dbi->dbi_verbose & DB_VERB_DEADLOCK));
1021  xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
1022  (dbi->dbi_verbose & DB_VERB_RECOVERY));
1023  xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
1024  (dbi->dbi_verbose & DB_VERB_WAITSFOR));
1025 
1026  if (dbi->dbi_tmpdir) {
1027  /*@-mods@*/
1028  const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
1029  /*@=mods@*/
1030  rc = dbenv->set_tmp_dir(dbenv, tmpdir);
1031  rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
1032  tmpdir = _free(tmpdir);
1033  if (rc) goto exit;
1034  }
1035 
1036  eflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON;
1037  rc = (dbenv->open)(dbenv, dbhome, eflags, 0);
1038  rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
1039  if (rc) goto exit;
1040 
1041  /*@-moduncon -nullstate@*/ /* FIX: annotate db3 methods */
1042  rc = db_create(&db, dbenv, 0);
1043  /*@=moduncon =nullstate@*/
1044  rc = cvtdberr(dbi, "db_create", rc, _debug);
1045 
1046  if (db != NULL) {
1047  /*@-mods@*/
1048  const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
1049  /*@=mods@*/
1050 
1051  rc = db->verify(db, dbf, NULL, NULL, flags);
1052  rc = cvtdberr(dbi, "db->verify", rc, _debug);
1053 
1054  rpmMessage(RPMMESS_DEBUG, D_("verified db index %s/%s\n"),
1055  (dbhome ? dbhome : ""),
1056  (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)));
1057 
1058  /*
1059  * The DB handle may not be accessed again after
1060  * DB->verify is called, regardless of its return.
1061  */
1062  db = NULL;
1063  dbf = _free(dbf);
1064  }
1065  xx = dbenv->close(dbenv, 0);
1066  xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
1067  if (rc == 0 && xx) rc = xx;
1068  }
1069 
1070 exit:
1071  dbi->dbi_db = NULL;
1072 
1073  urlfn = _free(urlfn);
1074 
1075  dbi = db3Free(dbi);
1076 
1077  return rc;
1078 }
1079 /*@=moduncon@*/
1080 
1081 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip)
1082  /*@globals rpmGlobalMacroContext, h_errno,
1083  fileSystem, internalState @*/
1084  /*@modifies *dbip, fileSystem, internalState @*/
1085 {
1086  /*@-nestedextern -shadow@*/
1087  extern struct _dbiVec db3vec;
1088  /*@=nestedextern =shadow@*/
1089  const char * urlfn = NULL;
1090  const char * root;
1091  const char * home;
1092  const char * dbhome;
1093  const char * dbfile;
1094  const char * dbsubfile;
1095  dbiIndex dbi = NULL;
1096  int rc = 0;
1097  int xx;
1098 
1099  DB * db = NULL;
1100  DB_ENV * dbenv = NULL;
1101 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
1102  DB_TXN * txnid = NULL;
1103 #endif
1104  DBTYPE dbi_type = DB_UNKNOWN;
1105  u_int32_t oflags;
1106  int _printit;
1107 
1108 /*@-boundswrite@*/
1109  if (dbip)
1110  *dbip = NULL;
1111 /*@=boundswrite@*/
1112 
1113  /*
1114  * Parse db configuration parameters.
1115  */
1116  /*@-mods@*/
1117  if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
1118  /*@-nullstate@*/
1119  return 1;
1120  /*@=nullstate@*/
1121  /*@=mods@*/
1122  dbi->dbi_api = DB_VERSION_MAJOR;
1123 
1124  /*
1125  * Get the prefix/root component and directory path.
1126  */
1127  root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
1128 /*@-boundsread@*/
1129  if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
1130  root = NULL;
1131 /*@=boundsread@*/
1132  home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
1133 
1134  /*
1135  * Either the root or directory components may be a URL. Concatenate,
1136  * convert the URL to a path, and add the name of the file.
1137  */
1138  /*@-mods@*/
1139  urlfn = rpmGenPath(root, home, NULL);
1140  /*@=mods@*/
1141  (void) urlPath(urlfn, &dbhome);
1142  if (dbi->dbi_temporary) {
1143  dbfile = NULL;
1144  dbsubfile = NULL;
1145  } else {
1146 #ifdef HACK /* XXX necessary to support dbsubfile */
1147  dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
1148  dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag));
1149 #else
1150  dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag));
1151  dbsubfile = NULL;
1152 #endif
1153  }
1154 
1155  oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
1156  oflags &= ~DB_TRUNCATE; /* XXX this is dangerous */
1157 
1158 #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */
1159  if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
1160 #endif
1161 
1162  /*
1163  * Map open mode flags onto configured database/environment flags.
1164  */
1165  if (dbi->dbi_temporary) {
1166  oflags |= DB_CREATE;
1167  dbi->dbi_oeflags |= DB_CREATE;
1168  oflags &= ~DB_RDONLY;
1169  dbi->dbi_oflags &= ~DB_RDONLY;
1170  } else {
1171  if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
1172  if (dbi->dbi_mode & O_CREAT) {
1173  oflags |= DB_CREATE;
1174  dbi->dbi_oeflags |= DB_CREATE;
1175  }
1176 #ifdef DANGEROUS
1177  if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
1178 #endif
1179  }
1180 
1181  /*
1182  * Create the /var/lib/rpm directory if it doesn't exist (root only).
1183  */
1184  (void) rpmioMkpath(dbhome, 0755, getuid(), getgid());
1185 
1186  /*
1187  * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open.
1188  */
1189  if (dbi->dbi_use_dbenv) {
1190 
1191  if (access(dbhome, W_OK) == -1) {
1192 
1193  /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */
1194  oflags &= ~DB_CREATE;
1195 
1196  /* ... but DBENV->open might still need DB_CREATE ... */
1197  if (dbi->dbi_eflags & DB_PRIVATE) {
1198  dbi->dbi_eflags &= ~DB_JOINENV;
1199  } else {
1200  dbi->dbi_eflags |= DB_JOINENV;
1201  dbi->dbi_oeflags &= ~DB_CREATE;
1202  dbi->dbi_oeflags &= ~DB_THREAD;
1203  /* ... but, unless DB_PRIVATE is used, skip DBENV. */
1204  dbi->dbi_use_dbenv = 0;
1205  }
1206 
1207  /* ... DB_RDONLY maps dbhome perms across files ... */
1208  if (dbi->dbi_temporary) {
1209  oflags |= DB_CREATE;
1210  dbi->dbi_oeflags |= DB_CREATE;
1211  oflags &= ~DB_RDONLY;
1212  dbi->dbi_oflags &= ~DB_RDONLY;
1213  } else {
1214  oflags |= DB_RDONLY;
1215  /* ... and DB_WRITECURSOR won't be needed ... */
1216  dbi->dbi_oflags |= DB_RDONLY;
1217  }
1218 
1219  } else { /* dbhome is writable, check for persistent dbenv. */
1220  /*@-mods@*/
1221  const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
1222  /*@=mods@*/
1223 
1224  if (access(dbf, F_OK) == -1) {
1225  /* ... non-existent (or unwritable) DBENV, will create ... */
1226  dbi->dbi_oeflags |= DB_CREATE;
1227  dbi->dbi_eflags &= ~DB_JOINENV;
1228  } else {
1229  /* ... pre-existent (or bogus) DBENV, will join ... */
1230  if (dbi->dbi_eflags & DB_PRIVATE) {
1231  dbi->dbi_eflags &= ~DB_JOINENV;
1232  } else {
1233  dbi->dbi_eflags |= DB_JOINENV;
1234  dbi->dbi_oeflags &= ~DB_CREATE;
1235  dbi->dbi_oeflags &= ~DB_THREAD;
1236  }
1237  }
1238  dbf = _free(dbf);
1239  }
1240  }
1241 
1242  /*
1243  * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open.
1244  */
1245  if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
1246  /* dbhome is writable, and DB->open flags may conflict. */
1247  const char * dbfn = (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag));
1248  /*@-mods@*/
1249  const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
1250  /*@=mods@*/
1251 
1252  if (access(dbf, F_OK) == -1) {
1253  /* File does not exist, DB->open might create ... */
1254  oflags &= ~DB_RDONLY;
1255  } else {
1256  /* File exists, DB->open need not create ... */
1257  oflags &= ~DB_CREATE;
1258  }
1259 
1260  /* Only writers need DB_WRITECURSOR ... */
1261  if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
1262  dbi->dbi_oflags &= ~DB_RDONLY;
1263  } else {
1264  dbi->dbi_oflags |= DB_RDONLY;
1265  }
1266  dbf = _free(dbf);
1267  }
1268 
1269  /*
1270  * Set db type if creating.
1271  */
1272  if (oflags & DB_CREATE)
1273  dbi_type = dbi->dbi_type;
1274 
1275  /*
1276  * Turn off verify-on-close if opening read-only.
1277  */
1278  if (oflags & DB_RDONLY)
1279  dbi->dbi_verify_on_close = 0;
1280 
1281 /*@-branchstate@*/
1282  if (dbi->dbi_use_dbenv) {
1283  /*@-mods@*/
1284  if (rpmdb->db_dbenv == NULL) {
1285  static int runrecoverycount = 0;
1286  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
1287  switch (rc) {
1288  default:
1289  break;
1290 
1291  case DB_RUNRECOVERY:
1292  if (runrecoverycount++ >= 1) {
1293  rpmlog(RPMLOG_ERR, _("RUNRECOVERY failed, exiting ...\n"));
1294  exit(EXIT_FAILURE);
1295  }
1296  rpmError(RPMERR_DBERR, _("Runnning db->verify ...\n"));
1297  rpmdb = rpmdbLink(rpmdb, "DB_RUNRECOVERY");
1298  rpmdb->db_remove_env = 1;
1299  rpmdb->db_verifying = 1;
1300  xx = rpmdbVerifyAllDBI(rpmdb);
1301  xx = cvtdberr(dbi, "db->verify", xx, _debug);
1302  rpmdb->db_remove_env = 0;
1303  rpmdb->db_verifying = 0;
1304 
1305  dbi->dbi_oeflags |= DB_CREATE;
1306  dbi->dbi_eflags &= ~DB_JOINENV;
1307  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
1308  /* XXX db_init EINVAL was masked. */
1309  rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
1310  if (rc)
1311  break;
1312 
1313 assert(dbenv);
1314  rpmdb->db_dbenv = dbenv;
1315  rpmdb->db_opens = 1;
1316  break;
1317 
1318 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */
1319  case DB_VERSION_MISMATCH:
1320 #endif
1321  case EINVAL:
1322  if (getuid() != 0)
1323  break;
1324  { char * filename = alloca(BUFSIZ);
1325  struct stat st;
1326  int i;
1327 
1328  for (i = 0; i < 16; i++) {
1329  sprintf(filename, "%s/__db.%03d", dbhome, i);
1330  (void)rpmCleanPath(filename);
1331  if (Stat(filename, &st)
1332  && (errno == ENOENT || errno == EINVAL))
1333  continue;
1334  xx = Unlink(filename);
1335  }
1336  }
1337  dbi->dbi_oeflags |= DB_CREATE;
1338  dbi->dbi_eflags &= ~DB_JOINENV;
1339  rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
1340  /* XXX db_init EINVAL was masked. */
1341  rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
1342  if (rc)
1343  break;
1344  /*@fallthrough@*/
1345  case 0:
1346 assert(dbenv);
1347  rpmdb->db_dbenv = dbenv;
1348  rpmdb->db_opens = 1;
1349  break;
1350  }
1351  } else {
1352 assert(rpmdb && rpmdb->db_dbenv);
1353  dbenv = rpmdb->db_dbenv;
1354  rpmdb->db_opens++;
1355  }
1356  /*@=mods@*/
1357  }
1358 /*@=branchstate@*/
1359 
1360  rpmMessage(RPMMESS_DEBUG, D_("opening db index %s/%s %s mode=0x%x\n"),
1361  dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)),
1362  prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
1363 
1364  if (rc == 0) {
1365  static int _lockdbfd = 0;
1366 
1367  /*@-moduncon@*/ /* FIX: annotate db3 methods */
1368  rc = db_create(&db, dbenv, dbi->dbi_cflags);
1369  /*@=moduncon@*/
1370  rc = cvtdberr(dbi, "db_create", rc, _debug);
1371  if (rc == 0 && db != NULL) {
1372 
1373 /* XXX 3.3.4 change. */
1374 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
1375  if (rc == 0 &&
1376  rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
1377  {
1378  rc = db->set_alloc(db,
1379  rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
1380  rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
1381  }
1382 #else
1383  if (rc == 0 && rpmdb->db_malloc) {
1384  rc = db->set_malloc(db, rpmdb->db_malloc);
1385  rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
1386  }
1387 #endif
1388 
1389 /* 4.1: db->set_cache_priority(???) */
1390  if (rc == 0 && !dbi->dbi_use_dbenv && dbi->dbi_cachesize) {
1391  rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
1392  rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
1393  }
1394 /* 4.1: db->set_encrypt(???) */
1395 /* 4.1: db->set_errcall(dbenv, rpmdb->db_errcall); */
1396 /* 4.1: db->set_errfile(dbenv, rpmdb->db_errfile); */
1397 /* 4.1: db->set_errpfx(dbenv, rpmdb->db_errpfx); */
1398  /* 4.1: db->set_feedback(???) */
1399 
1400  if (rc == 0 && dbi->dbi_lorder) {
1401  rc = db->set_lorder(db, dbi->dbi_lorder);
1402  rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
1403  }
1404  if (rc == 0 && dbi->dbi_pagesize) {
1405  rc = db->set_pagesize(db, dbi->dbi_pagesize);
1406  rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
1407  }
1408  /* 4.1: db->set_paniccall(???) */
1409  if (rc == 0 && oflags & DB_CREATE) {
1410  switch(dbi->dbi_type) {
1411  default:
1412  case DB_HASH:
1413  if (dbi->dbi_h_ffactor) {
1414  rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
1415  rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
1416  if (rc) break;
1417  }
1418  if (dbi->dbi_h_nelem) {
1419  rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
1420  rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
1421  if (rc) break;
1422  }
1423  if (dbi->dbi_h_flags) {
1424  rc = db->set_flags(db, dbi->dbi_h_flags);
1425  rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
1426  if (rc) break;
1427  }
1428 /* XXX db-3.2.9 has added a DB arg to the call. */
1429 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
1430  if (dbi->dbi_h_hash_fcn) {
1431  rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
1432  rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
1433  if (rc) break;
1434  }
1435  if (dbi->dbi_h_dup_compare_fcn) {
1436  rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
1437  rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
1438  if (rc) break;
1439  }
1440 #endif
1441  break;
1442  case DB_BTREE:
1443 /* 4.1: db->set_append_recno(???) */
1444  if (dbi->dbi_bt_flags) {
1445  rc = db->set_flags(db, dbi->dbi_bt_flags);
1446  rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
1447  if (rc) break;
1448  }
1449  if (dbi->dbi_bt_minkey) {
1450  rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
1451  rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
1452  if (rc) break;
1453  }
1454 /* XXX db-3.2.9 has added a DB arg to the call. */
1455 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
1456  if (dbi->dbi_bt_compare_fcn) {
1457  rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
1458  rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
1459  if (rc) break;
1460  }
1461  if (dbi->dbi_bt_dup_compare_fcn) {
1462  rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
1463  rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
1464  if (rc) break;
1465  }
1466  if (dbi->dbi_bt_prefix_fcn) {
1467  rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
1468  rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
1469  if (rc) break;
1470  }
1471 #endif
1472  break;
1473  case DB_RECNO:
1474  if (dbi->dbi_re_delim) {
1475 /* 4.1: db->set_append_recno(???) */
1476  rc = db->set_re_delim(db, dbi->dbi_re_delim);
1477  rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
1478  if (rc) break;
1479  }
1480  if (dbi->dbi_re_len) {
1481  rc = db->set_re_len(db, dbi->dbi_re_len);
1482  rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
1483  if (rc) break;
1484  }
1485  if (dbi->dbi_re_pad) {
1486  rc = db->set_re_pad(db, dbi->dbi_re_pad);
1487  rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
1488  if (rc) break;
1489  }
1490  if (dbi->dbi_re_source) {
1491  rc = db->set_re_source(db, dbi->dbi_re_source);
1492  rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
1493  if (rc) break;
1494  }
1495  break;
1496  case DB_QUEUE:
1497  if (dbi->dbi_q_extentsize) {
1498  rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
1499  rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
1500  if (rc) break;
1501  }
1502  break;
1503  }
1504  }
1505 
1506  if (rc == 0) {
1507  const char * dbfullpath;
1508  const char * dbpath;
1509  char * t;
1510  int nb;
1511 
1512  nb = strlen(dbhome);
1513  if (dbfile) nb += 1 + strlen(dbfile);
1514  dbfullpath = t = alloca(nb + 1);
1515 
1516 /*@-boundswrite@*/
1517  t = stpcpy(t, dbhome);
1518  if (dbfile)
1519  t = stpcpy( stpcpy( t, "/"), dbfile);
1520 /*@=boundswrite@*/
1521 #ifdef HACK /* XXX necessary to support dbsubfile */
1522  dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
1523  ? dbfullpath : dbfile;
1524 #else
1525  dbpath = (!dbi->dbi_temporary)
1526  ? dbfullpath : dbfile;
1527 #endif
1528 
1529 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
1530  rc = (db->open)(db, txnid, dbpath, dbsubfile,
1531  dbi_type, oflags, dbi->dbi_perms);
1532 #else
1533  rc = (db->open)(db, dbpath, dbsubfile,
1534  dbi_type, oflags, dbi->dbi_perms);
1535 #endif
1536 
1537  if (rc == 0 && dbi_type == DB_UNKNOWN) {
1538 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
1539  || (DB_VERSION_MAJOR == 4)
1540  xx = db->get_type(db, &dbi_type);
1541  if (xx == 0)
1542  dbi->dbi_type = dbi_type;
1543 #else
1544  dbi->dbi_type = db->get_type(db);
1545 #endif
1546  }
1547  }
1548 
1549  /* XXX return rc == errno without printing */
1550  _printit = (rc > 0 ? 0 : _debug);
1551  xx = cvtdberr(dbi, "db->open", rc, _printit);
1552 
1553  dbi->dbi_txnid = NULL;
1554 
1555  /*
1556  * Lock a file using fcntl(2). Traditionally this is Packages,
1557  * the file used to store metadata of installed header(s),
1558  * as Packages is always opened, and should be opened first,
1559  * for any rpmdb access.
1560  *
1561  * If no DBENV is used, then access is protected with a
1562  * shared/exclusive locking scheme, as always.
1563  *
1564  * With a DBENV, the fcntl(2) lock is necessary only to keep
1565  * the riff-raff from playing where they don't belong, as
1566  * the DBENV should provide it's own locking scheme. So try to
1567  * acquire a lock, but permit failures, as some other
1568  * DBENV player may already have acquired the lock.
1569  *
1570  * With NPTL posix mutexes, revert to fcntl lock on non-functioning
1571  * glibc/kernel combinations.
1572  */
1573  if (rc == 0 && dbi->dbi_lockdbfd &&
1574  !((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) &&
1575  (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
1576  {
1577  int fdno = -1;
1578 
1579  if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
1580  rc = 1;
1581  } else {
1582  struct flock l;
1583 /*@-boundswrite@*/
1584  memset(&l, 0, sizeof(l));
1585 /*@=boundswrite@*/
1586  l.l_whence = 0;
1587  l.l_start = 0;
1588  l.l_len = 0;
1589  l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
1590  ? F_WRLCK : F_RDLCK;
1591  l.l_pid = 0;
1592 
1593  rc = fcntl(fdno, F_SETLK, (void *) &l);
1594  if (rc) {
1595  /* Warning iff using non-private CDB locking. */
1596  rc = ((dbi->dbi_use_dbenv &&
1597  (dbi->dbi_eflags & DB_INIT_CDB) &&
1598  !(dbi->dbi_eflags & DB_PRIVATE))
1599  ? 0 : 1);
1601  _("cannot get %s lock on %s/%s\n"),
1602  ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
1603  ? _("exclusive") : _("shared")),
1604  dbhome, (dbfile ? dbfile : ""));
1605  } else if (dbfile) {
1607  D_("locked db index %s/%s\n"),
1608  dbhome, dbfile);
1609  }
1610  }
1611  }
1612  }
1613  }
1614 
1615  dbi->dbi_db = db;
1616 
1617  if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
1618  dbi->dbi_vec = &db3vec;
1619 /*@-boundswrite@*/
1620  *dbip = dbi;
1621 /*@=boundswrite@*/
1622  } else {
1623  dbi->dbi_verify_on_close = 0;
1624  (void) db3close(dbi, 0);
1625  }
1626 
1627  urlfn = _free(urlfn);
1628 
1629  /*@-nullstate -compmempass@*/
1630  return rc;
1631  /*@=nullstate =compmempass@*/
1632 }
1633 
1636 /*@-exportheadervar@*/
1637 /*@observer@*/ /*@unchecked@*/
1638 struct _dbiVec db3vec = {
1639  DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
1643 };
1644 /*@=exportheadervar@*/
1645 /*@=type@*/