summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Teigland <teigland@redhat.com>2017-02-16 15:26:42 -0600
committerDavid Teigland <teigland@redhat.com>2017-02-16 15:26:42 -0600
commit298b11aed1f1517329dc6e5ead661855b1abfb05 (patch)
tree4fe00dcadfbaad1c62a8324e28991137c828a033
parent1cb95fa5a050c5056d882ef9cbb01ce8040df019 (diff)
downloadlvm2-298b11aed1f1517329dc6e5ead661855b1abfb05.tar.gz
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.
-rw-r--r--tools/command.c126
-rw-r--r--tools/command.h1
-rw-r--r--tools/lvm2cmdline.h2
-rw-r--r--tools/lvmcmdlib.c3
-rw-r--r--tools/lvmcmdline.c22
5 files changed, 97 insertions, 57 deletions
diff --git a/tools/command.c b/tools/command.c
index 6814a54a5..5b31b4ef2 100644
--- a/tools/command.c
+++ b/tools/command.c
@@ -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
diff --git a/tools/command.h b/tools/command.h
index 0c3f9f3b7..fcf0ccb7a 100644
--- a/tools/command.h
+++ b/tools/command.h
@@ -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 {
diff --git a/tools/lvm2cmdline.h b/tools/lvm2cmdline.h
index 00162a48d..5c5eaee90 100644
--- a/tools/lvm2cmdline.h
+++ b/tools/lvm2cmdline.h
@@ -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);
diff --git a/tools/lvmcmdlib.c b/tools/lvmcmdlib.c
index 9e50343a4..8f15c1fc8 100644
--- a/tools/lvmcmdlib.c
+++ b/tools/lvmcmdlib.c
@@ -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;
}
diff --git a/tools/lvmcmdline.c b/tools/lvmcmdline.c
index e599ded74..7e50d054d 100644
--- a/tools/lvmcmdline.c
+++ b/tools/lvmcmdline.c
@@ -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 */