Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

rpmdb.c

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

Generated on Mon Jun 13 13:40:04 2005 for rpm by  doxygen 1.3.9.1