Convert oslfsck to lopsub.
authorAndre Noll <maan@tuebingen.mpg.de>
Sun, 28 Aug 2016 21:04:06 +0000 (23:04 +0200)
committerAndre Noll <maan@tuebingen.mpg.de>
Tue, 11 Apr 2017 12:44:29 +0000 (14:44 +0200)
The gengetopt project seems to be dead (last release was five years
ago), so we eventually need to switch to something else.

This commit migrates the option parser of oslfsck to the lopsub
library, which turned out to be rather simple. As a result, the osl
package no longer depends on gengetopt and help2man.

The change only affects the oslfsck executable. No changes to the
library proper.

.gitignore
INSTALL
Makefile
fsck.c
fsck.ggo [deleted file]
oslfsck.suite [new file with mode: 0644]

index 826d65d..907447f 100644 (file)
@@ -1,7 +1,7 @@
 *.[oa]
 foo
 bar*
-*cmdline.[ch]
+*lsg.[ch]
 osl.h
 osl_errors.h
 errtab.h
diff --git a/INSTALL b/INSTALL
index e370904..3bd8751 100644 (file)
--- a/INSTALL
+++ b/INSTALL
@@ -1,6 +1,9 @@
 As the bare minimum, you'll need gcc-4 and gnu make to install
-libosl. gengetopt is needed to build the oslfsck executable, and
-help2man to generate its man page.
+libosl. lopsub is needed to build the oslfsck executable and to
+generate its man page. Download and install lopsub with
+
+       git clone git://git.tuebingen.mpg.de/lopsub
+       cd lopsub && make && sudo make install
 
 If everything mentioned above is available on your system, type
 
index eeb5dcc..a4f5fad 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -6,7 +6,7 @@ bindir := $(PREFIX)/bin
 mandir := $(PREFIX)/man/man1
 
 objects := osl.o util.o rbtree.o sha1.o
-fsck_objects := fsck.fsck.o osl.fsck.o util.fsck.o rbtree.fsck.o sha1.fsck.o fsck.cmdline.o
+fsck_objects := fsck.fsck.o osl.fsck.o util.fsck.o rbtree.fsck.o sha1.fsck.o oslfsck.lsg.o
 headers := osl.h
 executables := oslfsck
 man_pages := oslfsck.1
@@ -119,31 +119,23 @@ osl.c fsck.c:
 
 -include Makefile.deps
 
-fsck.cmdline.o: fsck.cmdline.c fsck.cmdline.h
-       $(CC) -c -DVERSION='"$(VERSION)"' $<
-
-%.fsck.o: %.c Makefile fsck.cmdline.c fsck.cmdline.h osl.h errtab.h
-       $(CC) -c -DVERSION='"$(VERSION)"' $(CPPFLAGS) $(CFLAGS) $< -o $@
+%.fsck.o: %.c Makefile osl.h errtab.h oslfsck.lsg.h
+       $(CC) -c -DOSL_VERSION='"$(VERSION)"' $(CPPFLAGS) $(CFLAGS) $< -o $@
 
 %.o: %.c Makefile errtab.h
        $(CC) -c $(CPPFLAGS) $(CFLAGS) $(LIBCFLAGS) $<
 
-fsck.cmdline.h fsck.cmdline.c: fsck.ggo Makefile
-       gengetopt \
-               --conf-parser \
-               --unamed-opts=table \
-               --no-handle-version \
-               --file-name=fsck.cmdline \
-               --func-name=fsck_cmdline_parser \
-               --set-package="oslfsck" \
-               --arg-struct-name=fsck_args_info \
-               < $<
-
 oslfsck: $(fsck_objects)
-       $(CC) -o $@ $(fsck_objects)
+       $(CC) -o $@ $(fsck_objects) -llopsub
+
+%.lsg.c: %.suite
+       lopsubgen --gen-c < $<
+
+%.lsg.h: %.suite
+       lopsubgen --gen-header < $<
 
-oslfsck.1: oslfsck
-       help2man -h --detailed-help -N ./$< > $@
+%.1: %.suite
+       lopsubgen --gen-man=$@ < $<
 
 $(realname): $(objects)
        $(CC) $(LDFLAGS) -o $@ $(objects)
@@ -172,8 +164,8 @@ osl.h: osl.h.in osl_errors.h Makefile
        cat osl.h.in osl_errors.h >> $@
        echo '#endif /* _OSL_H */' >> $@
 clean:
