|
rpm
5.4.4
|
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 <rpmlog.h> 00016 #include <rpmmacro.h> 00017 #include <rpmbf.h> 00018 #include <rpmpgp.h> /* XXX pgpExtractPubkeyFingerprint */ 00019 #include <rpmurl.h> /* XXX urlPath proto */ 00020 00021 #define _RPMTAG_INTERNAL 00022 #include <rpmtag.h> 00023 00024 #define _RPMEVR_INTERNAL /* XXX isInstallPrereq */ 00025 #include <rpmevr.h> 00026 00027 #define _RPMDB_INTERNAL 00028 #include <rpmdb.h> 00029 00030 #include "debug.h" 00031 00032 #ifdef NOTYET /* XXX syscall ACID needs --with-db=internal */ 00033 extern int logio_dispatch(DB_ENV * dbenv, DBT * dbt, DB_LSN * lsn, db_recops op) 00034 /*@*/; 00035 #endif 00036 00037 #define DBIDEBUG(_dbi, _list) if ((_dbi)->dbi_debug) fprintf _list 00038 00039 /*@access rpmdb @*/ 00040 /*@access dbiIndex @*/ 00041 /*@access dbiIndexSet @*/ 00042 00043 /*@-redef@*/ 00044 union _dbswap { 00045 uint64_t ul; 00046 uint32_t ui; 00047 uint16_t us; 00048 uint8_t uc[8]; 00049 }; 00050 /*@=redef@*/ 00051 /*@unchecked@*/ 00052 static union _dbswap _endian = { .ui = 0x11223344 }; 00053 00054 static inline uint64_t _ntoh_ul(uint64_t ul) 00055 /*@*/ 00056 { 00057 union _dbswap _a; 00058 _a.ul = ul; 00059 if (_endian.uc[0] == 0x44) { 00060 uint8_t _b, *_c = _a.uc; \ 00061 _b = _c[7]; _c[7] = _c[0]; _c[0] = _b; \ 00062 _b = _c[6]; _c[6] = _c[1]; _c[1] = _b; \ 00063 _b = _c[5]; _c[5] = _c[2]; _c[2] = _b; \ 00064 _b = _c[4]; _c[4] = _c[3]; _c[3] = _b; \ 00065 } 00066 return _a.ul; 00067 } 00068 static inline uint64_t _hton_ul(uint64_t ul) 00069 /*@*/ 00070 { 00071 return _ntoh_ul(ul); 00072 } 00073 00074 static inline uint32_t _ntoh_ui(uint32_t ui) 00075 /*@*/ 00076 { 00077 union _dbswap _a; 00078 _a.ui = ui; 00079 if (_endian.uc[0] == 0x44) { 00080 uint8_t _b, *_c = _a.uc; \ 00081 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \ 00082 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \ 00083 } 00084 return _a.ui; 00085 } 00086 static inline uint32_t _hton_ui(uint32_t ui) 00087 /*@*/ 00088 { 00089 return _ntoh_ui(ui); 00090 } 00091 00092 static inline uint16_t _ntoh_us(uint16_t us) 00093 /*@*/ 00094 { 00095 union _dbswap _a; 00096 _a.us = us; 00097 if (_endian.uc[0] == 0x44) { 00098 uint8_t _b, *_c = _a.uc; \ 00099 _b = _c[1]; _c[1] = _c[0]; _c[0] = _b; \ 00100 } 00101 return _a.us; 00102 } 00103 static inline uint16_t _hton_us(uint16_t us) 00104 /*@*/ 00105 { 00106 return _ntoh_us(us); 00107 } 00108 00109 #ifdef NOTNOW 00110 static const char * bfstring(unsigned int x, const char * xbf) 00111 { 00112 const char * s = xbf; 00113 static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 00114 static char buf[BUFSIZ]; 00115 char * t, * te; 00116 unsigned radix; 00117 unsigned c, i, k; 00118 00119 radix = (s != NULL ? *s++ : 16); 00120 00121 if (radix <= 1 || radix >= 32) 00122 radix = 16; 00123 00124 t = buf; 00125 switch (radix) { 00126 case 8: *t++ = '0'; break; 00127 case 16: *t++ = '0'; *t++ = 'x'; break; 00128 } 00129 00130 i = 0; 00131 k = x; 00132 do { i++; k /= radix; } while (k); 00133 00134 te = t + i; 00135 00136 k = x; 00137 do { --i; t[i] = digits[k % radix]; k /= radix; } while (k); 00138 00139 t = te; 00140 i = '<'; 00141 if (s != NULL) 00142 while ((c = *s++) != '\0') { 00143 if (c > ' ') continue; 00144 00145 k = (1 << (c - 1)); 00146 if (!(x & k)) continue; 00147 00148 if (t == te) *t++ = '='; 00149 00150 *t++ = i; 00151 i = ','; 00152 while (*s > ' ') 00153 *t++ = *s++; 00154 } 00155 if (t > te) *t++ = '>'; 00156 *t = '\0'; 00157 return buf; 00158 } 00159 00160 /* XXX checked with db-4.5.20 */ 00161 static const char * dbtFlags = 00162 "\20\1APPMALLOC\2ISSET\3MALLOC\4PARTIAL\5REALLOC\6USERMEM\7DUPOK"; 00163 00164 static const char * dbenvOpenFlags = 00165 "\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"; 00166 00167 static const char * dbOpenFlags = 00168 "\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"; 00169 00170 static const char * dbenvSetFlags = 00171 "\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"; 00172 00173 static const char * dbSetFlags = 00174 "\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"; 00175 00176 static const char * dbiModeFlags = 00177 "\20\1WRONLY\2RDWR\7CREAT\10EXCL\11NOCTTY\12TRUNC\13APPEND\14NONBLOCK\15SYNC\16ASYNC\17DIRECT\20LARGEFILE\21DIRECTORY\22NOFOLLOW"; 00178 #endif /* NOTNOW */ 00179 00180 /*@-redef@*/ 00181 typedef struct key_s { 00182 uint32_t v; 00183 /*@observer@*/ 00184 const char *n; 00185 } KEY; 00186 /*@=redef@*/ 00187 00188 /*@observer@*/ 00189 static const char * tblName(uint32_t v, KEY * tbl, size_t ntbl) 00190 /*@*/ 00191 { 00192 const char * n = NULL; 00193 static char buf[32]; 00194 size_t i; 00195 00196 for (i = 0; i < ntbl; i++) { 00197 if (v != tbl[i].v) 00198 continue; 00199 n = tbl[i].n; 00200 break; 00201 } 00202 if (n == NULL) { 00203 (void) snprintf(buf, sizeof(buf), "0x%x", (unsigned)v); 00204 n = buf; 00205 } 00206 return n; 00207 } 00208 00209 static const char * fmtBits(uint32_t flags, KEY tbl[], size_t ntbl, char *t) 00210 /*@modifies t @*/ 00211 { 00212 char pre = '<'; 00213 char * te = t; 00214 int i; 00215 00216 sprintf(t, "0x%x", (unsigned)flags); 00217 te = t; 00218 te += strlen(te); 00219 for (i = 0; i < 32; i++) { 00220 uint32_t mask = (1 << i); 00221 const char * name; 00222 00223 if (!(flags & mask)) 00224 continue; 00225 00226 name = tblName(mask, tbl, ntbl); 00227 *te++ = pre; 00228 pre = ','; 00229 te = stpcpy(te, name); 00230 } 00231 if (pre == ',') *te++ = '>'; 00232 *te = '\0'; 00233 return t; 00234 } 00235 00236 #define _ENTRY(_v) { DB_##_v, #_v, } 00237 00238 /*@unchecked@*/ /*@observer@*/ 00239 static KEY DBeflags[] = { 00240 _ENTRY(INIT_CDB), 00241 _ENTRY(INIT_LOCK), 00242 _ENTRY(INIT_LOG), 00243 _ENTRY(INIT_MPOOL), 00244 _ENTRY(INIT_MUTEX), /* XXX not in DBENV->open() doco */ 00245 _ENTRY(INIT_REP), 00246 _ENTRY(INIT_TXN), 00247 _ENTRY(RECOVER), 00248 _ENTRY(RECOVER_FATAL), 00249 _ENTRY(USE_ENVIRON), 00250 _ENTRY(USE_ENVIRON_ROOT), 00251 _ENTRY(CREATE), 00252 _ENTRY(LOCKDOWN), 00253 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5) 00254 _ENTRY(FAILCHK), 00255 #endif 00256 _ENTRY(PRIVATE), 00257 _ENTRY(REGISTER), 00258 _ENTRY(SYSTEM_MEM), 00259 _ENTRY(THREAD), 00260 }; 00261 /*@unchecked@*/ 00262 static size_t nDBeflags = sizeof(DBeflags) / sizeof(DBeflags[0]); 00263 /*@observer@*/ 00264 static const char * fmtDBeflags(uint32_t flags) 00265 /*@*/ 00266 { 00267 static char buf[BUFSIZ]; 00268 char * te = buf; 00269 te = stpcpy(te, "\n\tflags: "); 00270 (void) fmtBits(flags, DBeflags, nDBeflags, te); 00271 return buf; 00272 } 00273 #define _EFLAGS(_eflags) fmtDBeflags(_eflags) 00274 00275 /*@unchecked@*/ /*@observer@*/ 00276 static KEY DBoflags[] = { 00277 _ENTRY(AUTO_COMMIT), 00278 _ENTRY(CREATE), 00279 _ENTRY(EXCL), 00280 _ENTRY(MULTIVERSION), 00281 _ENTRY(NOMMAP), 00282 _ENTRY(RDONLY), 00283 _ENTRY(READ_UNCOMMITTED), 00284 _ENTRY(THREAD), 00285 _ENTRY(TRUNCATE), 00286 }; 00287 /*@unchecked@*/ 00288 static size_t nDBoflags = sizeof(DBoflags) / sizeof(DBoflags[0]); 00289 /*@observer@*/ 00290 static const char * fmtDBoflags(uint32_t flags) 00291 /*@*/ 00292 { 00293 static char buf[BUFSIZ]; 00294 char * te = buf; 00295 te = stpcpy(te, "\n\tflags: "); 00296 (void) fmtBits(flags, DBoflags, nDBoflags, te); 00297 return buf; 00298 } 00299 #define _OFLAGS(_oflags) fmtDBoflags(_oflags) 00300 00301 /*@unchecked@*/ /*@observer@*/ 00302 static KEY DBaflags[] = { 00303 _ENTRY(CREATE), 00304 _ENTRY(IMMUTABLE_KEY), 00305 }; 00306 /*@unchecked@*/ 00307 static size_t nDBaflags = sizeof(DBaflags) / sizeof(DBaflags[0]); 00308 /*@observer@*/ 00309 static const char * fmtDBaflags(uint32_t flags) 00310 /*@*/ 00311 { 00312 static char buf[BUFSIZ]; 00313 char * te = buf; 00314 te = stpcpy(te, "\n\tflags: "); 00315 (void) fmtBits(flags, DBaflags, nDBaflags, te); 00316 return buf; 00317 } 00318 #define _AFLAGS(_aflags) fmtDBaflags(_aflags) 00319 00320 /*@unchecked@*/ /*@observer@*/ 00321 static KEY DBafflags[] = { 00322 _ENTRY(FOREIGN_ABORT), 00323 _ENTRY(FOREIGN_CASCADE), 00324 _ENTRY(FOREIGN_NULLIFY), 00325 }; 00326 /*@unchecked@*/ 00327 static size_t nDBafflags = sizeof(DBafflags) / sizeof(DBafflags[0]); 00328 /*@observer@*/ 00329 static const char * fmtDBafflags(uint32_t flags) 00330 /*@*/ 00331 { 00332 static char buf[BUFSIZ]; 00333 char * te = buf; 00334 te = stpcpy(te, "\n\tflags: "); 00335 (void) fmtBits(flags, DBafflags, nDBafflags, te); 00336 return buf; 00337 } 00338 #define _AFFLAGS(_afflags) fmtDBafflags(_afflags) 00339 00340 /*@unchecked@*/ /*@observer@*/ 00341 static KEY DBCoflags[] = { 00342 /* XXX DB->cursor() doco for db-5.1.19 lists, undef'd */ 00343 #if defined(DB_CURSOR_BULK) 00344 _ENTRY(CURSOR_BULK), 00345 #endif 00346 _ENTRY(READ_COMMITTED), 00347 _ENTRY(READ_UNCOMMITTED), 00348 _ENTRY(WRITECURSOR), 00349 _ENTRY(TXN_SNAPSHOT), 00350 }; 00351 /*@unchecked@*/ 00352 static size_t nDBCoflags = sizeof(DBCoflags) / sizeof(DBCoflags[0]); 00353 /*@observer@*/ 00354 static const char * fmtDBCoflags(uint32_t flags) 00355 /*@*/ 00356 { 00357 static char buf[BUFSIZ]; 00358 char * te = buf; 00359 (void) fmtBits(flags, DBCoflags, nDBCoflags, te); 00360 return buf; 00361 } 00362 #define _DBCOFLAGS(_coflags) fmtDBCoflags(_coflags) 00363 00364 /*@unchecked@*/ /*@observer@*/ 00365 static KEY DBCflags[] = { 00366 _ENTRY(AFTER), /* Dbc.put */ 00367 _ENTRY(APPEND), /* Db.put */ 00368 _ENTRY(BEFORE), /* Dbc.put */ 00369 _ENTRY(CONSUME), /* Db.get */ 00370 _ENTRY(CONSUME_WAIT), /* Db.get */ 00371 _ENTRY(CURRENT), /* Dbc.get, Dbc.put, DbLogc.get */ 00372 _ENTRY(FIRST), /* Dbc.get, DbLogc->get */ 00373 _ENTRY(GET_BOTH), /* Db.get, Dbc.get */ 00374 _ENTRY(GET_BOTHC), /* Dbc.get (internal) */ 00375 _ENTRY(GET_BOTH_RANGE), /* Db.get, Dbc.get */ 00376 _ENTRY(GET_RECNO), /* Dbc.get */ 00377 _ENTRY(JOIN_ITEM), /* Dbc.get; don't do primary lookup */ 00378 _ENTRY(KEYFIRST), /* Dbc.put */ 00379 _ENTRY(KEYLAST), /* Dbc.put */ 00380 _ENTRY(LAST), /* Dbc.get, DbLogc->get */ 00381 _ENTRY(NEXT), /* Dbc.get, DbLogc->get */ 00382 _ENTRY(NEXT_DUP), /* Dbc.get */ 00383 _ENTRY(NEXT_NODUP), /* Dbc.get */ 00384 _ENTRY(NODUPDATA), /* Db.put, Dbc.put */ 00385 _ENTRY(NOOVERWRITE), /* Db.put */ 00386 _ENTRY(NOSYNC), /* Db.close */ 00387 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5) 00388 _ENTRY(OVERWRITE_DUP), /* Dbc.put, Db.put; no DB_KEYEXIST */ 00389 #endif 00390 _ENTRY(POSITION), /* Dbc.dup */ 00391 _ENTRY(PREV), /* Dbc.get, DbLogc->get */ 00392 _ENTRY(PREV_DUP), /* Dbc.get */ 00393 _ENTRY(PREV_NODUP), /* Dbc.get */ 00394 _ENTRY(SET), /* Dbc.get, DbLogc->get */ 00395 _ENTRY(SET_RANGE), /* Dbc.get */ 00396 _ENTRY(SET_RECNO), /* Db.get, Dbc.get */ 00397 _ENTRY(UPDATE_SECONDARY), /* Dbc.get, Dbc.del (internal) */ 00398 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5) 00399 _ENTRY(SET_LTE), /* Dbc.get (internal) */ 00400 _ENTRY(GET_BOTH_LTE), /* Dbc.get (internal) */ 00401 #endif 00402 00403 _ENTRY(IGNORE_LEASE), 00404 _ENTRY(READ_COMMITTED), 00405 _ENTRY(READ_UNCOMMITTED), 00406 _ENTRY(MULTIPLE), 00407 _ENTRY(MULTIPLE_KEY), 00408 _ENTRY(RMW), 00409 }; 00410 /*@unchecked@*/ 00411 static size_t nDBCflags = sizeof(DBCflags) / sizeof(DBCflags[0]); 00412 /*@observer@*/ 00413 static const char * fmtDBCflags(uint32_t flags) 00414 /*@*/ 00415 { 00416 static char buf[BUFSIZ]; 00417 char * te = buf; 00418 uint32_t op = (flags & DB_OPFLAGS_MASK); 00419 flags &= ~DB_OPFLAGS_MASK; 00420 00421 te = stpcpy(te, "\n\tflags: "); 00422 if (op) { 00423 te = stpcpy( stpcpy(te, "DB_"), tblName(op, DBCflags, nDBCflags)); 00424 *te++ = ' '; 00425 *te = '\0'; 00426 } 00427 if (flags) 00428 (void) fmtBits(flags, DBCflags, nDBCflags, te); 00429 return buf; 00430 } 00431 #define _DBCFLAGS(_flags) fmtDBCflags(_flags) 00432 00433 #define _DBT_ENTRY(_v) { DB_DBT_##_v, #_v, } 00434 /*@unchecked@*/ /*@observer@*/ 00435 static KEY DBTflags[] = { 00436 _DBT_ENTRY(MALLOC), 00437 _DBT_ENTRY(REALLOC), 00438 _DBT_ENTRY(USERMEM), 00439 _DBT_ENTRY(PARTIAL), 00440 _DBT_ENTRY(APPMALLOC), 00441 _DBT_ENTRY(MULTIPLE), 00442 #if defined(DB_DBT_READONLY) /* XXX db-5.2.28 */ 00443 _DBT_ENTRY(READONLY), 00444 #endif 00445 }; 00446 /*@unchecked@*/ 00447 static size_t nDBTflags = sizeof(DBTflags) / sizeof(DBTflags[0]); 00448 /*@observer@*/ 00449 static char * fmtDBT(const DBT * K, char * te) 00450 /*@modifies te @*/ 00451 { 00452 static size_t keymax = 35; 00453 int unprintable; 00454 uint32_t i; 00455 00456 sprintf(te, "%p[%u]\t", K->data, (unsigned)K->size); 00457 te += strlen(te); 00458 (void) fmtBits(K->flags, DBTflags, nDBTflags, te); 00459 te += strlen(te); 00460 if (K->data && K->size > 0) { 00461 uint8_t * _u; 00462 size_t _nu; 00463 00464 /* Grab the key data/size. */ 00465 if (K->flags & DB_DBT_MULTIPLE) { 00466 DBT * _K = K->data; 00467 _u = _K->data; 00468 _nu = _K->size; 00469 } else { 00470 _u = K->data; 00471 _nu = K->size; 00472 } 00473 /* Verify if data is a string. */ 00474 unprintable = 0; 00475 for (i = 0; i < _nu; i++) 00476 unprintable |= !xisprint(_u[i]); 00477 00478 /* Display the data. */ 00479 if (!unprintable) { 00480 size_t nb = (_nu < keymax ? _nu : keymax); 00481 char * ellipsis = (_nu < keymax ? "" : "..."); 00482 sprintf(te, "\t\"%.*s%s\"", (int)nb, (char *)_u, ellipsis); 00483 } else { 00484 switch (_nu) { 00485 default: break; 00486 case 4: sprintf(te, "\t0x%08x", (unsigned)*(uint32_t *)_u); break; 00487 } 00488 } 00489 00490 te += strlen(te); 00491 *te = '\0'; 00492 } 00493 return te; 00494 } 00495 /*@observer@*/ 00496 static const char * fmtKDR(const DBT * K, const DBT * P, const DBT * D, const DBT * R) 00497 /*@*/ 00498 { 00499 static char buf[BUFSIZ]; 00500 char * te = buf; 00501 00502 if (K) { 00503 te = stpcpy(te, "\n\t key: "); 00504 te = fmtDBT(K, te); 00505 } 00506 if (P) { 00507 te = stpcpy(te, "\n\t pkey: "); 00508 te = fmtDBT(P, te); 00509 } 00510 if (D) { 00511 te = stpcpy(te, "\n\t data: "); 00512 te = fmtDBT(D, te); 00513 } 00514 if (R) { 00515 te = stpcpy(te, "\n\t res: "); 00516 te = fmtDBT(R, te); 00517 } 00518 *te = '\0'; 00519 00520 return buf; 00521 } 00522 #define _KEYDATA(_K, _P, _D, _R) fmtKDR(_K, _P, _D, _R) 00523 00524 #undef _ENTRY 00525 00526 /*@-globuse -mustmod @*/ /* FIX: rpmError not annotated yet. */ 00527 static int Xcvtdberr(/*@unused@*/ dbiIndex dbi, const char * msg, 00528 int error, int printit, 00529 const char * func, const char * fn, unsigned ln) 00530 /*@globals fileSystem @*/ 00531 /*@modifies fileSystem @*/ 00532 { 00533 int rc = error; 00534 00535 if (printit && rc) { 00536 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00537 rpmlog(RPMLOG_ERR, "%s:%s:%u: %s(%d): %s\n", 00538 func, fn, ln, msg, rc, db_strerror(error)); 00539 /*@=moduncon@*/ 00540 } 00541 00542 return rc; 00543 } 00544 /*@=globuse =mustmod @*/ 00545 #define cvtdberr(_dbi, _msg, _error, _printit) \ 00546 Xcvtdberr(_dbi, _msg, _error, _printit, __FUNCTION__, __FILE__, __LINE__) 00547 00554 /*@observer@*/ 00555 static const char * mapTagName(rpmdb rpmdb, dbiIndex dbi) 00556 /*@*/ 00557 { 00558 tagStore_t dbiTags = rpmdb->db_tags; 00559 size_t dbix = 0; 00560 00561 if (dbiTags != NULL) 00562 while (dbix < rpmdb->db_ndbi) { 00563 if (dbi->dbi_rpmtag == dbiTags->tag) 00564 return dbiTags->str; 00565 dbiTags++; 00566 dbix++; 00567 } 00568 /* XXX should never reach here */ 00569 return tagName(dbi->dbi_rpmtag); 00570 } 00571 00572 static int db_fini(dbiIndex dbi, const char * dbhome, 00573 /*@null@*/ const char * dbfile, 00574 /*@unused@*/ /*@null@*/ const char * dbsubfile) 00575 /*@globals fileSystem @*/ 00576 /*@modifies fileSystem @*/ 00577 { 00578 rpmdb rpmdb = dbi->dbi_rpmdb; 00579 DB_ENV * dbenv = rpmdb->db_dbenv; 00580 int rc; 00581 00582 DBIDEBUG(dbi, (stderr, "--> %s(%p,%s,%s,%s)\n", __FUNCTION__, dbi, dbhome, dbfile, dbsubfile)); 00583 00584 if (dbenv == NULL) 00585 return 0; 00586 00587 rc = dbenv->close(dbenv, 0); 00588 rc = cvtdberr(dbi, "dbenv->close", rc, _debug); 00589 rpmdb->db_dbenv = NULL; 00590 00591 if (dbfile) 00592 rpmlog(RPMLOG_DEBUG, D_("closed db environment %s/%s\n"), 00593 dbhome, dbfile); 00594 00595 if (rpmdb->db_remove_env) { 00596 int xx; 00597 00598 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00599 xx = db_env_create(&dbenv, 0); 00600 /*@=moduncon@*/ 00601 if (!xx && dbenv != NULL) { 00602 xx = cvtdberr(dbi, "db_env_create", xx, _debug); 00603 xx = dbenv->remove(dbenv, dbhome, DB_FORCE); 00604 xx = cvtdberr(dbi, "dbenv->remove", xx, _debug); 00605 00606 if (dbfile) 00607 rpmlog(RPMLOG_DEBUG, D_("removed db environment %s/%s\n"), 00608 dbhome, dbfile); 00609 } 00610 00611 } 00612 return rc; 00613 } 00614 00615 static int db3_fsync_disable(/*@unused@*/ int fd) 00616 /*@*/ 00617 { 00618 return 0; 00619 } 00620 00621 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5) 00622 00630 static int db3is_alive(/*@unused@*/ DB_ENV *dbenv, pid_t pid, 00631 /*@unused@*/ db_threadid_t tid, 00632 rpmuint32_t flags) 00633 /*@*/ 00634 { 00635 int is_alive = 1; /* assume all processes are alive */ 00636 00637 switch (flags) { 00638 case DB_MUTEX_PROCESS_ONLY: 00639 case 0: 00640 default: 00641 is_alive = (!(kill(pid, 0) < 0 && errno == ESRCH)); 00642 break; 00643 } 00644 return is_alive; 00645 } 00646 #endif 00647 00648 /*==============================================================*/ 00649 00650 /* HAVE_SYS_SYSCTL_H */ 00651 #if defined(HAVE_PHYSMEM_SYSCTL) || defined(HAVE_NCPU_SYSCTL) 00652 #include <sys/sysctl.h> 00653 #endif 00654 00655 static uint64_t physmem(void) 00656 /*@*/ 00657 { 00658 static uint64_t _physmem = 0; 00659 static int oneshot = 0; 00660 00661 if (!oneshot) { 00662 #if defined(HAVE_PHYSMEM_SYSCONF) 00663 const long _pagesize = sysconf(_SC_PAGESIZE); 00664 const long _pages = sysconf(_SC_PHYS_PAGES); 00665 if (_pagesize != -1 || _pages != -1) 00666 _physmem = (uint64_t)(_pagesize) * (uint64_t)(_pages); 00667 #elif defined(HAVE_PHYSMEM_SYSCTL) 00668 int name[2] = { CTL_HW, HW_PHYSMEM }; 00669 unsigned long mem; 00670 size_t mem_ptr_size = sizeof(mem); 00671 if (!sysctl(name, 2, &mem, &mem_ptr_size, NULL, 0)) { 00672 if (mem_ptr_size != sizeof(mem)) { 00673 if (mem_ptr_size == sizeof(unsigned int)) 00674 _physmem = *(unsigned int *)(&mem); 00675 } else { 00676 _physmem = mem; 00677 } 00678 } 00679 #endif 00680 oneshot++; 00681 } 00682 return _physmem; 00683 } 00684 00685 static size_t ncores(void) 00686 /*@*/ 00687 { 00688 static size_t _ncores = 1; 00689 static int oneshot = 0; 00690 00691 if (!oneshot) { 00692 #if defined(HAVE_NCPU_SYSCONF) 00693 const long cpus = sysconf(_SC_NPROCESSORS_ONLN); 00694 #elif defined(HAVE_NCPU_SYSCTL) 00695 int name[2] = { CTL_HW, HW_NCPU }; 00696 int cpus = 0; 00697 size_t cpus_size = sizeof(cpus); 00698 if (sysctl(name, 2, &cpus, &cpus_size, NULL, 0) 00699 || cpus_size != sizeof(cpus)) 00700 cpus = 0; 00701 #endif 00702 if (cpus > (int)_ncores) 00703 _ncores = (size_t)(cpus); 00704 oneshot++; 00705 } 00706 return _ncores; 00707 } 00708 00709 /*==============================================================*/ 00710 #define _TABLE(_v) { #_v, DB_EVENT_##_v } 00711 static struct _events_s { 00712 const char * n; 00713 uint32_t v; 00714 } _events[] = { 00715 #if (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR == 2) 00716 _TABLE(PANIC), /* 0 */ 00717 _TABLE(REG_ALIVE), /* 1 */ 00718 _TABLE(REG_PANIC), /* 2 */ 00719 _TABLE(REP_CLIENT), /* 3 */ 00720 _TABLE(REP_CONNECT_BROKEN), /* 4 */ 00721 _TABLE(REP_CONNECT_ESTD), /* 5 */ 00722 _TABLE(REP_CONNECT_TRY_FAILED), /* 6 */ 00723 _TABLE(REP_DUPMASTER), /* 7 */ 00724 _TABLE(REP_ELECTED), /* 8 */ 00725 _TABLE(REP_ELECTION_FAILED),/* 9 */ 00726 _TABLE(REP_INIT_DONE), /* 10 */ 00727 _TABLE(REP_JOIN_FAILURE), /* 11 */ 00728 _TABLE(REP_LOCAL_SITE_REMOVED), /* 12 */ 00729 _TABLE(REP_MASTER), /* 13 */ 00730 _TABLE(REP_MASTER_FAILURE), /* 14 */ 00731 _TABLE(REP_NEWMASTER), /* 15 */ 00732 _TABLE(REP_PERM_FAILED), /* 16 */ 00733 _TABLE(REP_SITE_ADDED), /* 17 */ 00734 _TABLE(REP_SITE_REMOVED), /* 18 */ 00735 _TABLE(REP_STARTUPDONE), /* 19 */ 00736 _TABLE(REP_WOULD_ROLLBACK), /* 20 */ 00737 _TABLE(WRITE_FAILED), /* 21 */ 00738 _TABLE(NO_SUCH_EVENT), /* 22 */ 00739 _TABLE(NO_SUCH_EVENT), /* 23 */ 00740 _TABLE(NO_SUCH_EVENT), /* 24 */ 00741 _TABLE(NO_SUCH_EVENT), /* 25 */ 00742 _TABLE(NO_SUCH_EVENT), /* 26 */ 00743 _TABLE(NO_SUCH_EVENT), /* 27 */ 00744 _TABLE(NO_SUCH_EVENT), /* 28 */ 00745 _TABLE(NO_SUCH_EVENT), /* 29 */ 00746 _TABLE(NO_SUCH_EVENT), /* 30 */ 00747 _TABLE(NO_SUCH_EVENT), /* 31 */ 00748 #elif (DB_VERSION_MAJOR == 5 && DB_VERSION_MINOR < 2) 00749 /* XXX numbered from db-5.1.19, older versions are different. */ 00750 _TABLE(PANIC), /* 0 */ 00751 _TABLE(REG_ALIVE), /* 1 */ 00752 _TABLE(REG_PANIC), /* 2 */ 00753 _TABLE(REP_CLIENT), /* 3 */ 00754 _TABLE(REP_DUPMASTER), /* 4 */ 00755 _TABLE(REP_ELECTED), /* 5 */ 00756 _TABLE(REP_ELECTION_FAILED),/* 6 */ 00757 _TABLE(REP_JOIN_FAILURE), /* 7 */ 00758 _TABLE(REP_MASTER), /* 8 */ 00759 _TABLE(REP_MASTER_FAILURE), /* 9 */ 00760 _TABLE(REP_NEWMASTER), /* 10 */ 00761 _TABLE(REP_PERM_FAILED), /* 11 */ 00762 _TABLE(REP_STARTUPDONE), /* 12 */ 00763 _TABLE(WRITE_FAILED), /* 13 */ 00764 _TABLE(NO_SUCH_EVENT), /* 14 */ 00765 _TABLE(NO_SUCH_EVENT), /* 15 */ 00766 _TABLE(NO_SUCH_EVENT), /* 16 */ 00767 _TABLE(NO_SUCH_EVENT), /* 17 */ 00768 _TABLE(NO_SUCH_EVENT), /* 18 */ 00769 _TABLE(NO_SUCH_EVENT), /* 19 */ 00770 _TABLE(NO_SUCH_EVENT), /* 20 */ 00771 _TABLE(NO_SUCH_EVENT), /* 21 */ 00772 _TABLE(NO_SUCH_EVENT), /* 22 */ 00773 _TABLE(NO_SUCH_EVENT), /* 23 */ 00774 _TABLE(NO_SUCH_EVENT), /* 24 */ 00775 _TABLE(NO_SUCH_EVENT), /* 25 */ 00776 _TABLE(NO_SUCH_EVENT), /* 26 */ 00777 _TABLE(NO_SUCH_EVENT), /* 27 */ 00778 _TABLE(NO_SUCH_EVENT), /* 28 */ 00779 _TABLE(NO_SUCH_EVENT), /* 29 */ 00780 _TABLE(NO_SUCH_EVENT), /* 30 */ 00781 _TABLE(NO_SUCH_EVENT), /* 31 */ 00782 #else 00783 _TABLE(NO_SUCH_EVENT), /* 0 */ 00784 _TABLE(PANIC), /* 1 */ 00785 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) 00786 _TABLE(REG_ALIVE), /* 2 */ 00787 _TABLE(REG_PANIC), /* 3 */ 00788 #else 00789 _TABLE(NO_SUCH_EVENT), /* 2 */ 00790 _TABLE(NO_SUCH_EVENT), /* 3 */ 00791 #endif 00792 _TABLE(REP_CLIENT), /* 4 */ 00793 _TABLE(REP_ELECTED), /* 5 */ 00794 _TABLE(REP_MASTER), /* 6 */ 00795 _TABLE(REP_NEWMASTER), /* 7 */ 00796 _TABLE(REP_PERM_FAILED), /* 8 */ 00797 _TABLE(REP_STARTUPDONE), /* 9 */ 00798 _TABLE(WRITE_FAILED), /* 10 */ 00799 _TABLE(NO_SUCH_EVENT), /* 11 */ 00800 _TABLE(NO_SUCH_EVENT), /* 12 */ 00801 _TABLE(NO_SUCH_EVENT), /* 13 */ 00802 _TABLE(NO_SUCH_EVENT), /* 14 */ 00803 _TABLE(NO_SUCH_EVENT), /* 15 */ 00804 _TABLE(NO_SUCH_EVENT), /* 16 */ 00805 _TABLE(NO_SUCH_EVENT), /* 17 */ 00806 _TABLE(NO_SUCH_EVENT), /* 18 */ 00807 _TABLE(NO_SUCH_EVENT), /* 19 */ 00808 _TABLE(NO_SUCH_EVENT), /* 20 */ 00809 _TABLE(NO_SUCH_EVENT), /* 21 */ 00810 _TABLE(NO_SUCH_EVENT), /* 22 */ 00811 _TABLE(NO_SUCH_EVENT), /* 23 */ 00812 _TABLE(NO_SUCH_EVENT), /* 24 */ 00813 _TABLE(NO_SUCH_EVENT), /* 25 */ 00814 _TABLE(NO_SUCH_EVENT), /* 26 */ 00815 _TABLE(NO_SUCH_EVENT), /* 27 */ 00816 _TABLE(NO_SUCH_EVENT), /* 28 */ 00817 _TABLE(NO_SUCH_EVENT), /* 29 */ 00818 _TABLE(NO_SUCH_EVENT), /* 30 */ 00819 _TABLE(NO_SUCH_EVENT), /* 31 */ 00820 #endif 00821 }; 00822 #undef _TABLE 00823 00824 static void 00825 rpmdbe_event_notify(DB_ENV * dbenv, u_int32_t event, void * event_info) 00826 { 00827 void * o = (dbenv ? dbenv->app_private : NULL); 00828 fprintf(stderr, "==> %s(%p, %s(%u), %p) app_private %p\n", __FUNCTION__, dbenv, _events[event & 0x1f].n, event, event_info, o); 00829 } 00830 00831 static void 00832 rpmdbe_feedback(DB_ENV * dbenv, int opcode, int percent) 00833 /*@*/ 00834 { 00835 dbenv = NULL; 00836 dbenv = dbenv; 00837 switch (opcode) { 00838 case DB_RECOVER: 00839 fprintf(stderr, "\rrecovery %d%% complete", percent); 00840 (void)fflush(stderr); /* XXX unnecessary? */ 00841 /*@fallthrough@*/ 00842 default: 00843 break; 00844 } 00845 } 00846 00847 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 00848 static int db_init(dbiIndex dbi, const char * dbhome, 00849 /*@null@*/ const char * dbfile, 00850 /*@unused@*/ /*@null@*/ const char * dbsubfile, 00851 /*@out@*/ DB_ENV ** dbenvp) 00852 /*@globals rpmGlobalMacroContext, h_errno, 00853 fileSystem, internalState @*/ 00854 /*@modifies dbi, *dbenvp, fileSystem, internalState @*/ 00855 { 00856 static int oneshot = 0; 00857 uint64_t _physmem = physmem(); 00858 size_t _ncores = ncores(); 00859 rpmdb rpmdb = dbi->dbi_rpmdb; 00860 DB_ENV *dbenv = NULL; 00861 int eflags; 00862 int rc; 00863 int xx; 00864 00865 if (!oneshot) { 00866 rpmlog(RPMLOG_DEBUG, D_("rpmdb: cpus %u physmem %uMb\n"), 00867 (unsigned)_ncores, (unsigned)(_physmem/(1024 * 1024))); 00868 xx = db_env_set_func_open((int (*)(const char *, int, ...))Open); 00869 xx = cvtdberr(dbi, "db_env_set_func_open", xx, _debug); 00870 oneshot++; 00871 } 00872 00873 if (dbenvp == NULL) 00874 return 1; 00875 00876 /* XXX HACK */ 00877 /*@-assignexpose@*/ 00878 if (rpmdb->db_errfile == NULL) 00879 rpmdb->db_errfile = stderr; 00880 /*@=assignexpose@*/ 00881 00882 eflags = (dbi->dbi_oeflags | dbi->dbi_eflags); 00883 /* Try to join, rather than create, the environment. */ 00884 /* XXX DB_JOINENV is defined to 0 in db-4.5.20 */ 00885 if (eflags & DB_JOINENV) eflags &= DB_JOINENV; 00886 /* XXX DB_RECOVER needs automagic */ 00887 if (!(eflags & DB_INIT_TXN)) eflags &= ~DB_RECOVER; 00888 00889 if (dbfile) 00890 rpmlog(RPMLOG_DEBUG, D_("opening db environment %s/%s %s\n"), 00891 dbhome, dbfile, prDbiOpenFlags(eflags, 1)); 00892 00893 /* XXX Can't do RPC w/o host. */ 00894 #if defined(DB_RPCCLIENT) 00895 if (dbi->dbi_host == NULL) 00896 dbi->dbi_ecflags &= ~DB_RPCCLIENT; 00897 #endif 00898 00899 rc = db_env_create(&dbenv, dbi->dbi_ecflags); 00900 rc = cvtdberr(dbi, "db_env_create", rc, _debug); 00901 if (dbenv == NULL || rc) 00902 goto errxit; 00903 00904 /*@-noeffectuncon@*/ 00905 /*@-castfcnptr@*/ 00906 dbenv->set_errcall(dbenv, (void *)rpmdb->db_errcall); 00907 /*@=castfcnptr@*/ 00908 dbenv->set_errfile(dbenv, rpmdb->db_errfile); 00909 dbenv->set_errpfx(dbenv, rpmdb->db_errpfx); 00910 /*@=noeffectuncon@*/ 00911 00912 /* 4.1: dbenv->set_alloc(???) */ 00913 /* 4.1: dbenv->set_data_dir(???) */ 00914 /* 4.1: dbenv->set_encrypt(???) */ 00915 00916 xx = dbenv->set_feedback(dbenv, rpmdbe_feedback); 00917 xx = cvtdberr(dbi, "dbenv->set_feedback", xx, _debug); 00918 xx = dbenv->set_event_notify(dbenv, rpmdbe_event_notify); 00919 xx = cvtdberr(dbi, "dbenv->set_event_notify", xx, _debug); 00920 00921 /* 4.1: dbenv->set_flags(???) */ 00922 00923 /* dbenv->set_paniccall(???) */ 00924 00925 #if defined(DB_RPCCLIENT) 00926 if ((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) { 00927 const char * home; 00928 int retry = 0; 00929 00930 if ((home = strrchr(dbhome, '/')) != NULL) 00931 dbhome = ++home; 00932 00933 while (retry++ < 5) { 00934 /* XXX 3.3.4 change. */ 00935 xx = dbenv->set_rpc_server(dbenv, NULL, dbi->dbi_host, 00936 dbi->dbi_cl_timeout, dbi->dbi_sv_timeout, 0); 00937 xx = cvtdberr(dbi, "dbenv->set_server", xx, _debug); 00938 if (!xx) 00939 break; 00940 (void) sleep(15); 00941 } 00942 } else 00943 #endif 00944 { 00945 00946 { size_t _lo = 16 * 1024 * 1024; 00947 size_t _hi = 512 * 1024 * 1024; 00948 size_t _mp_mmapsize = _physmem; /* XXX default value? */ 00949 if (_mp_mmapsize < _lo) _mp_mmapsize = _lo; 00950 if (_mp_mmapsize > _hi) _mp_mmapsize = _hi; 00951 xx = dbenv->set_mp_mmapsize(dbenv, _mp_mmapsize); 00952 xx = cvtdberr(dbi, "dbenv->set_mp_mmapsize", xx, _debug); 00953 } 00954 00955 if (dbi->dbi_tmpdir) { 00956 const char * root; 00957 const char * tmpdir; 00958 00959 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 00960 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 00961 root = NULL; 00962 /*@-mods@*/ 00963 tmpdir = rpmGenPath(root, dbi->dbi_tmpdir, NULL); 00964 /*@=mods@*/ 00965 xx = dbenv->set_tmp_dir(dbenv, tmpdir); 00966 xx = cvtdberr(dbi, "dbenv->set_tmp_dir", xx, _debug); 00967 tmpdir = _free(tmpdir); 00968 } 00969 } 00970 00971 /* ==== Locking: */ 00972 #define _RPMDB_NLOCKS 16384 00973 if (eflags & DB_INIT_LOCK) { 00974 uint32_t _lk_max_lockers = _RPMDB_NLOCKS; 00975 uint32_t _lk_max_locks = _RPMDB_NLOCKS; 00976 uint32_t _lk_max_objects = _RPMDB_NLOCKS; 00977 00978 xx = dbenv->set_lk_max_lockers(dbenv, _lk_max_lockers); 00979 xx = cvtdberr(dbi, "dbenv->set_lk_max_lockers", xx, _debug); 00980 xx = dbenv->set_lk_max_locks(dbenv, _lk_max_locks); 00981 xx = cvtdberr(dbi, "dbenv->set_lk_max_locks", xx, _debug); 00982 xx = dbenv->set_lk_max_objects(dbenv, _lk_max_objects); 00983 xx = cvtdberr(dbi, "dbenv->set_lk_max_objects", xx, _debug); 00984 00985 { uint32_t _max = 10 * _RPMDB_NLOCKS; 00986 xx = dbenv->mutex_set_max(dbenv, _max); 00987 xx = cvtdberr(dbi, "dbenv->mutex_set_max", xx, _debug); 00988 } 00989 00990 } 00991 00992 /* ==== Logging: */ 00993 const char *logdir; 00994 00995 logdir = rpmGetPath(dbhome, "/", "log", NULL); 00996 /* 00997 * Create the /var/lib/rpm/log directory if it doesn't exist (root only). 00998 */ 00999 rpmioMkpath(logdir, 0755, getuid(), getgid()); 01000 01001 xx = dbenv->set_lg_dir(dbenv, logdir); 01002 xx = cvtdberr(dbi, "dbenv->set_lg_dir", xx, _debug); 01003 01004 _free(logdir); 01005 01006 /* ==== Memory pool: */ 01007 if (eflags & DB_INIT_MPOOL) { 01008 uint32_t _lo = 16 * 1024 * 1024; 01009 uint32_t _hi = 512 * 1024 * 1024; 01010 uint32_t _gb = 0; 01011 uint32_t _bytes = _physmem; /* XXX default value? */ 01012 int _ncache = 4; 01013 if (_bytes < _lo) _bytes = _lo; 01014 if (_bytes > _hi) _bytes = _hi; 01015 xx = dbenv->set_cache_max(dbenv, _gb, _hi); 01016 xx = cvtdberr(dbi, "dbenv->set_cache_max", xx, _debug); 01017 if (_ncache > 0) 01018 _bytes /= _ncache; 01019 xx = dbenv->set_cachesize(dbenv, _gb, _bytes, _ncache); 01020 xx = cvtdberr(dbi, "dbenv->set_cachesize", xx, _debug); 01021 } 01022 01023 /* ==== Mutexes: */ 01024 /* ==== Replication: */ 01025 /* ==== Sequences: */ 01026 /* ==== Transactions: */ 01027 #ifdef NOTYET /* XXX syscall ACID needs --with-db=internal */ 01028 if (eflags & DB_INIT_TXN) { 01029 xx = dbenv->set_app_dispatch(dbenv, logio_dispatch); 01030 xx = cvtdberr(dbi, "dbenv->set_app_dispatch", xx, _debug); 01031 } 01032 #endif 01033 01034 /* ==== Other: */ 01035 if (dbi->dbi_no_fsync) { 01036 xx = db_env_set_func_fsync(db3_fsync_disable); 01037 xx = cvtdberr(dbi, "db_env_set_func_fsync", xx, _debug); 01038 } 01039 01040 /* XXX Set a default shm_key. */ 01041 if ((eflags & DB_SYSTEM_MEM) && dbi->dbi_shmkey == 0) { 01042 #if defined(HAVE_FTOK) 01043 dbi->dbi_shmkey = ftok(dbhome, 0); 01044 #else 01045 dbi->dbi_shmkey = 0x44631380; 01046 #endif 01047 } 01048 if (dbi->dbi_shmkey) { 01049 xx = dbenv->set_shm_key(dbenv, dbi->dbi_shmkey); 01050 xx = cvtdberr(dbi, "dbenv->set_shm_key", xx, _debug); 01051 } 01052 01053 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5) 01054 /* XXX capture dbenv->falchk output on stderr. */ 01055 /*@-noeffectuncon@*/ 01056 dbenv->set_msgfile(dbenv, rpmdb->db_errfile); 01057 /*@=noeffectuncon@*/ 01058 if (dbi->dbi_thread_count >= 8) { 01059 xx = dbenv->set_thread_count(dbenv, dbi->dbi_thread_count); 01060 xx = cvtdberr(dbi, "dbenv->set_thread_count", xx, _debug); 01061 } 01062 #endif 01063 01064 /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */ 01065 if (eflags & DB_RECOVER) { 01066 eflags |= DB_CREATE; 01067 xx = dbenv->set_verbose(dbenv, DB_VERB_RECOVERY, 1); 01068 xx = cvtdberr(dbi, "dbenv->set_verbose", xx, _debug); 01069 } 01070 01071 rc = (dbenv->open)(dbenv, dbhome, eflags, dbi->dbi_perms); 01072 xx = _debug; 01073 #if defined(DB_VERSION_MISMATCH) 01074 if (rc == DB_VERSION_MISMATCH) xx = 0; 01075 #endif 01076 if (rc == EINVAL) xx = 0; 01077 rc = cvtdberr(dbi, "dbenv->open", rc, xx); 01078 if (rc) 01079 goto errxit; 01080 01081 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 5) || (DB_VERSION_MAJOR == 5) 01082 if (dbi->dbi_thread_count >= 8) { 01083 /* XXX Set pid/tid is_alive probe. */ 01084 xx = dbenv->set_isalive(dbenv, db3is_alive); 01085 xx = cvtdberr(dbi, "dbenv->set_isalive", xx, _debug); 01086 /* XXX Clean out stale shared read locks. */ 01087 xx = dbenv->failchk(dbenv, 0); 01088 xx = cvtdberr(dbi, "dbenv->failchk", xx, _debug); 01089 if (xx == DB_RUNRECOVERY) { 01090 rc = xx; 01091 goto errxit; 01092 } 01093 } 01094 #endif 01095 01096 *dbenvp = dbenv; 01097 01098 DBIDEBUG(dbi, (stderr, "<-- %s(%p(%s),%s,%s,%s,%p) dbenv %p %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbhome, dbfile, dbsubfile, dbenvp, dbenv, _EFLAGS(eflags))); 01099 01100 return 0; 01101 01102 errxit: 01103 if (dbenv) { 01104 xx = dbenv->close(dbenv, 0); 01105 xx = cvtdberr(dbi, "dbenv->close", xx, _debug); 01106 } 01107 return rc; 01108 } 01109 /*@=moduncon@*/ 01110 01111 #ifdef NOTYET 01112 /*@-mustmod@*/ 01113 static int db3remove(dbiIndex dbi, /*@null@*/ const char * dbfile, 01114 /*@unused@*/ /*@null@*/ const char * dbsubfile, 01115 unsigned int flags) 01116 /*@globals fileSystem @*/ 01117 /*@modifies dbi, fileSystem @*/ 01118 { 01119 DB * db = dbi->dbi_db; 01120 int rc; 01121 01122 assert(db != NULL); 01123 rc = db->remove(db, dbfile, dbsubfile, flags); 01124 rc = cvtdberr(dbi, "db->remove", rc, _debug); 01125 01126 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, dbsubfile, flags, rc)); 01127 01128 return rc; 01129 } 01130 /*@=mustmod@*/ 01131 01132 /*@-mustmod@*/ 01133 static int db3rename(dbiIndex dbi, /*@null@*/ const char * dbfile, 01134 /*@unused@*/ /*@null@*/ const char * dbsubfile, 01135 /*@unused@*/ /*@null@*/ const char * newname, 01136 unsigned int flags) 01137 /*@globals fileSystem @*/ 01138 /*@modifies dbi, fileSystem @*/ 01139 { 01140 DB * db = dbi->dbi_db; 01141 int rc; 01142 01143 assert(db != NULL); 01144 rc = db->rename(db, dbfile, dbsubfile, newname, flags); 01145 rc = cvtdberr(dbi, "db->rename", rc, _debug); 01146 01147 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%s,%s,0x%x) rc %d %s\n", __FUNCTION__, dbi, dbfile, dbsubfile, newname, flags, rc, _DBCFLAGS(flags))); 01148 01149 return rc; 01150 } 01151 /*@=mustmod@*/ 01152 01153 /*@-mustmod@*/ 01154 static int db3truncate(dbiIndex dbi, unsigned int * countp, unsigned int flags) 01155 /*@globals fileSystem @*/ 01156 /*@modifies *countp, fileSystem @*/ 01157 { 01158 DB * db = dbi->dbi_db; 01159 DB_TXN * _txnid = dbiTxnid(dbi); 01160 int rc; 01161 01162 assert(db != NULL); 01163 rc = db->truncate(db, _txnid, countp, flags); 01164 rc = cvtdberr(dbi, "db->truncate", rc, _debug); 01165 01166 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, countp, flags, rc)); 01167 01168 return rc; 01169 } 01170 /*@=mustmod@*/ 01171 01172 /*@-mustmod@*/ 01173 static int db3upgrade(dbiIndex dbi, /*@null@*/ const char * dbfile, 01174 unsigned int flags) 01175 /*@globals fileSystem @*/ 01176 /*@modifies fileSystem @*/ 01177 { 01178 DB * db = dbi->dbi_db; 01179 int rc; 01180 01181 assert(db != NULL); 01182 rc = db->upgrade(db, dbfile, flags); 01183 rc = cvtdberr(dbi, "db->upgrade", rc, _debug); 01184 01185 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,0x%x) rc %d\n", __FUNCTION__, dbi, dbfile, flags, rc)); 01186 01187 return rc; 01188 } 01189 /*@=mustmod@*/ 01190 #endif /* NOTYET */ 01191 01192 static int db3sync(dbiIndex dbi, unsigned int flags) 01193 /*@globals fileSystem @*/ 01194 /*@modifies fileSystem @*/ 01195 { 01196 DB * db = dbi->dbi_db; 01197 int rc = 0; 01198 int _printit; 01199 01200 if (db != NULL) 01201 rc = db->sync(db, flags); 01202 _printit = _debug; 01203 rc = cvtdberr(dbi, "db->sync", rc, _printit); 01204 01205 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc)); 01206 01207 return rc; 01208 } 01209 01210 /*@-mustmod@*/ 01211 static int db3exists(dbiIndex dbi, DBT * key, unsigned int flags) 01212 /*@globals fileSystem @*/ 01213 /*@modifies fileSystem @*/ 01214 { 01215 DB * db = dbi->dbi_db; 01216 DB_TXN * _txnid = dbiTxnid(dbi); 01217 int _printit; 01218 int rc; 01219 01220 assert(db != NULL); 01221 rc = db->exists(db, _txnid, key, flags); 01222 /* XXX DB_NOTFOUND can be returned */ 01223 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01224 rc = cvtdberr(dbi, "db->exists", rc, _printit); 01225 01226 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, key, flags, rc, _KEYDATA(key, NULL, NULL, NULL))); 01227 01228 return rc; 01229 } 01230 /*@=mustmod@*/ 01231 01232 /*@-mustmod@*/ 01233 static int db3seqno(dbiIndex dbi, int64_t * seqnop, unsigned int flags) 01234 /*@globals fileSystem @*/ 01235 /*@modifies *seqnop, fileSystem @*/ 01236 { 01237 DB * db = dbi->dbi_db; 01238 DB_TXN * _txnid = dbiTxnid(dbi); 01239 DB_SEQUENCE * seq = dbi->dbi_seq; 01240 int32_t _delta = 1; 01241 db_seq_t seqno = 0; 01242 int rc; 01243 01244 assert(db != NULL); 01245 assert(seq != NULL); 01246 01247 if (seqnop && *seqnop) 01248 _delta = *seqnop; 01249 01250 rc = seq->get(seq, _txnid, _delta, &seqno, 0); 01251 rc = cvtdberr(dbi, "seq->get", rc, _debug); 01252 if (rc) goto exit; 01253 01254 if (seqnop) 01255 *seqnop = seqno; 01256 01257 exit: 01258 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) seqno %lld rc %d\n", __FUNCTION__, dbi, seqnop, flags, (long long)seqno, rc)); 01259 01260 return rc; 01261 } 01262 /*@=mustmod@*/ 01263 01264 static int db3cdup(dbiIndex dbi, DBC * dbcursor, DBC ** dbcp, 01265 unsigned int flags) 01266 /*@globals fileSystem @*/ 01267 /*@modifies *dbcp, fileSystem @*/ 01268 { 01269 int rc; 01270 01271 if (dbcp) *dbcp = NULL; 01272 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01273 rc = dbcursor->dup(dbcursor, dbcp, flags); 01274 rc = cvtdberr(dbi, "dbcursor->dup", rc, _debug); 01275 #else 01276 rc = dbcursor->c_dup(dbcursor, dbcp, flags); 01277 rc = cvtdberr(dbi, "dbcursor->c_dup", rc, _debug); 01278 #endif 01279 01280 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, dbcp, flags, rc)); 01281 01282 return rc; 01283 } 01284 01285 /*@-mustmod@*/ 01286 static int db3cclose(dbiIndex dbi, /*@only@*/ /*@null@*/ DBC * dbcursor, 01287 /*@unused@*/ unsigned int flags) 01288 /*@globals fileSystem @*/ 01289 /*@modifies dbi, fileSystem @*/ 01290 { 01291 int rc = -2; 01292 01293 /* XXX db3copen error pathways come through here. */ 01294 if (dbcursor != NULL) { 01295 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01296 rc = dbcursor->close(dbcursor); 01297 rc = cvtdberr(dbi, "dbcursor->close", rc, _debug); 01298 #else 01299 rc = dbcursor->c_close(dbcursor); 01300 rc = cvtdberr(dbi, "dbcursor->c_close", rc, _debug); 01301 #endif 01302 } 01303 01304 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, dbcursor, flags, rc)); 01305 01306 return rc; 01307 } 01308 /*@=mustmod@*/ 01309 01310 static int db3copen(dbiIndex dbi, DB_TXN * txnid, 01311 /*@null@*/ /*@out@*/ DBC ** dbcp, unsigned int dbiflags) 01312 /*@globals fileSystem @*/ 01313 /*@modifies dbi, *dbcp, fileSystem @*/ 01314 { 01315 DB * db = dbi->dbi_db; 01316 DBC * dbcursor = NULL; 01317 int flags; 01318 int rc; 01319 01320 /* XXX DB_WRITECURSOR cannot be used with sunrpc dbenv. */ 01321 assert(db != NULL); 01322 if ((dbiflags & DB_WRITECURSOR) && 01323 (dbi->dbi_eflags & DB_INIT_CDB) && !(dbi->dbi_oflags & DB_RDONLY)) 01324 { 01325 flags = DB_WRITECURSOR; 01326 } else 01327 flags = 0; 01328 01329 rc = db->cursor(db, txnid, &dbcursor, flags); 01330 rc = cvtdberr(dbi, "db->cursor", rc, _debug); 01331 01332 if (dbcp) 01333 *dbcp = dbcursor; 01334 else 01335 (void) db3cclose(dbi, dbcursor, 0); 01336 01337 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) dbc %p %s rc %d\n", __FUNCTION__, dbi, txnid, dbcp, dbiflags, dbcursor, _DBCOFLAGS(flags), rc)); 01338 return rc; 01339 } 01340 01341 static int db3cput(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 01342 /*@unused@*/ unsigned int flags) 01343 /*@globals fileSystem @*/ 01344 /*@modifies fileSystem @*/ 01345 { 01346 DB * db = dbi->dbi_db; 01347 DB_TXN * _txnid = dbiTxnid(dbi); 01348 int rc; 01349 01350 assert(db != NULL); 01351 if (dbcursor == NULL) { 01352 flags = 0; 01353 rc = db->put(db, _txnid, key, data, flags); 01354 rc = cvtdberr(dbi, "db->put", rc, _debug); 01355 } else { 01356 flags = DB_KEYLAST; 01357 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01358 rc = dbcursor->put(dbcursor, key, data, flags); 01359 rc = cvtdberr(dbi, "dbcursor->put", rc, _debug); 01360 #else 01361 rc = dbcursor->c_put(dbcursor, key, data, flags); 01362 rc = cvtdberr(dbi, "dbcursor->c_put", rc, _debug); 01363 #endif 01364 } 01365 01366 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL))); 01367 return rc; 01368 } 01369 01370 /*@-mustmod@*/ 01371 static int db3cget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 01372 unsigned int flags) 01373 /*@globals fileSystem @*/ 01374 /*@modifies *dbcursor, *key, *data, fileSystem @*/ 01375 { 01376 DB * db = dbi->dbi_db; 01377 DB_TXN * _txnid = dbiTxnid(dbi); 01378 int _printit; 01379 int rc; 01380 01381 assert(db != NULL); 01382 if (dbcursor == NULL) { 01383 /* XXX duplicates require cursors. */ 01384 rc = db->get(db, _txnid, key, data, flags); 01385 /* XXX DB_NOTFOUND can be returned */ 01386 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01387 rc = cvtdberr(dbi, "db->get", rc, _printit); 01388 } else { 01389 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01390 /* XXX db3 does DB_FIRST on uninitialized cursor */ 01391 rc = dbcursor->get(dbcursor, key, data, flags); 01392 /* XXX DB_NOTFOUND can be returned */ 01393 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01394 /* XXX Permit DB_BUFFER_SMALL to be returned (more restrictive?) */ 01395 _printit = (rc == DB_BUFFER_SMALL ? 0 : _printit); 01396 rc = cvtdberr(dbi, "dbcursor->get", rc, _printit); 01397 #else 01398 /* XXX db3 does DB_FIRST on uninitialized cursor */ 01399 rc = dbcursor->c_get(dbcursor, key, data, flags); 01400 /* XXX DB_NOTFOUND can be returned */ 01401 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01402 rc = cvtdberr(dbi, "dbcursor->c_get", rc, _printit); 01403 #endif 01404 } 01405 01406 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL))); 01407 return rc; 01408 } 01409 /*@=mustmod@*/ 01410 01411 /*@-mustmod@*/ 01412 static int db3cpget(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * pkey, 01413 DBT * data, unsigned int flags) 01414 /*@globals fileSystem @*/ 01415 /*@modifies *dbcursor, *key, *data, fileSystem @*/ 01416 { 01417 DB * db = dbi->dbi_db; 01418 DB_TXN * _txnid = dbiTxnid(dbi); 01419 int _printit; 01420 int rc; 01421 01422 assert(db != NULL); 01423 if (dbcursor == NULL) { 01424 /* XXX duplicates require cursors. */ 01425 rc = db->pget(db, _txnid, key, pkey, data, flags); 01426 /* XXX DB_NOTFOUND can be returned */ 01427 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01428 rc = cvtdberr(dbi, "db->pget", rc, _printit); 01429 } else { 01430 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01431 /* XXX db3 does DB_FIRST on uninitialized cursor */ 01432 rc = dbcursor->pget(dbcursor, key, pkey, data, flags); 01433 /* XXX DB_NOTFOUND can be returned */ 01434 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01435 rc = cvtdberr(dbi, "dbcursor->pget", rc, _printit); 01436 #else 01437 /* XXX db3 does DB_FIRST on uninitialized cursor */ 01438 rc = dbcursor->c_pget(dbcursor, key, pkey, data, flags); 01439 /* XXX DB_NOTFOUND can be returned */ 01440 _printit = (rc == DB_NOTFOUND ? 0 : _debug); 01441 rc = cvtdberr(dbi, "dbcursor->c_pget", rc, _printit); 01442 #endif 01443 } 01444 01445 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, pkey, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, pkey, data, NULL))); 01446 return rc; 01447 } 01448 /*@=mustmod@*/ 01449 01450 /*@-mustmod@*/ 01451 static int db3cdel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 01452 unsigned int flags) 01453 /*@globals fileSystem @*/ 01454 /*@modifies *dbcursor, fileSystem @*/ 01455 { 01456 DB * db = dbi->dbi_db; 01457 DB_TXN * _txnid = dbiTxnid(dbi); 01458 int rc; 01459 01460 assert(db != NULL); 01461 if (dbcursor == NULL) { 01462 rc = db->del(db, _txnid, key, flags); 01463 rc = cvtdberr(dbi, "db->del", rc, _debug); 01464 } else { 01465 01466 /* XXX TODO: insure that cursor is positioned with duplicates */ 01467 rc = db3cget(dbi, dbcursor, key, data, DB_SET); 01468 01469 if (rc == 0) { 01470 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01471 rc = dbcursor->del(dbcursor, flags); 01472 rc = cvtdberr(dbi, "dbcursor->del", rc, _debug); 01473 #else 01474 rc = dbcursor->c_del(dbcursor, flags); 01475 rc = cvtdberr(dbi, "dbcursor->c_del", rc, _debug); 01476 #endif 01477 } 01478 } 01479 01480 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,%p,0x%x) rc %d %s%s\n", __FUNCTION__, dbi, dbcursor, key, data, flags, rc, _DBCFLAGS(flags), _KEYDATA(key, NULL, data, NULL))); 01481 return rc; 01482 } 01483 /*@=mustmod@*/ 01484 01485 static int db3ccount(dbiIndex dbi, DBC * dbcursor, 01486 /*@null@*/ /*@out@*/ unsigned int * countp, 01487 /*@unused@*/ unsigned int flags) 01488 /*@globals fileSystem @*/ 01489 /*@modifies *countp, fileSystem @*/ 01490 { 01491 db_recno_t count = 0; 01492 int rc = 0; 01493 01494 flags = 0; 01495 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 6) || (DB_VERSION_MAJOR == 5) 01496 rc = dbcursor->count(dbcursor, &count, flags); 01497 rc = cvtdberr(dbi, "dbcursor->count", rc, _debug); 01498 #else 01499 rc = dbcursor->c_count(dbcursor, &count, flags); 01500 rc = cvtdberr(dbi, "dbcursor->c_count", rc, _debug); 01501 #endif 01502 if (countp) *countp = (!rc ? count : 0); 01503 01504 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p,%p,0x%x) count %d\n", __FUNCTION__, dbi, dbcursor, countp, flags, count)); 01505 01506 return rc; 01507 } 01508 01509 static int db3byteswapped(dbiIndex dbi) /*@*/ 01510 { 01511 DB * db = dbi->dbi_db; 01512 int rc = 0; 01513 01514 if (db != NULL) { 01515 int isswapped = 0; 01516 rc = db->get_byteswapped(db, &isswapped); 01517 if (rc == 0) 01518 rc = isswapped; 01519 } 01520 01521 return rc; 01522 } 01523 01524 static int db3stat(dbiIndex dbi, unsigned int flags) 01525 /*@globals fileSystem @*/ 01526 /*@modifies dbi, fileSystem @*/ 01527 { 01528 DB * db = dbi->dbi_db; 01529 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR == 5) 01530 DB_TXN * _txnid = dbiTxnid(dbi); 01531 #endif 01532 int rc = 0; 01533 01534 assert(db != NULL); 01535 #if defined(DB_FAST_STAT) 01536 if (flags) 01537 flags = DB_FAST_STAT; 01538 else 01539 #endif 01540 flags = 0; 01541 dbi->dbi_stats = _free(dbi->dbi_stats); 01542 /* XXX 3.3.4 change. */ 01543 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 3) || (DB_VERSION_MAJOR == 5) 01544 rc = db->stat(db, _txnid, &dbi->dbi_stats, flags); 01545 #else 01546 rc = db->stat(db, &dbi->dbi_stats, flags); 01547 #endif 01548 rc = cvtdberr(dbi, "db->stat", rc, _debug); 01549 01550 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc)); 01551 01552 return rc; 01553 } 01554 01555 /*@-mustmod@*/ 01556 static int db3associate(dbiIndex dbi, dbiIndex dbisecondary, 01557 int (*callback)(DB *, const DBT *, const DBT *, DBT *), 01558 unsigned int flags) 01559 /*@globals fileSystem @*/ 01560 /*@modifies dbi, fileSystem @*/ 01561 { 01562 DB * db = dbi->dbi_db; 01563 DB * secondary = dbisecondary->dbi_db; 01564 DB_TXN * _txnid = dbiTxnid(dbi); 01565 int rc; 01566 01567 assert(db != NULL); 01568 01569 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01570 rc = db->associate(db, _txnid, secondary, callback, flags); 01571 /*@=moduncon@*/ 01572 rc = cvtdberr(dbi, "db->associate", rc, _debug); 01573 01574 if (dbi->dbi_debug || dbisecondary->dbi_debug) { 01575 const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag)); 01576 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, (void *)callback, flags, rc, _AFLAGS(flags)); 01577 tag2 = _free(tag2); 01578 } 01579 01580 return rc; 01581 } 01582 /*@=mustmod@*/ 01583 01584 /*@-mustmod@*/ 01585 static int db3associate_foreign(dbiIndex dbi, dbiIndex dbisecondary, 01586 int (*callback)(DB *, const DBT *, DBT *, const DBT *, int *), 01587 unsigned int flags) 01588 /*@globals fileSystem @*/ 01589 /*@modifies dbi, fileSystem @*/ 01590 { 01591 int rc = ENOTSUP;; 01592 01593 #if !defined(__LCLINT__) 01594 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01595 #if (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 8) || (DB_VERSION_MAJOR == 5) 01596 DB * db = dbi->dbi_db; 01597 DB * secondary = dbisecondary->dbi_db; 01598 assert(db != NULL); 01599 rc = db->associate_foreign(db, secondary, callback, flags); 01600 #endif 01601 /*@=moduncon@*/ 01602 #endif /* !defined(__LCLINT__) */ 01603 rc = cvtdberr(dbi, "db->associate_foreign", rc, _debug); 01604 01605 if (dbi->dbi_debug || dbisecondary->dbi_debug) { 01606 const char * tag2 = xstrdup(tagName(dbisecondary->dbi_rpmtag)); 01607 fprintf(stderr, "<-- %s(%p(%s),%p(%s),%p,0x%x) rc %d %s\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbisecondary, tag2, callback, flags, rc, _AFFLAGS(flags)); 01608 tag2 = _free(tag2); 01609 } 01610 01611 return rc; 01612 } 01613 /*@=mustmod@*/ 01614 01615 /*@-mustmod@*/ 01616 static int db3join(dbiIndex dbi, DBC ** curslist, DBC ** dbcp, 01617 unsigned int flags) 01618 /*@globals fileSystem @*/ 01619 /*@modifies dbi, fileSystem @*/ 01620 { 01621 DB * db = dbi->dbi_db; 01622 int rc; 01623 01624 DBIDEBUG(dbi, (stderr, "--> %s(%p,%p,%p,0x%x)\n", __FUNCTION__, dbi, curslist, dbcp, flags)); 01625 assert(db != NULL); 01626 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01627 rc = db->join(db, curslist, dbcp, flags); 01628 /*@=moduncon@*/ 01629 rc = cvtdberr(dbi, "db->join", rc, _debug); 01630 return rc; 01631 } 01632 /*@=mustmod@*/ 01633 01634 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 01635 static int db3close(/*@only@*/ dbiIndex dbi, /*@unused@*/ unsigned int flags) 01636 /*@globals rpmGlobalMacroContext, h_errno, 01637 fileSystem, internalState @*/ 01638 /*@modifies dbi, fileSystem, internalState @*/ 01639 { 01640 rpmdb rpmdb = dbi->dbi_rpmdb; 01641 const char * urlfn = NULL; 01642 const char * root; 01643 const char * home; 01644 const char * dbhome; 01645 const char * dbfile; 01646 const char * dbsubfile; 01647 DB * db = dbi->dbi_db; 01648 DB_SEQUENCE * seq = dbi->dbi_seq; 01649 const char * dbiBN = mapTagName(rpmdb, dbi); 01650 int _printit; 01651 int rc = 0, xx; 01652 01653 flags = 0; /* XXX unused */ 01654 01655 /* 01656 * Get the prefix/root component and directory path. 01657 */ 01658 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 01659 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 01660 root = NULL; 01661 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home); 01662 01663 /* 01664 * Either the root or directory components may be a URL. Concatenate, 01665 * convert the URL to a path, and add the name of the file. 01666 */ 01667 /*@-mods@*/ 01668 urlfn = rpmGenPath(root, home, NULL); 01669 /*@=mods@*/ 01670 (void) urlPath(urlfn, &dbhome); 01671 if (dbi->dbi_temporary) { 01672 dbfile = NULL; 01673 dbsubfile = NULL; 01674 } else { 01675 #ifdef HACK /* XXX necessary to support dbsubfile */ 01676 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename); 01677 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN); 01678 #else 01679 dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN); 01680 dbsubfile = NULL; 01681 #endif 01682 } 01683 01684 if (seq) { 01685 rc = seq->close(seq, 0); 01686 rc = cvtdberr(dbi, "seq->close", rc, _debug); 01687 seq = dbi->dbi_seq = NULL; 01688 01689 rpmlog(RPMLOG_DEBUG, D_("closed db seqno %s/%s\n"), 01690 dbhome, (dbfile ? dbfile : dbiBN)); 01691 01692 } 01693 if (db) { 01694 rc = db->close(db, 0); 01695 /* XXX ignore not found error messages. */ 01696 _printit = (rc == ENOENT ? 0 : _debug); 01697 rc = cvtdberr(dbi, "db->close", rc, _printit); 01698 db = dbi->dbi_db = NULL; 01699 01700 rpmlog(RPMLOG_DEBUG, D_("closed db index %s/%s\n"), 01701 dbhome, (dbfile ? dbfile : dbiBN)); 01702 01703 } 01704 01705 /* XXX avoid non-root EPERM ACID PANIC with temp Depcache close. */ 01706 if (rpmdb->db_dbenv != NULL && dbi->dbi_use_dbenv && !dbi->dbi_temporary) { 01707 if (rpmdb->db_opens == 1) { 01708 /*@-nullstate@*/ 01709 xx = db_fini(dbi, (dbhome ? dbhome : ""), dbfile, dbsubfile); 01710 /*@=nullstate@*/ 01711 rpmdb->db_dbenv = NULL; 01712 } 01713 rpmdb->db_opens--; 01714 } 01715 01716 DBIDEBUG(dbi, (stderr, "<-- %s(%p,0x%x) rc %d\n", __FUNCTION__, dbi, flags, rc)); 01717 01718 dbi->dbi_db = NULL; 01719 01720 urlfn = _free(urlfn); 01721 01722 dbi = db3Free(dbi); 01723 01724 return rc; 01725 } 01726 /*@=moduncon@*/ 01727 01733 static inline unsigned char nibble(char c) 01734 /*@*/ 01735 { 01736 if (c >= '0' && c <= '9') 01737 return (unsigned char)(c - '0'); 01738 if (c >= 'A' && c <= 'F') 01739 return (unsigned char)((int)(c - 'A') + 10); 01740 if (c >= 'a' && c <= 'f') 01741 return (unsigned char)((int)(c - 'a') + 10); 01742 return '\0'; 01743 } 01744 01745 static int loadDBT(DBT * _r, rpmTag tag, const void * _s, size_t ns) 01746 /*@modifies *_r @*/ 01747 { 01748 const char * s = _s; 01749 void * data = NULL; 01750 size_t size = 0; 01751 uint8_t * t = NULL; 01752 uint32_t i; 01753 int xx; 01754 01755 if (ns == 0) ns = strlen(s); 01756 switch (tag) { 01757 case RPMTAG_FILEDIGESTS: 01758 /* Convert hex to binary, filter out odd hex strings. */ 01759 if (ns > 0 && !(ns & 1)) { 01760 ns /= 2; 01761 data = t = xmalloc(ns); 01762 for (i = 0; i < ns; i++, t++, s += 2) { 01763 if (!(isxdigit(s[0]) && isxdigit(s[1]))) 01764 /*@loopbreak@*/ break; 01765 *t = (uint8_t) (nibble(s[0]) << 4) | nibble(s[1]); 01766 } 01767 if (i == ns) 01768 size = ns; 01769 else 01770 data = _free(data); 01771 } 01772 break; 01773 case RPMTAG_PUBKEYS: 01774 /* Extract pubkey id from the base64 blob. */ 01775 t = xmalloc(32); 01776 if ((xx = pgpExtractPubkeyFingerprint(s, t)) > 0) { 01777 data = t; 01778 size = xx; 01779 } else 01780 t = _free(t); 01781 break; 01782 default: 01783 data = (void *) memcpy(xmalloc(ns), _s, ns); 01784 size = ns; 01785 break; 01786 } 01787 if ((_r->data = data) != NULL) _r->flags |= DB_DBT_APPMALLOC; 01788 return (_r->size = size); 01789 } 01790 01791 static int uint32Cmp(const void * _a, const void * _b) 01792 /*@*/ 01793 { 01794 const uint32_t * a = _a; 01795 const uint32_t * b = _b; 01796 return ((*a < *b) ? -1 : 01797 ((*a > *b) ? 1 : 0)); 01798 } 01799 01800 static int uint64Cmp(const void * _a, const void * _b) 01801 /*@*/ 01802 { 01803 const uint64_t * a = _a; 01804 const uint64_t * b = _b; 01805 return ((*a < *b) ? -1 : 01806 ((*a > *b) ? 1 : 0)); 01807 } 01808 01809 static int 01810 db3Acallback(DB * db, const DBT * key, const DBT * data, DBT * _r) 01811 /*@globals internalState @*/ 01812 /*@modifies *_r, internalState @*/ 01813 { 01814 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01815 HE_t Fhe = memset(alloca(sizeof(*Fhe)), 0, sizeof(*Fhe)); 01816 #ifdef NOTYET 01817 HE_t FMhe = memset(alloca(sizeof(*FMhe)), 0, sizeof(*FMhe)); 01818 #endif 01819 dbiIndex dbi = db->app_private; 01820 rpmdb rpmdb = NULL; 01821 Header h = NULL; 01822 uint32_t hdrNum; 01823 DBT * A = NULL; 01824 const char * s = NULL; 01825 size_t ns = 0; 01826 int rc = DB_DONOTINDEX; /* assume no-op */ 01827 uint32_t i; 01828 int xx; 01829 01830 assert(key->size == sizeof(hdrNum)); 01831 memcpy(&hdrNum, key->data, key->size); 01832 hdrNum = _ntoh_ui(hdrNum); 01833 01834 /* XXX Don't index the header instance counter at record 0. */ 01835 if (hdrNum == 0) 01836 goto exit; 01837 01838 assert(dbi); 01839 rpmdb = dbi->dbi_rpmdb; 01840 assert(rpmdb); 01841 01842 /* XXX Track the maximum primary key value. */ 01843 if (hdrNum > rpmdb->db_maxkey) 01844 rpmdb->db_maxkey = hdrNum; 01845 01846 h = headerLink(rpmdb->db_h); 01847 if (h == NULL) { 01848 /* XXX needs PROT_READ somewhen. */ 01849 h = headerLoad(data->data); 01850 if (h == NULL) { 01851 rpmlog(RPMLOG_ERR, 01852 _("db3: header #%u cannot be loaded -- skipping.\n"), 01853 (unsigned)hdrNum); 01854 goto exit; 01855 } 01856 } 01857 01858 memset(_r, 0, sizeof(*_r)); 01859 01860 he->tag = dbi->dbi_rpmtag; 01861 if (!headerGet(h, he, 0)) 01862 goto exit; 01863 01864 /* XXX catch busted headerGet() rc on RPMTAG_FILEPATHS w empty list. */ 01865 assert(he->p.ptr != NULL && he->c > 0); 01866 01867 /* Retrieve other tags needed for filtering decisions. */ 01868 switch (he->tag) { 01869 default: 01870 break; 01871 #ifdef NOTYET 01872 case RPMTAG_BASENAMES: 01873 case RPMTAG_FILEPATHS: 01874 /* XXX Add the pesky trailing '/' to directories. */ 01875 FMhe->tag = RPMTAG_FILEMODES; 01876 (void) headerGet(h, FMhe, 0); 01877 break; 01878 #endif 01879 case RPMTAG_REQUIREYAMLENTRY: 01880 case RPMTAG_REQUIRENAME: 01881 /* The Requires: F is needed to filter install context dependencies. */ 01882 Fhe->tag = RPMTAG_REQUIREFLAGS; 01883 (void) headerGet(h, Fhe, 0); 01884 break; 01885 } 01886 01887 switch (he->t) { 01888 default: 01889 assert(0); 01890 /*@notreached@*/ break; 01891 case RPM_UINT8_TYPE: /* XXX coerce to uint32_t */ 01892 { uint8_t * _u = he->p.ui8p; 01893 he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p)); 01894 for (i = 0; i < he->c; i++) 01895 he->p.ui32p[i] = _u[i]; 01896 _u = _free(_u); 01897 goto _ifill; 01898 } /*@notreached@*/ break; 01899 case RPM_UINT16_TYPE: /* XXX coerce to uint32_t */ 01900 { uint16_t * _u = he->p.ui16p; 01901 he->p.ui32p = xmalloc(he->c * sizeof(*he->p.ui32p)); 01902 for (i = 0; i < he->c; i++) 01903 he->p.ui32p[i] = _u[i]; 01904 _u = _free(_u); 01905 goto _ifill; 01906 } /*@notreached@*/ break; 01907 case RPM_UINT32_TYPE: 01908 _ifill: 01909 { uint32_t * _u = he->p.ui32p; 01910 size_t _ulen = sizeof(*_u); 01911 uint32_t _ube; /* XXX network order integer keys */ 01912 01913 /* Drop the transaction id usecs field (if present) when indexing. */ 01914 switch (he->tag) { 01915 case RPMTAG_INSTALLTID: 01916 case RPMTAG_REMOVETID: 01917 he->c = 1; 01918 /*@innerbreak@*/ break; 01919 default: 01920 /*@innerbreak@*/ break; 01921 } 01922 if (he->c == 1) { 01923 _ube = _hton_ui(*_u); /* XXX network order integer keys */ 01924 /* XXX is it worth avoiding the realloc here? */ 01925 xx = loadDBT(_r, he->tag, &_ube, _ulen); 01926 break; 01927 } 01928 _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC; 01929 _r->data = A = xcalloc(he->c, sizeof(*A)); 01930 _r->size = 0; 01931 if (he->c > 1) 01932 qsort(_u, he->c, _ulen, uint32Cmp); 01933 for (i = 0; i < he->c; i++, _u++) { 01934 /* Don't add identical (key,val) item to secondary. */ 01935 if (i > 0 && _u[-1] == _u[0]) 01936 continue; 01937 _ube = _hton_ui(*_u); /* XXX network order integer keys */ 01938 if (!loadDBT(A, he->tag, &_ube, _ulen)) 01939 continue; 01940 A++; 01941 _r->size++; 01942 } 01943 } break; 01944 case RPM_UINT64_TYPE: 01945 { uint64_t * _u = he->p.ui64p; 01946 size_t _ulen = sizeof(*_u); 01947 uint64_t _ube; /* XXX network order integer keys */ 01948 01949 if (he->c == 1) { 01950 _ube = _hton_ul(*_u); /* XXX network order integer keys */ 01951 /* XXX is it worth avoiding the realloc here? */ 01952 xx = loadDBT(_r, he->tag, _u, _ulen); 01953 break; 01954 } 01955 _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC; 01956 _r->data = A = xcalloc(he->c, sizeof(*A)); 01957 _r->size = 0; 01958 if (he->c > 1) 01959 qsort(_u, he->c, _ulen, uint64Cmp); 01960 for (i = 0; i < he->c; i++, _u++) { 01961 /* Don't add identical (key,val) item to secondary. */ 01962 if (i > 0 && _u[-1] == _u[0]) 01963 continue; 01964 _ube = _hton_ul(*_u); /* XXX network order integer keys */ 01965 if (!loadDBT(A, he->tag, &_ube, _ulen)) 01966 continue; 01967 A++; 01968 _r->size++; 01969 } 01970 } break; 01971 case RPM_BIN_TYPE: 01972 s = he->p.ptr; ns = he->c; 01973 /* XXX is it worth avoiding the realloc here? */ 01974 if (ns > 0) /* No "" empty keys please. */ 01975 xx = loadDBT(_r, he->tag, s, ns); 01976 break; 01977 case RPM_I18NSTRING_TYPE: /* XXX never occurs */ 01978 case RPM_STRING_TYPE: 01979 s = he->p.str; ns = strlen(s); 01980 /* XXX is it worth avoiding the realloc here? */ 01981 if (ns > 0) /* No "" empty keys please. */ 01982 xx = loadDBT(_r, he->tag, s, ns); 01983 break; 01984 case RPM_STRING_ARRAY_TYPE: 01985 if (he->c == 1) { 01986 s = he->p.argv[0]; ns = strlen(s); 01987 if (ns > 0) /* No "" empty keys please. */ 01988 xx = loadDBT(_r, he->tag, s, ns); 01989 } else { 01990 static double e = 1.0e-5; 01991 static size_t nmin = 16; 01992 size_t n = 2 * (he->c > nmin ? he->c : nmin); 01993 size_t m = 0; 01994 size_t k = 0; 01995 rpmbf bf; 01996 rpmbfParams(n, e, &m, &k); 01997 bf = rpmbfNew(m, k, 0); 01998 01999 _r->flags = DB_DBT_MULTIPLE | DB_DBT_APPMALLOC; 02000 _r->data = A = xcalloc(he->c, sizeof(*A)); 02001 _r->size = 0; 02002 for (i = 0; i < he->c; i++) { 02003 s = he->p.argv[i]; ns = strlen(s); 02004 02005 /* XXX Skip YAML "- ..." lead-in mark up if present. */ 02006 if (s[0] == '-' && s[1] == ' ') { 02007 s += 2, ns -= 2; 02008 } 02009 02010 #ifdef NOTYET 02011 /* Add the pesky trailing '/' to directories. */ 02012 if (FMhe->p.ui16p && !S_ISREG((mode_t)FMhe->p.ui16p[i])) { 02013 continue; 02014 } 02015 #endif 02016 02017 if (ns == 0) /* No "" empty keys please. */ 02018 continue; 02019 02020 /* Filter install context dependencies. */ 02021 if (Fhe->p.ui32p && isInstallPreReq(Fhe->p.ui32p[i])) 02022 continue; 02023 02024 /* Don't add identical (key,val) item to secondary. */ 02025 if (rpmbfChk(bf, s, ns) > 0) 02026 continue; 02027 xx = rpmbfAdd(bf, s, ns); 02028 assert(xx == 0); 02029 02030 if (!loadDBT(A, he->tag, s, ns)) 02031 continue; 02032 A++; 02033 _r->size++; 02034 } 02035 bf = rpmbfFree(bf); 02036 } 02037 break; 02038 } 02039 if (_r->data && _r->size > 0) 02040 rc = 0; 02041 else if (_r->flags & DB_DBT_APPMALLOC) { 02042 _r->data = _free(_r->data); 02043 memset(_r, 0, sizeof(*_r)); 02044 } 02045 02046 exit: 02047 if (!dbi->dbi_no_dbsync && rc != DB_DONOTINDEX) 02048 xx = dbiSync(dbi, 0); 02049 #ifdef NOTYET 02050 FMhe->p.ptr = _free(FMhe->p.ptr); 02051 #endif 02052 Fhe->p.ptr = _free(Fhe->p.ptr); 02053 he->p.ptr = _free(he->p.ptr); 02054 h = headerFree(h); 02055 02056 DBIDEBUG(dbi, (stderr, "<-- %s(%p, %p, %p, %p) rc %d\n\tdbi %p(%s) rpmdb %p h %p %s\n", __FUNCTION__, db, key, data, _r, rc, dbi, tagName(dbi->dbi_rpmtag), rpmdb, h, _KEYDATA(key, NULL, data, _r))); 02057 02058 return rc; 02059 } 02060 02061 static int seqid_init(dbiIndex dbi, const char * keyp, size_t keylen, 02062 DB_SEQUENCE ** seqp) 02063 /*@modifies *seqp @*/ 02064 { 02065 DB * db = dbi->dbi_db; 02066 DBT k = {0}; 02067 DB_TXN * _txnid = dbiTxnid(dbi); 02068 DB_SEQUENCE * seq = NULL; 02069 db_seq_t _rangemin = -922337203685477600LL; 02070 db_seq_t _rangemax = 922337203685477600LL; 02071 db_seq_t _value = 0; 02072 int32_t _cachesize = 0; 02073 uint32_t _flags = DB_SEQ_INC; 02074 uint32_t _oflags = DB_CREATE; 02075 int rc; 02076 02077 assert(db != NULL); 02078 if (seqp) *seqp = NULL; 02079 02080 /*@-moduncon@*/ 02081 rc = db_sequence_create(&seq, db, 0); 02082 /*@=moduncon@*/ 02083 rc = cvtdberr(dbi, "db_sequence_create", rc, _debug); 02084 if (rc) goto exit; 02085 assert(seq != NULL); 02086 02087 if (dbi->dbi_seq_cachesize) { 02088 _cachesize = dbi->dbi_seq_cachesize; 02089 rc = seq->set_cachesize(seq, _cachesize); 02090 rc = cvtdberr(dbi, "seq->set_cachesize", rc, _debug); 02091 if (rc) goto exit; 02092 } 02093 02094 if (dbi->dbi_seq_initial) 02095 _value = dbi->dbi_seq_initial; 02096 if (_value <= 0) _value = 1; 02097 rc = seq->initial_value(seq, _value); 02098 rc = cvtdberr(dbi, "seq->initial_value", rc, _debug); 02099 if (rc) goto exit; 02100 02101 if (dbi->dbi_seq_min) 02102 _rangemin = dbi->dbi_seq_min; 02103 if (dbi->dbi_seq_max) 02104 _rangemax = dbi->dbi_seq_max; 02105 rc = seq->set_range(seq, _rangemin, _rangemax); 02106 rc = cvtdberr(dbi, "seq->set_range", rc, _debug); 02107 if (rc) goto exit; 02108 02109 if (dbi->dbi_seq_flags) 02110 _flags = dbi->dbi_seq_flags; 02111 rc = seq->set_flags(seq, _flags); 02112 rc = cvtdberr(dbi, "seq->set_flags", rc, _debug); 02113 if (rc) goto exit; 02114 02115 k.data = (void *)keyp; 02116 k.size = (u_int32_t) (keylen > 0 ? keylen : strlen(keyp)); 02117 rc = seq->open(seq, _txnid, &k, _oflags); 02118 rc = cvtdberr(dbi, "seq->open", rc, _debug); 02119 if (rc) goto exit; 02120 02121 exit: 02122 if (rc == 0 && seqp != NULL) 02123 *seqp = seq; 02124 else { 02125 int xx = seq->close(seq, 0); 02126 xx = cvtdberr(dbi, "seq->close", xx, _debug); 02127 } 02128 02129 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%p[%u],%p) seq %p rc %d %s\n", __FUNCTION__, dbi, keyp, (unsigned)keylen, seqp, (seqp ? *seqp : NULL), rc, _KEYDATA(&k, NULL, NULL, NULL))); 02130 02131 return rc; 02132 } 02133 02141 static int db3open(rpmdb rpmdb, rpmTag rpmtag, dbiIndex * dbip) 02142 /*@globals rpmGlobalMacroContext, h_errno, 02143 fileSystem, internalState @*/ 02144 /*@modifies *dbip, fileSystem, internalState @*/ 02145 { 02146 /*@-nestedextern -shadow@*/ 02147 extern struct _dbiVec db3vec; 02148 /*@=nestedextern =shadow@*/ 02149 const char * urlfn = NULL; 02150 const char * root; 02151 const char * home; 02152 const char * dbhome; 02153 const char * dbfile; 02154 const char * dbsubfile; 02155 const char * dbiBN; 02156 dbiIndex dbi = NULL; 02157 int rc = 0; 02158 int xx; 02159 02160 DB * db = NULL; 02161 DB_ENV * dbenv = NULL; 02162 DB_TXN * _txnid = NULL; 02163 DBTYPE dbi_type = DB_UNKNOWN; 02164 rpmuint32_t oflags; 02165 int _printit; 02166 02167 if (dbip) 02168 *dbip = NULL; 02169 02170 /* 02171 * Parse db configuration parameters. 02172 */ 02173 /*@-mods@*/ 02174 if ((dbi = db3New(rpmdb, rpmtag)) == NULL) 02175 /*@-nullstate@*/ 02176 return 1; 02177 /*@=nullstate@*/ 02178 /*@=mods@*/ 02179 dbi->dbi_api = DB_VERSION_MAJOR; 02180 dbiBN = mapTagName(rpmdb, dbi); 02181 dbi->dbi_txnid = NULL; 02182 _txnid = NULL; 02183 02184 /* 02185 * Get the prefix/root component and directory path. 02186 */ 02187 root = (dbi->dbi_root ? dbi->dbi_root : rpmdb->db_root); 02188 if ((root[0] == '/' && root[1] == '\0') || rpmdb->db_chrootDone) 02189 root = NULL; 02190 home = (dbi->dbi_home ? dbi->dbi_home : rpmdb->db_home); 02191 02192 /* 02193 * Either the root or directory components may be a URL. Concatenate, 02194 * convert the URL to a path, and add the name of the file. 02195 */ 02196 /*@-mods@*/ 02197 urlfn = rpmGenPath(root, home, NULL); 02198 /*@=mods@*/ 02199 (void) urlPath(urlfn, &dbhome); 02200 if (dbi->dbi_temporary) { 02201 dbfile = NULL; 02202 dbsubfile = NULL; 02203 } else { 02204 #ifdef HACK /* XXX necessary to support dbsubfile */ 02205 dbfile = (dbi->dbi_file ? dbi->dbi_file : db3basename); 02206 dbsubfile = (dbi->dbi_subfile ? dbi->dbi_subfile : dbiBN); 02207 #else 02208 dbfile = (dbi->dbi_file ? dbi->dbi_file : dbiBN); 02209 dbsubfile = NULL; 02210 #endif 02211 } 02212 02213 oflags = (dbi->dbi_oeflags | dbi->dbi_oflags); 02214 /* XXX permit DB_TRUNCATE iff a secondary index. */ 02215 if (dbi->dbi_primary) oflags &= ~DB_TRUNCATE; 02216 02217 #if 0 /* XXX rpmdb: illegal flag combination specified to DB->open */ 02218 if ( dbi->dbi_mode & O_EXCL) oflags |= DB_EXCL; 02219 #endif 02220 02221 /* 02222 * Map open mode flags onto configured database/environment flags. 02223 */ 02224 if (dbi->dbi_temporary) { 02225 oflags |= DB_CREATE; 02226 dbi->dbi_oeflags |= DB_CREATE; 02227 oflags &= ~DB_RDONLY; 02228 dbi->dbi_oflags &= ~DB_RDONLY; 02229 } else { 02230 if (!(dbi->dbi_mode & (O_RDWR|O_WRONLY))) oflags |= DB_RDONLY; 02231 if (dbi->dbi_mode & O_CREAT) { 02232 oflags |= DB_CREATE; 02233 dbi->dbi_oeflags |= DB_CREATE; 02234 } 02235 /* XXX permit DB_TRUNCATE iff a secondary index. */ 02236 if (dbi->dbi_primary && (dbi->dbi_mode & O_TRUNC)) 02237 oflags |= DB_TRUNCATE; 02238 } 02239 02240 /* 02241 * Create the /var/lib/rpm directory if it doesn't exist (root only). 02242 */ 02243 (void) rpmioMkpath(dbhome, 0755, getuid(), getgid()); 02244 02245 /* 02246 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DBENV->open. 02247 */ 02248 if (dbi->dbi_use_dbenv) { 02249 02250 if (access(dbhome, W_OK) == -1) { 02251 02252 /* dbhome is unwritable, don't attempt DB_CREATE on DB->open ... */ 02253 oflags &= ~DB_CREATE; 02254 oflags &= ~DB_AUTO_COMMIT; 02255 02256 /* ... but DBENV->open might still need DB_CREATE ... */ 02257 if (dbi->dbi_eflags & DB_PRIVATE) { 02258 dbi->dbi_eflags &= ~DB_JOINENV; 02259 } else { 02260 dbi->dbi_eflags |= DB_JOINENV; 02261 dbi->dbi_oeflags &= ~DB_CREATE; 02262 #ifdef DYING 02263 dbi->dbi_oeflags &= ~DB_THREAD; 02264 #endif 02265 /* ... but, unless DB_PRIVATE is used, skip DBENV. */ 02266 dbi->dbi_use_dbenv = 0; 02267 } 02268 02269 /* ... DB_RDONLY maps dbhome perms across files ... */ 02270 if (dbi->dbi_temporary) { 02271 oflags |= DB_CREATE; 02272 dbi->dbi_oeflags |= DB_CREATE; 02273 oflags &= ~DB_RDONLY; 02274 dbi->dbi_oflags &= ~DB_RDONLY; 02275 } else { 02276 oflags |= DB_RDONLY; 02277 /* ... and DB_WRITECURSOR won't be needed ... */ 02278 dbi->dbi_oflags |= DB_RDONLY; 02279 } 02280 02281 } else { /* dbhome is writable, check for persistent dbenv. */ 02282 /*@-mods@*/ 02283 const char * dbf = rpmGetPath(dbhome, "/__db.001", NULL); 02284 /*@=mods@*/ 02285 02286 #if defined(RPM_VENDOR_OPENPKG) /* bdb-allow-zero-sized-files */ 02287 /* Make sure RPM passes DB_CREATE to Berkeley-DB also 02288 if file exists, but is (still) zero-sized. */ 02289 struct stat sb; 02290 long size = -1; 02291 if (stat(dbf, &sb) == 0) 02292 size = (long)sb.st_size; 02293 if (access(dbf, F_OK) == -1 || size == 0) 02294 #else 02295 if (access(dbf, F_OK) == -1) 02296 #endif 02297 { 02298 /* ... non-existent (or unwritable) DBENV, will create ... */ 02299 dbi->dbi_oeflags |= DB_CREATE; 02300 dbi->dbi_eflags &= ~DB_JOINENV; 02301 } else { 02302 /* ... pre-existent (or bogus) DBENV, will join ... */ 02303 if (dbi->dbi_eflags & DB_PRIVATE) { 02304 dbi->dbi_eflags &= ~DB_JOINENV; 02305 } else { 02306 dbi->dbi_eflags |= DB_JOINENV; 02307 dbi->dbi_oeflags &= ~DB_CREATE; 02308 #ifdef DYING 02309 dbi->dbi_oeflags &= ~DB_THREAD; 02310 #endif 02311 } 02312 } 02313 /* ... transactionally protected open's need DB_AUTO_COMMIT ... */ 02314 if (rpmdb->_dbi[0] 02315 && rpmdb->_dbi[0]->dbi_eflags & DB_INIT_TXN) 02316 oflags |= DB_AUTO_COMMIT; 02317 dbf = _free(dbf); 02318 } 02319 } 02320 02321 /* 02322 * Avoid incompatible DB_CREATE/DB_RDONLY flags on DB->open. 02323 */ 02324 if ((oflags & DB_CREATE) && (oflags & DB_RDONLY)) { 02325 /* dbhome is writable, and DB->open flags may conflict. */ 02326 const char * dbfn = (dbfile ? dbfile : dbiBN); 02327 /*@-mods@*/ 02328 const char * dbf = rpmGetPath(dbhome, "/", dbfn, NULL); 02329 /*@=mods@*/ 02330 02331 if (access(dbf, F_OK) == -1) { 02332 /* File does not exist, DB->open might create ... */ 02333 oflags &= ~DB_RDONLY; 02334 } else { 02335 /* File exists, DB->open need not create ... */ 02336 oflags &= ~DB_CREATE; 02337 } 02338 02339 /* Only writers need DB_WRITECURSOR ... */ 02340 if (!(oflags & DB_RDONLY) && access(dbf, W_OK) == 0) { 02341 dbi->dbi_oflags &= ~DB_RDONLY; 02342 } else { 02343 dbi->dbi_oflags |= DB_RDONLY; 02344 } 02345 dbf = _free(dbf); 02346 } 02347 02348 /* 02349 * Set db type if creating or truncating. 02350 */ 02351 if (oflags & (DB_CREATE|DB_TRUNCATE)) 02352 dbi_type = dbi->dbi_type; 02353 02354 if (dbi->dbi_use_dbenv) { 02355 /*@-mods@*/ 02356 if (rpmdb->db_dbenv == NULL) { 02357 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 02358 switch (rc) { 02359 default: 02360 break; 02361 case DB_RUNRECOVERY: 02362 if (getuid() != 0) 02363 break; 02364 rpmlog(RPMLOG_NOTICE, _("Re-opening dbenv with DB_RECOVER ...\n")); 02365 /* XXX Attempt db_recover -ev (i.e. dbenv w DB_INIT_LOCK) */ 02366 dbi->dbi_eflags |= DB_RECOVER; 02367 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 02368 dbi->dbi_eflags &= ~DB_RECOVER; 02369 if (rc) { 02370 rpmlog(RPMLOG_NOTICE, _("\nrecovery failed. Exiting ...\n")); 02371 exit(EXIT_FAILURE); 02372 } 02373 rpmlog(RPMLOG_NOTICE, _(".\nrecovery succeeded.\n")); 02374 assert(dbenv); 02375 rpmdb->db_dbenv = dbenv; 02376 rpmdb->db_opens = 1; 02377 break; 02378 02379 #if defined(DB_VERSION_MISMATCH) /* Nuke __db* files and retry open once. */ 02380 case DB_VERSION_MISMATCH: 02381 #endif 02382 case EINVAL: 02383 if (getuid() != 0) 02384 break; 02385 { char * filename = alloca(BUFSIZ); 02386 struct stat st; 02387 int i; 02388 02389 for (i = 0; i < 16; i++) { 02390 sprintf(filename, "%s/__db.%03d", dbhome, i); 02391 (void)rpmCleanPath(filename); 02392 if (Stat(filename, &st) 02393 && (errno == ENOENT || errno == EINVAL)) 02394 continue; 02395 xx = Unlink(filename); 02396 } 02397 } 02398 dbi->dbi_oeflags |= DB_CREATE; 02399 dbi->dbi_eflags &= ~DB_JOINENV; 02400 rc = db_init(dbi, dbhome, dbfile, dbsubfile, &dbenv); 02401 /* XXX db_init EINVAL was masked. */ 02402 rc = cvtdberr(dbi, "dbenv->open", rc, _debug); 02403 if (rc) 02404 break; 02405 /*@fallthrough@*/ 02406 case 0: 02407 assert(dbenv); 02408 rpmdb->db_dbenv = dbenv; 02409 rpmdb->db_opens = 1; 02410 break; 02411 } 02412 } else { 02413 assert(rpmdb && rpmdb->db_dbenv); 02414 dbenv = rpmdb->db_dbenv; 02415 rpmdb->db_opens++; 02416 } 02417 /*@=mods@*/ 02418 } 02419 02420 rpmlog(RPMLOG_DEBUG, D_("opening db index %s/%s %s mode=0x%x\n"), 02421 dbhome, (dbfile ? dbfile : dbiBN), 02422 prDbiOpenFlags(oflags, 0), dbi->dbi_mode); 02423 02424 if (rc == 0) { 02425 static int _lockdbfd = 0; 02426 02427 /*@-moduncon@*/ /* FIX: annotate db3 methods */ 02428 rc = db_create(&db, dbenv, dbi->dbi_cflags); 02429 /*@=moduncon@*/ 02430 rc = cvtdberr(dbi, "db_create", rc, _debug); 02431 if (rc == 0 && db != NULL) { 02432 02433 /* XXX 3.3.4 change. */ 02434 if (rc == 0 && 02435 rpmdb->db_malloc && rpmdb->db_realloc && rpmdb->db_free) 02436 { 02437 rc = db->set_alloc(db, 02438 rpmdb->db_malloc, rpmdb->db_realloc, rpmdb->db_free); 02439 rc = cvtdberr(dbi, "db->set_alloc", rc, _debug); 02440 } 02441 02442 /* 4.1: db->set_cache_priority(???) */ 02443 /* 4.1: db->set_encrypt(???) */ 02444 02445 if (rc == 0 && dbi->dbi_lorder) { 02446 rc = db->set_lorder(db, dbi->dbi_lorder); 02447 rc = cvtdberr(dbi, "db->set_lorder", rc, _debug); 02448 } 02449 if (rc == 0 && dbi->dbi_pagesize) { 02450 rc = db->set_pagesize(db, dbi->dbi_pagesize); 02451 rc = cvtdberr(dbi, "db->set_pagesize", rc, _debug); 02452 } 02453 /* 4.1: db->set_paniccall(???) */ 02454 if (rc == 0 && oflags & DB_CREATE) { 02455 switch(dbi->dbi_type) { 02456 default: 02457 case DB_HASH: 02458 if (dbi->dbi_h_ffactor) { 02459 rc = db->set_h_ffactor(db, dbi->dbi_h_ffactor); 02460 rc = cvtdberr(dbi, "db->set_h_ffactor", rc, _debug); 02461 if (rc) break; 02462 } 02463 if (dbi->dbi_h_nelem) { 02464 rc = db->set_h_nelem(db, dbi->dbi_h_nelem); 02465 rc = cvtdberr(dbi, "db->set_h_nelem", rc, _debug); 02466 if (rc) break; 02467 } 02468 if (dbi->dbi_h_flags) { 02469 rc = db->set_flags(db, dbi->dbi_h_flags); 02470 rc = cvtdberr(dbi, "db->set_h_flags", rc, _debug); 02471 if (rc) break; 02472 } 02473 if (dbi->dbi_h_hash_fcn) { 02474 rc = db->set_h_hash(db, dbi->dbi_h_hash_fcn); 02475 rc = cvtdberr(dbi, "db->set_h_hash", rc, _debug); 02476 if (rc) break; 02477 } 02478 if (dbi->dbi_h_dup_compare_fcn) { 02479 rc = db->set_dup_compare(db, dbi->dbi_h_dup_compare_fcn); 02480 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); 02481 if (rc) break; 02482 } 02483 break; 02484 case DB_BTREE: 02485 /* 4.1: db->set_append_recno(???) */ 02486 if (dbi->dbi_bt_flags) { 02487 rc = db->set_flags(db, dbi->dbi_bt_flags); 02488 rc = cvtdberr(dbi, "db->set_bt_flags", rc, _debug); 02489 if (rc) break; 02490 } 02491 if (dbi->dbi_bt_minkey) { 02492 rc = db->set_bt_minkey(db, dbi->dbi_bt_minkey); 02493 rc = cvtdberr(dbi, "db->set_bt_minkey", rc, _debug); 02494 if (rc) break; 02495 } 02496 if (dbi->dbi_bt_compare_fcn) { 02497 rc = db->set_bt_compare(db, dbi->dbi_bt_compare_fcn); 02498 rc = cvtdberr(dbi, "db->set_bt_compare", rc, _debug); 02499 if (rc) break; 02500 } 02501 if (dbi->dbi_bt_dup_compare_fcn) { 02502 rc = db->set_dup_compare(db, dbi->dbi_bt_dup_compare_fcn); 02503 rc = cvtdberr(dbi, "db->set_dup_compare", rc, _debug); 02504 if (rc) break; 02505 } 02506 if (dbi->dbi_bt_prefix_fcn) { 02507 rc = db->set_bt_prefix(db, dbi->dbi_bt_prefix_fcn); 02508 rc = cvtdberr(dbi, "db->set_bt_prefix", rc, _debug); 02509 if (rc) break; 02510 } 02511 break; 02512 case DB_RECNO: 02513 /* 4.1: db->set_append_recno(???) */ 02514 if (dbi->dbi_re_delim) { 02515 rc = db->set_re_delim(db, dbi->dbi_re_delim); 02516 rc = cvtdberr(dbi, "db->set_re_selim", rc, _debug); 02517 if (rc) break; 02518 } 02519 if (dbi->dbi_re_len) { 02520 rc = db->set_re_len(db, dbi->dbi_re_len); 02521 rc = cvtdberr(dbi, "db->set_re_len", rc, _debug); 02522 if (rc) break; 02523 } 02524 if (dbi->dbi_re_pad) { 02525 rc = db->set_re_pad(db, dbi->dbi_re_pad); 02526 rc = cvtdberr(dbi, "db->set_re_pad", rc, _debug); 02527 if (rc) break; 02528 } 02529 if (dbi->dbi_re_source) { 02530 rc = db->set_re_source(db, dbi->dbi_re_source); 02531 rc = cvtdberr(dbi, "db->set_re_source", rc, _debug); 02532 if (rc) break; 02533 } 02534 break; 02535 case DB_QUEUE: 02536 if (dbi->dbi_q_extentsize) { 02537 rc = db->set_q_extentsize(db, dbi->dbi_q_extentsize); 02538 rc = cvtdberr(dbi, "db->set_q_extentsize", rc, _debug); 02539 if (rc) break; 02540 } 02541 break; 02542 #if defined(DB_HEAP) /* XXX FIXME: db-5.2.28 parameters */ 02543 case DB_HEAP: 02544 if (dbi->dbi_heapsize) { 02545 static uint32_t _gbytes = 0; 02546 static uint32_t _bytes = dbi->db_heapsize; 02547 assert(_heapsize >= (3 * dbi->dbi_pagesize)); 02548 rc = db->set_heapsize(db, _gbytes, _bytes); 02549 rc = cvtdberr(dbi, "db->set_heapsize", rc, _debug); 02550 if (rc) break; 02551 } 02552 break; 02553 #endif 02554 } 02555 } 02556 02557 if (rc == 0) { 02558 const char * dbfullpath; 02559 const char * dbpath; 02560 char * t; 02561 int nb; 02562 02563 nb = strlen(dbhome); 02564 if (dbfile) nb += 1 + strlen(dbfile); 02565 dbfullpath = t = alloca(nb + 1); 02566 02567 t = stpcpy(t, dbhome); 02568 if (dbfile) 02569 t = stpcpy( stpcpy( t, "/"), dbfile); 02570 #ifdef HACK /* XXX necessary to support dbsubfile */ 02571 dbpath = (!dbi->dbi_use_dbenv && !dbi->dbi_temporary) 02572 ? dbfullpath : dbfile; 02573 #else 02574 #ifdef PLD_CHROOT 02575 /* XXX Make dbpath relative. */ 02576 dbpath = (!dbi->dbi_use_dbenv) 02577 ? dbfullpath : dbfile; 02578 #else 02579 dbpath = (!dbi->dbi_temporary) 02580 ? dbfullpath : dbfile; 02581 #endif /* PLD_CHROOT */ 02582 #endif /* HACK */ 02583 02584 rc = (db->open)(db, _txnid, dbpath, dbsubfile, 02585 dbi_type, oflags, dbi->dbi_perms); 02586 02587 if (rc == 0 && dbi_type == DB_UNKNOWN) { 02588 xx = db->get_type(db, &dbi_type); 02589 if (xx == 0) 02590 dbi->dbi_type = dbi_type; 02591 } 02592 } 02593 02594 /* XXX return rc == errno without printing */ 02595 _printit = (rc > 0 ? 0 : _debug); 02596 xx = cvtdberr(dbi, "db->open", rc, _printit); 02597 02598 /* 02599 * Lock a file using fcntl(2). Traditionally this is Packages, 02600 * the file used to store metadata of installed header(s), 02601 * as Packages is always opened, and should be opened first, 02602 * for any rpmdb access. 02603 * 02604 * If no DBENV is used, then access is protected with a 02605 * shared/exclusive locking scheme, as always. 02606 * 02607 * With a DBENV, the fcntl(2) lock is necessary only to keep 02608 * the riff-raff from playing where they don't belong, as 02609 * the DBENV should provide it's own locking scheme. So try to 02610 * acquire a lock, but permit failures, as some other 02611 * DBENV player may already have acquired the lock. 02612 * 02613 * With NPTL posix mutexes, revert to fcntl lock on non-functioning 02614 * glibc/kernel combinations. 02615 */ 02616 if (rc == 0 && dbi->dbi_lockdbfd && 02617 #if defined(DB_RPCCLIENT) 02618 !((dbi->dbi_ecflags & DB_RPCCLIENT) && dbi->dbi_host) && 02619 #endif 02620 (!dbi->dbi_use_dbenv || _lockdbfd++ == 0)) 02621 { 02622 int fdno = -1; 02623 02624 if (!(db->fd(db, &fdno) == 0 && fdno >= 0)) { 02625 rc = 1; 02626 } else { 02627 struct flock l; 02628 memset(&l, 0, sizeof(l)); 02629 l.l_whence = 0; 02630 l.l_start = 0; 02631 l.l_len = 0; 02632 l.l_type = (dbi->dbi_mode & (O_RDWR|O_WRONLY)) 02633 ? F_WRLCK : F_RDLCK; 02634 l.l_pid = 0; 02635 02636 rc = fcntl(fdno, F_SETLK, (void *) &l); 02637 if (rc) { 02638 /* Warning iff using non-private CDB locking. */ 02639 rc = ((dbi->dbi_use_dbenv && 02640 (dbi->dbi_eflags & DB_INIT_CDB) && 02641 !(dbi->dbi_eflags & DB_PRIVATE)) 02642 ? 0 : 1); 02643 rpmlog( (rc ? RPMLOG_ERR : RPMLOG_WARNING), 02644 _("cannot get %s lock on %s/%s\n"), 02645 ((dbi->dbi_mode & (O_RDWR|O_WRONLY)) 02646 ? _("exclusive") : _("shared")), 02647 dbhome, (dbfile ? dbfile : "")); 02648 } else if (dbfile) { 02649 rpmlog(RPMLOG_DEBUG, 02650 D_("locked db index %s/%s\n"), 02651 dbhome, dbfile); 02652 } 02653 } 02654 } 02655 } 02656 } 02657 02658 dbi->dbi_db = db; 02659 if (db) 02660 db->app_private = dbi; 02661 02662 DBIDEBUG(dbi, (stderr, "<-- %s(%p,%s,%p) dbi %p rc %d %s\n", __FUNCTION__, rpmdb, tagName(rpmtag), dbip, dbi, rc, _OFLAGS(dbi->dbi_oflags))); 02663 02664 if (rc == 0 && dbi->dbi_db != NULL && dbip != NULL) { 02665 dbi->dbi_vec = &db3vec; 02666 *dbip = dbi; 02667 if (dbi->dbi_primary) { 02668 rpmTag Ptag = tagValue(dbi->dbi_primary); 02669 dbiIndex Pdbi = NULL; 02670 int (*_callback)(DB *, const DBT *, const DBT *, DBT *) 02671 = db3Acallback; 02672 #ifdef NOTYET /* XXX KISS for now */ 02673 int _flags = DB_IMMUTABLE_KEY; 02674 #else 02675 int _flags = 0; 02676 #endif 02677 assert(Ptag == RPMDBI_PACKAGES && Ptag != rpmtag); 02678 Pdbi = dbiOpen(rpmdb, Ptag, 0); 02679 assert(Pdbi != NULL); 02680 if (oflags & (DB_CREATE|DB_TRUNCATE)) _flags |= DB_CREATE; 02681 xx = db3associate(Pdbi, dbi, _callback, _flags); 02682 } 02683 if (dbi->dbi_seq_id) { 02684 char * end = NULL; 02685 uint32_t u = (uint32_t) strtoll(dbi->dbi_seq_id, &end, 0); 02686 02687 /* Reset the Seqno counter to the next primary key */ 02688 if (oflags & (DB_CREATE|DB_TRUNCATE)) 02689 dbi->dbi_seq_initial = rpmdb->db_maxkey + 1; 02690 02691 if (*end == '\0') 02692 xx = seqid_init(dbi,(const char *)&u, sizeof(u), &dbi->dbi_seq); 02693 else 02694 xx = seqid_init(dbi, dbi->dbi_seq_id, 0, &dbi->dbi_seq); 02695 if (xx) { 02696 (void) db3close(dbi, 0); 02697 dbi = NULL; 02698 if (dbip) *dbip = dbi; 02699 } 02700 } 02701 } else { 02702 (void) db3close(dbi, 0); 02703 dbi = NULL; 02704 if (dbip) *dbip = dbi; 02705 } 02706 02707 urlfn = _free(urlfn); 02708 02709 /*@-nullstate -compmempass@*/ 02710 return rc; 02711 /*@=nullstate =compmempass@*/ 02712 } 02713 02716 /*@-exportheadervar@*/ 02717 /*@observer@*/ /*@unchecked@*/ 02718 struct _dbiVec db3vec = { 02719 DB_VERSION_STRING, DB_VERSION_MAJOR, DB_VERSION_MINOR, DB_VERSION_PATCH, 02720 db3open, db3close, db3sync, db3associate, db3associate_foreign, db3join, 02721 db3exists, db3seqno, 02722 db3copen, db3cclose, db3cdup, db3cdel, db3cget, db3cpget, db3cput, db3ccount, 02723 db3byteswapped, db3stat 02724 }; 02725 /*@=exportheadervar@*/ 02726 /*@=type@*/
1.7.5.1