|
rpm
5.4.4
|
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_DEPCACHE: 00689 case RPMDBI_BTREE: 00690 case RPMDBI_HASH: 00691 case RPMDBI_QUEUE: 00692 case RPMDBI_RECNO: 00693 case RPMDBI_HEAP: 00694 continue; 00695 /*@notreached@*/ /*@switchbreak@*/ break; 00696 default: 00697 /*@switchbreak@*/ break; 00698 } 00699 (void) dbiOpen(db, db->db_tags[dbix].tag, db->db_flags); 00700 } 00701 } 00702 return rc; 00703 } 00704 00705 int rpmdbBlockDBI(rpmdb db, int tag) 00706 { 00707 rpmTag tagn = (rpmTag)(tag >= 0 ? tag : -tag); 00708 size_t dbix; 00709 00710 if (db == NULL || db->_dbi == NULL) 00711 return 0; 00712 00713 if (db->db_tags != NULL) 00714 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00715 if (db->db_tags[dbix].tag != tagn) 00716 continue; 00717 db->db_tags[dbix].tag = tag; 00718 return 0; 00719 } 00720 return 0; 00721 } 00722 00723 int rpmdbCloseDBI(rpmdb db, int tag) 00724 { 00725 size_t dbix; 00726 int rc = 0; 00727 00728 if (db == NULL || db->_dbi == NULL) 00729 return 0; 00730 00731 if (db->db_tags != NULL) 00732 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00733 if (db->db_tags[dbix].tag != (rpmTag)tag) 00734 continue; 00735 if (db->_dbi[dbix] != NULL) { 00736 int xx; 00737 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00738 xx = dbiClose(db->_dbi[dbix], 0); 00739 if (xx && rc == 0) rc = xx; 00740 db->_dbi[dbix] = NULL; 00741 /*@=unqualifiedtrans@*/ 00742 } 00743 break; 00744 } 00745 return rc; 00746 } 00747 00748 /* XXX query.c, rpminstall.c, verify.c */ 00749 /*@-incondefs@*/ 00750 int rpmdbClose(rpmdb db) 00751 /*@globals rpmdbRock @*/ 00752 /*@modifies rpmdbRock @*/ 00753 { 00754 static const char msg[] = "rpmdbClose"; 00755 rpmdb * prev, next; 00756 size_t dbix; 00757 int rc = 0; 00758 00759 if (db == NULL) 00760 return rc; 00761 00762 yarnPossess(db->_item.use); 00763 /*@-modfilesys@*/ 00764 if (_rpmdb_debug) 00765 fprintf(stderr, "--> db %p -- %ld %s at %s:%u\n", db, yarnPeekLock(db->_item.use), msg, __FILE__, __LINE__); 00766 00767 /*@-usereleased@*/ 00768 if (yarnPeekLock(db->_item.use) <= 1L) { 00769 00770 if (db->_dbi) 00771 for (dbix = db->db_ndbi; dbix;) { 00772 int xx; 00773 dbix--; 00774 if (db->_dbi[dbix] == NULL) 00775 continue; 00776 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00777 xx = dbiClose(db->_dbi[dbix], 0); 00778 if (xx && rc == 0) rc = xx; 00779 db->_dbi[dbix] = NULL; 00780 /*@=unqualifiedtrans@*/ 00781 } 00782 db->db_errpfx = _free(db->db_errpfx); 00783 db->db_root = _free(db->db_root); 00784 db->db_home = _free(db->db_home); 00785 db->db_tags = tagStoreFree(db->db_tags, db->db_ndbi); 00786 db->_dbi = _free(db->_dbi); 00787 db->db_ndbi = 0; 00788 00789 /*@-newreftrans@*/ 00790 prev = &rpmdbRock; 00791 while ((next = *prev) != NULL && next != db) 00792 prev = &next->db_next; 00793 if (next) { 00794 /*@i@*/ *prev = next->db_next; 00795 next->db_next = NULL; 00796 } 00797 /*@=newreftrans@*/ 00798 00799 if (rpmdbRock == NULL && rpmmiRock == NULL) { 00800 /* Last close uninstalls special signal handling. */ 00801 (void) rpmsqEnable(-SIGHUP, NULL); 00802 (void) rpmsqEnable(-SIGINT, NULL); 00803 (void) rpmsqEnable(-SIGTERM, NULL); 00804 (void) rpmsqEnable(-SIGQUIT, NULL); 00805 (void) rpmsqEnable(-SIGPIPE, NULL); 00806 /* Pending signals strike here. */ 00807 (void) rpmdbCheckSignals(); 00808 } 00809 00810 /*@=usereleased@*/ 00811 db = (rpmdb)rpmioPutPool((rpmioItem)db); 00812 } else 00813 yarnTwist(db->_item.use, BY, -1); 00814 00815 return rc; 00816 } 00817 /*@=incondefs@*/ 00818 00824 static const char * rpmdbURIPath(const char *uri) 00825 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00826 /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/ 00827 { 00828 const char * s = rpmGetPath(uri, NULL); 00829 ARGV_t av = NULL; 00830 int xx = argvSplit(&av, s, ":"); 00831 const char * fn = NULL; 00832 /* XXX av contains a colon separated path split, use the 1st path. */ 00833 urltype ut = urlPath(av[0], &fn); 00834 00835 xx = xx; 00836 00837 switch (ut) { 00838 case URL_IS_PATH: 00839 case URL_IS_UNKNOWN: 00840 fn = xstrdup(av[0]); 00841 break; 00842 case URL_IS_DASH: 00843 case URL_IS_HKP: 00844 case URL_IS_FTP: 00845 case URL_IS_HTTP: 00846 case URL_IS_HTTPS: 00847 case URL_IS_MONGO: /* XXX FIXME */ 00848 default: 00849 /* HACK: strip the URI prefix for these schemes. */ 00850 fn = rpmGetPath(fn, NULL); 00851 break; 00852 } 00853 00854 /* Convert relative to absolute paths. */ 00855 if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */ 00856 if (fn && *fn && *fn != '/') { 00857 char dn[PATH_MAX]; 00858 char *t; 00859 dn[0] = '\0'; 00860 if ((t = Realpath(".", dn)) != NULL) { 00861 t += strlen(dn); 00862 if (t > dn && t[-1] != '/') 00863 *t++ = '/'; 00864 t = stpncpy(t, fn, (sizeof(dn) - (t - dn))); 00865 *t = '\0'; 00866 fn = _free(fn); 00867 fn = rpmGetPath(dn, NULL); 00868 } 00869 } 00870 00871 av = argvFree(av); 00872 s = _free(s); 00873 assert(fn != NULL); 00874 return fn; 00875 } 00876 00877 #define _DB_ROOT "/" 00878 #define _DB_HOME "%{?_dbpath}" 00879 #define _DB_FLAGS 0 00880 #define _DB_MODE 0 00881 #define _DB_PERMS 0644 00882 00883 #define _DB_MAJOR 3 00884 #define _DB_ERRPFX "rpmdb" 00885 00886 /*@-exportheader -globs -mods @*/ 00887 /*@only@*/ /*@null@*/ 00888 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root, 00889 /*@kept@*/ /*@null@*/ const char * home, 00890 int mode, mode_t perms, int flags) 00891 /*@*/ 00892 { 00893 rpmdb db = rpmdbGetPool(_rpmdbPool); 00894 const char * epfx = _DB_ERRPFX; 00895 00896 /*@-modfilesys@*/ /*@-nullpass@*/ 00897 if (_rpmdb_debug) 00898 fprintf(stderr, "==> rpmdbNew(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", root, home, mode, perms, flags, db); 00899 /*@=modfilesys@*/ /*@=nullpass@*/ 00900 00901 if (!(perms & 0600)) perms = 0644; /* XXX sanity */ 00902 00903 db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) ); 00904 db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) ); 00905 00906 if (!(db->db_home && db->db_home[0] && db->db_home[0] != '%')) { 00907 rpmlog(RPMLOG_ERR, _("no dbpath has been set\n")); 00908 db->db_root = _free(db->db_root); 00909 db->db_home = _free(db->db_home); 00910 db = (rpmdb) rpmioPutPool((rpmioItem)db); 00911 /*@-globstate@*/ return NULL; /*@=globstate@*/ 00912 } 00913 00914 db->db_flags = (flags >= 0) ? flags : _DB_FLAGS; 00915 db->db_mode = (mode >= 0) ? mode : _DB_MODE; 00916 db->db_perms = (perms > 0) ? perms : _DB_PERMS; 00917 db->db_api = _DB_MAJOR; 00918 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL); 00919 00920 db->db_remove_env = 0; 00921 db->db_chrootDone = 0; 00922 db->db_maxkey = 0; 00923 db->db_errcall = NULL; 00924 db->db_errfile = NULL; 00925 db->db_malloc = NULL; 00926 db->db_realloc = NULL; 00927 db->db_free = NULL; 00928 db->db_export = rpmdbExportInfo; 00929 db->db_h = NULL; 00930 00931 db->db_next = NULL; 00932 db->db_opens = 0; 00933 00934 db->db_dbenv = NULL; 00935 db->db_txn = NULL; 00936 db->db_logc = NULL; 00937 db->db_mpf = NULL; 00938 00939 dbiTagsInit(&db->db_tags, &db->db_ndbi); 00940 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi)); 00941 00942 memset(&db->db_getops, 0, sizeof(db->db_getops)); 00943 memset(&db->db_putops, 0, sizeof(db->db_putops)); 00944 memset(&db->db_delops, 0, sizeof(db->db_delops)); 00945 00946 /*@-globstate@*/ 00947 return rpmdbLink(db, __FUNCTION__); 00948 /*@=globstate@*/ 00949 } 00950 /*@=exportheader =globs =mods @*/ 00951 00952 static int rpmdbOpenDatabase(/*@null@*/ const char * prefix, 00953 /*@null@*/ const char * dbpath, 00954 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp, 00955 int mode, mode_t perms, int flags) 00956 /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno, 00957 fileSystem, internalState @*/ 00958 /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext, 00959 fileSystem, internalState @*/ 00960 { 00961 rpmdb db; 00962 int rc; 00963 int xx; 00964 00965 /* Insure that _dbapi has one of -1, 1, 2, or 3 */ 00966 if (_dbapi < -1 || _dbapi > 4) 00967 _dbapi = -1; 00968 if (_dbapi == 0) 00969 _dbapi = 1; 00970 00971 if (dbp) 00972 *dbp = NULL; 00973 if (mode & O_WRONLY) 00974 return 1; 00975 00976 db = rpmdbNew(prefix, dbpath, mode, perms, flags); 00977 if (db == NULL) 00978 return 1; 00979 00980 if (rpmdbRock == NULL && rpmmiRock == NULL) { 00981 /* First open installs special signal handling. */ 00982 (void) rpmsqEnable(SIGHUP, NULL); 00983 (void) rpmsqEnable(SIGINT, NULL); 00984 (void) rpmsqEnable(SIGTERM, NULL); 00985 (void) rpmsqEnable(SIGQUIT, NULL); 00986 (void) rpmsqEnable(SIGPIPE, NULL); 00987 } 00988 00989 /*@-assignexpose -newreftrans@*/ 00990 /*@i@*/ db->db_next = rpmdbRock; 00991 rpmdbRock = db; 00992 /*@=assignexpose =newreftrans@*/ 00993 00994 db->db_api = _dbapi; 00995 00996 { size_t dbix; 00997 00998 rc = 0; 00999 if (db->db_tags != NULL) 01000 for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) { 01001 tagStore_t dbiTag = db->db_tags + dbix; 01002 rpmTag tag = dbiTag->tag; 01003 dbiIndex dbi; 01004 01005 /* Filter out temporary databases */ 01006 switch (tag) { 01007 case RPMDBI_AVAILABLE: 01008 case RPMDBI_ADDED: 01009 case RPMDBI_REMOVED: 01010 case RPMDBI_DEPCACHE: 01011 continue; 01012 /*@notreached@*/ /*@switchbreak@*/ break; 01013 default: 01014 /*@switchbreak@*/ break; 01015 } 01016 01017 dbi = dbiOpen(db, tag, 0); 01018 if (dbi == NULL) { 01019 rc = -2; 01020 break; 01021 } 01022 01023 switch (tag) { 01024 case RPMDBI_PACKAGES: 01025 if (dbi == NULL) rc |= 1; 01026 #if 0 01027 /* XXX open only Packages, indices created on the fly. */ 01028 if (db->db_api == 3) 01029 #endif 01030 goto exit; 01031 /*@notreached@*/ /*@switchbreak@*/ break; 01032 case RPMTAG_NAME: 01033 if (dbi == NULL) rc |= 1; 01034 /*@switchbreak@*/ break; 01035 default: 01036 /*@switchbreak@*/ break; 01037 } 01038 } 01039 } 01040 01041 exit: 01042 if (rc || dbp == NULL) 01043 xx = rpmdbClose(db); 01044 else { 01045 /*@-assignexpose -newreftrans@*/ 01046 /*@i@*/ *dbp = db; 01047 /*@=assignexpose =newreftrans@*/ 01048 } 01049 01050 return rc; 01051 } 01052 01053 /* XXX python/rpmmodule.c */ 01054 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, mode_t perms) 01055 { 01056 int _dbapi = rpmExpandNumeric("%{?_dbapi}"); 01057 return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0); 01058 } 01059 01060 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen) 01061 { 01062 unsigned int count = 0; 01063 DBC * dbcursor = NULL; 01064 DBT k = DBT_INIT; 01065 DBT v = DBT_INIT; 01066 dbiIndex dbi; 01067 int rc; 01068 int xx; 01069 01070 if (db == NULL || keyp == NULL) 01071 return 0; 01072 01073 dbi = dbiOpen(db, tag, 0); 01074 if (dbi == NULL) 01075 return 0; 01076 01077 if (keylen == 0) 01078 keylen = strlen(keyp); 01079 01080 /*@-temptrans@*/ 01081 k.data = (void *) keyp; 01082 /*@=temptrans@*/ 01083 k.size = (UINT32_T) keylen; 01084 01085 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01086 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET); 01087 switch (rc) { 01088 case 0: 01089 rc = dbiCount(dbi, dbcursor, &count, 0); 01090 if (rc != 0) 01091 rc = -1; 01092 else 01093 rc = count; 01094 break; 01095 case DB_NOTFOUND: 01096 rc = 0; 01097 break; 01098 default: 01099 rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"), 01100 rc, tagName(dbi->dbi_rpmtag)); 01101 rc = -1; 01102 break; 01103 } 01104 xx = dbiCclose(dbi, dbcursor, 0); 01105 dbcursor = NULL; 01106 return rc; 01107 } 01108 01109 /* XXX python/upgrade.c, install.c, uninstall.c */ 01110 int rpmdbCountPackages(rpmdb db, const char * N) 01111 { 01112 return rpmdbCount(db, RPMTAG_NAME, N, strlen(N)); 01113 } 01114 01115 /* Return pointer to first RE character (or NUL terminator) */ 01116 static const char * stemEnd(const char * s) 01117 /*@*/ 01118 { 01119 int c; 01120 01121 while ((c = (int)*s)) { 01122 switch (c) { 01123 case '.': 01124 case '^': 01125 case '$': 01126 case '?': 01127 case '*': 01128 case '+': 01129 case '|': 01130 case '[': 01131 case '(': 01132 case '{': 01133 case '\0': 01134 goto exit; 01135 /*@notreached@*/ /*@switchbreak@*/ break; 01136 case '\\': 01137 s++; 01138 if (*s == '\0') goto exit; 01139 /*@fallthrough@*/ 01140 default: 01141 /*@switchbreak@*/ break; 01142 } 01143 s++; 01144 } 01145 exit: 01146 return s; 01147 } 01148 01149 /*@only@*/ 01150 static const char * _str2PCREpat(/*@null@*/ const char *_pre, const char *s, 01151 /*@null@*/ const char *_post) 01152 /*@*/ 01153 { 01154 static const char _REchars[] = "^.*(|)[]+?{}$"; 01155 size_t nt = 0; 01156 const char * se; 01157 char * t; 01158 char * te; 01159 01160 /* Find the PCRE pattern length, including escapes. */ 01161 for (se = s; *se != '\0'; se++, nt++) 01162 if (strchr(_REchars, *se)) nt++; 01163 nt += strlen(_pre) + strlen(_post); 01164 01165 /* Build the PCRE pattern, escaping characters as needed. */ 01166 te = t = xmalloc(nt + 1); 01167 te = stpcpy(te, _pre); 01168 for (se = s; *se != '\0'; *te++ = *se++) 01169 if (strchr(_REchars, *se)) *te++ = '\\'; 01170 te = stpcpy(te, _post); 01171 *te = '\0'; 01172 01173 /*@-dependenttrans@*/ 01174 return t; 01175 /*@=dependenttrans@*/ 01176 } 01177 01188 static int dbiMireKeys(rpmdb db, rpmTag tag, rpmMireMode mode, 01189 /*@null@*/ const char * pat, 01190 /*@null@*/ dbiIndexSet * matches, 01191 /*@null@*/ const char *** argvp) 01192 /*@globals internalState @*/ 01193 /*@modifies *matches, *argvp, internalState @*/ 01194 { 01195 DBC * dbcursor = NULL; 01196 DBT k = DBT_INIT; 01197 DBT p = DBT_INIT; 01198 DBT v = DBT_INIT; 01199 dbiIndex dbi; 01200 miRE mire = NULL; 01201 uint32_t _flags = DB_NEXT; 01202 ARGV_t av = NULL; 01203 dbiIndexSet set = NULL; 01204 const char * b = NULL; 01205 size_t nb = 0; 01206 int ret = 1; /* assume error */ 01207 int rc; 01208 int xx; 01209 01210 dbi = dbiOpen(db, tag, 0); 01211 if (dbi == NULL) 01212 goto exit; 01213 01214 if (_rpmmi_debug || dbi->dbi_debug) 01215 fprintf(stderr, "--> %s(%p, %s(%u), %d, \"%s\", %p, %p)\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, matches, argvp); 01216 01217 if (pat) { 01218 01219 mire = mireNew(mode, 0); 01220 xx = mireRegcomp(mire, pat); 01221 01222 /* Initialize the secondary retrieval key. */ 01223 switch (mode) { 01224 default: 01225 assert(0); /* XXX sanity */ 01226 /*@notreached@*/ break; 01227 case RPMMIRE_GLOB: 01228 break; 01229 case RPMMIRE_REGEX: 01230 case RPMMIRE_PCRE: 01231 if (*pat == '^') pat++; 01232 01233 /* If partial match on stem won't help, just iterate. */ 01234 nb = stemEnd(pat) - pat; 01235 if (nb == 0) { 01236 k.doff = 0; 01237 goto doit; 01238 } 01239 01240 /* Remove the escapes in the stem. */ 01241 { char *be; 01242 b = be = xmalloc(nb + 1); 01243 while (nb--) { 01244 if ((*be = *pat++) != '\\') 01245 be++; 01246 } 01247 *be = '\0'; 01248 } 01249 nb = strlen(b); 01250 01251 /* Set stem length for partial match retrieve. */ 01252 k.flags = DB_DBT_PARTIAL; 01253 k.dlen = nb; 01254 k.size = nb; 01255 k.data = (void *) b; 01256 _flags = DB_SET_RANGE; 01257 break; 01258 case RPMMIRE_STRCMP: 01259 k.size = (UINT32_T) strlen(pat); 01260 k.data = (void *) pat; 01261 _flags = DB_SET; 01262 break; 01263 } 01264 } 01265 01266 doit: 01267 v.flags |= DB_DBT_PARTIAL; 01268 01269 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01270 01271 /* Iterate over matches, collecting primary/secondary keys. */ 01272 while ((rc = dbiPget(dbi, dbcursor, &k, &p, &v, _flags)) == 0) { 01273 uint32_t hdrNum; 01274 const char * s; 01275 size_t ns; 01276 01277 if (_flags == DB_SET) _flags = DB_NEXT_DUP; 01278 if (b != NULL && nb > 0) { 01279 01280 /* Exit if the stem doesn't match. */ 01281 if (k.size < nb || memcmp(b, k.data, nb)) 01282 break; 01283 01284 /* Retrieve the full record after DB_SET_RANGE. */ 01285 if (_flags == DB_SET_RANGE) { 01286 memset (&k, 0, sizeof(k)); 01287 xx = dbiPget(dbi, dbcursor, &k, &p, &v, DB_CURRENT); 01288 _flags = DB_NEXT; 01289 } 01290 } 01291 01292 /* Get the secondary key. */ 01293 s = (const char * ) k.data; 01294 ns = k.size; 01295 01296 /* Skip if not matched. */ 01297 if (mire && mireRegexec(mire, s, ns) < 0) 01298 continue; 01299 01300 /* Get a native endian copy of the primary package key. */ 01301 memcpy(&hdrNum, p.data, sizeof(hdrNum)); 01302 hdrNum = _ntoh_ui(hdrNum); 01303 01304 /* Collect primary keys. */ 01305 if (matches) { 01306 if (set == NULL) 01307 set = xcalloc(1, sizeof(*set)); 01308 /* XXX TODO: sort/uniqify set? */ 01309 (void) dbiAppendSet(set, &hdrNum, 1, sizeof(hdrNum), 0); 01310 } 01311 01312 /* Collect secondary keys. */ 01313 if (argvp) { 01314 char * a = memcpy(xmalloc(ns+1), s, ns); 01315 a[ns] = '\0'; 01316 xx = argvAdd(&av, a); 01317 a = _free(a); 01318 } 01319 } 01320 01321 xx = dbiCclose(dbi, dbcursor, 0); 01322 dbcursor = NULL; 01323 01324 switch (rc) { 01325 case 0: 01326 case DB_NOTFOUND: 01327 ret = 0; 01328 break; 01329 default: 01330 rpmlog(RPMLOG_ERR, _("error(%d) getting keys from %s index\n"), 01331 rc, tagName(dbi->dbi_rpmtag)); 01332 break; 01333 } 01334 01335 exit: 01336 if (ret == 0) { 01337 if (matches) { 01338 /* XXX TODO: sort/uniqify set? */ 01339 *matches = set; 01340 set = NULL; 01341 } 01342 if (argvp) 01343 xx = argvAppend(argvp, av); 01344 } 01345 set = dbiFreeIndexSet(set); 01346 av = argvFree(av); 01347 b = _free(b); 01348 mire = mireFree(mire); 01349 if (_rpmmi_debug || dbi->dbi_debug) 01350 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)); 01351 return ret; 01352 } 01353 01354 int rpmdbMireApply(rpmdb db, rpmTag tag, rpmMireMode mode, const char * pat, 01355 const char *** argvp) 01356 { 01357 int rc = dbiMireKeys(db, tag, mode, pat, NULL, argvp); 01358 if (_rpmmi_debug) 01359 fprintf(stderr, "<-- %s(%p, %s(%u), %d, \"%s\", %p) rc %d\n", __FUNCTION__, db, tagName(tag), (unsigned)tag, mode, pat, argvp, rc); 01360 return rc; 01361 } 01362 01363 int rpmmiGrowBasename(rpmmi mi, const char * bn) 01364 { 01365 rpmTag _tag = RPMTAG_BASENAMES; 01366 rpmMireMode _mode = RPMMIRE_STRCMP; 01367 dbiIndexSet set = NULL; 01368 unsigned int i; 01369 int rc = 1; /* assume error */ 01370 01371 if (mi == NULL || mi->mi_db == NULL || bn == NULL || *bn == '\0') 01372 goto exit; 01373 01374 #ifdef NOTYET 01375 assert(mi->mi_rpmtag == _tag); 01376 #endif 01377 /* Retrieve set of headers that contain the base name. */ 01378 rc = dbiMireKeys(mi->mi_db, _tag, _mode, bn, &set, NULL); 01379 if (rc == 0 && set != NULL) { 01380 rpmuint32_t tagNum = hashFunctionString(0, bn, 0); 01381 /* Set tagNum to the hash of the basename. */ 01382 for (i = 0; i < set->count; i++) 01383 set->recs[i].tagNum = tagNum; 01384 if (mi->mi_set == NULL) 01385 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set)); 01386 (void) dbiAppendSet(mi->mi_set, set->recs, set->count, sizeof(*set->recs), 0); 01387 } 01388 rc = 0; 01389 01390 exit: 01391 if (_rpmmi_debug) 01392 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)); 01393 set = dbiFreeIndexSet(set); 01394 return rc; 01395 } 01396 01404 static rpmRC dbiFindMatches(dbiIndex dbi, 01405 const char * pat, /*@out@*/ dbiIndexSet * matches) 01406 /*@*/ 01407 { 01408 const char * s = pat; 01409 size_t ns = (s ? strlen(s) : 0); 01410 DBC * dbcursor = NULL; 01411 rpmRC rc = RPMRC_NOTFOUND; 01412 int ret; 01413 int xx; 01414 01415 if (ns == 0) goto exit; 01416 01417 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 01418 01419 /* Add ^...$ *RE anchors. Escape pattern characters. */ 01420 { rpmTag tag = dbi->dbi_rpmtag; 01421 rpmMireMode mode = RPMMIRE_PCRE; 01422 static const char _post_NVRA[] = "(-[^-]+-[^-]+\\.[^.]+|-[^-]+\\.[^.]+|\\.[^.]+|)$"; 01423 const char * _pat; 01424 01425 switch (tag) { 01426 default: 01427 mode = RPMMIRE_PCRE; 01428 _pat = _str2PCREpat("^", s, ".*$"); 01429 break; 01430 case RPMTAG_NVRA: 01431 mode = RPMMIRE_PCRE; 01432 _pat = (s[0] == '^' || s[ns-1] == '$') 01433 ? xstrdup(s) 01434 : _str2PCREpat("^", s, _post_NVRA); 01435 break; 01436 case RPMTAG_FILEPATHS: 01437 if (s[0] == '^' || s[ns-1] == '$') 01438 mode = RPMMIRE_PCRE; 01439 else 01440 #ifdef NOTYET 01441 if (s[0] == '/' && Glob_pattern_p(s, 1)) 01442 mode = RPMMIRE_GLOB; 01443 else 01444 #endif 01445 mode = RPMMIRE_STRCMP; 01446 _pat = xstrdup(s); 01447 break; 01448 } 01449 01450 ret = dbiMireKeys(dbi->dbi_rpmdb, tag, mode, _pat, matches, NULL); 01451 01452 _pat = _free(_pat); 01453 } 01454 01455 switch (ret) { 01456 case 0: rc = RPMRC_OK; break; 01457 case DB_NOTFOUND: rc = RPMRC_NOTFOUND; break; 01458 default: rc = RPMRC_FAIL; 01459 rpmlog(RPMLOG_ERR, _("error(%d) getting records from %s index\n"), 01460 ret, tagName(dbi->dbi_rpmtag)); 01461 break; 01462 } 01463 01464 xx = dbiCclose(dbi, dbcursor, 0); 01465 dbcursor = NULL; 01466 01467 exit: 01468 /*@-unqualifiedtrans@*/ /* FIX: double indirection */ 01469 if (rc != RPMRC_OK && matches && *matches) 01470 *matches = dbiFreeIndexSet(*matches); 01471 /*@=unqualifiedtrans@*/ 01472 return rc; 01473 } 01474 01475 void * dbiStatsAccumulator(dbiIndex dbi, int opx) 01476 { 01477 void * sw = NULL; 01478 switch (opx) { 01479 case 14: /* RPMTS_OP_DBGET */ 01480 sw = &dbi->dbi_rpmdb->db_getops; 01481 break; 01482 case 15: /* RPMTS_OP_DBPUT */ 01483 sw = &dbi->dbi_rpmdb->db_putops; 01484 break; 01485 default: /* XXX wrong, but let's not return NULL. */ 01486 case 16: /* RPMTS_OP_DBDEL */ 01487 sw = &dbi->dbi_rpmdb->db_delops; 01488 break; 01489 } 01490 return sw; 01491 } 01492 01501 static int miFreeHeader(rpmmi mi, dbiIndex dbi) 01502 /*@globals fileSystem, internalState @*/ 01503 /*@modifies mi, dbi, fileSystem, internalState @*/ 01504 { 01505 int rc = 0; 01506 01507 if (mi == NULL || mi->mi_h == NULL) 01508 return 0; 01509 01510 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) { 01511 DBT k = DBT_INIT; 01512 DBT v = DBT_INIT; 01513 int xx; 01514 01515 /*@i@*/ k.data = (void *) &mi->mi_prevoffset; 01516 k.size = (UINT32_T) sizeof(mi->mi_prevoffset); 01517 { size_t len = 0; 01518 v.data = headerUnload(mi->mi_h, &len); 01519 v.size = (UINT32_T) len; 01520 } 01521 01522 if (v.data != NULL) { 01523 sigset_t signalMask; 01524 (void) blockSignals(dbi->dbi_rpmdb, &signalMask); 01525 rc = dbiPut(dbi, mi->mi_dbc, &k, &v, DB_KEYLAST); 01526 if (rc) { 01527 rpmlog(RPMLOG_ERR, 01528 _("error(%d) storing record h#%u into %s\n"), 01529 rc, (unsigned)_ntoh_ui(mi->mi_prevoffset), 01530 tagName(dbi->dbi_rpmtag)); 01531 } 01532 xx = dbiSync(dbi, 0); 01533 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask); 01534 } 01535 v.data = _free(v.data); /* headerUnload */ 01536 v.size = 0; 01537 } 01538 01539 (void)headerFree(mi->mi_h); 01540 mi->mi_h = NULL; 01541 01542 /*@-nullstate@*/ 01543 return rc; 01544 /*@=nullstate@*/ 01545 } 01546 01547 static void rpmmiFini(void * _mi) 01548 /*@globals rpmmiRock @*/ 01549 /*@modifies _mi, rpmmiRock @*/ 01550 { 01551 rpmmi mi = _mi; 01552 rpmmi * prev, next; 01553 dbiIndex dbi; 01554 int xx; 01555 01556 prev = &rpmmiRock; 01557 while ((next = *prev) != NULL && next != mi) 01558 prev = &next->mi_next; 01559 if (next) { 01560 /*@i@*/ *prev = next->mi_next; 01561 next->mi_next = NULL; 01562 } 01563 01564 /* XXX NOTFOUND exits traverse here w mi->mi_db == NULL. b0rked imho. */ 01565 if (mi->mi_db) { 01566 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0); 01567 assert(dbi != NULL); /* XXX sanity */ 01568 01569 xx = miFreeHeader(mi, dbi); 01570 01571 if (mi->mi_dbc) 01572 xx = dbiCclose(dbi, mi->mi_dbc, 0); 01573 mi->mi_dbc = NULL; 01574 /* XXX rpmdbUnlink will not do. 01575 * NB: must be called after rpmmiRock cleanup. 01576 */ 01577 (void) rpmdbClose(mi->mi_db); 01578 mi->mi_db = NULL; 01579 } 01580 01581 (void) mireFreeAll(mi->mi_re, mi->mi_nre); 01582 mi->mi_re = NULL; 01583 01584 (void) rpmbfFree(mi->mi_bf); 01585 mi->mi_bf = NULL; 01586 mi->mi_set = dbiFreeIndexSet(mi->mi_set); 01587 01588 mi->mi_keyp = _free(mi->mi_keyp); 01589 mi->mi_keylen = 0; 01590 mi->mi_primary = _free(mi->mi_primary); 01591 01592 /* XXX this needs to be done elsewhere, not within destructor. */ 01593 (void) rpmdbCheckSignals(); 01594 } 01595 01596 /*@unchecked@*/ /*@only@*/ /*@null@*/ 01597 rpmioPool _rpmmiPool; 01598 01599 static rpmmi rpmmiGetPool(/*@null@*/ rpmioPool pool) 01600 /*@globals _rpmdbPool, fileSystem @*/ 01601 /*@modifies pool, _rpmdbPool, fileSystem @*/ 01602 { 01603 rpmmi mi; 01604 01605 if (_rpmmiPool == NULL) { 01606 _rpmmiPool = rpmioNewPool("mi", sizeof(*mi), -1, _rpmmi_debug, 01607 NULL, NULL, rpmmiFini); 01608 pool = _rpmmiPool; 01609 } 01610 mi = (rpmmi) rpmioGetPool(pool, sizeof(*mi)); 01611 memset(((char *)mi)+sizeof(mi->_item), 0, sizeof(*mi)-sizeof(mi->_item)); 01612 return mi; 01613 } 01614 01615 uint32_t rpmmiInstance(rpmmi mi) 01616 { 01617 /* Get a native endian copy of the primary package key. */ 01618 uint32_t rc = _ntoh_ui(mi ? mi->mi_offset : 0); 01619 if (_rpmmi_debug) 01620 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01621 return rc; 01622 } 01623 01624 uint32_t rpmmiBNTag(rpmmi mi) { 01625 uint32_t rc = (mi ? mi->mi_bntag : 0); 01626 if (_rpmmi_debug) 01627 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01628 return rc; 01629 } 01630 01631 unsigned int rpmmiCount(rpmmi mi) 01632 { 01633 unsigned int rc; 01634 int initDbc; 01635 01636 /* XXX Secondary db associated with Packages needs cursor record count */ 01637 if (mi && mi->mi_primary && ((initDbc = mi->mi_dbc == NULL) || mi->mi_count == 0)) { 01638 dbiIndex dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0); 01639 DBT k = DBT_INIT; 01640 DBT v = DBT_INIT; 01641 int xx; 01642 if(initDbc) { 01643 assert(dbi != NULL); /* XXX dbiCopen doesn't handle dbi == NULL */ 01644 xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags); 01645 } 01646 k.data = mi->mi_keyp; 01647 k.size = (u_int32_t)mi->mi_keylen; 01648 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data); 01649 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */ 01650 if (!dbiGet(dbi, mi->mi_dbc, &k, &v, DB_SET)) 01651 xx = dbiCount(dbi, mi->mi_dbc, &mi->mi_count, 0); 01652 if(initDbc) 01653 mi->mi_dbc = NULL; 01654 } 01655 01656 rc = (mi ? mi->mi_count : 0); 01657 01658 if (_rpmmi_debug) 01659 fprintf(stderr, "<-- %s(%p) rc %u\n", __FUNCTION__, mi, (unsigned)rc); 01660 return rc; 01661 } 01662 01669 static int mireCmp(const void * a, const void * b) 01670 { 01671 /*@-castexpose @*/ 01672 const miRE mireA = (const miRE) a; 01673 const miRE mireB = (const miRE) b; 01674 /*@=castexpose @*/ 01675 return (mireA->tag - mireB->tag); 01676 } 01677 01685 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep, 01686 const char * pattern) 01687 /*@modifies *modep @*/ 01688 /*@requires maxSet(modep) >= 0 @*/ 01689 { 01690 const char * s; 01691 char * pat; 01692 char * t; 01693 int brackets; 01694 size_t nb; 01695 int c; 01696 01697 switch (*modep) { 01698 default: 01699 case RPMMIRE_DEFAULT: 01700 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES 01701 || tag == RPMTAG_FILEPATHS) 01702 { 01703 *modep = RPMMIRE_GLOB; 01704 pat = xstrdup(pattern); 01705 break; 01706 } 01707 01708 nb = strlen(pattern) + sizeof("^$"); 01709 01710 /* Find no. of bytes needed for pattern. */ 01711 /* periods and plusses are escaped, splats become '.*' */ 01712 c = (int) '\0'; 01713 brackets = 0; 01714 for (s = pattern; *s != '\0'; s++) { 01715 switch (*s) { 01716 case '.': 01717 case '+': 01718 case '*': 01719 if (!brackets) nb++; 01720 /*@switchbreak@*/ break; 01721 case '\\': 01722 s++; 01723 /*@switchbreak@*/ break; 01724 case '[': 01725 brackets = 1; 01726 /*@switchbreak@*/ break; 01727 case ']': 01728 if (c != (int) '[') brackets = 0; 01729 /*@switchbreak@*/ break; 01730 } 01731 c = (int) *s; 01732 } 01733 01734 pat = t = xmalloc(nb); 01735 01736 if (pattern[0] != '^') *t++ = '^'; 01737 01738 /* Copy pattern, escaping periods, prefixing splats with period. */ 01739 c = (int) '\0'; 01740 brackets = 0; 01741 for (s = pattern; *s != '\0'; s++, t++) { 01742 switch (*s) { 01743 case '.': 01744 case '+': 01745 if (!brackets) *t++ = '\\'; 01746 /*@switchbreak@*/ break; 01747 case '*': 01748 if (!brackets) *t++ = '.'; 01749 /*@switchbreak@*/ break; 01750 case '\\': 01751 *t++ = *s++; 01752 /*@switchbreak@*/ break; 01753 case '[': 01754 brackets = 1; 01755 /*@switchbreak@*/ break; 01756 case ']': 01757 if (c != (int) '[') brackets = 0; 01758 /*@switchbreak@*/ break; 01759 } 01760 *t = *s; 01761 c = (int) *t; 01762 } 01763 01764 if (s > pattern && s[-1] != '$') *t++ = '$'; 01765 *t = '\0'; 01766 *modep = RPMMIRE_REGEX; 01767 break; 01768 case RPMMIRE_STRCMP: 01769 case RPMMIRE_REGEX: 01770 case RPMMIRE_GLOB: 01771 pat = xstrdup(pattern); 01772 break; 01773 } 01774 01775 return pat; 01776 } 01777 01778 int rpmmiAddPattern(rpmmi mi, rpmTag tag, 01779 rpmMireMode mode, const char * pattern) 01780 { 01781 static rpmMireMode defmode = (rpmMireMode)-1; 01782 miRE nmire = NULL; 01783 miRE mire = NULL; 01784 const char * allpat = NULL; 01785 int notmatch = 0; 01786 int rc = 0; 01787 01788 if (defmode == (rpmMireMode)-1) { 01789 const char *t = rpmExpand("%{?_query_selector_match}", NULL); 01790 01791 if (*t == '\0' || !strcmp(t, "default")) 01792 defmode = RPMMIRE_DEFAULT; 01793 else if (!strcmp(t, "strcmp")) 01794 defmode = RPMMIRE_STRCMP; 01795 else if (!strcmp(t, "regex")) 01796 defmode = RPMMIRE_REGEX; 01797 else if (!strcmp(t, "glob")) 01798 defmode = RPMMIRE_GLOB; 01799 else 01800 defmode = RPMMIRE_DEFAULT; 01801 t = _free(t); 01802 } 01803 01804 if (mi == NULL || pattern == NULL) 01805 return rc; 01806 01807 /* Leading '!' inverts pattern match sense, like "grep -v". */ 01808 if (*pattern == '!') { 01809 notmatch = 1; 01810 pattern++; 01811 } 01812 01813 nmire = mireNew(mode, tag); 01814 assert(nmire != NULL); 01815 allpat = mireDup(nmire->tag, &nmire->mode, pattern); 01816 01817 if (nmire->mode == RPMMIRE_DEFAULT) 01818 nmire->mode = defmode; 01819 01820 rc = mireRegcomp(nmire, allpat); 01821 if (rc) 01822 goto exit; 01823 01824 if (mi->mi_re == NULL) { 01825 mi->mi_re = mireGetPool(_mirePool); 01826 mire = mireLink(mi->mi_re); 01827 } else { 01828 void *use = mi->mi_re->_item.use; 01829 void *pool = mi->mi_re->_item.pool; 01830 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re)); 01831 if (_mire_debug) 01832 fprintf(stderr, " mire %p[%u] realloc\n", mi->mi_re, mi->mi_nre+1); 01833 mire = mi->mi_re + mi->mi_nre; 01834 memset(mire, 0, sizeof(*mire)); 01835 /* XXX ensure no segfault, copy the use/pool from 1st item. */ 01836 /*@-assignexpose@*/ 01837 mire->_item.use = use; 01838 mire->_item.pool = pool; 01839 /*@=assignexpose@*/ 01840 } 01841 mi->mi_nre++; 01842 01843 mire->mode = nmire->mode; 01844 mire->pattern = nmire->pattern; nmire->pattern = NULL; 01845 mire->preg = nmire->preg; nmire->preg = NULL; 01846 mire->cflags = nmire->cflags; 01847 mire->eflags = nmire->eflags; 01848 mire->fnflags = nmire->fnflags; 01849 mire->tag = nmire->tag; 01850 mire->notmatch = notmatch; 01851 /* XXX todo: permit PCRE patterns to be used. */ 01852 mire->offsets = NULL; 01853 mire->noffsets = 0; 01854 01855 if (mi->mi_nre > 1) 01856 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp); 01857 01858 exit: 01859 if (_rpmmi_debug) 01860 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)); 01861 allpat = _free(allpat); 01862 nmire = mireFree(nmire); 01863 return rc; 01864 } 01865 01871 static inline unsigned char nibble(char c) 01872 /*@*/ 01873 { 01874 if (c >= '0' && c <= '9') 01875 return (unsigned char)(c - '0'); 01876 if (c >= 'A' && c <= 'F') 01877 return (unsigned char)((int)(c - 'A') + 10); 01878 if (c >= 'a' && c <= 'f') 01879 return (unsigned char)((int)(c - 'a') + 10); 01880 return '\0'; 01881 } 01882 01889 /*@only@*/ 01890 static char * bin2hex(const void *data, size_t size) 01891 /*@*/ 01892 { 01893 static char hex[] = "0123456789abcdef"; 01894 const char * s = data; 01895 char * t, * val; 01896 val = t = xmalloc(size * 2 + 1); 01897 while (size-- > 0) { 01898 unsigned i; 01899 i = (unsigned) *s++; 01900 *t++ = hex[ (i >> 4) & 0xf ]; 01901 *t++ = hex[ (i ) & 0xf ]; 01902 } 01903 *t = '\0'; 01904 01905 return val; 01906 } 01907 01913 /*@-onlytrans@*/ /* XXX miRE array, not refcounted. */ 01914 static int mireSkip (const rpmmi mi) 01915 /*@globals internalState @*/ 01916 /*@modifies mi->mi_re, internalState @*/ 01917 { 01918 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01919 char numbuf[32]; 01920 miRE mire; 01921 int ntags = 0; 01922 int nmatches = 0; 01923 int i; 01924 int rc; 01925 01926 if (mi->mi_h == NULL) /* XXX can't happen */ 01927 return 1; 01928 01929 /* 01930 * Apply tag tests, implicitly "||" for multiple patterns/values of a 01931 * single tag, implicitly "&&" between multiple tag patterns. 01932 */ 01933 if ((mire = mi->mi_re) == NULL) 01934 return 0; 01935 01936 for (i = 0; i < mi->mi_nre; i++, mire++) { 01937 int anymatch; 01938 01939 he->tag = mire->tag; 01940 01941 if (!headerGet(mi->mi_h, he, 0)) { 01942 if (he->tag != RPMTAG_EPOCH) { 01943 ntags++; 01944 continue; 01945 } 01946 he->t = RPM_UINT32_TYPE; 01947 he->p.ui32p = xcalloc(1, sizeof(*he->p.ui32p)); 01948 he->c = 1; 01949 } 01950 01951 anymatch = 0; /* no matches yet */ 01952 while (1) { 01953 unsigned j; 01954 switch (he->t) { 01955 case RPM_UINT8_TYPE: 01956 for (j = 0; j < (unsigned) he->c; j++) { 01957 sprintf(numbuf, "%u", (unsigned) he->p.ui8p[j]); 01958 rc = mireRegexec(mire, numbuf, 0); 01959 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01960 anymatch++; 01961 } 01962 /*@switchbreak@*/ break; 01963 case RPM_UINT16_TYPE: 01964 for (j = 0; j < (unsigned) he->c; j++) { 01965 sprintf(numbuf, "%u", (unsigned) he->p.ui16p[j]); 01966 rc = mireRegexec(mire, numbuf, 0); 01967 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01968 anymatch++; 01969 } 01970 /*@switchbreak@*/ break; 01971 case RPM_UINT32_TYPE: 01972 for (j = 0; j < (unsigned) he->c; j++) { 01973 sprintf(numbuf, "%u", (unsigned) he->p.ui32p[j]); 01974 rc = mireRegexec(mire, numbuf, 0); 01975 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01976 anymatch++; 01977 } 01978 /*@switchbreak@*/ break; 01979 case RPM_UINT64_TYPE: 01980 /*@-duplicatequals@*/ 01981 for (j = 0; j < (unsigned) he->c; j++) { 01982 sprintf(numbuf, "%llu", (unsigned long long)he->p.ui64p[j]); 01983 rc = mireRegexec(mire, numbuf, 0); 01984 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01985 anymatch++; 01986 } 01987 /*@=duplicatequals@*/ 01988 /*@switchbreak@*/ break; 01989 case RPM_STRING_TYPE: 01990 rc = mireRegexec(mire, he->p.str, 0); 01991 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 01992 anymatch++; 01993 /*@switchbreak@*/ break; 01994 case RPM_STRING_ARRAY_TYPE: 01995 for (j = 0; j < (unsigned) he->c; j++) { 01996 rc = mireRegexec(mire, he->p.argv[j], 0); 01997 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) { 01998 anymatch++; 01999 /*@innerbreak@*/ break; 02000 } 02001 } 02002 /*@switchbreak@*/ break; 02003 case RPM_BIN_TYPE: 02004 { const char * s; 02005 assert(he->p.ptr != NULL); 02006 s = bin2hex(he->p.ptr, he->c); 02007 rc = mireRegexec(mire, s, 0); 02008 if ((rc >= 0 && !mire->notmatch) || (rc < 0 && mire->notmatch)) 02009 anymatch++; 02010 s = _free(s); 02011 } /*@switchbreak@*/ break; 02012 case RPM_I18NSTRING_TYPE: 02013 default: 02014 /*@switchbreak@*/ break; 02015 } 02016 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) { 02017 i++; 02018 mire++; 02019 /*@innercontinue@*/ continue; 02020 } 02021 /*@innerbreak@*/ break; 02022 } 02023 02024 he->p.ptr = _free(he->p.ptr); 02025 02026 if (anymatch) 02027 nmatches++; 02028 ntags++; 02029 } 02030 02031 return (ntags > 0 && ntags == nmatches ? 0 : 1); 02032 } 02033 /*@=onlytrans@*/ 02034 02035 int rpmmiSetRewrite(rpmmi mi, int rewrite) 02036 { 02037 int rc; 02038 if (mi == NULL) 02039 return 0; 02040 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0; 02041 if (rewrite) 02042 mi->mi_cflags |= DB_WRITECURSOR; 02043 else 02044 mi->mi_cflags &= ~DB_WRITECURSOR; 02045 return rc; 02046 } 02047 02048 int rpmmiSetModified(rpmmi mi, int modified) 02049 { 02050 int rc; 02051 if (mi == NULL) 02052 return 0; 02053 rc = mi->mi_modified; 02054 mi->mi_modified = modified; 02055 return rc; 02056 } 02057 02058 /*@unchecked@*/ 02059 static int _rpmmi_usermem = 1; 02060 02061 static int rpmmiGet(dbiIndex dbi, DBC * dbcursor, DBT * kp, DBT * pk, DBT * vp, 02062 unsigned int flags) 02063 /*@globals internalState @*/ 02064 /*@modifies dbi, dbcursor, *kp, *pk, *vp, internalState @*/ 02065 { 02066 int map; 02067 int rc; 02068 02069 switch (dbi->dbi_rpmdb->db_api) { 02070 default: map = 0; break; 02071 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */ 02072 } 02073 02074 if (map) { 02075 static const int _prot = PROT_READ | PROT_WRITE; 02076 static const int _flags = MAP_PRIVATE| MAP_ANONYMOUS; 02077 static const int _fdno = -1; 02078 static const off_t _off = 0; 02079 02080 memset(vp, 0, sizeof(*vp)); 02081 vp->flags |= DB_DBT_USERMEM; 02082 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02083 if (rc == DB_BUFFER_SMALL) { 02084 size_t uhlen = vp->size; 02085 void * uh = mmap(NULL, uhlen, _prot, _flags, _fdno, _off); 02086 if (uh == NULL || uh == (void *)-1) 02087 fprintf(stderr, 02088 "==> mmap(%p[%u], 0x%x, 0x%x, %d, 0x%x) error(%d): %s\n", 02089 NULL, (unsigned)uhlen, _prot, _flags, _fdno, (unsigned)_off, 02090 errno, strerror(errno)); 02091 02092 vp->ulen = (u_int32_t)uhlen; 02093 vp->data = uh; 02094 if (dbi->dbi_primary && pk) 02095 rc = dbiPget(dbi, dbcursor, kp, pk, vp, flags); 02096 else 02097 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02098 if (rc == 0) { 02099 if (mprotect(uh, uhlen, PROT_READ) != 0) 02100 fprintf(stderr, "==> mprotect(%p[%u],0x%x) error(%d): %s\n", 02101 uh, (unsigned)uhlen, PROT_READ, 02102 errno, strerror(errno)); 02103 } else { 02104 if (munmap(uh, uhlen) != 0) 02105 fprintf(stderr, "==> munmap(%p[%u]) error(%d): %s\n", 02106 uh, (unsigned)uhlen, errno, strerror(errno)); 02107 } 02108 } 02109 } else 02110 rc = dbiGet(dbi, dbcursor, kp, vp, flags); 02111 if (_rpmmi_debug || dbi->dbi_debug) 02112 fprintf(stderr, "<-- %s(%p(%s),%p,%p,%p,0x%x) rc %d\n", __FUNCTION__, dbi, tagName(dbi->dbi_rpmtag), dbcursor, kp, vp, flags, rc); 02113 02114 return rc; 02115 } 02116 02117 Header rpmmiNext(rpmmi mi) 02118 { 02119 dbiIndex dbi; 02120 DBT k = DBT_INIT; 02121 DBT p = DBT_INIT; 02122 DBT v = DBT_INIT; 02123 void * uh; 02124 size_t uhlen; 02125 rpmTag tag; 02126 unsigned int _flags; 02127 int map; 02128 int rc; 02129 int xx; 02130 02131 if (mi == NULL) 02132 return NULL; 02133 02134 /* Find the tag to open. */ 02135 tag = (mi->mi_set == NULL && mi->mi_primary != NULL 02136 ? mi->mi_rpmtag : RPMDBI_PACKAGES); 02137 dbi = dbiOpen(mi->mi_db, tag, 0); 02138 if (dbi == NULL) 02139 return NULL; 02140 02141 switch (dbi->dbi_rpmdb->db_api) { 02142 default: map = 0; break; 02143 case 3: map = _rpmmi_usermem; break; /* Berkeley DB */ 02144 } 02145 02146 if (_rpmmi_debug || dbi->dbi_debug) 02147 fprintf(stderr, "--> %s(%p) dbi %p(%s)\n", __FUNCTION__, mi, dbi, tagName(tag)); 02148 02149 /* 02150 * Cursors are per-iterator, not per-dbi, so get a cursor for the 02151 * iterator on 1st call. If the iteration is to rewrite headers, and the 02152 * CDB model is used for the database, then the cursor needs to 02153 * marked with DB_WRITECURSOR as well. 02154 */ 02155 if (mi->mi_dbc == NULL) { 02156 xx = dbiCopen(dbi, dbiTxnid(dbi), &mi->mi_dbc, mi->mi_cflags); 02157 k.data = mi->mi_keyp; 02158 k.size = (u_int32_t)mi->mi_keylen; 02159 if (k.data && k.size == 0) k.size = (UINT32_T) strlen((char *)k.data); 02160 if (k.data && k.size == 0) k.size++; /* XXX "/" fixup. */ 02161 _flags = DB_SET; 02162 } else 02163 _flags = (mi->mi_setx ? DB_NEXT_DUP : DB_SET); 02164 02165 next: 02166 if (mi->mi_set) { 02167 /* The set of header instances is known in advance. */ 02168 if (!(mi->mi_setx < mi->mi_set->count)) 02169 return NULL; 02170 mi->mi_offset = _hton_ui(dbiIndexRecordOffset(mi->mi_set, mi->mi_setx)); 02171 mi->mi_bntag = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx); 02172 mi->mi_setx++; 02173 02174 /* If next header is identical, return it now. */ 02175 if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL) 02176 return mi->mi_h; 02177 02178 /* Should this header be skipped? */ 02179 if (mi->mi_bf != NULL 02180 && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0) 02181 goto next; 02182 02183 /* Fetch header by offset. */ 02184 k.data = &mi->mi_offset; 02185 k.size = (UINT32_T)sizeof(mi->mi_offset); 02186 rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_SET); 02187 } 02188 else if (dbi->dbi_primary) { 02189 rc = rpmmiGet(dbi, mi->mi_dbc, &k, &p, &v, _flags); 02190 switch (rc) { 02191 default: 02192 assert(0); 02193 /*@notreached@*/ break; 02194 case DB_NOTFOUND: 02195 return NULL; 02196 /*@notreached@*/ break; 02197 case 0: 02198 mi->mi_setx++; 02199 assert((size_t)p.size == sizeof(mi->mi_offset)); 02200 memcpy(&mi->mi_offset, p.data, sizeof(mi->mi_offset)); 02201 /* If next header is identical, return it now. */ 02202 if (mi->mi_offset == mi->mi_prevoffset && mi->mi_h != NULL) 02203 return mi->mi_h; 02204 break; 02205 } 02206 _flags = DB_NEXT_DUP; 02207 } 02208 else { 02209 /* Iterating Packages database. */ 02210 assert(mi->mi_rpmtag == RPMDBI_PACKAGES); 02211 02212 /* Fetch header with DB_NEXT. */ 02213 /* Instance 0 is the largest header instance in legacy databases, 02214 * and must be skipped. */ 02215 do { 02216 rc = rpmmiGet(dbi, mi->mi_dbc, &k, NULL, &v, DB_NEXT); 02217 if (rc == 0) { 02218 assert((size_t)k.size == sizeof(mi->mi_offset)); 02219 memcpy(&mi->mi_offset, k.data, sizeof(mi->mi_offset)); 02220 } 02221 } while (rc == 0 && mi->mi_offset == 0); 02222 } 02223 02224 /* Did the header blob load correctly? */ 02225 if (rc) 02226 return NULL; 02227 02228 /* Should this header be skipped? */ 02229 if (mi->mi_set == NULL && mi->mi_bf != NULL 02230 && rpmbfChk(mi->mi_bf, &mi->mi_offset, sizeof(mi->mi_offset)) > 0) 02231 goto next; 02232 02233 uh = v.data; 02234 uhlen = v.size; 02235 if (uh == NULL) 02236 return NULL; 02237 02238 /* Rewrite current header (if necessary) and unlink. */ 02239 xx = miFreeHeader(mi, dbi); 02240 02241 if (map) { 02242 /*@-onlytrans@*/ 02243 mi->mi_h = headerLoad(uh); 02244 /*@=onlytrans@*/ 02245 if (mi->mi_h) { 02246 mi->mi_h->flags |= HEADERFLAG_MAPPED; 02247 mi->mi_h->flags |= HEADERFLAG_RDONLY; 02248 } 02249 } else 02250 mi->mi_h = headerCopyLoad(uh); 02251 02252 if (mi->mi_h == NULL) { 02253 rpmlog(RPMLOG_ERR, 02254 _("rpmdb: header #%u cannot be loaded -- skipping.\n"), 02255 (unsigned)_ntoh_ui(mi->mi_offset)); 02256 /* damaged header should not be reused */ 02257 if (mi->mi_h) { 02258 (void)headerFree(mi->mi_h); 02259 mi->mi_h = NULL; 02260 } 02261 /* TODO: skip more mi_set records */ 02262 goto next; 02263 } 02264 02265 /* Skip this header if iterator selector (if any) doesn't match. */ 02266 if (mireSkip(mi)) 02267 goto next; 02268 02269 /* Mark header with its instance number. */ 02270 { char origin[32]; 02271 uint32_t hdrNum = _ntoh_ui(mi->mi_offset); 02272 sprintf(origin, "rpmdb (h#%u)", (unsigned)hdrNum); 02273 (void) headerSetOrigin(mi->mi_h, origin); 02274 (void) headerSetInstance(mi->mi_h, hdrNum); 02275 } 02276 02277 mi->mi_prevoffset = mi->mi_offset; 02278 mi->mi_modified = 0; 02279 02280 /*@-compdef -retalias -retexpose -usereleased @*/ 02281 return mi->mi_h; 02282 /*@=compdef =retalias =retexpose =usereleased @*/ 02283 } 02284 02285 int rpmmiSort(rpmmi mi) 02286 { 02287 int rc = 0; 02288 02289 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) { 02290 /* 02291 * mergesort is much (~10x with lots of identical basenames) faster 02292 * than pure quicksort, but glibc uses msort_with_tmp() on stack. 02293 */ 02294 if (mi->mi_set->count > 1) { 02295 #if defined(__GLIBC__) 02296 qsort(mi->mi_set->recs, mi->mi_set->count, 02297 sizeof(*mi->mi_set->recs), hdrNumCmp); 02298 #else 02299 rpm_mergesort(mi->mi_set->recs, mi->mi_set->count, 02300 sizeof(*mi->mi_set->recs), hdrNumCmp); 02301 #endif 02302 } 02303 mi->mi_sorted = 1; 02304 #ifdef NOTNOW 02305 { struct _dbiIndexItem * rec; 02306 int i; 02307 for (i = 0, rec = mi->mi_set->recs; i < mi->mi_set->count; i++, rec++) { 02308 fprintf(stderr, "\t%p[%u] = %p: %u %u %u\n", mi->mi_set->recs, 02309 i, rec, rec->hdrNum, rec->tagNum, rec->fpNum); 02310 } 02311 } 02312 #endif 02313 } 02314 return rc; 02315 } 02316 02317 /* XXX TODO: a Bloom Filter on removed packages created once, not each time. */ 02318 int rpmmiPrune(rpmmi mi, uint32_t * hdrNums, int nHdrNums, int sorted) 02319 { 02320 int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0); 02321 02322 if (!rc) { 02323 int i; 02324 if (mi->mi_bf == NULL) { 02325 static size_t nRemoves = 2 * 8192; /* XXX population estimate */ 02326 static double e = 1.0e-4; 02327 size_t m = 0; 02328 size_t k = 0; 02329 rpmbfParams(nRemoves, e, &m, &k); 02330 mi->mi_bf = rpmbfNew(m, k, 0); 02331 } 02332 for (i = 0; i < nHdrNums; i++) { 02333 uint32_t mi_offset = _hton_ui(hdrNums[i]); 02334 int xx = rpmbfAdd(mi->mi_bf, &mi_offset, sizeof(mi_offset)); 02335 assert(xx == 0); 02336 } 02337 } 02338 02339 if (_rpmmi_debug) 02340 fprintf(stderr, "<-- %s(%p, %p[%u], %d) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, sorted, rc, (unsigned) (hdrNums ? hdrNums[0] : 0)); 02341 return rc; 02342 } 02343 02344 int rpmmiGrow(rpmmi mi, const uint32_t * hdrNums, int nHdrNums) 02345 { 02346 int rc = (mi == NULL || hdrNums == NULL || nHdrNums <= 0); 02347 02348 if (!rc) { 02349 if (mi->mi_set == NULL) 02350 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set)); 02351 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0); 02352 } 02353 02354 if (_rpmmi_debug) 02355 fprintf(stderr, "<-- %s(%p, %p[%u]) rc %d h# %u\n", __FUNCTION__, mi, hdrNums, (unsigned)nHdrNums, rc, (unsigned) (hdrNums ? hdrNums[0] : 0)); 02356 return rc; 02357 } 02358 02359 /*@-dependenttrans -exposetrans -globstate @*/ 02360 rpmmi rpmmiInit(rpmdb db, rpmTag tag, const void * keyp, size_t keylen) 02361 { 02362 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02363 rpmmi mi = NULL; 02364 dbiIndexSet set = NULL; 02365 dbiIndex dbi = NULL; 02366 int usePatterns = 0; 02367 02368 if (db == NULL) 02369 goto exit; 02370 02371 (void) rpmdbCheckSignals(); 02372 02373 /* XXX Control for whether patterns are permitted. */ 02374 switch (tag) { 02375 default: break; 02376 case 2: /* XXX HACK to remove RPMDBI_LABEL from RPM. */ 02377 /* XXX rpmlog message warning RPMDBI is deprecated? */ 02378 tag = RPMTAG_NVRA; 02379 /*@fallthrough@*/ 02380 case RPMTAG_NVRA: 02381 #ifdef NOTYET /* XXX JS unit tests break. */ 02382 case RPMTAG_NAME: 02383 #endif 02384 #ifdef RPM_VENDOR_MANDRIVA_XXX /* XXX rpm -qf /non/existent breaks */ 02385 case RPMTAG_PROVIDENAME: 02386 #endif 02387 case RPMTAG_VERSION: 02388 case RPMTAG_RELEASE: 02389 case RPMTAG_ARCH: 02390 case RPMTAG_OS: 02391 case RPMTAG_GROUP: 02392 usePatterns = 1; 02393 break; 02394 #ifndef NOTYET /* XXX can't quite do this yet */ 02395 /* XXX HACK to remove the existing complexity of RPMTAG_BASENAMES */ 02396 case RPMTAG_BASENAMES: 02397 if (keyp == NULL) /* XXX rpmdbFindFpList & grow are speshul */ 02398 break; 02399 tag = RPMTAG_FILEPATHS; 02400 /*@fallthrough@*/ 02401 #endif 02402 case RPMTAG_FILEPATHS: 02403 case RPMTAG_DIRNAMES: 02404 usePatterns = 1; 02405 break; 02406 } 02407 02408 dbi = dbiOpen(db, tag, 0); 02409 #ifdef NOTYET /* XXX non-configured tag indices force NULL return */ 02410 assert(dbi != NULL); /* XXX sanity */ 02411 #else 02412 if (dbi == NULL) 02413 goto exit; 02414 #endif 02415 02416 mi = rpmmiGetPool(_rpmmiPool); 02417 (void)rpmioLinkPoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__); 02418 02419 if (_rpmmi_debug || (dbi && dbi->dbi_debug)) 02420 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); 02421 02422 /* Chain cursors for teardown on abnormal exit. */ 02423 mi->mi_next = rpmmiRock; 02424 rpmmiRock = mi; 02425 02426 if (tag == RPMDBI_PACKAGES && keyp == NULL) { 02427 /* Special case #1: sequentially iterate Packages database. */ 02428 assert(keylen == 0); 02429 /* This should be the only case when (set == NULL). */ 02430 } 02431 else if (tag == RPMDBI_PACKAGES) { 02432 /* Special case #2: will fetch header instance. */ 02433 uint32_t hdrNum; 02434 assert(keylen == sizeof(hdrNum)); 02435 memcpy(&hdrNum, keyp, sizeof(hdrNum)); 02436 /* The set has only one element, which is hdrNum. */ 02437 set = xcalloc(1, sizeof(*set)); 02438 set->count = 1; 02439 set->recs = xcalloc(1, sizeof(set->recs[0])); 02440 set->recs[0].hdrNum = hdrNum; 02441 } 02442 else if (keyp == NULL) { 02443 /* XXX Special case #3: empty iterator with rpmmiGrow() */ 02444 assert(keylen == 0); 02445 } 02446 else if (usePatterns) { 02447 /* XXX Special case #4: gather primary keys with patterns. */ 02448 rpmRC rc; 02449 02450 rc = dbiFindMatches(dbi, keyp, &set); 02451 #if defined(RPM_VENDOR_MANDRIVA) 02452 /* 02453 * Hack to workaround disttag/distepoch pattern matching issue to buy some 02454 * time to come up with better pattern fix.. 02455 * One size should fit all now.. ;) 02456 * 02457 * This patch will try match NVR first, then for all matches returned, 02458 * it will match disttag, distepoch & arch individually. 02459 */ 02460 02461 /* We'll only try this if query fails */ 02462 if(!rc && ((const char*)keyp)[0] != '^' && tag == RPMTAG_NVRA && 02463 (set == NULL || set->count < 1)) { 02464 size_t i; 02465 char *tmp = (char*)keyp; 02466 02467 /* If pattern has less than three '-', it can't contain disttag, so 02468 * no point in trying */ 02469 for (i = 0; (tmp = strchr(tmp, '-')); i++, tmp++); 02470 if (i >= 3) { 02471 dbiIndex pdbi; 02472 DBC *pdbc; 02473 const char *origkeyp = keyp; 02474 size_t klen = strlen(keyp)+1; 02475 size_t size = 0; 02476 int xx; 02477 02478 keyp = alloca(klen); 02479 stpcpy((char*)keyp, origkeyp); 02480 tmp = strrchr(keyp, '-'); 02481 *tmp = '\0'; 02482 rc = dbiFindMatches(dbi, keyp, &set); 02483 02484 pdbi = dbiOpen(db, RPMDBI_PACKAGES, 0); 02485 xx = dbiCopen(pdbi, dbiTxnid(pdbi), &pdbc, 0); 02486 02487 for(i = 0; set && i < set->count; i++) { 02488 DBT k = DBT_INIT; 02489 DBT v = DBT_INIT; 02490 Header h; 02491 uint32_t offset = _hton_ui(set->recs[i].hdrNum); 02492 rpmTag checkTags[] = 02493 { RPMTAG_DISTTAG, RPMTAG_DISTEPOCH, RPMTAG_ARCH }; 02494 int j; 02495 02496 memset(&k, 0, sizeof(k)); 02497 memset(&v, 0, sizeof(v)); 02498 k.data = &offset; 02499 k.size = sizeof(offset); 02500 02501 xx = dbiGet(dbi, pdbc, &k, &v, DB_SET); 02502 h = headerLoad(v.data); 02503 tmp = (char*)((size_t)keyp + strlen(keyp) + 1); 02504 02505 for (j = 0; j < (int)(sizeof(checkTags)/sizeof(checkTags[0])) && 02506 *tmp != '\0'; j++) { 02507 he->tag = checkTags[j]; 02508 if(headerGet(h, he, 0)) { 02509 size_t len = strlen(he->p.str); 02510 02511 if (he->tag == RPMTAG_ARCH && *tmp == '.') 02512 tmp++; 02513 02514 if(!strncmp(he->p.str, tmp, len)) 02515 tmp += len; 02516 _free(he->p.ptr); 02517 } 02518 } 02519 if(j && *tmp == '\0') { 02520 set->recs[size].hdrNum = set->recs[i].hdrNum; 02521 set->recs[size].tagNum = set->recs[i].tagNum; 02522 size++; 02523 } 02524 02525 h = headerFree(h); 02526 } 02527 if(set && set->count != size) { 02528 set->count = size; 02529 set->recs = realloc(set->recs, size * sizeof(*set->recs)); 02530 } 02531 02532 xx = dbiCclose(pdbi, pdbc, 0); 02533 } 02534 } 02535 #endif 02536 02537 if ((rc && rc != RPMRC_NOTFOUND) || set == NULL || set->count < 1) { /* error or empty set */ 02538 set = dbiFreeIndexSet(set); 02539 rpmmiRock = mi->mi_next; 02540 mi->mi_next = NULL; 02541 mi = (rpmmi)rpmioFreePoolItem((rpmioItem)mi, __FUNCTION__, __FILE__, __LINE__); 02542 return NULL; 02543 } 02544 } 02545 else if (dbi && dbi->dbi_primary != NULL) { 02546 /* XXX Special case #5: secondary index associated w primary table. */ 02547 } 02548 else { 02549 /* Common case: retrieve join keys. */ 02550 assert(0); 02551 } 02552 02553 /*@-assignexpose@*/ 02554 mi->mi_db = rpmdbLink(db, __FUNCTION__); 02555 /*@=assignexpose@*/ 02556 mi->mi_rpmtag = tag; 02557 02558 mi->mi_dbc = NULL; 02559 mi->mi_set = set; 02560 mi->mi_setx = 0; 02561 mi->mi_count = (set ? set->count : 0); 02562 02563 mi->mi_primary = (dbi && dbi->dbi_primary 02564 ? xstrdup(dbi->dbi_primary) : NULL); 02565 02566 /* Coerce/swab integer keys. Save key ind keylen in the iterator. */ 02567 switch (tagType(tag) & 0xffff) { 02568 case RPM_UINT8_TYPE: 02569 assert(keylen == sizeof(he->p.ui8p[0])); 02570 mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */ 02571 mi->mi_keyp = he->p.ui32p = xmalloc(mi->mi_keylen); 02572 he->p.ui32p[0] = 0; 02573 memcpy(&he->p.ui8p[3], keyp, keylen); 02574 break; 02575 case RPM_UINT16_TYPE: 02576 assert(keylen == sizeof(he->p.ui16p[0])); 02577 mi->mi_keylen = sizeof(he->p.ui32p[0]); /* XXX coerce to uint32_t */ 02578 mi->mi_keyp = he->p.ui32p = xmalloc(mi->mi_keylen); 02579 he->p.ui32p[0] = 0; 02580 memcpy(&he->p.ui16p[1], keyp, keylen); 02581 he->p.ui16p[1] = _hton_us(he->p.ui16p[1]); 02582 break; 02583 #if !defined(__LCLINT__) /* LCL: buggy */ 02584 case RPM_UINT32_TYPE: 02585 assert(keylen == sizeof(he->p.ui32p[0])); 02586 mi->mi_keylen = keylen; 02587 /*@-mayaliasunique@*/ 02588 mi->mi_keyp = memcpy((he->p.ui32p = xmalloc(keylen)), keyp, keylen); 02589 /*@=mayaliasunique@*/ 02590 he->p.ui32p[0] = _hton_ui(he->p.ui32p[0]); 02591 break; 02592 case RPM_UINT64_TYPE: 02593 assert(keylen == sizeof(he->p.ui64p[0])); 02594 mi->mi_keylen = keylen; 02595 /*@-mayaliasunique@*/ 02596 mi->mi_keyp = memcpy((he->p.ui64p = xmalloc(keylen)), keyp, keylen); 02597 /*@=mayaliasunique@*/ 02598 { uint32_t _tmp = he->p.ui32p[0]; 02599 he->p.ui32p[0] = _hton_ui(he->p.ui32p[1]); 02600 he->p.ui32p[1] = _hton_ui(_tmp); 02601 } 02602 break; 02603 #endif /* !defined(__LCLINT__) */ 02604 case RPM_BIN_TYPE: 02605 case RPM_I18NSTRING_TYPE: /* XXX never occurs */ 02606 case RPM_STRING_TYPE: 02607 case RPM_STRING_ARRAY_TYPE: 02608 default: 02609 mi->mi_keylen = keylen; 02610 if (keyp) 02611 mi->mi_keyp = keylen > 0 02612 ? memcpy(xmalloc(keylen), keyp, keylen) : xstrdup(keyp) ; 02613 else 02614 mi->mi_keyp = NULL; 02615 break; 02616 } 02617 he->p.ptr = NULL; 02618 02619 mi->mi_h = NULL; 02620 mi->mi_sorted = 0; 02621 mi->mi_cflags = 0; 02622 mi->mi_modified = 0; 02623 mi->mi_prevoffset = 0; 02624 mi->mi_offset = 0; 02625 mi->mi_nre = 0; 02626 mi->mi_re = NULL; 02627 02628 exit: 02629 return mi; 02630 } 02631 /*@=dependenttrans =exposetrans =globstate @*/ 02632 02633 /* XXX psm.c */ 02634 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, uint32_t hdrNum, 02635 /*@unused@*/ rpmts ts) 02636 { 02637 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02638 Header h = NULL; 02639 sigset_t signalMask; 02640 dbiIndex dbi; 02641 size_t dbix; 02642 int rc = RPMRC_FAIL; /* XXX RPMRC */ 02643 int xx; 02644 02645 if (db == NULL) 02646 return RPMRC_OK; /* XXX RPMRC */ 02647 02648 /* Retrieve header for use by associated secondary index callbacks. */ 02649 { rpmmi mi; 02650 mi = rpmmiInit(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum)); 02651 h = rpmmiNext(mi); 02652 if (h) 02653 h = headerLink(h); 02654 mi = rpmmiFree(mi); 02655 } 02656 02657 if (h == NULL) { 02658 rpmlog(RPMLOG_ERR, _("%s: cannot read header at 0x%x\n"), 02659 "rpmdbRemove", (unsigned)hdrNum); 02660 return RPMRC_FAIL; /* XXX RPMRC */ 02661 } 02662 02663 he->tag = RPMTAG_NVRA; 02664 xx = headerGet(h, he, 0); 02665 rpmlog(RPMLOG_DEBUG, " --- h#%8u %s\n", (unsigned)hdrNum, he->p.str); 02666 he->p.ptr = _free(he->p.ptr); 02667 02668 (void) blockSignals(db, &signalMask); 02669 02670 dbix = db->db_ndbi - 1; 02671 if (db->db_tags != NULL) 02672 do { 02673 tagStore_t dbiTag = db->db_tags + dbix; 02674 DBC * dbcursor; 02675 DBT k; 02676 DBT v; 02677 uint32_t ui; 02678 02679 dbi = NULL; 02680 dbcursor = NULL; 02681 (void) memset(&k, 0, sizeof(k)); 02682 (void) memset(&v, 0, sizeof(v)); 02683 (void) memset(he, 0, sizeof(*he)); 02684 he->tag = dbiTag->tag; 02685 02686 switch (he->tag) { 02687 default: 02688 /* Don't bother if tag is not present. */ 02689 if (!headerGet(h, he, 0)) 02690 /*@switchbreak@*/ break; 02691 02692 dbi = dbiOpen(db, he->tag, 0); 02693 if (dbi == NULL) goto exit; 02694 02695 he->p.ptr = _free(he->p.ptr); 02696 /*@switchbreak@*/ break; 02697 case RPMDBI_AVAILABLE: /* Filter out temporary databases */ 02698 case RPMDBI_ADDED: 02699 case RPMDBI_REMOVED: 02700 case RPMDBI_DEPCACHE: 02701 case RPMDBI_SEQNO: 02702 /*@switchbreak@*/ break; 02703 case RPMDBI_PACKAGES: 02704 if (db->db_export != NULL) 02705 xx = db->db_export(db, h, 0); 02706 02707 ui = _hton_ui(hdrNum); 02708 k.data = &ui; 02709 k.size = (UINT32_T) sizeof(ui); 02710 02711 /* New h ref for use by associated secondary index callbacks. */ 02712 db->db_h = headerLink(h); 02713 02714 dbi = dbiOpen(db, he->tag, 0); 02715 if (dbi == NULL) goto exit; 02716 02717 rc = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR); 02718 rc = dbiGet(dbi, dbcursor, &k, &v, DB_SET); 02719 if (!rc) 02720 rc = dbiDel(dbi, dbcursor, &k, &v, 0); 02721 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 02722 02723 /* Unreference db_h used by associated secondary index callbacks. */ 02724 (void) headerFree(db->db_h); 02725 db->db_h = NULL; 02726 02727 if (!dbi->dbi_no_dbsync) 02728 xx = dbiSync(dbi, 0); 02729 02730 /*@switchbreak@*/ break; 02731 } 02732 } while (dbix-- > 0); 02733 02734 /* Unreference header used by associated secondary index callbacks. */ 02735 (void) headerFree(h); 02736 h = NULL; 02737 rc = RPMRC_OK; /* XXX RPMRC */ 02738 02739 exit: 02740 (void) unblockSignals(db, &signalMask); 02741 return rc; 02742 } 02743 02744 /* XXX install.c */ 02745 int rpmdbAdd(rpmdb db, int iid, Header h, /*@unused@*/ rpmts ts) 02746 { 02747 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 02748 sigset_t signalMask; 02749 dbiIndex dbi; 02750 size_t dbix; 02751 uint32_t hdrNum = headerGetInstance(h); 02752 int rc = RPMRC_FAIL; /* XXX RPMRC */ 02753 int xx; 02754 02755 if (db == NULL) 02756 return RPMRC_OK; /* XXX RPMRC */ 02757 02758 if (_rpmdb_debug) 02759 fprintf(stderr, "--> %s(%p, %u, %p, %p) h# %u\n", __FUNCTION__, db, (unsigned)iid, h, ts, (unsigned)hdrNum); 02760 02761 assert(headerIsEntry(h, RPMTAG_REMOVETID) == 0); /* XXX sanity */ 02762 02763 /* Add the install transaction id. */ 02764 if (iid != 0 && iid != -1) { 02765 rpmuint32_t tid[2]; 02766 tid[0] = iid; 02767 tid[1] = 0; 02768 he->tag = RPMTAG_INSTALLTID; 02769 he->t = RPM_UINT32_TYPE; 02770 he->p.ui32p = tid; 02771 he->c = 2; 02772 if (!headerIsEntry(h, he->tag)) 02773 /*@-compmempass@*/ 02774 xx = headerPut(h, he, 0); 02775 /*@=compmempass@*/ 02776 } 02777 02778 /* XXX pubkeys used to set RPMTAG_PACKAGECOLOR here. */ 02779 assert(headerIsEntry(h, RPMTAG_PACKAGECOLOR) != 0); /* XXX sanity */ 02780 02781 (void) blockSignals(db, &signalMask); 02782 02783 /* Assign a primary Packages key for new Header's. */ 02784 if (hdrNum == 0) { 02785 int64_t seqno = 0; 02786 02787 dbi = dbiOpen(db, RPMDBI_SEQNO, 0); 02788 if (dbi == NULL) goto exit; 02789 02790 if ((xx = dbiSeqno(dbi, &seqno, 0)) == 0) { 02791 hdrNum = seqno; 02792 (void) headerSetInstance(h, hdrNum); 02793 } else 02794 goto exit; 02795 } 02796 02797 /* XXX ensure that the header instance is set persistently. */ 02798 if (hdrNum == 0) { 02799 assert(hdrNum > 0); 02800 assert(hdrNum == headerGetInstance(h)); 02801 } 02802 02803 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0); 02804 if (dbi == NULL) goto exit; 02805 02806 dbix = db->db_ndbi - 1; 02807 if (db->db_tags != NULL) 02808 do { 02809 tagStore_t dbiTag = db->db_tags + dbix; 02810 DBC * dbcursor; 02811 DBT k; 02812 DBT v; 02813 uint32_t ui; 02814 02815 dbi = NULL; 02816 dbcursor = NULL; 02817 (void) memset(&k, 0, sizeof(k)); 02818 (void) memset(&v, 0, sizeof(v)); 02819 (void) memset(he, 0, sizeof(*he)); 02820 he->tag = dbiTag->tag; 02821 02822 switch (he->tag) { 02823 default: 02824 /* Don't bother if tag is not present. */ 02825 if (!headerGet(h, he, 0)) 02826 /*@switchbreak@*/ break; 02827 02828 dbi = dbiOpen(db, he->tag, 0); 02829 if (dbi == NULL) goto exit; 02830 02831 he->p.ptr = _free(he->p.ptr); 02832 /*@switchbreak@*/ break; 02833 case RPMDBI_AVAILABLE: /* Filter out temporary databases */ 02834 case RPMDBI_ADDED: 02835 case RPMDBI_REMOVED: 02836 case RPMDBI_DEPCACHE: 02837 case RPMDBI_SEQNO: 02838 /*@switchbreak@*/ break; 02839 case RPMDBI_PACKAGES: 02840 if (db->db_export != NULL) 02841 xx = db->db_export(db, h, 1); 02842 02843 ui = _hton_ui(hdrNum); 02844 k.data = (void *) &ui; 02845 k.size = (UINT32_T) sizeof(ui); 02846 02847 { size_t len = 0; 02848 v.data = headerUnload(h, &len); 02849 assert(v.data != NULL); 02850 v.size = (UINT32_T) len; 02851 } 02852 02853 /* New h ref for use by associated secondary index callbacks. */ 02854 db->db_h = headerLink(h); 02855 02856 dbi = dbiOpen(db, he->tag, 0); 02857 if (dbi == NULL) goto exit; 02858 02859 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR); 02860 xx = dbiPut(dbi, dbcursor, &k, &v, DB_KEYLAST); 02861 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 02862 02863 /* Unreference db_h used by associated secondary index callbacks. */ 02864 (void) headerFree(db->db_h); 02865 db->db_h = NULL; 02866 02867 if (!dbi->dbi_no_dbsync) 02868 xx = dbiSync(dbi, 0); 02869 02870 v.data = _free(v.data); /* headerUnload */ 02871 v.size = 0; 02872 /*@switchbreak@*/ break; 02873 } 02874 02875 } while (dbix-- > 0); 02876 rc = RPMRC_OK; /* XXX RPMRC */ 02877 02878 exit: 02879 (void) unblockSignals(db, &signalMask); 02880 return rc; 02881 }
1.7.5.1