summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorColin Watson <cjwatson@debian.org>2009-08-22 15:36:11 +0100
committerColin Watson <cjwatson@debian.org>2009-08-22 15:36:11 +0100
commitdec775fc93131970035d5c2ecfe86bea4974032f (patch)
treeb047c17db2d38a4c73ae58fd492f53c1a982f5ab
parentbe4324693660b678af2979d9503474fa09caf366 (diff)
Cope with some more cases of database corruption (Debian bug
#187750). * libdb/db_store.c (dbstore): Always replace existing keys once we've decided we ought to. If the key already exists in the database, then that probably indicates some kind of database corruption, but our new key is almost certainly better. * src/check_mandirs.c (sanity_check_db): New function, checking dbver_rd and ensuring that all keys have non-NULL content. (update_db): Use sanity_check_db to decide whether an existing database is OK. * src/accessdb.c (main): If we encounter a key with no content, print a debugging message and continue as far as we can before exiting non-zero, rather than just silently exiting non-zero immediately.
-rw-r--r--ChangeLog19
-rw-r--r--libdb/db_store.c24
-rw-r--r--src/accessdb.c11
-rw-r--r--src/check_mandirs.c30
4 files changed, 67 insertions, 17 deletions
diff --git a/ChangeLog b/ChangeLog
index 554df34d..ea45dc51 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+Sat Aug 22 15:34:15 BST 2009 Colin Watson <cjwatson@debian.org>
+
+ Cope with some more cases of database corruption (Debian bug
+ #187750).
+
+ * libdb/db_store.c (dbstore): Always replace existing keys once
+ we've decided we ought to. If the key already exists in the
+ database, then that probably indicates some kind of database
+ corruption, but our new key is almost certainly better.
+ * src/check_mandirs.c (sanity_check_db): New function, checking
+ dbver_rd and ensuring that all keys have non-NULL content.
+ (update_db): Use sanity_check_db to decide whether an existing
+ database is OK.
+
+ * src/accessdb.c (main): If we encounter a key with no content,
+ print a debugging message and continue as far as we can before
+ exiting non-zero, rather than just silently exiting non-zero
+ immediately.
+
Sat Aug 22 14:58:39 BST 2009 Colin Watson <cjwatson@debian.org>
* src/tests/mandb-2: Run mandb with a clean path, and only on the
diff --git a/libdb/db_store.c b/libdb/db_store.c
index b7546bc3..08b501c8 100644
--- a/libdb/db_store.c
+++ b/libdb/db_store.c
@@ -42,13 +42,6 @@
#include "mydbm.h"
#include "db_storage.h"
-/* deal with situation where we cannot insert an unused key */
-static void gripe_insert_unused (char *data)
-{
- error (0, 0, _("cannot insert unused key %s"), data);
- gripe_corrupt_data ();
-}
-
/* compare_ids(a,b) is true if id 'a' is preferred to id 'b', i.e. if 'a' is
* a more canonical database entry than 'b'. This usually goes in comparison
* order, but there's a special exception when FAVOUR_STRAYCATS is set.
@@ -177,8 +170,8 @@ int dbstore (struct mandata *in, const char *base)
if (!STREQ (base, MYDBM_DPTR (oldkey)))
in->name = xstrdup (base);
oldcont = make_content (in);
- if (MYDBM_INSERT (dbf, oldkey, oldcont))
- gripe_insert_unused (MYDBM_DPTR (oldkey));
+ if (MYDBM_REPLACE (dbf, oldkey, oldcont))
+ gripe_replace_key (MYDBM_DPTR (oldkey));
free (MYDBM_DPTR (oldcont));
free (in->name);
in->name = NULL;
@@ -286,8 +279,13 @@ int dbstore (struct mandata *in, const char *base)
lastcont = make_content (&old);
- if (MYDBM_INSERT (dbf, lastkey, lastcont))
- gripe_insert_unused (MYDBM_DPTR (lastkey));
+ /* We always replace here; if the multi key already exists
+ * in the database, then that indicates some kind of
+ * database corruption, but our new multi key is almost
+ * certainly better.
+ */
+ if (MYDBM_REPLACE (dbf, lastkey, lastcont))
+ gripe_replace_key (MYDBM_DPTR (lastkey));
free (MYDBM_DPTR (lastkey));
free (MYDBM_DPTR (lastcont));
@@ -295,8 +293,8 @@ int dbstore (struct mandata *in, const char *base)
newkey = make_multi_key (base, in->ext);
newcont = make_content (in);
- if (MYDBM_INSERT (dbf, newkey, newcont))
- gripe_insert_unused (MYDBM_DPTR (newkey));
+ if (MYDBM_REPLACE (dbf, newkey, newcont))
+ gripe_replace_key (MYDBM_DPTR (newkey));
free (MYDBM_DPTR (newkey));
free (MYDBM_DPTR (newcont));
diff --git a/src/accessdb.c b/src/accessdb.c
index 9beb4ddb..cf04e0a0 100644
--- a/src/accessdb.c
+++ b/src/accessdb.c
@@ -106,6 +106,7 @@ static struct argp argp = { options, parse_opt, args_doc, doc, 0,
int main (int argc, char *argv[])
{
datum key;
+ int ret = OK;
program_name = base_name (argv[0]);
@@ -141,8 +142,11 @@ int main (int argc, char *argv[])
char *t, *nicekey;
content = MYDBM_FETCH (dbf, key);
- if (!MYDBM_DPTR (content))
- exit (FATAL);
+ if (!MYDBM_DPTR (content)) {
+ debug ("key %s has no content!\n", MYDBM_DPTR (key));
+ ret = FATAL;
+ goto next;
+ }
nicekey = xstrdup (MYDBM_DPTR (key));
while ( (t = strchr (nicekey, '\t')) )
*t = '~';
@@ -151,11 +155,12 @@ int main (int argc, char *argv[])
printf ("%s -> \"%s\"\n", nicekey, MYDBM_DPTR (content));
free (nicekey);
MYDBM_FREE (MYDBM_DPTR (content));
+next:
nextkey = MYDBM_NEXTKEY (dbf, key);
MYDBM_FREE (MYDBM_DPTR (key));
key = nextkey;
}
MYDBM_CLOSE (dbf);
- exit (OK);
+ exit (ret);
}
diff --git a/src/check_mandirs.c b/src/check_mandirs.c
index fd13e938..c21c744c 100644
--- a/src/check_mandirs.c
+++ b/src/check_mandirs.c
@@ -511,12 +511,40 @@ int create_db (const char *manpath, const char *catpath)
return amount;
}
+/* Make sure an existing database is essentially sane. */
+int sanity_check_db (void)
+{
+ datum key;
+
+ if (dbver_rd (dbf))
+ return 0;
+
+ key = MYDBM_FIRSTKEY (dbf);
+ while (MYDBM_DPTR (key) != NULL) {
+ datum content, nextkey;
+
+ content = MYDBM_FETCH (dbf, key);
+ if (!MYDBM_DPTR (content)) {
+ debug ("warning: %s has a key with no content (%s); "
+ "rebuilding\n", database, MYDBM_DPTR (key));
+ MYDBM_FREE (MYDBM_DPTR (key));
+ return 0;
+ }
+ MYDBM_FREE (MYDBM_DPTR (content));
+ nextkey = MYDBM_NEXTKEY (dbf, key);
+ MYDBM_FREE (MYDBM_DPTR (key));
+ key = nextkey;
+ }
+
+ return 1;
+}
+
/* routine to update the db, ensure that it is consistent with the
filesystem */
int update_db (const char *manpath, const char *catpath)
{
dbf = MYDBM_RDOPEN (database);
- if (dbf && dbver_rd (dbf)) {
+ if (dbf && !sanity_check_db ()) {
MYDBM_CLOSE (dbf);
dbf = NULL;
}