diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c index 7d29b6fab..860e6de3a 100644 --- a/tools/lvmcmdline.c +++ b/tools/lvmcmdline.c @@ -1519,6 +1519,65 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp return 0; } +/* + * Return 1 if we should skip this command from consideration. + * This would happen if the command does not include a --type + * option that does not match type_arg. + */ + +static int _command_skip_for_type_arg(struct cmd_context *cmd, int ci, const char *type_arg) +{ + int ro, oo, opt_enum; + + for (ro = 0; ro < (commands[ci].ro_count + commands[ci].any_ro_count); ro++) { + opt_enum = commands[ci].required_opt_args[ro].opt; + + if (opt_enum != type_ARG) + continue; + + /* SegType keyword in command def matches any type_arg */ + if (val_bit_is_set(commands[ci].required_opt_args[ro].def.val_bits, segtype_VAL)) + return 0; + + if (!commands[ci].required_opt_args[ro].def.str) + return 0; + + if (!strcmp(commands[ci].required_opt_args[ro].def.str, type_arg)) + return 0; + + if (!strncmp(commands[ci].required_opt_args[ro].def.str, "raid", 4) && + !strncmp(type_arg, "raid", 4)) + return 0; + + return 1; + } + + for (oo = 0; oo < commands[ci].oo_count; oo++) { + opt_enum = commands[ci].optional_opt_args[oo].opt; + + if (opt_enum != type_ARG) + continue; + + /* SegType keyword in command def matches any type_arg */ + if (val_bit_is_set(commands[ci].optional_opt_args[oo].def.val_bits, segtype_VAL)) + return 0; + + if (!commands[ci].optional_opt_args[oo].def.str) + return 0; + + if (!strcmp(commands[ci].optional_opt_args[oo].def.str, type_arg)) + return 0; + + if (!strncmp(commands[ci].optional_opt_args[oo].def.str, "raid", 4) && + !strncmp(type_arg, "raid", 4)) + return 0; + + return 1; + } + + return 1; +} + /* * Match what the user typed with a one specific command definition/prototype * from commands[]. If nothing matches, it's not a valid command. The match @@ -1549,6 +1608,7 @@ static int _command_required_pos_matches(struct cmd_context *cmd, int ci, int rp static struct command *_find_command(struct cmd_context *cmd, const char *path, int *argc, char **argv) { const char *name; + const char *type_arg = NULL; char opts_msg[MAX_OPTS_MSG]; char check_opts_msg[MAX_OPTS_MSG]; int match_required, match_ro, match_rp, match_any_ro, match_type, match_unused, mismatch_required; @@ -1575,6 +1635,9 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, variants++; } + if (arg_is_set(cmd, type_ARG)) + type_arg = arg_str_value(cmd, type_ARG, ""); + for (i = 0; i < COMMAND_COUNT; i++) { if (strcmp(name, commands[i].name)) continue; @@ -1597,6 +1660,16 @@ static struct command *_find_command(struct cmd_context *cmd, const char *path, continue; } + /* + * '--type foo' is special. If the user has set --type foo, then + * we will only look at command defs that include the same --type foo + * (as required or optional). We'll never match some command based + * on *other* (non-type) options, and then at the end complain that + * the user's --type is not accepted. + */ + if (type_arg && _command_skip_for_type_arg(cmd, i, type_arg)) + continue; + match_required = 0; /* required parameters that match */ match_ro = 0; /* required opt_args that match */ match_rp = 0; /* required pos_args that match */