I think it would be helpful to the user to list the condition and action
names, when the condition or action name is missing or unrecognized.
This patch implements that, here are some examples of the result:
$ lttng add-trigger --action notify --condition
Error: While parsing argument #4: Missing required argument for option `--condition`
Error: Valid condition names are:
Error: event-rule-matches
$ lttng add-trigger --action notify --condition pouet
Error: While parsing argument #5: Unknown condition name 'pouet'
Error: Valid condition names are:
Error: event-rule-matches
$ lttng add-trigger --condition event-rule-matches --action
Error: While parsing argument #4: Missing required argument for option `--action`
Error: Valid action names are:
Error: notify
$ lttng add-trigger --condition event-rule-matches --action pouet
Error: While parsing argument #5: Unknown action name: pouet
Error: Valid action names are:
Error: notify
To achieve this, add a new optional out argument to parse_next_item, to
allow the caller to get the argpar_error object if a parsing error
happened. Because of this, the callers must now be able to
differentiate parsing error from memory errors: in the latter case, no
argpar_error object is returned. So, add a new
PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY status, and make users of
parse_next_item handle it.
In the add-trigger command implementation, handle the "missing opt arg"
case of OPT_ACTION and OPT_CONDITION specially to print the valid names.
Handle unknown names in parse_action and parse_condition.
Add a test for an unknown action name, it seems to be missing. Change
the error message format slightly to make it match the messages for
unknown condition names.
Change-Id: I4c13cecacb3a2ff4367e391c4aba0d05f1f28f22
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item,
- argc_offset, *argv, false, NULL);
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ argc_offset, *argv, false, NULL, NULL);
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
{ "event-rule-matches", handle_condition_event },
};
{ "event-rule-matches", handle_condition_event },
};
+static
+void print_valid_condition_names(void)
+{
+ unsigned int i;
+
+ ERR("Valid condition names are:");
+
+ for (i = 0; i < ARRAY_SIZE(condition_descrs); ++i) {
+ ERR(" %s", condition_descrs[i].name);
+ }
+}
+
static
struct lttng_condition *parse_condition(const char *condition_name, int *argc,
const char ***argv, int argc_offset, int orig_arg_index,
static
struct lttng_condition *parse_condition(const char *condition_name, int *argc,
const char ***argv, int argc_offset, int orig_arg_index,
if (!descr) {
ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown condition name '%s'",
orig_arg_index + 1, orig_arg, condition_name);
if (!descr) {
ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown condition name '%s'",
orig_arg_index + 1, orig_arg, condition_name);
+ print_valid_condition_names();
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item,
- argc_offset, *argv, false,
+ argc_offset, *argv, false, NULL,
"While parsing `notify` action:");
"While parsing `notify` action:");
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
"While parsing `%s` action:", action_name);
"While parsing `%s` action:", action_name);
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, argc_offset,
- *argv, false, "While parsing `snapshot` action:");
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ *argv, false, NULL, "While parsing `snapshot` action:");
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
{ "snapshot-session", handle_action_snapshot_session },
};
{ "snapshot-session", handle_action_snapshot_session },
};
+static
+void print_valid_action_names(void)
+{
+ unsigned int i;
+
+ ERR("Valid action names are:");
+
+ for (i = 0; i < ARRAY_SIZE(condition_descrs); ++i) {
+ ERR(" %s", action_descrs[i].name);
+ }
+}
+
static
struct lttng_action *parse_action(const char *action_name, int *argc,
const char ***argv, int argc_offset, int orig_arg_index,
static
struct lttng_action *parse_action(const char *action_name, int *argc,
const char ***argv, int argc_offset, int orig_arg_index,
- ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown action name: %s",
+ ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown action name '%s'",
orig_arg_index + 1, orig_arg, action_name);
orig_arg_index + 1, orig_arg, action_name);
+ print_valid_action_names();
struct lttng_dynamic_pointer_array actions;
struct argpar_iter *argpar_iter = NULL;
const struct argpar_item *argpar_item = NULL;
struct lttng_dynamic_pointer_array actions;
struct argpar_iter *argpar_iter = NULL;
const struct argpar_item *argpar_item = NULL;
+ const struct argpar_error *argpar_error = NULL;
struct lttng_action *action_list = NULL;
struct lttng_action *action = NULL;
struct lttng_trigger *trigger = NULL;
struct lttng_action *action_list = NULL;
struct lttng_action *action = NULL;
struct lttng_trigger *trigger = NULL;
}
status = parse_next_item(argpar_iter, &argpar_item,
}
status = parse_next_item(argpar_iter, &argpar_item,
- argc - my_argc, my_argv, true, NULL);
+ argc - my_argc, my_argv, true, &argpar_error, NULL);
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+
+ if (argpar_error_type(argpar_error) ==
+ ARGPAR_ERROR_TYPE_MISSING_OPT_ARG) {
+ int opt_id = argpar_error_opt_descr(argpar_error, NULL)->id;
+
+ if (opt_id == OPT_CONDITION) {
+ print_valid_condition_names();
+ } else if (opt_id == OPT_ACTION) {
+ print_valid_action_names();
+ }
+ }
+
+ goto error;
+ } else if (status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
+ argpar_error_destroy(argpar_error);
argpar_iter_destroy(argpar_iter);
argpar_item_destroy(argpar_item);
lttng_dynamic_pointer_array_reset(&actions);
argpar_iter_destroy(argpar_iter);
argpar_item_destroy(argpar_item);
lttng_dynamic_pointer_array_reset(&actions);
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
- true, NULL);
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ true, NULL, NULL);
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
enum parse_next_item_status status;
status = parse_next_item(argpar_iter, &argpar_item, 1, argv,
- true, NULL);
- if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
+ true, NULL, NULL);
+ if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
+ status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
goto error;
} else if (status == PARSE_NEXT_ITEM_STATUS_END) {
break;
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
const struct argpar_item **item, int argc_offset,
const char **argv, bool unknown_opt_is_error,
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
const struct argpar_item **item, int argc_offset,
const char **argv, bool unknown_opt_is_error,
+ const struct argpar_error **error_out,
const char *context_fmt, ...)
{
enum argpar_iter_next_status status;
const char *context_fmt, ...)
{
enum argpar_iter_next_status status;
switch (status) {
case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
ERR("Failed to get next argpar item.");
switch (status) {
case ARGPAR_ITER_NEXT_STATUS_ERROR_MEMORY:
ERR("Failed to get next argpar item.");
- ret = PARSE_NEXT_ITEM_STATUS_ERROR;
+ ret = PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY;
break;
case ARGPAR_ITER_NEXT_STATUS_ERROR:
{
break;
case ARGPAR_ITER_NEXT_STATUS_ERROR:
{
+ if (error_out) {
+ argpar_error_destroy(*error_out);
+ *error_out = error;
+ error = NULL;
+ }
+
argpar_error_destroy(error);
return ret;
argpar_error_destroy(error);
return ret;
PARSE_NEXT_ITEM_STATUS_OK = 0,
PARSE_NEXT_ITEM_STATUS_END = 1,
PARSE_NEXT_ITEM_STATUS_ERROR = -1,
PARSE_NEXT_ITEM_STATUS_OK = 0,
PARSE_NEXT_ITEM_STATUS_END = 1,
PARSE_NEXT_ITEM_STATUS_ERROR = -1,
+ PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY = -2,
*
* If `unknown_opt_is_error` is true, an unknown option is considered an error.
* Otherwise, it is considered as the end of the argument list.
*
* If `unknown_opt_is_error` is true, an unknown option is considered an error.
* Otherwise, it is considered as the end of the argument list.
+ *
+ * If `error_out` is given and PARSE_NEXT_ITEM_STATUS_ERROR is returned, set
+ * `*error_out` to the argpar_error object corresponding to the error. The
+ * caller must free the object with `argpar_error_destroy`.
*/
LTTNG_HIDDEN
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
const struct argpar_item **item, int argc_offset,
const char **argv, bool unknown_opt_is_error,
*/
LTTNG_HIDDEN
enum parse_next_item_status parse_next_item(struct argpar_iter *iter,
const struct argpar_item **item, int argc_offset,
const char **argv, bool unknown_opt_is_error,
+ const struct argpar_error **error_out,
const char *context_fmt, ...);
#endif
const char *context_fmt, ...);
#endif
# shellcheck source=../../../utils/utils.sh
source "$TESTDIR/utils/utils.sh"
# shellcheck source=../../../utils/utils.sh
source "$TESTDIR/utils/utils.sh"
FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
FULL_LTTNG_BIN="${TESTDIR}/../src/bin/lttng/${LTTNG_BIN}"
# `--condition` failures
test_failure "missing args after --condition" \
# `--condition` failures
test_failure "missing args after --condition" \
- "Error: While parsing argument #2 (\`--condition\`): Missing required argument for option \`--condition\`" \
+ "Error: While parsing argument #2 (\`--condition\`): Missing required argument for option \`--condition\`
+Error: Valid condition names are:
+Error: event-rule-matches" \
--condition
test_failure "unknown --condition" \
--condition
test_failure "unknown --condition" \
- "Error: While parsing argument #2 (\`--condition\`): Unknown condition name 'zoofest'" \
+ "Error: While parsing argument #2 (\`--condition\`): Unknown condition name 'zoofest'
+Error: Valid condition names are:
+Error: event-rule-matches" \
--condition zoofest
test_failure "unknown --condition=" \
--condition zoofest
test_failure "unknown --condition=" \
- "Error: While parsing argument #2 (\`--condition=zoofest\`): Unknown condition name 'zoofest'" \
+ "Error: While parsing argument #2 (\`--condition=zoofest\`): Unknown condition name 'zoofest'
+Error: Valid condition names are:
+Error: event-rule-matches" \
--condition=zoofest
# `--condition event-rule-matches` failures
--condition=zoofest
# `--condition event-rule-matches` failures
# `--action` failures
test_failure "missing args after --action" \
# `--action` failures
test_failure "missing args after --action" \
- "Error: While parsing argument #5 (\`--action\`): Missing required argument for option \`--action\`" \
+ "Error: While parsing argument #5 (\`--action\`): Missing required argument for option \`--action\`
+Error: Valid action names are:
+Error: notify" \
--condition event-rule-matches --type=user \
--action
--condition event-rule-matches --type=user \
--action
+test_failure "unknown --action" \
+ "Error: While parsing argument #5 (\`--action\`): Unknown action name 'zoofest'
+Error: Valid action names are:
+Error: notify" \
+ --condition event-rule-matches --type=user \
+ --action zoofest
+
+test_failure "unknown --action=" \
+ "Error: While parsing argument #5 (\`--action=zoofest\`): Unknown action name 'zoofest'
+Error: Valid action names are:
+Error: notify" \
+ --condition event-rule-matches --type=user \
+ --action=zoofest
+
# `--action notify` failures
test_failure "extra arg after --action notify" \
"Error: Unexpected argument \`bob\`." \
# `--action notify` failures
test_failure "extra arg after --action notify" \
"Error: Unexpected argument \`bob\`." \