diff options
author | Colin Watson <cjwatson@debian.org> | 2009-08-22 15:36:11 +0100 |
---|---|---|
committer | Colin Watson <cjwatson@debian.org> | 2009-08-22 15:36:11 +0100 |
commit | dec775fc93131970035d5c2ecfe86bea4974032f (patch) | |
tree | b047c17db2d38a4c73ae58fd492f53c1a982f5ab | |
parent | be4324693660b678af2979d9503474fa09caf366 (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-- | ChangeLog | 19 | ||||
-rw-r--r-- | libdb/db_store.c | 24 | ||||
-rw-r--r-- | src/accessdb.c | 11 | ||||
-rw-r--r-- | src/check_mandirs.c | 30 |
4 files changed, 67 insertions, 17 deletions
@@ -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; } |