Prepare the generic command infrastructure for reuse with daxctl.

Signed-off-by: Dan Williams <dan.j.willi...@intel.com>
---
 Makefile.am                       |    2 
 ndctl/Makefile.am                 |    1 
 ndctl/builtin-bat.c               |    2 
 ndctl/builtin-create-nfit.c       |    2 
 ndctl/builtin-dimm.c              |   14 ++-
 ndctl/builtin-list.c              |    2 
 ndctl/builtin-test.c              |    2 
 ndctl/builtin-xable-region.c      |    4 -
 ndctl/builtin-xaction-namespace.c |    8 +-
 ndctl/builtin.h                   |   36 ++++----
 ndctl/ndctl.c                     |  160 +++++++++----------------------------
 test/device-dax.c                 |    2 
 util/help.c                       |   44 ++--------
 util/main.c                       |  123 ++++++++++++++++++++++++++++
 util/main.h                       |   10 ++
 15 files changed, 219 insertions(+), 193 deletions(-)
 rename ndctl/builtin-help.c => util/help.c (73%)
 create mode 100644 util/main.c
 create mode 100644 util/main.h

diff --git a/Makefile.am b/Makefile.am
index 9eb396639efe..01caca803540 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -64,6 +64,8 @@ libutil_a_SOURCES = \
        util/parse-options.h \
        util/usage.c \
        util/size.c \
+       util/main.c \
+       util/help.c \
        util/strbuf.c \
        util/wrapper.c \
        util/filter.c
diff --git a/ndctl/Makefile.am b/ndctl/Makefile.am
index 2d0d8eb40841..f03647ae9d99 100644
--- a/ndctl/Makefile.am
+++ b/ndctl/Makefile.am
@@ -10,7 +10,6 @@ ndctl_SOURCES = ndctl.c \
                 ../util/log.c \
                builtin-list.c \
                builtin-test.c \
-               builtin-help.c \
                util/json.c
 
 if ENABLE_SMART
diff --git a/ndctl/builtin-bat.c b/ndctl/builtin-bat.c
index 48b41dab6d92..5e14d39cfac5 100644
--- a/ndctl/builtin-bat.c
+++ b/ndctl/builtin-bat.c
@@ -4,7 +4,7 @@
 #include <limits.h>
 #include <util/parse-options.h>
 
-int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_bat(int argc, const char **argv, void *ctx)
 {
        int loglevel = LOG_DEBUG, i, rc;
        struct ndctl_test *test;
diff --git a/ndctl/builtin-create-nfit.c b/ndctl/builtin-create-nfit.c
index 780bb84580f5..ebcd7446d14f 100644
--- a/ndctl/builtin-create-nfit.c
+++ b/ndctl/builtin-create-nfit.c
@@ -164,7 +164,7 @@ static int write_nfit(struct nfit *nfit, const char *file, 
int force)
 }
 
 struct ndctl_ctx;