-       rm -f *.o $(realname) osl.h osl_errors.h errtab.h fsck.cmdline.h \
-               fsck.cmdline.c oslfsck *.a *.ga *.sym
+       rm -f *.o $(realname) osl.h osl_errors.h errtab.h \
+               oslfsck *.a *.ga *.sym *.lsg.*
 
 distclean: clean
        rm -f web/index.html web/oslfsck.1.html web/osl.png
diff --git a/fsck.c b/fsck.c
index 9701f27..f96f77c 100644 (file)
--- a/fsck.c
+++ b/fsck.c
@@ -9,6 +9,7 @@
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <dirent.h>
+#include <lopsub.h>
 #include <assert.h>
 #include <pwd.h>
 
 #include "osl.h"
 #include "util.h"
 #include "osl_core.h"
-#include "fsck.cmdline.h"
-
-#define VERSION_TEXT(prefix) "osl" prefix " " VERSION " " "\n" \
-       "Copyright (C) 2008-2009 Andre Noll\n" \
-       "This is free software with ABSOLUTELY NO WARRANTY." \
-       " See COPYING for details.\n" \
-       "Written by Andre Noll.\n" \
-       "Report bugs to <maan@tuebingen.mpg.de>.\n"
-
-/** print out \p VERSION_TEXT and exit if version flag was given */
-#define HANDLE_VERSION_FLAG(_prefix, _args_info_struct) \
-       if (_args_info_struct.version_given) { \
-               printf("%s", VERSION_TEXT(_prefix)); \
-               exit(EXIT_SUCCESS); \
-       }
+#include "oslfsck.lsg.h"
 
-static struct fsck_args_info conf;
+static struct lls_parse_result *lpr;
+#define CMD_PTR (lls_cmd(0, oslfsck_suite))
+#define OPT_RESULT(_name) \
+       (lls_opt_result(LSG_OSLFSCK_OSLFSCK_OPT_ ## _name, lpr))
+#define OPT_GIVEN(_name) (lls_opt_given(OPT_RESULT(_name)))
+#define OPT_STRING_VAL(_name) (lls_string_val(0, OPT_RESULT(_name)))
+#define OPT_UINT32_VAL(_name) (lls_uint32_val(0, OPT_RESULT(_name)))
 
 #define FSCK_ERRORS \
        FSCK_ERROR(RANGE_VIOLATION, "range violation detected, very bad"), \
@@ -390,7 +383,7 @@ static int check_range(struct osl_table *t, uint32_t row_num, uint32_t col_num)
 
 static int fsck_mark_row_invalid(struct osl_table *t, int i)
 {
-       if (conf.dry_run_given)
+       if (OPT_GIVEN(DRY_RUN))
                return 0;
        return mark_row_invalid(t, i);
 }
@@ -474,7 +467,7 @@ static int prune_invalid_rows_from_index(struct osl_table *t)
        }
        NOTICE_LOG("index contains %u invalid row(s) (%d bytes)\n",
                t->num_invalid_rows, t->row_index_size * t->num_invalid_rows);
-       if (conf.dry_run_given)
+       if (OPT_GIVEN(DRY_RUN))
                return 0;
        NOTICE_LOG("removing invalid rows from index\n");
        bottom = t->num_rows - 1;
@@ -683,7 +676,7 @@ static int check_disk_storage_column(struct osl_table *t, int row_num,
                (*num_missing_objects)++;
                ERROR_LOG("row %d: object %s is missing\n", row_num, path);
                ret = 0;
-               if (conf.dry_run_given)
+               if (OPT_GIVEN(DRY_RUN))
                        goto out;
                NOTICE_LOG("trying to delete row %d\n", row_num);
                ret = osl_get_row(t, dsnc, &obj, &row);
@@ -804,7 +797,7 @@ static int prune_disk_storage_file(const char *path, void *private_data)
 invalid:
        ERROR_LOG("could not read hash value of %s\n", path);
 remove:
-       if (conf.dry_run_given)
+       if (OPT_GIVEN(DRY_RUN))
                return 0;
        NOTICE_LOG("removing %s\n", path);
        unlink(path);
@@ -896,7 +889,7 @@ static int fsck_init(struct osl_table_description *desc, struct osl_table **t)
        }
        DEBUG_LOG("unmapping index\n");
        osl_munmap(map.data, map.size);
-       if (conf.force_given)
+       if (OPT_GIVEN(FORCE))
                ret = map_table(*t, (MAP_TBL_FL_IGNORE_DIRTY));
        else
                ret = map_table(*t, 0);
@@ -1100,7 +1093,7 @@ out:
        return ret;
 }
 
