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