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