rpm 5.3.12
|
00001 00005 #include "system.h" 00006 00007 #include <sys/file.h> 00008 00009 #include <rpmiotypes.h> 00010 #include <rpmlog.h> 00011 #include <rpmpgp.h> 00012 #include <rpmurl.h> 00013 #include <rpmhash.h> /* hashFunctionString */ 00014 #define _MIRE_INTERNAL 00015 #include <rpmmacro.h> 00016 #include <rpmsq.h> 00017 #include <rpmsx.h> 00018 #include <argv.h> 00019 00020 #define _RPMBF_INTERNAL 00021 #include <rpmbf.h> 00022 00023 #include <rpmtypes.h> 00024 #define _RPMTAG_INTERNAL 00025 #include "header_internal.h" /* XXX for HEADERFLAG_MAPPED */ 00026 00027 #define _RPMDB_INTERNAL 00028 #include "rpmdb.h" 00029 #include "pkgio.h" 00030 #include "fprint.h" 00031 #include "legacy.h" 00032 00033 #include "debug.h" 00034 00035 #if defined(__LCLINT__) 00036 #define UINT32_T u_int32_t 00037 #else 00038 #define UINT32_T rpmuint32_t 00039 #endif 00040 00041 /* XXX retrofit the *BSD typedef for the deprived. */ 00042 #if defined(__QNXNTO__) 00043 typedef rpmuint32_t u_int32_t; 00044 #endif 00045 00046 /*@access dbiIndexSet@*/ 00047 /*@access dbiIndexItem@*/ 00048 /*@access miRE@*/ 00049 /*@access Header@*/ /* XXX compared with NULL */ 00050 /*@access rpmmi@*/ 00051 /*@access rpmts@*/ /* XXX compared with NULL */ 00052 00053 /*@unchecked@*/ 00054 int _rpmdb_debug = 0; 00055 00056 /*@unchecked@*/ 00057 int _rpmmi_debug = 0; 00058 00059 #define _DBI_FLAGS 0 00060 #define _DBI_PERMS 0644 00061 #define _DBI_MAJOR -1 00062 00069 static size_t dbiTagToDbix(rpmdb db, rpmTag tag) 00070 /*@*/ 00071 { 00072 size_t dbix; 00073 00074 if (db->db_tags != NULL) 00075 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00076 if (tag != db->db_tags[dbix].tag) 00077 continue; 00078 return dbix; 00079 } 00080 return 0xffffffff; 00081 } 00082 00086 /*@-exportheader@*/ 00087 static void dbiTagsInit(/*@null@*/ tagStore_t * dbiTagsP, 00088 /*@null@*/ size_t * dbiNTagsP) 00089 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 00090 /*@modifies *dbiTagsP, *dbiNTagsP, rpmGlobalMacroContext, internalState @*/ 00091 { 00092 /*@observer@*/ 00093 static const char * const _dbiTagStr_default = 00094 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filedigests:Depends:Pubkeys"; 00095 tagStore_t dbiTags = NULL; 00096 size_t dbiNTags = 0; 00097 char * dbiTagStr = NULL; 00098 char * o, * oe; 00099 rpmTag tag; 00100 size_t dbix; 00101 int bingo; 00102 00103 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL); 00104 if (!(dbiTagStr && *dbiTagStr)) { 00105 dbiTagStr = _free(dbiTagStr); 00106 dbiTagStr = xstrdup(_dbiTagStr_default); 00107 } 00108 00109 #ifdef NOISY 00110 if (_rpmdb_debug) 00111 fprintf(stderr, "--> %s(%p, %p) dbiTagStr %s\n", __FUNCTION__, dbiTagsP, dbiNTagsP, dbiTagStr); 00112 #endif 00113 /* Always allocate package index */ 00114 dbiTags = xcalloc(1, sizeof(*dbiTags)); 00115 dbiTags[dbiNTags].str = xstrdup("Packages"); 00116 dbiTags[dbiNTags].tag = RPMDBI_PACKAGES; 00117 dbiTags[dbiNTags].iob = NULL; 00118 dbiNTags++; 00119 00120 for (o = dbiTagStr; o && *o; o = oe) { 00121 while (*o && xisspace((int)*o)) 00122 o++; 00123 if (*o == '\0') 00124 break; 00125 for (oe = o; oe && *oe; oe++) { 00126 if (xisspace((int)*oe)) 00127 /*@innerbreak@*/ break; 00128 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/')) 00129 /*@innerbreak@*/ break; 00130 } 00131 if (oe && *oe) 00132 *oe++ = '\0'; 00133 tag = tagValue(o); 00134 00135 bingo = 0; 00136 if (dbiTags != NULL) 00137 for (dbix = 0; dbix < dbiNTags; dbix++) { 00138 if (tag == dbiTags[dbix].tag) { 00139 bingo = 1; 00140 /*@innerbreak@*/ break; 00141 } 00142 } 00143 if (bingo) 00144 continue; 00145 00146 dbiTags = xrealloc(dbiTags, (dbiNTags + 1) * sizeof(*dbiTags)); 00147 dbiTags[dbiNTags].str = xstrdup(o); 00148 dbiTags[dbiNTags].tag = tag; 00149 dbiTags[dbiNTags].iob = NULL; 00150 #ifdef NOISY 00151 if (_rpmdb_debug) { 00152 fprintf(stderr, "\t%u %s(", (unsigned)dbiNTags, o); 00153 if (tag & 0x40000000) 00154 fprintf(stderr, "0x%x)\n", tag); 00155 else 00156 fprintf(stderr, "%d)\n", tag); 00157 } 00158 #endif 00159 dbiNTags++; 00160 } 00161 00162 if (dbiNTagsP != NULL) 00163 *dbiNTagsP = dbiNTags; 00164 if (dbiTagsP != NULL) 00165 *dbiTagsP = dbiTags; 00166 else 00167 dbiTags = tagStoreFree(dbiTags, dbiNTags); 00168 dbiTagStr = _free(dbiTagStr); 00169 } 00170 /*@=exportheader@*/ 00171 00172 /*@-redecl@*/ 00173 #define DB1vec NULL 00174 #define DB2vec NULL 00175 00176 #if defined(WITH_DB) 00177 /*@-exportheadervar -declundef @*/ 00178 /*@observer@*/ /*@unchecked@*/ 00179 extern struct _dbiVec db3vec; 00180 /*@=exportheadervar =declundef @*/ 00181 #define DB3vec &db3vec 00182 /*@=redecl@*/ 00183 #else 00184 #define DB3vec NULL 00185 #endif 00186 00187 #ifdef HAVE_SQLITE3_H 00188 #define SQLITE_HACK 00189 /*@-exportheadervar -declundef @*/ 00190 /*@observer@*/ /*@unchecked@*/ 00191 extern struct _dbiVec sqlitevec; 00192 /*@=exportheadervar =declundef @*/ 00193 #define SQLITEvec &sqlitevec 00194 /*@=redecl@*/ 00195 #else 00196 #define SQLITEvec NULL 00197 #endif 00198 00199 /*@-nullassign@*/ 00200 /*@observer@*/ /*@unchecked@*/ 00201 static struct _dbiVec *mydbvecs[] = { 00202 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL 00203 }; 00204 /*@=nullassign@*/ 00205 00206 static inline int checkfd(const char * devnull, int fdno, int flags) 00207 /*@*/ 00208 { 00209 struct stat sb; 00210 int ret = 0; 00211 00212 if (fstat(fdno, &sb) == -1 && errno == EBADF) 00213 ret = (open(devnull, flags) == fdno) ? 1 : 2; 00214 return ret; 00215 } 00216 00217 dbiIndex dbiOpen(rpmdb db, rpmTag tag, /*@unused@*/ unsigned int flags) 00218 { 00219 static int _oneshot = 0; 00220 size_t dbix; 00221 dbiIndex dbi = NULL; 00222 int _dbapi; 00223 int rc = 0; 00224 00225 /* Insure that stdin/stdout/stderr are open, lest stderr end up in rpmdb. */ 00226 if (!_oneshot) { 00227 static const char _devnull[] = "/dev/null"; 00228 /*@-noeffect@*/ 00229 #if defined(STDIN_FILENO) 00230 (void) checkfd(_devnull, STDIN_FILENO, O_RDONLY); 00231 #endif 00232 #if defined(STDOUT_FILENO) 00233 (void) checkfd(_devnull, STDOUT_FILENO, O_WRONLY); 00234 #endif 00235 #if defined(STDERR_FILENO) 00236 (void) checkfd(_devnull, STDERR_FILENO, O_WRONLY); 00237 #endif 00238 /*@=noeffect@*/ 00239 _oneshot++; 00240 } 00241 00242 assert(db != NULL); /* XXX sanity */ 00243 assert(db->_dbi != NULL); /* XXX sanity */ 00244 00245 /* Is this index configured? */ 00246 dbix = dbiTagToDbix(db, tag); 00247 if (dbix >= db->db_ndbi) 00248 goto exit; 00249 00250 /* Is this index already open ? */ 00251 if ((dbi = db->_dbi[dbix]) != NULL) 00252 goto exit; 00253 00254 _dbapi = db->db_api; 00255 assert(_dbapi == 3 || _dbapi == 4); 00256 assert(mydbvecs[_dbapi] != NULL); 00257 00258 rc = (*mydbvecs[_dbapi]->open) (db, tag, &dbi); 00259 if (rc) { 00260 static uint8_t _printed[128]; 00261 if (!_printed[dbix & 0x1f]++) 00262 rpmlog(RPMLOG_ERR, 00263 _("cannot open %s(%u) index: %s(%d)\n\tDB: %s\n"), 00264 tagName(tag), tag, 00265 (rc > 0 ? strerror(rc) : ""), rc, 00266 ((mydbvecs[_dbapi]->dbv_version != NULL) 00267 ? mydbvecs[_dbapi]->dbv_version : "unknown")); 00268 dbi = db3Free(dbi); 00269 goto exit; 00270 } 00271 db->_dbi[dbix] = dbi; 00272 00273 exit: 00274 00275 /*@-modfilesys@*/ 00276 if (_rpmdb_debug) 00277 fprintf(stderr, "<== dbiOpen(%p, %s(%u), 0x%x) dbi %p = %p[%u:%u]\n", db, tagName(tag), tag, flags, dbi, db->_dbi, (unsigned)dbix, (unsigned)db->db_ndbi); 00278 /*@=modfilesys@*/ 00279 00280 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */ 00281 return dbi; 00282 /*@=compdef =nullstate@*/ 00283 } 00284 00285 /*@-redef@*/ 00286 union _dbswap { 00287 uint64_t ul; 00288 uint32_t ui; 00289 uint16_t us; 00290 uint8_t uc[8]; 00291 }; 00292 /*@=redef@*/ 00293 00294 /*@unchecked@*/ 00295 static union _dbswap _endian = { .ui = 0x11223344 }; 00296 00297 static inline uint64_t _ntoh_ul(uint64_t ul) 00298 /*@*/ 00299 { 00300 union _dbswap _a; 00301 _a.ul = ul; 00302 if (_endian.uc[0] == 0x44) { 00303 uint8_t _b, *_c = _a.uc; \ 00304 _b = _c[7]; _c[7] = _c[0]; _c[0] = _b; \ 00305 _b = _c[6]; _c[6] = _c[1]; _c[1] = _b; \ 00306 _b = _c[5]; _c[5] = _c[2]; _c[2] = _b; \ 00307 _b = _c[4]; _c[4] = _c[3]; _c[3] = _b; \ 00308 } 00309 return _a.ul; 00310 } 00311 static inline uint64_t _hton_ul(uint64_t ul) 00312 /*@*/ 00313 { 00314 return _ntoh_ul(ul); 00315 } 00316 00317 static inline uint32_t _ntoh_ui(uint32_t ui) 00318 /*@*/ 00319 { 00320 union _dbswap _a; 00321 _a.ui = ui; 00322 if (_endian.uc[0] == 0x44) { 00323 uint8_t _b, *_c = _a.uc; \ 00324 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \ 00325 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \ 00326 } 00327 return _a.ui; 00328 } 00329 static inline uint32_t _hton_ui(uint32_t ui) 00330 /*@*/ 00331 { 00332 return _ntoh_ui(ui); 00333 } 00334 00335 static inline uint16_t _ntoh_us(uint16_t us) 00336 /*@*/ 00337 { 00338 union _dbswap _a; 00339 _a.us = us; 00340 if (_endian.uc[0] == 0x44) { 00341 uint8_t _b, *_c = _a.uc; \ 00342 _b = _c[1]; _c[1] = _c[0]; _c[0] = _b; \ 00343 } 00344 return _a.us; 00345 } 00346 static inline uint16_t _hton_us(uint16_t us) 00347 /*@*/ 00348 { 00349 return _ntoh_us(us); 00350 } 00351 00352 typedef struct _setSwap_s { 00353 union _dbswap hdr; 00354 union _dbswap tag; 00355 uint32_t fp; 00356 } * setSwap; 00357 00358 /* XXX assumes hdrNum is first int in dbiIndexItem */ 00359 static int hdrNumCmp(const void * one, const void * two) 00360 /*@*/ 00361 { 00362 const int * a = one, * b = two; 00363 return (*a - *b); 00364 } 00365 00375 static int dbiAppendSet(dbiIndexSet set, const void * recs, 00376 int nrecs, size_t recsize, int sortset) 00377 /*@modifies *set @*/ 00378 { 00379 const char * rptr = recs; 00380 size_t rlen = (recsize < sizeof(*(set->recs))) 00381 ? recsize : sizeof(*(set->recs)); 00382 00383 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0) 00384 return 1; 00385 00386 set->recs = xrealloc(set->recs, 00387 (set->count + nrecs) * sizeof(*(set->recs))); 00388 00389 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs))); 00390 00391 while (nrecs-- > 0) { 00392 /*@-mayaliasunique@*/ 00393 memcpy(set->recs + set->count, rptr, rlen); 00394 /*@=mayaliasunique@*/ 00395 rptr += recsize; 00396 set->count++; 00397 } 00398 00399 if (sortset && set->count > 1) 00400 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp); 00401 00402 return 0; 00403 } 00404 00405 /* XXX transaction.c */ 00406 unsigned int dbiIndexSetCount(dbiIndexSet set) { 00407 return set->count; 00408 } 00409 00410 /* XXX transaction.c */ 00411 uint32_t dbiIndexRecordOffset(dbiIndexSet set, unsigned int recno) { 00412 return set->recs[recno].hdrNum; 00413 } 00414 00415 /* XXX transaction.c */ 00416 uint32_t dbiIndexRecordFileNumber(dbiIndexSet set, unsigned int recno) { 00417 return set->recs[recno].tagNum; 00418 } 00419 00420 /* XXX transaction.c */ 00421 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) { 00422 if (set) { 00423 set->recs = _free(set->recs); 00424 set = _free(set); 00425 } 00426 return set; 00427 } 00428 00429 struct rpmmi_s { 00430 struct rpmioItem_s _item; 00431 /*@dependent@*/ /*@null@*/ 00432 rpmmi mi_next; 00433 /*@refcounted@*/ 00434 rpmdb mi_db; 00435 rpmTag mi_rpmtag; 00436 dbiIndexSet mi_set; 00437 DBC * mi_dbc; 00438 unsigned int mi_count; 00439 uint32_t mi_setx; 00440 void * mi_keyp; 00441 const char * mi_primary; 00442 size_t mi_keylen; 00443 /*@refcounted@*/ /*@null@*/ 00444 Header mi_h; 00445 int mi_sorted; 00446 int mi_cflags; 00447 int mi_modified; 00448 uint32_t mi_prevoffset; /* header instance (big endian) */ 00449 uint32_t mi_offset; /* header instance (big endian) */ 00450 uint32_t mi_bntag; /* base name tag (native endian) */ 00451 /*@refcounted@*/ /*@null@*/ 00452 rpmbf mi_bf; /* Iterator instance Bloom filter. */ 00453 int mi_nre; 00454 /*@only@*/ /*@null@*/ 00455 miRE mi_re; 00456 00457 }; 00458 00459 /*@unchecked@*/ 00460 static rpmdb rpmdbRock; 00461 00462 /*@unchecked@*/ /*@exposed@*/ /*@null@*/ 00463 static rpmmi rpmmiRock; 00464 00465 int rpmdbCheckTerminate(int terminate) 00466 /*@globals rpmdbRock, rpmmiRock @*/ 00467 /*@modifies rpmdbRock, rpmmiRock @*/ 00468 { 00469 sigset_t newMask, oldMask; 00470 static int terminating = 0; 00471 00472 if (terminating) return 1; 00473 00474 (void) sigfillset(&newMask); /* block all signals */ 00475 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask); 00476 00477 if (sigismember(&rpmsqCaught, SIGINT) 00478 || sigismember(&rpmsqCaught, SIGQUIT) 00479 || sigismember(&rpmsqCaught, SIGHUP) 00480 || sigismember(&rpmsqCaught, SIGTERM) 00481 || sigismember(&rpmsqCaught, SIGPIPE) 00482 #ifdef NOTYET /* XXX todo++ */ 00483 || sigismember(&rpmsqCaught, SIGXCPU) 00484 || sigismember(&rpmsqCaught, SIGXFSZ) 00485 #endif 00486 || terminate) 00487 terminating = 1; 00488 00489 if (terminating) { 00490 rpmdb db; 00491 rpmmi mi; 00492 00493 while ((mi = rpmmiRock) != NULL) { 00494 /*@i@*/ rpmmiRock = mi->mi_next; 00495 mi->mi_next = NULL; 00496 /*@i@*/ mi = rpmmiFree(mi); 00497 } 00498 00499 /*@-newreftrans@*/ 00500 while ((db = rpmdbRock) != NULL) { 00501 /*@i@*/ rpmdbRock = db->db_next; 00502 db->db_next = NULL; 00503 (void) rpmdbClose(db); 00504 } 00505 /*@=newreftrans@*/ 00506 } 00507 00508 (void) sigprocmask(SIG_SETMASK, &oldMask, NULL); 00509 return terminating; 00510 } 00511 00512 int rpmdbCheckSignals(void) 00513 { 00514 00515 if (rpmdbCheckTerminate(0)) { 00516 /*@-abstract@*/ /* sigset_t is abstract type */ 00517 rpmlog(RPMLOG_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught)); 00518 /*@=abstract@*/ 00519 exit(EXIT_FAILURE); 00520 } 00521 return 0; 00522 } 00523 00530 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask) 00531 /*@globals fileSystem @*/ 00532 /*@modifies *oldMask, fileSystem @*/ 00533 { 00534 sigset_t newMask; 00535 00536 (void) sigfillset(&newMask); /* block all signals */ 00537 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask); 00538 (void) sigdelset(&newMask, SIGINT); 00539 (void) sigdelset(&newMask, SIGQUIT); 00540 (void) sigdelset(&newMask, SIGHUP); 00541 (void) sigdelset(&newMask, SIGTERM); 00542 (void) sigdelset(&newMask, SIGPIPE); 00543 return sigprocmask(SIG_BLOCK, &newMask, NULL); 00544 } 00545 00552 /*@mayexit@*/ 00553 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask) 00554 /*@globals fileSystem, internalState @*/ 00555 /*@modifies fileSystem, internalState @*/ 00556 { 00557 (void) rpmdbCheckSignals(); 00558 return sigprocmask(SIG_SETMASK, oldMask, NULL); 00559 } 00560 00568 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt) 00569 /*@globals headerCompoundFormats, fileSystem, internalState @*/ 00570 /*@modifies h, fileSystem, internalState @*/ 00571 { 00572 const char * errstr = "(unkown error)"; 00573 const char * str; 00574 00575 /*@-modobserver@*/ 00576 str = headerSprintf(h, qfmt, NULL, headerCompoundFormats, &errstr); 00577 /*@=modobserver@*/ 00578 if (str == NULL) 00579 rpmlog(RPMLOG_ERR, _("incorrect format: \"%s\": %s\n"), qfmt, errstr); 00580 return str; 00581 } 00582 00590 static int rpmdbExportInfo(/*@unused@*/ rpmdb db, Header h, int adding) 00591 /*@globals headerCompoundFormats, rpmGlobalMacroContext, h_errno, 00592 fileSystem, internalState @*/ 00593 /*@modifies h, rpmGlobalMacroContext, 00594 fileSystem, internalState @*/ 00595 { 00596 static int oneshot; 00597 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00598 const char * fn = NULL; 00599 int xx; 00600 00601 { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL); 00602 if (fnfmt && *fnfmt) 00603 fn = queryHeader(h, fnfmt); 00604 fnfmt = _free(fnfmt); 00605 } 00606 00607 if (fn == NULL) 00608 goto exit; 00609 00610 /* Lazily create the directory in chroot's if configured. */ 00611 if (!oneshot) { 00612 char * _fn = xstrdup(fn); 00613 char * dn = dirname(_fn); 00614 mode_t _mode = 0755; 00615 uid_t _uid = 0; 00616 gid_t _gid = 0; 00617 /* If not a directory, then disable, else don't retry. */ 00618 errno = 0; 00619 oneshot = (rpmioMkpath(dn, _mode, _uid, _gid) ? -1 : 1); 00620 _fn = _free(_fn); 00621 } 00622 /* If directory is AWOL, don't bother exporting info. */ 00623 if (oneshot < 0) 00624 goto exit; 00625 00626 if (adding) { 00627 FD_t fd = Fopen(fn, "w.fdio"); 00628 00629 if (fd != NULL) { 00630 xx = Fclose(fd); 00631 fd = NULL; 00632 he->tag = RPMTAG_INSTALLTID; 00633 if (headerGet(h, he, 0)) { 00634 struct utimbuf stamp; 00635 stamp.actime = he->p.ui32p[0]; 00636 stamp.modtime = he->p.ui32p[0]; 00637 if (!Utime(fn, &stamp)) 00638 rpmlog(RPMLOG_DEBUG, " +++ %s\n", fn); 00639 } 00640 he->p.ptr = _free(he->p.ptr); 00641 } 00642 } else { 00643 if (!Unlink(fn)) 00644 rpmlog(RPMLOG_DEBUG, " --- %s\n", fn); 00645 } 00646 00647 exit: 00648 fn = _free(fn); 00649 return 0; 00650 } 00651 00652 /*@unchecked@*/ /*@only@*/ /*@null@*/ 00653 rpmioPool _rpmdbPool; 00654 00655 static rpmdb rpmdbGetPool(/*@null@*/ rpmioPool pool) 00656 /*@globals _rpmdbPool, fileSystem @*/ 00657 /*@modifies pool, _rpmdbPool, fileSystem @*/ 00658 { 00659 rpmdb db; 00660 00661 if (_rpmdbPool == NULL) { 00662 _rpmdbPool = rpmioNewPool("db", sizeof(*db), -1, _rpmdb_debug, 00663 NULL, NULL, NULL); 00664 pool = _rpmdbPool; 00665 } 00666 db = (rpmdb) rpmioGetPool(pool, sizeof(*db)); 00667 memset(((char *)db)+sizeof(db->_item), 0, sizeof(*db)-sizeof(db->_item)); 00668 return db; 00669 } 00670 00671 int rpmdbOpenAll(rpmdb db) 00672 { 00673 int rc = 0; 00674 00675 if (db == NULL) return -2; 00676 00677 if (db->db_tags != NULL && db->_dbi != NULL) { 00678 size_t dbix; 00679 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00680 if ((int)db->db_tags[dbix].tag < 0) 00681 continue; 00682 if (db->_dbi[dbix] != NULL) 00683 continue; 00684 switch (db->db_tags[dbix].tag) { 00685 case RPMDBI_AVAILABLE: 00686 case RPMDBI_ADDED: 00687 case RPMDBI_REMOVED: 00688 case RPMDBI_DEPENDS: 00689 case RPMDBI_BTREE: 00690 case RPMDBI_HASH: 00691 case RPMDBI_QUEUE: 00692 case RPMDBI_RECNO: 00693 continue; 00694 /*@notreached@*/ /*@switchbreak@*/ break; 00695 default: 00696 /*@switchbreak@*/ break; 00697 } 00698 (void) dbiOpen(db, db->db_tags[dbix].tag, db->db_flags); 00699 } 00700 } 00701 return rc; 00702 } 00703 00704 int rpmdbBlockDBI(rpmdb db, int tag) 00705 { 00706 rpmTag tagn = (rpmTag)(tag >= 0 ? tag : -tag); 00707 size_t dbix; 00708 00709 if (db == NULL || db->_dbi == NULL) 00710 return 0; 00711 00712 if (db->db_tags != NULL) 00713 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00714 if (db->db_tags[dbix].tag != tagn) 00715 continue; 00716 db->db_tags[dbix].tag = tag; 00717 return 0; 00718 } 00719 return 0; 00720 } 00721 00722 int rpmdbCloseDBI(rpmdb db, int tag) 00723 { 00724 size_t dbix; 00725 int rc = 0; 00726 00727 if (db == NULL || db->_dbi == NULL) 00728 return 0; 00729 00730 if (db->db_tags != NULL) 00731 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00732 if (db->db_tags[dbix].tag != (rpmTag)tag) 00733 continue; 00734 if (db->_dbi[dbix] != NULL) { 00735 int xx; 00736 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00737 xx = dbiClose(db->_dbi[dbix], 0); 00738 if (xx && rc == 0) rc = xx; 00739 db->_dbi[dbix] = NULL; 00740 /*@=unqualifiedtrans@*/ 00741 } 00742 break; 00743 } 00744 return rc; 00745 } 00746 00747 /* XXX query.c, rpminstall.c, verify.c */ 00748 /*@-incondefs@*/ 00749 int rpmdbClose(rpmdb db) 00750 /*@globals rpmdbRock @*/ 00751 /*@modifies rpmdbRock @*/ 00752 { 00753 static const char msg[] = "rpmdbClose"; 00754 rpmdb * prev, next; 00755 size_t dbix; 00756 int rc = 0; 00757 00758 if (db == NULL) 00759 return rc; 00760 00761 yarnPossess(db->_item.use); 00762 /*@-modfilesys@*/ 00763 if (_rpmdb_debug) 00764 fprintf(stderr, "--> db %p -- %ld %s at %s:%u\n", db, yarnPeekLock(db->_item.use), msg, __FILE__, __LINE__); 00765 00766 /*@-usereleased@*/ 00767 if (yarnPeekLock(db->_item.use) <= 1L) { 00768 00769 if (db->_dbi) 00770 for (dbix = db->db_ndbi; dbix;) { 00771 int xx; 00772 dbix--; 00773 if (db->_dbi[dbix] == NULL) 00774 continue; 00775 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00776 xx = dbiClose(db->_dbi[dbix], 0); 00777 if (xx && rc == 0) rc = xx; 00778 db->_dbi[dbix] = NULL; 00779 /*@=unqualifiedtrans@*/ 00780 } 00781 db->db_errpfx = _free(db->db_errpfx); 00782 db->db_root = _free(db->db_root); 00783 db->db_home = _free(db->db_home); 00784 db->db_tags = tagStoreFree(db->db_tags, db->db_ndbi); 00785 db->_dbi = _free(db->_dbi); 00786 db->db_ndbi = 0; 00787 00788 /*@-newreftrans@*/ 00789 prev = &rpmdbRock; 00790 while ((next = *prev) != NULL && next != db) 00791 prev = &next->db_next; 00792 if (next) { 00793 /*@i@*/ *prev = next->db_next; 00794 next->db_next = NULL; 00795 } 00796 /*@=newreftrans@*/ 00797 00798 if (rpmdbRock == NULL && rpmmiRock == NULL) { 00799 /* Last close uninstalls special signal handling. */ 00800 (void) rpmsqEnable(-SIGHUP, NULL); 00801 (void) rpmsqEnable(-SIGINT, NULL); 00802 (void) rpmsqEnable(-SIGTERM, NULL); 00803 (void) rpmsqEnable(-SIGQUIT, NULL); 00804 (void) rpmsqEnable(-SIGPIPE, NULL); 00805 /* Pending signals strike here. */ 00806 (void) rpmdbCheckSignals(); 00807 } 00808 00809 /*@=usereleased@*/ 00810 db = (rpmdb)rpmioPutPool((rpmioItem)db); 00811 } else 00812 yarnTwist(db->_item.use, BY, -1); 00813 00814 return rc; 00815 } 00816 /*@=incondefs@*/ 00817 00823 static const char * rpmdbURIPath(const char *uri) 00824 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00825 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00826 { 00827 const char * s = rpmGetPath(uri, NULL); 00828 ARGV_t av = NULL; 00829 int xx = argvSplit(&av, s, ":"); 00830 const char * fn = NULL; 00831 /* XXX av contains a colon separated path split, use the 1st path. */ 00832 urltype ut = urlPath(av[0], &fn); 00833 00834 xx = xx; 00835 00836 switch (ut) { 00837 case URL_IS_PATH: 00838 case URL_IS_UNKNOWN: 00839 fn = xstrdup(av[0]); 00840 break; 00841 case URL_IS_HTTPS: 00842 case URL_IS_HTTP: 00843 case URL_IS_FTP: 00844 case URL_IS_HKP: 00845 case URL_IS_DASH: 00846 default: 00847 /* HACK: strip the URI prefix for these schemes. */ 00848 fn = rpmGetPath(fn, NULL); 00849 break; 00850 } 00851 00852 /* Convert relative to absolute paths. */ 00853 if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */ 00854 if (fn && *fn && *fn != '/') { 00855 char dn[PATH_MAX]; 00856 char *t; 00857 dn[0] = '\0'; 00858 if ((t = Realpath(".", dn)) != NULL) { 00859 t += strlen(dn); 00860 if (t > dn && t[-1] != '/') 00861 *t++ = '/'; 00862 t = stpncpy(t, fn, (sizeof(dn) - (t - dn))); 00863 *t = '\0'; 00864 fn = _free(fn); 00865 fn = rpmGetPath(dn, NULL); 00866 } 00867 } 00868 00869 av = argvFree(av); 00870 s = _free(s); 00871 assert(fn != NULL); 00872 return fn; 00873 } 00874 00875 #define _DB_ROOT "/" 00876 #define _DB_HOME "%{?_dbpath}" 00877 #define _DB_FLAGS 0 00878 #define _DB_MODE 0 00879 #define _DB_PERMS 0644 00880 00881 #define _DB_MAJOR 3 00882 #define _DB_ERRPFX "rpmdb" 00883 00884 /*@-exportheader -globs -mods @*/ 00885 /*@only@*/ /*@null@*/ 00886 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root, 00887 /*@kept@*/ /*@null@*/ const char * home, 00888 int mode, mode_t perms, int flags) 00889 /*@*/ 00890 { 00891 rpmdb db = rpmdbGetPool(_rpmdbPool); 00892 const char * epfx = _DB_ERRPFX; 00893 00894 /*@-modfilesys@*/ /*@-nullpass@*/ 00895 if (_rpmdb_debug) 00896 fprintf(stderr, "==> rpmdbNew(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", root, home, mode, perms, flags, db); 00897 /*@=modfilesys@*/ /*@=nullpass@*/ 00898 00899 if (!(perms & 0600)) perms = 0644; /* XXX sanity */ 00900 00901 db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) ); 00902 db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) ); 00903 00904 if (!(db->db_home && db->db_home[0] && db->db_home[0] != '%')) { 00905 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n")); 00906 db->db_root = _free(db->db_root); 00907 db->db_home = _free(db->db_home); 00908 db = (rpmdb) rpmioPutPool((rpmioItem)db); 00909 /*@-globstate@*/ return NULL; /*@=globstate@*/ 00910 } 00911 00912 db->db_flags = (flags >= 0) ? flags : _DB_FLAGS; 00913 db->db_mode = (mode >= 0) ? mode : _DB_MODE; 00914 db->db_perms = (perms > 0) ? perms : _DB_PERMS; 00915 db->db_api = _DB_MAJOR; 00916 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL); 00917 00918 db->db_remove_env = 0; 00919 db->db_chrootDone = 0; 00920 db->db_maxkey = 0; 00921 db->db_errcall = NULL; 00922 db->db_errfile = NULL; 00923 db->db_malloc = NULL; 00924 db->db_realloc = NULL; 00925 db->db_free = NULL; 00926 db->db_export = rpmdbExportInfo; 00927 db->db_h = NULL; 00928 00929 db->db_next = NULL; 00930 db->db_opens = 0; 00931 00932 db->db_dbenv = NULL; 00933 db->db_txn = NULL; 00934 db->db_logc = NULL; 00935 db->db_mpf = NULL; 00936 00937 dbiTagsInit(&db->db_tags, &db->db_ndbi); 00938 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi)); 00939 00940 memset(&db->db_getops, 0, sizeof(db->db_getops)); 00941 memset(&db->db_putops, 0, sizeof(db->db_putops)); 00942 memset(&db->db_delops, 0, sizeof(db->db_delops)); 00943 00944 /*@-globstate@*/ 00945 return rpmdbLink(db, __FUNCTION__); 00946 /*@=globstate@*/ 00947 } 00948 /*@=exportheader =globs =mods @*/ 00949 00950 static int rpmdbOpenDatabase(/*@null@*/ const char * prefix, 00951 /*@null@*/ const char * dbpath, 00952 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp, 00953 int mode, mode_t perms, int flags) 00954 /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno, 00955 fileSystem, internalState @*/ 00956 /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext, 00957 fileSystem, internalState @*/ 00958 { 00959 rpmdb db; 00960 int rc; 00961 int xx; 00962 00963 /* Insure that _dbapi has one of -1, 1, 2, or 3 */ 00964 if (_dbapi < -1 || _dbapi > 4) 00965 _dbapi = -1; 00966 if (_dbapi == 0) 00967 _dbapi = 1; 00968 00969 if (dbp) 00970 *dbp = NULL; 00971 if (mode & O_WRONLY) 00972 return 1; 00973 00974 db = rpmdbNew(prefix, dbpath, mode, perms, flags); 00975 if (db == NULL) 00976 return 1; 00977 00978 if (rpmdbRock == NULL && rpmmiRock == NULL) { 00979 /* First open installs special signal handling. */ 00980 (void) rpmsqEnable(SIGHUP, NULL); 00981 (void) rpmsqEnable(SIGINT, NULL); 00982 (void) rpmsqEnable(SIGTERM, NULL); 00983 (void) rpmsqEnable(SIGQUIT, NULL); 00984 (void) rpmsqEnable(SIGPIPE, NULL); 00985 } 00986 00987 /*@-assignexpose -newreftrans@*/ 00988 /*@i@*/ db->db_next = rpmdbRock; 00989 rpmdbRock = db; 00990 /*@=assignexpose =newreftrans@*/ 00991 00992 db->db_api = _dbapi; 00993 00994 { size_t dbix; 00995 00996 rc = 0; 00997 if (db->db_tags != NULL) 00998 for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) { 00999 tagStore_t dbiTag = db->db_tags + dbix; 01000 rpmTag tag = dbiTag->tag; 01001 dbiIndex dbi; 01002 01003 /* Filter out temporary databases */ 01004 switch (tag) { 01005 case RPMDBI_AVAILABLE: 01006 case RPMDBI_ADDED: 01007 case RPMDBI_REMOVED: 01008 case RPMDBI_DEPENDS: 01009 continue; 01010 /*@notreached@*/ /*@switchbreak@*/ break; 01011 default: 01012 /*@switchbreak@*/ break; 01013 } 01014 01015 dbi = dbiOpen(db, tag, 0); 01016 if (dbi == NULL) { 01017 rc = -2; 01018 break; 01019 } 01020 01021 switch (tag) { 01022 case RPMDBI_PACKAGES: 01023 if (dbi == NULL) rc |= 1; 01024 #if 0 01025 /* XXX open only Packages, indices created on the fly. */ 01026 if (db->db_api == 3) 01027 #endif 01028 goto exit; 01029 /*@notreached@*/ /*@switchbreak@*/ break; 01030 case RPMTAG_NAME: 01031 if (dbi == NULL) rc |= 1; 01032 /*@switchbreak@*/ break; 01033 default: 01034 /*@switchbreak@*/ break; 01035 } 01036 } 01037 } 01038 01039 exit: 01040 if (rc || dbp == NULL) 01041 xx = rpmdbClose(db); 01042 else { 01043 /*@-assignexpose -newreftrans@*/ 01044 /*@i@*/ *dbp = db; 01045 /*@=assignexpose =newreftrans@*/ 01046 } 01047 01048 return rc; 01049 } 01050 01051 /* XXX python/rpmmodule.c */ 01052 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, mode_t perms) 01053 { 01054 int _dbapi = rpmExpandNumeric("%{?_dbapi}"); 01055 return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0); 01056 } 01057 01058 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen) 01059 { 01060 unsigned int count = 0; 01061 DBC * dbcursor = NULL; 01062 DBT k = DBT_INIT; 01063 DBT v = DBT_INIT; 01064 dbiIndex dbi; 01065 int rc; 01066 int xx; 01067 01068 if (db == NULL || keyp == NULL) 01069 return 0; 01070 01071 dbi = dbiOpen(db, tag, 0); 01072 if (dbi == NULL) 01073 return 0; 01074 01075 if (keylen == 0) 01076 keylen = strlen(keyp); 01077 01078 /*@-temptrans@*/ 01079 k.data = (void *) keyp; 01080 /*@=temptrans@*/ 01081 k.size = (UINT32_T) keylen; 01082 01083 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01084 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET); 01085 switch (rc) { 01086 case 0: 01087 rc = dbiCount(dbi, dbcursor, &count, 0); 01088 if (rc != 0) 01089 rc = -1; 01090 else 01091 rc = count; 01092 break; 01093 case DB_NOTFOUND: 01094 rc = 0; 01095 break; 01096 default: 01097 rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"), 01098 rc, tagName(dbi->dbi_rpmtag)); 01099 rc = -1; 01100 break; 01101 } 01102 xx = dbiCclose(dbi, dbcursor, 0); 01103 dbcursor = NULL; 01104 return rc; 01105 } 01106 01107 /* XXX python/upgrade.c, install.c, uninstall.c */ 01108 int rpmdbCountPackages(rpmdb db, const char * N) 01109 { 01110 return rpmdbCount(db, RPMTAG_NAME, N, strlen(N)); 01111 } 01112 01113 /* Return pointer to first RE character (or NUL terminator) */ 01114 static const char * stemEnd(const char * s) 01115 /*@*/ 01116 { 01117 int c; 01118 01119 while ((c = (int)*s)) { 01120 switch (c) { 01121 case '.': 01122 case '^': 01123 case '$': 01124 case '?': 01125 case '*': 01126 case '+': 01127 case '|': 01128 case '[': 01129 case '(': 01130 case '{': 01131 case '\0': 01132 goto exit; 01133 /*@notreached@*/ /*@switchbreak@*/ break; 01134 case '\\': 01135 s++; 01136 if (*s == '\0') goto exit; 01137 /*@fallthrough@*/ 01138 default: 01139 /*@switchbreak@*/ break; 01140 } 01141 s++; 01142 } 01143 exit: 01144 return s; 01145 } 01146 01147 /*@only@*/ 01148 static const char * _str2PCREpat(/*@null@*/ const char *_pre, const char *s, 01149 /*@null@*/ const char *_post) 01150 /*@*/ 01151 { 01152 static const char _REchars[] = "^.*(|)[]+?{}$"; 01153 size_t nt = 0; 01154 const char * se; 01155 char * t; 01156 char * te; 01157 01158 /* Find the PCRE pattern length, including escapes. */ 01159 for (se = s; *se != '\0'; se++, nt++) 01160 if (strchr(_REchars, *se)) nt++; 01161 nt += strlen(_pre) + strlen(_post); 01162 01163 /* Build the PCRE pattern, escaping characters as needed. */ 01164 te = t = xmalloc(nt + 1); 01165 te = stpcpy(te, _pre); 01166 for (se = s; *se != '\0'; *te++ = *se++) 01167 if (strchr(_REchars, *se)) *te++ = '\\'; 01168 te = stpcpy(te, _post); 01169 *te = '\0'; 01170 01171 /*@-dependenttrans@*/ 01172 return t; 01173 /*@=dependenttrans@*/ 01174 } 01175 01186 static int dbiMireKeys(rpmdb db, rpmTag tag, rpmMireMode mode, 01187 /*@null@*/ const char * pat, 01188 /*@null@*/ dbiIndexSet * matches, 01189 /*@null@*/ const char *** argvp) 01190 /*@globals internalState @*/ 01191 /*@modifies *matches, *argvp, internalState @*/ 01192 { 01193 DBC * dbcursor = NULL; 01194 DBT k = DBT_INIT; 01195 DBT p = DBT_INIT; 01196 DBT v = DBT_INIT; 01197 dbiIndex dbi; 01198 miRE mire = NULL; 01199 uint32_t _flags = DB_NEXT; 01200 ARGV_t av = NULL; 01201 dbiIndexSet set = NULL; 01202 const char * b = NULL; 01203 size_t nb = 0; 01204 int ret = 1; /* assume error */ 01205 int rc; 01206 int xx; 01207 01208 dbi = dbiOpen(db, tag, 0); 01209 if (dbi == NULL) 01210 goto exit; 01211 01212 if (_rpmmi_debug || dbi->dbi_debug) 01213 fprintf(stderr, "--> %s(%p, %s(%u), %d, \"%s\", %p, %p)\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, matches, argvp); 01214 01215 if (pat) { 01216 01217 mire = mireNew(mode, 0); 01218 xx = mireRegcomp(mire, pat); 01219 01220 /* Initialize the secondary retrieval key. */ 01221 switch (mode) { 01222 default: 01223 assert(0); /* XXX sanity */ 01224 /*@notreached@*/ break; 01225 case RPMMIRE_GLOB: 01226 break; 01227 case RPMMIRE_REGEX: 01228 case RPMMIRE_PCRE: 01229 if (*pat == '^') pat++; 01230 01231 /* If partial match on stem won't help, just iterate. */ 01232 nb = stemEnd(pat) - pat; 01233 if (nb == 0) { 01234 k.doff = 0; 01235 goto doit; 01236 } 01237 01238 /* Remove the escapes in the stem. */ 01239 { char *be; 01240 b = be = xmalloc(nb + 1); 01241 while (nb--) { 01242 if ((*be = *pat++) != '\\') 01243 be++; 01244 } 01245 *be = '\0'; 01246 } 01247 nb = strlen(b); 01248 01249 /* Set stem length for partial match retrieve. */ 01250 k.flags = DB_DBT_PARTIAL; 01251 k.dlen = nb; 01252 k.size = nb; 01253 k.data = (void *) b; 01254 _flags = DB_SET_RANGE; 01255 break; 01256 case RPMMIRE_STRCMP: 01257 k.size = (UINT32_T) strlen(pat); 01258 k.data = (void *) pat; 01259 _flags = DB_SET; 01260 break; 01261 } 01262 } 01263 01264 doit: 01265 p.flags |= DB_DBT_PARTIAL; 01266 v.flags |= DB_DBT_PARTIAL; 01267 01268 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01269 01270 /* Iterate over matches, collecting primary/secondary keys. */ 01271 while ((rc = dbiPget(dbi, dbcursor, &k, &p, &v, _flags)) == 0) { 01272 uint32_t hdrNum; 01273 const char * s; 01274 size_t ns; 01275 01276 if (_flags == DB_SET) _flags = DB_NEXT_DUP; 01277 if (b != NULL && nb > 0) { 01278 01279 /* Exit if the stem doesn't match. */ 01280 if (k.size < nb || memcmp(b, k.data, nb)) 01281 break; 01282 01283 /* Retrieve the full record after DB_SET_RANGE. */ 01284 if (_flags == DB_SET_RANGE) { 01285 memset (&k, 0, sizeof(k)); 01286 xx = dbiPget(dbi, dbcursor, &k, &p, &v, DB_CURRENT); 01287 _flags = DB_NEXT; 01288 } 01289 } 01290 01291 /* Get the secondary key. */ 01292 s = (const char * ) k.data; 01293 ns = k.size; 01294 01295 /* Skip if not matched. */ 01296 if (mire && mireRegexec(mire, s, ns) < 0) 01297 continue; 01298 01299 /* Get a native endian copy of the primary package key. */ 01300 memcpy(&hdrNum, p.data, sizeof(hdrNum)); 01301 hdrNum = _ntoh_ui(hdrNum); 01302 01303 /* Collect primary keys. */ 01304 if (matches) { 01305 if (set == NULL) 01306 set = xcalloc(1, sizeof(*set)); 01307 /* XXX TODO: sort/uniqify set? */ 01308 (void) dbiAppendSet(set, &hdrNum, 1, sizeof(hdrNum), 0); 01309 } 01310 01311 /* Collect secondary keys. */ 01312 if (argvp) { 01313 char * a = memcpy(xmalloc(ns+1), s, ns); 01314 a[ns] = '\0'; 01315 xx = argvAdd(&av, a); 01316 a = _free(a); 01317 } 01318 } 01319 01320 xx = dbiCclose(dbi, dbcursor, 0); 01321 dbcursor = NULL; 01322 01323 switch (rc) { 01324 case 0: 01325 case DB_NOTFOUND: 01326 ret = 0; 01327 break; 01328 default: 01329 rpmlog(RPMLOG_ERR, _("error(%d) getting keys from %s index\n"), 01330 rc, tagName(dbi->dbi_rpmtag)); 01331 break; 01332 } 01333 01334 exit: 01335 if (ret == 0) { 01336 if (matches) { 01337 /* XXX TODO: sort/uniqify set? */ 01338 *matches = set; 01339 set = NULL; 01340 } 01341 if (argvp) 01342 xx = argvAppend(argvp, av); 01343 } 01344 set = dbiFreeIndexSet(set); 01345 av = argvFree(av); 01346 b = _free(b); 01347 mire = mireFree(mire); 01348 if (_rpmmi_debug || dbi->dbi_debug) 01349 fprintf(stderr, "<-- %s(%p, %s(%u), %d, %p, %p, %p) rc %d %p[%u]\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, matches, argvp, ret, (matches && *matches ? (*matches)->recs : NULL), (matches && *matches ? (*matches)->count : 0)); 01350 return ret; 01351 } 01352 01353 int rpmdbMireApply(rpmdb db, rpmTag tag, rpmMireMode mode, const char * pat, 01354 const char *** argvp) 01355 { 01356 int rc = dbiMireKeys(db, tag, mode, pat, NULL, argvp); 01357 if (_rpmmi_debug) 01358 fprintf(stderr, "<-- %s(%p, %s(%u), %d, \"%s\", %p) rc %d\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, argvp, rc); 01359 return rc; 01360 } 01361 01362 int rpmmiGrowBasename(rpmmi mi, const char * bn) 01363 { 01364 rpmTag _tag = RPMTAG_BASENAMES; 01365 rpmMireMode _mode = RPMMIRE_STRCMP; 01366 dbiIndexSet set = NULL; 01367 unsigned int i; 01368 int rc = 1; /* assume error */ 01369 01370 if (mi == NULL || mi->mi_db == NULL || bn == NULL || *bn == '\0') 01371 goto exit; 01372 01373 #ifdef NOTYET 01374 assert(mi->mi_rpmtag == _tag); 01375 #endif 01376 /* Retrieve set of headers that contain the base name. */ 01377 rc = dbiMireKeys(mi->mi_db, _tag, _mode, bn, &set, NULL); 01378 if (rc == 0 && set != NULL) { 01379 rpmuint32_t tagNum = hashFunctionString(0, bn, 0); 01380 /* Set tagNum to the hash of the basename. */ 01381 for (i = 0; i < set->count; i++) 01382 set->recs[i].tagNum = tagNum; 01383 if (mi->mi_set == NULL) 01384 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set)); 01385 (void) dbiAppendSet(mi->mi_set, set->recs, set->count, sizeof(*set->recs), 0); 01386 } 01387 rc = 0; 01388 01389 exit: 01390 if (_rpmmi_debug) 01391 fprintf(stderr, "<-- %s(%p, \"%s\")\trc %d set %p %p[%u]\n", __FUNCTION__, mi, bn, rc, set, (set ? set->recs : NULL), (unsigned)(set ? set->count : 0)); 01392 set = dbiFreeIndexSet(set); 01393 return rc; 01394 } 01395 01403 static rpmRC dbiFindMatches(dbiIndex dbi, 01404 const char * pat, /*@out@*/ dbiIndexSet * matches) 01405 /*@*/ 01406 { 01407 const char * s = pat; 01408 size_t ns = (s ? strlen(s) : 0); 01409 DBC * dbcursor = NULL; 01410 rpmRC rc = RPMRC_NOTFOUND; 01411 int ret; 01412 int xx; 01413 01414 if (ns == 0) goto exit; 01415 01416 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01417 01418 /* Add ^...$ *RE anchors. Escape pattern characters. */ 01419 { rpmTag tag = dbi->dbi_rpmtag; 01420 rpmMireMode mode = RPMMIRE_PCRE; 01421 static const char _post_NVRA[] = "(-[^-]+-[^-]+\\.[^.]+|-[^-]+\\.[^.]+|\\.[^.]+|)$"; 01422 const char * _pat; 01423 01424 switch (tag) { 01425 default: 01426 mode = RPMMIRE_PCRE; 01427 _pat = _str2PCREpat("^", s, ".*$"); 01428 break; 01429 case RPMTAG_NVRA: 01430 mode = RPMMIRE_PCRE; 01431 _pat = (s[0] == '^' || s[ns-1] == '$') 01432 ? xstrdup(s) 01433 : _str2PCREpat("^", s, _post_NVRA); 01434 break; 01435 case RPMTAG_FILEPATHS: 01436 if (s[0] == '^' || s[ns-1] == '$') 01437 mode = RPMMIRE_PCRE; 01438 else 01439 #ifdef NOTYET 01440 if (s[0] == '/' && Glob_pattern_p(s, 1)) 01441 mode = RPMMIRE_GLOB; 01442 else 01443 #endif 01444 mode = RPMMIRE_STRCMP; 01445 _pat = xstrdup(s); 01446 break; 01447 } 01448 01449 ret = dbiMireKeys(dbi->dbi_rpmdb, tag, mode, _pat, matches, NULL); 01450 01451 _pat = _free(_pat); 01452 } 01453 01454 switch (ret) { 01455 case 0: rc = RPMRC_OK; break; 01456 case DB_NOTFOUND: rc = RPMRC_NOTFOUND; break; 01457 default: rc = RPMRC_FAIL; 01458 rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"), 01459 ret, tagName(dbi->dbi_rpmtag)); 01460 break; 01461 } 01462 01463 xx = dbiCclose(dbi, dbcursor, 0); 01464 dbcursor = NULL; 01465 01466 exit: 01467 /*@-unqualifiedtrans@*/ /* FIX: double indirection */ 01468 if (rc != RPMRC_OK && matches && *matches) 01469 *matches = dbiFreeIndexSet(*matches); 01470 /*@=unqualifiedtrans@*/ 01471 return rc; 01472 } 01473 01474 void * dbiStatsAccumulator(dbiIndex dbi, int opx) 01475 { 01476 void * sw = NULL; 01477 switch (opx) { 01478 case 14: /* RPMTS_OP_DBGET */ 01479 sw = &dbi->dbi_rpmdb->db_getops; 01480 break; 01481 case 15: /* RPMTS_OP_DBPUT */ 01482 sw = &dbi->dbi_rpmdb->db_putops; 01483 break; 01484 default: /* XXX wrong, but let's not return NULL. */ 01485 case 16: /* RPMTS_OP_DBDEL */ 01486 sw = &dbi->dbi_rpmdb->db_delops; 01487 break; 01488 } 01489 return sw; 01490 } 01491 01500 static int miFreeHeader(rpmmi mi, dbiIndex dbi) 01501 /*@globals fileSystem, internalState @*/ 01502 /*@modifies mi, dbi, fileSystem, internalState @*/ 01503 { 01504 int rc = 0; 01505 01506 if (mi == NULL || mi->mi_h == NULL) 01507 return 0; 01508 01509 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) { 01510 DBT k = DBT_INIT; 01511 DBT v = DBT_INIT; 01512 int xx; 01513 01514 /*@i@*/ k.data = (void *) &mi->mi_prevoffset; 01515 k.size = (UINT32_T) sizeof(mi->mi_prevoffset); 01516 { size_t len = 0; 01517 v.data = headerUnload(mi->mi_h, &len); 01518 v.size = (UINT32_T) len; 01519 } 01520 01521 if (v.data != NULL) { 01522 sigset_t signalMask; 01523 (void) blockSignals(dbi->dbi_rpmdb, &signalMask); 01524 rc = dbiPut(dbi, mi->mi_dbc, &k, &v, DB_KEYLAST); 01525 if (rc) { 01526 rpmlog(RPMLOG_ERR, 01527 _("error(%d) storing record h#%u into %s\n"), 01528 rc, (unsigned)_ntoh_ui(mi->mi_prevoffset), 01529 tagName(dbi->dbi_rpmtag)); 01530 } 01531 xx = dbiSync(dbi, 0); 01532 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask); 01533 } 01534 v.data = _free(v.data); /* headerUnload */ 01535 v.size = 0; 01536 } 01537 01538 (void)headerFree(mi->mi_h); 01539 mi->mi_h = NULL; 01540 01541 /*@-nullstate@*/ 01542 return rc; 01543 /*@=nullstate@*/ 01544 } 01545 01546 static void rpmmiFini(void * _mi) 01547 /*@globals rpmmiRock @*/ 01548 /*@modifies _mi, rpmmiRock @*/ 01549 { 01550 rpmmi mi = _mi; 01551 rpmmi * prev, next; 01552 dbiIndex dbi; 01553 int xx; 01554 01555 prev = &rpmmiRock; 01556 while ((next = *prev) != NULL && next != mi) 01557 prev = &next->mi_next; 01558 if (next) { 01559 /*@i@*/ *prev = next->mi_next; 01560 next->mi_next = NULL; 01561 } 01562 01563 /* XXX NOTFOUND exits traverse here w mi->mi_db == NULL. b0rked imho. */ 01564 if (mi->mi_db) { 01565 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0); 01566 assert(dbi != NULL); /* XXX sanity */ 01567 01568 xx = miFreeHeader(mi, dbi); 01569 01570 if (mi->mi_dbc) 01571 xx = dbiCclose(dbi, mi->mi_dbc, 0); 01572 mi->mi_dbc = NULL; 01573 /* XXX rpmdbUnlink will not do. 01574 * NB: must be called after rpmmiRock cleanup. 01575 */ 01576 (void) rpmdbClose(mi->mi_db); 01577 mi->mi_db = NULL; 01578 } 01579 01580 (void) mireFreeAll(mi->mi_re, mi->mi_nre); 01581 mi->mi_re = NULL; 01582 01583 (void) rpmbfFree(mi->mi_bf); 01584 mi->mi_bf = NULL; 01585 mi->mi_set = dbiFreeIndexSet(mi->mi_set); 01586 01587 mi->mi_keyp = _free(mi->mi_keyp); 01588 mi->mi_keylen = 0; 01589 mi->mi_primary = _free(mi->mi_primary); 01590 01591 /* XXX this needs to be done elsewhere, not within destructor. */ 01592 (void) rpmdbCheckSignals(); 01593 } 01594 01595 /*@unchecked@*/ /*@only@*/ /*@null@*/ 01596 rpmioPool _rpmmiPool; 01597 01598 static rpmmi rpmmiGetPool(/*@null@*/ rpmioPool pool) 01599 /*@globals _rpmdbPool, fileSystem @*/ 01600 /*@modifies pool, _rpmdbPool, fileSystem @*/ 01601 { 01602 rpmmi mi; 01603 01604 if (_rpmmiPool == NULL) { 01605 _rpmmiPool = rpmioNewPool("mi", sizeof(*mi), -1, _rpmmi_debug, 01606 NULL, NULL, rpmmiFini); 01607 pool = _rpmmiPool; 01608 } 01609 mi = (rpmmi) rpmioGetPool(pool, sizeof(*mi)); 01610 memset(((char *)mi)+sizeof(mi->_item), 0, sizeof(*mi)-sizeof(mi->_item)); 01611 return mi; 01612 } 01613 01614 uint32_t rpmmiInstance(rpmmi mi) 01615 { 01616 /* Get a native endian copy of the primary package key. */ 01617 uint32_t rc = _ntoh_ui(mi ? mi->mi_offset : 0); 01618 if (_rpmmi_debug) 01619 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01620 return rc; 01621 } 01622 01623 uint32_t rpmmiBNTag(rpmmi mi) { 01624 uint32_t rc = (mi ? mi->mi_bntag : 0); 01625 if (_rpmmi_debug) 01626 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01627 return rc; 01628 } 01629 01630 unsigned int rpmmiCount(rpmmi mi) 01631 { 01632 unsigned int rc; 01633 int initDbc; 01634 01635 /* XXX Secondary db associated with Packages needs cursor record count */ 01636 if (mi && mi->mi_primary && ((initDbc = mi->mi_dbc == NULL) || mi->mi_count == 0)) { 01637 dbiIndex dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0); 01638 DBT k = DBT_INIT; 01639 DBT v = DBT_INIT; 01640 int xx; 01641 if(initDbc) { 01642 assert(dbi != NULL); /* XXX dbiCopen doesn't handle dbi == NULL */ 01643 xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags); 01644 } 01645 k.data = mi->mi_keyp; 01646 k.size = (u_int32_t)mi->mi_keylen; 01647 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data); 01648 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */ 01649 if (!dbiGet(dbi, mi->mi_dbc, &k, &v, DB_SET)) 01650 xx = dbiCount(dbi, mi->mi_dbc, &mi->mi_count, 0); 01651 if(initDbc) 01652 mi->mi_dbc = NULL; 01653 } 01654 01655 rc = (mi ? mi->mi_count : 0); 01656 01657 if (_rpmmi_debug) 01658 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01659 return rc; 01660 } 01661 01668 static int mireCmp(const void * a, const void * b) 01669 { 01670 /*@-castexpose @*/ 01671 const miRE mireA = (const miRE) a; 01672 const miRE mireB = (const miRE) b; 01673 /*@=castexpose @*/ 01674 return (mireA->tag - mireB->tag); 01675 } 01676 01684 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep, 01685 const char * pattern) 01686 /*@modifies *modep @*/ 01687 /*@requires maxSet(modep) >= 0 @*/ 01688 { 01689 const char * s; 01690 char * pat; 01691 char * t; 01692 int brackets; 01693 size_t nb; 01694 int c; 01695 01696 switch (*modep) { 01697 default: 01698 case RPMMIRE_DEFAULT: 01699 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES 01700 || tag == RPMTAG_FILEPATHS) 01701 { 01702 *modep = RPMMIRE_GLOB; 01703 pat = xstrdup(pattern); 01704 break; 01705 } 01706 01707 nb = strlen(pattern) + sizeof("^$"); 01708 01709 /* Find no. of bytes needed for pattern. */ 01710 /* periods and plusses are escaped, splats become '.*' */ 01711 c = (int) '\0'; 01712 brackets = 0; 01713 for (s = pattern; *s != '\0'; s++) { 01714 switch (*s) { 01715 case '.': 01716 case '+': 01717 case '*': 01718 if (!brackets) nb++; 01719 /*@switchbreak@*/ break; 01720 case '\\': 01721 s++; 01722 /*@switchbreak@*/ break; 01723 case '[': 01724 brackets = 1; 01725 /*@switchbreak@*/ break; 01726 case ']': 01727 if (c != (int) '[') brackets = 0; 01728 /*@switchbreak@*/ break; 01729 } 01730 c = (int) *s; 01731 } 01732 01733 pat = t = xmalloc(nb); 01734 01735 if (pattern[0] != '^') *t++ = '^'; 01736 01737 /* Copy pattern, escaping periods, prefixing splats with period. */ 01738 c = (int) '\0'; 01739 brackets = 0; 01740 for (s = pattern; *s != '\0'; s++, t++) { 01741 switch (*s) { 01742 case '.': 01743 case '+': 01744 if (!brackets) *t++ = '\\'; 01745 /*@switchbreak@*/ break; 01746 case '*': 01747 if (!brackets) *t++ = '.'; 01748 /*@switchbreak@*/ break; 01749 case '\\': 01750 *t++ = *s++; 01751 /*@switchbreak@*/ break; 01752 case '[': 01753 brackets = 1; 01754 /*@switchbreak@*/ break; 01755 case ']': 01756 if (c != (int) '[') brackets = 0; 01757 /*@switchbreak@*/ break; 01758 } 01759 *t = *s; 01760 c = (int) *t; 01761 } 01762 01763 if (s > pattern && s[-1] != '$') *t++ = '$'; 01764 *t = '\0'; 01765 *modep = RPMMIRE_REGEX; 01766 break; 01767 case RPMMIRE_STRCMP: 01768 case RPMMIRE_REGEX: 01769 case RPMMIRE_GLOB: 01770 pat = xstrdup(pattern); 01771 break; 01772 } 01773 01774 return pat; 01775 } 01776 01777 int rpmmiAddPattern(rpmmi mi, rpmTag tag, 01778 rpmMireMode mode, const char * pattern) 01779 { 01780 static rpmMireMode defmode = (rpmMireMode)-1; 01781 miRE nmire = NULL; 01782 miRE mire = NULL; 01783 const char * allpat = NULL; 01784 int notmatch = 0; 01785 int rc = 0; 01786 01787 if (defmode == (rpmMireMode)-1) { 01788 const char *t = rpmExpand("%{?_query_selector_match}", NULL); 01789 01790 if (*t == '\0' || !strcmp(t, "default")) 01791 defmode = RPMMIRE_DEFAULT; 01792 else if (!strcmp(t, "strcmp")) 01793 defmode = RPMMIRE_STRCMP; 01794 else if (!strcmp(t, "regex")) 01795 defmode = RPMMIRE_REGEX; 01796 else if (!strcmp(t, "glob")) 01797 defmode = RPMMIRE_GLOB; 01798 else 01799 defmode = RPMMIRE_DEFAULT; 01800 t = _free(t); 01801 } 01802 01803 if (mi == NULL || pattern == NULL) 01804 return rc; 01805 01806 /* Leading '!' inverts pattern match sense, like "grep -v". */ 01807 if (*pattern == '!') { 01808 notmatch = 1; 01809 pattern++; 01810 } 01811 01812 nmire = mireNew(mode, tag); 01813 assert(nmire != NULL); 01814 allpat = mireDup(nmire->tag, &nmire->mode, pattern); 01815 01816 if (nmire->mode == RPMMIRE_DEFAULT) 01817 nmire->mode = defmode; 01818 01819 rc = mireRegcomp(nmire, allpat); 01820 if (rc) 01821 goto exit; 01822 01823 if (mi->mi_re == NULL) { 01824 mi->mi_re = mireGetPool(_mirePool); 01825 mire = mireLink(mi->mi_re); 01826 } else { 01827 void *use = mi->mi_re->_item.use; 01828 void *pool = mi->mi_re->_item.pool; 01829 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re)); 01830 if (_mire_debug) 01831 fprintf(stderr, " mire %p[%u] realloc\n", mi->mi_re, mi->mi_nre+1); 01832 mire = mi->mi_re + mi->mi_nre; 01833 memset(mire, 0, sizeof(*mire)); 01834 /* XXX ensure no segfault, copy the use/pool from 1st item. */ 01835 /*@-assignexpose@*/ 01836 mire->_item.use = use; 01837 mire->_item.pool = pool; 01838 /*@=assignexpose@*/ 01839 } 01840 mi->mi_nre++; 01841 01842 mire->mode = nmire->mode; 01843 mire->pattern = nmire->pattern; nmire->pattern = NULL; 01844 mire->preg = nmire->preg; nmire->preg = NULL; 01845 mire->cflags = nmire->cflags; 01846 mire->eflags = nmire->eflags; 01847 mire->fnflags = nmire->fnflags; 01848 mire->tag = nmire->tag; 01849 mire->notmatch = notmatch; 01850 /* XXX todo: permit PCRE patterns to be used. */ 01851 mire->offsets = NULL; 01852 mire->noffsets = 0; 01853 01854 if (mi->mi_nre > 1) 01855 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp); 01856 01857 exit: 01858 if (_rpmmi_debug) 01859 fprintf(stderr, "<-- %s(%p, %u(%s), %u, \"%s\") rc %d mi_re %p[%u]\n", __FUNCTION__, mi, (unsigned)tag, tagName(tag), (unsigned)mode, pattern, rc, (mi ? mi->mi_re: NULL), (unsigned)(mi ? mi->mi_nre : 0)); 01860 allpat = _free(allpat); 01861 nmire = mireFree(nmire); 01862 return rc; 01863 } 01864 01870 static inline unsigned char nibble(char c) 01871 /*@*/ 01872 { 01873 if (c >= '0' && c <= '9') 01874 return (unsigned char)(c - '0'); 01875 if (c >= 'A' && c <= 'F') 01876 return (unsigned char)((int)(c - 'A') + 10); 01877 if (c >= 'a' && c <= 'f') 01878 return (unsigned char)((int)(c - 'a') + 10); 01879 return '\0'; 01880 } 01881 01888 /*@only@*/ 01889 static char * bin2hex(const void *data, size_t size) 01890 /*@*/ 01891 { 01892 static char hex[] = "0123456789abcdef"; 01893 const char * s = data; 01894 char * t, * val; 01895 val = t = xmalloc(size * 2 + 1); 01896 while (size-- > 0) { 01897 unsigned i; 01898 i = (unsigned) *s++; 01899 *t++ = hex[ (i >> 4) & 0xf ]; 01900 *t++ = hex[ (i ) & 0xf ]; 01901 } 01902 *t = '\0'; 01903 01904 return val; 01905 } 01906 01912 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */ 01913 static int mireSkip (const rpmmi mi) 01914 /*@globals internalState @*/ 01915 /*@modifies mi->mi_re, internalState @*/ 01916 { 01917 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01918 char numbuf[32]; 01919 miRE mire; 01920 int ntags = 0; 01921 int nmatches = 0; 01922 int i; 01923 int rc; 01924 01925 if (mi->mi_h == NULL) /* XXX can't happen */ 01926 return 1; 01927 01928 /* 01929 * Apply tag tests, implicitly "||" for multiple patterns/values of a 01930 * single tag, implicitly "&&" between multiple tag patterns. 01931 */ 01932 if ((mire = mi->mi_re) == NULL) 01933 return 0; 01934 01935 for (i = 0; i < mi->mi_nre; i++, mire++) { 01936 int anymatch; 01937 01938 he->tag = mire->tag; 01939 01940 if (!headerGet(mi->mi_h, he, 0)) { 01941 if (he->tag != RPMTAG_EPOCH) { 01942 ntags++; 01943 continue; 01944 } 01945 he->t = RPM_UINT32_TYPE; 01946 he->p.ui32p = xcalloc(1, sizeof(*he->p.ui32p)); 01947 he->c = 1; 01948 } 01949 01950 anymatch = 0; /* no matches yet */ 01951 while (1) { 01952 unsigned j; 01953 switch (he->t) { 01954 case RPM_UINT8_TYPE: 01955 for (j = 0; j < (unsigned) he->c; j++) { 01956 sprintf(numbuf, "%u", (unsigned) he->p.ui8p[j]); 01957 rc = mireRegexec(mire, numbuf, 0); 01958 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01959 anymatch++; 01960 } 01961 /*@switchbreak@*/ break; 01962 case RPM_UINT16_TYPE: 01963 for (j = 0; j < (unsigned) he->c; j++) { 01964 sprintf(numbuf, "%u", (unsigned) he->p.ui16p[j]); 01965 rc = mireRegexec(mire, numbuf, 0); 01966 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01967 anymatch++; 01968 } 01969 /*@switchbreak@*/ break; 01970 case RPM_UINT32_TYPE: 01971 for (j = 0; j < (unsigned) he->c; j++) { 01972 sprintf(numbuf, "%u", (unsigned) he->p.ui32p[j]); 01973 rc = mireRegexec(mire, numbuf, 0); 01974 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01975 anymatch++; 01976 } 01977 /*@switchbreak@*/ break; 01978 case RPM_UINT64_TYPE: 01979 /*@-duplicatequals@*/ 01980 for (j = 0; j < (unsigned) he->c; j++) { 01981 sprintf(numbuf, "%llu", (unsigned long long)he->p.ui64p[j]); 01982 rc = mireRegexec(mire, numbuf, 0); 01983 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01984 anymatch++; 01985 } 01986 /*@=duplicatequals@*/ 01987 /*@switchbreak@*/ break; 01988 case RPM_STRING_TYPE: 01989 rc = mireRegexec(mire, he->p.str, 0); 01990 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01991 anymatch++; 01992 /*@switchbreak@*/ break; 01993 case RPM_STRING_ARRAY_TYPE: 01994 for (j = 0; j < (unsigned) he->c; j++) { 01995 rc = mireRegexec(mire, he->p.argv[j], 0); 01996 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) { 01997 anymatch++; 01998 /*@innerbreak@*/ break; 01999 } 02000 } 02001 /*@switchbreak@*/ break; 02002 case RPM_BIN_TYPE: 02003 { const char * s; 02004 assert(he->p.ptr != NULL); 02005 s = bin2hex(he->p.ptr, he->c); 02006 rc = mireRegexec(mire, s, 0); 02007 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 02008 anymatch++; 02009 s = _free(s); 02010 } /*@switchbreak@*/ break; 02011 case RPM_I18NSTRING_TYPE: 02012 default: 02013 /*@switchbreak@*/ break; 02014 } 02015 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) { 02016 i++; 02017 mire++; 02018 /*@innercontinue@*/ continue; 02019 } 02020 /*@innerbreak@*/ break; 02021 } 02022 02023 he->p.ptr = _free(he->p.ptr); 02024 02025 if (anymatch) 02026 nmatches++; 02027 ntags++; 02028 } 02029 02030 return (ntags > 0 && ntags == nmatches ? 0 : 1); 02031 } 02032 /*@=onlytrans@*/ 02033 02034 int rpmmiSetRewrite(rpmmi mi, int rewrite) 02035 { 02036 int rc; 02037 if (mi == NULL) 02038 return 0; 02039 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0; 02040 if (rewrite) 02041 mi->mi_cflags |= DB_WRITECURSOR; 02042 else 02043 mi->mi_cflags &= ~DB_WRITECURSOR; 02044 return rc; 02045 } 02046 02047 int rpmmiSetModified(rpmmi mi, int modified) 02048 { 02049 int rc; 02050 if (mi == NULL) 02051 return 0; 02052 rc = mi->mi_modified; 02053 mi->mi_modified = modified; 02054 return rc; 02055 } 02056 02057 /*@unchecked@*/ 02058 static int _rpmmi_usermem = 1; 02059 02060 static int rpmmiGet(dbiIndex dbi, DBC * dbcursor, DBT * kp, DBT * pk, DBT * vp, 02061 unsigned int flags) 02062 /*@globals internalState @*/ 02063 /*@modifies dbi, dbcursor, *kp, *pk, *vp, internalState @*/ 02064 { 02065 int map; 02066 int rc; 02067 02068 switch (dbi->dbi_rpmdb->db_api) { 02069 default: map = 0; break; 02070 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */ 02071 } 02072 02073 if (map) { 02074 static const int _prot = PROT_READ | PROT_WRITE; 02075 static const int _flags = MAP_PRIVATE| MAP_ANONYMOUS; 02076 static const int _fdno = -1; 02077 static const off_t _off = 0; 02078 02079 memset(vp, 0, sizeof(*vp)); 02080 vp->flags |= DB_DBT_USERMEM; 02081 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02082 if (rc == DB_BUFFER_SMALL) { 02083 size_t uhlen = vp->size; 02084 void * uh = mmap(NULL, uhlen, _prot, _flags, _fdno, _off); 02085 if (uh == NULL || uh == (void *)-1) 02086 fprintf(stderr, 02087 "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n", 02088 NULL, (unsigned)uhlen, _prot, _flags, _fdno, (unsigned)_off, 02089 errno, strerror(errno)); 02090 02091 vp->ulen = (u_int32_t)uhlen; 02092 vp->data = uh; 02093 if (dbi->dbi_primary && pk) 02094 rc = dbiPget(dbi, dbcursor, kp, pk, vp, flags); 02095 else 02096 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02097 if (rc == 0) { 02098 if (mprotect(uh, uhlen, PROT_READ) != 0) 02099 fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n", 02100 uh, (unsigned)uhlen, PROT_READ, 02101 errno, strerror(errno)); 02102 } else { 02103 if (munmap(uh, uhlen) != 0) 02104 fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n", 02105 uh, (unsigned)uhlen, errno, strerror(errno)); 02106 } 02107 } 02108 } else 02109 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02110 if (_rpmmi_debug || dbi->dbi_debug) 02111 fprintf(stderr, "<-- %s(%p(%s),%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbcursor, kp, vp, flags, rc); 02112 02113 return rc; 02114 } 02115 02116 Header rpmmiNext(rpmmi mi) 02117 { 02118 dbiIndex dbi; 02119 DBT k = DBT_INIT; 02120 DBT p = DBT_INIT; 02121 DBT v = DBT_INIT; 02122 void * uh; 02123 size_t uhlen; 02124 rpmTag tag; 02125 unsigned int _flags; 02126 int map; 02127 int rc; 02128 int xx; 02129 02130 if (mi == NULL) 02131 return NULL; 02132 02133 /* Find the tag to open. */ 02134 tag = (mi->mi_set == NULL && mi->mi_primary != NULL 02135 ? mi->mi_rpmtag : RPMDBI_PACKAGES); 02136 dbi = dbiOpen(mi->mi_db, tag, 0); 02137 if (dbi == NULL) 02138 return NULL; 02139 02140 switch (dbi->dbi_rpmdb->db_api) { 02141 default: map = 0; break; 02142 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */ 02143 } 02144 02145 if (_rpmmi_debug || dbi->dbi_debug) 02146 fprintf(stderr, "--> %s(%p) dbi %p(%s)\n", __FUNCTION__, mi, dbi, tagName(tag)); 02147 02148 /* 02149 * Cursors are per-iterator, not per-dbi, so get a cursor for the 02150 * iterator on 1st call. If the iteration is to rewrite headers, and the 02151 * CDB model is used for the database, then the cursor needs to 02152 * marked with DB_WRITECURSOR as well. 02153 */ 02154 if (mi->mi_dbc == NULL) { 02155 xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags); 02156 k.data = mi->mi_keyp; 02157 k.size = (u_int32_t)mi->mi_keylen; 02158 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data); 02159 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */ 02160 _flags = DB_SET; 02161 } else 02162 _flags = (mi->mi_setx ? DB_NEXT_DUP : DB_SET); 02163 02164 next: 02165 if (mi->mi_set) { 02166 /* The set of header instances is known in advance. */ 02167 if (!(mi->mi_setx < mi->mi_set->count)) 02168 return NULL; 02169 mi->mi_offset = _hton_ui(dbiIndexRecordOffset(mi->mi_set, mi->mi_setx)); 02170 mi->mi_bntag = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx); 02171 mi->mi_setx++; 02172 02173 /* If next header is identical, return it now. */ 02174 if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL) 02175 return mi->mi_h; 02176 02177 /* Should this header be skipped? */ 02178 if (mi->mi_bf != NULL 02179 && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0) 02180 goto next; 02181 02182 /* Fetch header by offset. */ 02183 k.data = &mi->mi_offset; 02184 k.size = (UINT32_T)sizeof(mi->mi_offset); 02185 rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_SET); 02186 } 02187 else if (dbi->dbi_primary) { 02188 rc = rpmmiGet(dbi, mi->mi_dbc, &k, &p, &v, _flags); 02189 switch (rc) { 02190 default: 02191 assert(0); 02192 /*@notreached@*/ break; 02193 case DB_NOTFOUND: 02194 return NULL; 02195 /*@notreached@*/ break; 02196 case 0: 02197 mi->mi_setx++; 02198 assert((size_t)p.size == sizeof(mi->mi_offset)); 02199 memcpy(&mi->mi_offset, p.data, sizeof(mi->mi_offset)); 02200 /* If next header is identical, return it now. */ 02201 if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL) 02202 return mi->mi_h; 02203 break; 02204 } 02205 _flags = DB_NEXT_DUP; 02206 } 02207 else { 02208 /* Iterating Packages database. */ 02209 assert(mi->mi_rpmtag == RPMDBI_PACKAGES); 02210 02211 /* Fetch header with DB_NEXT. */ 02212 /* Instance 0 is the largest header instance in legacy databases, 02213 * and must be skipped. */ 02214 do { 02215 rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_NEXT); 02216 if (rc == 0) { 02217 assert((size_t)k.size == sizeof(mi->mi_offset)); 02218 memcpy(&mi->mi_offset, k.data, sizeof(mi->mi_offset)); 02219 } 02220 } while (rc == 0 && mi->mi_offset == 0); 02221 } 02222 02223 /* Did the header blob load correctly? */ 02224 if (rc) 02225 return NULL; 02226 02227 /* Should this header be skipped? */ 02228 if (mi->mi_set == NULL && mi->mi_bf != NULL 02229 && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0) 02230 goto next; 02231 02232 uh = v.data; 02233 uhlen = v.size; 02234 if (uh == NULL) 02235 return NULL; 02236 02237 /* Rewrite current header (if necessary) and unlink. */ 02238 xx = miFreeHeader(mi, dbi); 02239 02240 if (map) { 02241 /*@-onlytrans@*/ 02242 mi->mi_h = headerLoad(uh); 02243 /*@=onlytrans@*/ 02244 if (mi->mi_h) { 02245 mi->mi_h->flags |= HEADERFLAG_MAPPED; 02246 mi->mi_h->flags |= HEADERFLAG_RDONLY; 02247 } 02248 } else 02249 mi->mi_h = headerCopyLoad(uh); 02250 02251 if (mi->mi_h == NULL) { 02252 rpmlog(RPMLOG_ERR, 02253 _("rpmdb: header #%u cannot be loaded -- skipping.\n"), 02254 (unsigned)_ntoh_ui(mi->mi_offset)); 02255 /* damaged header should not be reused */ 02256 if (mi->mi_h) { 02257 (void)headerFree(mi->mi_h); 02258 mi->mi_h = NULL; 02259 } 02260 /* TODO: skip more mi_set records */ 02261 goto next; 02262 } 02263 02264 /* Skip this header if iterator selector (if any) doesn't match. */ 02265 if (mireSkip(mi)) 02266 goto next; 02267 02268 /* Mark header with its instance number. */ 02269 { char origin[32]; 02270 uint32_t hdrNum = _ntoh_ui(mi->mi_offset); 02271 sprintf(origin, "rpmdb (h#%u)", (unsigned)hdrNum); 02272 (void) headerSetOrigin(mi->mi_h, origin); 02273 (void) headerSetInstance(mi->mi_h, hdrNum); 02274 } 02275 02276 mi->mi_prevoffset = mi->mi_offset; 02277 mi->mi_modified = 0; 02278 02279 /*@-compdef -retalias -retexpose -usereleased @*/ 02280 return mi->mi_h; 02281 /*@=compdef =retalias =retexpose =usereleased @*/ 02282 } 02283 02284 int rpmmiSort(rpmmi mi) 02285 { 02286 int rc = 0; 02287 02288 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) { 02289 /* 02290 * mergesort is much (~10x with lots of identical basenames) faster 02291 * than pure quicksort, but glibc uses msort_with_tmp() on stack. 02292 */ 02293 if (mi->mi_set->count > 1) { 02294 #if defined(__GLIBC__) 02295 qsort(mi->mi_set->recs, mi->mi_set->count, 02296 sizeof(*mi->mi_set->recs), hdrNumCmp); 02297 #else 02298 rpm_mergesort(mi->mi_set->recs, mi->mi_set->count, 02299 sizeof(*mi->mi_set->recs), hdrNumCmp); 02300 #endif 02301 } 02302 mi->mi_sorted = 1; 02303 #ifdef NOTNOW 02304 { struct _dbiIndexItem * rec; 02305 int i; 02306 for (i = 0, rec = mi->mi_set->recs; i < mi->mi_set->count; i++, rec++) { 02307 fprintf(stderr, "\t%p[%u] = %p: %u %u %u\n", mi->mi_set->recs, 02308 i, rec, rec->hdrNum, rec->tagNum, rec->fpNum); 02309 } 02310 } 02311 #endif 02312 } 02313 return rc; 02314 } 02315 02316 /* XXX TODO: a Bloom Filter on removed packages created once, not each time. */ 02317 int rpmmiPrune(rpmmi mi, uint32_t * hdrNums, int nHdrNums, int sorted) 02318 { 02319 int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0); 02320 02321 if (!rc) { 02322 int i; 02323 if (mi->mi_bf == NULL) { 02324 static size_t nRemoves = 2 * 8192; /* XXX population estimate */ 02325 static double e = 1.0e-4; 02326 size_t m = 0; 02327 size_t k = 0; 02328 rpmbfParams(nRemoves, e, &m, &k); 02329 mi->mi_bf = rpmbfNew(m, k, 0); 02330 } 02331 for (i = 0; i < nHdrNums; i++) { 02332 uint32_t mi_offset = _hton_ui(hdrNums[i]); 02333 int xx = rpmbfAdd(mi->mi_bf, &mi_offset, sizeof(mi_offset)); 02334 assert(xx == 0); 02335 } 02336 } 02337 02338 if (_rpmmi_debug) 02339 fprintf(stderr, "<-- %s(%p, %p[%u], %d) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, sorted, rc, (unsigned) (hdrNums ? hdrNums[0] : 0)); 02340 return rc; 02341 } 02342 02343 int rpmmiGrow(rpmmi mi, const uint32_t * hdrNums, int nHdrNums) 02344 { 02345 int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0); 02346 02347 if (!rc) { 02348 if (mi->mi_set == NULL) 02349 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set)); 02350 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0); 02351 } 02352 02353 if (_rpmmi_debug) 02354 fprintf(stderr, "<-- %s(%p, %p[%u]) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, rc, (unsigned) (hdrNums ? hdrNums[0] : 0)); 02355 return rc; 02356 } 02357 02358 /*@-dependenttrans -exposetrans -globstate @*/ 02359 rpmmi rpmmiInit(rpmdb db, rpmTag tag, const void * keyp, size_t keylen) 02360 { 02361 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02362 rpmmi mi = NULL; 02363 dbiIndexSet set = NULL; 02364 dbiIndex dbi = NULL; 02365 int usePatterns = 0; 02366 02367 if (db == NULL) 02368 goto exit; 02369 02370 (void) rpmdbCheckSignals(); 02371 02372 /* XXX Control for whether patterns are permitted. */ 02373 switch (tag) { 02374 default: break; 02375 case 2: /* XXX HACK to remove RPMDBI_LABEL from RPM. */ 02376 /* XXX rpmlog message warning RPMDBI is deprecated? */ 02377 tag = RPMTAG_NVRA; 02378 /*@fallthrough@*/ 02379 case RPMTAG_NVRA: 02380 #ifdef NOTYET /* XXX JS unit tests break. */ 02381 case RPMTAG_NAME: 02382 #endif 02383 #ifdef RPM_VENDOR_MANDRIVA_XXX /* XXX rpm -qf /non/existent breaks */ 02384 case RPMTAG_PROVIDENAME: 02385 #endif 02386 case RPMTAG_VERSION: 02387 case RPMTAG_RELEASE: 02388 case RPMTAG_ARCH: 02389 case RPMTAG_OS: 02390 case RPMTAG_GROUP: 02391 usePatterns = 1; 02392 break; 02393 #ifndef NOTYET /* XXX can't quite do this yet */ 02394 /* XXX HACK to remove the existing complexity of RPMTAG_BASENAMES */ 02395 case RPMTAG_BASENAMES: 02396 if (keyp == NULL) /* XXX rpmdbFindFpList & grow are speshul */ 02397 break; 02398 tag = RPMTAG_FILEPATHS; 02399 /*@fallthrough@*/ 02400 #endif 02401 case RPMTAG_FILEPATHS: 02402 case RPMTAG_DIRNAMES: 02403 usePatterns = 1; 02404 break; 02405 } 02406 02407 dbi = dbiOpen(db, tag, 0); 02408 #ifdef NOTYET /* XXX non-configured tag indices force NULL return */ 02409 assert(dbi != NULL); /* XXX sanity */ 02410 #else 02411 if (dbi == NULL) 02412 goto exit; 02413 #endif 02414 02415 mi = rpmmiGetPool(_rpmmiPool); 02416 (void)rpmioLinkPoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__); 02417 02418 if (_rpmmi_debug || (dbi && dbi->dbi_debug)) 02419 fprintf(stderr, "--> %s(%p, %s, %p[%u]=\"%s\") dbi %p mi %p\n", __FUNCTION__, db, tagName(tag), keyp, (unsigned)keylen, (keylen == 0 || ((const char *)keyp)[keylen] == '\0' ? (const char *)keyp : "???"), dbi, mi); 02420 02421 /* Chain cursors for teardown on abnormal exit. */ 02422 mi->mi_next = rpmmiRock; 02423 rpmmiRock = mi; 02424 02425 if (tag == RPMDBI_PACKAGES && keyp == NULL) { 02426 /* Special case #1: sequentially iterate Packages database. */ 02427 assert(keylen == 0); 02428 /* This should be the only case when (set == NULL). */ 02429 } 02430 else if (tag == RPMDBI_PACKAGES) { 02431 /* Special case #2: will fetch header instance. */ 02432 uint32_t hdrNum; 02433 assert(keylen == sizeof(hdrNum)); 02434 memcpy(&hdrNum, keyp, sizeof(hdrNum)); 02435 /* The set has only one element, which is hdrNum. */ 02436 set = xcalloc(1, sizeof(*set)); 02437 set->count = 1; 02438 set->recs = xcalloc(1, sizeof(set->recs[0])); 02439 set->recs[0].hdrNum = hdrNum; 02440 } 02441 else if (keyp == NULL) { 02442 /* XXX Special case #3: empty iterator with rpmmiGrow() */ 02443 assert(keylen == 0); 02444 } 02445 else if (usePatterns) { 02446 /* XXX Special case #4: gather primary keys with patterns. */ 02447 rpmRC rc; 02448 02449 rc = dbiFindMatches(dbi, keyp, &set); 02450 #if defined(RPM_VENDOR_MANDRIVA) 02451 /* 02452 * Hack to workaround disttag/distepoch pattern matching issue to buy some 02453 * time to come up with better pattern fix.. 02454 * One size should fit all now.. ;) 02455 * 02456 * This patch will try match NVR first, then for all matches returned, 02457 * it will match disttag, distepoch & arch individually. 02458 */ 02459 02460 /* We'll only try this if query fails */ 02461 if(!rc && ((const char*)keyp)[0] != '^' && tag == RPMTAG_NVRA && 02462 (set == NULL || set->count < 1)) { 02463 size_t i; 02464 char *tmp = (char*)keyp; 02465 02466 /* If pattern has less than three '-', it can't contain disttag, so 02467 * no point in trying */ 02468 for (i = 0; (tmp = strchr(tmp, '-')); i++, tmp++); 02469 if (i >= 3) { 02470 dbiIndex pdbi; 02471 DBC *pdbc; 02472 const char *origkeyp = keyp; 02473 size_t klen = strlen(keyp)+1; 02474 size_t size = 0; 02475 int xx; 02476 02477 keyp = alloca(klen); 02478 stpcpy((char*)keyp, origkeyp); 02479 tmp = strrchr(keyp, '-'); 02480 *tmp = '\0'; 02481 rc = dbiFindMatches(dbi, keyp, &set); 02482 02483 pdbi = dbiOpen(db, RPMDBI_PACKAGES, 0); 02484 xx = dbiCopen(pdbi, dbiTxnid(pdbi), &pdbc, 0); 02485 02486 for(i = 0; set && i < set->count; i++) { 02487 DBT k = DBT_INIT; 02488 DBT v = DBT_INIT; 02489 Header h; 02490 uint32_t offset = _hton_ui(set->recs[i].hdrNum); 02491 rpmTag checkTags[] = 02492 { RPMTAG_DISTTAG, RPMTAG_DISTEPOCH, RPMTAG_ARCH }; 02493 int j; 02494 02495 memset(&k, 0, sizeof(k)); 02496 memset(&v, 0, sizeof(v)); 02497 k.data = &offset; 02498 k.size = sizeof(offset); 02499 02500 xx = dbiGet(dbi, pdbc, &k, &v, DB_SET); 02501 h = headerLoad(v.data); 02502 tmp = (char*)((size_t)keyp + strlen(keyp) + 1); 02503 02504 for (j = 0; j < (int)(sizeof(checkTags)/sizeof(checkTags[0])) && 02505 *tmp != '\0'; j++) { 02506 he->tag = checkTags[j]; 02507 if(headerGet(h, he, 0)) { 02508 size_t len = strlen(he->p.str); 02509 02510 if (he->tag == RPMTAG_ARCH && *tmp == '.') 02511 tmp++; 02512 02513 if(!strncmp(he->p.str, tmp, len)) 02514 tmp += len; 02515 _free(he->p.ptr); 02516 } 02517 } 02518 if(j && *tmp == '\0') { 02519 set->recs[size].hdrNum = set->recs[i].hdrNum; 02520 set->recs[size].tagNum = set->recs[i].tagNum; 02521 size++; 02522 } 02523 02524 h = headerFree(h); 02525 } 02526 if(set && set->count != size) { 02527 set->count = size; 02528 set->recs = realloc(set->recs, size * sizeof(*set->recs)); 02529 } 02530 02531 xx = dbiCclose(pdbi, pdbc, 0); 02532 } 02533 } 02534 #endif 02535 02536 if ((rc && rc != RPMRC_NOTFOUND) || set == NULL || set->count < 1) { /* error or empty set */ 02537 set = dbiFreeIndexSet(set); 02538 rpmmiRock = mi->mi_next; 02539 mi->mi_next = NULL; 02540 mi = (rpmmi)rpmioFreePoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__); 02541 return NULL; 02542 } 02543 } 02544 else if (dbi && dbi->dbi_primary != NULL) { 02545 /* XXX Special case #5: secondary index associated w primary table. */ 02546 } 02547 else { 02548 /* Common case: retrieve join keys. */ 02549 assert(0); 02550 } 02551 02552 /*@-assignexpose@*/ 02553 mi->mi_db = rpmdbLink(db, __FUNCTION__); 02554 /*@=assignexpose@*/ 02555 mi->mi_rpmtag = tag; 02556 02557 mi->mi_dbc = NULL; 02558 mi->mi_set = set; 02559 mi->mi_setx = 0; 02560 mi->mi_count = (set ? set->count : 0); 02561 02562 mi->mi_primary = (dbi && dbi->dbi_primary 02563 ? xstrdup(dbi->dbi_primary) : NULL); 02564 02565 /* Coerce/swab integer keys. Save key ind keylen in the iterator. */ 02566 switch (tagType(tag) & 0xffff) { 02567 case RPM_UINT8_TYPE: 02568 assert(keylen == sizeof(he->p.ui8p[0])); 02569 mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */ 02570 mi->mi_keyp = he->p.ui32p = xmalloc(mi->mi_keylen); 02571 he->p.ui32p[0] = 0; 02572 memcpy(&he->p.ui8p[3], keyp, keylen); 02573 break; 02574 case RPM_UINT16_TYPE: 02575 assert(keylen == sizeof(he->p.ui16p[0])); 02576 mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */ 02577 mi->mi_keyp = he->p.ui32p = xmalloc(mi->mi_keylen); 02578 he->p.ui32p[0] = 0; 02579 memcpy(&he->p.ui16p[1], keyp, keylen); 02580 he->p.ui16p[1] = _hton_us(he->p.ui16p[1]); 02581 break; 02582 #if !defined(__LCLINT__) /* LCL: buggy */ 02583 case RPM_UINT32_TYPE: 02584 assert(keylen == sizeof(he->p.ui32p[0])); 02585 mi->mi_keylen = keylen; 02586 /*@-mayaliasunique@*/ 02587 mi->mi_keyp = memcpy((he->p.ui32p = xmalloc(keylen)), keyp, keylen); 02588 /*@=mayaliasunique@*/ 02589 he->p.ui32p[0] = _hton_ui(he->p.ui32p[0]); 02590 break; 02591 case RPM_UINT64_TYPE: 02592 assert(keylen == sizeof(he->p.ui64p[0])); 02593 mi->mi_keylen = keylen; 02594 /*@-mayaliasunique@*/ 02595 mi->mi_keyp = memcpy((he->p.ui64p = xmalloc(keylen)), keyp, keylen); 02596 /*@=mayaliasunique@*/ 02597 { uint32_t _tmp = he->p.ui32p[0]; 02598 he->p.ui32p[0] = _hton_ui(he->p.ui32p[1]); 02599 he->p.ui32p[1] = _hton_ui(_tmp); 02600 } 02601 break; 02602 #endif /* !defined(__LCLINT__) */ 02603 case RPM_BIN_TYPE: 02604 case RPM_I18NSTRING_TYPE: /* XXX never occurs */ 02605 case RPM_STRING_TYPE: 02606 case RPM_STRING_ARRAY_TYPE: 02607 default: 02608 mi->mi_keylen = keylen; 02609 if (keyp) 02610 mi->mi_keyp = keylen > 0 02611 ? memcpy(xmalloc(keylen), keyp, keylen) : xstrdup(keyp) ; 02612 else 02613 mi->mi_keyp = NULL; 02614 break; 02615 } 02616 he->p.ptr = NULL; 02617 02618 mi->mi_h = NULL; 02619 mi->mi_sorted = 0; 02620 mi->mi_cflags = 0; 02621 mi->mi_modified = 0; 02622 mi->mi_prevoffset = 0; 02623 mi->mi_offset = 0; 02624 mi->mi_nre = 0; 02625 mi->mi_re = NULL; 02626 02627 exit: 02628 return mi; 02629 } 02630 /*@=dependenttrans =exposetrans =globstate @*/ 02631 02632 /* XXX psm.c */ 02633 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, uint32_t hdrNum, 02634 /*@unused@*/ rpmts ts) 02635 { 02636 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02637 Header h = NULL; 02638 sigset_t signalMask; 02639 dbiIndex dbi; 02640 size_t dbix; 02641 int rc = RPMRC_FAIL; /* XXX RPMRC */ 02642 int xx; 02643 02644 if (db == NULL) 02645 return RPMRC_OK; /* XXX RPMRC */ 02646 02647 /* Retrieve header for use by associated secondary index callbacks. */ 02648 { rpmmi mi; 02649 mi = rpmmiInit(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum)); 02650 h = rpmmiNext(mi); 02651 if (h) 02652 h = headerLink(h); 02653 mi = rpmmiFree(mi); 02654 } 02655 02656 if (h == NULL) { 02657 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"), 02658 "rpmdbRemove", (unsigned)hdrNum); 02659 return RPMRC_FAIL; /* XXX RPMRC */ 02660 } 02661 02662 he->tag = RPMTAG_NVRA; 02663 xx = headerGet(h, he, 0); 02664 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", (unsigned)hdrNum, he->p.str); 02665 he->p.ptr = _free(he->p.ptr); 02666 02667 (void) blockSignals(db, &signalMask); 02668 02669 dbix = db->db_ndbi - 1; 02670 if (db->db_tags != NULL) 02671 do { 02672 tagStore_t dbiTag = db->db_tags + dbix; 02673 DBC * dbcursor; 02674 DBT k; 02675 DBT v; 02676 uint32_t ui; 02677 02678 dbi = NULL; 02679 dbcursor = NULL; 02680 (void) memset(&k, 0, sizeof(k)); 02681 (void) memset(&v, 0, sizeof(v)); 02682 (void) memset(he, 0, sizeof(*he)); 02683 he->tag = dbiTag->tag; 02684 02685 switch (he->tag) { 02686 default: 02687 /* Don't bother if tag is not present. */ 02688 if (!headerGet(h, he, 0)) 02689 /*@switchbreak@*/ break; 02690 02691 dbi = dbiOpen(db, he->tag, 0); 02692 if (dbi == NULL) goto exit; 02693 02694 he->p.ptr = _free(he->p.ptr); 02695 /*@switchbreak@*/ break; 02696 case RPMDBI_AVAILABLE: /* Filter out temporary databases */ 02697 case RPMDBI_ADDED: 02698 case RPMDBI_REMOVED: 02699 case RPMDBI_DEPENDS: 02700 case RPMDBI_SEQNO: 02701 /*@switchbreak@*/ break; 02702 case RPMDBI_PACKAGES: 02703 if (db->db_export != NULL) 02704 xx = db->db_export(db, h, 0); 02705 02706 ui = _hton_ui(hdrNum); 02707 k.data = &ui; 02708 k.size = (UINT32_T) sizeof(ui); 02709 02710 /* New h ref for use by associated secondary index callbacks. */ 02711 db->db_h = headerLink(h); 02712 02713 dbi = dbiOpen(db, he->tag, 0); 02714 if (dbi == NULL) goto exit; 02715 02716 rc = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR); 02717 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET); 02718 if (!rc) 02719 rc = dbiDel(dbi, dbcursor, &k, &v, 0); 02720 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 02721 02722 /* Unreference db_h used by associated secondary index callbacks. */ 02723 (void) headerFree(db->db_h); 02724 db->db_h = NULL; 02725 02726 if (!dbi->dbi_no_dbsync) 02727 xx = dbiSync(dbi, 0); 02728 02729 /*@switchbreak@*/ break; 02730 } 02731 } while (dbix-- > 0); 02732 02733 /* Unreference header used by associated secondary index callbacks. */ 02734 (void) headerFree(h); 02735 h = NULL; 02736 rc = RPMRC_OK; /* XXX RPMRC */ 02737 02738 exit: 02739 (void) unblockSignals(db, &signalMask); 02740 return rc; 02741 } 02742 02743 /* XXX install.c */ 02744 int rpmdbAdd(rpmdb db, int iid, Header h, /*@unused@*/ rpmts ts) 02745 { 02746 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02747 sigset_t signalMask; 02748 dbiIndex dbi; 02749 size_t dbix; 02750 uint32_t hdrNum = headerGetInstance(h); 02751 int rc = RPMRC_FAIL; /* XXX RPMRC */ 02752 int xx; 02753 02754 if (db == NULL) 02755 return RPMRC_OK; /* XXX RPMRC */ 02756 02757 if (_rpmdb_debug) 02758 fprintf(stderr, "--> %s(%p, %u, %p, %p) h# %u\n", __FUNCTION__, db, (unsigned)iid, h, ts, (unsigned)hdrNum); 02759 02760 assert(headerIsEntry(h, RPMTAG_REMOVETID) == 0); /* XXX sanity */ 02761 02762 /* Add the install transaction id. */ 02763 if (iid != 0 && iid != -1) { 02764 rpmuint32_t tid[2]; 02765 tid[0] = iid; 02766 tid[1] = 0; 02767 he->tag = RPMTAG_INSTALLTID; 02768 he->t = RPM_UINT32_TYPE; 02769 he->p.ui32p = tid; 02770 he->c = 2; 02771 if (!headerIsEntry(h, he->tag)) 02772 /*@-compmempass@*/ 02773 xx = headerPut(h, he, 0); 02774 /*@=compmempass@*/ 02775 } 02776 02777 /* XXX pubkeys used to set RPMTAG_PACKAGECOLOR here. */ 02778 assert(headerIsEntry(h, RPMTAG_PACKAGECOLOR) != 0); /* XXX sanity */ 02779 02780 (void) blockSignals(db, &signalMask); 02781 02782 /* Assign a primary Packages key for new Header's. */ 02783 if (hdrNum == 0) { 02784 int64_t seqno = 0; 02785 02786 dbi = dbiOpen(db, RPMDBI_SEQNO, 0); 02787 if (dbi == NULL) goto exit; 02788 02789 if ((xx = dbiSeqno(dbi, &seqno, 0)) == 0) { 02790 hdrNum = seqno; 02791 (void) headerSetInstance(h, hdrNum); 02792 } else 02793 goto exit; 02794 } 02795 02796 /* XXX ensure that the header instance is set persistently. */ 02797 if (hdrNum == 0) { 02798 assert(hdrNum > 0); 02799 assert(hdrNum == headerGetInstance(h)); 02800 } 02801 02802 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0); 02803 if (dbi == NULL) goto exit; 02804 02805 dbix = db->db_ndbi - 1; 02806 if (db->db_tags != NULL) 02807 do { 02808 tagStore_t dbiTag = db->db_tags + dbix; 02809 DBC * dbcursor; 02810 DBT k; 02811 DBT v; 02812 uint32_t ui; 02813 02814 dbi = NULL; 02815 dbcursor = NULL; 02816 (void) memset(&k, 0, sizeof(k)); 02817 (void) memset(&v, 0, sizeof(v)); 02818 (void) memset(he, 0, sizeof(*he)); 02819 he->tag = dbiTag->tag; 02820 02821 switch (he->tag) { 02822 default: 02823 /* Don't bother if tag is not present. */ 02824 if (!headerGet(h, he, 0)) 02825 /*@switchbreak@*/ break; 02826 02827 dbi = dbiOpen(db, he->tag, 0); 02828 if (dbi == NULL) goto exit; 02829 02830 he->p.ptr = _free(he->p.ptr); 02831 /*@switchbreak@*/ break; 02832 case RPMDBI_AVAILABLE: /* Filter out temporary databases */ 02833 case RPMDBI_ADDED: 02834 case RPMDBI_REMOVED: 02835 case RPMDBI_DEPENDS: 02836 case RPMDBI_SEQNO: 02837 /*@switchbreak@*/ break; 02838 case RPMDBI_PACKAGES: 02839 if (db->db_export != NULL) 02840 xx = db->db_export(db, h, 1); 02841 02842 ui = _hton_ui(hdrNum); 02843 k.data = (void *) &ui; 02844 k.size = (UINT32_T) sizeof(ui); 02845 02846 { size_t len = 0; 02847 v.data = headerUnload(h, &len); 02848 assert(v.data != NULL); 02849 v.size = (UINT32_T) len; 02850 } 02851 02852 /* New h ref for use by associated secondary index callbacks. */ 02853 db->db_h = headerLink(h); 02854 02855 dbi = dbiOpen(db, he->tag, 0); 02856 if (dbi == NULL) goto exit; 02857 02858 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR); 02859 xx = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST); 02860 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 02861 02862 /* Unreference db_h used by associated secondary index callbacks. */ 02863 (void) headerFree(db->db_h); 02864 db->db_h = NULL; 02865 02866 if (!dbi->dbi_no_dbsync) 02867 xx = dbiSync(dbi, 0); 02868 02869 v.data = _free(v.data); /* headerUnload */ 02870 v.size = 0; 02871 /*@switchbreak@*/ break; 02872 } 02873 02874 } while (dbix-- > 0); 02875 rc = RPMRC_OK; /* XXX RPMRC */ 02876 02877 exit: 02878 (void) unblockSignals(db, &signalMask); 02879 return rc; 02880 }