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