00001
00006
00007 static int _debug = 1;
00008
00009 #include "system.h"
00010
00011 #if defined(HAVE_FTOK) && defined(HAVE_SYS_IPC_H)
00012 #include <sys/ipc.h>
00013 #endif
00014
00015 #if defined(__LCLINT__)
00016
00017 typedef unsigned int u_int32_t;
00018 typedef unsigned short u_int16_t;
00019 typedef unsigned char u_int8_t;
00020
00021 typedef int int32_t;
00022
00023
00024 #endif
00025
00026 #if defined(HAVE_DB4_DB_H)
00027 #include <db4/db.h>
00028 #elif defined(HAVE_DB3_DB_H)
00029 #include <db3/db.h>
00030 #endif
00031
00032 #include "rpmlib.h"
00033 #include "rpmmacro.h"
00034 #include "rpmurl.h"
00035
00036 #include "rpmdb.h"
00037
00038 #include "debug.h"
00039
00040
00041
00042
00043
00047
00048 struct dbiHStats_s {
00049 unsigned int hash_magic;
00050 unsigned int hash_version;
00051 unsigned int hash_nkeys;
00052 unsigned int hash_ndata;
00053 unsigned int hash_pagesize;
00054 unsigned int hash_nelem;
00055 unsigned int hash_ffactor;
00056 unsigned int hash_buckets;
00057 unsigned int hash_free;
00058 unsigned int hash_bfree;
00059 unsigned int hash_bigpages;
00060 unsigned int hash_big_bfree;
00061 unsigned int hash_overflows;
00062 unsigned int hash_ovfl_free;
00063 unsigned int hash_dup;
00064 unsigned int hash_dup_free;
00065 };
00066
00070 struct dbiBStats_s {
00071 unsigned int bt_magic;
00072 unsigned int bt_version;
00073 unsigned int bt_nkeys;
00074 unsigned int bt_ndata;
00075 unsigned int bt_pagesize;
00076 unsigned int bt_minkey;
00077 unsigned int bt_re_len;
00078 unsigned int bt_re_pad;
00079 unsigned int bt_levels;
00080 unsigned int bt_int_pg;
00081 unsigned int bt_leaf_pg;
00082 unsigned int bt_dup_pg;
00083 unsigned int bt_over_pg;
00084 unsigned int bt_free;
00085 unsigned int bt_int_pgfree;
00086 unsigned int bt_leaf_pgfree;
00087 unsigned int bt_dup_pgfree;
00088 unsigned int bt_over_pgfree;
00089 };
00090
00091
00092
00093 static int cvtdberr(dbiIndex dbi, const char * msg, int error, int printit)
00094
00095
00096 {
00097 int rc = 0;
00098
00099 rc = error;
00100
00101 if (printit && rc) {
00102
00103 if (msg)
00104 rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"),
00105 dbi->dbi_api, rc, msg, db_strerror(error));
00106 else
00107 rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"),
00108 dbi->dbi_api, rc, db_strerror(error));
00109
00110 }
00111
00112 return rc;
00113 }
00114
00115
00116 static int db_fini(dbiIndex dbi, const char * dbhome,
00117 const char * dbfile,
00118 const char * dbsubfile)
00119
00120
00121 {
00122 rpmdb rpmdb = dbi->dbi_rpmdb;
00123 DB_ENV * dbenv = rpmdb->db_dbenv;
00124 int rc;
00125
00126 if (dbenv == NULL)
00127 return 0;
00128
00129 rc = dbenv->close(dbenv, 0);
00130 rc = cvtdberr(dbi, "dbenv->close", rc, _debug);
00131
00132 if (dbfile)
00133 rpmMessage(RPMMESS_DEBUG, _("closed db environment %s/%s\n"),
00134 dbhome, dbfile);
00135
00136 if (rpmdb->db_remove_env || dbi->dbi_tear_down) {
00137 int xx;
00138
00139
00140 xx = db_env_create(&dbenv, 0);
00141
00142 xx = cvtdberr(dbi, "db_env_create", rc, _debug);
00143 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00144 xx = dbenv->remove(dbenv, dbhome, 0);
00145 #else
00146 xx = dbenv->remove(dbenv, dbhome, NULL, 0);
00147 #endif
00148 xx = cvtdberr(dbi, "dbenv->remove", rc, _debug);
00149
00150 if (dbfile)
00151 rpmMessage(RPMMESS_DEBUG, _("removed db environment %s/%s\n"),
00152 dbhome, dbfile);
00153
00154 }
00155 return rc;
00156 }
00157
00158 static int db3_fsync_disable( int fd)
00159
00160 {
00161 return 0;
00162 }
00163
00164
00165 static int db_init(dbiIndex dbi, const char * dbhome,
00166 const char * dbfile,
00167 const char * dbsubfile,
00168 DB_ENV ** dbenvp)
00169
00170
00171
00172 {
00173 rpmdb rpmdb = dbi->dbi_rpmdb;
00174 DB_ENV *dbenv = NULL;
00175 int eflags;
00176 int rc;
00177
00178 if (dbenvp == NULL)
00179 return 1;
00180
00181
00182
00183 if (rpmdb->db_errfile == NULL)
00184 rpmdb->db_errfile = stderr;
00185
00186
00187 eflags = (dbi->dbi_oeflags | dbi->dbi_eflags);
00188 if (eflags & DB_JOINENV) eflags &= DB_JOINENV;
00189
00190 if (dbfile)
00191 rpmMessage(RPMMESS_DEBUG, _("opening db environment %s/%s %s\n"),
00192 dbhome, dbfile, prDbiOpenFlags(eflags, 1));
00193
00194
00195 if (dbi->dbi_host == NULL)
00196 dbi->dbi_ecflags &= ~DB_CLIENT;
00197
00198
00199 if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) {
00200 #if defined(HAVE_FTOK)
00201 dbi->dbi_shmkey = ftok(dbhome, 0);
00202 #else
00203 dbi->dbi_shmkey = 0x44631380;
00204 #endif
00205 }
00206
00207 rc = db_env_create(&dbenv, dbi->dbi_ecflags);
00208 rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00209 if (rc)
00210 goto errxit;
00211
00212 if (dbenv == NULL)
00213 return 1;
00214
00215 { int xx;
00216
00217 dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00218 dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00219 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00220
00221
00222 xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00223 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00224 xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00225 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00226 xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00227 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00228 xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00229 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00230
00231
00232
00233
00234 xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mp_mmapsize);
00235 xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug);
00236 xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_mp_size, 0);
00237 xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug);
00238
00239
00240 if (dbi->dbi_no_fsync) {
00241 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00242 xx = db_env_set_func_fsync(db3_fsync_disable);
00243 #else
00244 xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable);
00245 #endif
00246 xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug);
00247 }
00248
00249
00250 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00251 if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00252 xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host,
00253 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00254 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00255 }
00256 #else
00257 if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) {
00258 xx = dbenv->set_server(dbenv, dbi->dbi_host,
00259 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0);
00260 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug);
00261 }
00262 #endif
00263 if (dbi->dbi_shmkey) {
00264 xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey);
00265 xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug);
00266 }
00267 if (dbi->dbi_tmpdir) {
00268 const char * root;
00269 const char * tmpdir;
00270
00271 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00272 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00273 root = NULL;
00274
00275 tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00276
00277 xx = dbenv->set_tmp_dir(dbenv, tmpdir);
00278 xx = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
00279 tmpdir = _free(tmpdir);
00280 }
00281 }
00282
00283 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4)
00284 rc = dbenv->open(dbenv, dbhome, eflags, dbi->dbi_perms);
00285 #else
00286 rc = dbenv->open(dbenv, dbhome, NULL, eflags, dbi->dbi_perms);
00287 #endif
00288 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
00289 if (rc)
00290 goto errxit;
00291
00292 *dbenvp = dbenv;
00293
00294 return 0;
00295
00296 errxit:
00297 if (dbenv) {
00298 int xx;
00299 xx = dbenv->close(dbenv, 0);
00300 xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00301 }
00302 return rc;
00303 }
00304
00305
00306 static int db3sync(dbiIndex dbi, unsigned int flags)
00307
00308
00309 {
00310 DB * db = dbi->dbi_db;
00311 int rc = 0;
00312 int _printit;
00313
00314 if (db != NULL)
00315 rc = db->sync(db, flags);
00316
00317 _printit = (rc == DB_INCOMPLETE ? 0 : _debug);
00318 rc = cvtdberr(dbi, "db->sync", rc, _printit);
00319 return rc;
00320 }
00321
00322 static int db3c_del(dbiIndex dbi, DBC * dbcursor, u_int32_t flags)
00323
00324
00325 {
00326 int rc;
00327
00328 rc = dbcursor->c_del(dbcursor, flags);
00329 rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug);
00330 return rc;
00331 }
00332
00333 static int db3c_dup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp,
00334 u_int32_t flags)
00335
00336
00337 {
00338 int rc;
00339
00340 if (dbcp) *dbcp = NULL;
00341 rc = dbcursor->c_dup(dbcursor, dbcp, flags);
00342 rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug);
00343
00344 return rc;
00345
00346 }
00347
00348 static int db3c_get(dbiIndex dbi, DBC * dbcursor,
00349 DBT * key, DBT * data, u_int32_t flags)
00350
00351
00352 {
00353 int _printit;
00354 int rc;
00355 int rmw;
00356
00357 #ifdef NOTYET
00358 if ((dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00359 rmw = DB_RMW;
00360 else
00361 #endif
00362 rmw = 0;
00363
00364 rc = dbcursor->c_get(dbcursor, key, data, rmw | flags);
00365
00366
00367 _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00368 rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit);
00369 return rc;
00370 }
00371
00372 static int db3c_put(dbiIndex dbi, DBC * dbcursor,
00373 DBT * key, DBT * data, u_int32_t flags)
00374
00375
00376 {
00377 int rc;
00378
00379 rc = dbcursor->c_put(dbcursor, key, data, flags);
00380
00381 rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug);
00382 return rc;
00383 }
00384
00385 static inline int db3c_close(dbiIndex dbi, DBC * dbcursor)
00386
00387
00388 {
00389 int rc;
00390
00391 if (dbcursor == NULL) return -2;
00392
00393 rc = dbcursor->c_close(dbcursor);
00394 rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug);
00395 return rc;
00396 }
00397
00398 static inline int db3c_open(dbiIndex dbi, DBC ** dbcp,
00399 int dbiflags)
00400
00401
00402 {
00403 DB * db = dbi->dbi_db;
00404 DB_TXN * txnid = NULL;
00405 int flags;
00406 int rc;
00407
00408 if (db == NULL) return -2;
00409 if ((dbiflags & DBI_WRITECURSOR) &&
00410 (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY))
00411 {
00412 flags = DB_WRITECURSOR;
00413 } else
00414 flags = 0;
00415 if (dbcp) *dbcp = NULL;
00416 rc = db->cursor(db, txnid, dbcp, flags);
00417 rc = cvtdberr(dbi, "db3c_open", rc, _debug);
00418
00419 return rc;
00420 }
00421
00422 static int db3cclose(dbiIndex dbi, DBC * dbcursor,
00423 unsigned int flags)
00424
00425
00426 {
00427 int rc = 0;
00428
00429
00430 if (flags & DBI_ITERATOR)
00431 return db3c_close(dbi, dbcursor);
00432
00433 if (!dbi->dbi_use_cursors)
00434 return 0;
00435
00436
00437 if (dbcursor == NULL)
00438 dbcursor = dbi->dbi_rmw;
00439
00440 if (dbcursor) {
00441
00442 if (dbcursor == dbi->dbi_rmw)
00443 dbi->dbi_rmw = NULL;
00444
00445 rc = db3c_close(dbi, dbcursor);
00446 }
00447 return rc;
00448 }
00449
00450 static int db3copen(dbiIndex dbi,
00451 DBC ** dbcp, unsigned int flags)
00452
00453
00454 {
00455 DBC * dbcursor;
00456 int rc = 0;
00457
00458
00459 if (flags & DBI_ITERATOR)
00460 return db3c_open(dbi, dbcp, flags);
00461
00462 if (!dbi->dbi_use_cursors) {
00463 if (dbcp) *dbcp = NULL;
00464 return 0;
00465 }
00466
00467 if ((dbcursor = dbi->dbi_rmw) == NULL) {
00468 if ((rc = db3c_open(dbi, &dbcursor, flags)) == 0)
00469 dbi->dbi_rmw = dbcursor;
00470 }
00471
00472 if (dbcp)
00473 *dbcp = dbi->dbi_rmw;
00474
00475 return rc;
00476 }
00477
00478 static int db3cput(dbiIndex dbi, DBC * dbcursor,
00479 const void * keyp, size_t keylen,
00480 const void * datap, size_t datalen,
00481 unsigned int flags)
00482
00483
00484 {
00485 DB * db = dbi->dbi_db;
00486 DB_TXN * txnid = NULL;
00487 DBT key, data;
00488 int rc;
00489
00490 memset(&key, 0, sizeof(key));
00491 memset(&data, 0, sizeof(data));
00492 key.data = (void *)keyp;
00493 key.size = keylen;
00494 data.data = (void *)datap;
00495 data.size = datalen;
00496
00497 if (dbcursor == NULL) {
00498 if (db == NULL) return -2;
00499 rc = db->put(db, txnid, &key, &data, 0);
00500 rc = cvtdberr(dbi, "db->put", rc, _debug);
00501 } else {
00502
00503 rc = db3c_put(dbi, dbcursor, &key, &data, DB_KEYLAST);
00504
00505 }
00506
00507 return rc;
00508 }
00509
00510 static int db3cdel(dbiIndex dbi, DBC * dbcursor,
00511 const void * keyp, size_t keylen,
00512 unsigned int flags)
00513
00514
00515 {
00516 DB * db = dbi->dbi_db;
00517 DB_TXN * txnid = NULL;
00518 DBT key, data;
00519 int rc;
00520
00521 memset(&key, 0, sizeof(key));
00522 memset(&data, 0, sizeof(data));
00523
00524 key.data = (void *)keyp;
00525 key.size = keylen;
00526
00527 if (dbcursor == NULL) {
00528 if (db == NULL) return -2;
00529 rc = db->del(db, txnid, &key, 0);
00530 rc = cvtdberr(dbi, "db->del", rc, _debug);
00531 } else {
00532
00533 rc = db3c_get(dbi, dbcursor, &key, &data, DB_SET);
00534
00535 if (rc == 0) {
00536
00537 rc = db3c_del(dbi, dbcursor, 0);
00538 }
00539
00540 }
00541
00542 return rc;
00543 }
00544
00545 static int db3cget(dbiIndex dbi, DBC * dbcursor,
00546 void ** keyp, size_t * keylen,
00547 void ** datap, size_t * datalen,
00548 unsigned int flags)
00549
00550
00551 {
00552 DB * db = dbi->dbi_db;
00553 DB_TXN * txnid = NULL;
00554 DBT key, data;
00555 int rc;
00556
00557 memset(&key, 0, sizeof(key));
00558 memset(&data, 0, sizeof(data));
00559
00560 if (keyp) key.data = *keyp;
00561 if (keylen) key.size = *keylen;
00562 if (datap) data.data = *datap;
00563 if (datalen) data.size = *datalen;
00564
00565
00566 if (dbcursor == NULL) {
00567 int _printit;
00568
00569 if (db == NULL) return -2;
00570
00571 rc = db->get(db, txnid, &key, &data, 0);
00572
00573 _printit = (rc == DB_NOTFOUND ? 0 : _debug);
00574 rc = cvtdberr(dbi, "db->get", rc, _printit);
00575 } else {
00576
00577
00578 rc = db3c_get(dbi, dbcursor, &key, &data,
00579 key.data == NULL ? DB_NEXT : DB_SET);
00580
00581 }
00582
00583 if (rc == 0) {
00584
00585 if (keyp) *keyp = key.data;
00586 if (keylen) *keylen = key.size;
00587 if (datap) *datap = data.data;
00588 if (datalen) *datalen = data.size;
00589
00590 }
00591
00592
00593 return rc;
00594
00595 }
00596
00597 static int db3ccount(dbiIndex dbi, DBC * dbcursor,
00598 unsigned int * countp,
00599 unsigned int flags)
00600
00601
00602 {
00603 db_recno_t count = 0;
00604 int rc = 0;
00605
00606 flags = 0;
00607 rc = dbcursor->c_count(dbcursor, &count, flags);
00608 rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug);
00609 if (rc) return rc;
00610 if (countp) *countp = count;
00611
00612 return rc;
00613 }
00614
00615 static int db3byteswapped(dbiIndex dbi)
00616 {
00617 DB * db = dbi->dbi_db;
00618 int rc = 0;
00619
00620 if (db != NULL) {
00621 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
00622 || (DB_VERSION_MAJOR == 4)
00623 int isswapped = 0;
00624 rc = db->get_byteswapped(db, &isswapped);
00625 if (rc == 0)
00626 rc = isswapped;
00627 #else
00628 rc = db->get_byteswapped(db);
00629 #endif
00630 }
00631
00632 return rc;
00633 }
00634
00635 static int db3stat(dbiIndex dbi, unsigned int flags)
00636
00637
00638 {
00639 DB * db = dbi->dbi_db;
00640 int rc = 0;
00641
00642 if (db == NULL) return -2;
00643 #if defined(DB_FAST_STAT)
00644 if (flags)
00645 flags = DB_FAST_STAT;
00646 else
00647 #endif
00648 flags = 0;
00649 dbi->dbi_stats = _free(dbi->dbi_stats);
00650
00651 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
00652 rc = db->stat(db, &dbi->dbi_stats, flags);
00653 #else
00654 rc = db->stat(db, &dbi->dbi_stats, NULL, flags);
00655 #endif
00656 rc = cvtdberr(dbi, "db->stat", rc, _debug);
00657 return rc;
00658 }
00659
00660
00661 static int db3close( dbiIndex dbi, unsigned int flags)
00662
00663
00664
00665 {
00666 rpmdb rpmdb = dbi->dbi_rpmdb;
00667 const char * urlfn = NULL;
00668 const char * root;
00669 const char * home;
00670 const char * dbhome;
00671 const char * dbfile;
00672 const char * dbsubfile;
00673 DB * db = dbi->dbi_db;
00674 int rc = 0, xx;
00675
00676 flags = 0;
00677
00678
00679
00680
00681 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00682 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00683 root = NULL;
00684 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00685
00686
00687
00688
00689
00690
00691 urlfn = rpmGenPath(root, home, NULL);
00692
00693 (void) urlPath(urlfn, &dbhome);
00694 if (dbi->dbi_temporary) {
00695 dbfile = NULL;
00696 dbsubfile = NULL;
00697 } else {
00698 #ifdef HACK
00699 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00700 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
00701 #else
00702 dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
00703 dbsubfile = NULL;
00704 #endif
00705 }
00706
00707 if (dbi->dbi_rmw)
00708 rc = db3cclose(dbi, NULL, 0);
00709
00710 if (db) {
00711 rc = db->close(db, 0);
00712 rc = cvtdberr(dbi, "db->close", rc, _debug);
00713 db = dbi->dbi_db = NULL;
00714
00715 rpmMessage(RPMMESS_DEBUG, _("closed db index %s/%s\n"),
00716 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
00717
00718 }
00719
00720 if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) {
00721 if (rpmdb->db_opens == 1) {
00722
00723 xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile);
00724
00725 rpmdb->db_dbenv = NULL;
00726 }
00727 rpmdb->db_opens--;
00728 }
00729
00730 if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) {
00731 DB_ENV * dbenv = NULL;
00732
00733
00734 rc = db_env_create(&dbenv, 0);
00735
00736 rc = cvtdberr(dbi, "db_env_create", rc, _debug);
00737 if (rc || dbenv == NULL) goto exit;
00738
00739
00740 dbenv->set_errcall(dbenv, rpmdb->db_errcall);
00741 dbenv->set_errfile(dbenv, rpmdb->db_errfile);
00742 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx);
00743
00744
00745 xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT,
00746 (dbi->dbi_verbose & DB_VERB_CHKPOINT));
00747 xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK,
00748 (dbi->dbi_verbose & DB_VERB_DEADLOCK));
00749 xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY,
00750 (dbi->dbi_verbose & DB_VERB_RECOVERY));
00751 xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR,
00752 (dbi->dbi_verbose & DB_VERB_WAITSFOR));
00753
00754 if (dbi->dbi_tmpdir) {
00755
00756 const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL);
00757
00758 rc = dbenv->set_tmp_dir(dbenv, tmpdir);
00759 rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug);
00760 tmpdir = _free(tmpdir);
00761 if (rc) goto exit;
00762 }
00763
00764 rc = dbenv->open(dbenv, dbhome,
00765 DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON, 0);
00766 rc = cvtdberr(dbi, "dbenv->open", rc, _debug);
00767 if (rc) goto exit;
00768
00769
00770 rc = db_create(&db, dbenv, 0);
00771
00772 rc = cvtdberr(dbi, "db_create", rc, _debug);
00773
00774 if (db != NULL) {
00775
00776 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL);
00777
00778
00779 rc = db->verify(db, dbf, NULL, NULL, flags);
00780 rc = cvtdberr(dbi, "db->verify", rc, _debug);
00781
00782 rpmMessage(RPMMESS_DEBUG, _("verified db index %s/%s\n"),
00783 (dbhome ? dbhome : ""),
00784 (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)));
00785
00786 xx = db->close(db, 0);
00787 xx = cvtdberr(dbi, "db->close", xx, _debug);
00788 db = NULL;
00789 if (rc == 0 && xx) rc = xx;
00790
00791 dbf = _free(dbf);
00792 }
00793 xx = dbenv->close(dbenv, 0);
00794 xx = cvtdberr(dbi, "dbenv->close", xx, _debug);
00795 if (rc == 0 && xx) rc = xx;
00796 }
00797
00798 exit:
00799 dbi->dbi_db = NULL;
00800
00801 urlfn = _free(urlfn);
00802
00803 dbi = db3Free(dbi);
00804
00805 return rc;
00806 }
00807
00808
00809 static inline int parseYesNo( const char *s )
00810 {
00811 if (!s ||
00812 !strcasecmp(s, "no") ||
00813 !strcasecmp(s, "false") ||
00814 !strcasecmp(s, "off") ||
00815 !strcmp(s, "0")) {
00816 return 0;
00817 }
00818
00819 return 1;
00820 }
00821
00822 static int wait_for_lock (void)
00823 {
00824 const char *str = rpmExpand ("%{_wait_for_lock}", NULL);
00825 int val = (str && *str != '%') ? parseYesNo (str) : 1;
00826 str = _free (str);
00827
00828 return val;
00829 }
00830
00831 static int db3open( rpmdb rpmdb, int rpmtag, dbiIndex * dbip)
00832
00833
00834
00835 {
00836
00837 extern struct _dbiVec db3vec;
00838
00839 const char * urlfn = NULL;
00840 const char * root;
00841 const char * home;
00842 const char * dbhome;
00843 const char * dbfile;
00844 const char * dbsubfile;
00845 dbiIndex dbi = NULL;
00846 int rc = 0;
00847 int xx;
00848
00849 DB * db = NULL;
00850 DB_ENV * dbenv = NULL;
00851 DB_TXN * txnid = NULL;
00852 u_int32_t oflags;
00853 int _printit;
00854
00855 if (dbip)
00856 *dbip = NULL;
00857
00858
00859
00860
00861
00862 if ((dbi = db3New(rpmdb, rpmtag)) == NULL)
00863
00864 return 1;
00865
00866
00867 dbi->dbi_api = DB_VERSION_MAJOR;
00868
00869
00870
00871
00872 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root);
00873 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone)
00874 root = NULL;
00875 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home);
00876
00877
00878
00879
00880
00881
00882 urlfn = rpmGenPath(root, home, NULL);
00883
00884 (void) urlPath(urlfn, &dbhome);
00885 if (dbi->dbi_temporary) {
00886 dbfile = NULL;
00887 dbsubfile = NULL;
00888 } else {
00889 #ifdef HACK
00890 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename);
00891 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : tagName(dbi->dbi_rpmtag));
00892 #else
00893 dbfile = (dbi->dbi_file ? dbi->dbi_file : tagName(dbi->dbi_rpmtag));
00894 dbsubfile = NULL;
00895 #endif
00896 }
00897
00898 oflags = (dbi->dbi_oeflags | dbi->dbi_oflags);
00899 oflags &= ~DB_TRUNCATE;
00900
00901 #if 0
00902 if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL;
00903 #endif
00904
00905
00906
00907
00908 if (dbi->dbi_temporary) {
00909 oflags |= DB_CREATE;
00910 dbi->dbi_oeflags |= DB_CREATE;
00911 oflags &= ~DB_RDONLY;
00912 dbi->dbi_oflags &= ~DB_RDONLY;
00913 } else {
00914 if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY;
00915 if (dbi->dbi_mode & O_CREAT) {
00916 oflags |= DB_CREATE;
00917 dbi->dbi_oeflags |= DB_CREATE;
00918 }
00919 #ifdef DANGEROUS
00920 if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE;
00921 #endif
00922 }
00923
00924
00925
00926
00927 if (dbi->dbi_use_dbenv) {
00928 if (access(dbhome, W_OK) == -1) {
00929
00930
00931 oflags &= ~DB_CREATE;
00932
00933
00934 if (dbi->dbi_eflags & DB_PRIVATE) {
00935 dbi->dbi_eflags &= ~DB_JOINENV;
00936 } else {
00937 dbi->dbi_eflags |= DB_JOINENV;
00938 dbi->dbi_oeflags &= ~DB_CREATE;
00939 dbi->dbi_oeflags &= ~DB_THREAD;
00940
00941 dbi->dbi_use_dbenv = 0;
00942 }
00943
00944
00945 if (dbi->dbi_temporary) {
00946 oflags |= DB_CREATE;
00947 dbi->dbi_oeflags |= DB_CREATE;
00948 oflags &= ~DB_RDONLY;
00949 dbi->dbi_oflags &= ~DB_RDONLY;
00950 } else {
00951 oflags |= DB_RDONLY;
00952
00953 dbi->dbi_oflags |= DB_RDONLY;
00954 }
00955
00956 } else {
00957
00958 const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL);
00959
00960
00961 if (access(dbf, F_OK) == -1) {
00962
00963 dbi->dbi_oeflags |= DB_CREATE;
00964 dbi->dbi_eflags &= ~DB_JOINENV;
00965 } else {
00966
00967 if (dbi->dbi_eflags & DB_PRIVATE) {
00968 dbi->dbi_eflags &= ~DB_JOINENV;
00969 } else {
00970 dbi->dbi_eflags |= DB_JOINENV;
00971 dbi->dbi_oeflags &= ~DB_CREATE;
00972 dbi->dbi_oeflags &= ~DB_THREAD;
00973 }
00974 }
00975 dbf = _free(dbf);
00976 }
00977 }
00978
00979
00980
00981
00982 if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) {
00983
00984 const char * dbfn = (dbfile ? dbfile : tagName(dbi->dbi_rpmtag));
00985
00986 const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL);
00987
00988
00989 if (access(dbf, F_OK) == -1) {
00990
00991 oflags &= ~DB_RDONLY;
00992 } else {
00993
00994 oflags &= ~DB_CREATE;
00995 }
00996
00997
00998 if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) {
00999 dbi->dbi_oflags &= ~DB_RDONLY;
01000 } else {
01001 dbi->dbi_oflags |= DB_RDONLY;
01002 }
01003 dbf = _free(dbf);
01004 }
01005
01006
01007
01008
01009 if (oflags & DB_RDONLY)
01010 dbi->dbi_verify_on_close = 0;
01011
01012 if (dbi->dbi_use_dbenv) {
01013
01014 if (rpmdb->db_dbenv == NULL) {
01015 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv);
01016 if (rc == 0) {
01017 rpmdb->db_dbenv = dbenv;
01018 rpmdb->db_opens = 1;
01019 }
01020 } else {
01021 dbenv = rpmdb->db_dbenv;
01022 rpmdb->db_opens++;
01023 }
01024
01025 }
01026
01027 rpmMessage(RPMMESS_DEBUG, _("opening db index %s/%s %s mode=0x%x\n"),
01028 dbhome, (dbfile ? dbfile : tagName(dbi->dbi_rpmtag)),
01029 prDbiOpenFlags(oflags, 0), dbi->dbi_mode);
01030
01031 if (rc == 0) {
01032 static int _lockdbfd = 0;
01033
01034
01035 rc = db_create(&db, dbenv, dbi->dbi_cflags);
01036
01037 rc = cvtdberr(dbi, "db_create", rc, _debug);
01038 if (rc == 0 && db != NULL) {
01039 if (rc == 0 && dbi->dbi_lorder) {
01040 rc = db->set_lorder(db, dbi->dbi_lorder);
01041 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug);
01042 }
01043 if (rc == 0 && dbi->dbi_cachesize) {
01044 rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0);
01045 rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug);
01046 }
01047 if (rc == 0 && dbi->dbi_pagesize) {
01048 rc = db->set_pagesize(db, dbi->dbi_pagesize);
01049 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug);
01050 }
01051
01052 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4)
01053 if (rc == 0 &&
01054 rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free)
01055 {
01056 rc = db->set_alloc(db,
01057 rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free);
01058 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug);
01059 }
01060 #else
01061 if (rc == 0 && rpmdb->db_malloc) {
01062 rc = db->set_malloc(db, rpmdb->db_malloc);
01063 rc = cvtdberr(dbi, "db->set_malloc", rc, _debug);
01064 }
01065 #endif
01066 if (rc == 0 && oflags & DB_CREATE) {
01067 switch(dbi->dbi_type) {
01068 default:
01069 case DB_HASH:
01070 if (dbi->dbi_h_ffactor) {
01071 rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor);
01072 rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug);
01073 if (rc) break;
01074 }
01075 if (dbi->dbi_h_nelem) {
01076 rc = db->set_h_nelem(db, dbi->dbi_h_nelem);
01077 rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug);
01078 if (rc) break;
01079 }
01080 if (dbi->dbi_h_flags) {
01081 rc = db->set_flags(db, dbi->dbi_h_flags);
01082 rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug);
01083 if (rc) break;
01084 }
01085
01086 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01087 if (dbi->dbi_h_hash_fcn) {
01088 rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn);
01089 rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug);
01090 if (rc) break;
01091 }
01092 if (dbi->dbi_h_dup_compare_fcn) {
01093 rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn);
01094 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01095 if (rc) break;
01096 }
01097 #endif
01098 break;
01099 case DB_BTREE:
01100 if (dbi->dbi_bt_flags) {
01101 rc = db->set_flags(db, dbi->dbi_bt_flags);
01102 rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug);
01103 if (rc) break;
01104 }
01105 if (dbi->dbi_bt_minkey) {
01106 rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey);
01107 rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug);
01108 if (rc) break;
01109 }
01110
01111 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4)
01112 if (dbi->dbi_bt_compare_fcn) {
01113 rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn);
01114 rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug);
01115 if (rc) break;
01116 }
01117 if (dbi->dbi_bt_dup_compare_fcn) {
01118 rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn);
01119 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug);
01120 if (rc) break;
01121 }
01122 if (dbi->dbi_bt_prefix_fcn) {
01123 rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn);
01124 rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug);
01125 if (rc) break;
01126 }
01127 #endif
01128 break;
01129 case DB_RECNO:
01130 if (dbi->dbi_re_delim) {
01131 rc = db->set_re_delim(db, dbi->dbi_re_delim);
01132 rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug);
01133 if (rc) break;
01134 }
01135 if (dbi->dbi_re_len) {
01136 rc = db->set_re_len(db, dbi->dbi_re_len);
01137 rc = cvtdberr(dbi, "db->set_re_len", rc, _debug);
01138 if (rc) break;
01139 }
01140 if (dbi->dbi_re_pad) {
01141 rc = db->set_re_pad(db, dbi->dbi_re_pad);
01142 rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug);
01143 if (rc) break;
01144 }
01145 if (dbi->dbi_re_source) {
01146 rc = db->set_re_source(db, dbi->dbi_re_source);
01147 rc = cvtdberr(dbi, "db->set_re_source", rc, _debug);
01148 if (rc) break;
01149 }
01150 break;
01151 case DB_QUEUE:
01152 if (dbi->dbi_q_extentsize) {
01153 rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize);
01154 rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug);
01155 if (rc) break;
01156 }
01157 break;
01158 }
01159 }
01160
01161 if (rc == 0) {
01162 const char * dbfullpath;
01163 const char * dbpath;
01164 char * t;
01165 int nb;
01166
01167 nb = strlen(dbhome);
01168 if (dbfile) nb += 1 + strlen(dbfile);
01169 dbfullpath = t = alloca(nb + 1);
01170
01171 t = stpcpy(t, dbhome);
01172 if (dbfile)
01173 t = stpcpy( stpcpy( t, "/"), dbfile);
01174 #ifdef HACK
01175 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary)
01176 ? dbfullpath : dbfile;
01177 #else
01178 dbpath = (!dbi->dbi_temporary)
01179 ? dbfullpath : dbfile;
01180 #endif
01181
01182 rc = db->open(db, dbpath, dbsubfile,
01183 dbi->dbi_type, oflags, dbi->dbi_perms);
01184
01185 if (rc == 0 && dbi->dbi_type == DB_UNKNOWN) {
01186 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \
01187 || (DB_VERSION_MAJOR == 4)
01188 DBTYPE dbi_type = DB_UNKNOWN;
01189 xx = db->get_type(db, &dbi_type);
01190 if (xx == 0)
01191 dbi->dbi_type = dbi_type;
01192 #else
01193 dbi->dbi_type = db->get_type(db);
01194 #endif
01195 }
01196 }
01197
01198
01199 _printit = (rc > 0 ? 0 : _debug);
01200 xx = cvtdberr(dbi, "db->open", rc, _printit);
01201
01202 if (rc == 0 && dbi->dbi_use_dbenv
01203 && (dbi->dbi_eflags & DB_INIT_CDB) && dbi->dbi_get_rmw_cursor)
01204 {
01205 DBC * dbcursor = NULL;
01206 xx = db->cursor(db, txnid, &dbcursor,
01207 ((oflags & DB_RDONLY) ? 0 : DB_WRITECURSOR));
01208 xx = cvtdberr(dbi, "db->cursor", xx, _debug);
01209 dbi->dbi_rmw = dbcursor;
01210 } else
01211 dbi->dbi_rmw = NULL;
01212
01213
01214
01215
01216
01217
01218
01219
01220
01221
01222
01223
01224
01225
01226
01227
01228 if (rc == 0 && dbi->dbi_lockdbfd &&
01229 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0))
01230 {
01231 int fdno = -1;
01232
01233 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) {
01234 rc = 1;
01235 } else {
01236 int ignore_lock = dbi->dbi_use_dbenv && (dbi->dbi_eflags & DB_INIT_CDB);
01237 int wait_lock = wait_for_lock();
01238 int cmd = (ignore_lock || !wait_lock) ? F_SETLK : F_SETLKW;
01239 struct flock l;
01240 memset(&l, 0, sizeof(l));
01241 l.l_whence = 0;
01242 l.l_start = 0;
01243 l.l_len = 0;
01244 l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY))
01245 ? F_WRLCK : F_RDLCK;
01246 l.l_pid = 0;
01247
01248 for (;;) {
01249 rc = fcntl(fdno, cmd, (void *) &l);
01250 if (rc) {
01251 if (EINTR == errno)
01252 continue;
01253
01254
01255 if (ignore_lock)
01256 rc = 0;
01257 else if (wait_lock && (EACCES == errno || EAGAIN == errno || ENOLCK == errno))
01258 continue;
01259 rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK),
01260 _("cannot get %s lock on %s/%s\n"),
01261 ((dbi->dbi_mode & (O_RDWR|O_WRONLY))
01262 ? _("exclusive") : _("shared")),
01263 dbhome, (dbfile ? dbfile : ""));
01264 } else if (dbfile) {
01265 rpmMessage(RPMMESS_DEBUG,
01266 _("locked db index %s/%s\n"),
01267 dbhome, dbfile);
01268 }
01269 break;
01270 }
01271 }
01272 }
01273 }
01274 }
01275
01276 dbi->dbi_db = db;
01277
01278 if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) {
01279 dbi->dbi_vec = &db3vec;
01280 *dbip = dbi;
01281 } else {
01282 dbi->dbi_verify_on_close = 0;
01283 (void) db3close(dbi, 0);
01284 }
01285
01286 urlfn = _free(urlfn);
01287
01288
01289 return rc;
01290
01291 }
01292
01295
01296
01297 struct _dbiVec db3vec = {
01298 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH,
01299 db3open, db3close, db3sync, db3copen, db3cclose, db3cdel, db3cget, db3cput,
01300 db3ccount, db3byteswapped, db3stat
01301 };
01302
01303