]> git.pld-linux.org Git - packages/rpm.git/commitdiff
add rpmdbchk tool from proyvind
authorElan Ruusamäe <glen@delfi.ee>
Wed, 7 Jan 2015 12:59:42 +0000 (14:59 +0200)
committerElan Ruusamäe <glen@delfi.ee>
Wed, 7 Jan 2015 13:11:43 +0000 (15:11 +0200)
rpm-5.4.14-no-assert-abort-with-broken-headers.patch [new file with mode: 0644]
rpm-5.4.14-rpmdbchk.patch [new file with mode: 0644]
rpm.spec

diff --git a/rpm-5.4.14-no-assert-abort-with-broken-headers.patch b/rpm-5.4.14-no-assert-abort-with-broken-headers.patch
new file mode 100644 (file)
index 0000000..0b9278e
--- /dev/null
@@ -0,0 +1,11 @@
+--- rpm-5.4.14/rpmdb/header.c.noassert~        2014-06-25 19:22:35.521902207 +0200
++++ rpm-5.4.14/rpmdb/header.c  2014-06-25 19:22:37.381920455 +0200
+@@ -1076,7 +1076,7 @@ assert(h != NULL);
+               rpmuint32_t * stei = (rpmuint32_t *)
+                       memcpy(alloca(nb), dataStart + off, nb);
+               rdl = (rpmuint32_t)-ntohl(stei[2]);     /* negative offset */
+-assert((rpmint32_t)rdl >= 0); /* XXX insurance */
++//assert((rpmint32_t)rdl >= 0);       /* XXX insurance */
+               ril = (rpmuint32_t)(rdl/sizeof(*pe));
+               if (hdrchkTags(ril) || hdrchkData(rdl))
+                   goto errxit;
diff --git a/rpm-5.4.14-rpmdbchk.patch b/rpm-5.4.14-rpmdbchk.patch
new file mode 100644 (file)
index 0000000..3587b1d
--- /dev/null
@@ -0,0 +1,334 @@
+--- rpm-5.4.14/tools/Makefile.am.rpmdbchk~     2013-08-18 21:40:58.000000000 +0200
++++ rpm-5.4.14/tools/Makefile.am       2014-02-17 17:52:10.032157038 +0100
+@@ -33,7 +33,7 @@ EXTRA_PROGRAMS += augtool cudftool dbcon
+       nix-build nix-channel nix-collect-garbage \
+       nix-log2xml nix-prefetch-url nix-pull nix-push \
+       xiu-echo xiu-hash \
+-      roto rpmkey sandbox semodule spooktool
++      roto rpmdbchk rpmkey sandbox semodule spooktool
+ RPMMISC_LDADD_COMMON = \
+       $(top_builddir)/misc/librpmmisc.la \
+@@ -64,7 +64,7 @@ pkgbin_PROGRAMS =    \
+       rpmcache rpmdigest rpmrepo rpmspecdump \
+       rpmcmp rpmdeps sqlite3 @WITH_KEYUTILS_RPMKEY@ @WITH_LIBELF_DEBUGEDIT@
+ if WITH_DB
+-pkgbin_PROGRAMS +=    dbconvert
++pkgbin_PROGRAMS +=    dbconvert rpmdbchk
+ endif
+ dist_man_MANS =               rpmgrep.1
+@@ -234,6 +234,13 @@ rpm2cpio_LDFLAGS =        @LDFLAGS_STATIC@ $(LD
+ rpm2cpio_LDADD =      $(LDFLAGS) $(RPM_LDADD_COMMON)
+ ##
++##  rpmdbchk tool for finding and fixing broken headers
++##
++rpmdbchk_SOURCES =      rpmdbchk.c
++rpmdbchk_LDFLAGS =    @LDFLAGS_STATIC@ $(LDFLAGS)
++rpmdbchk_LDADD =        $(LDFLAGS) $(RPM_LDADD_COMMON)
++
++##
+ ##  keyctl(1) clone
+ ##
+ rpmkey_SOURCES =        rpmkey.c
+--- rpm-5.4.14/tools/rpmdbchk.c.rpmdbchk~      2014-02-17 17:52:10.032157038 +0100
++++ rpm-5.4.14/tools/rpmdbchk.c        2014-02-17 17:52:28.846342856 +0100
+@@ -0,0 +1,297 @@
++#include <arpa/inet.h>
++#include <stdint.h>
++#include <sys/types.h>
++#include <sys/stat.h>
++#include <fcntl.h>
++#include <errno.h>
++#include <popt.h>
++
++#include <rpmio.h>
++#include <rpmlog.h>
++#include <rpmmacro.h>
++#include <argv.h>
++
++#define _RPMTAG_INTERNAL
++#define _RPMDB_INTERNAL
++#define WITH_DB
++#include <rpmdb.h>
++
++#include <rpmts.h>
++#include <rpmrc.h>
++#include <pkgio.h>
++#include <rpmcli.h>
++
++static char *rootPath = NULL;
++static char *rpmdbPath = NULL;
++static int checkOnly = 0;
++
++struct node {
++    uint32_t state;
++    uint32_t keysize;
++    void *keydata;
++    struct node *next;
++};
++
++static int
++rpmdb_check(uint32_t **state, uint32_t *nkeys, struct node **broken)
++{
++    rpmts ts = NULL;
++    DBC *dbcp = NULL;
++    dbiIndex dbi = NULL;
++    DBT key;
++    DBT data;
++    DB_TXN *txnid = NULL;
++    DB *bdb;
++
++    uint32_t hdrNum = 0;
++    uint32_t damaged = 0;
++    float pct = 0;
++    uint8_t tmp;
++
++    int xx;
++
++    ts = rpmtsCreate();
++
++    rpmtsSetRootDir(ts, rootPath && rootPath[0] ? rootPath : NULL);
++    if(rpmtsOpenDB(ts, O_RDONLY))
++      goto exit;
++
++    dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_PACKAGES, 0);
++
++    if ((xx = dbiCopen(dbi, NULL, NULL, 0)))
++      goto exit;
++
++    txnid = dbiTxnid(dbi);
++    *nkeys = 0;
++
++    memset(&key, 0, sizeof(key));
++    memset(&data, 0, sizeof(data));
++    bdb = dbi->dbi_db;
++
++    /* Acquire a cursor for the database. */
++    xx = bdb->cursor(bdb, NULL, &dbcp, 0);
++    if (xx)
++      bdb->err(bdb, xx, "DB->cursor");
++
++    xx = bdb->stat(bdb, txnid, &dbi->dbi_stats, 0);
++    if (xx)
++      goto exit;
++
++    switch (bdb->type) {
++    case DB_BTREE:
++    case DB_RECNO:{
++      DB_BTREE_STAT *db_stat = dbi->dbi_stats;
++      *nkeys = db_stat->bt_nkeys;
++    }   break;
++    case DB_HASH:{
++      DB_HASH_STAT *db_stat = dbi->dbi_stats;
++      *nkeys = db_stat->hash_nkeys;
++    }   break;
++    case DB_QUEUE:{
++      DB_QUEUE_STAT *db_stat = dbi->dbi_stats;
++      *nkeys = db_stat->qs_nkeys;
++    }   break;
++    case DB_UNKNOWN:
++    default:
++      xx = -1;
++      goto exit;
++      break;
++    }
++    uint32_t *status = calloc(*nkeys, sizeof(uint32_t));
++    struct node *curr;
++
++    hdrNum = 0;
++    pct = 0;
++
++    while ((xx = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
++      tmp = pct;
++      pct = (100 * (float) ++hdrNum / *nkeys) + 0.5;
++      /* TODO: callbacks for status output? */
++      if (tmp < (int) (pct + 0.5)) {
++          fprintf(stderr, "\rchecking %s%s/Packages: %u/%u %d%%",
++                      rootPath && rootPath[0] ? rootPath : "",
++                      rpmdbPath, hdrNum, *nkeys, (int) pct);
++      }
++      const char *msg = NULL;
++      int lvl = headerCheck(rpmtsDig(ts), data.data, data.size, &msg);
++      rpmtsCleanDig(ts);
++      if (lvl == RPMRC_FAIL) {
++          status[hdrNum-1] = htonl(*(uint32_t*)(dbcp->rkey->data));
++          damaged++;
++          fprintf(stderr, "\n%d (%d): %s\n", hdrNum-1, status[hdrNum-1], msg);
++      } else if (key.size != sizeof(hdrNum)) {
++          curr = malloc(sizeof(struct node));
++          curr->state = htonl(*(uint32_t*)(dbcp->rkey->data));
++          curr->keysize = key.size;
++          curr->keydata = malloc(key.size);
++          memcpy(curr->keydata, key.data, key.size);
++          curr->next = *broken;
++          *broken = curr;
++          status[hdrNum-1] = -1;
++          damaged++;
++          fprintf(stderr, "\n%d: %s (key.size(%d) != %d)\n", hdrNum-1, msg, key.size, sizeof(hdrNum));
++      } else
++          status[hdrNum-1] = -1;
++      fflush(stderr);
++    }
++
++    fprintf(stderr, "\n");
++
++
++    *state = status;
++    xx = dbiCclose(dbi, dbcp, 0);
++    
++exit:
++    xx = rpmtsCloseDB(ts);
++    ts = rpmtsFree(ts);
++
++    return damaged;
++}
++
++static int
++rpmdb_dump_delete(DB *dbp, const char *db, const char *lost, DBT *key, uint32_t n) {
++    int gotrec;
++    int ret = 0;
++    DBT data;
++
++    memset(&data, 0, sizeof(data));
++
++    if ((ret = dbp->get(dbp, NULL, key, &data, 0)) == 0) {
++      char copy[1024];
++      snprintf(copy, sizeof(copy), "%s/header.%d", lost, n);
++      FILE *fp = fopen(copy, "w");
++      fwrite(data.data, data.size, 1, fp);
++      fclose(fp);
++      gotrec = 0;
++      memcpy(&gotrec, key->data, sizeof(gotrec));
++      printf("db: get key: %p[%d] = 0x%x, data at %p[%d].\n",
++              (char *)key->data, key->size, gotrec,
++              (char *)data.data, data.size);
++      printf("Dumping broken header to disk: %s\n", copy);
++    } else {
++      dbp->err(dbp, ret, "DB->get");
++      if (ret == DB_NOTFOUND)
++          return 0;
++      return ret;
++    }
++
++    if ((ret = dbp->del(dbp, NULL, key, 0)) == 0) {
++      gotrec = 0;
++      memcpy(&gotrec, key->data, sizeof(gotrec));
++      printf("db: del key: %p[%d] = 0x%x, data at %p[%d].\n",
++              (char *)key->data, key->size, gotrec,
++              (char *)data.data, data.size);
++    } else {
++      dbp->err(dbp, ret, "DB->del");
++      return ret;
++    }
++    return 0;
++}
++
++static int
++rpmdb_fix(uint32_t *state, uint32_t nkeys, struct node *broken)
++{
++    DB * dbp;
++    DBT key;
++    struct stat sb;
++    const char * db = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/Packages", NULL);
++    const char * lost = rpmGetPath(rootPath && rootPath[0] ? rootPath : "", rpmdbPath, "/broken", NULL);
++    int ret, t_ret;
++    uint32_t i;
++
++
++    if ((ret = db_create(&dbp, NULL, 0)) != 0) {
++      fprintf(stderr, "db_create: %s\n", db_strerror(ret));
++      exit (1);
++    }
++
++    if (Stat(lost, &sb))
++      Mkdir(lost, 0700);
++
++    if ((ret = dbp->open(dbp, NULL, db, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
++      dbp->err(dbp, ret, "%s", db);
++      goto err;
++    }
++
++    for (i = 0; i < nkeys; i++) {
++      if (state[i] == -1) continue;
++      int badrec, badrec2;
++      memset(&key, 0, sizeof(key));
++      badrec2 = state[i];
++      badrec = htonl(badrec2);
++      printf("fix record[%d] at #%d/#%d --\n", i, badrec2, badrec);
++      key.data = &badrec;
++      key.size = sizeof(badrec);
++
++      ret = rpmdb_dump_delete(dbp, db, lost, &key, state[i]);
++    }
++
++    while (broken) {
++      memset(&key, 0, sizeof(key));
++      key.size = broken->keysize;
++      key.data = broken->keydata;
++      ret = rpmdb_dump_delete(dbp, db, lost, &key, broken->state);
++      free(broken->keydata);
++      free(broken);
++      broken = broken->next;
++    }
++
++
++err:
++    if ((t_ret = dbp->close(dbp, 0)) != 0 && ret == 0)
++      ret = t_ret; 
++    _free(db);
++    _free(lost);
++
++    return 0;
++}
++
++static struct poptOption optionsTable[] = {
++  { "root", '\0', POPT_ARG_STRING, &rootPath, 0,
++      "rpm root path", "path"},
++  { "dbpath", '\0', POPT_ARG_STRING, &rpmdbPath, 0,
++      "rpmdb path", "path"},
++  { "checkonly", '\0', POPT_ARG_VAL, &checkOnly, 1,
++      "only check, don't fix anything", NULL},  
++
++    POPT_AUTOALIAS
++    POPT_AUTOHELP
++    POPT_TABLEEND
++};
++
++int main(int argc, char *argv[])
++{
++    poptContext optCon = rpmcliInit(argc, argv, optionsTable);
++    ARGV_t av = poptGetArgs(optCon);
++    int ac = argvCount(av);
++    int rc = 2;               /* assume failure */
++    uint32_t nkeys = 0;
++    uint32_t *state = NULL;
++    struct node *broken = NULL;
++
++    if (ac) {
++      poptPrintUsage(optCon, stderr, 0);
++      goto exit;
++    }
++
++    rc = rpmReadConfigFiles(NULL, NULL);
++
++    if(!rpmdbPath)
++      rpmdbPath = rpmExpand("%{?_dbpath}%{?!_dbpath:/var/lib/rpm}", NULL);
++    else
++      addMacro(NULL, "_dbpath", NULL, rpmdbPath, -1);
++
++
++    rc = rpmdb_check(&state, &nkeys, &broken);
++    printf("%d/%d (%f%%) headers damaged", rc, nkeys, (float)rc/nkeys);
++    printf("\n");
++    if (!checkOnly && rc) {
++      printf("fixing...\n");
++      rc = rpmdb_fix(state, nkeys, broken);
++    }
++
++exit:
++    _free(state);
++    optCon = rpmcliFini(optCon);
++    return rc;
++}
index bebd8eedb845038f016260994d0e86ff3ed86c5d..9f6bd99d45aa3aade35a99d8f095ad6fcb741452 100644 (file)
--- a/rpm.spec
+++ b/rpm.spec
@@ -51,7 +51,7 @@ Summary(ru.UTF-8):    Менеджер пакетов от RPM
 Summary(uk.UTF-8):     Менеджер пакетів від RPM
 Name:          rpm
 Version:       5.4.15
-Release:       6
+Release:       7
 License:       LGPL v2.1
 Group:         Base
 # http://rpm5.org/files/rpm/rpm-5.4/rpm-5.4.15-0.20140824.src.rpm
@@ -278,6 +278,15 @@ Patch1044: %{name}-5.4.12-fix-rpmlua-print.patch
 Patch1045:     %{name}-5.4.12-fix-rpmpython-module-import-init.patch
 Patch1046:     %{name}-5.4.12-truncate-output-buffer-after-use.patch
 Patch1047:     %{name}-5.4.13-perl-bindings-do-not-use-xmalloc.patch
+# proyvind:
+# there's a rpmdbchk tool I wrote a while back, which might help you. although
+# the incidents it's able to deal with is rather limited ATM... it might help
+# you out, if not and you'll be able to solve yer problem, you could take a
+# stab at adding support for fixing your specific problem to the util ;)
+# https://abf.io/openmandriva/rpm/raw/master/rpm-5.4.14-rpmdbchk.patch
+Patch1048:     %{name}-5.4.14-rpmdbchk.patch
+# https://abf.io/openmandriva/rpm/raw/master/rpm-5.4.14-no-assert-abort-with-broken-headers.patch
+Patch1049:     %{name}-5.4.14-no-assert-abort-with-broken-headers.patch
 
 URL:           http://rpm5.org/
 BuildRequires: %{reqdb_pkg}-devel >= %{reqdb_pkgver}
@@ -970,6 +979,8 @@ Dokumentacja API RPM-a oraz przewodniki w formacie HTML generowane ze
 %patch1045 -p1
 %patch1046 -p1
 %patch1047 -p1
+%patch1048 -p1
+%patch1049 -p1
 
 %patch83 -p1
 
@@ -1385,6 +1396,7 @@ find %{_rpmlibdir} -name '*-linux' -type l | xargs rm -f
 %attr(755,root,root) %{_rpmlibdir}/bin/dbupgrade.sh
 %attr(755,root,root) %{_rpmlibdir}/bin/rpmdb_checkversion
 %attr(755,root,root) %{_rpmlibdir}/bin/rpmdb_reset
+%attr(755,root,root) %{_rpmlibdir}/bin/rpmdbchk
 
 %files base
 %defattr(644,root,root,755)
This page took 0.206396 seconds and 4 git commands to generate.