-static int dump_table(char *dump_dir, struct osl_table_description *desc)
+static int dump_table(const char *dump_dir, struct osl_table_description *desc)
 {
        struct osl_table *t = NULL;
        int fd, ret = fsck_init(desc, &t);
@@ -1154,7 +1147,8 @@ static int fsck(struct osl_table_description *desc)
        ret = check_for_invalid_objects(t, &lost_bytes);
        if (ret < 0)
                goto out_unmap;
-       if (ret > 0 && !conf.dry_run_given) { /* at least one mapped data file needs pruning */
+       if (ret > 0 && !OPT_GIVEN(DRY_RUN)) {
+               /* at least one mapped data file needs pruning */
                ret = prune_objects(t, lost_bytes);
                if (ret < 0)
                        goto out_unmap;
@@ -1167,7 +1161,7 @@ out:
        return ret;
 }
 
-static int check_table(char *db_dir, char *table_name)
+static int check_table(const char *db_dir, const char *table_name)
 {
        struct osl_table_description desc = {
                .column_descriptions = NULL,
@@ -1177,15 +1171,15 @@ static int check_table(char *db_dir, char *table_name)
        int ret;
 
        INFO_LOG("checking table %s\n", table_name);
-       if (!conf.no_fsck_given) {
+       if (!OPT_GIVEN(NO_FSCK)) {
                ret = fsck(&desc);
                if (ret < 0)
                        goto out;
        }
        ret = 1;
-       if (!conf.dump_dir_given || !*conf.dump_dir_arg)
+       if (!OPT_GIVEN(DUMP_DIR) || !*OPT_STRING_VAL(DUMP_DIR))
                goto out;
-       ret = dump_table(conf.dump_dir_arg, &desc);
+       ret = dump_table(OPT_STRING_VAL(DUMP_DIR), &desc);
 out:
        if (ret < 0)
                ERROR_LOG("failed to check table %s: %s\n", table_name,
@@ -1195,7 +1189,7 @@ out:
        return ret;
 }
 
-static int check_all_tables(char *db_dir)
+static int check_all_tables(const char *db_dir)
 {
        DIR *dir;
        struct dirent *entry;
@@ -1230,37 +1224,58 @@ static int check_all_tables(char *db_dir)
 int main(int argc, char **argv)
 {
        int i, ret;
-       struct fsck_cmdline_parser_params params = {
-               .override = 0,
-               .initialize = 1,
-               .check_required = 1,
-               .check_ambiguity = 1,
-               .print_errors = 1
-       };
-       ret = fsck_cmdline_parser_ext(argc, argv, &conf, &params);
+       char *errctx = NULL;
+       const char *dd;
+
+       loglevel = 0;
+       ret = lls_parse(argc, argv, CMD_PTR, &lpr, &errctx);
        if (ret < 0) {
-               loglevel = EMERG;
-               ret = -E_FSCK_SYNTAX;
-               goto out;
+               if (errctx)
+                       ERROR_LOG("%s\n", errctx);
+               EMERG_LOG("%s\n", lls_strerror(-ret));
+               exit(EXIT_FAILURE);
+       }
+       loglevel = OPT_UINT32_VAL(LOGLEVEL);
+       if (OPT_GIVEN(DETAILED_HELP)) {
+               printf("%s\n", lls_long_help(CMD_PTR));
+               exit(EXIT_SUCCESS);
+       }
+       if (OPT_GIVEN(HELP)) {
+               printf("%s\n", lls_short_help(CMD_PTR));
+               exit(EXIT_SUCCESS);
+       }
+       if (OPT_GIVEN(VERSION)) {
+               printf(
+                       "oslfsck " OSL_VERSION "\n"
+                       "Copyright (C) 2008-2009 Andre Noll\n"
+                       "This is free software with ABSOLUTELY NO WARRANTY."
+                       " See COPYING for details.\n"
+                       "Written by Andre Noll.\n"
+                       "Report bugs to <maan@tuebingen.mpg.de>.\n"
+               );
+               exit(EXIT_SUCCESS);
+       }
+       dd = OPT_STRING_VAL(DATABASE_DIR);
+       if (!dd) {
+               EMERG_LOG("--database-dir: mandatory option not given\n");
+               exit(EXIT_FAILURE);
        }
-       loglevel = conf.loglevel_arg;
-       HANDLE_VERSION_FLAG("fsck", conf);
-       INFO_LOG("database dir: %s\n", conf.database_dir_arg);
-       if (!conf.inputs_num) {
-               ret = check_all_tables(conf.database_dir_arg);
+       INFO_LOG("database dir: %s\n", dd);
+       if (lls_num_inputs(lpr) == 0) {
+               ret = check_all_tables(dd);
                goto out;
        }
-       for (i = 0; i < conf.inputs_num; i++) {
-               ret = check_table(conf.database_dir_arg, conf.inputs[i]);
+       for (i = 0; i < lls_num_inputs(lpr); i++) {
+               ret = check_table(dd, lls_input(i, lpr));
                if (ret < 0)
                        break;
        }
 out:
        if (ret < 0) {
                ERROR_LOG("%s\n", fsck_strerror(-ret));
-               if (conf.loglevel_arg > 1)
+               if (loglevel > 1)
                        EMERG_LOG("re-run with \"--loglevel %d\" to increase verbosity\n",
-                               conf.loglevel_arg - 1);
+                               loglevel - 1);
        } else
                NOTICE_LOG("success\n");
        return ret < 0? EXIT_FAILURE : EXIT_SUCCESS;
diff --git a/fsck.ggo b/fsck.ggo
deleted file mode 100644 (file)
index 2452e3d..0000000
--- a/fsck.ggo
+++ /dev/null
@@ -1,54 +0,0 @@
-option "loglevel" l
-#~~~~~~~~~~~~~~~~~~
-"Set loglevel (0-6)"
-int typestr="level"
-default="3"
-optional
-details="
-       Log messages are always written to stderr while normal output
-       goes to stdout. Lower values mean more verbose logging.
-"
-
-option "database-dir" d
-#~~~~~~~~~~~~~~~~~~~~~~
-"Full path to the database directory"
-string typestr="path"
-required
-details="
-       Unless non-option arguments are given, all subdirectories
-       of \"path\" are considered osl tables which oslfsck will try
-       to fix.
-"
-
-option "dump-dir" D
-#~~~~~~~~~~~~~~~~~~
-"Enable dump mode"
-string typestr="path"
-optional
-default=""
-details="
-       If path is non-empty, oslfsck will write a dump of all
-       given tables to the specified path.
-"
-
-option "no-fsck" n
-#~~~~~~~~~~~~~~~~~
-"Disable fsck mode."
-flag off
-details="
-       This is mainly useful in conjunction with the --dump-dir
-       option.
-"
-
-option "force" f
-#~~~~~~~~~~~~~~~
-"Enable force mode"
-flag off
-details="
-       Ignore the dirty bit when opening osl tables.
-"
-
-option "dry-run" -
-#~~~~~~~~~~~~~~~~~
-"Only report problems, don't try to fix them."
-flag off
diff --git a/oslfsck.suite b/oslfsck.suite
new file mode 100644 (file)
index 0000000..a58e54f
--- /dev/null
@@ -0,0 +1,61 @@
+[suite oslfsck]
+[supercommand oslfsck]
+       purpose = check and repair the tables of an osl database
+       non-opts-name = [table]...
+       [description]
+               oslfsck tries to recover the tables of an osl database after a crash
+               which potentially leaves the database in an inconsistent state.
+       [/description]
+       [option help]
+               summary = print help and exit
+               short_opt = h
+       [option detailed-help]
+               summary = print help, including all details, and exit
+       [option version]
+               summary = print version and exit
+               short_opt = V
+       [option loglevel]
+               short_opt = l
+               summary = set loglevel (0-6)
+               arg_info = required_arg
+               arg_type = uint32
+               typestr = severity
+               default_val = 3
+               [help]
+                       Log messages are always written to stderr while normal output goes
+                       to stdout. Lower values mean more verbose logging.
+               [/help]
+       [option database-dir]
+               short_opt = d
+               summary = full path to the database directory
+               arg_info = required_arg
+               arg_type = string
+               typestr = path
+               [help]
+                       Unless non-option arguments are given, all subdirectories of <path>
+                       are considered osl tables which oslfsck will try to fix.
+               [/help]
+       [option dump-dir]
+               short_opt = D
+               summary = enable dump mode
+               arg_info = required_arg
+               arg_type = string
+               typestr = path
+               [help]
+                       If path is non-empty, oslfsck will write a dump of all given tables
+                       to the specified path.
+               [/help]
+       [option no-fsck]
+               short_opt = n
+               summary = disable fsck mode
+               [help]
+                       This is mainly useful in conjunction with the --dump-dir option.
+               [/help]
+       [option force]
+               short_opt = f
+               summary = enable force mode
+               [help]
+                       Ignore the dirty bit when opening osl tables.
+               [/help]
+       [option dry-run]
+               summary = only report problems, don't try to fix them