diff --git a/tools/command.c b/tools/command.c index 3ad5b816d..4d23e2dc9 100644 --- a/tools/command.c +++ b/tools/command.c @@ -47,7 +47,7 @@ static const struct val_name val_names[VAL_COUNT + 1] = { /* create table of option names, e.g. --foo, and corresponding enum from args.h */ -static struct opt_name opt_names[ARG_COUNT + 1] = { +static const struct opt_name opt_names[ARG_COUNT + 1] = { #define arg(a, b, c, d, e, f, g) { # a, b, a, "--" c, d, e, f, g }, #include "args.h" #undef arg @@ -85,7 +85,7 @@ static const struct cmd_name cmd_names[CMD_COUNT + 1] = { #ifdef MAN_PAGE_GENERATOR static struct command_name command_names[] = { -#define xx(a, b, c...) { # a, b, c }, +#define xx(a, b, c...) { # a, b, c, NULL, a ## _COMMAND }, #include "commands.h" #undef xx { .name = NULL } @@ -95,7 +95,7 @@ static struct command commands[COMMAND_COUNT]; #else /* MAN_PAGE_GENERATOR */ struct command_name command_names[] = { -#define xx(a, b, c...) { # a, b, c, a}, +#define xx(a, b, c...) { # a, b, c, a, a ## _COMMAND }, #include "commands.h" #undef xx { .name = NULL } @@ -130,7 +130,7 @@ const struct lv_type *get_lv_type(int lvt_enum) /* array of pointers into opt_names[] that is sorted alphabetically (by long opt name) */ -static struct opt_name *opt_names_alpha[ARG_COUNT + 1]; +static const struct opt_name *opt_names_alpha[ARG_COUNT + 1]; /* lvm_all is for recording options that are common for all lvm commands */ @@ -1517,6 +1517,7 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) return 1; } +#ifndef MAN_PAGE_GENERATOR /* * The opt_names[] table describes each option. It is indexed by the * option typedef, e.g. size_ARG. The size_ARG entry specifies the @@ -1533,8 +1534,10 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) * (they are created at build time), but different commands accept different * types of values for the same option, e.g. one command will accept * signed size values (ssizemb_VAL), while another does not accept a signed - * number, (sizemb_VAL). This function deals with this problem by tweaking - * the opt_names[] table at run time according to the specific command being run. + * number, (sizemb_VAL). + * + * To resolve the issue, at run time command 'reconfigures' its opt_names[] + * values by querying particular arg_enum for particular command. * i.e. it changes size_ARG to accept sizemb_VAL or ssizemb_VAL depending * on the command. * @@ -1558,53 +1561,57 @@ int define_commands(struct cmd_context *cmdtool, const char *run_name) * so the commands[] entry for the cmd def already references the * correct ssizemb_VAL. */ -void configure_command_option_values(const char *name) +int configure_command_option_values(const struct command_name *cname, int arg_enum, int val_enum) { - if (!strcmp(name, "lvresize")) { - /* relative +|- allowed for LV, + allowed for metadata */ - opt_names[size_ARG].val_enum = ssizemb_VAL; - opt_names[extents_ARG].val_enum = sextents_VAL; - opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL; - return; - } - - if (!strcmp(name, "lvextend")) { - /* relative + allowed */ - opt_names[size_ARG].val_enum = psizemb_VAL; - opt_names[extents_ARG].val_enum = pextents_VAL; - opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL; - return; - } - - if (!strcmp(name, "lvreduce")) { - /* relative - allowed */ - opt_names[size_ARG].val_enum = nsizemb_VAL; - opt_names[extents_ARG].val_enum = nextents_VAL; - return; - } - - if (!strcmp(name, "lvconvert")) { - opt_names[mirrors_ARG].val_enum = snumber_VAL; - return; - } - - if (!strcmp(name, "lvcreate")) { + switch (cname->lvm_command_enum) { + case lvconvert_COMMAND: + switch (arg_enum) { + case mirrors_ARG: return snumber_VAL; + } + break; + case lvcreate_COMMAND: /* - * lvcreate is a bit of a mess because it has previously - * accepted + but used it as an absolute value, so we - * have to recognize it. (We don't want to show the + - * option in man/help, though, since it's confusing, + * lvcreate is accepts also sizes with + (positive) value, + * so we have to recognize it. But we don't want to show + * the + option in man/help as it can be seen confusing, * so there's a special case when printing man/help * output to show sizemb_VAL/extents_VAL rather than * psizemb_VAL/pextents_VAL.) */ - opt_names[size_ARG].val_enum = psizemb_VAL; - opt_names[extents_ARG].val_enum = pextents_VAL; - opt_names[poolmetadatasize_ARG].val_enum = psizemb_VAL; - opt_names[mirrors_ARG].val_enum = pnumber_VAL; - return; + switch (arg_enum) { + case size_ARG: return psizemb_VAL; + case extents_ARG: return pextents_VAL; + case poolmetadatasize_ARG: return psizemb_VAL; + case mirrors_ARG: return pnumber_VAL; + } + break; + case lvextend_COMMAND: + /* relative + allowed */ + switch (arg_enum) { + case size_ARG: return psizemb_VAL; + case extents_ARG: return pextents_VAL; + case poolmetadatasize_ARG: return psizemb_VAL; + } + break; + case lvreduce_COMMAND: + /* relative - allowed */ + switch (arg_enum) { + case size_ARG: return nsizemb_VAL; + case extents_ARG: return nextents_VAL; + } + break; + case lvresize_COMMAND: + switch (arg_enum) { + case size_ARG: return ssizemb_VAL; + case extents_ARG: return sextents_VAL; + case poolmetadatasize_ARG: return psizemb_VAL; + } + break; } + + return val_enum; } +#endif /* type_LVT to "type" */ @@ -1644,38 +1651,49 @@ static void _print_usage_description(struct command *cmd) } } -static void _update_relative_opt(const char *name, int opt_enum, int *val_enum) +/* Function remappas existing command definitions val_enums for printing + * within man pages or command's help lines */ +static int _update_relative_opt(const char *name, int opt_enum, int val_enum) { /* check for relative sign */ - switch (opt_enum) { - case extents_ARG: - case mirrors_ARG: - case poolmetadatasize_ARG: - case size_ARG: + if (!strcmp(name, "lvconvert")) + switch (opt_enum) { + case mirrors_ARG: return snumber_VAL; + } + else if (!strcmp(name, "lvcreate")) /* * Suppress the [+] prefix for lvcreate which we have to * accept for backwards compat, but don't want to advertise. + * 'command-lines.in' currently uses PNumber in definition */ - if (!strcmp(name, "lvcreate")) { - switch (*val_enum) { - case psizemb_VAL: - *val_enum = sizemb_VAL; - break; - case pextents_VAL: - *val_enum = extents_VAL; - break; - case pnumber_VAL: - if (opt_enum == mirrors_ARG) - *val_enum = number_VAL; - break; - } + switch (opt_enum) { + case mirrors_ARG: return number_VAL; } - } + else if (!strcmp(name, "lvextend")) + switch (opt_enum) { + case extents_ARG: return pextents_VAL; + case poolmetadatasize_ARG: + case size_ARG: return psizemb_VAL; + } + else if (!strcmp(name, "lvreduce")) + switch (opt_enum) { + case extents_ARG: return nextents_VAL; + case poolmetadatasize_ARG: + case size_ARG: return nsizemb_VAL; + } + else if (!strcmp(name, "lvresize")) + switch (opt_enum) { + case extents_ARG: return sextents_VAL; + case poolmetadatasize_ARG: + case size_ARG: return ssizemb_VAL; + } + + return val_enum; } static void _print_val_usage(struct command *cmd, int opt_enum, int val_enum) { - _update_relative_opt(cmd->name, opt_enum, &val_enum); + val_enum = _update_relative_opt(cmd->name, opt_enum, val_enum); if (!val_names[val_enum].usage) printf("%s", val_names[val_enum].name); diff --git a/tools/command.h b/tools/command.h index fc8d5dc18..b8df18bb7 100644 --- a/tools/command.h +++ b/tools/command.h @@ -35,6 +35,7 @@ struct command_name { const char *desc; /* general command description from commands.h */ unsigned int flags; command_fn fn; /* old style */ + uint16_t lvm_command_enum; /* as declared in commands.h with _COMMAND */ /* union of {required,optional}_opt_args for all commands with this name */ uint16_t valid_args[ARG_COUNT]; /* used for getopt */ @@ -274,7 +275,7 @@ void print_usage_common_lvm(const struct command_name *cname, struct command *cm void print_usage_notes(const struct command_name *cname); void factor_common_options(void); int command_has_alternate_extents(const char *name); -void configure_command_option_values(const char *name); +int configure_command_option_values(const struct command_name *cname, int arg_enum, int val_enum); const struct command_name *find_command_name(const char *name); #endif diff --git a/tools/command_enums.h b/tools/command_enums.h index 2331b2772..f0c4825f2 100644 --- a/tools/command_enums.h +++ b/tools/command_enums.h @@ -49,6 +49,13 @@ enum { #undef lvt }; +enum { +#define xx(a, b...) a ## _COMMAND, +#include "commands.h" +#undef xx + LVM_COMMAND_COUNT +}; + #define PERMITTED_READ_ONLY 0x00000002 /* Process all VGs if none specified on the command line. */ #define ALL_VGS_IS_DEFAULT 0x00000004 diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index a2e34c127..66b269538 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -2021,8 +2021,6 @@ static int _usage(const char *name, int longhelp, int skip_notes) return 0; } - configure_command_option_values(name); - /* * Looks at all variants of each command name and figures out * which options are common to all variants (for compact output) @@ -2200,6 +2198,7 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg struct arg_values *av; struct arg_value_group_list *current_group = NULL; int arg_enum; /* e.g. foo_ARG */ + int val_enum; int goval; /* the number returned from getopt_long identifying what it found */ int i; @@ -2291,8 +2290,8 @@ static int _process_command_line(struct cmd_context *cmd, int *argc, char ***arg } av->value = optarg; - - if (!get_val_name(a->val_enum)->fn(cmd, av)) { + val_enum = configure_command_option_values(cmd->cname, arg_enum, a->val_enum); + if (!get_val_name(val_enum)->fn(cmd, av)) { log_error("Invalid argument for %s: %s", a->long_opt, optarg); return 0; } @@ -3072,8 +3071,6 @@ int lvm_run_command(struct cmd_context *cmd, int argc, char **argv) init_log_command(find_config_tree_bool(cmd, log_command_names_CFG, NULL), 0); - configure_command_option_values(cmd->name); - /* eliminate '-' from all options starting with -- */ for (i = 1; i < argc; i++) { diff --git a/tools/man-generator.c b/tools/man-generator.c index dfb2a368f..d602bb22f 100644 --- a/tools/man-generator.c +++ b/tools/man-generator.c @@ -119,6 +119,10 @@ static const char *_lvt_enum_to_name(int lvt_enum) return lv_types[lvt_enum].name; } +static int _get_val_enum(const struct command_name *cname, int opt_enum) +{ + return _update_relative_opt(cname->name, opt_enum, opt_names[opt_enum].val_enum); +} /* * FIXME: this just replicates the val usage strings * that officially lives in vals.h. Should there @@ -137,8 +141,6 @@ static void _print_val_man(const struct command_name *cname, int opt_enum, int v _was_hyphen = 0; - _update_relative_opt(cname->name, opt_enum, &val_enum); - switch (val_enum) { case sizemb_VAL: printf("\\fISize\\fP[m|UNIT]"); @@ -232,7 +234,7 @@ static void _print_val_man(const struct command_name *cname, int opt_enum, int v static void _print_def_man(const struct command_name *cname, int opt_enum, struct arg_def *def, int usage, uint64_t *lv_type_bits) { - int val_enum; + int val_enum, tmp_val; int sep = 0; if (lv_type_bits) @@ -264,7 +266,8 @@ static void _print_def_man(const struct command_name *cname, int opt_enum, struc printf("\\fI%s\\fP", val_names[val_enum].name); } } else { - _print_val_man(cname, opt_enum, val_enum); + tmp_val = _update_relative_opt(cname->name, opt_enum, val_enum); + _print_val_man(cname, opt_enum, tmp_val); } sep = 1; @@ -577,7 +580,7 @@ static void _print_man_usage(char *lvmname, struct command *cmd) * in opt_names[] according to the command name. */ printf("[ \\fB-l\\fP|\\fB--extents\\fP "); - _print_val_man(cname, extents_ARG, opt_names[extents_ARG].val_enum); + _print_val_man(cname, extents_ARG, _get_val_enum(cname, extents_ARG)); printf_hyphen(']'); sep = 1; @@ -1020,7 +1023,7 @@ static void _print_man_all_options_list(const struct command_name *cname) printf(" \\fB%s\\fP", _man_long_opt_name(cname->name, opt_enum)); } - val_enum = opt_names[opt_enum].val_enum; + val_enum = _get_val_enum(cname, opt_enum); if (!val_names[val_enum].fn) { /* takes no arg */ @@ -1059,7 +1062,7 @@ static void _print_man_all_options_desc(const struct command_name *cname) if (!cname->all_options[opt_enum]) continue; - val_enum = opt_names[opt_enum].val_enum; + val_enum = _get_val_enum(cname, opt_enum); if (val_names[val_enum].usage && (strlen(val_names[val_enum].usage) > _LONG_LINE)) { @@ -1781,9 +1784,6 @@ int main(int argc, char *argv[]) if (!define_commands(&cmdtool, NULL)) goto out_free; - if (!check) - configure_command_option_values(cmdname); - factor_common_options(); if (primary && cmdname)