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