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