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