rpm
4.5
|
00001 00005 #include "system.h" 00006 00007 #define _USE_COPY_LOAD /* XXX don't use DB_DBT_MALLOC (yet) */ 00008 00009 #include <sys/file.h> 00010 00011 #include <rpmio.h> 00012 #include <rpmpgp.h> 00013 #include <rpmurl.h> 00014 #include <rpmmacro.h> 00015 #include <rpmsq.h> 00016 00017 #define _RPMEVR_INTERNAL /* XXX isInstallPrereq */ 00018 #include <rpmevr.h> 00019 00020 #define _RPMDB_INTERNAL 00021 #define _MIRE_INTERNAL 00022 #include "rpmdb.h" 00023 #include "fprint.h" 00024 #include "legacy.h" 00025 #include "header_internal.h" /* XXX for HEADERFLAG_ALLOCATED */ 00026 #include "debug.h" 00027 00028 /*@access dbiIndexSet@*/ 00029 /*@access dbiIndexItem@*/ 00030 /*@access rpmts@*/ /* XXX compared with NULL */ 00031 /*@access Header@*/ /* XXX compared with NULL */ 00032 /*@access rpmdbMatchIterator@*/ 00033 00034 /*@unchecked@*/ 00035 int _rpmdb_debug = 0; 00036 00037 /*@unchecked@*/ 00038 static int _rebuildinprogress = 0; 00039 /*@unchecked@*/ 00040 static int _db_filter_dups = 0; 00041 00042 00043 /* Use a path uniquifier in the upper 16 bits of tagNum? */ 00044 /* XXX Note: one cannot just choose a value, rpmdb tagNum's need fixing too */ 00045 #define _DB_TAGGED_FILE_INDICES 1 00046 /*@unchecked@*/ 00047 static int _db_tagged_file_indices = _DB_TAGGED_FILE_INDICES; 00048 00049 #define _DBI_FLAGS 0 00050 #define _DBI_PERMS 0644 00051 #define _DBI_MAJOR -1 00052 00053 /* Bit mask macros. */ 00054 /*@-exporttype@*/ 00055 typedef unsigned int __pbm_bits; 00056 /*@=exporttype@*/ 00057 #define __PBM_NBITS (8 * sizeof (__pbm_bits)) 00058 #define __PBM_IX(d) ((d) / __PBM_NBITS) 00059 #define __PBM_MASK(d) ((__pbm_bits) 1 << (((unsigned)(d)) % __PBM_NBITS)) 00060 /*@-exporttype@*/ 00061 typedef struct { 00062 __pbm_bits bits[1]; 00063 } pbm_set; 00064 /*@=exporttype@*/ 00065 #define __PBM_BITS(set) ((set)->bits) 00066 00067 #define PBM_FREE(s) _free(s); 00068 #define PBM_SET(d, s) (__PBM_BITS (s)[__PBM_IX (d)] |= __PBM_MASK (d)) 00069 #define PBM_CLR(d, s) (__PBM_BITS (s)[__PBM_IX (d)] &= ~__PBM_MASK (d)) 00070 #define PBM_ISSET(d, s) ((__PBM_BITS (s)[__PBM_IX (d)] & __PBM_MASK (d)) != 0) 00071 00072 #define PBM_ALLOC(d) xcalloc(__PBM_IX (d) + 1, sizeof(__pbm_bits)) 00073 00080 /*@unused@*/ 00081 static inline pbm_set * PBM_REALLOC(pbm_set ** sp, int * odp, int nd) 00082 /*@modifies *sp, *odp @*/ 00083 { 00084 int i, nb; 00085 00086 /*@-bounds -sizeoftype@*/ 00087 if (nd > (*odp)) { 00088 nd *= 2; 00089 nb = __PBM_IX(nd) + 1; 00090 /*@-unqualifiedtrans@*/ 00091 *sp = xrealloc(*sp, nb * sizeof(__pbm_bits)); 00092 /*@=unqualifiedtrans@*/ 00093 for (i = __PBM_IX(*odp) + 1; i < nb; i++) 00094 __PBM_BITS(*sp)[i] = 0; 00095 *odp = nd; 00096 } 00097 /*@=bounds =sizeoftype@*/ 00098 /*@-compdef -retalias -usereleased@*/ 00099 return *sp; 00100 /*@=compdef =retalias =usereleased@*/ 00101 } 00102 00108 static inline unsigned char nibble(char c) 00109 /*@*/ 00110 { 00111 if (c >= '0' && c <= '9') 00112 return (c - '0'); 00113 if (c >= 'A' && c <= 'F') 00114 return (c - 'A') + 10; 00115 if (c >= 'a' && c <= 'f') 00116 return (c - 'a') + 10; 00117 return 0; 00118 } 00119 00120 #ifdef DYING 00121 00127 static int printable(const void * ptr, size_t len) /*@*/ 00128 { 00129 const char * s = ptr; 00130 int i; 00131 for (i = 0; i < len; i++, s++) 00132 if (!(*s >= ' ' && *s <= '~')) return 0; 00133 return 1; 00134 } 00135 #endif 00136 00143 static int dbiTagToDbix(rpmdb db, int rpmtag) 00144 /*@*/ 00145 { 00146 int dbix; 00147 00148 if (db->db_tagn != NULL) 00149 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00150 /*@-boundsread@*/ 00151 if (rpmtag != db->db_tagn[dbix]) 00152 continue; 00153 return dbix; 00154 /*@=boundsread@*/ 00155 } 00156 return -1; 00157 } 00158 00162 /*@-exportheader@*/ 00163 static void dbiTagsInit(/*@null@*/int ** dbiTagsP, /*@null@*/int * dbiTagsMaxP) 00164 /*@globals rpmGlobalMacroContext, h_errno @*/ 00165 /*@modifies dbiTagsP, dbiTagsMaxP, rpmGlobalMacroContext @*/ 00166 { 00167 /*@observer@*/ 00168 static const char * const _dbiTagStr_default = 00169 "Packages:Name:Basenames:Group:Requirename:Providename:Conflictname:Triggername:Dirnames:Requireversion:Provideversion:Installtid:Sigmd5:Sha1header:Filemd5s:Depends:Pubkeys"; 00170 int * dbiTags = NULL; 00171 int dbiTagsMax = 0; 00172 char * dbiTagStr = NULL; 00173 char * o, * oe; 00174 int dbix, rpmtag, bingo; 00175 00176 dbiTagStr = rpmExpand("%{?_dbi_tags}", NULL); 00177 if (!(dbiTagStr && *dbiTagStr)) { 00178 dbiTagStr = _free(dbiTagStr); 00179 dbiTagStr = xstrdup(_dbiTagStr_default); 00180 } 00181 00182 /* Always allocate package index */ 00183 dbiTags = xcalloc(1, sizeof(*dbiTags)); 00184 dbiTags[dbiTagsMax++] = RPMDBI_PACKAGES; 00185 00186 for (o = dbiTagStr; o && *o; o = oe) { 00187 while (*o && xisspace(*o)) 00188 o++; 00189 if (*o == '\0') 00190 break; 00191 for (oe = o; oe && *oe; oe++) { 00192 if (xisspace(*oe)) 00193 /*@innerbreak@*/ break; 00194 if (oe[0] == ':' && !(oe[1] == '/' && oe[2] == '/')) 00195 /*@innerbreak@*/ break; 00196 } 00197 if (oe && *oe) 00198 *oe++ = '\0'; 00199 rpmtag = tagValue(o); 00200 if (rpmtag < 0) { 00201 rpmMessage(RPMMESS_WARNING, 00202 _("dbiTagsInit: unrecognized tag name: \"%s\" ignored\n"), o); 00203 continue; 00204 } 00205 00206 bingo = 0; 00207 if (dbiTags != NULL) 00208 for (dbix = 0; dbix < dbiTagsMax; dbix++) { 00209 /*@-boundsread@*/ 00210 if (rpmtag == dbiTags[dbix]) { 00211 bingo = 1; 00212 /*@innerbreak@*/ break; 00213 } 00214 /*@=boundsread@*/ 00215 } 00216 if (bingo) 00217 continue; 00218 00219 dbiTags = xrealloc(dbiTags, (dbiTagsMax + 1) * sizeof(*dbiTags)); /* XXX memory leak */ 00220 dbiTags[dbiTagsMax++] = rpmtag; 00221 } 00222 00223 if (dbiTagsMaxP != NULL) 00224 *dbiTagsMaxP = dbiTagsMax; 00225 /*@-branchstate@*/ 00226 if (dbiTagsP != NULL) 00227 *dbiTagsP = dbiTags; 00228 else 00229 dbiTags = _free(dbiTags); 00230 /*@=branchstate@*/ 00231 dbiTagStr = _free(dbiTagStr); 00232 } 00233 /*@=exportheader@*/ 00234 00235 /*@-redecl@*/ 00236 #define DB1vec NULL 00237 #define DB2vec NULL 00238 00239 #ifdef HAVE_DB3_DB_H 00240 /*@-exportheadervar -declundef @*/ 00241 /*@observer@*/ /*@unchecked@*/ 00242 extern struct _dbiVec db3vec; 00243 /*@=exportheadervar =declundef @*/ 00244 #define DB3vec &db3vec 00245 /*@=redecl@*/ 00246 #else 00247 #define DB3vec NULL 00248 #endif 00249 00250 #ifdef HAVE_SQLITE3_H 00251 #define SQLITE_HACK 00252 /*@-exportheadervar -declundef @*/ 00253 /*@observer@*/ /*@unchecked@*/ 00254 extern struct _dbiVec sqlitevec; 00255 /*@=exportheadervar =declundef @*/ 00256 #define SQLITEvec &sqlitevec 00257 /*@=redecl@*/ 00258 #else 00259 #define SQLITEvec NULL 00260 #endif 00261 00262 /*@-nullassign@*/ 00263 /*@observer@*/ /*@unchecked@*/ 00264 static struct _dbiVec *mydbvecs[] = { 00265 DB1vec, DB1vec, DB2vec, DB3vec, SQLITEvec, NULL 00266 }; 00267 /*@=nullassign@*/ 00268 00269 00275 static const char * mapTagName(int value) 00276 /*@*/ 00277 { 00278 const char * s = tagName(value); 00279 if (s == NULL) 00280 s = ""; 00281 else if (!strcmp(s, "Filedigests")) 00282 s = "Filemd5s"; 00283 return s; 00284 } 00285 00286 dbiIndex dbiOpen(rpmdb db, rpmTag rpmtag, /*@unused@*/ unsigned int flags) 00287 { 00288 int dbix; 00289 dbiIndex dbi = NULL; 00290 int _dbapi, _dbapi_rebuild, _dbapi_wanted; 00291 int rc = 0; 00292 00293 /*@-modfilesys@*/ 00294 if (_rpmdb_debug) 00295 fprintf(stderr, "==> %s(%p, %s, 0x%x)\n", __FUNCTION__, db, mapTagName(rpmtag), flags); 00296 /*@=modfilesys@*/ 00297 00298 if (db == NULL) 00299 return NULL; 00300 00301 dbix = dbiTagToDbix(db, rpmtag); 00302 if (dbix < 0 || dbix >= db->db_ndbi) 00303 return NULL; 00304 00305 /* Is this index already open ? */ 00306 /*@-compdef@*/ /* FIX: db->_dbi may be NULL */ 00307 if (db->_dbi != NULL && (dbi = db->_dbi[dbix]) != NULL) 00308 return dbi; 00309 /*@=compdef@*/ 00310 00311 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}"); 00312 if (_dbapi_rebuild < 1 || _dbapi_rebuild > 4) 00313 _dbapi_rebuild = 4; 00314 /* _dbapi_wanted = (_rebuildinprogress ? -1 : db->db_api); */ 00315 _dbapi_wanted = (_rebuildinprogress ? _dbapi_rebuild : db->db_api); 00316 00317 switch (_dbapi_wanted) { 00318 default: 00319 _dbapi = _dbapi_wanted; 00320 if (_dbapi < 0 || _dbapi >= 5 || mydbvecs[_dbapi] == NULL) { 00321 rpmMessage(RPMMESS_DEBUG, D_("dbiOpen: _dbiapi failed\n")); 00322 return NULL; 00323 } 00324 errno = 0; 00325 dbi = NULL; 00326 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi); 00327 if (rc) { 00328 static int _printed[32]; 00329 if (!_printed[dbix & 0x1f]++) 00330 rpmError(RPMERR_DBOPEN, 00331 _("cannot open %s index using db%d - %s (%d)\n"), 00332 mapTagName(rpmtag), _dbapi, 00333 (rc > 0 ? strerror(rc) : ""), rc); 00334 _dbapi = -1; 00335 } 00336 break; 00337 case -1: 00338 _dbapi = 5; 00339 while (_dbapi-- > 1) { 00340 if (mydbvecs[_dbapi] == NULL) 00341 continue; 00342 errno = 0; 00343 dbi = NULL; 00344 rc = (*mydbvecs[_dbapi]->open) (db, rpmtag, &dbi); 00345 if (rc == 0 && dbi) 00346 /*@loopbreak@*/ break; 00347 } 00348 if (_dbapi <= 0) { 00349 static int _printed[32]; 00350 if (!_printed[dbix & 0x1f]++) 00351 rpmError(RPMERR_DBOPEN, _("cannot open %s index\n"), 00352 mapTagName(rpmtag)); 00353 rc = 1; 00354 goto exit; 00355 } 00356 if (db->db_api == -1 && _dbapi > 0) 00357 db->db_api = _dbapi; 00358 break; 00359 } 00360 00361 exit: 00362 if (dbi != NULL && rc == 0) { 00363 if (db->_dbi != NULL) 00364 db->_dbi[dbix] = dbi; 00365 /*@-sizeoftype@*/ 00366 if (rpmtag == RPMDBI_PACKAGES && db->db_bits == NULL) { 00367 db->db_nbits = 1024; 00368 if (!dbiStat(dbi, DB_FAST_STAT)) { 00369 DB_HASH_STAT * hash = (DB_HASH_STAT *)dbi->dbi_stats; 00370 if (hash) 00371 db->db_nbits += hash->hash_nkeys; 00372 } 00373 db->db_bits = PBM_ALLOC(db->db_nbits); 00374 } 00375 /*@=sizeoftype@*/ 00376 } 00377 #ifdef HAVE_DB3_DB_H 00378 else 00379 dbi = db3Free(dbi); 00380 #endif 00381 00382 /*@-compdef -nullstate@*/ /* FIX: db->_dbi may be NULL */ 00383 return dbi; 00384 /*@=compdef =nullstate@*/ 00385 } 00386 00393 static dbiIndexItem dbiIndexNewItem(unsigned int hdrNum, unsigned int tagNum) 00394 /*@*/ 00395 { 00396 dbiIndexItem rec = xcalloc(1, sizeof(*rec)); 00397 rec->hdrNum = hdrNum; 00398 rec->tagNum = tagNum; 00399 return rec; 00400 } 00401 00402 union _dbswap { 00403 uint32_t ui; 00404 unsigned char uc[4]; 00405 }; 00406 00407 #define _DBSWAP(_a) \ 00408 /*@-bounds@*/ \ 00409 { unsigned char _b, *_c = (_a).uc; \ 00410 _b = _c[3]; _c[3] = _c[0]; _c[0] = _b; \ 00411 _b = _c[2]; _c[2] = _c[1]; _c[1] = _b; \ 00412 /*@=bounds@*/ \ 00413 } 00414 00422 static int dbt2set(dbiIndex dbi, DBT * data, /*@out@*/ dbiIndexSet * setp) 00423 /*@modifies dbi, *setp @*/ 00424 { 00425 int _dbbyteswapped; 00426 const char * sdbir; 00427 dbiIndexSet set; 00428 int i; 00429 00430 if (dbi == NULL || data == NULL || setp == NULL) 00431 return -1; 00432 _dbbyteswapped = dbiByteSwapped(dbi); 00433 00434 if ((sdbir = data->data) == NULL) { 00435 *setp = NULL; 00436 return 0; 00437 } 00438 00439 set = xmalloc(sizeof(*set)); 00440 set->count = data->size / dbi->dbi_jlen; 00441 set->recs = xmalloc(set->count * sizeof(*(set->recs))); 00442 00443 /*@-bounds -sizeoftype @*/ 00444 switch (dbi->dbi_jlen) { 00445 default: 00446 case 2*sizeof(int_32): 00447 for (i = 0; i < set->count; i++) { 00448 union _dbswap hdrNum, tagNum; 00449 00450 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui)); 00451 sdbir += sizeof(hdrNum.ui); 00452 memcpy(&tagNum.ui, sdbir, sizeof(tagNum.ui)); 00453 sdbir += sizeof(tagNum.ui); 00454 if (_dbbyteswapped) { 00455 _DBSWAP(hdrNum); 00456 _DBSWAP(tagNum); 00457 } 00458 set->recs[i].hdrNum = hdrNum.ui; 00459 set->recs[i].tagNum = tagNum.ui; 00460 set->recs[i].fpNum = 0; 00461 } 00462 break; 00463 case 1*sizeof(int_32): 00464 for (i = 0; i < set->count; i++) { 00465 union _dbswap hdrNum; 00466 00467 memcpy(&hdrNum.ui, sdbir, sizeof(hdrNum.ui)); 00468 sdbir += sizeof(hdrNum.ui); 00469 if (_dbbyteswapped) { 00470 _DBSWAP(hdrNum); 00471 } 00472 set->recs[i].hdrNum = hdrNum.ui; 00473 set->recs[i].tagNum = 0; 00474 set->recs[i].fpNum = 0; 00475 } 00476 break; 00477 } 00478 *setp = set; 00479 /*@=bounds =sizeoftype @*/ 00480 /*@-compdef@*/ 00481 return 0; 00482 /*@=compdef@*/ 00483 } 00484 00492 static int set2dbt(dbiIndex dbi, DBT * data, dbiIndexSet set) 00493 /*@modifies dbi, *data @*/ 00494 { 00495 int _dbbyteswapped; 00496 char * tdbir; 00497 int i; 00498 00499 if (dbi == NULL || data == NULL || set == NULL) 00500 return -1; 00501 _dbbyteswapped = dbiByteSwapped(dbi); 00502 00503 data->size = set->count * (dbi->dbi_jlen); 00504 if (data->size == 0) { 00505 data->data = NULL; 00506 return 0; 00507 } 00508 tdbir = data->data = xmalloc(data->size); 00509 00510 /*@-bounds -sizeoftype@*/ 00511 switch (dbi->dbi_jlen) { 00512 default: 00513 case 2*sizeof(int_32): 00514 for (i = 0; i < set->count; i++) { 00515 union _dbswap hdrNum, tagNum; 00516 00517 memset(&hdrNum, 0, sizeof(hdrNum)); 00518 memset(&tagNum, 0, sizeof(tagNum)); 00519 hdrNum.ui = set->recs[i].hdrNum; 00520 tagNum.ui = set->recs[i].tagNum; 00521 if (_dbbyteswapped) { 00522 _DBSWAP(hdrNum); 00523 _DBSWAP(tagNum); 00524 } 00525 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui)); 00526 tdbir += sizeof(hdrNum.ui); 00527 memcpy(tdbir, &tagNum.ui, sizeof(tagNum.ui)); 00528 tdbir += sizeof(tagNum.ui); 00529 } 00530 break; 00531 case 1*sizeof(int_32): 00532 for (i = 0; i < set->count; i++) { 00533 union _dbswap hdrNum; 00534 00535 memset(&hdrNum, 0, sizeof(hdrNum)); 00536 hdrNum.ui = set->recs[i].hdrNum; 00537 if (_dbbyteswapped) { 00538 _DBSWAP(hdrNum); 00539 } 00540 memcpy(tdbir, &hdrNum.ui, sizeof(hdrNum.ui)); 00541 tdbir += sizeof(hdrNum.ui); 00542 } 00543 break; 00544 } 00545 /*@=bounds =sizeoftype@*/ 00546 00547 /*@-compdef@*/ 00548 return 0; 00549 /*@=compdef@*/ 00550 } 00551 00552 /* XXX assumes hdrNum is first int in dbiIndexItem */ 00553 static int hdrNumCmp(const void * one, const void * two) 00554 /*@*/ 00555 { 00556 const int * a = one, * b = two; 00557 return (*a - *b); 00558 } 00559 00569 static int dbiAppendSet(dbiIndexSet set, const void * recs, 00570 int nrecs, size_t recsize, int sortset) 00571 /*@modifies *set @*/ 00572 { 00573 const char * rptr = recs; 00574 size_t rlen = (recsize < sizeof(*(set->recs))) 00575 ? recsize : sizeof(*(set->recs)); 00576 00577 if (set == NULL || recs == NULL || nrecs <= 0 || recsize == 0) 00578 return 1; 00579 00580 set->recs = xrealloc(set->recs, 00581 (set->count + nrecs) * sizeof(*(set->recs))); 00582 00583 memset(set->recs + set->count, 0, nrecs * sizeof(*(set->recs))); 00584 00585 while (nrecs-- > 0) { 00586 /*@-mayaliasunique@*/ 00587 memcpy(set->recs + set->count, rptr, rlen); 00588 /*@=mayaliasunique@*/ 00589 rptr += recsize; 00590 set->count++; 00591 } 00592 00593 if (sortset && set->count > 1) 00594 qsort(set->recs, set->count, sizeof(*(set->recs)), hdrNumCmp); 00595 00596 return 0; 00597 } 00598 00608 static int dbiPruneSet(dbiIndexSet set, void * recs, int nrecs, 00609 size_t recsize, int sorted) 00610 /*@modifies set, recs @*/ 00611 { 00612 int from; 00613 int to = 0; 00614 int num = set->count; 00615 int numCopied = 0; 00616 00617 assert(set->count > 0); 00618 if (nrecs > 1 && !sorted) 00619 qsort(recs, nrecs, recsize, hdrNumCmp); 00620 00621 for (from = 0; from < num; from++) { 00622 if (bsearch(&set->recs[from], recs, nrecs, recsize, hdrNumCmp)) { 00623 set->count--; 00624 continue; 00625 } 00626 if (from != to) 00627 set->recs[to] = set->recs[from]; /* structure assignment */ 00628 to++; 00629 numCopied++; 00630 } 00631 return (numCopied == num); 00632 } 00633 00634 /* XXX transaction.c */ 00635 unsigned int dbiIndexSetCount(dbiIndexSet set) { 00636 return set->count; 00637 } 00638 00639 /* XXX transaction.c */ 00640 unsigned int dbiIndexRecordOffset(dbiIndexSet set, int recno) { 00641 return set->recs[recno].hdrNum; 00642 } 00643 00644 /* XXX transaction.c */ 00645 unsigned int dbiIndexRecordFileNumber(dbiIndexSet set, int recno) { 00646 return set->recs[recno].tagNum; 00647 } 00648 00649 /* XXX transaction.c */ 00650 dbiIndexSet dbiFreeIndexSet(dbiIndexSet set) { 00651 if (set) { 00652 set->recs = _free(set->recs); 00653 set = _free(set); 00654 } 00655 return set; 00656 } 00657 00658 struct _rpmdbMatchIterator { 00659 /*@dependent@*/ /*@null@*/ 00660 rpmdbMatchIterator mi_next; 00661 /*@only@*/ 00662 const void * mi_keyp; 00663 size_t mi_keylen; 00664 /*@refcounted@*/ 00665 rpmdb mi_db; 00666 rpmTag mi_rpmtag; 00667 dbiIndexSet mi_set; 00668 DBC * mi_dbc; 00669 DBT mi_key; 00670 DBT mi_data; 00671 int mi_setx; 00672 /*@refcounted@*/ /*@null@*/ 00673 Header mi_h; 00674 int mi_sorted; 00675 int mi_cflags; 00676 int mi_modified; 00677 unsigned int mi_prevoffset; /* header instance (native endian) */ 00678 unsigned int mi_offset; /* header instance (native endian) */ 00679 unsigned int mi_filenum; /* tag element (native endian) */ 00680 int mi_nre; 00681 /*@only@*/ /*@null@*/ 00682 miRE mi_re; 00683 /*@null@*/ 00684 rpmts mi_ts; 00685 /*@null@*/ 00686 rpmRC (*mi_hdrchk) (rpmts ts, const void * uh, size_t uc, const char ** msg) 00687 /*@modifies ts, *msg @*/; 00688 00689 }; 00690 00691 /*@unchecked@*/ 00692 static rpmdb rpmdbRock; 00693 00694 /*@unchecked@*/ /*@exposed@*/ /*@null@*/ 00695 static rpmdbMatchIterator rpmmiRock; 00696 00697 int rpmdbCheckTerminate(int terminate) 00698 /*@globals rpmdbRock, rpmmiRock @*/ 00699 /*@modifies rpmdbRock, rpmmiRock @*/ 00700 { 00701 sigset_t newMask, oldMask; 00702 static int terminating = 0; 00703 00704 if (terminating) return 1; 00705 00706 (void) sigfillset(&newMask); /* block all signals */ 00707 (void) sigprocmask(SIG_BLOCK, &newMask, &oldMask); 00708 00709 if (sigismember(&rpmsqCaught, SIGINT) 00710 || sigismember(&rpmsqCaught, SIGQUIT) 00711 || sigismember(&rpmsqCaught, SIGHUP) 00712 || sigismember(&rpmsqCaught, SIGTERM) 00713 || sigismember(&rpmsqCaught, SIGPIPE) 00714 || terminate) 00715 terminating = 1; 00716 00717 if (terminating) { 00718 rpmdb db; 00719 rpmdbMatchIterator mi; 00720 00721 /*@-branchstate@*/ 00722 while ((mi = rpmmiRock) != NULL) { 00723 /*@i@*/ rpmmiRock = mi->mi_next; 00724 mi->mi_next = NULL; 00725 /*@i@*/ mi = rpmdbFreeIterator(mi); 00726 } 00727 /*@=branchstate@*/ 00728 00729 /*@-newreftrans@*/ 00730 while ((db = rpmdbRock) != NULL) { 00731 /*@i@*/ rpmdbRock = db->db_next; 00732 db->db_next = NULL; 00733 (void) rpmdbClose(db); 00734 } 00735 /*@=newreftrans@*/ 00736 } 00737 (void) sigprocmask(SIG_SETMASK, &oldMask, NULL); 00738 return terminating; 00739 } 00740 00741 int rpmdbCheckSignals(void) 00742 /*@globals rpmdbRock, rpmmiRock @*/ 00743 /*@modifies rpmdbRock, rpmmiRock @*/ 00744 { 00745 00746 if (rpmdbCheckTerminate(0)) { 00747 /*@-abstract@*/ /* sigset_t is abstract type */ 00748 rpmMessage(RPMMESS_DEBUG, D_("Exiting on signal(0x%lx) ...\n"), *((unsigned long *)&rpmsqCaught)); 00749 /*@=abstract@*/ 00750 exit(EXIT_FAILURE); 00751 } 00752 return 0; 00753 00754 } 00755 00762 static int blockSignals(/*@unused@*/ rpmdb db, /*@out@*/ sigset_t * oldMask) 00763 /*@globals fileSystem @*/ 00764 /*@modifies *oldMask, fileSystem @*/ 00765 { 00766 sigset_t newMask; 00767 00768 (void) sigfillset(&newMask); /* block all signals */ 00769 (void) sigprocmask(SIG_BLOCK, &newMask, oldMask); 00770 (void) sigdelset(&newMask, SIGINT); 00771 (void) sigdelset(&newMask, SIGQUIT); 00772 (void) sigdelset(&newMask, SIGHUP); 00773 (void) sigdelset(&newMask, SIGTERM); 00774 (void) sigdelset(&newMask, SIGPIPE); 00775 return sigprocmask(SIG_BLOCK, &newMask, NULL); 00776 } 00777 00784 /*@mayexit@*/ 00785 static int unblockSignals(/*@unused@*/ rpmdb db, sigset_t * oldMask) 00786 /*@globals rpmdbRock, fileSystem, internalState @*/ 00787 /*@modifies rpmdbRock, fileSystem, internalState @*/ 00788 { 00789 (void) rpmdbCheckSignals(); 00790 return sigprocmask(SIG_SETMASK, oldMask, NULL); 00791 } 00792 00800 static inline /*@null@*/ const char * queryHeader(Header h, const char * qfmt) 00801 /*@globals headerDefaultFormats @*/ 00802 { 00803 static const struct headerSprintfExtension_s * hdrfmts = headerDefaultFormats; 00804 const char * errstr = "(unkown error)"; 00805 const char * str; 00806 00807 /*@-modobserver@*/ 00808 str = headerSprintf(h, qfmt, rpmTagTable, hdrfmts, &errstr); 00809 /*@=modobserver@*/ 00810 if (str == NULL) 00811 rpmError(RPMERR_QFMT, _("incorrect format: \"%s\": %s\n"), qfmt, errstr); 00812 return str; 00813 } 00814 00822 static int rpmdbExportInfo(/*@unused@*/ rpmdb db, Header h, int adding) 00823 /*@globals headerDefaultFormats, rpmGlobalMacroContext, h_errno, 00824 fileSystem, internalState @*/ 00825 /*@modifies rpmGlobalMacroContext, 00826 fileSystem, internalState @*/ 00827 { 00828 const char * fn = NULL; 00829 int xx; 00830 00831 /*@-branchstate@*/ 00832 { const char * fnfmt = rpmGetPath("%{?_hrmib_path}", NULL); 00833 if (fnfmt && *fnfmt) 00834 fn = queryHeader(h, fnfmt); 00835 fnfmt = _free(fnfmt); 00836 } 00837 /*@=branchstate@*/ 00838 00839 if (fn == NULL) 00840 goto exit; 00841 00842 if (adding) { 00843 FD_t fd = Fopen(fn, "w"); 00844 int_32 *iidp; 00845 00846 if (fd != NULL) { 00847 xx = Fclose(fd); 00848 fd = NULL; 00849 if (headerGetEntry(h, RPMTAG_INSTALLTIME, NULL, &iidp, NULL)) { 00850 struct utimbuf stamp; 00851 stamp.actime = *iidp; 00852 stamp.modtime = *iidp; 00853 if (!Utime(fn, &stamp)) 00854 rpmMessage(RPMMESS_DEBUG, " +++ %s\n", fn); 00855 } 00856 } 00857 } else { 00858 if (!Unlink(fn)) 00859 rpmMessage(RPMMESS_DEBUG, " --- %s\n", fn); 00860 } 00861 00862 exit: 00863 fn = _free(fn); 00864 return 0; 00865 } 00866 00867 #define _DB_ROOT "/" 00868 #define _DB_HOME "%{?_dbpath}" 00869 #define _DB_FLAGS 0 00870 #define _DB_MODE 0 00871 #define _DB_PERMS 0644 00872 00873 #define _DB_MAJOR -1 00874 #define _DB_ERRPFX "rpmdb" 00875 00876 /*@-fullinitblock@*/ 00877 /*@observer@*/ /*@unchecked@*/ 00878 static struct rpmdb_s dbTemplate = { 00879 _DB_ROOT, _DB_HOME, _DB_FLAGS, _DB_MODE, _DB_PERMS, 00880 _DB_MAJOR, _DB_ERRPFX 00881 }; 00882 /*@=fullinitblock@*/ 00883 00884 int rpmdbOpenAll(rpmdb db) 00885 { 00886 int dbix; 00887 int rc = 0; 00888 00889 if (db == NULL) return -2; 00890 00891 if (db->db_tagn != NULL && db->_dbi != NULL) 00892 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00893 if (db->db_tagn[dbix] < 0) 00894 continue; 00895 if (db->_dbi[dbix] != NULL) 00896 continue; 00897 switch ((db->db_tagn[dbix])) { 00898 case RPMDBI_AVAILABLE: 00899 case RPMDBI_ADDED: 00900 case RPMDBI_REMOVED: 00901 case RPMDBI_DEPENDS: 00902 continue; 00903 /*@notreached@*/ /*@switchbreak@*/ break; 00904 default: 00905 /*@switchbreak@*/ break; 00906 } 00907 (void) dbiOpen(db, db->db_tagn[dbix], db->db_flags); 00908 } 00909 return rc; 00910 } 00911 00912 int rpmdbBlockDBI(rpmdb db, int rpmtag) 00913 { 00914 int tagn = (rpmtag >= 0 ? rpmtag : -rpmtag); 00915 int dbix; 00916 00917 if (db == NULL || db->_dbi == NULL) 00918 return 0; 00919 00920 if (db->db_tagn != NULL) 00921 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00922 if (db->db_tagn[dbix] != tagn) 00923 continue; 00924 db->db_tagn[dbix] = rpmtag; 00925 return 0; 00926 } 00927 return 0; 00928 } 00929 00930 int rpmdbCloseDBI(rpmdb db, int rpmtag) 00931 { 00932 int dbix; 00933 int rc = 0; 00934 00935 if (db == NULL || db->_dbi == NULL) 00936 return 0; 00937 00938 if (db->db_tagn != NULL) 00939 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 00940 if (db->db_tagn[dbix] != rpmtag) 00941 continue; 00942 /*@-boundswrite@*/ 00943 if (db->_dbi[dbix] != NULL) { 00944 int xx; 00945 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00946 xx = dbiClose(db->_dbi[dbix], 0); 00947 if (xx && rc == 0) rc = xx; 00948 db->_dbi[dbix] = NULL; 00949 /*@=unqualifiedtrans@*/ 00950 } 00951 /*@=boundswrite@*/ 00952 break; 00953 } 00954 return rc; 00955 } 00956 00957 /* XXX query.c, rpminstall.c, verify.c */ 00958 /*@-incondefs@*/ 00959 int rpmdbClose(rpmdb db) 00960 /*@globals rpmdbRock @*/ 00961 /*@modifies rpmdbRock @*/ 00962 { 00963 rpmdb * prev, next; 00964 int dbix; 00965 int rc = 0; 00966 00967 if (db == NULL) 00968 goto exit; 00969 00970 (void) rpmdbUnlink(db, "rpmdbClose"); 00971 00972 /*@-usereleased@*/ 00973 if (db->nrefs > 0) 00974 goto exit; 00975 00976 if (db->_dbi) 00977 for (dbix = db->db_ndbi; --dbix >= 0; ) { 00978 int xx; 00979 if (db->_dbi[dbix] == NULL) 00980 continue; 00981 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 00982 xx = dbiClose(db->_dbi[dbix], 0); 00983 if (xx && rc == 0) rc = xx; 00984 db->_dbi[dbix] = NULL; 00985 /*@=unqualifiedtrans@*/ 00986 } 00987 db->db_errpfx = _free(db->db_errpfx); 00988 db->db_root = _free(db->db_root); 00989 db->db_home = _free(db->db_home); 00990 db->db_bits = PBM_FREE(db->db_bits); 00991 db->db_tagn = _free(db->db_tagn); 00992 db->_dbi = _free(db->_dbi); 00993 db->db_ndbi = 0; 00994 00995 /*@-newreftrans@*/ 00996 prev = &rpmdbRock; 00997 while ((next = *prev) != NULL && next != db) 00998 prev = &next->db_next; 00999 if (next) { 01000 /*@i@*/ *prev = next->db_next; 01001 next->db_next = NULL; 01002 } 01003 /*@=newreftrans@*/ 01004 01005 /*@-refcounttrans@*/ db = _free(db); /*@=refcounttrans@*/ 01006 /*@=usereleased@*/ 01007 01008 exit: 01009 (void) rpmsqEnable(-SIGHUP, NULL); 01010 (void) rpmsqEnable(-SIGINT, NULL); 01011 (void) rpmsqEnable(-SIGTERM,NULL); 01012 (void) rpmsqEnable(-SIGQUIT,NULL); 01013 (void) rpmsqEnable(-SIGPIPE,NULL); 01014 return rc; 01015 } 01016 /*@=incondefs@*/ 01017 01018 int rpmdbSync(rpmdb db) 01019 { 01020 int dbix; 01021 int rc = 0; 01022 01023 if (db == NULL) return 0; 01024 if (db->_dbi != NULL) 01025 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 01026 int xx; 01027 if (db->_dbi[dbix] == NULL) 01028 continue; 01029 if (db->_dbi[dbix]->dbi_no_dbsync) 01030 continue; 01031 xx = dbiSync(db->_dbi[dbix], 0); 01032 if (xx && rc == 0) rc = xx; 01033 } 01034 return rc; 01035 } 01036 01042 static const char * rpmdbURIPath(const char *uri) 01043 /*@globals rpmGlobalMacroContext, h_errno @*/ 01044 /*@modifies rpmGlobalMacroContext @*/ 01045 { 01046 const char * s = rpmGetPath(uri, NULL); 01047 const char * fn = NULL; 01048 urltype ut = urlPath(s, &fn); 01049 01050 /*@-branchstate@*/ 01051 switch (ut) { 01052 case URL_IS_PATH: 01053 case URL_IS_UNKNOWN: 01054 fn = s; 01055 s = NULL; 01056 break; 01057 case URL_IS_HTTPS: 01058 case URL_IS_HTTP: 01059 case URL_IS_FTP: 01060 case URL_IS_HKP: 01061 case URL_IS_DASH: 01062 default: 01063 /* HACK: strip the URI prefix for these schemes. */ 01064 fn = rpmGetPath(fn, NULL); 01065 break; 01066 } 01067 /*@=branchstate@*/ 01068 01069 /* Convert relative to absolute paths. */ 01070 if (ut != URL_IS_PATH) /* XXX permit file:///... URI's */ 01071 if (fn && *fn && *fn != '/') { 01072 char dn[PATH_MAX]; 01073 char *t; 01074 dn[0] = '\0'; 01075 if ((t = realpath(".", dn)) != NULL) { 01076 t += strlen(dn); 01077 if (t > dn && t[-1] != '/') 01078 *t++ = '/'; 01079 t = stpncpy(t, fn, (sizeof(dn) - (t - dn))); 01080 *t = '\0'; 01081 fn = _free(fn); 01082 fn = rpmGetPath(dn, NULL); 01083 } 01084 } 01085 01086 s = _free(s); 01087 assert(fn != NULL); 01088 return fn; 01089 } 01090 01091 /*@-exportheader@*/ 01092 /*@-mods@*/ /* FIX: dbTemplate structure assignment */ 01093 /*@only@*/ /*@null@*/ 01094 rpmdb rpmdbNew(/*@kept@*/ /*@null@*/ const char * root, 01095 /*@kept@*/ /*@null@*/ const char * home, 01096 int mode, int perms, int flags) 01097 /*@globals _db_filter_dups, rpmGlobalMacroContext, h_errno @*/ 01098 /*@modifies _db_filter_dups, rpmGlobalMacroContext @*/ 01099 { 01100 rpmdb db = xcalloc(sizeof(*db), 1); 01101 const char * epfx = _DB_ERRPFX; 01102 static int oneshot = 0; 01103 01104 /*@-modfilesys@*/ /*@-nullpass@*/ 01105 if (_rpmdb_debug) 01106 fprintf(stderr, "==> %s(%s, %s, 0x%x, 0%o, 0x%x) db %p\n", __FUNCTION__, root, home, mode, perms, flags, db); 01107 /*@=modfilesys@*/ /*@=nullpass@*/ 01108 01109 if (!oneshot) { 01110 _db_filter_dups = rpmExpandNumeric("%{_filterdbdups}"); 01111 oneshot = 1; 01112 } 01113 01114 /*@-boundswrite@*/ 01115 /*@-assignexpose@*/ 01116 *db = dbTemplate; /* structure assignment */ 01117 /*@=assignexpose@*/ 01118 /*@=boundswrite@*/ 01119 01120 db->_dbi = NULL; 01121 01122 if (!(perms & 0600)) perms = 0644; /* XXX sanity */ 01123 01124 if (mode >= 0) db->db_mode = mode; 01125 if (perms >= 0) db->db_perms = perms; 01126 if (flags >= 0) db->db_flags = flags; 01127 01128 db->db_root = rpmdbURIPath( (root && *root ? root : _DB_ROOT) ); 01129 db->db_home = rpmdbURIPath( (home && *home ? home : _DB_HOME) ); 01130 01131 if (!(db->db_home && db->db_home[0])) { 01132 rpmError(RPMERR_DBOPEN, _("no dbpath has been set\n")); 01133 db->db_root = _free(db->db_root); 01134 db->db_home = _free(db->db_home); 01135 db = _free(db); 01136 /*@-globstate@*/ return NULL; /*@=globstate@*/ 01137 } 01138 01139 /* XXX if default "/var/lib/rpm" path, manage %{_hrmib_path} entries too. */ 01140 { const char * dbpath = rpmGetPath("%{?_dbpath}", NULL); 01141 const char * rootpath = NULL; 01142 const char * homepath = NULL; 01143 01144 (void) urlPath(db->db_root, &rootpath); 01145 (void) urlPath(db->db_home, &homepath); 01146 #define _VARLIBRPM "/var/lib/rpm" 01147 if (!strcmp(rootpath, "/") 01148 && !strncmp(homepath, _VARLIBRPM, sizeof(_VARLIBRPM)-1)) 01149 db->db_export = rpmdbExportInfo; 01150 dbpath = _free(dbpath); 01151 #undef _VARLIBRPM 01152 } 01153 01154 db->db_errpfx = rpmExpand( (epfx && *epfx ? epfx : _DB_ERRPFX), NULL); 01155 db->db_remove_env = 0; 01156 db->db_filter_dups = _db_filter_dups; 01157 dbiTagsInit(&db->db_tagn, &db->db_ndbi); 01158 db->_dbi = xcalloc(db->db_ndbi, sizeof(*db->_dbi)); 01159 db->nrefs = 0; 01160 /*@-globstate@*/ 01161 return rpmdbLink(db, "rpmdbCreate"); 01162 /*@=globstate@*/ 01163 } 01164 /*@=mods@*/ 01165 /*@=exportheader@*/ 01166 01167 /*@-exportheader@*/ 01168 int rpmdbOpenDatabase(/*@null@*/ const char * prefix, 01169 /*@null@*/ const char * dbpath, 01170 int _dbapi, /*@null@*/ /*@out@*/ rpmdb *dbp, 01171 int mode, int perms, int flags) 01172 /*@globals rpmdbRock, rpmGlobalMacroContext, h_errno, 01173 fileSystem, internalState @*/ 01174 /*@modifies rpmdbRock, *dbp, rpmGlobalMacroContext, 01175 fileSystem, internalState @*/ 01176 /*@requires maxSet(dbp) >= 0 @*/ 01177 { 01178 rpmdb db; 01179 int rc, xx; 01180 int justCheck = flags & RPMDB_FLAG_JUSTCHECK; 01181 int minimal = flags & RPMDB_FLAG_MINIMAL; 01182 01183 /* Insure that _dbapi has one of -1, 1, 2, or 3 */ 01184 if (_dbapi < -1 || _dbapi > 4) 01185 _dbapi = -1; 01186 if (_dbapi == 0) 01187 _dbapi = 1; 01188 01189 if (dbp) 01190 *dbp = NULL; 01191 if (mode & O_WRONLY) 01192 return 1; 01193 01194 db = rpmdbNew(prefix, dbpath, mode, perms, flags); 01195 if (db == NULL) 01196 return 1; 01197 01198 (void) rpmsqEnable(SIGHUP, NULL); 01199 (void) rpmsqEnable(SIGINT, NULL); 01200 (void) rpmsqEnable(SIGTERM, NULL); 01201 (void) rpmsqEnable(SIGQUIT, NULL); 01202 (void) rpmsqEnable(SIGPIPE, NULL); 01203 01204 db->db_api = _dbapi; 01205 01206 { int dbix; 01207 01208 rc = 0; 01209 if (db->db_tagn != NULL) 01210 for (dbix = 0; rc == 0 && dbix < db->db_ndbi; dbix++) { 01211 dbiIndex dbi; 01212 int rpmtag; 01213 01214 /* Filter out temporary databases */ 01215 switch ((rpmtag = db->db_tagn[dbix])) { 01216 case RPMDBI_AVAILABLE: 01217 case RPMDBI_ADDED: 01218 case RPMDBI_REMOVED: 01219 case RPMDBI_DEPENDS: 01220 continue; 01221 /*@notreached@*/ /*@switchbreak@*/ break; 01222 default: 01223 /*@switchbreak@*/ break; 01224 } 01225 01226 dbi = dbiOpen(db, rpmtag, 0); 01227 if (dbi == NULL) { 01228 rc = -2; 01229 break; 01230 } 01231 01232 switch (rpmtag) { 01233 case RPMDBI_PACKAGES: 01234 if (dbi == NULL) rc |= 1; 01235 #if 0 01236 /* XXX open only Packages, indices created on the fly. */ 01237 if (db->db_api == 3) 01238 #endif 01239 goto exit; 01240 /*@notreached@*/ /*@switchbreak@*/ break; 01241 case RPMTAG_NAME: 01242 if (dbi == NULL) rc |= 1; 01243 if (minimal) 01244 goto exit; 01245 /*@switchbreak@*/ break; 01246 default: 01247 /*@switchbreak@*/ break; 01248 } 01249 } 01250 } 01251 01252 exit: 01253 if (rc || justCheck || dbp == NULL) 01254 xx = rpmdbClose(db); 01255 else { 01256 /*@-assignexpose -newreftrans@*/ 01257 /*@i@*/ db->db_next = rpmdbRock; 01258 rpmdbRock = db; 01259 /*@i@*/ *dbp = db; 01260 /*@=assignexpose =newreftrans@*/ 01261 } 01262 01263 return rc; 01264 } 01265 /*@=exportheader@*/ 01266 01267 rpmdb XrpmdbUnlink(rpmdb db, const char * msg, const char * fn, unsigned ln) 01268 { 01269 /*@-modfilesys@*/ 01270 if (_rpmdb_debug) 01271 fprintf(stderr, "--> db %p -- %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln); 01272 /*@=modfilesys@*/ 01273 db->nrefs--; 01274 return NULL; 01275 } 01276 01277 rpmdb XrpmdbLink(rpmdb db, const char * msg, const char * fn, unsigned ln) 01278 { 01279 db->nrefs++; 01280 /*@-modfilesys@*/ 01281 if (_rpmdb_debug) 01282 fprintf(stderr, "--> db %p ++ %d %s at %s:%u\n", db, db->nrefs, msg, fn, ln); 01283 /*@=modfilesys@*/ 01284 /*@-refcounttrans@*/ return db; /*@=refcounttrans@*/ 01285 } 01286 01287 /* XXX python/rpmmodule.c */ 01288 int rpmdbOpen (const char * prefix, rpmdb *dbp, int mode, int perms) 01289 { 01290 int _dbapi = rpmExpandNumeric("%{_dbapi}"); 01291 /*@-boundswrite@*/ 01292 return rpmdbOpenDatabase(prefix, NULL, _dbapi, dbp, mode, perms, 0); 01293 /*@=boundswrite@*/ 01294 } 01295 01296 int rpmdbInit (const char * prefix, int perms) 01297 { 01298 rpmdb db = NULL; 01299 int _dbapi = rpmExpandNumeric("%{_dbapi}"); 01300 int rc; 01301 01302 /*@-boundswrite@*/ 01303 rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, (O_CREAT | O_RDWR), 01304 perms, RPMDB_FLAG_JUSTCHECK); 01305 /*@=boundswrite@*/ 01306 if (db != NULL) { 01307 int xx; 01308 xx = rpmdbOpenAll(db); 01309 if (xx && rc == 0) rc = xx; 01310 xx = rpmdbClose(db); 01311 if (xx && rc == 0) rc = xx; 01312 db = NULL; 01313 } 01314 return rc; 01315 } 01316 01317 int rpmdbVerifyAllDBI(rpmdb db) 01318 { 01319 int rc = 0; 01320 01321 if (db != NULL) { 01322 int dbix; 01323 int xx; 01324 rc = rpmdbOpenAll(db); 01325 01326 if (db->_dbi != NULL) 01327 for (dbix = db->db_ndbi; --dbix >= 0; ) { 01328 if (db->_dbi[dbix] == NULL) 01329 continue; 01330 /*@-unqualifiedtrans@*/ /* FIX: double indirection. */ 01331 xx = dbiVerify(db->_dbi[dbix], 0); 01332 if (xx && rc == 0) rc = xx; 01333 db->_dbi[dbix] = NULL; 01334 /*@=unqualifiedtrans@*/ 01335 } 01336 01337 /*@-nullstate@*/ /* FIX: db->_dbi[] may be NULL. */ 01338 xx = rpmdbClose(db); 01339 /*@=nullstate@*/ 01340 if (xx && rc == 0) rc = xx; 01341 db = NULL; 01342 } 01343 return rc; 01344 } 01345 01346 int rpmdbVerify(const char * prefix) 01347 { 01348 rpmdb db = NULL; 01349 int _dbapi = rpmExpandNumeric("%{_dbapi}"); 01350 int rc = rpmdbOpenDatabase(prefix, NULL, _dbapi, &db, O_RDONLY, 0644, 0); 01351 01352 if (!rc && db != NULL) 01353 rc = rpmdbVerifyAllDBI(db); 01354 return rc; 01355 } 01356 01362 static inline unsigned taghash(const char *s) 01363 { 01364 unsigned int r = 0; 01365 int c; 01366 while ((c = *(const unsigned char *)s++) != 0) { 01367 /* XXX Excluding the '/' character may cause hash collisions. */ 01368 if (c != '/') 01369 r += (r << 3) + c; 01370 } 01371 return ((r & 0x7fff) | 0x8000) << 16; 01372 } 01373 01383 static int rpmdbFindByFile(rpmdb db, /*@null@*/ const char * filespec, 01384 DBT * key, DBT * data, /*@out@*/ dbiIndexSet * matches) 01385 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01386 /*@modifies db, *key, *data, *matches, rpmGlobalMacroContext, 01387 fileSystem, internalState @*/ 01388 /*@requires maxSet(matches) >= 0 @*/ 01389 { 01390 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 01391 HFD_t hfd = headerFreeData; 01392 const char * dirName; 01393 const char * baseName; 01394 rpmTagType bnt, dnt; 01395 fingerPrintCache fpc; 01396 fingerPrint fp1; 01397 dbiIndex dbi = NULL; 01398 DBC * dbcursor; 01399 dbiIndexSet allMatches = NULL; 01400 dbiIndexItem rec = NULL; 01401 int i; 01402 int rc; 01403 int xx; 01404 01405 *matches = NULL; 01406 if (filespec == NULL) return -2; 01407 01408 /*@-branchstate@*/ 01409 if ((baseName = strrchr(filespec, '/')) != NULL) { 01410 char * t; 01411 size_t len; 01412 01413 len = baseName - filespec + 1; 01414 /*@-boundswrite@*/ 01415 t = strncpy(alloca(len + 1), filespec, len); 01416 t[len] = '\0'; 01417 /*@=boundswrite@*/ 01418 dirName = t; 01419 baseName++; 01420 } else { 01421 dirName = ""; 01422 baseName = filespec; 01423 } 01424 /*@=branchstate@*/ 01425 if (baseName == NULL) 01426 return -2; 01427 01428 fpc = fpCacheCreate(20); 01429 fp1 = fpLookup(fpc, dirName, baseName, 1); 01430 01431 dbi = dbiOpen(db, RPMTAG_BASENAMES, 0); 01432 /*@-branchstate@*/ 01433 if (dbi != NULL) { 01434 dbcursor = NULL; 01435 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0); 01436 01437 /*@-temptrans@*/ 01438 key->data = (void *) baseName; 01439 /*@=temptrans@*/ 01440 key->size = strlen(baseName); 01441 if (key->size == 0) key->size++; /* XXX "/" fixup. */ 01442 01443 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 01444 if (rc > 0) { 01445 rpmError(RPMERR_DBGETINDEX, 01446 _("error(%d) getting \"%s\" records from %s index\n"), 01447 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 01448 } 01449 01450 if (rc == 0) 01451 (void) dbt2set(dbi, data, &allMatches); 01452 01453 /* strip off directory tags */ 01454 if (_db_tagged_file_indices && allMatches != NULL) 01455 for (i = 0; i < allMatches->count; i++) { 01456 if (allMatches->recs[i].tagNum & 0x80000000) 01457 allMatches->recs[i].tagNum &= 0x0000ffff; 01458 } 01459 01460 xx = dbiCclose(dbi, dbcursor, 0); 01461 dbcursor = NULL; 01462 } else 01463 rc = -2; 01464 /*@=branchstate@*/ 01465 01466 if (rc) { 01467 allMatches = dbiFreeIndexSet(allMatches); 01468 fpc = fpCacheFree(fpc); 01469 return rc; 01470 } 01471 01472 *matches = xcalloc(1, sizeof(**matches)); 01473 rec = dbiIndexNewItem(0, 0); 01474 i = 0; 01475 if (allMatches != NULL) 01476 while (i < allMatches->count) { 01477 const char ** baseNames, ** dirNames; 01478 int_32 * dirIndexes; 01479 unsigned int offset = dbiIndexRecordOffset(allMatches, i); 01480 unsigned int prevoff; 01481 Header h; 01482 01483 { rpmdbMatchIterator mi; 01484 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &offset, sizeof(offset)); 01485 h = rpmdbNextIterator(mi); 01486 if (h) 01487 h = headerLink(h); 01488 mi = rpmdbFreeIterator(mi); 01489 } 01490 01491 if (h == NULL) { 01492 i++; 01493 continue; 01494 } 01495 01496 xx = hge(h, RPMTAG_BASENAMES, &bnt, &baseNames, NULL); 01497 xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL); 01498 xx = hge(h, RPMTAG_DIRINDEXES, NULL, &dirIndexes, NULL); 01499 01500 do { 01501 fingerPrint fp2; 01502 int num = dbiIndexRecordFileNumber(allMatches, i); 01503 01504 fp2 = fpLookup(fpc, dirNames[dirIndexes[num]], baseNames[num], 1); 01505 /*@-nullpass@*/ 01506 if (FP_EQUAL(fp1, fp2)) { 01507 /*@=nullpass@*/ 01508 rec->hdrNum = dbiIndexRecordOffset(allMatches, i); 01509 rec->tagNum = dbiIndexRecordFileNumber(allMatches, i); 01510 xx = dbiAppendSet(*matches, rec, 1, sizeof(*rec), 0); 01511 } 01512 01513 prevoff = offset; 01514 i++; 01515 if (i < allMatches->count) 01516 offset = dbiIndexRecordOffset(allMatches, i); 01517 } while (i < allMatches->count && offset == prevoff); 01518 01519 baseNames = hfd(baseNames, bnt); 01520 dirNames = hfd(dirNames, dnt); 01521 h = headerFree(h); 01522 } 01523 01524 rec = _free(rec); 01525 allMatches = dbiFreeIndexSet(allMatches); 01526 01527 fpc = fpCacheFree(fpc); 01528 01529 if ((*matches)->count == 0) { 01530 *matches = dbiFreeIndexSet(*matches); 01531 return 1; 01532 } 01533 01534 return 0; 01535 } 01536 01537 int rpmdbCount(rpmdb db, rpmTag tag, const void * keyp, size_t keylen) 01538 { 01539 DBC * dbcursor = NULL; 01540 DBT * key = alloca(sizeof(*key)); 01541 DBT * data = alloca(sizeof(*data)); 01542 dbiIndex dbi; 01543 int rc; 01544 int xx; 01545 01546 if (db == NULL || keyp == NULL) 01547 return 0; 01548 01549 memset(key, 0, sizeof(*key)); 01550 memset(data, 0, sizeof(*data)); 01551 01552 dbi = dbiOpen(db, tag, 0); 01553 if (dbi == NULL) 01554 return 0; 01555 01556 if (keylen == 0) 01557 keylen = strlen(keyp); 01558 01559 /*@-temptrans@*/ 01560 key->data = (void *) keyp; 01561 /*@=temptrans@*/ 01562 key->size = (u_int32_t) keylen; 01563 01564 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0); 01565 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 01566 #ifndef SQLITE_HACK 01567 xx = dbiCclose(dbi, dbcursor, 0); 01568 dbcursor = NULL; 01569 #endif 01570 01571 if (rc == 0) { /* success */ 01572 dbiIndexSet matches; 01573 /*@-nullpass@*/ /* FIX: matches might be NULL */ 01574 matches = NULL; 01575 (void) dbt2set(dbi, data, &matches); 01576 if (matches) { 01577 rc = dbiIndexSetCount(matches); 01578 matches = dbiFreeIndexSet(matches); 01579 } 01580 /*@=nullpass@*/ 01581 } else 01582 if (rc == DB_NOTFOUND) { /* not found */ 01583 rc = 0; 01584 } else { /* error */ 01585 rpmError(RPMERR_DBGETINDEX, 01586 _("error(%d) getting \"%s\" records from %s index\n"), 01587 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 01588 rc = -1; 01589 } 01590 01591 #ifdef SQLITE_HACK 01592 xx = dbiCclose(dbi, dbcursor, 0); 01593 dbcursor = NULL; 01594 #endif 01595 01596 return rc; 01597 } 01598 01599 /* XXX python/upgrade.c, install.c, uninstall.c */ 01600 int rpmdbCountPackages(rpmdb db, const char * name) 01601 { 01602 return rpmdbCount(db, RPMTAG_NAME, name, 0); 01603 } 01604 01617 static rpmRC dbiFindMatches(dbiIndex dbi, DBC * dbcursor, 01618 DBT * key, DBT * data, 01619 const char * name, 01620 /*@null@*/ const char * version, 01621 /*@null@*/ const char * release, 01622 /*@out@*/ dbiIndexSet * matches) 01623 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01624 /*@modifies dbi, *dbcursor, *key, *data, *matches, 01625 rpmGlobalMacroContext, fileSystem, internalState @*/ 01626 /*@requires maxSet(matches) >= 0 @*/ 01627 { 01628 int gotMatches = 0; 01629 int rc; 01630 int i; 01631 01632 /*@-temptrans@*/ 01633 key->data = (void *) name; 01634 /*@=temptrans@*/ 01635 key->size = strlen(name); 01636 01637 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 01638 01639 if (rc == 0) { /* success */ 01640 (void) dbt2set(dbi, data, matches); 01641 if (version == NULL && release == NULL) 01642 return RPMRC_OK; 01643 } else 01644 if (rc == DB_NOTFOUND) { /* not found */ 01645 return RPMRC_NOTFOUND; 01646 } else { /* error */ 01647 rpmError(RPMERR_DBGETINDEX, 01648 _("error(%d) getting \"%s\" records from %s index\n"), 01649 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 01650 return RPMRC_FAIL; 01651 } 01652 01653 /* Make sure the version and release match. */ 01654 /*@-branchstate@*/ 01655 for (i = 0; i < dbiIndexSetCount(*matches); i++) { 01656 unsigned int recoff = dbiIndexRecordOffset(*matches, i); 01657 rpmdbMatchIterator mi; 01658 Header h; 01659 01660 if (recoff == 0) 01661 continue; 01662 01663 mi = rpmdbInitIterator(dbi->dbi_rpmdb, 01664 RPMDBI_PACKAGES, &recoff, sizeof(recoff)); 01665 01666 /* Set iterator selectors for version/release if available. */ 01667 if (version && 01668 rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_DEFAULT, version)) 01669 { 01670 rc = RPMRC_FAIL; 01671 goto exit; 01672 } 01673 if (release && 01674 rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_DEFAULT, release)) 01675 { 01676 rc = RPMRC_FAIL; 01677 goto exit; 01678 } 01679 01680 h = rpmdbNextIterator(mi); 01681 /*@-boundswrite@*/ 01682 if (h) 01683 (*matches)->recs[gotMatches++] = (*matches)->recs[i]; 01684 else 01685 (*matches)->recs[i].hdrNum = 0; 01686 /*@=boundswrite@*/ 01687 mi = rpmdbFreeIterator(mi); 01688 } 01689 /*@=branchstate@*/ 01690 01691 if (gotMatches) { 01692 (*matches)->count = gotMatches; 01693 rc = RPMRC_OK; 01694 } else 01695 rc = RPMRC_NOTFOUND; 01696 01697 exit: 01698 /*@-unqualifiedtrans@*/ /* FIX: double indirection */ 01699 if (rc && matches && *matches) 01700 *matches = dbiFreeIndexSet(*matches); 01701 /*@=unqualifiedtrans@*/ 01702 return rc; 01703 } 01704 01717 static rpmRC dbiFindByLabel(dbiIndex dbi, DBC * dbcursor, DBT * key, DBT * data, 01718 /*@null@*/ const char * arg, /*@out@*/ dbiIndexSet * matches) 01719 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01720 /*@modifies dbi, *dbcursor, *key, *data, *matches, 01721 rpmGlobalMacroContext, fileSystem, internalState @*/ 01722 /*@requires maxSet(matches) >= 0 @*/ 01723 { 01724 const char * release; 01725 char * localarg; 01726 char * s; 01727 char c; 01728 int brackets; 01729 rpmRC rc; 01730 01731 if (arg == NULL || strlen(arg) == 0) return RPMRC_NOTFOUND; 01732 01733 /* did they give us just a name? */ 01734 rc = dbiFindMatches(dbi, dbcursor, key, data, arg, NULL, NULL, matches); 01735 if (rc != RPMRC_NOTFOUND) return rc; 01736 01737 /*@-unqualifiedtrans@*/ /* FIX: double indirection */ 01738 *matches = dbiFreeIndexSet(*matches); 01739 /*@=unqualifiedtrans@*/ 01740 01741 /* maybe a name and a release */ 01742 localarg = alloca(strlen(arg) + 1); 01743 s = stpcpy(localarg, arg); 01744 01745 c = '\0'; 01746 brackets = 0; 01747 for (s -= 1; s > localarg; s--) { 01748 switch (*s) { 01749 case '[': 01750 brackets = 1; 01751 /*@switchbreak@*/ break; 01752 case ']': 01753 if (c != '[') brackets = 0; 01754 /*@switchbreak@*/ break; 01755 } 01756 c = *s; 01757 if (!brackets && *s == '-') 01758 break; 01759 } 01760 01761 /*@-nullstate@*/ /* FIX: *matches may be NULL. */ 01762 if (s == localarg) return RPMRC_NOTFOUND; 01763 01764 /*@-boundswrite@*/ 01765 *s = '\0'; 01766 /*@=boundswrite@*/ 01767 rc = dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, NULL, matches); 01768 /*@=nullstate@*/ 01769 if (rc != RPMRC_NOTFOUND) return rc; 01770 01771 /*@-unqualifiedtrans@*/ /* FIX: double indirection */ 01772 *matches = dbiFreeIndexSet(*matches); 01773 /*@=unqualifiedtrans@*/ 01774 01775 /* how about name-version-release? */ 01776 01777 release = s + 1; 01778 01779 c = '\0'; 01780 brackets = 0; 01781 for (; s > localarg; s--) { 01782 switch (*s) { 01783 case '[': 01784 brackets = 1; 01785 /*@switchbreak@*/ break; 01786 case ']': 01787 if (c != '[') brackets = 0; 01788 /*@switchbreak@*/ break; 01789 } 01790 c = *s; 01791 if (!brackets && *s == '-') 01792 break; 01793 } 01794 01795 if (s == localarg) return RPMRC_NOTFOUND; 01796 01797 /*@-boundswrite@*/ 01798 *s = '\0'; 01799 /*@=boundswrite@*/ 01800 /*@-nullstate@*/ /* FIX: *matches may be NULL. */ 01801 return dbiFindMatches(dbi, dbcursor, key, data, localarg, s + 1, release, matches); 01802 /*@=nullstate@*/ 01803 } 01804 01805 void * dbiStatsAccumulator(dbiIndex dbi, int opx) 01806 { 01807 void * sw = NULL; 01808 switch (opx) { 01809 case 14: /* RPMTS_OP_DBGET */ 01810 sw = &dbi->dbi_rpmdb->db_getops; 01811 break; 01812 case 15: /* RPMTS_OP_DBPUT */ 01813 sw = &dbi->dbi_rpmdb->db_putops; 01814 break; 01815 default: /* XXX wrong, but let's not return NULL. */ 01816 case 16: /* RPMTS_OP_DBDEL */ 01817 sw = &dbi->dbi_rpmdb->db_delops; 01818 break; 01819 } 01820 return sw; 01821 } 01822 01831 static int miFreeHeader(rpmdbMatchIterator mi, dbiIndex dbi) 01832 /*@globals fileSystem, internalState @*/ 01833 /*@modifies mi, dbi, fileSystem, internalState @*/ 01834 { 01835 int rc = 0; 01836 01837 if (mi == NULL || mi->mi_h == NULL) 01838 return 0; 01839 01840 if (dbi && mi->mi_dbc && mi->mi_modified && mi->mi_prevoffset) { 01841 DBT * key = &mi->mi_key; 01842 DBT * data = &mi->mi_data; 01843 sigset_t signalMask; 01844 rpmRC rpmrc = RPMRC_NOTFOUND; 01845 int xx; 01846 01847 /*@i@*/ key->data = (void *) &mi->mi_prevoffset; 01848 key->size = sizeof(mi->mi_prevoffset); 01849 data->data = headerUnload(mi->mi_h); 01850 data->size = headerSizeof(mi->mi_h, HEADER_MAGIC_NO); 01851 01852 /* Check header digest/signature on blob export (if requested). */ 01853 if (mi->mi_hdrchk && mi->mi_ts) { 01854 const char * msg = NULL; 01855 int lvl; 01856 01857 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, data->data, data->size, &msg); 01858 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG); 01859 rpmMessage(lvl, "%s h#%8u %s", 01860 (rpmrc == RPMRC_FAIL ? _("miFreeHeader: skipping") : "write"), 01861 mi->mi_prevoffset, (msg ? msg : "\n")); 01862 msg = _free(msg); 01863 } 01864 01865 if (data->data != NULL && rpmrc != RPMRC_FAIL) { 01866 (void) blockSignals(dbi->dbi_rpmdb, &signalMask); 01867 rc = dbiPut(dbi, mi->mi_dbc, key, data, DB_KEYLAST); 01868 if (rc) { 01869 rpmError(RPMERR_DBPUTINDEX, 01870 _("error(%d) storing record #%d into %s\n"), 01871 rc, mi->mi_prevoffset, mapTagName(dbi->dbi_rpmtag)); 01872 } 01873 xx = dbiSync(dbi, 0); 01874 (void) unblockSignals(dbi->dbi_rpmdb, &signalMask); 01875 } 01876 data->data = _free(data->data); 01877 data->size = 0; 01878 } 01879 01880 mi->mi_h = headerFree(mi->mi_h); 01881 01882 /*@-nullstate@*/ 01883 return rc; 01884 /*@=nullstate@*/ 01885 } 01886 01887 rpmdbMatchIterator rpmdbFreeIterator(rpmdbMatchIterator mi) 01888 /*@globals rpmmiRock @*/ 01889 /*@modifies rpmmiRock @*/ 01890 { 01891 rpmdbMatchIterator * prev, next; 01892 dbiIndex dbi; 01893 int xx; 01894 int i; 01895 01896 if (mi == NULL) 01897 return NULL; 01898 01899 prev = &rpmmiRock; 01900 while ((next = *prev) != NULL && next != mi) 01901 prev = &next->mi_next; 01902 if (next) { 01903 /*@i@*/ *prev = next->mi_next; 01904 next->mi_next = NULL; 01905 } 01906 01907 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0); 01908 if (dbi == NULL) /* XXX can't happen */ 01909 return NULL; 01910 01911 xx = miFreeHeader(mi, dbi); 01912 01913 if (mi->mi_dbc) 01914 xx = dbiCclose(dbi, mi->mi_dbc, 0); 01915 mi->mi_dbc = NULL; 01916 01917 if (mi->mi_re != NULL) 01918 for (i = 0; i < mi->mi_nre; i++) 01919 xx = mireClean(mi->mi_re + i); 01920 mi->mi_re = _free(mi->mi_re); 01921 01922 mi->mi_set = dbiFreeIndexSet(mi->mi_set); 01923 mi->mi_keyp = _free(mi->mi_keyp); 01924 mi->mi_db = rpmdbUnlink(mi->mi_db, "matchIterator"); 01925 01926 mi = _free(mi); 01927 01928 (void) rpmdbCheckSignals(); 01929 01930 return mi; 01931 } 01932 01933 unsigned int rpmdbGetIteratorOffset(rpmdbMatchIterator mi) { 01934 return (mi ? mi->mi_offset : 0); 01935 } 01936 01937 unsigned int rpmdbGetIteratorFileNum(rpmdbMatchIterator mi) { 01938 return (mi ? mi->mi_filenum : 0); 01939 } 01940 01941 int rpmdbGetIteratorCount(rpmdbMatchIterator mi) { 01942 return (mi && mi->mi_set ? mi->mi_set->count : 0); 01943 } 01944 01951 static int mireCmp(const void * a, const void * b) 01952 { 01953 const miRE mireA = (const miRE) a; 01954 const miRE mireB = (const miRE) b; 01955 return (mireA->tag - mireB->tag); 01956 } 01957 01965 static /*@only@*/ char * mireDup(rpmTag tag, rpmMireMode *modep, 01966 const char * pattern) 01967 /*@modifies *modep @*/ 01968 /*@requires maxSet(modep) >= 0 @*/ 01969 { 01970 const char * s; 01971 char * pat; 01972 char * t; 01973 int brackets; 01974 size_t nb; 01975 int c; 01976 01977 /*@-boundswrite@*/ 01978 switch (*modep) { 01979 default: 01980 case RPMMIRE_DEFAULT: 01981 if (tag == RPMTAG_DIRNAMES || tag == RPMTAG_BASENAMES) { 01982 *modep = RPMMIRE_GLOB; 01983 pat = xstrdup(pattern); 01984 break; 01985 } 01986 01987 nb = strlen(pattern) + sizeof("^$"); 01988 01989 /* Find no. of bytes needed for pattern. */ 01990 /* periods and plusses are escaped, splats become '.*' */ 01991 c = '\0'; 01992 brackets = 0; 01993 for (s = pattern; *s != '\0'; s++) { 01994 switch (*s) { 01995 case '.': 01996 case '+': 01997 case '*': 01998 if (!brackets) nb++; 01999 /*@switchbreak@*/ break; 02000 case '\\': 02001 s++; 02002 /*@switchbreak@*/ break; 02003 case '[': 02004 brackets = 1; 02005 /*@switchbreak@*/ break; 02006 case ']': 02007 if (c != '[') brackets = 0; 02008 /*@switchbreak@*/ break; 02009 } 02010 c = *s; 02011 } 02012 02013 pat = t = xmalloc(nb); 02014 02015 if (pattern[0] != '^') *t++ = '^'; 02016 02017 /* Copy pattern, escaping periods, prefixing splats with period. */ 02018 c = '\0'; 02019 brackets = 0; 02020 for (s = pattern; *s != '\0'; s++, t++) { 02021 switch (*s) { 02022 case '.': 02023 case '+': 02024 if (!brackets) *t++ = '\\'; 02025 /*@switchbreak@*/ break; 02026 case '*': 02027 if (!brackets) *t++ = '.'; 02028 /*@switchbreak@*/ break; 02029 case '\\': 02030 *t++ = *s++; 02031 /*@switchbreak@*/ break; 02032 case '[': 02033 brackets = 1; 02034 /*@switchbreak@*/ break; 02035 case ']': 02036 if (c != '[') brackets = 0; 02037 /*@switchbreak@*/ break; 02038 } 02039 c = *t = *s; 02040 } 02041 02042 if (s > pattern && s[-1] != '$') *t++ = '$'; 02043 *t = '\0'; 02044 *modep = RPMMIRE_REGEX; 02045 break; 02046 case RPMMIRE_STRCMP: 02047 case RPMMIRE_REGEX: 02048 case RPMMIRE_GLOB: 02049 pat = xstrdup(pattern); 02050 break; 02051 } 02052 /*@-boundswrite@*/ 02053 02054 return pat; 02055 } 02056 02057 int rpmdbSetIteratorRE(rpmdbMatchIterator mi, rpmTag tag, 02058 rpmMireMode mode, const char * pattern) 02059 { 02060 static rpmMireMode defmode = (rpmMireMode)-1; 02061 miRE nmire = NULL; 02062 miRE mire = NULL; 02063 const char * allpat = NULL; 02064 int notmatch = 0; 02065 int rc = 0; 02066 02067 /*@-boundsread@*/ 02068 if (defmode == (rpmMireMode)-1) { 02069 const char *t = rpmExpand("%{?_query_selector_match}", NULL); 02070 02071 if (*t == '\0' || !strcmp(t, "default")) 02072 defmode = RPMMIRE_DEFAULT; 02073 else if (!strcmp(t, "strcmp")) 02074 defmode = RPMMIRE_STRCMP; 02075 else if (!strcmp(t, "regex")) 02076 defmode = RPMMIRE_REGEX; 02077 else if (!strcmp(t, "glob")) 02078 defmode = RPMMIRE_GLOB; 02079 else 02080 defmode = RPMMIRE_DEFAULT; 02081 t = _free(t); 02082 } 02083 02084 if (mi == NULL || pattern == NULL) 02085 return rc; 02086 02087 /* Leading '!' inverts pattern match sense, like "grep -v". */ 02088 if (*pattern == '!') { 02089 notmatch = 1; 02090 pattern++; 02091 } 02092 /*@=boundsread@*/ 02093 02094 nmire = mireNew(mode, tag); 02095 /*@-boundswrite@*/ 02096 allpat = mireDup(nmire->tag, &nmire->mode, pattern); 02097 /*@=boundswrite@*/ 02098 02099 if (nmire->mode == RPMMIRE_DEFAULT) 02100 nmire->mode = defmode; 02101 02102 rc = mireRegcomp(nmire, allpat); 02103 if (rc) 02104 goto exit; 02105 02106 mi->mi_re = xrealloc(mi->mi_re, (mi->mi_nre + 1) * sizeof(*mi->mi_re)); 02107 mire = mi->mi_re + mi->mi_nre; 02108 mi->mi_nre++; 02109 02110 mire->mode = nmire->mode; 02111 mire->pattern = nmire->pattern; nmire->pattern = NULL; 02112 mire->preg = nmire->preg; nmire->preg = NULL; 02113 mire->cflags = nmire->cflags; 02114 mire->eflags = nmire->eflags; 02115 mire->fnflags = nmire->fnflags; 02116 mire->tag = nmire->tag; 02117 mire->notmatch = notmatch; 02118 02119 /*@-boundsread@*/ 02120 if (mi->mi_nre > 1) 02121 qsort(mi->mi_re, mi->mi_nre, sizeof(*mi->mi_re), mireCmp); 02122 /*@=boundsread@*/ 02123 02124 exit: 02125 allpat = _free(allpat); 02126 nmire = mireFree(nmire); 02127 return rc; 02128 } 02129 02135 static int mireSkip (const rpmdbMatchIterator mi) 02136 /*@modifies mi->mi_re @*/ 02137 { 02138 HGE_t hge = (HGE_t) headerGetEntryMinMemory; 02139 HFD_t hfd = (HFD_t) headerFreeData; 02140 union { 02141 void * ptr; 02142 const char ** argv; 02143 const char * str; 02144 int_32 * i32p; 02145 int_16 * i16p; 02146 int_8 * i8p; 02147 } u; 02148 char numbuf[32]; 02149 rpmTagType t; 02150 int_32 c; 02151 miRE mire; 02152 static int_32 zero = 0; 02153 int ntags = 0; 02154 int nmatches = 0; 02155 int i, j; 02156 int rc; 02157 02158 if (mi->mi_h == NULL) /* XXX can't happen */ 02159 return 1; 02160 02161 /* 02162 * Apply tag tests, implicitly "||" for multiple patterns/values of a 02163 * single tag, implicitly "&&" between multiple tag patterns. 02164 */ 02165 /*@-boundsread@*/ 02166 if ((mire = mi->mi_re) == NULL) 02167 return 0; 02168 02169 for (i = 0; i < mi->mi_nre; i++, mire++) { 02170 int anymatch; 02171 02172 if (!hge(mi->mi_h, mire->tag, &t, (void **)&u, &c)) { 02173 if (mire->tag != RPMTAG_EPOCH) 02174 continue; 02175 t = RPM_INT32_TYPE; 02176 /*@-immediatetrans@*/ 02177 u.i32p = &zero; 02178 /*@=immediatetrans@*/ 02179 c = 1; 02180 } 02181 02182 anymatch = 0; /* no matches yet */ 02183 while (1) { 02184 switch (t) { 02185 case RPM_CHAR_TYPE: 02186 case RPM_INT8_TYPE: 02187 sprintf(numbuf, "%d", (int) *u.i8p); 02188 rc = mireRegexec(mire, numbuf); 02189 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) 02190 anymatch++; 02191 /*@switchbreak@*/ break; 02192 case RPM_INT16_TYPE: 02193 sprintf(numbuf, "%d", (int) *u.i16p); 02194 rc = mireRegexec(mire, numbuf); 02195 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) 02196 anymatch++; 02197 /*@switchbreak@*/ break; 02198 case RPM_INT32_TYPE: 02199 sprintf(numbuf, "%d", (int) *u.i32p); 02200 rc = mireRegexec(mire, numbuf); 02201 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) 02202 anymatch++; 02203 /*@switchbreak@*/ break; 02204 case RPM_STRING_TYPE: 02205 rc = mireRegexec(mire, u.str); 02206 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) 02207 anymatch++; 02208 /*@switchbreak@*/ break; 02209 case RPM_I18NSTRING_TYPE: 02210 case RPM_STRING_ARRAY_TYPE: 02211 for (j = 0; j < c; j++) { 02212 rc = mireRegexec(mire, u.argv[j]); 02213 if ((!rc && !mire->notmatch) || (rc && mire->notmatch)) { 02214 anymatch++; 02215 /*@innerbreak@*/ break; 02216 } 02217 } 02218 /*@switchbreak@*/ break; 02219 case RPM_NULL_TYPE: 02220 case RPM_BIN_TYPE: 02221 default: 02222 /*@switchbreak@*/ break; 02223 } 02224 if ((i+1) < mi->mi_nre && mire[0].tag == mire[1].tag) { 02225 i++; 02226 mire++; 02227 /*@innercontinue@*/ continue; 02228 } 02229 /*@innerbreak@*/ break; 02230 } 02231 /*@=boundsread@*/ 02232 02233 u.ptr = hfd(u.ptr, t); 02234 02235 ntags++; 02236 if (anymatch) 02237 nmatches++; 02238 } 02239 02240 return (ntags > 0 && ntags == nmatches ? 0 : 1); 02241 } 02242 02243 int rpmdbSetIteratorRewrite(rpmdbMatchIterator mi, int rewrite) 02244 { 02245 int rc; 02246 if (mi == NULL) 02247 return 0; 02248 rc = (mi->mi_cflags & DB_WRITECURSOR) ? 1 : 0; 02249 if (rewrite) 02250 mi->mi_cflags |= DB_WRITECURSOR; 02251 else 02252 mi->mi_cflags &= ~DB_WRITECURSOR; 02253 return rc; 02254 } 02255 02256 int rpmdbSetIteratorModified(rpmdbMatchIterator mi, int modified) 02257 { 02258 int rc; 02259 if (mi == NULL) 02260 return 0; 02261 rc = mi->mi_modified; 02262 mi->mi_modified = modified; 02263 return rc; 02264 } 02265 02266 int rpmdbSetHdrChk(rpmdbMatchIterator mi, rpmts ts, 02267 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg)) 02268 { 02269 int rc = 0; 02270 if (mi == NULL) 02271 return 0; 02272 /*@-assignexpose -newreftrans @*/ /* XXX forward linkage prevents rpmtsLink */ 02273 /*@i@*/ mi->mi_ts = ts; 02274 mi->mi_hdrchk = hdrchk; 02275 /*@=assignexpose =newreftrans @*/ 02276 return rc; 02277 } 02278 02279 02280 /*@-nullstate@*/ /* FIX: mi->mi_key.data may be NULL */ 02281 Header rpmdbNextIterator(rpmdbMatchIterator mi) 02282 { 02283 dbiIndex dbi; 02284 void * uh; 02285 size_t uhlen; 02286 DBT * key; 02287 DBT * data; 02288 void * keyp; 02289 size_t keylen; 02290 int rc; 02291 int xx; 02292 02293 if (mi == NULL) 02294 return NULL; 02295 02296 dbi = dbiOpen(mi->mi_db, RPMDBI_PACKAGES, 0); 02297 if (dbi == NULL) 02298 return NULL; 02299 02300 /* 02301 * Cursors are per-iterator, not per-dbi, so get a cursor for the 02302 * iterator on 1st call. If the iteration is to rewrite headers, and the 02303 * CDB model is used for the database, then the cursor needs to 02304 * marked with DB_WRITECURSOR as well. 02305 */ 02306 if (mi->mi_dbc == NULL) 02307 xx = dbiCopen(dbi, dbi->dbi_txnid, &mi->mi_dbc, mi->mi_cflags); 02308 02309 /*@-boundswrite@*/ 02310 key = &mi->mi_key; 02311 memset(key, 0, sizeof(*key)); 02312 data = &mi->mi_data; 02313 memset(data, 0, sizeof(*data)); 02314 /*@=boundswrite@*/ 02315 02316 top: 02317 uh = NULL; 02318 uhlen = 0; 02319 02320 do { 02321 union _dbswap mi_offset; 02322 02323 /*@-branchstate -compmempass @*/ 02324 if (mi->mi_set) { 02325 if (!(mi->mi_setx < mi->mi_set->count)) 02326 return NULL; 02327 mi->mi_offset = dbiIndexRecordOffset(mi->mi_set, mi->mi_setx); 02328 mi->mi_filenum = dbiIndexRecordFileNumber(mi->mi_set, mi->mi_setx); 02329 mi_offset.ui = mi->mi_offset; 02330 if (dbiByteSwapped(dbi) == 1) 02331 _DBSWAP(mi_offset); 02332 keyp = &mi_offset; 02333 keylen = sizeof(mi_offset.ui); 02334 } else { 02335 02336 key->data = keyp = (void *)mi->mi_keyp; 02337 key->size = keylen = mi->mi_keylen; 02338 data->data = uh; 02339 data->size = uhlen; 02340 #if !defined(_USE_COPY_LOAD) 02341 data->flags |= DB_DBT_MALLOC; 02342 #endif 02343 rc = dbiGet(dbi, mi->mi_dbc, key, data, 02344 (key->data == NULL ? DB_NEXT : DB_SET)); 02345 data->flags = 0; 02346 keyp = key->data; 02347 keylen = key->size; 02348 uh = data->data; 02349 uhlen = data->size; 02350 02351 /* 02352 * If we got the next key, save the header instance number. 02353 * 02354 * For db3 Packages, instance 0 (i.e. mi->mi_setx == 0) is the 02355 * largest header instance in the database, and should be 02356 * skipped. 02357 */ 02358 /*@-boundswrite@*/ 02359 if (keyp && mi->mi_setx && rc == 0) { 02360 memcpy(&mi_offset, keyp, sizeof(mi_offset.ui)); 02361 if (dbiByteSwapped(dbi) == 1) 02362 _DBSWAP(mi_offset); 02363 mi->mi_offset = mi_offset.ui; 02364 } 02365 /*@=boundswrite@*/ 02366 02367 /* Terminate on error or end of keys */ 02368 if (rc || (mi->mi_setx && mi->mi_offset == 0)) 02369 return NULL; 02370 } 02371 /*@=branchstate =compmempass @*/ 02372 mi->mi_setx++; 02373 } while (mi->mi_offset == 0); 02374 02375 /* If next header is identical, return it now. */ 02376 /*@-compdef -refcounttrans -retalias -retexpose -usereleased @*/ 02377 if (mi->mi_prevoffset && mi->mi_offset == mi->mi_prevoffset) 02378 return mi->mi_h; 02379 /*@=compdef =refcounttrans =retalias =retexpose =usereleased @*/ 02380 02381 /* Retrieve next header blob for index iterator. */ 02382 /*@-branchstate -compmempass -immediatetrans @*/ 02383 if (uh == NULL) { 02384 key->data = keyp; 02385 key->size = keylen; 02386 #if !defined(_USE_COPY_LOAD) 02387 data->flags |= DB_DBT_MALLOC; 02388 #endif 02389 rc = dbiGet(dbi, mi->mi_dbc, key, data, DB_SET); 02390 data->flags = 0; 02391 keyp = key->data; 02392 keylen = key->size; 02393 uh = data->data; 02394 uhlen = data->size; 02395 if (rc) 02396 return NULL; 02397 } 02398 /*@=branchstate =compmempass =immediatetrans @*/ 02399 02400 /* Rewrite current header (if necessary) and unlink. */ 02401 xx = miFreeHeader(mi, dbi); 02402 02403 /* Is this the end of the iteration? */ 02404 if (uh == NULL) 02405 return NULL; 02406 02407 /* Check header digest/signature once (if requested). */ 02408 /*@-boundsread -branchstate -sizeoftype @*/ 02409 if (mi->mi_hdrchk && mi->mi_ts) { 02410 rpmRC rpmrc = RPMRC_NOTFOUND; 02411 02412 /* Don't bother re-checking a previously read header. */ 02413 if (mi->mi_db->db_bits) { 02414 pbm_set * set; 02415 02416 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits, 02417 &mi->mi_db->db_nbits, mi->mi_offset); 02418 if (PBM_ISSET(mi->mi_offset, set)) 02419 rpmrc = RPMRC_OK; 02420 } 02421 02422 /* If blob is unchecked, check blob import consistency now. */ 02423 if (rpmrc != RPMRC_OK) { 02424 const char * msg = NULL; 02425 int lvl; 02426 02427 rpmrc = (*mi->mi_hdrchk) (mi->mi_ts, uh, uhlen, &msg); 02428 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG); 02429 rpmMessage(lvl, "%s h#%8u %s", 02430 (rpmrc == RPMRC_FAIL ? _("rpmdbNextIterator: skipping") : " read"), 02431 mi->mi_offset, (msg ? msg : "\n")); 02432 msg = _free(msg); 02433 02434 /* Mark header checked. */ 02435 if (mi->mi_db && mi->mi_db->db_bits && rpmrc == RPMRC_OK) { 02436 pbm_set * set; 02437 02438 set = PBM_REALLOC((pbm_set **)&mi->mi_db->db_bits, 02439 &mi->mi_db->db_nbits, mi->mi_offset); 02440 PBM_SET(mi->mi_offset, set); 02441 } 02442 02443 /* Skip damaged and inconsistent headers. */ 02444 if (rpmrc == RPMRC_FAIL) 02445 goto top; 02446 } 02447 } 02448 /*@=boundsread =branchstate =sizeoftype @*/ 02449 02450 /* Did the header blob load correctly? */ 02451 #if !defined(_USE_COPY_LOAD) 02452 /*@-onlytrans@*/ 02453 mi->mi_h = headerLoad(uh); 02454 /*@=onlytrans@*/ 02455 if (mi->mi_h) 02456 mi->mi_h->flags |= HEADERFLAG_ALLOCATED; 02457 #else 02458 mi->mi_h = headerCopyLoad(uh); 02459 #endif 02460 if (mi->mi_h == NULL || !headerIsEntry(mi->mi_h, RPMTAG_NAME)) { 02461 rpmError(RPMERR_BADHEADER, 02462 _("rpmdb: damaged header #%u retrieved -- skipping.\n"), 02463 mi->mi_offset); 02464 goto top; 02465 } 02466 02467 /* 02468 * Skip this header if iterator selector (if any) doesn't match. 02469 */ 02470 if (mireSkip(mi)) { 02471 /* XXX hack, can't restart with Packages locked on single instance. */ 02472 if (mi->mi_set || mi->mi_keyp == NULL) 02473 goto top; 02474 return NULL; 02475 } 02476 02477 /* Mark header with its instance number. */ 02478 { char origin[32]; 02479 sprintf(origin, "rpmdb (h#%u)", mi->mi_offset); 02480 (void) headerSetOrigin(mi->mi_h, origin); 02481 (void) headerSetInstance(mi->mi_h, mi->mi_offset); 02482 } 02483 02484 mi->mi_prevoffset = mi->mi_offset; 02485 mi->mi_modified = 0; 02486 02487 /*@-compdef -retalias -retexpose -usereleased @*/ 02488 return mi->mi_h; 02489 /*@=compdef =retalias =retexpose =usereleased @*/ 02490 } 02491 /*@=nullstate@*/ 02492 02493 static void rpmdbSortIterator(/*@null@*/ rpmdbMatchIterator mi) 02494 /*@modifies mi @*/ 02495 { 02496 if (mi && mi->mi_set && mi->mi_set->recs && mi->mi_set->count > 0) { 02497 /* 02498 * mergesort is much (~10x with lots of identical basenames) faster 02499 * than pure quicksort, but glibc uses msort_with_tmp() on stack. 02500 */ 02501 #if defined(__GLIBC__) 02502 /*@-boundsread@*/ 02503 qsort(mi->mi_set->recs, mi->mi_set->count, 02504 sizeof(*mi->mi_set->recs), hdrNumCmp); 02505 /*@=boundsread@*/ 02506 #else 02507 mergesort(mi->mi_set->recs, mi->mi_set->count, 02508 sizeof(*mi->mi_set->recs), hdrNumCmp); 02509 #endif 02510 mi->mi_sorted = 1; 02511 } 02512 } 02513 02514 /*@-bounds@*/ /* LCL: segfault */ 02515 static int rpmdbGrowIterator(/*@null@*/ rpmdbMatchIterator mi, int fpNum, 02516 unsigned int exclude, unsigned int tag) 02517 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02518 /*@modifies mi, rpmGlobalMacroContext, fileSystem, internalState @*/ 02519 { 02520 DBC * dbcursor; 02521 DBT * key; 02522 DBT * data; 02523 dbiIndex dbi = NULL; 02524 dbiIndexSet set; 02525 int rc; 02526 int xx; 02527 int i, j; 02528 02529 if (mi == NULL) 02530 return 1; 02531 02532 dbcursor = mi->mi_dbc; 02533 key = &mi->mi_key; 02534 data = &mi->mi_data; 02535 if (key->data == NULL) 02536 return 1; 02537 02538 dbi = dbiOpen(mi->mi_db, mi->mi_rpmtag, 0); 02539 if (dbi == NULL) 02540 return 1; 02541 02542 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0); 02543 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 02544 #ifndef SQLITE_HACK 02545 xx = dbiCclose(dbi, dbcursor, 0); 02546 dbcursor = NULL; 02547 #endif 02548 02549 if (rc) { /* error/not found */ 02550 if (rc != DB_NOTFOUND) 02551 rpmError(RPMERR_DBGETINDEX, 02552 _("error(%d) getting \"%s\" records from %s index\n"), 02553 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 02554 #ifdef SQLITE_HACK 02555 xx = dbiCclose(dbi, dbcursor, 0); 02556 dbcursor = NULL; 02557 #endif 02558 return rc; 02559 } 02560 02561 set = NULL; 02562 (void) dbt2set(dbi, data, &set); 02563 02564 /* prune the set against exclude and tag */ 02565 for (i = j = 0; i < set->count; i++) { 02566 if (exclude && set->recs[i].hdrNum == exclude) 02567 continue; 02568 if (_db_tagged_file_indices && set->recs[i].tagNum & 0x80000000) { 02569 /* tagged entry */ 02570 if ((set->recs[i].tagNum & 0xffff0000) != tag) 02571 continue; 02572 set->recs[i].tagNum &= 0x0000ffff; 02573 } 02574 if (i > j) 02575 set->recs[j] = set->recs[i]; 02576 j++; 02577 } 02578 if (j == 0) { 02579 #ifdef SQLITE_HACK 02580 xx = dbiCclose(dbi, dbcursor, 0); 02581 dbcursor = NULL; 02582 #endif 02583 set = dbiFreeIndexSet(set); 02584 return DB_NOTFOUND; 02585 } 02586 set->count = j; 02587 02588 for (i = 0; i < set->count; i++) 02589 set->recs[i].fpNum = fpNum; 02590 02591 #ifdef SQLITE_HACK 02592 xx = dbiCclose(dbi, dbcursor, 0); 02593 dbcursor = NULL; 02594 #endif 02595 02596 /*@-branchstate@*/ 02597 if (mi->mi_set == NULL) { 02598 mi->mi_set = set; 02599 } else { 02600 #if 0 02601 fprintf(stderr, "+++ %d = %d + %d\t\"%s\"\n", (mi->mi_set->count + set->count), mi->mi_set->count, set->count, ((char *)key->data)); 02602 #endif 02603 mi->mi_set->recs = xrealloc(mi->mi_set->recs, 02604 (mi->mi_set->count + set->count) * sizeof(*(mi->mi_set->recs))); 02605 memcpy(mi->mi_set->recs + mi->mi_set->count, set->recs, 02606 set->count * sizeof(*(mi->mi_set->recs))); 02607 mi->mi_set->count += set->count; 02608 set = dbiFreeIndexSet(set); 02609 } 02610 /*@=branchstate@*/ 02611 02612 return rc; 02613 } 02614 /*@=bounds@*/ 02615 02616 int rpmdbPruneIterator(rpmdbMatchIterator mi, int * hdrNums, 02617 int nHdrNums, int sorted) 02618 { 02619 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0) 02620 return 1; 02621 02622 if (mi->mi_set) 02623 (void) dbiPruneSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), sorted); 02624 return 0; 02625 } 02626 02627 int rpmdbAppendIterator(rpmdbMatchIterator mi, const int * hdrNums, int nHdrNums) 02628 { 02629 if (mi == NULL || hdrNums == NULL || nHdrNums <= 0) 02630 return 1; 02631 02632 if (mi->mi_set == NULL) 02633 mi->mi_set = xcalloc(1, sizeof(*mi->mi_set)); 02634 (void) dbiAppendSet(mi->mi_set, hdrNums, nHdrNums, sizeof(*hdrNums), 0); 02635 return 0; 02636 } 02637 02638 rpmdbMatchIterator rpmdbInitIterator(rpmdb db, rpmTag rpmtag, 02639 const void * keyp, size_t keylen) 02640 /*@globals rpmmiRock @*/ 02641 /*@modifies rpmmiRock @*/ 02642 { 02643 rpmdbMatchIterator mi; 02644 DBT * key; 02645 DBT * data; 02646 dbiIndexSet set = NULL; 02647 dbiIndex dbi; 02648 const void * mi_keyp = NULL; 02649 int isLabel = 0; 02650 02651 if (db == NULL) 02652 return NULL; 02653 02654 (void) rpmdbCheckSignals(); 02655 02656 /* XXX HACK to remove rpmdbFindByLabel/findMatches from the API */ 02657 if (rpmtag == RPMDBI_LABEL) { 02658 rpmtag = RPMTAG_NAME; 02659 isLabel = 1; 02660 } 02661 02662 dbi = dbiOpen(db, rpmtag, 0); 02663 if (dbi == NULL) 02664 return NULL; 02665 02666 /* Chain cursors for teardown on abnormal exit. */ 02667 mi = xcalloc(1, sizeof(*mi)); 02668 mi->mi_next = rpmmiRock; 02669 rpmmiRock = mi; 02670 02671 key = &mi->mi_key; 02672 data = &mi->mi_data; 02673 02674 /* 02675 * Handle label and file name special cases. 02676 * Otherwise, retrieve join keys for secondary lookup. 02677 */ 02678 /*@-branchstate@*/ 02679 if (rpmtag != RPMDBI_PACKAGES && keyp) { 02680 DBC * dbcursor = NULL; 02681 int rc; 02682 int xx; 02683 02684 if (isLabel) { 02685 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0); 02686 rc = dbiFindByLabel(dbi, dbcursor, key, data, keyp, &set); 02687 xx = dbiCclose(dbi, dbcursor, 0); 02688 dbcursor = NULL; 02689 } else if (rpmtag == RPMTAG_BASENAMES) { 02690 rc = rpmdbFindByFile(db, keyp, key, data, &set); 02691 } else { 02692 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0); 02693 02694 /*@-temptrans@*/ 02695 key->data = (void *) keyp; 02696 /*@=temptrans@*/ 02697 key->size = keylen; 02698 if (key->data && key->size == 0) key->size = strlen((char *)key->data); 02699 if (key->data && key->size == 0) key->size++; /* XXX "/" fixup. */ 02700 02701 /*@-nullstate@*/ 02702 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 02703 /*@=nullstate@*/ 02704 if (rc > 0) { 02705 rpmError(RPMERR_DBGETINDEX, 02706 _("error(%d) getting \"%s\" records from %s index\n"), 02707 rc, (key->data ? key->data : "???"), mapTagName(dbi->dbi_rpmtag)); 02708 } 02709 02710 /* Join keys need to be native endian internally. */ 02711 if (rc == 0) 02712 (void) dbt2set(dbi, data, &set); 02713 02714 xx = dbiCclose(dbi, dbcursor, 0); 02715 dbcursor = NULL; 02716 } 02717 if (rc) { /* error/not found */ 02718 set = dbiFreeIndexSet(set); 02719 rpmmiRock = mi->mi_next; 02720 mi->mi_next = NULL; 02721 mi = _free(mi); 02722 return NULL; 02723 } 02724 } 02725 /*@=branchstate@*/ 02726 02727 /* Copy the retrieval key, byte swapping header instance if necessary. */ 02728 if (keyp) { 02729 switch (rpmtag) { 02730 case RPMDBI_PACKAGES: 02731 { union _dbswap *k; 02732 02733 assert(keylen == sizeof(k->ui)); /* xxx programmer error */ 02734 k = xmalloc(sizeof(*k)); 02735 memcpy(k, keyp, keylen); 02736 if (dbiByteSwapped(dbi) == 1) 02737 _DBSWAP(*k); 02738 mi_keyp = k; 02739 } break; 02740 default: 02741 { char * k; 02742 if (keylen == 0) 02743 keylen = strlen(keyp); 02744 k = xmalloc(keylen + 1); 02745 /*@-boundsread@*/ 02746 memcpy(k, keyp, keylen); 02747 /*@=boundsread@*/ 02748 k[keylen] = '\0'; /* XXX assumes strings */ 02749 mi_keyp = k; 02750 } break; 02751 } 02752 } 02753 02754 mi->mi_keyp = mi_keyp; 02755 mi->mi_keylen = keylen; 02756 02757 mi->mi_db = rpmdbLink(db, "matchIterator"); 02758 mi->mi_rpmtag = rpmtag; 02759 02760 mi->mi_dbc = NULL; 02761 mi->mi_set = set; 02762 mi->mi_setx = 0; 02763 mi->mi_h = NULL; 02764 mi->mi_sorted = 0; 02765 mi->mi_cflags = 0; 02766 mi->mi_modified = 0; 02767 mi->mi_prevoffset = 0; 02768 mi->mi_offset = 0; 02769 mi->mi_filenum = 0; 02770 mi->mi_nre = 0; 02771 mi->mi_re = NULL; 02772 02773 mi->mi_ts = NULL; 02774 mi->mi_hdrchk = NULL; 02775 02776 /*@i@*/ return mi; 02777 } 02778 02779 /* XXX psm.c */ 02780 int rpmdbRemove(rpmdb db, /*@unused@*/ int rid, unsigned int hdrNum, 02781 /*@unused@*/ rpmts ts, 02782 /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg)) 02783 { 02784 DBC * dbcursor = NULL; 02785 DBT * key = alloca(sizeof(*key)); 02786 DBT * data = alloca(sizeof(*data)); 02787 union _dbswap mi_offset; 02788 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 02789 HFD_t hfd = headerFreeData; 02790 Header h; 02791 sigset_t signalMask; 02792 int ret = 0; 02793 int rc = 0; 02794 02795 if (db == NULL) 02796 return 0; 02797 02798 memset(key, 0, sizeof(*key)); 02799 memset(data, 0, sizeof(*data)); 02800 02801 { rpmdbMatchIterator mi; 02802 mi = rpmdbInitIterator(db, RPMDBI_PACKAGES, &hdrNum, sizeof(hdrNum)); 02803 h = rpmdbNextIterator(mi); 02804 if (h) 02805 h = headerLink(h); 02806 mi = rpmdbFreeIterator(mi); 02807 } 02808 02809 if (h == NULL) { 02810 rpmError(RPMERR_DBCORRUPT, _("%s: cannot read header at 0x%x\n"), 02811 "rpmdbRemove", hdrNum); 02812 return 1; 02813 } 02814 02815 #ifdef DYING 02816 /* Add remove transaction id to header. */ 02817 if (rid != 0 && rid != -1) { 02818 int_32 tid = rid; 02819 (void) headerAddEntry(h, RPMTAG_REMOVETID, RPM_INT32_TYPE, &tid, 1); 02820 } 02821 #endif 02822 02823 { const char *n, *v, *r; 02824 (void) headerNVR(h, &n, &v, &r); 02825 rpmMessage(RPMMESS_DEBUG, " --- h#%8u %s-%s-%s\n", hdrNum, n, v, r); 02826 } 02827 02828 (void) blockSignals(db, &signalMask); 02829 02830 /*@-nullpass -nullptrarith -nullderef @*/ /* FIX: rpmvals heartburn */ 02831 { int dbix; 02832 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0); 02833 02834 if (db->db_tagn != NULL) 02835 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 02836 dbiIndex dbi; 02837 const char *av[1]; 02838 const char ** rpmvals = NULL; 02839 byte * bin = NULL; 02840 rpmTagType rpmtype = 0; 02841 int rpmcnt = 0; 02842 int rpmtag; 02843 int xx; 02844 int i, j; 02845 02846 dbi = NULL; 02847 /*@-boundsread@*/ 02848 rpmtag = db->db_tagn[dbix]; 02849 /*@=boundsread@*/ 02850 02851 /*@-branchstate@*/ 02852 switch (rpmtag) { 02853 /* Filter out temporary databases */ 02854 case RPMDBI_AVAILABLE: 02855 case RPMDBI_ADDED: 02856 case RPMDBI_REMOVED: 02857 case RPMDBI_DEPENDS: 02858 continue; 02859 /*@notreached@*/ /*@switchbreak@*/ break; 02860 case RPMDBI_PACKAGES: 02861 if (db->db_export != NULL) 02862 xx = db->db_export(db, h, 0); 02863 dbi = dbiOpen(db, rpmtag, 0); 02864 if (dbi == NULL) /* XXX shouldn't happen */ 02865 continue; 02866 02867 /*@-immediatetrans@*/ 02868 mi_offset.ui = hdrNum; 02869 if (dbiByteSwapped(dbi) == 1) 02870 _DBSWAP(mi_offset); 02871 key->data = &mi_offset; 02872 /*@=immediatetrans@*/ 02873 key->size = sizeof(mi_offset.ui); 02874 02875 rc = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR); 02876 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 02877 if (rc) { 02878 rpmError(RPMERR_DBGETINDEX, 02879 _("error(%d) setting header #%d record for %s removal\n"), 02880 rc, hdrNum, mapTagName(dbi->dbi_rpmtag)); 02881 } else 02882 rc = dbiDel(dbi, dbcursor, key, data, 0); 02883 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 02884 dbcursor = NULL; 02885 if (!dbi->dbi_no_dbsync) 02886 xx = dbiSync(dbi, 0); 02887 continue; 02888 /*@notreached@*/ /*@switchbreak@*/ break; 02889 } 02890 /*@=branchstate@*/ 02891 02892 if (!hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt)) 02893 continue; 02894 02895 dbi = dbiOpen(db, rpmtag, 0); 02896 if (dbi != NULL) { 02897 int printed; 02898 02899 if (rpmtype == RPM_STRING_TYPE) { 02900 /* XXX force uniform headerGetEntry return */ 02901 av[0] = (const char *) rpmvals; 02902 rpmvals = av; 02903 rpmcnt = 1; 02904 } 02905 02906 printed = 0; 02907 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR); 02908 /*@-branchstate@*/ 02909 for (i = 0; i < rpmcnt; i++) { 02910 dbiIndexSet set; 02911 int stringvalued; 02912 02913 bin = _free(bin); 02914 switch (dbi->dbi_rpmtag) { 02915 case RPMTAG_FILEDIGESTS: 02916 /* Filter out empty file digests. */ 02917 if (!(rpmvals[i] && *rpmvals[i] != '\0')) 02918 /*@innercontinue@*/ continue; 02919 /*@switchbreak@*/ break; 02920 default: 02921 /*@switchbreak@*/ break; 02922 } 02923 02924 /* Identify value pointer and length. */ 02925 stringvalued = 0; 02926 switch (rpmtype) { 02927 /*@-sizeoftype@*/ 02928 case RPM_CHAR_TYPE: 02929 case RPM_INT8_TYPE: 02930 key->size = sizeof(RPM_CHAR_TYPE); 02931 key->data = rpmvals + i; 02932 /*@switchbreak@*/ break; 02933 case RPM_INT16_TYPE: 02934 key->size = sizeof(int_16); 02935 key->data = rpmvals + i; 02936 /*@switchbreak@*/ break; 02937 case RPM_INT32_TYPE: 02938 key->size = sizeof(int_32); 02939 key->data = rpmvals + i; 02940 /*@switchbreak@*/ break; 02941 /*@=sizeoftype@*/ 02942 case RPM_BIN_TYPE: 02943 key->size = rpmcnt; 02944 key->data = rpmvals; 02945 rpmcnt = 1; /* XXX break out of loop. */ 02946 /*@switchbreak@*/ break; 02947 case RPM_STRING_TYPE: 02948 case RPM_I18NSTRING_TYPE: 02949 rpmcnt = 1; /* XXX break out of loop. */ 02950 /*@fallthrough@*/ 02951 case RPM_STRING_ARRAY_TYPE: 02952 /* Convert from hex to binary. */ 02953 /*@-boundsread@*/ 02954 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) { 02955 const char * s = rpmvals[i]; 02956 size_t dlen = strlen(s); 02957 byte * t; 02958 assert((dlen & 1) == 0); 02959 dlen /= 2; 02960 bin = t = xcalloc(1, dlen); 02961 for (j = 0; j < dlen; j++, t++, s += 2) 02962 *t = (nibble(s[0]) << 4) | nibble(s[1]); 02963 key->data = bin; 02964 key->size = dlen; 02965 /*@switchbreak@*/ break; 02966 } 02967 /* Extract the pubkey id from the base64 blob. */ 02968 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) { 02969 int nbin; 02970 bin = xcalloc(1, 32); 02971 nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin); 02972 if (nbin <= 0) 02973 /*@innercontinue@*/ continue; 02974 key->data = bin; 02975 key->size = nbin; 02976 /*@switchbreak@*/ break; 02977 } 02978 /*@=boundsread@*/ 02979 /*@fallthrough@*/ 02980 default: 02981 /*@i@*/ key->data = (void *) rpmvals[i]; 02982 key->size = strlen(rpmvals[i]); 02983 stringvalued = 1; 02984 /*@switchbreak@*/ break; 02985 } 02986 02987 if (!printed) { 02988 if (rpmcnt == 1 && stringvalued) { 02989 rpmMessage(RPMMESS_DEBUG, 02990 D_("removing \"%s\" from %s index.\n"), 02991 (char *)key->data, mapTagName(dbi->dbi_rpmtag)); 02992 } else { 02993 rpmMessage(RPMMESS_DEBUG, 02994 D_("removing %d entries from %s index.\n"), 02995 rpmcnt, mapTagName(dbi->dbi_rpmtag)); 02996 } 02997 printed++; 02998 } 02999 03000 /* XXX 03001 * This is almost right, but, if there are duplicate tag 03002 * values, there will be duplicate attempts to remove 03003 * the header instance. It's faster to just ignore errors 03004 * than to do things correctly. 03005 */ 03006 03007 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */ 03008 03009 set = NULL; 03010 03011 if (key->size == 0) key->size = strlen((char *)key->data); 03012 if (key->size == 0) key->size++; /* XXX "/" fixup. */ 03013 03014 /*@-compmempass@*/ 03015 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 03016 if (rc == 0) { /* success */ 03017 (void) dbt2set(dbi, data, &set); 03018 } else if (rc == DB_NOTFOUND) { /* not found */ 03019 /*@innercontinue@*/ continue; 03020 } else { /* error */ 03021 rpmError(RPMERR_DBGETINDEX, 03022 _("error(%d) setting \"%s\" records from %s index\n"), 03023 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 03024 ret += 1; 03025 /*@innercontinue@*/ continue; 03026 } 03027 /*@=compmempass@*/ 03028 03029 rc = dbiPruneSet(set, rec, 1, sizeof(*rec), 1); 03030 03031 /* If nothing was pruned, then don't bother updating. */ 03032 if (rc) { 03033 set = dbiFreeIndexSet(set); 03034 /*@innercontinue@*/ continue; 03035 } 03036 03037 /*@-compmempass@*/ 03038 if (set->count > 0) { 03039 (void) set2dbt(dbi, data, set); 03040 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST); 03041 if (rc) { 03042 rpmError(RPMERR_DBPUTINDEX, 03043 _("error(%d) storing record \"%s\" into %s\n"), 03044 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 03045 ret += 1; 03046 } 03047 data->data = _free(data->data); 03048 data->size = 0; 03049 } else { 03050 rc = dbiDel(dbi, dbcursor, key, data, 0); 03051 if (rc) { 03052 rpmError(RPMERR_DBPUTINDEX, 03053 _("error(%d) removing record \"%s\" from %s\n"), 03054 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 03055 ret += 1; 03056 } 03057 } 03058 /*@=compmempass@*/ 03059 set = dbiFreeIndexSet(set); 03060 } 03061 /*@=branchstate@*/ 03062 03063 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 03064 dbcursor = NULL; 03065 03066 if (!dbi->dbi_no_dbsync) 03067 xx = dbiSync(dbi, 0); 03068 } 03069 03070 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */ 03071 rpmvals = hfd(rpmvals, rpmtype); 03072 rpmtype = 0; 03073 rpmcnt = 0; 03074 bin = _free(bin); 03075 } 03076 03077 rec = _free(rec); 03078 } 03079 /*@=nullpass =nullptrarith =nullderef @*/ 03080 03081 (void) unblockSignals(db, &signalMask); 03082 03083 h = headerFree(h); 03084 03085 /* XXX return ret; */ 03086 return 0; 03087 } 03088 03089 /* XXX install.c */ 03090 int rpmdbAdd(rpmdb db, int iid, Header h, 03091 /*@unused@*/ rpmts ts, 03092 /*@unused@*/ rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg)) 03093 { 03094 DBC * dbcursor = NULL; 03095 DBT * key = alloca(sizeof(*key)); 03096 DBT * data = alloca(sizeof(*data)); 03097 HGE_t hge = (HGE_t) headerGetEntryMinMemory; 03098 HAE_t hae = (HAE_t) headerAddEntry; 03099 HFD_t hfd = headerFreeData; 03100 sigset_t signalMask; 03101 const char ** baseNames; 03102 rpmTagType bnt; 03103 const char ** dirNames; 03104 int_32 * dirIndexes; 03105 rpmTagType dit, dnt; 03106 int count = 0; 03107 dbiIndex dbi; 03108 int dbix; 03109 union _dbswap mi_offset; 03110 unsigned int hdrNum = 0; 03111 int ret = 0; 03112 int rc; 03113 int xx; 03114 03115 /* Initialize the header instance */ 03116 (void) headerSetInstance(h, 0); 03117 03118 if (db == NULL) 03119 return 0; 03120 03121 memset(key, 0, sizeof(*key)); 03122 memset(data, 0, sizeof(*data)); 03123 03124 #ifdef NOTYET /* XXX headerRemoveEntry() broken on dribbles. */ 03125 xx = headerRemoveEntry(h, RPMTAG_REMOVETID); 03126 #endif 03127 if (iid != 0 && iid != -1) { 03128 int_32 tid = iid; 03129 if (!headerIsEntry(h, RPMTAG_INSTALLTID)) 03130 xx = hae(h, RPMTAG_INSTALLTID, RPM_INT32_TYPE, &tid, 1); 03131 } 03132 03133 /* Add the package color if not present. */ 03134 if (!headerIsEntry(h, RPMTAG_PACKAGECOLOR)) { 03135 uint32_t hcolor = hGetColor(h); 03136 xx = hae(h, RPMTAG_PACKAGECOLOR, RPM_INT32_TYPE, &hcolor, 1); 03137 } 03138 03139 /* 03140 * If old style filename tags is requested, the basenames need to be 03141 * retrieved early, and the header needs to be converted before 03142 * being written to the package header database. 03143 */ 03144 03145 xx = hge(h, RPMTAG_BASENAMES, &bnt, &baseNames, &count); 03146 xx = hge(h, RPMTAG_DIRINDEXES, &dit, &dirIndexes, NULL); 03147 xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL); 03148 03149 (void) blockSignals(db, &signalMask); 03150 03151 { 03152 unsigned int firstkey = 0; 03153 void * keyp = &firstkey; 03154 size_t keylen = sizeof(firstkey); 03155 void * datap = NULL; 03156 size_t datalen = 0; 03157 03158 dbi = dbiOpen(db, RPMDBI_PACKAGES, 0); 03159 /*@-branchstate@*/ 03160 if (dbi != NULL) { 03161 03162 /* XXX db0: hack to pass sizeof header to fadAlloc */ 03163 datap = h; 03164 datalen = headerSizeof(h, HEADER_MAGIC_NO); 03165 03166 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR); 03167 03168 /* Retrieve join key for next header instance. */ 03169 03170 /*@-compmempass@*/ 03171 key->data = keyp; 03172 key->size = keylen; 03173 /*@i@*/ data->data = datap; 03174 data->size = datalen; 03175 ret = dbiGet(dbi, dbcursor, key, data, DB_SET); 03176 keyp = key->data; 03177 keylen = key->size; 03178 datap = data->data; 03179 datalen = data->size; 03180 /*@=compmempass@*/ 03181 03182 /*@-bounds@*/ 03183 hdrNum = 0; 03184 if (ret == 0 && datap) { 03185 memcpy(&mi_offset, datap, sizeof(mi_offset.ui)); 03186 if (dbiByteSwapped(dbi) == 1) 03187 _DBSWAP(mi_offset); 03188 hdrNum = mi_offset.ui; 03189 } 03190 ++hdrNum; 03191 mi_offset.ui = hdrNum; 03192 if (dbiByteSwapped(dbi) == 1) 03193 _DBSWAP(mi_offset); 03194 if (ret == 0 && datap) { 03195 memcpy(datap, &mi_offset, sizeof(mi_offset.ui)); 03196 } else { 03197 datap = &mi_offset; 03198 datalen = sizeof(mi_offset.ui); 03199 } 03200 /*@=bounds@*/ 03201 03202 key->data = keyp; 03203 key->size = keylen; 03204 /*@-kepttrans@*/ 03205 data->data = datap; 03206 /*@=kepttrans@*/ 03207 data->size = datalen; 03208 03209 /*@-compmempass@*/ 03210 ret = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST); 03211 /*@=compmempass@*/ 03212 xx = dbiSync(dbi, 0); 03213 03214 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 03215 dbcursor = NULL; 03216 } 03217 /*@=branchstate@*/ 03218 03219 } 03220 03221 if (ret) { 03222 rpmError(RPMERR_DBCORRUPT, 03223 _("error(%d) allocating new package instance\n"), ret); 03224 goto exit; 03225 } 03226 03227 /* Now update the indexes */ 03228 03229 if (hdrNum) 03230 { 03231 dbiIndexItem rec = dbiIndexNewItem(hdrNum, 0); 03232 03233 /* Save the header instance. */ 03234 (void) headerSetInstance(h, hdrNum); 03235 03236 if (db->db_tagn != NULL) 03237 for (dbix = 0; dbix < db->db_ndbi; dbix++) { 03238 const char *av[1]; 03239 const char **rpmvals = NULL; 03240 byte * bin = NULL; 03241 rpmTagType rpmtype = 0; 03242 int rpmcnt = 0; 03243 int rpmtag; 03244 int_32 * requireFlags; 03245 rpmRC rpmrc; 03246 int i, j; 03247 03248 rpmrc = RPMRC_NOTFOUND; 03249 dbi = NULL; 03250 requireFlags = NULL; 03251 /*@-boundsread@*/ 03252 rpmtag = db->db_tagn[dbix]; 03253 /*@=boundsread@*/ 03254 03255 switch (rpmtag) { 03256 /* Filter out temporary databases */ 03257 case RPMDBI_AVAILABLE: 03258 case RPMDBI_ADDED: 03259 case RPMDBI_REMOVED: 03260 case RPMDBI_DEPENDS: 03261 continue; 03262 /*@notreached@*/ /*@switchbreak@*/ break; 03263 case RPMDBI_PACKAGES: 03264 if (db->db_export != NULL) 03265 xx = db->db_export(db, h, 1); 03266 dbi = dbiOpen(db, rpmtag, 0); 03267 if (dbi == NULL) /* XXX shouldn't happen */ 03268 continue; 03269 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR); 03270 03271 mi_offset.ui = hdrNum; 03272 if (dbiByteSwapped(dbi) == 1) 03273 _DBSWAP(mi_offset); 03274 /*@-immediatetrans@*/ 03275 key->data = (void *) &mi_offset; 03276 /*@=immediatetrans@*/ 03277 key->size = sizeof(mi_offset.ui); 03278 data->data = headerUnload(h); 03279 data->size = headerSizeof(h, HEADER_MAGIC_NO); 03280 03281 /* Check header digest/signature on blob export. */ 03282 if (hdrchk && ts) { 03283 const char * msg = NULL; 03284 int lvl; 03285 03286 rpmrc = (*hdrchk) (ts, data->data, data->size, &msg); 03287 lvl = (rpmrc == RPMRC_FAIL ? RPMMESS_ERROR : RPMMESS_DEBUG); 03288 rpmMessage(lvl, "%s h#%8u %s", 03289 (rpmrc == RPMRC_FAIL ? _("rpmdbAdd: skipping") : " +++"), 03290 hdrNum, (msg ? msg : "\n")); 03291 msg = _free(msg); 03292 } 03293 03294 if (data->data != NULL && rpmrc != RPMRC_FAIL) { 03295 /*@-compmempass@*/ 03296 xx = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST); 03297 /*@=compmempass@*/ 03298 xx = dbiSync(dbi, 0); 03299 } 03300 data->data = _free(data->data); 03301 data->size = 0; 03302 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 03303 dbcursor = NULL; 03304 if (!dbi->dbi_no_dbsync) 03305 xx = dbiSync(dbi, 0); 03306 continue; 03307 /*@notreached@*/ /*@switchbreak@*/ break; 03308 case RPMTAG_BASENAMES: /* XXX preserve legacy behavior */ 03309 rpmtype = bnt; 03310 rpmvals = baseNames; 03311 rpmcnt = count; 03312 /*@switchbreak@*/ break; 03313 case RPMTAG_REQUIRENAME: 03314 xx = hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt); 03315 xx = hge(h, RPMTAG_REQUIREFLAGS, NULL, &requireFlags, NULL); 03316 /*@switchbreak@*/ break; 03317 default: 03318 xx = hge(h, rpmtag, &rpmtype, &rpmvals, &rpmcnt); 03319 /*@switchbreak@*/ break; 03320 } 03321 03322 /*@-branchstate@*/ 03323 if (rpmcnt <= 0) { 03324 if (rpmtag != RPMTAG_GROUP) 03325 continue; 03326 03327 /* XXX preserve legacy behavior */ 03328 rpmtype = RPM_STRING_TYPE; 03329 rpmvals = (const char **) "Unknown"; 03330 rpmcnt = 1; 03331 } 03332 /*@=branchstate@*/ 03333 03334 dbi = dbiOpen(db, rpmtag, 0); 03335 if (dbi != NULL) { 03336 int printed; 03337 03338 if (rpmtype == RPM_STRING_TYPE) { 03339 /* XXX force uniform headerGetEntry return */ 03340 /*@-observertrans@*/ 03341 av[0] = (const char *) rpmvals; 03342 /*@=observertrans@*/ 03343 rpmvals = av; 03344 rpmcnt = 1; 03345 } 03346 03347 printed = 0; 03348 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR); 03349 03350 /*@-branchstate@*/ 03351 for (i = 0; i < rpmcnt; i++) { 03352 dbiIndexSet set; 03353 int stringvalued; 03354 03355 bin = _free(bin); 03356 /* 03357 * Include the tagNum in all indices. rpm-3.0.4 and earlier 03358 * included the tagNum only for files. 03359 */ 03360 rec->tagNum = i; 03361 switch (dbi->dbi_rpmtag) { 03362 case RPMTAG_BASENAMES: 03363 /* tag index entry with directory hash */ 03364 if (_db_tagged_file_indices && i < 0x010000) 03365 rec->tagNum |= taghash(dirNames[dirIndexes[i]]); 03366 /*@switchbreak@*/ break; 03367 case RPMTAG_PUBKEYS: 03368 /*@switchbreak@*/ break; 03369 case RPMTAG_FILEMD5S: 03370 /* Filter out empty MD5 strings. */ 03371 if (!(rpmvals[i] && *rpmvals[i] != '\0')) 03372 /*@innercontinue@*/ continue; 03373 /*@switchbreak@*/ break; 03374 case RPMTAG_REQUIRENAME: 03375 /* Filter out install prerequisites. */ 03376 if (requireFlags && isInstallPreReq(requireFlags[i])) 03377 /*@innercontinue@*/ continue; 03378 /*@switchbreak@*/ break; 03379 case RPMTAG_TRIGGERNAME: 03380 if (i) { /* don't add duplicates */ 03381 /*@-boundsread@*/ 03382 for (j = 0; j < i; j++) { 03383 if (!strcmp(rpmvals[i], rpmvals[j])) 03384 /*@innerbreak@*/ break; 03385 } 03386 /*@=boundsread@*/ 03387 if (j < i) 03388 /*@innercontinue@*/ continue; 03389 } 03390 /*@switchbreak@*/ break; 03391 default: 03392 /*@switchbreak@*/ break; 03393 } 03394 03395 /* Identify value pointer and length. */ 03396 stringvalued = 0; 03397 switch (rpmtype) { 03398 /*@-sizeoftype@*/ 03399 case RPM_CHAR_TYPE: 03400 case RPM_INT8_TYPE: 03401 key->size = sizeof(int_8); 03402 /*@i@*/ key->data = rpmvals + i; 03403 /*@switchbreak@*/ break; 03404 case RPM_INT16_TYPE: 03405 key->size = sizeof(int_16); 03406 /*@i@*/ key->data = rpmvals + i; 03407 /*@switchbreak@*/ break; 03408 case RPM_INT32_TYPE: 03409 key->size = sizeof(int_32); 03410 /*@i@*/ key->data = rpmvals + i; 03411 /*@switchbreak@*/ break; 03412 /*@=sizeoftype@*/ 03413 case RPM_BIN_TYPE: 03414 key->size = rpmcnt; 03415 /*@i@*/ key->data = rpmvals; 03416 rpmcnt = 1; /* XXX break out of loop. */ 03417 /*@switchbreak@*/ break; 03418 case RPM_STRING_TYPE: 03419 case RPM_I18NSTRING_TYPE: 03420 rpmcnt = 1; /* XXX break out of loop. */ 03421 /*@fallthrough@*/ 03422 case RPM_STRING_ARRAY_TYPE: 03423 /* Convert from hex to binary. */ 03424 /*@-boundsread@*/ 03425 if (dbi->dbi_rpmtag == RPMTAG_FILEDIGESTS) { 03426 const char * s = rpmvals[i]; 03427 size_t dlen = strlen(s); 03428 byte * t; 03429 assert((dlen & 1) == 0); 03430 dlen /= 2; 03431 bin = t = xcalloc(1, dlen); 03432 for (j = 0; j < dlen; j++, t++, s += 2) 03433 *t = (nibble(s[0]) << 4) | nibble(s[1]); 03434 key->data = bin; 03435 key->size = dlen; 03436 /*@switchbreak@*/ break; 03437 } 03438 /* Extract the pubkey id from the base64 blob. */ 03439 if (dbi->dbi_rpmtag == RPMTAG_PUBKEYS) { 03440 int nbin; 03441 bin = xcalloc(1, 32); 03442 nbin = pgpExtractPubkeyFingerprint(rpmvals[i], bin); 03443 if (nbin <= 0) 03444 /*@innercontinue@*/ continue; 03445 key->data = bin; 03446 key->size = nbin; 03447 /*@switchbreak@*/ break; 03448 } 03449 /*@=boundsread@*/ 03450 /*@fallthrough@*/ 03451 default: 03452 /*@i@*/ key->data = (void *) rpmvals[i]; 03453 key->size = strlen(rpmvals[i]); 03454 stringvalued = 1; 03455 /*@switchbreak@*/ break; 03456 } 03457 03458 if (!printed) { 03459 if (rpmcnt == 1 && stringvalued) { 03460 rpmMessage(RPMMESS_DEBUG, 03461 D_("adding \"%s\" to %s index.\n"), 03462 (char *)key->data, mapTagName(dbi->dbi_rpmtag)); 03463 } else { 03464 rpmMessage(RPMMESS_DEBUG, 03465 D_("adding %d entries to %s index.\n"), 03466 rpmcnt, mapTagName(dbi->dbi_rpmtag)); 03467 } 03468 printed++; 03469 } 03470 03471 /* XXX with duplicates, an accurate data value and DB_GET_BOTH is needed. */ 03472 03473 set = NULL; 03474 03475 if (key->size == 0) key->size = strlen((char *)key->data); 03476 if (key->size == 0) key->size++; /* XXX "/" fixup. */ 03477 03478 /*@-compmempass@*/ 03479 rc = dbiGet(dbi, dbcursor, key, data, DB_SET); 03480 if (rc == 0) { /* success */ 03481 /* With duplicates, cursor is positioned, discard the record. */ 03482 if (!dbi->dbi_permit_dups) 03483 (void) dbt2set(dbi, data, &set); 03484 } else if (rc != DB_NOTFOUND) { /* error */ 03485 rpmError(RPMERR_DBGETINDEX, 03486 _("error(%d) getting \"%s\" records from %s index\n"), 03487 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 03488 ret += 1; 03489 /*@innercontinue@*/ continue; 03490 } 03491 /*@=compmempass@*/ 03492 03493 if (set == NULL) /* not found or duplicate */ 03494 set = xcalloc(1, sizeof(*set)); 03495 03496 (void) dbiAppendSet(set, rec, 1, sizeof(*rec), 0); 03497 03498 /*@-compmempass@*/ 03499 (void) set2dbt(dbi, data, set); 03500 rc = dbiPut(dbi, dbcursor, key, data, DB_KEYLAST); 03501 /*@=compmempass@*/ 03502 03503 if (rc) { 03504 rpmError(RPMERR_DBPUTINDEX, 03505 _("error(%d) storing record %s into %s\n"), 03506 rc, key->data, mapTagName(dbi->dbi_rpmtag)); 03507 ret += 1; 03508 } 03509 /*@-unqualifiedtrans@*/ 03510 data->data = _free(data->data); 03511 /*@=unqualifiedtrans@*/ 03512 data->size = 0; 03513 set = dbiFreeIndexSet(set); 03514 } 03515 /*@=branchstate@*/ 03516 03517 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 03518 dbcursor = NULL; 03519 03520 if (!dbi->dbi_no_dbsync) 03521 xx = dbiSync(dbi, 0); 03522 } 03523 03524 /*@-observertrans@*/ 03525 if (rpmtype != RPM_BIN_TYPE) /* XXX WTFO? HACK ALERT */ 03526 rpmvals = hfd(rpmvals, rpmtype); 03527 /*@=observertrans@*/ 03528 rpmtype = 0; 03529 rpmcnt = 0; 03530 bin = _free(bin); 03531 } 03532 /*@=nullpass =nullptrarith =nullderef @*/ 03533 03534 rec = _free(rec); 03535 } 03536 03537 exit: 03538 (void) unblockSignals(db, &signalMask); 03539 dirIndexes = hfd(dirIndexes, dit); 03540 dirNames = hfd(dirNames, dnt); 03541 03542 return ret; 03543 } 03544 03545 /* XXX transaction.c */ 03546 /*@-compmempass@*/ 03547 int rpmdbFindFpList(rpmdb db, fingerPrint * fpList, dbiIndexSet * matchList, 03548 int numItems, unsigned int exclude) 03549 { 03550 DBT * key; 03551 DBT * data; 03552 HGE_t hge = (HGE_t)headerGetEntryMinMemory; 03553 HFD_t hfd = headerFreeData; 03554 rpmdbMatchIterator mi; 03555 fingerPrintCache fpc; 03556 Header h; 03557 int i, xx; 03558 03559 if (db == NULL) return 0; 03560 03561 mi = rpmdbInitIterator(db, RPMTAG_BASENAMES, NULL, 0); 03562 assert(mi); /* XXX will never happen. */ 03563 if (mi == NULL) 03564 return 2; 03565 03566 key = &mi->mi_key; 03567 data = &mi->mi_data; 03568 03569 /* Gather all installed headers with matching basename's. */ 03570 for (i = 0; i < numItems; i++) { 03571 unsigned int tag; 03572 03573 /*@-boundswrite@*/ 03574 matchList[i] = xcalloc(1, sizeof(*(matchList[i]))); 03575 /*@=boundswrite@*/ 03576 03577 /*@-boundsread -dependenttrans@*/ 03578 key->data = (void *) fpList[i].baseName; 03579 /*@=boundsread =dependenttrans@*/ 03580 key->size = strlen((char *)key->data); 03581 if (key->size == 0) key->size++; /* XXX "/" fixup. */ 03582 03583 tag = (_db_tagged_file_indices ? taghash(fpList[i].entry->dirName) : 0); 03584 xx = rpmdbGrowIterator(mi, i, exclude, tag); 03585 03586 } 03587 03588 if ((i = rpmdbGetIteratorCount(mi)) == 0) { 03589 mi = rpmdbFreeIterator(mi); 03590 return 0; 03591 } 03592 fpc = fpCacheCreate(i); 03593 03594 rpmdbSortIterator(mi); 03595 /* iterator is now sorted by (recnum, filenum) */ 03596 03597 /* For all installed headers with matching basename's ... */ 03598 if (mi != NULL) 03599 while ((h = rpmdbNextIterator(mi)) != NULL) { 03600 const char ** dirNames; 03601 const char ** baseNames; 03602 const char ** fullBaseNames; 03603 rpmTagType bnt, dnt; 03604 uint_32 * dirIndexes; 03605 uint_32 * fullDirIndexes; 03606 fingerPrint * fps; 03607 dbiIndexItem im; 03608 int start; 03609 int num; 03610 int end; 03611 03612 start = mi->mi_setx - 1; 03613 im = mi->mi_set->recs + start; 03614 03615 /* Find the end of the set of matched basename's in this package. */ 03616 /*@-boundsread@*/ 03617 for (end = start + 1; end < mi->mi_set->count; end++) { 03618 if (im->hdrNum != mi->mi_set->recs[end].hdrNum) 03619 /*@innerbreak@*/ break; 03620 } 03621 /*@=boundsread@*/ 03622 num = end - start; 03623 03624 /* Compute fingerprints for this installed header's matches */ 03625 xx = hge(h, RPMTAG_BASENAMES, &bnt, &fullBaseNames, NULL); 03626 xx = hge(h, RPMTAG_DIRNAMES, &dnt, &dirNames, NULL); 03627 xx = hge(h, RPMTAG_DIRINDEXES, NULL, &fullDirIndexes, NULL); 03628 03629 baseNames = xcalloc(num, sizeof(*baseNames)); 03630 dirIndexes = xcalloc(num, sizeof(*dirIndexes)); 03631 /*@-bounds@*/ 03632 for (i = 0; i < num; i++) { 03633 baseNames[i] = fullBaseNames[im[i].tagNum]; 03634 dirIndexes[i] = fullDirIndexes[im[i].tagNum]; 03635 } 03636 /*@=bounds@*/ 03637 03638 fps = xcalloc(num, sizeof(*fps)); 03639 fpLookupList(fpc, dirNames, baseNames, dirIndexes, num, fps); 03640 03641 /* Add db (recnum,filenum) to list for fingerprint matches. */ 03642 /*@-boundsread@*/ 03643 for (i = 0; i < num; i++, im++) { 03644 /*@-nullpass@*/ /* FIX: fpList[].subDir may be NULL */ 03645 if (!FP_EQUAL(fps[i], fpList[im->fpNum])) 03646 /*@innercontinue@*/ continue; 03647 /*@=nullpass@*/ 03648 xx = dbiAppendSet(matchList[im->fpNum], im, 1, sizeof(*im), 0); 03649 } 03650 /*@=boundsread@*/ 03651 03652 fps = _free(fps); 03653 dirNames = hfd(dirNames, dnt); 03654 fullBaseNames = hfd(fullBaseNames, bnt); 03655 baseNames = _free(baseNames); 03656 dirIndexes = _free(dirIndexes); 03657 03658 mi->mi_setx = end; 03659 } 03660 03661 mi = rpmdbFreeIterator(mi); 03662 03663 fpc = fpCacheFree(fpc); 03664 03665 return 0; 03666 03667 } 03668 /*@=compmempass@*/ 03669 03675 static int rpmioFileExists(const char * urlfn) 03676 /*@globals h_errno, fileSystem, internalState @*/ 03677 /*@modifies fileSystem, internalState @*/ 03678 { 03679 const char *fn; 03680 int urltype = urlPath(urlfn, &fn); 03681 struct stat buf; 03682 03683 /*@-branchstate@*/ 03684 if (*fn == '\0') fn = "/"; 03685 /*@=branchstate@*/ 03686 switch (urltype) { 03687 case URL_IS_HTTPS: /* XXX WRONG WRONG WRONG */ 03688 case URL_IS_HTTP: /* XXX WRONG WRONG WRONG */ 03689 case URL_IS_FTP: /* XXX WRONG WRONG WRONG */ 03690 case URL_IS_HKP: /* XXX WRONG WRONG WRONG */ 03691 case URL_IS_PATH: 03692 case URL_IS_UNKNOWN: 03693 if (Stat(fn, &buf)) { 03694 switch(errno) { 03695 case ENOENT: 03696 case EINVAL: 03697 return 0; 03698 } 03699 } 03700 break; 03701 case URL_IS_DASH: 03702 default: 03703 return 0; 03704 /*@notreached@*/ break; 03705 } 03706 03707 return 1; 03708 } 03709 03710 static int rpmdbRemoveDatabase(const char * prefix, 03711 const char * dbpath, int _dbapi, 03712 const int * dbiTags, int dbiTagsMax) 03713 /*@globals h_errno, fileSystem, internalState @*/ 03714 /*@modifies fileSystem, internalState @*/ 03715 { 03716 int i; 03717 char * filename; 03718 int xx; 03719 03720 i = strlen(dbpath); 03721 /*@-bounds -branchstate@*/ 03722 if (dbpath[i - 1] != '/') { 03723 filename = alloca(i); 03724 strcpy(filename, dbpath); 03725 filename[i] = '/'; 03726 filename[i + 1] = '\0'; 03727 dbpath = filename; 03728 } 03729 /*@=bounds =branchstate@*/ 03730 03731 filename = alloca(strlen(prefix) + strlen(dbpath) + 40); 03732 03733 switch (_dbapi) { 03734 case 4: 03735 /*@fallthrough@*/ 03736 case 3: 03737 /* Nuke the rpmdb tables. */ 03738 if (dbiTags != NULL) 03739 for (i = 0; i < dbiTagsMax; i++) { 03740 /*@-boundsread@*/ 03741 const char * base = mapTagName(dbiTags[i]); 03742 /*@=boundsread@*/ 03743 sprintf(filename, "%s/%s/%s", prefix, dbpath, base); 03744 (void)rpmCleanPath(filename); 03745 if (!rpmioFileExists(filename)) 03746 continue; 03747 xx = Unlink(filename); 03748 } 03749 /* Nuke the dbenv. */ 03750 for (i = 0; i < 16; i++) { 03751 sprintf(filename, "%s/%s/__db.%03d", prefix, dbpath, i); 03752 (void)rpmCleanPath(filename); 03753 if (!rpmioFileExists(filename)) 03754 continue; 03755 xx = Unlink(filename); 03756 } 03757 break; 03758 case 2: 03759 case 1: 03760 case 0: 03761 break; 03762 } 03763 03764 sprintf(filename, "%s/%s", prefix, dbpath); 03765 (void)rpmCleanPath(filename); 03766 xx = rmdir(filename); 03767 03768 return 0; 03769 } 03770 03771 static int rpmdbMoveDatabase(const char * prefix, 03772 const char * olddbpath, int _olddbapi, 03773 const char * newdbpath, /*@unused@*/ int _newdbapi, 03774 const int * dbiTags, int dbiTagsMax) 03775 /*@globals h_errno, fileSystem, internalState @*/ 03776 /*@modifies fileSystem, internalState @*/ 03777 { 03778 int i; 03779 char * ofn, * nfn; 03780 struct stat * nst = alloca(sizeof(*nst)); 03781 int rc = 0; 03782 int xx; 03783 int selinux = is_selinux_enabled() > 0 && (matchpathcon_init(NULL) != -1); 03784 sigset_t sigMask; 03785 03786 i = strlen(olddbpath); 03787 /*@-branchstate@*/ 03788 if (olddbpath[i - 1] != '/') { 03789 ofn = alloca(i + 2); 03790 strcpy(ofn, olddbpath); 03791 ofn[i] = '/'; 03792 ofn[i + 1] = '\0'; 03793 olddbpath = ofn; 03794 } 03795 /*@=branchstate@*/ 03796 03797 i = strlen(newdbpath); 03798 /*@-branchstate@*/ 03799 if (newdbpath[i - 1] != '/') { 03800 nfn = alloca(i + 2); 03801 strcpy(nfn, newdbpath); 03802 nfn[i] = '/'; 03803 nfn[i + 1] = '\0'; 03804 newdbpath = nfn; 03805 } 03806 /*@=branchstate@*/ 03807 03808 ofn = alloca(strlen(prefix) + strlen(olddbpath) + 40); 03809 nfn = alloca(strlen(prefix) + strlen(newdbpath) + 40); 03810 03811 blockSignals(NULL, &sigMask); 03812 switch (_olddbapi) { 03813 case 4: 03814 /* Fall through */ 03815 case 3: 03816 if (dbiTags != NULL) 03817 for (i = 0; i < dbiTagsMax; i++) { 03818 const char * base; 03819 int rpmtag; 03820 03821 /* Filter out temporary databases */ 03822 switch ((rpmtag = dbiTags[i])) { 03823 case RPMDBI_AVAILABLE: 03824 case RPMDBI_ADDED: 03825 case RPMDBI_REMOVED: 03826 case RPMDBI_DEPENDS: 03827 continue; 03828 /*@notreached@*/ /*@switchbreak@*/ break; 03829 default: 03830 /*@switchbreak@*/ break; 03831 } 03832 03833 base = mapTagName(rpmtag); 03834 sprintf(ofn, "%s/%s/%s", prefix, olddbpath, base); 03835 (void)rpmCleanPath(ofn); 03836 if (!rpmioFileExists(ofn)) 03837 continue; 03838 sprintf(nfn, "%s/%s/%s", prefix, newdbpath, base); 03839 (void)rpmCleanPath(nfn); 03840 03841 /* 03842 * Get uid/gid/mode/mtime. If old doesn't exist, use new. 03843 * XXX Yes, the variable names are backwards. 03844 */ 03845 if (stat(nfn, nst) < 0) 03846 if (stat(ofn, nst) < 0) 03847 continue; 03848 03849 if ((xx = rename(ofn, nfn)) != 0) { 03850 rc = 1; 03851 continue; 03852 } 03853 03854 /* Restore uid/gid/mode/mtime/security context if possible. */ 03855 xx = chown(nfn, nst->st_uid, nst->st_gid); 03856 xx = chmod(nfn, (nst->st_mode & 07777)); 03857 { struct utimbuf stamp; 03858 stamp.actime = nst->st_atime; 03859 stamp.modtime = nst->st_mtime; 03860 xx = utime(nfn, &stamp); 03861 } 03862 if (selinux) { 03863 security_context_t scon = NULL; 03864 if (matchpathcon(nfn, nst->st_mode, &scon) != -1) 03865 xx = setfilecon(nfn, scon); 03866 if (scon != NULL) 03867 freecon(scon); 03868 } 03869 } 03870 for (i = 0; i < 16; i++) { 03871 sprintf(ofn, "%s/%s/__db.%03d", prefix, olddbpath, i); 03872 (void)rpmCleanPath(ofn); 03873 if (rpmioFileExists(ofn)) 03874 xx = unlink(ofn); 03875 sprintf(nfn, "%s/%s/__db.%03d", prefix, newdbpath, i); 03876 (void)rpmCleanPath(nfn); 03877 if (rpmioFileExists(nfn)) 03878 xx = unlink(nfn); 03879 } 03880 break; 03881 case 2: 03882 case 1: 03883 case 0: 03884 break; 03885 } 03886 unblockSignals(NULL, &sigMask); 03887 03888 if (selinux) 03889 matchpathcon_fini(); 03890 return rc; 03891 } 03892 03893 int rpmdbRebuild(const char * prefix, rpmts ts, 03894 rpmRC (*hdrchk) (rpmts ts, const void *uh, size_t uc, const char ** msg)) 03895 /*@globals _rebuildinprogress @*/ 03896 /*@modifies _rebuildinprogress @*/ 03897 { 03898 rpmdb olddb; 03899 const char * dbpath = NULL; 03900 const char * rootdbpath = NULL; 03901 rpmdb newdb; 03902 const char * newdbpath = NULL; 03903 const char * newrootdbpath = NULL; 03904 const char * tfn; 03905 int nocleanup = 1; 03906 int failed = 0; 03907 int removedir = 0; 03908 int rc = 0, xx; 03909 int _dbapi; 03910 int _dbapi_rebuild; 03911 int * dbiTags = NULL; 03912 int dbiTagsMax = 0; 03913 03914 /*@-branchstate@*/ 03915 if (prefix == NULL) prefix = "/"; 03916 /*@=branchstate@*/ 03917 prefix = rpmGetPath(prefix, NULL); /* strip trailing '/' */ 03918 03919 _dbapi = rpmExpandNumeric("%{_dbapi}"); 03920 _dbapi_rebuild = rpmExpandNumeric("%{_dbapi_rebuild}"); 03921 03922 dbiTagsInit(&dbiTags, &dbiTagsMax); 03923 03924 /*@-nullpass@*/ 03925 tfn = rpmGetPath("%{?_dbpath}", NULL); 03926 /*@=nullpass@*/ 03927 /*@-boundsread@*/ 03928 if (!(tfn && tfn[0] != '\0')) 03929 /*@=boundsread@*/ 03930 { 03931 rpmMessage(RPMMESS_DEBUG, D_("no dbpath has been set")); 03932 rc = 1; 03933 goto exit; 03934 } 03935 dbpath = rootdbpath = rpmGetPath(prefix, tfn, NULL); 03936 if (!(prefix[0] == '/' && prefix[1] == '\0')) 03937 dbpath += strlen(prefix); 03938 tfn = _free(tfn); 03939 03940 /*@-nullpass@*/ 03941 tfn = rpmGetPath("%{?_dbpath_rebuild}", NULL); 03942 /*@=nullpass@*/ 03943 /*@-boundsread@*/ 03944 if (!(tfn && tfn[0] != '\0' && strcmp(tfn, dbpath))) 03945 /*@=boundsread@*/ 03946 { 03947 char pidbuf[20]; 03948 char *t; 03949 sprintf(pidbuf, "rebuilddb.%d", (int) getpid()); 03950 t = xmalloc(strlen(dbpath) + strlen(pidbuf) + 1); 03951 /*@-boundswrite@*/ 03952 (void)stpcpy(stpcpy(t, dbpath), pidbuf); 03953 /*@=boundswrite@*/ 03954 tfn = _free(tfn); 03955 tfn = t; 03956 nocleanup = 0; 03957 } 03958 newdbpath = newrootdbpath = rpmGetPath(prefix, tfn, NULL); 03959 if (!(prefix[0] == '/' && prefix[1] == '\0')) 03960 newdbpath += strlen(prefix) - 1; 03961 tfn = _free(tfn); 03962 03963 rpmMessage(RPMMESS_DEBUG, D_("rebuilding database %s into %s\n"), 03964 rootdbpath, newrootdbpath); 03965 03966 if (!Access(newrootdbpath, F_OK)) { 03967 rpmError(RPMERR_MKDIR, _("temporary database %s already exists\n"), 03968 newrootdbpath); 03969 rc = 1; 03970 goto exit; 03971 } 03972 03973 rpmMessage(RPMMESS_DEBUG, D_("creating directory %s\n"), newrootdbpath); 03974 if (Mkdir(newrootdbpath, 0755)) { 03975 rpmError(RPMERR_MKDIR, _("creating directory %s: %s\n"), 03976 newrootdbpath, strerror(errno)); 03977 rc = 1; 03978 goto exit; 03979 } 03980 removedir = 1; 03981 03982 _rebuildinprogress = 0; 03983 03984 rpmMessage(RPMMESS_DEBUG, D_("opening old database with dbapi %d\n"), 03985 _dbapi); 03986 /*@-boundswrite@*/ 03987 if (rpmdbOpenDatabase(prefix, dbpath, _dbapi, &olddb, O_RDONLY, 0644, 03988 RPMDB_FLAG_MINIMAL)) { 03989 rc = 1; 03990 goto exit; 03991 } 03992 /*@=boundswrite@*/ 03993 _dbapi = olddb->db_api; 03994 _rebuildinprogress = 1; 03995 rpmMessage(RPMMESS_DEBUG, D_("opening new database with dbapi %d\n"), 03996 _dbapi_rebuild); 03997 (void) rpmDefineMacro(NULL, "_rpmdb_rebuild %{nil}", -1); 03998 /*@-boundswrite@*/ 03999 if (rpmdbOpenDatabase(prefix, newdbpath, _dbapi_rebuild, &newdb, O_RDWR | O_CREAT, 0644, 0)) { 04000 rc = 1; 04001 goto exit; 04002 } 04003 /*@=boundswrite@*/ 04004 04005 _rebuildinprogress = 0; 04006 04007 _dbapi_rebuild = newdb->db_api; 04008 04009 { Header h = NULL; 04010 rpmdbMatchIterator mi; 04011 #define _RECNUM rpmdbGetIteratorOffset(mi) 04012 04013 mi = rpmdbInitIterator(olddb, RPMDBI_PACKAGES, NULL, 0); 04014 if (ts && hdrchk) 04015 (void) rpmdbSetHdrChk(mi, ts, hdrchk); 04016 04017 while ((h = rpmdbNextIterator(mi)) != NULL) { 04018 04019 /* let's sanity check this record a bit, otherwise just skip it */ 04020 if (!(headerIsEntry(h, RPMTAG_NAME) && 04021 headerIsEntry(h, RPMTAG_VERSION) && 04022 headerIsEntry(h, RPMTAG_RELEASE) && 04023 headerIsEntry(h, RPMTAG_BUILDTIME))) 04024 { 04025 rpmError(RPMERR_INTERNAL, 04026 _("header #%u in the database is bad -- skipping.\n"), 04027 _RECNUM); 04028 continue; 04029 } 04030 04031 /* Filter duplicate entries ? (bug in pre rpm-3.0.4) */ 04032 if (_db_filter_dups || newdb->db_filter_dups) { 04033 const char * name, * version, * release; 04034 int skip = 0; 04035 04036 (void) headerNVR(h, &name, &version, &release); 04037 04038 /*@-shadow@*/ 04039 { rpmdbMatchIterator mi; 04040 mi = rpmdbInitIterator(newdb, RPMTAG_NAME, name, 0); 04041 (void) rpmdbSetIteratorRE(mi, RPMTAG_VERSION, 04042 RPMMIRE_DEFAULT, version); 04043 (void) rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, 04044 RPMMIRE_DEFAULT, release); 04045 while (rpmdbNextIterator(mi)) { 04046 skip = 1; 04047 /*@innerbreak@*/ break; 04048 } 04049 mi = rpmdbFreeIterator(mi); 04050 } 04051 /*@=shadow@*/ 04052 04053 if (skip) 04054 continue; 04055 } 04056 04057 /* Deleted entries are eliminated in legacy headers by copy. */ 04058 { Header nh = (headerIsEntry(h, RPMTAG_HEADERIMAGE) 04059 ? headerCopy(h) : NULL); 04060 rc = rpmdbAdd(newdb, -1, (nh ? nh : h), ts, hdrchk); 04061 nh = headerFree(nh); 04062 } 04063 04064 if (rc) { 04065 rpmError(RPMERR_INTERNAL, 04066 _("cannot add record originally at %u\n"), _RECNUM); 04067 failed = 1; 04068 break; 04069 } 04070 } 04071 04072 mi = rpmdbFreeIterator(mi); 04073 04074 } 04075 04076 xx = rpmdbClose(olddb); 04077 xx = rpmdbClose(newdb); 04078 04079 if (failed) { 04080 rpmMessage(RPMMESS_NORMAL, _("failed to rebuild database: original database " 04081 "remains in place\n")); 04082 04083 xx = rpmdbRemoveDatabase(prefix, newdbpath, _dbapi_rebuild, 04084 dbiTags, dbiTagsMax); 04085 rc = 1; 04086 goto exit; 04087 } else if (!nocleanup) { 04088 xx = rpmdbMoveDatabase(prefix, newdbpath, _dbapi_rebuild, dbpath, _dbapi, 04089 dbiTags, dbiTagsMax); 04090 04091 if (xx) { 04092 rpmMessage(RPMMESS_ERROR, _("failed to replace old database with new " 04093 "database!\n")); 04094 rpmMessage(RPMMESS_ERROR, _("replace files in %s with files from %s " 04095 "to recover"), dbpath, newdbpath); 04096 rc = 1; 04097 goto exit; 04098 } 04099 } 04100 rc = 0; 04101 04102 exit: 04103 if (removedir && !(rc == 0 && nocleanup)) { 04104 rpmMessage(RPMMESS_DEBUG, D_("removing directory %s\n"), newrootdbpath); 04105 if (Rmdir(newrootdbpath)) 04106 rpmMessage(RPMMESS_ERROR, D_("failed to remove directory %s: %s\n"), 04107 newrootdbpath, strerror(errno)); 04108 } 04109 newrootdbpath = _free(newrootdbpath); 04110 rootdbpath = _free(rootdbpath); 04111 dbiTags = _free(dbiTags); 04112 prefix = _free(prefix); 04113 04114 return rc; 04115 }