rpm
4.5
|
00001 /*@-type@*/ /* FIX: annotate db3 methods */ 00006 /*@unchecked@*/ 00007 static int _debug = 1; /* XXX if < 0 debugging, > 0 unusual error returns */ 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> /* XXX urlPath proto */ 00018 00019 #define _RPMDB_INTERNAL 00020 #include <rpmdb.h> 00021 00022 #include "debug.h" 00023 00024 #if !defined(DB_CLIENT) /* XXX db-4.2.42 retrofit */ 00025 #define DB_CLIENT DB_RPCCLIENT 00026 #endif 00027 00028 /*@access rpmdb @*/ 00029 /*@access dbiIndex @*/ 00030 /*@access dbiIndexSet @*/ 00031 00035 /*@-fielduse@*/ 00036 struct dbiHStats_s { 00037 unsigned int hash_magic; 00038 unsigned int hash_version; 00039 unsigned int hash_nkeys; 00040 unsigned int hash_ndata; 00041 unsigned int hash_pagesize; 00042 unsigned int hash_nelem; 00043 unsigned int hash_ffactor; 00044 unsigned int hash_buckets; 00045 unsigned int hash_free; 00046 unsigned int hash_bfree; 00047 unsigned int hash_bigpages; 00048 unsigned int hash_big_bfree; 00049 unsigned int hash_overflows; 00050 unsigned int hash_ovfl_free; 00051 unsigned int hash_dup; 00052 unsigned int hash_dup_free; 00053 }; 00054 00058 struct dbiBStats_s { 00059 unsigned int bt_magic; 00060 unsigned int bt_version; 00061 unsigned int bt_nkeys; 00062 unsigned int bt_ndata; 00063 unsigned int bt_pagesize; 00064 unsigned int bt_minkey; 00065 unsigned int bt_re_len; 00066 unsigned int bt_re_pad; 00067 unsigned int bt_levels; 00068 unsigned int bt_int_pg; 00069 unsigned int bt_leaf_pg; 00070 unsigned int bt_dup_pg; 00071 unsigned int bt_over_pg; 00072 unsigned int bt_free; 00073 unsigned int bt_int_pgfree; 00074 unsigned int bt_leaf_pgfree; 00075 unsigned int bt_dup_pgfree; 00076 unsigned int bt_over_pgfree; 00077 }; 00078 /*@=fielduse@*/ 00079 00080 #ifdef NOTNOW 00081 static const char * bfstring(unsigned int x, const char * xbf) 00082 { 00083 const char * s = xbf; 00084 static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 00085 static char buf[BUFSIZ]; 00086 char * t, * te; 00087 unsigned radix; 00088 unsigned c, i, k; 00089 00090 radix = (s != NULL ? *s++ : 16); 00091 00092 if (radix <= 1 || radix >= 32) 00093 radix = 16; 00094 00095 t = buf; 00096 switch (radix) { 00097 case 8: *t++ = '0'; break; 00098 case 16: *t++ = '0'; *t++ = 'x'; break; 00099 } 00100 00101 i = 0; 00102 k = x; 00103 do { i++; k /= radix; } while (k); 00104 00105 te = t + i; 00106 00107 k = x; 00108 do { --i; t[i] = digits[k % radix]; k /= radix; } while (k); 00109 00110 t = te; 00111 i = '<'; 00112 if (s != NULL) 00113 while ((c = *s++) != '\0') { 00114 if (c > ' ') continue; 00115 00116 k = (1 << (c - 1)); 00117 if (!(x & k)) continue; 00118 00119 if (t == te) *t++ = '='; 00120 00121 *t++ = i; 00122 i = ','; 00123 while (*s > ' ') 00124 *t++ = *s++; 00125 } 00126 if (t > te) *t++ = '>'; 00127 *t = '\0'; 00128 return buf; 00129 } 00130 00131 /* XXX checked with db-4.5.20 */ 00132 static const char * dbtFlags = 00133 "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK"; 00134 00135 static const char * dbenvOpenFlags = 00136 "\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"; 00137 00138 static const char * dbOpenFlags = 00139 "\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"; 00140 00141 static const char * dbenvSetFlags = 00142 "\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"; 00143 00144 static const char * dbSetFlags = 00145 "\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"; 00146 00147 static const char * dbiModeFlags = 00148 "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW"; 00149 #endif /* NOTNOW */ 00150 00151 00152 /*@-globuse -mustmod @*/ /* FIX: rpmError not annotated yet. */ 00153 static int cvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg, int error, int printit) 00154 /*@globals fileSystem @*/ 00155 /*@modifies fileSystem @*/ 00156 { 00157 int rc = error; 00158 00159 if (printit && rc) { 00160 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00161 if (msg) 00162 rpmError(RPMERR_DBERR, _("db%d error(%d) from %s: %s\n"), 00163 DB_VERSION_MAJOR, rc, msg, db_strerror(error)); 00164 else 00165 rpmError(RPMERR_DBERR, _("db%d error(%d): %s\n"), 00166 DB_VERSION_MAJOR, rc, db_strerror(error)); 00167 /*@=moduncon@*/ 00168 } 00169 00170 return rc; 00171 } 00172 /*@=globuse =mustmod @*/ 00173 00179 static const char * mapTagName(int value) 00180 /*@*/ 00181 { 00182 const char * s = tagName(value); 00183 if (s == NULL) 00184 s = ""; 00185 else if (!strcmp(s, "Filedigests")) 00186 s = "Filemd5s"; 00187 return s; 00188 } 00189 00190 static int db_fini(dbiIndex dbi, const char * dbhome, 00191 /*@null@*/ const char * dbfile, 00192 /*@unused@*/ /*@null@*/ const char * dbsubfile) 00193 /*@globals fileSystem @*/ 00194 /*@modifies fileSystem @*/ 00195 { 00196 rpmdb rpmdb = dbi->dbi_rpmdb; 00197 DB_ENV * dbenv = rpmdb->db_dbenv; 00198 int rc; 00199 00200 if (dbenv == NULL) 00201 return 0; 00202 00203 rc = dbenv->close(dbenv, 0); 00204 rc = cvtdberr(dbi, "dbenv->close", rc, _debug); 00205 00206 if (dbfile) 00207 rpmMessage(RPMMESS_DEBUG, D_("closed db environment %s/%s\n"), 00208 dbhome, dbfile); 00209 00210 if (rpmdb->db_remove_env) { 00211 int xx; 00212 00213 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00214 xx = db_env_create(&dbenv, 0); 00215 /*@=moduncon@*/ 00216 if (!xx && dbenv != NULL) { 00217 xx = cvtdberr(dbi, "db_env_create", xx, _debug); 00218 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4) 00219 xx = dbenv->remove(dbenv, dbhome, DB_FORCE); 00220 #else 00221 xx = dbenv->remove(dbenv, dbhome, NULL, 0); 00222 #endif 00223 xx = cvtdberr(dbi, "dbenv->remove", xx, _debug); 00224 00225 if (dbfile) 00226 rpmMessage(RPMMESS_DEBUG, D_("removed db environment %s/%s\n"), 00227 dbhome, dbfile); 00228 } 00229 00230 } 00231 return rc; 00232 } 00233 00234 static int db3_fsync_disable(/*@unused@*/ int fd) 00235 /*@*/ 00236 { 00237 return 0; 00238 } 00239 00240 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) 00241 00249 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid, /*@unused@*/ db_threadid_t tid, 00250 u_int32_t flags) 00251 /*@*/ 00252 { 00253 int is_alive = 1; /* assume all processes are alive */ 00254 00255 switch (flags) { 00256 case DB_MUTEX_PROCESS_ONLY: 00257 case 0: 00258 default: 00259 is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH)); 00260 break; 00261 } 00262 return is_alive; 00263 } 00264 #endif 00265 00266 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00267 static int db_init(dbiIndex dbi, const char * dbhome, 00268 /*@null@*/ const char * dbfile, 00269 /*@unused@*/ /*@null@*/ const char * dbsubfile, 00270 /*@out@*/ DB_ENV ** dbenvp) 00271 /*@globals rpmGlobalMacroContext, h_errno, 00272 fileSystem @*/ 00273 /*@modifies dbi, *dbenvp, fileSystem @*/ 00274 { 00275 static int oneshot = 0; 00276 rpmdb rpmdb = dbi->dbi_rpmdb; 00277 DB_ENV *dbenv = NULL; 00278 int eflags; 00279 int rc; 00280 int xx; 00281 00282 if (!oneshot) { 00283 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4) 00284 xx = db_env_set_func_open((int (*)(const char *, int, ...))Open); 00285 xx = cvtdberr(dbi, "db_env_set_func_open", xx, _debug); 00286 #endif 00287 oneshot++; 00288 } 00289 00290 if (dbenvp == NULL) 00291 return 1; 00292 00293 /* XXX HACK */ 00294 /*@-assignexpose@*/ 00295 if (rpmdb->db_errfile == NULL) 00296 rpmdb->db_errfile = stderr; 00297 /*@=assignexpose@*/ 00298 00299 eflags = (dbi->dbi_oeflags | dbi->dbi_eflags); 00300 /* Try to join, rather than create, the environment. */ 00301 /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */ 00302 if (eflags & DB_JOINENV) eflags &= DB_JOINENV; 00303 00304 if (dbfile) 00305 rpmMessage(RPMMESS_DEBUG, D_("opening db environment %s/%s %s\n"), 00306 dbhome, dbfile, prDbiOpenFlags(eflags, 1)); 00307 00308 /* XXX Can't do RPC w/o host. */ 00309 if (dbi->dbi_host == NULL) 00310 dbi->dbi_ecflags &= ~DB_CLIENT; 00311 00312 /* XXX Set a default shm_key. */ 00313 if ((dbi->dbi_eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) { 00314 #if defined(HAVE_FTOK) 00315 dbi->dbi_shmkey = ftok(dbhome, 0); 00316 #else 00317 dbi->dbi_shmkey = 0x44631380; 00318 #endif 00319 } 00320 00321 rc = db_env_create(&dbenv, dbi->dbi_ecflags); 00322 rc = cvtdberr(dbi, "db_env_create", rc, _debug); 00323 if (dbenv == NULL || rc) 00324 goto errxit; 00325 00326 /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */ 00327 00328 /* 4.1: dbenv->set_app_dispatch(???) */ 00329 /* 4.1: dbenv->set_alloc(???) */ 00330 /* 4.1: dbenv->set_data_dir(???) */ 00331 /* 4.1: dbenv->set_encrypt(???) */ 00332 00333 dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall); 00334 dbenv->set_errfile(dbenv, rpmdb->db_errfile); 00335 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx); 00336 /*@=noeffectuncon@*/ 00337 00338 /* 4.1: dbenv->set_feedback(???) */ 00339 /* 4.1: dbenv->set_flags(???) */ 00340 00341 /* dbenv->set_paniccall(???) */ 00342 00343 if ((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) { 00344 const char * home; 00345 int retry = 0; 00346 00347 if ((home = strrchr(dbhome, '/')) != NULL) 00348 dbhome = ++home; 00349 00350 while (retry++ < 5) { 00351 /* XXX 3.3.4 change. */ 00352 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4) 00353 xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host, 00354 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0); 00355 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug); 00356 #else 00357 xx = dbenv->set_server(dbenv, dbi->dbi_host, 00358 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0); 00359 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug); 00360 #endif 00361 if (!xx) 00362 break; 00363 (void) sleep(15); 00364 } 00365 } else { 00366 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) 00367 xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 00368 (dbi->dbi_verbose & DB_VERB_CHKPOINT)); 00369 #endif 00370 xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 00371 (dbi->dbi_verbose & DB_VERB_DEADLOCK)); 00372 xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 00373 (dbi->dbi_verbose & DB_VERB_RECOVERY)); 00374 #if defined(DB_VERB_REGISTER) 00375 xx = dbenv->set_verbose(dbenv, DB_VERB_REGISTER, 00376 (dbi->dbi_verbose & DB_VERB_REGISTER)); 00377 #endif 00378 #if defined(DB_VERB_REPLICATION) 00379 xx = dbenv->set_verbose(dbenv, DB_VERB_REPLICATION, 00380 (dbi->dbi_verbose & DB_VERB_REPLICATION)); 00381 #endif 00382 xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, 00383 (dbi->dbi_verbose & DB_VERB_WAITSFOR)); 00384 #if defined(DB_VERB_FILEOPS) 00385 xx = dbenv->set_verbose(dbenv, DB_VERB_FILEOPS, 00386 (dbi->dbi_verbose & DB_VERB_FILEOPS)); 00387 #endif 00388 #if defined(DB_VERB_FILEOPS_ALL) 00389 xx = dbenv->set_verbose(dbenv, DB_VERB_FILEOPS_ALL, 00390 (dbi->dbi_verbose & DB_VERB_FILEOPS_ALL)); 00391 #endif 00392 00393 if (dbi->dbi_mmapsize) { 00394 xx = dbenv->set_mp_mmapsize(dbenv, dbi->dbi_mmapsize); 00395 xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug); 00396 } 00397 if (dbi->dbi_tmpdir) { 00398 const char * root; 00399 const char * tmpdir; 00400 00401 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 00402 /*@-boundsread@*/ 00403 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 00404 root = NULL; 00405 /*@=boundsread@*/ 00406 /*@-mods@*/ 00407 tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL); 00408 /*@=mods@*/ 00409 xx = dbenv->set_tmp_dir(dbenv, tmpdir); 00410 xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug); 00411 tmpdir = _free(tmpdir); 00412 } 00413 } 00414 00415 /* ==== Locking: */ 00416 /* dbenv->set_lk_conflicts(???) */ 00417 if (dbi->dbi_lk_detect) { 00418 xx = dbenv->set_lk_detect(dbenv, dbi->dbi_lk_detect); 00419 xx = cvtdberr(dbi, "dbenv->set_lk_detect", xx, _debug); 00420 } 00421 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) 00422 if (dbi->dbi_lk_max_lockers) { 00423 xx = dbenv->set_lk_max_lockers(dbenv, dbi->dbi_lk_max_lockers); 00424 xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug); 00425 } 00426 if (dbi->dbi_lk_max_locks) { 00427 xx = dbenv->set_lk_max_locks(dbenv, dbi->dbi_lk_max_locks); 00428 xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug); 00429 } 00430 if (dbi->dbi_lk_max_objects) { 00431 xx = dbenv->set_lk_max_objects(dbenv, dbi->dbi_lk_max_objects); 00432 xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug); 00433 } 00434 /* ==== Logging: */ 00435 if (dbi->dbi_lg_bsize) { 00436 xx = dbenv->set_lg_bsize(dbenv, dbi->dbi_lg_bsize); 00437 xx = cvtdberr(dbi, "dbenv->set_lg_bsize", xx, _debug); 00438 } 00439 if (dbi->dbi_lg_dir) { 00440 xx = dbenv->set_lg_dir(dbenv, dbi->dbi_lg_dir); 00441 xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug); 00442 } 00443 if (dbi->dbi_lg_filemode) { 00444 xx = dbenv->set_lg_filemode(dbenv, dbi->dbi_lg_filemode); 00445 xx = cvtdberr(dbi, "dbenv->set_lg_filemode", xx, _debug); 00446 } 00447 if (dbi->dbi_lg_max) { 00448 xx = dbenv->set_lg_max(dbenv, dbi->dbi_lg_max); 00449 xx = cvtdberr(dbi, "dbenv->set_lg_max", xx, _debug); 00450 } 00451 if (dbi->dbi_lg_regionmax) { 00452 xx = dbenv->set_lg_regionmax(dbenv, dbi->dbi_lg_regionmax); 00453 xx = cvtdberr(dbi, "dbenv->set_lg_regionmax", xx, _debug); 00454 } 00455 #endif 00456 00457 /* ==== Memory pool: */ 00458 if (dbi->dbi_cachesize) { 00459 xx = dbenv->set_cachesize(dbenv, 0, dbi->dbi_cachesize, 0); 00460 xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug); 00461 } 00462 00463 /* ==== Mutexes: */ 00464 if (dbi->dbi_mutex_align) { 00465 xx = dbenv->mutex_set_align(dbenv, dbi->dbi_mutex_align); 00466 xx = cvtdberr(dbi, "dbenv->mutex_set_align", xx, _debug); 00467 } 00468 if (dbi->dbi_mutex_increment) { 00469 xx = dbenv->mutex_set_increment(dbenv, dbi->dbi_mutex_increment); 00470 xx = cvtdberr(dbi, "dbenv->mutex_set_increment", xx, _debug); 00471 } 00472 if (dbi->dbi_mutex_max) { 00473 xx = dbenv->mutex_set_max(dbenv, dbi->dbi_mutex_max); 00474 xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug); 00475 } 00476 if (dbi->dbi_mutex_tas_spins) { 00477 xx = dbenv->mutex_set_tas_spins(dbenv, dbi->dbi_mutex_tas_spins); 00478 xx = cvtdberr(dbi, "dbenv->mutex_set_tas_spins", xx, _debug); 00479 } 00480 00481 /* ==== Replication: */ 00482 /* dbenv->rep_set_config */ 00483 /* dbenv->rep_set_limit */ 00484 /* dbenv->rep_set_nsites */ 00485 /* dbenv->rep_set_priority */ 00486 /* dbenv->rep_set_timeout */ 00487 /* dbenv->rep_set_transport */ 00488 00489 /* ==== Sequences: */ 00490 00491 /* ==== Transactions: */ 00492 if (dbi->dbi_tx_max) { 00493 xx = dbenv->set_tx_max(dbenv, dbi->dbi_tx_max); 00494 xx = cvtdberr(dbi, "dbenv->set_tx_max", xx, _debug); 00495 } 00496 /* XXX dbenv->txn_checkpoint */ 00497 /* XXX dbenv->txn_recover */ 00498 /* XXX dbenv->txn_stat */ 00499 /* 4.1 dbenv->set_timeout(???) */ 00500 /* 4.1: dbenv->set_tx_timestamp(???) */ 00501 00502 00503 /* ==== Other: */ 00504 if (dbi->dbi_no_fsync) { 00505 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4) 00506 xx = db_env_set_func_fsync(db3_fsync_disable); 00507 #else 00508 xx = dbenv->set_func_fsync(dbenv, db3_fsync_disable); 00509 #endif 00510 xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug); 00511 } 00512 00513 if (dbi->dbi_shmkey) { 00514 xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey); 00515 xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug); 00516 } 00517 00518 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) 00519 /* XXX capture dbenv->falchk output on stderr. */ 00520 /*@-noeffectuncon@*/ 00521 dbenv->set_msgfile(dbenv, rpmdb->db_errfile); 00522 /*@=noeffectuncon@*/ 00523 /* XXX must be at least 8, and __db* files need nuking to instantiate. */ 00524 if (dbi->dbi_thread_count >= 8) { 00525 xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count); 00526 xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug); 00527 } 00528 #endif 00529 00530 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR != 0) || (DB_VERSION_MAJOR == 4) 00531 rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms); 00532 #else 00533 rc = (dbenv->open)(dbenv, dbhome, NULL, eflags, dbi->dbi_perms); 00534 #endif 00535 xx = _debug; 00536 #if defined(DB_VERSION_MISMATCH) 00537 if (rc == DB_VERSION_MISMATCH) xx = 0; 00538 #endif 00539 if (rc == EINVAL) xx = 0; 00540 rc = cvtdberr(dbi, "dbenv->open", rc, xx); 00541 if (rc) 00542 goto errxit; 00543 00544 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) 00545 if (!rpmdb->db_verifying && dbi->dbi_thread_count >= 8) { 00546 /* XXX Set pid/tid is_alive probe. */ 00547 xx = dbenv->set_isalive(dbenv, db3is_alive); 00548 xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug); 00549 /* XXX Clean out stale shared read locks. */ 00550 xx = dbenv->failchk(dbenv, 0); 00551 xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug); 00552 if (xx == DB_RUNRECOVERY) { 00553 rc = xx; 00554 goto errxit; 00555 } 00556 } 00557 #endif 00558 00559 /*@-boundswrite@*/ 00560 *dbenvp = dbenv; 00561 /*@=boundswrite@*/ 00562 00563 return 0; 00564 00565 errxit: 00566 if (dbenv) { 00567 xx = dbenv->close(dbenv, 0); 00568 xx = cvtdberr(dbi, "dbenv->close", xx, _debug); 00569 } 00570 return rc; 00571 } 00572 /*@=moduncon@*/ 00573 00574 static int db3sync(dbiIndex dbi, unsigned int flags) 00575 /*@globals fileSystem @*/ 00576 /*@modifies fileSystem @*/ 00577 { 00578 DB * db = dbi->dbi_db; 00579 int rc = 0; 00580 int _printit; 00581 00582 if (db != NULL) 00583 rc = db->sync(db, flags); 00584 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) 00585 _printit = _debug; 00586 #else 00587 /* XXX DB_INCOMPLETE is returned occaisionally with multiple access. */ 00588 _printit = (rc == DB_INCOMPLETE ? 0 : _debug); 00589 #endif 00590 rc = cvtdberr(dbi, "db->sync", rc, _printit); 00591 return rc; 00592 } 00593 00594 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp, 00595 unsigned int flags) 00596 /*@globals fileSystem @*/ 00597 /*@modifies *dbcp, fileSystem @*/ 00598 { 00599 int rc; 00600 00601 /*@-boundswrite@*/ 00602 if (dbcp) *dbcp = NULL; 00603 /*@=boundswrite@*/ 00604 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00605 rc = dbcursor->dup(dbcursor, dbcp, flags); 00606 rc = cvtdberr(dbi, "dbcursor->dup", rc, _debug); 00607 #else 00608 rc = dbcursor->c_dup(dbcursor, dbcp, flags); 00609 rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug); 00610 #endif 00611 /*@-nullstate @*/ /* FIX: *dbcp can be NULL */ 00612 return rc; 00613 /*@=nullstate @*/ 00614 } 00615 00616 /*@-mustmod@*/ 00617 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor, 00618 /*@unused@*/ unsigned int flags) 00619 /*@globals fileSystem @*/ 00620 /*@modifies dbi, fileSystem @*/ 00621 { 00622 int rc = -2; 00623 00624 /* XXX db3copen error pathways come through here. */ 00625 if (dbcursor != NULL) { 00626 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00627 rc = dbcursor->close(dbcursor); 00628 rc = cvtdberr(dbi, "dbcursor->close", rc, _debug); 00629 #else 00630 rc = dbcursor->c_close(dbcursor); 00631 rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug); 00632 #endif 00633 } 00634 return rc; 00635 } 00636 /*@=mustmod@*/ 00637 00638 static int db3copen(dbiIndex dbi, DB_TXN * txnid, 00639 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags) 00640 /*@globals fileSystem @*/ 00641 /*@modifies dbi, *dbcp, fileSystem @*/ 00642 { 00643 DB * db = dbi->dbi_db; 00644 DBC * dbcursor = NULL; 00645 int flags; 00646 int rc; 00647 00648 /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */ 00649 assert(db != NULL); 00650 if ((dbiflags & DB_WRITECURSOR) && 00651 (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY)) 00652 { 00653 flags = DB_WRITECURSOR; 00654 } else 00655 flags = 0; 00656 00657 rc = db->cursor(db, txnid, &dbcursor, flags); 00658 rc = cvtdberr(dbi, "db->cursor", rc, _debug); 00659 00660 if (dbcp) 00661 /*@-boundswrite -onlytrans@*/ *dbcp = dbcursor; /*@=boundswrite =onlytrans@*/ 00662 else 00663 (void) db3cclose(dbi, dbcursor, 0); 00664 00665 return rc; 00666 } 00667 00668 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 00669 /*@unused@*/ unsigned int flags) 00670 /*@globals fileSystem @*/ 00671 /*@modifies fileSystem @*/ 00672 { 00673 DB * db = dbi->dbi_db; 00674 int rc; 00675 00676 assert(db != NULL); 00677 if (dbcursor == NULL) { 00678 rc = db->put(db, dbi->dbi_txnid, key, data, 0); 00679 rc = cvtdberr(dbi, "db->put", rc, _debug); 00680 } else { 00681 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00682 rc = dbcursor->put(dbcursor, key, data, DB_KEYLAST); 00683 rc = cvtdberr(dbi, "dbcursor->put", rc, _debug); 00684 #else 00685 rc = dbcursor->c_put(dbcursor, key, data, DB_KEYLAST); 00686 rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug); 00687 #endif 00688 } 00689 00690 return rc; 00691 } 00692 00693 /*@-mustmod@*/ 00694 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 00695 unsigned int flags) 00696 /*@globals fileSystem @*/ 00697 /*@modifies *dbcursor, fileSystem @*/ 00698 { 00699 DB * db = dbi->dbi_db; 00700 int rc; 00701 00702 assert(db != NULL); 00703 if (dbcursor == NULL) { 00704 rc = db->del(db, dbi->dbi_txnid, key, flags); 00705 rc = cvtdberr(dbi, "db->del", rc, _debug); 00706 } else { 00707 int _printit; 00708 00709 /* XXX TODO: insure that cursor is positioned with duplicates */ 00710 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00711 rc = dbcursor->get(dbcursor, key, data, DB_SET); 00712 /* XXX DB_NOTFOUND can be returned */ 00713 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00714 rc = cvtdberr(dbi, "dbcursor->get", rc, _printit); 00715 #else 00716 rc = dbcursor->c_get(dbcursor, key, data, DB_SET); 00717 /* XXX DB_NOTFOUND can be returned */ 00718 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00719 rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit); 00720 #endif 00721 00722 if (rc == 0) { 00723 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00724 rc = dbcursor->del(dbcursor, flags); 00725 rc = cvtdberr(dbi, "dbcursor->del", rc, _debug); 00726 #else 00727 rc = dbcursor->c_del(dbcursor, flags); 00728 rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug); 00729 #endif 00730 } 00731 } 00732 00733 return rc; 00734 } 00735 /*@=mustmod@*/ 00736 00737 /*@-mustmod@*/ 00738 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 00739 unsigned int flags) 00740 /*@globals fileSystem @*/ 00741 /*@modifies *dbcursor, *key, *data, fileSystem @*/ 00742 { 00743 DB * db = dbi->dbi_db; 00744 int _printit; 00745 int rc; 00746 00747 assert(db != NULL); 00748 if (dbcursor == NULL) { 00749 /* XXX duplicates require cursors. */ 00750 rc = db->get(db, dbi->dbi_txnid, key, data, 0); 00751 /* XXX DB_NOTFOUND can be returned */ 00752 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00753 rc = cvtdberr(dbi, "db->get", rc, _printit); 00754 } else { 00755 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00756 /* XXX db3 does DB_FIRST on uninitialized cursor */ 00757 rc = dbcursor->get(dbcursor, key, data, flags); 00758 /* XXX DB_NOTFOUND can be returned */ 00759 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00760 rc = cvtdberr(dbi, "dbcursor->get", rc, _printit); 00761 #else 00762 /* XXX db3 does DB_FIRST on uninitialized cursor */ 00763 rc = dbcursor->c_get(dbcursor, key, data, flags); 00764 /* XXX DB_NOTFOUND can be returned */ 00765 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00766 rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit); 00767 #endif 00768 } 00769 00770 return rc; 00771 } 00772 /*@=mustmod@*/ 00773 00774 /*@-mustmod@*/ 00775 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey, 00776 DBT * data, unsigned int flags) 00777 /*@globals fileSystem @*/ 00778 /*@modifies *dbcursor, *key, *data, fileSystem @*/ 00779 { 00780 DB * db = dbi->dbi_db; 00781 int _printit; 00782 int rc; 00783 00784 assert(db != NULL); 00785 assert(dbcursor != NULL); 00786 00787 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00788 /* XXX db3 does DB_FIRST on uninitialized cursor */ 00789 rc = dbcursor->pget(dbcursor, key, pkey, data, flags); 00790 /* XXX DB_NOTFOUND can be returned */ 00791 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00792 rc = cvtdberr(dbi, "dbcursor->pget", rc, _printit); 00793 #else 00794 /* XXX db3 does DB_FIRST on uninitialized cursor */ 00795 rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags); 00796 /* XXX DB_NOTFOUND can be returned */ 00797 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 00798 rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit); 00799 #endif 00800 00801 return rc; 00802 } 00803 /*@=mustmod@*/ 00804 00805 static int db3ccount(dbiIndex dbi, DBC * dbcursor, 00806 /*@null@*/ /*@out@*/ unsigned int * countp, 00807 /*@unused@*/ unsigned int flags) 00808 /*@globals fileSystem @*/ 00809 /*@modifies *countp, fileSystem @*/ 00810 { 00811 db_recno_t count = 0; 00812 int rc = 0; 00813 00814 flags = 0; 00815 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) 00816 rc = dbcursor->count(dbcursor, &count, flags); 00817 rc = cvtdberr(dbi, "dbcursor->count", rc, _debug); 00818 #else 00819 rc = dbcursor->c_count(dbcursor, &count, flags); 00820 rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug); 00821 #endif 00822 if (rc) return rc; 00823 /*@-boundswrite@*/ 00824 if (countp) *countp = count; 00825 /*@=boundswrite@*/ 00826 00827 return rc; 00828 } 00829 00830 static int db3byteswapped(dbiIndex dbi) /*@*/ 00831 { 00832 DB * db = dbi->dbi_db; 00833 int rc = 0; 00834 00835 if (db != NULL) { 00836 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \ 00837 || (DB_VERSION_MAJOR == 4) 00838 int isswapped = 0; 00839 rc = db->get_byteswapped(db, &isswapped); 00840 if (rc == 0) 00841 rc = isswapped; 00842 #else 00843 rc = db->get_byteswapped(db); 00844 #endif 00845 } 00846 00847 return rc; 00848 } 00849 00850 static int db3stat(dbiIndex dbi, unsigned int flags) 00851 /*@globals fileSystem @*/ 00852 /*@modifies dbi, fileSystem @*/ 00853 { 00854 DB * db = dbi->dbi_db; 00855 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) 00856 DB_TXN * txnid = NULL; 00857 #endif 00858 int rc = 0; 00859 00860 assert(db != NULL); 00861 #if defined(DB_FAST_STAT) 00862 if (flags) 00863 flags = DB_FAST_STAT; 00864 else 00865 #endif 00866 flags = 0; 00867 dbi->dbi_stats = _free(dbi->dbi_stats); 00868 /* XXX 3.3.4 change. */ 00869 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4) 00870 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) 00871 rc = db->stat(db, txnid, &dbi->dbi_stats, flags); 00872 #else 00873 rc = db->stat(db, &dbi->dbi_stats, flags); 00874 #endif 00875 #else 00876 rc = db->stat(db, &dbi->dbi_stats, NULL, flags); 00877 #endif 00878 rc = cvtdberr(dbi, "db->stat", rc, _debug); 00879 return rc; 00880 } 00881 00882 /*@-mustmod@*/ 00883 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary, 00884 int (*callback)(DB *, const DBT *, const DBT *, DBT *), 00885 unsigned int flags) 00886 /*@globals fileSystem @*/ 00887 /*@modifies dbi, fileSystem @*/ 00888 { 00889 DB * db = dbi->dbi_db; 00890 DB * secondary = dbisecondary->dbi_db; 00891 int rc; 00892 00893 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00894 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) 00895 DB_TXN * txnid = NULL; 00896 00897 assert(db != NULL); 00898 rc = db->associate(db, txnid, secondary, callback, flags); 00899 #else 00900 assert(db != NULL); 00901 rc = db->associate(db, secondary, callback, flags); 00902 #endif 00903 /*@=moduncon@*/ 00904 rc = cvtdberr(dbi, "db->associate", rc, _debug); 00905 return rc; 00906 } 00907 /*@=mustmod@*/ 00908 00909 /*@-mustmod@*/ 00910 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp, 00911 unsigned int flags) 00912 /*@globals fileSystem @*/ 00913 /*@modifies dbi, fileSystem @*/ 00914 { 00915 DB * db = dbi->dbi_db; 00916 int rc; 00917 00918 assert(db != NULL); 00919 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00920 rc = db->join(db, curslist, dbcp, flags); 00921 /*@=moduncon@*/ 00922 rc = cvtdberr(dbi, "db->join", rc, _debug); 00923 return rc; 00924 } 00925 /*@=mustmod@*/ 00926 00927 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00928 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags) 00929 /*@globals rpmGlobalMacroContext, h_errno, 00930 fileSystem @*/ 00931 /*@modifies dbi, fileSystem @*/ 00932 { 00933 rpmdb rpmdb = dbi->dbi_rpmdb; 00934 const char * urlfn = NULL; 00935 const char * root; 00936 const char * home; 00937 const char * dbhome; 00938 const char * dbfile; 00939 const char * dbsubfile; 00940 DB * db = dbi->dbi_db; 00941 int _printit; 00942 int rc = 0, xx; 00943 00944 flags = 0; /* XXX unused */ 00945 00946 /* 00947 * Get the prefix/root component and directory path. 00948 */ 00949 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 00950 /*@-boundsread@*/ 00951 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 00952 root = NULL; 00953 /*@=boundsread@*/ 00954 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home); 00955 00956 /* 00957 * Either the root or directory components may be a URL. Concatenate, 00958 * convert the URL to a path, and add the name of the file. 00959 */ 00960 /*@-mods@*/ 00961 urlfn = rpmGenPath(root, home, NULL); 00962 /*@=mods@*/ 00963 (void) urlPath(urlfn, &dbhome); 00964 if (dbi->dbi_temporary) { 00965 dbfile = NULL; 00966 dbsubfile = NULL; 00967 } else { 00968 #ifdef HACK /* XXX necessary to support dbsubfile */ 00969 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename); 00970 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag)); 00971 #else 00972 dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag)); 00973 dbsubfile = NULL; 00974 #endif 00975 } 00976 00977 if (db) { 00978 rc = db->close(db, 0); 00979 /* XXX ignore not found error messages. */ 00980 _printit = (rc == ENOENT ? 0 : _debug); 00981 rc = cvtdberr(dbi, "db->close", rc, _printit); 00982 db = dbi->dbi_db = NULL; 00983 00984 rpmMessage(RPMMESS_DEBUG, D_("closed db index %s/%s\n"), 00985 dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag))); 00986 00987 } 00988 00989 if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv) { 00990 if (rpmdb->db_opens == 1) { 00991 /*@-nullstate@*/ 00992 xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile); 00993 /*@=nullstate@*/ 00994 rpmdb->db_dbenv = NULL; 00995 } 00996 rpmdb->db_opens--; 00997 } 00998 00999 if (dbi->dbi_verify_on_close && !dbi->dbi_temporary) { 01000 DB_ENV * dbenv = NULL; 01001 int eflags; 01002 01003 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01004 rc = db_env_create(&dbenv, 0); 01005 /*@=moduncon@*/ 01006 rc = cvtdberr(dbi, "db_env_create", rc, _debug); 01007 if (rc || dbenv == NULL) goto exit; 01008 01009 /*@-noeffectuncon@*/ /* FIX: annotate db3 methods */ 01010 dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall); 01011 dbenv->set_errfile(dbenv, rpmdb->db_errfile); 01012 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx); 01013 /* dbenv->set_paniccall(???) */ 01014 /*@=noeffectuncon@*/ 01015 #if !(DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) 01016 xx = dbenv->set_verbose(dbenv, DB_VERB_CHKPOINT, 01017 (dbi->dbi_verbose & DB_VERB_CHKPOINT)); 01018 #endif 01019 xx = dbenv->set_verbose(dbenv, DB_VERB_DEADLOCK, 01020 (dbi->dbi_verbose & DB_VERB_DEADLOCK)); 01021 xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 01022 (dbi->dbi_verbose & DB_VERB_RECOVERY)); 01023 xx = dbenv->set_verbose(dbenv, DB_VERB_WAITSFOR, 01024 (dbi->dbi_verbose & DB_VERB_WAITSFOR)); 01025 01026 if (dbi->dbi_tmpdir) { 01027 /*@-mods@*/ 01028 const char * tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL); 01029 /*@=mods@*/ 01030 rc = dbenv->set_tmp_dir(dbenv, tmpdir); 01031 rc = cvtdberr(dbi, "dbenv->set_tmp_dir", rc, _debug); 01032 tmpdir = _free(tmpdir); 01033 if (rc) goto exit; 01034 } 01035 01036 eflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE | DB_USE_ENVIRON; 01037 rc = (dbenv->open)(dbenv, dbhome, eflags, 0); 01038 rc = cvtdberr(dbi, "dbenv->open", rc, _debug); 01039 if (rc) goto exit; 01040 01041 /*@-moduncon -nullstate@*/ /* FIX: annotate db3 methods */ 01042 rc = db_create(&db, dbenv, 0); 01043 /*@=moduncon =nullstate@*/ 01044 rc = cvtdberr(dbi, "db_create", rc, _debug); 01045 01046 if (db != NULL) { 01047 /*@-mods@*/ 01048 const char * dbf = rpmGetPath(dbhome, "/", dbfile, NULL); 01049 /*@=mods@*/ 01050 01051 rc = db->verify(db, dbf, NULL, NULL, flags); 01052 rc = cvtdberr(dbi, "db->verify", rc, _debug); 01053 01054 rpmMessage(RPMMESS_DEBUG, D_("verified db index %s/%s\n"), 01055 (dbhome ? dbhome : ""), 01056 (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag))); 01057 01058 /* 01059 * The DB handle may not be accessed again after 01060 * DB->verify is called, regardless of its return. 01061 */ 01062 db = NULL; 01063 dbf = _free(dbf); 01064 } 01065 xx = dbenv->close(dbenv, 0); 01066 xx = cvtdberr(dbi, "dbenv->close", xx, _debug); 01067 if (rc == 0 && xx) rc = xx; 01068 } 01069 01070 exit: 01071 dbi->dbi_db = NULL; 01072 01073 urlfn = _free(urlfn); 01074 01075 dbi = db3Free(dbi); 01076 01077 return rc; 01078 } 01079 /*@=moduncon@*/ 01080 01081 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip) 01082 /*@globals rpmGlobalMacroContext, h_errno, 01083 fileSystem, internalState @*/ 01084 /*@modifies *dbip, fileSystem, internalState @*/ 01085 { 01086 /*@-nestedextern -shadow@*/ 01087 extern struct _dbiVec db3vec; 01088 /*@=nestedextern =shadow@*/ 01089 const char * urlfn = NULL; 01090 const char * root; 01091 const char * home; 01092 const char * dbhome; 01093 const char * dbfile; 01094 const char * dbsubfile; 01095 dbiIndex dbi = NULL; 01096 int rc = 0; 01097 int xx; 01098 01099 DB * db = NULL; 01100 DB_ENV * dbenv = NULL; 01101 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) 01102 DB_TXN * txnid = NULL; 01103 #endif 01104 DBTYPE dbi_type = DB_UNKNOWN; 01105 u_int32_t oflags; 01106 int _printit; 01107 01108 /*@-boundswrite@*/ 01109 if (dbip) 01110 *dbip = NULL; 01111 /*@=boundswrite@*/ 01112 01113 /* 01114 * Parse db configuration parameters. 01115 */ 01116 /*@-mods@*/ 01117 if ((dbi = db3New(rpmdb, rpmtag)) == NULL) 01118 /*@-nullstate@*/ 01119 return 1; 01120 /*@=nullstate@*/ 01121 /*@=mods@*/ 01122 dbi->dbi_api = DB_VERSION_MAJOR; 01123 01124 /* 01125 * Get the prefix/root component and directory path. 01126 */ 01127 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 01128 /*@-boundsread@*/ 01129 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 01130 root = NULL; 01131 /*@=boundsread@*/ 01132 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home); 01133 01134 /* 01135 * Either the root or directory components may be a URL. Concatenate, 01136 * convert the URL to a path, and add the name of the file. 01137 */ 01138 /*@-mods@*/ 01139 urlfn = rpmGenPath(root, home, NULL); 01140 /*@=mods@*/ 01141 (void) urlPath(urlfn, &dbhome); 01142 if (dbi->dbi_temporary) { 01143 dbfile = NULL; 01144 dbsubfile = NULL; 01145 } else { 01146 #ifdef HACK /* XXX necessary to support dbsubfile */ 01147 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename); 01148 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : mapTagName(dbi->dbi_rpmtag)); 01149 #else 01150 dbfile = (dbi->dbi_file ? dbi->dbi_file : mapTagName(dbi->dbi_rpmtag)); 01151 dbsubfile = NULL; 01152 #endif 01153 } 01154 01155 oflags = (dbi->dbi_oeflags | dbi->dbi_oflags); 01156 oflags &= ~DB_TRUNCATE; /* XXX this is dangerous */ 01157 01158 #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */ 01159 if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL; 01160 #endif 01161 01162 /* 01163 * Map open mode flags onto configured database/environment flags. 01164 */ 01165 if (dbi->dbi_temporary) { 01166 oflags |= DB_CREATE; 01167 dbi->dbi_oeflags |= DB_CREATE; 01168 oflags &= ~DB_RDONLY; 01169 dbi->dbi_oflags &= ~DB_RDONLY; 01170 } else { 01171 if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY; 01172 if (dbi->dbi_mode & O_CREAT) { 01173 oflags |= DB_CREATE; 01174 dbi->dbi_oeflags |= DB_CREATE; 01175 } 01176 #ifdef DANGEROUS 01177 if ( dbi->dbi_mode & O_TRUNC) oflags |= DB_TRUNCATE; 01178 #endif 01179 } 01180 01181 /* 01182 * Create the /var/lib/rpm directory if it doesn't exist (root only). 01183 */ 01184 (void) rpmioMkpath(dbhome, 0755, getuid(), getgid()); 01185 01186 /* 01187 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open. 01188 */ 01189 if (dbi->dbi_use_dbenv) { 01190 01191 if (access(dbhome, W_OK) == -1) { 01192 01193 /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */ 01194 oflags &= ~DB_CREATE; 01195 01196 /* ... but DBENV->open might still need DB_CREATE ... */ 01197 if (dbi->dbi_eflags & DB_PRIVATE) { 01198 dbi->dbi_eflags &= ~DB_JOINENV; 01199 } else { 01200 dbi->dbi_eflags |= DB_JOINENV; 01201 dbi->dbi_oeflags &= ~DB_CREATE; 01202 dbi->dbi_oeflags &= ~DB_THREAD; 01203 /* ... but, unless DB_PRIVATE is used, skip DBENV. */ 01204 dbi->dbi_use_dbenv = 0; 01205 } 01206 01207 /* ... DB_RDONLY maps dbhome perms across files ... */ 01208 if (dbi->dbi_temporary) { 01209 oflags |= DB_CREATE; 01210 dbi->dbi_oeflags |= DB_CREATE; 01211 oflags &= ~DB_RDONLY; 01212 dbi->dbi_oflags &= ~DB_RDONLY; 01213 } else { 01214 oflags |= DB_RDONLY; 01215 /* ... and DB_WRITECURSOR won't be needed ... */ 01216 dbi->dbi_oflags |= DB_RDONLY; 01217 } 01218 01219 } else { /* dbhome is writable, check for persistent dbenv. */ 01220 /*@-mods@*/ 01221 const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL); 01222 /*@=mods@*/ 01223 01224 if (access(dbf, F_OK) == -1) { 01225 /* ... non-existent (or unwritable) DBENV, will create ... */ 01226 dbi->dbi_oeflags |= DB_CREATE; 01227 dbi->dbi_eflags &= ~DB_JOINENV; 01228 } else { 01229 /* ... pre-existent (or bogus) DBENV, will join ... */ 01230 if (dbi->dbi_eflags & DB_PRIVATE) { 01231 dbi->dbi_eflags &= ~DB_JOINENV; 01232 } else { 01233 dbi->dbi_eflags |= DB_JOINENV; 01234 dbi->dbi_oeflags &= ~DB_CREATE; 01235 dbi->dbi_oeflags &= ~DB_THREAD; 01236 } 01237 } 01238 dbf = _free(dbf); 01239 } 01240 } 01241 01242 /* 01243 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open. 01244 */ 01245 if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) { 01246 /* dbhome is writable, and DB->open flags may conflict. */ 01247 const char * dbfn = (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)); 01248 /*@-mods@*/ 01249 const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL); 01250 /*@=mods@*/ 01251 01252 if (access(dbf, F_OK) == -1) { 01253 /* File does not exist, DB->open might create ... */ 01254 oflags &= ~DB_RDONLY; 01255 } else { 01256 /* File exists, DB->open need not create ... */ 01257 oflags &= ~DB_CREATE; 01258 } 01259 01260 /* Only writers need DB_WRITECURSOR ... */ 01261 if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) { 01262 dbi->dbi_oflags &= ~DB_RDONLY; 01263 } else { 01264 dbi->dbi_oflags |= DB_RDONLY; 01265 } 01266 dbf = _free(dbf); 01267 } 01268 01269 /* 01270 * Set db type if creating. 01271 */ 01272 if (oflags & DB_CREATE) 01273 dbi_type = dbi->dbi_type; 01274 01275 /* 01276 * Turn off verify-on-close if opening read-only. 01277 */ 01278 if (oflags & DB_RDONLY) 01279 dbi->dbi_verify_on_close = 0; 01280 01281 /*@-branchstate@*/ 01282 if (dbi->dbi_use_dbenv) { 01283 /*@-mods@*/ 01284 if (rpmdb->db_dbenv == NULL) { 01285 static int runrecoverycount = 0; 01286 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 01287 switch (rc) { 01288 default: 01289 break; 01290 01291 case DB_RUNRECOVERY: 01292 if (runrecoverycount++ >= 1) { 01293 rpmlog(RPMLOG_ERR, _("RUNRECOVERY failed, exiting ...\n")); 01294 exit(EXIT_FAILURE); 01295 } 01296 rpmError(RPMERR_DBERR, _("Runnning db->verify ...\n")); 01297 rpmdb = rpmdbLink(rpmdb, "DB_RUNRECOVERY"); 01298 rpmdb->db_remove_env = 1; 01299 rpmdb->db_verifying = 1; 01300 xx = rpmdbVerifyAllDBI(rpmdb); 01301 xx = cvtdberr(dbi, "db->verify", xx, _debug); 01302 rpmdb->db_remove_env = 0; 01303 rpmdb->db_verifying = 0; 01304 01305 dbi->dbi_oeflags |= DB_CREATE; 01306 dbi->dbi_eflags &= ~DB_JOINENV; 01307 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 01308 /* XXX db_init EINVAL was masked. */ 01309 rc = cvtdberr(dbi, "dbenv->open", rc, _debug); 01310 if (rc) 01311 break; 01312 01313 assert(dbenv); 01314 rpmdb->db_dbenv = dbenv; 01315 rpmdb->db_opens = 1; 01316 break; 01317 01318 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */ 01319 case DB_VERSION_MISMATCH: 01320 #endif 01321 case EINVAL: 01322 if (getuid() != 0) 01323 break; 01324 { char * filename = alloca(BUFSIZ); 01325 struct stat st; 01326 int i; 01327 01328 for (i = 0; i < 16; i++) { 01329 sprintf(filename, "%s/__db.%03d", dbhome, i); 01330 (void)rpmCleanPath(filename); 01331 if (Stat(filename, &st) 01332 && (errno == ENOENT || errno == EINVAL)) 01333 continue; 01334 xx = Unlink(filename); 01335 } 01336 } 01337 dbi->dbi_oeflags |= DB_CREATE; 01338 dbi->dbi_eflags &= ~DB_JOINENV; 01339 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 01340 /* XXX db_init EINVAL was masked. */ 01341 rc = cvtdberr(dbi, "dbenv->open", rc, _debug); 01342 if (rc) 01343 break; 01344 /*@fallthrough@*/ 01345 case 0: 01346 assert(dbenv); 01347 rpmdb->db_dbenv = dbenv; 01348 rpmdb->db_opens = 1; 01349 break; 01350 } 01351 } else { 01352 assert(rpmdb && rpmdb->db_dbenv); 01353 dbenv = rpmdb->db_dbenv; 01354 rpmdb->db_opens++; 01355 } 01356 /*@=mods@*/ 01357 } 01358 /*@=branchstate@*/ 01359 01360 rpmMessage(RPMMESS_DEBUG, D_("opening db index %s/%s %s mode=0x%x\n"), 01361 dbhome, (dbfile ? dbfile : mapTagName(dbi->dbi_rpmtag)), 01362 prDbiOpenFlags(oflags, 0), dbi->dbi_mode); 01363 01364 if (rc == 0) { 01365 static int _lockdbfd = 0; 01366 01367 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01368 rc = db_create(&db, dbenv, dbi->dbi_cflags); 01369 /*@=moduncon@*/ 01370 rc = cvtdberr(dbi, "db_create", rc, _debug); 01371 if (rc == 0 && db != NULL) { 01372 01373 /* XXX 3.3.4 change. */ 01374 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3) || (DB_VERSION_MAJOR == 4) 01375 if (rc == 0 && 01376 rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free) 01377 { 01378 rc = db->set_alloc(db, 01379 rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free); 01380 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug); 01381 } 01382 #else 01383 if (rc == 0 && rpmdb->db_malloc) { 01384 rc = db->set_malloc(db, rpmdb->db_malloc); 01385 rc = cvtdberr(dbi, "db->set_malloc", rc, _debug); 01386 } 01387 #endif 01388 01389 /* 4.1: db->set_cache_priority(???) */ 01390 if (rc == 0 && !dbi->dbi_use_dbenv && dbi->dbi_cachesize) { 01391 rc = db->set_cachesize(db, 0, dbi->dbi_cachesize, 0); 01392 rc = cvtdberr(dbi, "db->set_cachesize", rc, _debug); 01393 } 01394 /* 4.1: db->set_encrypt(???) */ 01395 /* 4.1: db->set_errcall(dbenv, rpmdb->db_errcall); */ 01396 /* 4.1: db->set_errfile(dbenv, rpmdb->db_errfile); */ 01397 /* 4.1: db->set_errpfx(dbenv, rpmdb->db_errpfx); */ 01398 /* 4.1: db->set_feedback(???) */ 01399 01400 if (rc == 0 && dbi->dbi_lorder) { 01401 rc = db->set_lorder(db, dbi->dbi_lorder); 01402 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug); 01403 } 01404 if (rc == 0 && dbi->dbi_pagesize) { 01405 rc = db->set_pagesize(db, dbi->dbi_pagesize); 01406 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug); 01407 } 01408 /* 4.1: db->set_paniccall(???) */ 01409 if (rc == 0 && oflags & DB_CREATE) { 01410 switch(dbi->dbi_type) { 01411 default: 01412 case DB_HASH: 01413 if (dbi->dbi_h_ffactor) { 01414 rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor); 01415 rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug); 01416 if (rc) break; 01417 } 01418 if (dbi->dbi_h_nelem) { 01419 rc = db->set_h_nelem(db, dbi->dbi_h_nelem); 01420 rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug); 01421 if (rc) break; 01422 } 01423 if (dbi->dbi_h_flags) { 01424 rc = db->set_flags(db, dbi->dbi_h_flags); 01425 rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug); 01426 if (rc) break; 01427 } 01428 /* XXX db-3.2.9 has added a DB arg to the call. */ 01429 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4) 01430 if (dbi->dbi_h_hash_fcn) { 01431 rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn); 01432 rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug); 01433 if (rc) break; 01434 } 01435 if (dbi->dbi_h_dup_compare_fcn) { 01436 rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn); 01437 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); 01438 if (rc) break; 01439 } 01440 #endif 01441 break; 01442 case DB_BTREE: 01443 /* 4.1: db->set_append_recno(???) */ 01444 if (dbi->dbi_bt_flags) { 01445 rc = db->set_flags(db, dbi->dbi_bt_flags); 01446 rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug); 01447 if (rc) break; 01448 } 01449 if (dbi->dbi_bt_minkey) { 01450 rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey); 01451 rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug); 01452 if (rc) break; 01453 } 01454 /* XXX db-3.2.9 has added a DB arg to the call. */ 01455 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR > 2) || (DB_VERSION_MAJOR == 4) 01456 if (dbi->dbi_bt_compare_fcn) { 01457 rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn); 01458 rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug); 01459 if (rc) break; 01460 } 01461 if (dbi->dbi_bt_dup_compare_fcn) { 01462 rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn); 01463 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); 01464 if (rc) break; 01465 } 01466 if (dbi->dbi_bt_prefix_fcn) { 01467 rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn); 01468 rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug); 01469 if (rc) break; 01470 } 01471 #endif 01472 break; 01473 case DB_RECNO: 01474 if (dbi->dbi_re_delim) { 01475 /* 4.1: db->set_append_recno(???) */ 01476 rc = db->set_re_delim(db, dbi->dbi_re_delim); 01477 rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug); 01478 if (rc) break; 01479 } 01480 if (dbi->dbi_re_len) { 01481 rc = db->set_re_len(db, dbi->dbi_re_len); 01482 rc = cvtdberr(dbi, "db->set_re_len", rc, _debug); 01483 if (rc) break; 01484 } 01485 if (dbi->dbi_re_pad) { 01486 rc = db->set_re_pad(db, dbi->dbi_re_pad); 01487 rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug); 01488 if (rc) break; 01489 } 01490 if (dbi->dbi_re_source) { 01491 rc = db->set_re_source(db, dbi->dbi_re_source); 01492 rc = cvtdberr(dbi, "db->set_re_source", rc, _debug); 01493 if (rc) break; 01494 } 01495 break; 01496 case DB_QUEUE: 01497 if (dbi->dbi_q_extentsize) { 01498 rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize); 01499 rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug); 01500 if (rc) break; 01501 } 01502 break; 01503 } 01504 } 01505 01506 if (rc == 0) { 01507 const char * dbfullpath; 01508 const char * dbpath; 01509 char * t; 01510 int nb; 01511 01512 nb = strlen(dbhome); 01513 if (dbfile) nb += 1 + strlen(dbfile); 01514 dbfullpath = t = alloca(nb + 1); 01515 01516 /*@-boundswrite@*/ 01517 t = stpcpy(t, dbhome); 01518 if (dbfile) 01519 t = stpcpy( stpcpy( t, "/"), dbfile); 01520 /*@=boundswrite@*/ 01521 #ifdef HACK /* XXX necessary to support dbsubfile */ 01522 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary) 01523 ? dbfullpath : dbfile; 01524 #else 01525 dbpath = (!dbi->dbi_temporary) 01526 ? dbfullpath : dbfile; 01527 #endif 01528 01529 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1) 01530 rc = (db->open)(db, txnid, dbpath, dbsubfile, 01531 dbi_type, oflags, dbi->dbi_perms); 01532 #else 01533 rc = (db->open)(db, dbpath, dbsubfile, 01534 dbi_type, oflags, dbi->dbi_perms); 01535 #endif 01536 01537 if (rc == 0 && dbi_type == DB_UNKNOWN) { 01538 #if (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR == 3 && DB_VERSION_PATCH == 11) \ 01539 || (DB_VERSION_MAJOR == 4) 01540 xx = db->get_type(db, &dbi_type); 01541 if (xx == 0) 01542 dbi->dbi_type = dbi_type; 01543 #else 01544 dbi->dbi_type = db->get_type(db); 01545 #endif 01546 } 01547 } 01548 01549 /* XXX return rc == errno without printing */ 01550 _printit = (rc > 0 ? 0 : _debug); 01551 xx = cvtdberr(dbi, "db->open", rc, _printit); 01552 01553 dbi->dbi_txnid = NULL; 01554 01555 /* 01556 * Lock a file using fcntl(2). Traditionally this is Packages, 01557 * the file used to store metadata of installed header(s), 01558 * as Packages is always opened, and should be opened first, 01559 * for any rpmdb access. 01560 * 01561 * If no DBENV is used, then access is protected with a 01562 * shared/exclusive locking scheme, as always. 01563 * 01564 * With a DBENV, the fcntl(2) lock is necessary only to keep 01565 * the riff-raff from playing where they don't belong, as 01566 * the DBENV should provide it's own locking scheme. So try to 01567 * acquire a lock, but permit failures, as some other 01568 * DBENV player may already have acquired the lock. 01569 * 01570 * With NPTL posix mutexes, revert to fcntl lock on non-functioning 01571 * glibc/kernel combinations. 01572 */ 01573 if (rc == 0 && dbi->dbi_lockdbfd && 01574 !((dbi->dbi_ecflags & DB_CLIENT) && dbi->dbi_host) && 01575 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0)) 01576 { 01577 int fdno = -1; 01578 01579 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) { 01580 rc = 1; 01581 } else { 01582 struct flock l; 01583 /*@-boundswrite@*/ 01584 memset(&l, 0, sizeof(l)); 01585 /*@=boundswrite@*/ 01586 l.l_whence = 0; 01587 l.l_start = 0; 01588 l.l_len = 0; 01589 l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY)) 01590 ? F_WRLCK : F_RDLCK; 01591 l.l_pid = 0; 01592 01593 rc = fcntl(fdno, F_SETLK, (void *) &l); 01594 if (rc) { 01595 /* Warning iff using non-private CDB locking. */ 01596 rc = ((dbi->dbi_use_dbenv && 01597 (dbi->dbi_eflags & DB_INIT_CDB) && 01598 !(dbi->dbi_eflags & DB_PRIVATE)) 01599 ? 0 : 1); 01600 rpmError( (rc ? RPMERR_FLOCK : RPMWARN_FLOCK), 01601 _("cannot get %s lock on %s/%s\n"), 01602 ((dbi->dbi_mode & (O_RDWR|O_WRONLY)) 01603 ? _("exclusive") : _("shared")), 01604 dbhome, (dbfile ? dbfile : "")); 01605 } else if (dbfile) { 01606 rpmMessage(RPMMESS_DEBUG, 01607 D_("locked db index %s/%s\n"), 01608 dbhome, dbfile); 01609 } 01610 } 01611 } 01612 } 01613 } 01614 01615 dbi->dbi_db = db; 01616 01617 if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) { 01618 dbi->dbi_vec = &db3vec; 01619 /*@-boundswrite@*/ 01620 *dbip = dbi; 01621 /*@=boundswrite@*/ 01622 } else { 01623 dbi->dbi_verify_on_close = 0; 01624 (void) db3close(dbi, 0); 01625 } 01626 01627 urlfn = _free(urlfn); 01628 01629 /*@-nullstate -compmempass@*/ 01630 return rc; 01631 /*@=nullstate =compmempass@*/ 01632 } 01633 01636 /*@-exportheadervar@*/ 01637 /*@observer@*/ /*@unchecked@*/ 01638 struct _dbiVec db3vec = { 01639 DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, 01640 db3open, db3close, db3sync, db3associate, db3join, 01641 db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount, 01642 db3byteswapped, db3stat 01643 }; 01644 /*@=exportheadervar@*/ 01645 /*@=type@*/