From de8f30c969f3fc866e0f668a0a0dd86e5ba48091 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sun, 17 Sep 2023 15:07:51 +1000 Subject: [PATCH] cmd: add 'help' subcommand to zpool and zfs 'program help subcommand' is a reasonably common pattern for multifunction command-line programs. This commit adds support for that style to the zpool and zfs commands. When run as 'zpool help []' or 'zfs help []', executes the 'man' program on the PATH with the most likely manpage name for the requested topic: "zpool-" or "zfs-" for subcommands, or "zpool" or "zfs" for the "concepts" and "props" topics. If no topic is supplied, uses the top "zpool" or "zfs" pages. Signed-off-by: Rob Norris --- cmd/zfs/zfs_main.c | 30 ++++++++++++++++++++++++++++++ cmd/zpool/zpool_main.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) diff --git a/cmd/zfs/zfs_main.c b/cmd/zfs/zfs_main.c index ea73bb018a92..629e048872bd 100644 --- a/cmd/zfs/zfs_main.c +++ b/cmd/zfs/zfs_main.c @@ -132,6 +132,8 @@ static int zfs_do_zone(int argc, char **argv); static int zfs_do_unzone(int argc, char **argv); #endif +static int zfs_do_help(int argc, char **argv); + /* * Enable a reasonable set of defaults for libumem debugging on DEBUG builds. */ @@ -606,6 +608,9 @@ usage(boolean_t requested) (void) fprintf(fp, gettext("\nFor the delegated permission list, run: %s\n"), "zfs allow|unallow"); + (void) fprintf(fp, + gettext("\nFor further help on a command or topic, " + "run: %s\n"), "zfs help []"); } /* @@ -8730,6 +8735,25 @@ zfs_do_version(int argc, char **argv) return (zfs_version_print() != 0); } +/* Display documentation */ +static int +zfs_do_help(int argc, char **argv) +{ + char page[MAXNAMELEN]; + if (argc < 3 || strcmp(argv[2], "zfs") == 0) + strcpy(page, "zfs"); + else if (strcmp(argv[2], "concepts") == 0 || + strcmp(argv[2], "props") == 0) + snprintf(page, sizeof (page), "zfs%s", argv[2]); + else + snprintf(page, sizeof (page), "zfs-%s", argv[2]); + + execlp("man", "man", page, NULL); + + fprintf(stderr, "couldn't run man program: %s", strerror(errno)); + return (-1); +} + int main(int argc, char **argv) { @@ -8785,6 +8809,12 @@ main(int argc, char **argv) if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0)) return (zfs_do_version(argc, argv)); + /* + * Special case 'help' + */ + if (strcmp(cmdname, "help") == 0) + return (zfs_do_help(argc, argv)); + if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, "%s\n", libzfs_error_init(errno)); return (1); diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 6d0dae8d8b05..d64fdfa5ba4c 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -126,6 +126,8 @@ static int zpool_do_version(int, char **); static int zpool_do_wait(int, char **); +static int zpool_do_help(int argc, char **argv); + static zpool_compat_status_t zpool_do_load_compat( const char *, boolean_t *); @@ -538,6 +540,10 @@ usage(boolean_t requested) (void) fprintf(fp, "%s", get_usage(command_table[i].usage)); } + + (void) fprintf(fp, + gettext("\nFor further help on a command or topic, " + "run: %s\n"), "zpool help []"); } else { (void) fprintf(fp, gettext("usage:\n")); (void) fprintf(fp, "%s", get_usage(current_command->usage)); @@ -11051,6 +11057,25 @@ zpool_do_version(int argc, char **argv) return (zfs_version_print() != 0); } +/* Display documentation */ +static int +zpool_do_help(int argc, char **argv) +{ + char page[MAXNAMELEN]; + if (argc < 3 || strcmp(argv[2], "zpool") == 0) + strcpy(page, "zpool"); + else if (strcmp(argv[2], "concepts") == 0 || + strcmp(argv[2], "props") == 0) + snprintf(page, sizeof (page), "zpool%s", argv[2]); + else + snprintf(page, sizeof (page), "zpool-%s", argv[2]); + + execlp("man", "man", page, NULL); + + fprintf(stderr, "couldn't run man program: %s", strerror(errno)); + return (-1); +} + /* * Do zpool_load_compat() and print error message on failure */ @@ -11118,6 +11143,12 @@ main(int argc, char **argv) if ((strcmp(cmdname, "-V") == 0) || (strcmp(cmdname, "--version") == 0)) return (zpool_do_version(argc, argv)); + /* + * Special case 'help' + */ + if (strcmp(cmdname, "help") == 0) + return (zpool_do_help(argc, argv)); + if ((g_zfs = libzfs_init()) == NULL) { (void) fprintf(stderr, "%s\n", libzfs_error_init(errno)); return (1);