[packages/rpm] add rpmdbchk tool from proyvind
glen
glen at pld-linux.org
Wed Jan 7 14:12:00 CET 2015
commit 0004e9b0df65404717547955fbc58c6c018182f5
Author: Elan Ruusamäe <glen at delfi.ee>
Date: Wed Jan 7 14:59:42 2015 +0200
add rpmdbchk tool from proyvind
....4.14-no-assert-abort-with-broken-headers.patch | 11 +
rpm-5.4.14-rpmdbchk.patch | 334 +++++++++++++++++++++
rpm.spec | 14 +-
3 files changed, 358 insertions(+), 1 deletion(-)
---
diff --git a/rpm.spec b/rpm.spec
index bebd8ee..9f6bd99 100644
--- 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)
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
index 0000000..0b9278e
--- /dev/null
+++ b/rpm-5.4.14-no-assert-abort-with-broken-headers.patch
@@ -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
index 0000000..3587b1d
--- /dev/null
+++ b/rpm-5.4.14-rpmdbchk.patch
@@ -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;
++}
================================================================
---- gitweb:
http://git.pld-linux.org/gitweb.cgi/packages/rpm.git/commitdiff/0004e9b0df65404717547955fbc58c6c018182f5
More information about the pld-cvs-commit
mailing list