1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00

commands: track errors in command def parsing

When parsing command defs, track and report all
errors that are found.  Add an error return case
from define_commands so the standard error exit
path is used.
This commit is contained in:
David Teigland 2017-02-16 15:26:42 -06:00
parent 1cb95fa5a0
commit 298b11aed1
5 changed files with 97 additions and 57 deletions

View File

@ -354,7 +354,7 @@ static int val_str_to_num(char *str)
#define MAX_LONG_OPT_NAME_LEN 32
static int opt_str_to_num(char *str)
static int opt_str_to_num(struct command *cmd, char *str)
{
char long_name[MAX_LONG_OPT_NAME_LEN];
char *p;
@ -383,7 +383,8 @@ static int opt_str_to_num(char *str)
}
log_error("Parsing command defs: unknown opt str: %s %s", str, long_name);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return ARG_UNUSED;
}
for (i = 0; i < ARG_COUNT; i++) {
@ -397,7 +398,8 @@ static int opt_str_to_num(char *str)
}
log_error("Parsing command defs: unknown opt str: \"%s\"", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return ARG_UNUSED;
}
/* "foo" string to foo_CMD int */
@ -410,13 +412,13 @@ int command_id_to_enum(const char *str)
if (!strcmp(str, cmd_names[i].name))
return cmd_names[i].cmd_enum;
}
log_error("Parsing command defs: unknown cmd name %s", str);
exit(EXIT_FAILURE);
return CMD_NONE;
}
/* "lv_is_prop" to is_prop_LVP */
static int lvp_name_to_enum(char *str)
static int lvp_name_to_enum(struct command *cmd, char *str)
{
int i;
@ -424,13 +426,15 @@ static int lvp_name_to_enum(char *str)
if (!strcmp(str, lvp_names[i].name))
return lvp_names[i].lvp_enum;
}
log_error("Parsing command defs: unknown lv property %s", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return LVP_NONE;
}
/* "type" to type_LVT */
static int lvt_name_to_enum(char *str)
static int lvt_name_to_enum(struct command *cmd, char *str)
{
int i;
@ -438,15 +442,17 @@ static int lvt_name_to_enum(char *str)
if (!strcmp(str, lvt_names[i].name))
return lvt_names[i].lvt_enum;
}
log_error("Parsing command defs: unknown lv type %s", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return LVT_NONE;
}
/* LV_<type> to <type>_LVT */
static int lv_to_enum(char *name)
static int lv_to_enum(struct command *cmd, char *name)
{
return lvt_name_to_enum(name + 3);
return lvt_name_to_enum(cmd, name + 3);
}
/*
@ -460,7 +466,7 @@ static int lv_to_enum(char *name)
#define LVTYPE_LEN 64
static uint64_t lv_to_bits(char *name)
static uint64_t lv_to_bits(struct command *cmd, char *name)
{
char buf[LVTYPE_LEN];
char *argv[MAX_LINE_ARGC];
@ -478,7 +484,7 @@ static uint64_t lv_to_bits(char *name)
for (i = 1; i < argc; i++) {
if (!strcmp(argv[i], "new"))
continue;
lvt_enum = lvt_name_to_enum(argv[i]);
lvt_enum = lvt_name_to_enum(cmd, argv[i]);
lvt_bits |= lvt_enum_to_bit(lvt_enum);
}
@ -516,10 +522,8 @@ static int is_opt_name(char *str)
if (!strncmp(str, "--", 2))
return 1;
if ((str[0] == '-') && (str[1] != '-')) {
if ((str[0] == '-') && (str[1] != '-'))
log_error("Parsing command defs: options must be specified in long form: %s", str);
exit(EXIT_FAILURE);
}
return 0;
}
@ -625,13 +629,14 @@ static void set_pos_def(struct command *cmd, char *str, struct arg_def *def)
if (!val_enum) {
log_error("Parsing command defs: unknown pos arg: %s", name);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
def->val_bits |= val_enum_to_bit(val_enum);
if ((val_enum == lv_VAL) && strstr(name, "_"))
def->lvt_bits = lv_to_bits(name);
def->lvt_bits = lv_to_bits(cmd, name);
if (strstr(name, "_new")) {
if (val_enum == lv_VAL)
@ -673,7 +678,8 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
else {
log_error("Parsing command defs: unknown opt arg: %s", name);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
@ -688,7 +694,7 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
if (val_enum == lv_VAL) {
if (strstr(name, "_"))
def->lvt_bits = lv_to_bits(name);
def->lvt_bits = lv_to_bits(cmd, name);
}
if (strstr(name, "_new")) {
@ -711,7 +717,7 @@ static void set_opt_def(struct command *cmd, char *str, struct arg_def *def)
* oo->line = "--opt1 ...";
*/
static void add_oo_definition_line(const char *name, const char *line)
static void add_oo_definition_line(struct command *cmd, const char *name, const char *line)
{
struct oo_line *oo;
char *colon;
@ -724,7 +730,8 @@ static void add_oo_definition_line(const char *name, const char *line)
*colon = '\0';
else {
log_error("Parsing command defs: invalid OO definition");
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
start = strstr(line, ":") + 2;
@ -733,7 +740,7 @@ static void add_oo_definition_line(const char *name, const char *line)
/* Support OO_FOO: continuing on multiple lines. */
static void append_oo_definition_line(const char *new_line)
static void append_oo_definition_line(struct command *cmd, const char *new_line)
{
struct oo_line *oo;
char *old_line;
@ -749,7 +756,8 @@ static void append_oo_definition_line(const char *new_line)
line = dm_malloc(len);
if (!line) {
log_error("Parsing command defs: no memory");
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
memset(line, 0, len);
@ -801,11 +809,14 @@ static void include_optional_opt_args(struct command *cmd, const char *str)
if (!(oo_line = get_oo_line(str))) {
log_error("Parsing command defs: no OO line found for %s", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
if (!(line = dm_strdup(oo_line)))
exit(EXIT_FAILURE);
if (!(line = dm_strdup(oo_line))) {
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
split_line(line, &line_argc, line_argv, ' ');
add_optional_opt_line(cmd, line_argc, line_argv);
@ -838,7 +849,7 @@ static void add_opt_arg(struct command *cmd, char *str, int *takes_arg, int requ
goto skip;
}
opt = opt_str_to_num(str);
opt = opt_str_to_num(cmd, str);
skip:
if (required > 0)
cmd->required_opt_args[cmd->ro_count++].opt = opt;
@ -846,8 +857,6 @@ skip:
cmd->optional_opt_args[cmd->oo_count++].opt = opt;
else if (required < 0)
cmd->ignore_opt_args[cmd->io_count++].opt = opt;
else
exit(EXIT_FAILURE);
*takes_arg = opt_names[opt].val_enum ? 1 : 0;
}
@ -864,7 +873,8 @@ static void update_prev_opt_arg(struct command *cmd, char *str, int required)
if (str[0] == '-') {
log_error("Parsing command defs: option %s must be followed by an arg.", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
/* opt_arg.def set here */
@ -882,7 +892,7 @@ static void update_prev_opt_arg(struct command *cmd, char *str, int required)
else if (required < 0)
cmd->ignore_opt_args[cmd->io_count-1].def = def;
else
exit(EXIT_FAILURE);
return;
}
/*
@ -926,7 +936,8 @@ static void update_prev_pos_arg(struct command *cmd, char *str, int required)
def->flags |= ARG_DEF_FLAG_MAY_REPEAT;
else {
log_error("Parsing command defs: unknown pos arg: %s", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
@ -949,7 +960,8 @@ static void add_optional_opt_line(struct command *cmd, int argc, char *argv[])
else {
log_error("Parsing command defs: can't parse argc %d argv %s prev %s",
i, argv[i], argv[i-1]);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
}
@ -971,7 +983,8 @@ static void add_ignore_opt_line(struct command *cmd, int argc, char *argv[])
else {
log_error("Parsing command defs: can't parse argc %d argv %s prev %s",
i, argv[i], argv[i-1]);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
}
@ -1005,7 +1018,8 @@ static void add_required_opt_line(struct command *cmd, int argc, char *argv[])
else {
log_error("Parsing command defs: can't parse argc %d argv %s prev %s",
i, argv[i], argv[i-1]);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
}
@ -1028,11 +1042,14 @@ static void include_required_opt_args(struct command *cmd, char *str)
if (!(oo_line = get_oo_line(str))) {
log_error("Parsing command defs: no OO line found for %s", str);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
if (!(line = dm_strdup(oo_line)))
exit(EXIT_FAILURE);
if (!(line = dm_strdup(oo_line))) {
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
split_line(line, &line_argc, line_argv, ' ');
add_required_opt_line(cmd, line_argc, line_argv);
@ -1080,9 +1097,9 @@ static void add_required_line(struct command *cmd, int argc, char *argv[])
} else {
log_error("Parsing command defs: can't parse argc %d argv %s prev %s",
i, argv[i], argv[i-1]);
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
}
}
@ -1105,7 +1122,8 @@ static void add_rule(struct command *cmd, char *line)
if (cmd->rule_count == CMD_MAX_RULES) {
log_error("Parsing command defs: too many rules for cmd");
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
rule = &cmd->rules[cmd->rule_count++];
@ -1134,7 +1152,8 @@ static void add_rule(struct command *cmd, char *line)
if (!rule->opts) {
if (!(rule->opts = dm_malloc(MAX_RULE_OPTS * sizeof(int)))) {
log_error("Parsing command defs: no mem");
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
memset(rule->opts, 0, MAX_RULE_OPTS * sizeof(int));
}
@ -1142,19 +1161,20 @@ static void add_rule(struct command *cmd, char *line)
if (!rule->check_opts) {
if (!(rule->check_opts = dm_malloc(MAX_RULE_OPTS * sizeof(int)))) {
log_error("Parsing command defs: no mem");
exit(EXIT_FAILURE);
cmd->cmd_flags |= CMD_FLAG_PARSE_ERROR;
return;
}
memset(rule->check_opts, 0, MAX_RULE_OPTS * sizeof(int));
}
if (check)
rule->check_opts[rule->check_opts_count++] = opt_str_to_num(arg);
rule->check_opts[rule->check_opts_count++] = opt_str_to_num(cmd, arg);
else
rule->opts[rule->opts_count++] = opt_str_to_num(arg);
rule->opts[rule->opts_count++] = opt_str_to_num(cmd, arg);
}
else if (!strncmp(arg, "LV_", 3)) {
lvt_enum = lv_to_enum(arg);
lvt_enum = lv_to_enum(cmd, arg);
if (check)
rule->check_lvt_bits |= lvt_enum_to_bit(lvt_enum);
@ -1163,7 +1183,7 @@ static void add_rule(struct command *cmd, char *line)
}
else if (!strncmp(arg, "lv_is_", 6)) {
lvp_enum = lvp_name_to_enum(arg);
lvp_enum = lvp_name_to_enum(cmd, arg);
if (check)
rule->check_lvp_bits |= lvp_enum_to_bit(lvp_enum);
@ -1315,6 +1335,7 @@ int define_commands(char *run_name)
int prev_was_op = 0;
int copy_pos = 0;
int skip = 0;
int i;
if (run_name && !strcmp(run_name, "help"))
run_name = NULL;
@ -1408,7 +1429,7 @@ int define_commands(char *run_name)
/* OO_FOO: ... */
if (is_oo_definition(line_argv[0])) {
add_oo_definition_line(line_argv[0], line_orig);
add_oo_definition_line(cmd, line_argv[0], line_orig);
prev_was_oo_def = 1;
prev_was_oo = 0;
prev_was_op = 0;
@ -1444,7 +1465,7 @@ int define_commands(char *run_name)
/* handle OO_FOO:, OO:, OP: continuing on multiple lines */
if (prev_was_oo_def) {
append_oo_definition_line(line_orig);
append_oo_definition_line(cmd, line_orig);
continue;
}
@ -1459,6 +1480,11 @@ int define_commands(char *run_name)
}
}
for (i = 0; i < COMMAND_COUNT; i++) {
if (commands[i].cmd_flags & CMD_FLAG_PARSE_ERROR)
return 0;
}
/*
* For usage.
* Predefined string of options common to all commands

View File

@ -166,6 +166,7 @@ struct cmd_rule {
*/
#define CMD_FLAG_ONE_REQUIRED_OPT 1 /* lvchange/vgchage require one item from required_opt_args */
#define CMD_FLAG_SECONDARY_SYNTAX 2 /* allows syntax variants to be suppressed in certain output */
#define CMD_FLAG_PARSE_ERROR 4 /* error parsing command-lines.in def */
/* a register of the lvm commands */
struct command {

View File

@ -32,7 +32,7 @@ void *cmdlib_lvm2_init(unsigned static_compile);
void lvm_fin(struct cmd_context *cmd);
struct cmd_context *init_lvm(unsigned set_connections, unsigned set_filters);
void lvm_register_commands(char *name);
int lvm_register_commands(char *name);
int lvm_split(char *str, int *argc, char **argv, int max);
int lvm_run_command(struct cmd_context *cmd, int argc, char **argv);
int lvm_return_code(int ret);

View File

@ -34,7 +34,8 @@ void *cmdlib_lvm2_init(unsigned static_compile)
if (!(cmd = init_lvm(1, 1)))
return NULL;
lvm_register_commands(NULL);
if (!lvm_register_commands(NULL))
return NULL;
return (void *) cmd;
}

View File

@ -1126,13 +1126,13 @@ static struct command_function *_find_command_id_function(int command_enum)
return NULL;
}
void lvm_register_commands(char *name)
int lvm_register_commands(char *name)
{
int i;
/* already initialized */
if (_cmdline.commands)
return;
return 1;
memset(&commands, 0, sizeof(commands));
@ -1141,8 +1141,8 @@ void lvm_register_commands(char *name)
* by parsing command-lines.in/command-lines-input.h
*/
if (!define_commands(name)) {
log_error("Failed to parse command definitions.");
return;
log_error(INTERNAL_ERROR "Failed to parse command definitions.");
return 0;
}
_cmdline.commands = commands;
@ -1151,6 +1151,13 @@ void lvm_register_commands(char *name)
for (i = 0; i < COMMAND_COUNT; i++) {
commands[i].command_enum = command_id_to_enum(commands[i].command_id);
if (!commands[i].command_enum) {
log_error(INTERNAL_ERROR "Failed to find command id %s.", commands[i].command_id);
_cmdline.commands = NULL;
_cmdline.num_commands = 0;
return 0;
}
/* new style */
commands[i].functions = _find_command_id_function(commands[i].command_enum);
@ -1172,6 +1179,8 @@ void lvm_register_commands(char *name)
for (i = 0; i < _cmdline.num_command_names; i++)
_set_valid_args_for_command_name(i);
return 1;
}
struct lv_props *get_lv_prop(int lvp_enum)
@ -3214,7 +3223,10 @@ int lvm2_main(int argc, char **argv)
else
name = argv[1];
lvm_register_commands(name);
if (!lvm_register_commands(name)) {
ret = ECMD_FAILED;
goto out;
}
if (_lvm1_fallback(cmd)) {
/* Attempt to run equivalent LVM1 tool instead */