[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