rpm 5.2.1

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

- File List
- Globals

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) {
1636 rpmlog(RPMLOG_DEBUG,
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 = {
1667 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
1668 db3open, db3close, db3sync, db3associate, db3join,
1669 db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount,
1670 db3byteswapped, db3stat
1671 };
1672 /*@=exportheadervar@*/
1673 /*@=type@*/