diff options
author | Sergey Poznyakoff <gray@gnu.org> | 2016-07-19 12:01:48 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2016-07-19 12:58:16 +0300 |
commit | 85f1e72da83e3078e2ae1f78093ef0966e43cec1 (patch) | |
tree | b00707979e9088d5f7b7880d438260eb063c9160 /src/gdbmtool.c | |
parent | 8e83f209342e2b035bbb19efa87ec5295158ef65 (diff) | |
download | gdbm-85f1e72da83e3078e2ae1f78093ef0966e43cec1.tar.gz gdbm-85f1e72da83e3078e2ae1f78093ef0966e43cec1.tar.bz2 |
Implement gdbm_recover function
* configure.ac: Don't check for rename.
* src/Makefile.am (libgdbm_la_SOURCES): Add recover.c
* src/recover.c: New file.
* src/bucket.c (_gdbm_get_bucket): Remove extra space before [
* src/err.c (prerror): Take additional argument
(gdbm_perror): Print system errno if necessary.
* src/gdbm.h.in (GDBM_CLOERROR): New flag.
(gdbm_fd_open, gdbm_copy_meta): New proto.
(gdbm_last_syserr,gdbm_db_strerror,gdbm_recover): New proto.
(gdbm_syserr): New extern.
(gdbm_recovery): New struct.
(GDBM_RCVR_DEFAULT,GDBM_RCVR_ERRFUN)
(GDBM_RCVR_MAX_FAILED_KEYS)
(GDBM_RCVR_MAX_FAILED_BUCKETS)
(GDBM_RCVR_MAX_FAILURES)
(GDBM_RCVR_BACKUP): New flags.
(GDBM_BACKUP_FAILED): New error code.
* src/gdbmclose.c (gdbm_close): Work correctly if dbf->desc == -1.
* src/gdbmcount.c (gdbm_count): Remove spurious sorting.
Use _gdbm_next_bucket_dir for iterating over the buckets.
* src/gdbmdefs.h (struct gdbm_file_info)<last_syserror>
<last_errstr>: New members.
* src/gdbmerrno.c (gdbm_set_errno): Set last_syserror as well.
(gdbm_clear_error): Reset last_syserror.
(gdbm_last_syserr): New function.
(gdbm_errlist): New entry for GDBM_BACKUP_FAILED.
(gdbm_db_strerror): New function.
(gdbm_syserr): New global.
* src/gdbmload.c (get_parms): Buffer can be NULL.
* src/gdbmopen.c (gdbm_fd_open): New function.
(gdbm_open): Rewrite as a wrapper over gdbm_fd_open.
* src/gdbmreorg.c (gdbm_reorganize): Rewrite as a wrapper
over gdbm_recover.
* src/proto.h (_gdbm_next_bucket_dir): New proto.
* src/gdbmtool.c: New command: recover.
* tests/.gitignore: Add gtrecover
* tests/gtrecover.c: New test program.
* tests/Makefile.am: Build gtrecover
Diffstat (limited to 'src/gdbmtool.c')
-rw-r--r-- | src/gdbmtool.c | 105 |
1 files changed, 104 insertions, 1 deletions
diff --git a/src/gdbmtool.c b/src/gdbmtool.c index bba68df..9c49403 100644 --- a/src/gdbmtool.c +++ b/src/gdbmtool.c @@ -531,6 +531,100 @@ reorganize_handler (struct handler_param *param GDBM_ARG_UNUSED) fprintf (stderr, _("Reorganization succeeded.\n")); } +static void +err_printer (void *data GDBM_ARG_UNUSED, char const *fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + vfprintf (stderr, fmt, ap); + va_end (ap); + fprintf (stderr, "\n"); +} + +/* recover verbose backup max-failed-keys=N max-failed-buckets=N max-failures=N */ +void +recover_handler (struct handler_param *param) +{ + gdbm_recovery rcvr; + int flags = 0; + int rc; + int i; + char *p; + + for (i = 1; i < param->argc; i++) + { + char *arg = PARAM_STRING (param, i); + if (strcmp (arg, "verbose") == 0) + { + rcvr.errfun = err_printer; + flags |= GDBM_RCVR_ERRFUN; + } + else if (strcmp (arg, "backup") == 0) + { + rcvr.errfun = err_printer; + flags |= GDBM_RCVR_BACKUP; + } + else if (strncmp (arg, "max-failures=", 13) == 0) + { + rcvr.max_failures = strtoul (arg + 13, &p, 10); + if (*p) + { + printf (_("not a number (stopped near %s)\n"), p); + return; + } + flags |= GDBM_RCVR_MAX_FAILURES; + } + else if (strncmp (arg, "max-failed-keys=", 16) == 0) + { + rcvr.max_failed_keys = strtoul (arg + 16, &p, 10); + if (*p) + { + printf (_("not a number (stopped near %s)\n"), p); + return; + } + flags |= GDBM_RCVR_MAX_FAILED_KEYS; + } + else if (strncmp (arg, "max-failed-buckets=", 19) == 0) + { + rcvr.max_failures = strtoul (arg + 19, &p, 10); + if (*p) + { + printf (_("not a number (stopped near %s)\n"), p); + return; + } + flags |= GDBM_RCVR_MAX_FAILED_BUCKETS; + } + else + { + terror (_("unrecognized argument: %s"), arg); + return; + } + } + + rc = gdbm_recover (gdbm_file, &rcvr, flags); + + if (rc == 0) + { + fprintf (param->fp, _("Recovery succeeded.\n")); + if (rcvr.backup_name) + { + fprintf (param->fp, + _("Original database preserved in file %s"), + rcvr.backup_name); + free (rcvr.backup_name); + } + fputc ('\n', param->fp); + } + else + { + fprintf (stderr, _("Recovery failed: %s"), gdbm_strerror (gdbm_errno)); + if (gdbm_syserr[gdbm_errno]) + fprintf (stderr, ": %s", strerror (errno)); + fputc ('\n', stderr); + } +} + /* avail - print available list */ int avail_begin (struct handler_param *param GDBM_ARG_UNUSED, size_t *exp_count) @@ -929,7 +1023,7 @@ struct argdef int ds; }; -#define NARGS 5 +#define NARGS 10 struct command { @@ -988,6 +1082,15 @@ struct command command_tab[] = { { S(reorganize), T_CMD, checkdb, reorganize_handler, NULL, { { NULL } }, N_("reorganize") }, + { S(recover), T_CMD, + checkdb, recover_handler, NULL, + { { "[verbose]", GDBM_ARG_STRING }, + { "[backup]", GDBM_ARG_STRING }, + { "[max-failed-keys=N]", GDBM_ARG_STRING }, + { "[max-failed-buckets=N]", GDBM_ARG_STRING }, + { "[max-failures=N]", GDBM_ARG_STRING }, + { NULL } }, + N_("recover the database") }, { S(avail), T_CMD, avail_begin, avail_handler, NULL, { { NULL } }, N_("print avail list") }, |