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

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

Generated on Sun Oct 26 13:02:03 2003 for rpm by doxygen1.2.18