-int cmd_create_nfit(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_create_nfit(int argc, const char **argv, void *ctx)
 {
        int i, rc = -ENXIO, force = 0;
        const char * const u[] = {
diff --git a/ndctl/builtin-dimm.c b/ndctl/builtin-dimm.c
index 4c433d56dfe3..8a041cee8cab 100644
--- a/ndctl/builtin-dimm.c
+++ b/ndctl/builtin-dimm.c
@@ -772,7 +772,7 @@ static const struct option init_options[] = {
        OPT_END(),
 };
 
-static int dimm_action(int argc, const char **argv, struct ndctl_ctx *ctx,
+static int dimm_action(int argc, const char **argv, void *ctx,
                int (*action)(struct ndctl_dimm *dimm, struct action_context 
*actx),
                const struct option *options, const char *usage)
 {
@@ -874,7 +874,7 @@ static int dimm_action(int argc, const char **argv, struct 
ndctl_ctx *ctx,
        return count;
 }
 
-int cmd_read_labels(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_read_labels(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_read, read_options,
                        "ndctl read-labels <nmem0> [<nmem1>..<nmemN>] [-o 
<filename>]");
@@ -884,7 +884,7 @@ int cmd_read_labels(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        return count >= 0 ? 0 : EXIT_FAILURE;
 }
 
-int cmd_zero_labels(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_zero_labels(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_zero, base_options,
                        "ndctl zero-labels <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
@@ -894,7 +894,7 @@ int cmd_zero_labels(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        return count >= 0 ? 0 : EXIT_FAILURE;
 }
 
-int cmd_init_labels(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_init_labels(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_init, init_options,
                        "ndctl init-labels <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
@@ -904,7 +904,7 @@ int cmd_init_labels(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        return count >= 0 ? 0 : EXIT_FAILURE;
 }
 
-int cmd_check_labels(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_check_labels(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_check, base_options,
                        "ndctl check-labels <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
@@ -914,7 +914,7 @@ int cmd_check_labels(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        return count >= 0 ? 0 : EXIT_FAILURE;
 }
 
-int cmd_disable_dimm(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_disable_dimm(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_disable, base_options,
                        "ndctl disable-dimm <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
@@ -924,7 +924,7 @@ int cmd_disable_dimm(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        return count >= 0 ? 0 : EXIT_FAILURE;
 }
 
-int cmd_enable_dimm(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_enable_dimm(int argc, const char **argv, void *ctx)
 {
        int count = dimm_action(argc, argv, ctx, action_enable, base_options,
                        "ndctl enable-dimm <nmem0> [<nmem1>..<nmemN>] 
[<options>]");
diff --git a/ndctl/builtin-list.c b/ndctl/builtin-list.c
index 1486cb1dedc3..caafec8b8f39 100644
--- a/ndctl/builtin-list.c
+++ b/ndctl/builtin-list.c
@@ -188,7 +188,7 @@ static int num_list_flags(void)
        return list.buses + list.dimms + list.regions + list.namespaces;
 }
 
-int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_list(int argc, const char **argv, void *ctx)
 {
        const struct option options[] = {
                OPT_STRING('b', "bus", &param.bus, "bus-id", "filter by bus"),
diff --git a/ndctl/builtin-test.c b/ndctl/builtin-test.c
index caa666b68e69..01ff981749fc 100644
--- a/ndctl/builtin-test.c
+++ b/ndctl/builtin-test.c
@@ -14,7 +14,7 @@ static char *result(int rc)
                return "PASS";
 }
 
-int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_test(int argc, const char **argv, void *ctx)
 {
        struct ndctl_test *test;
        int loglevel = LOG_DEBUG, i, rc;
diff --git a/ndctl/builtin-xable-region.c b/ndctl/builtin-xable-region.c
index 41f465a4543f..50cbdef5b339 100644
--- a/ndctl/builtin-xable-region.c
+++ b/ndctl/builtin-xable-region.c
@@ -64,7 +64,7 @@ static int do_xable_region(const char *region_arg,
        return rc;
 }
 
-int cmd_disable_region(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_disable_region(int argc, const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl disable-region <region> [<options>]";
        const char *region = parse_region_options(argc, argv, xable_usage);
@@ -85,7 +85,7 @@ int cmd_disable_region(int argc, const char **argv, struct 
ndctl_ctx *ctx)
        }
 }
 
-int cmd_enable_region(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_enable_region(int argc, const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl enable-region <region> [<options>]";
        const char *region = parse_region_options(argc, argv, xable_usage);
diff --git a/ndctl/builtin-xaction-namespace.c 
b/ndctl/builtin-xaction-namespace.c
index 8257eb9cd65e..f7a4e5b74a16 100644
--- a/ndctl/builtin-xaction-namespace.c
+++ b/ndctl/builtin-xaction-namespace.c
@@ -781,7 +781,7 @@ static int do_xaction_namespace(const char *namespace,
        return rc;
 }
 
-int cmd_disable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_disable_namespace(int argc, const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl disable-namespace <namespace> [<options>]";
        const char *namespace = parse_namespace_options(argc, argv,
@@ -802,7 +802,7 @@ int cmd_disable_namespace(int argc, const char **argv, 
struct ndctl_ctx *ctx)
        }
 }
 
-int cmd_enable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_enable_namespace(int argc, const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl enable-namespace <namespace> [<options>]";
        const char *namespace = parse_namespace_options(argc, argv,
@@ -823,7 +823,7 @@ int cmd_enable_namespace(int argc, const char **argv, 
struct ndctl_ctx *ctx)
        }
 }
 
-int cmd_create_namespace(int argc, const char **argv, struct ndctl_ctx *ctx)
+int cmd_create_namespace(int argc, const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl create-namespace [<options>]";
        const char *namespace = parse_namespace_options(argc, argv,
@@ -853,7 +853,7 @@ int cmd_create_namespace(int argc, const char **argv, 
struct ndctl_ctx *ctx)
        return 0;
 }
 
-int cmd_destroy_namespace(int argc , const char **argv, struct ndctl_ctx *ctx)
+int cmd_destroy_namespace(int argc , const char **argv, void *ctx)
 {
        char *xable_usage = "ndctl destroy-namespace <namespace> [<options>]";
        const char *namespace = parse_namespace_options(argc, argv,
diff --git a/ndctl/builtin.h b/ndctl/builtin.h
index 0293335c127e..9b66196450fd 100644
--- a/ndctl/builtin.h
+++ b/ndctl/builtin.h
@@ -3,31 +3,29 @@
 extern const char ndctl_usage_string[];
 extern const char ndctl_more_info_string[];
 
-struct ndctl_ctx;
 struct cmd_struct {
        const char *cmd;
-       int (*fn)(int, const char **, struct ndctl_ctx *ctx);
+       int (*fn)(int, const char **, void *ctx);
 };
 
-int cmd_create_nfit(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_enable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_create_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_destroy_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_disable_namespace(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_enable_region(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_disable_region(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_enable_dimm(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_disable_dimm(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_zero_labels(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_read_labels(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_init_labels(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_check_labels(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_list(int argc, const char **argv, struct ndctl_ctx *ctx);
-int cmd_help(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_create_nfit(int argc, const char **argv, void *ctx);
+int cmd_enable_namespace(int argc, const char **argv, void *ctx);
+int cmd_create_namespace(int argc, const char **argv, void *ctx);
+int cmd_destroy_namespace(int argc, const char **argv, void *ctx);
+int cmd_disable_namespace(int argc, const char **argv, void *ctx);
+int cmd_enable_region(int argc, const char **argv, void *ctx);
+int cmd_disable_region(int argc, const char **argv, void *ctx);
+int cmd_enable_dimm(int argc, const char **argv, void *ctx);
+int cmd_disable_dimm(int argc, const char **argv, void *ctx);
+int cmd_zero_labels(int argc, const char **argv, void *ctx);
+int cmd_read_labels(int argc, const char **argv, void *ctx);
+int cmd_init_labels(int argc, const char **argv, void *ctx);
+int cmd_check_labels(int argc, const char **argv, void *ctx);
+int cmd_list(int argc, const char **argv, void *ctx);
 #ifdef ENABLE_TEST
-int cmd_test(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_test(int argc, const char **argv, void *ctx);
 #endif
 #ifdef ENABLE_DESTRUCTIVE
-int cmd_bat(int argc, const char **argv, struct ndctl_ctx *ctx);
+int cmd_bat(int argc, const char **argv, void *ctx);
 #endif
 #endif /* _NDCTL_BUILTIN_H_ */
diff --git a/ndctl/ndctl.c b/ndctl/ndctl.c
index 4f000fe51fae..80a0491c440a 100644
--- a/ndctl/ndctl.c
+++ b/ndctl/ndctl.c
@@ -9,20 +9,47 @@
 #include <ndctl/libndctl.h>
 #include <ccan/array_size/array_size.h>
 
+#include <util/parse-options.h>
 #include <util/strbuf.h>
 #include <util/util.h>
+#include <util/main.h>
 
 const char ndctl_usage_string[] = "ndctl [--version] [--help] COMMAND [ARGS]";
 const char ndctl_more_info_string[] =
        "See 'ndctl help COMMAND' for more information on a specific command.\n"
        " ndctl --list-cmds to see all available commands";
 
-static int cmd_version(int argc, const char **argv, struct ndctl_ctx *ctx)
+static int cmd_version(int argc, const char **argv, void *ctx)
 {
        printf("%s\n", VERSION);
        return 0;
 }
 
+static int cmd_help(int argc, const char **argv, void *ctx)
+{
+       const char * const builtin_help_subcommands[] = {
+               "enable-region", "disable-region", "zero-labels",
+               "enable-namespace", "disable-namespace", NULL };
+       struct option builtin_help_options[] = {
+               OPT_END(),
+       };
+       const char *builtin_help_usage[] = {
+               "ndctl help [command]",
+               NULL
+       };
+
+       argc = parse_options_subcommand(argc, argv, builtin_help_options,
+                       builtin_help_subcommands, builtin_help_usage, 0);
+
+       if (!argv[0]) {
+               printf("\n usage: %s\n\n", ndctl_usage_string);
+               printf("\n %s\n\n", ndctl_more_info_string);
+               return 0;
+       }
+
+       return help_show_man_page(argv[0], "ndctl", "NDCTL_MAN_VIEWER");
+}
+
 static struct cmd_struct commands[] = {
        { "version", cmd_version },
        { "create-nfit", cmd_create_nfit },
@@ -48,131 +75,16 @@ static struct cmd_struct commands[] = {
        #endif
 };
 
-static int handle_options(const char ***argv, int *argc)
-{
-       int handled = 0;
-
-       while (*argc > 0) {
-               const char *cmd = (*argv)[0];
-               if (cmd[0] != '-')
-                       break;
-
-               if (!strcmp(cmd, "--version") || !strcmp(cmd, "--help"))
-                       break;
-
-               /*
-                * Shortcut for '-h' and '-v' options to invoke help
-                * and version command.
-                */
-               if (!strcmp(cmd, "-h")) {
-                       (*argv)[0] = "--help";
-                       break;
-               }
-
-               if (!strcmp(cmd, "-v")) {
-                       (*argv)[0] = "--version";
-                       break;
-               }
-
-               if (!strcmp(cmd, "--list-cmds")) {
-                       unsigned int i;
-
-                       for (i = 0; i < ARRAY_SIZE(commands); i++) {
-                               struct cmd_struct *p = commands+i;
-
-                               /* filter out commands from auto-complete */
-                               if (strcmp(p->cmd, "create-nfit") == 0)
-                                       continue;
-                               if (strcmp(p->cmd, "test") == 0)
-                                       continue;
-                               if (strcmp(p->cmd, "bat") == 0)
-                                       continue;
-                               printf("%s\n", p->cmd);
-                       }
-                       exit(0);
-               } else {
-                       fprintf(stderr, "Unknown option: %s\n", cmd);
-                       usage(ndctl_usage_string);
-               }
-
-               (*argv)++;
-               (*argc)--;
-               handled++;
-       }
-       return handled;
-}
-
-static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
+int main(int argc, const char **argv)
 {
-       int status;
-       struct stat st;
        struct ndctl_ctx *ctx;
+       int rc;
 
-       /*
-        * Yes, establishing the ndctl context here makes this code less
-        * generic, but it allows for unit testing the top level
-        * interface to the built-in commands.
-        */
-       status = ndctl_new(&ctx);
-       if (status)
-               return status;
-       status = p->fn(argc, argv, ctx);
-       ndctl_unref(ctx);
-
-       if (status)
-               return status & 0xff;
-
-       /* Somebody closed stdout? */
-       if (fstat(fileno(stdout), &st))
-               return 0;
-       /* Ignore write errors for pipes and sockets.. */
-       if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
-               return 0;
-
-       status = 1;
-       /* Check for ENOSPC and EIO errors.. */
-       if (fflush(stdout)) {
-               fprintf(stderr, "write failure on standard output: %s", 
strerror(errno));
-               goto out;
-       }
-       if (ferror(stdout)) {
-               fprintf(stderr, "unknown write failure on standard output");
-               goto out;
-       }
-       if (fclose(stdout)) {
-               fprintf(stderr, "close failed on standard output: %s", 
strerror(errno));
-               goto out;
-       }
-       status = 0;
-out:
-       return status;
-}
-
-static void handle_internal_command(int argc, const char **argv)
-{
-       const char *cmd = argv[0];
-       unsigned int i;
-
-       /* Turn "ndctl cmd --help" into "ndctl help cmd" */
-       if (argc > 1 && !strcmp(argv[1], "--help")) {
-               argv[1] = argv[0];
-               argv[0] = cmd = "help";
-       }
-
-       for (i = 0; i < ARRAY_SIZE(commands); i++) {
-               struct cmd_struct *p = commands+i;
-               if (strcmp(p->cmd, cmd))
-                       continue;
-               exit(run_builtin(p, argc, argv));
-       }
-}
-
-int main(int argc, const char **argv)
-{
        /* Look for flags.. */
        argv++;
        argc--;
-       handle_options(&argv, &argc);
+       main_handle_options(&argv, &argc, ndctl_usage_string, commands,
+                       ARRAY_SIZE(commands));
 
        if (argc > 0) {
                if (!prefixcmp(argv[0], "--"))
@@ -183,7 +95,13 @@ int main(int argc, const char **argv)
                printf("\n %s\n\n", ndctl_more_info_string);
                goto out;
        }
-       handle_internal_command(argc, argv);
+
+       rc = ndctl_new(&ctx);
+       if (rc)
+               goto out;
+       main_handle_internal_command(argc, argv, ctx, commands,
+                       ARRAY_SIZE(commands));
+       ndctl_unref(ctx);
        fprintf(stderr, "Unknown command: '%s'\n", argv[0]);
 out:
        return 1;
diff --git a/test/device-dax.c b/test/device-dax.c
index 75b17ed63088..0ace922ee55d 100644
--- a/test/device-dax.c
+++ b/test/device-dax.c
@@ -23,7 +23,7 @@
 
 static sigjmp_buf sj_env;
 
-static int create_namespace(int argc, const char **argv, struct ndctl_ctx *ctx)
+static int create_namespace(int argc, const char **argv, void *ctx)
 {
        builtin_xaction_namespace_reset();
        return cmd_create_namespace(argc, argv, ctx);
diff --git a/ndctl/builtin-help.c b/util/help.c
similarity index 73%
rename from ndctl/builtin-help.c
rename to util/help.c
index 14ad9d5738d0..310a40bd83e8 100644
--- a/ndctl/builtin-help.c
+++ b/util/help.c
@@ -56,16 +56,16 @@ static void exec_man_man(const char *path, const char *page)
                strerror_r(errno, sbuf, sizeof(sbuf)));
 }
 
-static char *cmd_to_page(const char *ndctl_cmd, char **page)
+static char *cmd_to_page(const char *cmd, char **page, const char *util_name)
 {
        int rc;
 
-       if (!ndctl_cmd)
-               rc = asprintf(page, "ndctl");
-       else if (!prefixcmp(ndctl_cmd, "ndctl"))
-               rc = asprintf(page, "%s", ndctl_cmd);
+       if (!cmd)
+               rc = asprintf(page, "%s", util_name);
+       else if (!prefixcmp(cmd, util_name))
+               rc = asprintf(page, "%s", cmd);
        else
-               rc = asprintf(page, "ndctl-%s", ndctl_cmd);
+               rc = asprintf(page, "%s-%s", util_name, cmd);
 
        if (rc < 0)
                return NULL;
@@ -119,12 +119,13 @@ static void exec_viewer(const char *name, const char 
*page)
                warning("'%s': unknown man viewer.", name);
 }
 
-static int show_man_page(const char *ndctl_cmd)
+int help_show_man_page(const char *cmd, const char *util_name,
+               const char *viewer)
 {
-       const char *fallback = getenv("NDCTL_MAN_VIEWER");
+       const char *fallback = getenv(viewer);
        char *page;
 
-       page = cmd_to_page(ndctl_cmd, &page);
+       page = cmd_to_page(cmd, &page, util_name);
        if (!page)
                return -1;
        setup_man_path();
@@ -136,28 +137,3 @@ static int show_man_page(const char *ndctl_cmd)
        free(page);
        return -1;
 }
-
-int cmd_help(int argc, const char **argv, struct ndctl_ctx *ctx)
-{
-       const char * const builtin_help_subcommands[] = {
-               "enable-region", "disable-region", "zero-labels",
-               "enable-namespace", "disable-namespace", NULL };
-       struct option builtin_help_options[] = {
-               OPT_END(),
-       };
-       const char *builtin_help_usage[] = {
-               "ndctl help [command]",
-               NULL
-       };
-
-       argc = parse_options_subcommand(argc, argv, builtin_help_options,
-                       builtin_help_subcommands, builtin_help_usage, 0);
-
-       if (!argv[0]) {
-               printf("\n usage: %s\n\n", ndctl_usage_string);
-               printf("\n %s\n\n", ndctl_more_info_string);
-               return 0;
-       }
-
-       return show_man_page(argv[0]);
-}
diff --git a/util/main.c b/util/main.c
new file mode 100644
index 000000000000..cb3c634e93f5
--- /dev/null
+++ b/util/main.c
@@ -0,0 +1,123 @@
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <builtin.h>
+
+#include <util/strbuf.h>
+#include <util/util.h>
+
+int main_handle_options(const char ***argv, int *argc, const char *usage_msg,
+               struct cmd_struct *cmds, int num_cmds)
+{
+       int handled = 0;
+
+       while (*argc > 0) {
+               const char *cmd = (*argv)[0];
+               if (cmd[0] != '-')
+                       break;
+
+               if (!strcmp(cmd, "--version") || !strcmp(cmd, "--help"))
+                       break;
+
+               /*
+                * Shortcut for '-h' and '-v' options to invoke help
+                * and version command.
+                */
+               if (!strcmp(cmd, "-h")) {
+                       (*argv)[0] = "--help";
+                       break;
+               }
+
+               if (!strcmp(cmd, "-v")) {
+                       (*argv)[0] = "--version";
+                       break;
+               }
+
+               if (!strcmp(cmd, "--list-cmds")) {
+                       int i;
+
+                       for (i = 0; i < num_cmds; i++) {
+                               struct cmd_struct *p = cmds+i;
+
+                               /* filter out commands from auto-complete */
+                               if (strcmp(p->cmd, "create-nfit") == 0)
+                                       continue;
+                               if (strcmp(p->cmd, "test") == 0)
+                                       continue;
+                               if (strcmp(p->cmd, "bat") == 0)
+                                       continue;
+                               printf("%s\n", p->cmd);
+                       }
+                       exit(0);
+               } else {
+                       fprintf(stderr, "Unknown option: %s\n", cmd);
+                       usage(usage_msg);
+               }
+
+               (*argv)++;
+               (*argc)--;
+               handled++;
+       }
+       return handled;
+}
+
+static int run_builtin(struct cmd_struct *p, int argc, const char **argv,
+               void *ctx)
+{
+       int status;
+       struct stat st;
+
+       status = p->fn(argc, argv, ctx);
+
+       if (status)
+               return status & 0xff;
+
+       /* Somebody closed stdout? */
+       if (fstat(fileno(stdout), &st))
+               return 0;
+       /* Ignore write errors for pipes and sockets.. */
+       if (S_ISFIFO(st.st_mode) || S_ISSOCK(st.st_mode))
+               return 0;
+
+       status = 1;
+       /* Check for ENOSPC and EIO errors.. */
+       if (fflush(stdout)) {
+               fprintf(stderr, "write failure on standard output: %s", 
strerror(errno));
+               goto out;
+       }
+       if (ferror(stdout)) {
+               fprintf(stderr, "unknown write failure on standard output");
+               goto out;
+       }
+       if (fclose(stdout)) {
+               fprintf(stderr, "close failed on standard output: %s", 
strerror(errno));
+               goto out;
+       }
+       status = 0;
+out:
+       return status;
+}
+
+void main_handle_internal_command(int argc, const char **argv, void *ctx,
+               struct cmd_struct *cmds, int num_cmds)
+{
+       const char *cmd = argv[0];
+       int i;
+
+       /* Turn "<binary> cmd --help" into "<binary> help cmd" */
+       if (argc > 1 && !strcmp(argv[1], "--help")) {
+               argv[1] = argv[0];
+               argv[0] = cmd = "help";
+       }
+
+       for (i = 0; i < num_cmds; i++) {
+               struct cmd_struct *p = cmds+i;
+               if (strcmp(p->cmd, cmd))
+                       continue;
+               exit(run_builtin(p, argc, argv, ctx));
+       }
+}
diff --git a/util/main.h b/util/main.h
new file mode 100644
index 000000000000..bdd4f701665c
--- /dev/null
+++ b/util/main.h
@@ -0,0 +1,10 @@
+#ifndef __MAIN_H__
+#define __MAIN_H__
+struct cmd_struct;
+int main_handle_options(const char ***argv, int *argc, const char *usage_msg,
+               struct cmd_struct *cmds, int num_cmds);
+void main_handle_internal_command(int argc, const char **argv, void *ctx,
+               struct cmd_struct *cmds, int num_cmds);
+int help_show_man_page(const char *cmd, const char *util_name,
+               const char *viewer);
+#endif /* __MAIN_H__ */

_______________________________________________
Linux-nvdimm mailing list
Linux-nvdimm@lists.01.org
https://lists.01.org/mailman/listinfo/linux-nvdimm

Reply via email to