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

Generated on Sat Apr 23 09:29:35 2005 for rpm by  doxygen 1.3.9.1