Skip to content

Commit

Permalink
Validate command argument types (string or command list) and give more
Browse files Browse the repository at this point in the history
useful error messages.
  • Loading branch information
nicm committed Aug 25, 2021
1 parent 45a9d9d commit e4c0b81
Show file tree
Hide file tree
Showing 12 changed files with 242 additions and 56 deletions.
89 changes: 79 additions & 10 deletions usr.bin/tmux/arguments.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: arguments.c,v 1.46 2021/08/23 17:05:43 nicm Exp $ */
/* $OpenBSD: arguments.c,v 1.47 2021/08/25 08:51:55 nicm Exp $ */

/*
* Copyright (c) 2010 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -124,10 +124,11 @@ args_create(void)
/* Parse arguments into a new argument set. */
struct args *
args_parse(const struct args_parse *parse, struct args_value *values,
u_int count)
u_int count, char **cause)
{
struct args *args;
u_int i;
enum args_parse_type type;
struct args_value *value, *new;
u_char flag, argument;
const char *found, *string, *s;
Expand All @@ -153,11 +154,13 @@ args_parse(const struct args_parse *parse, struct args_value *values,
if (flag == '\0')
break;
if (!isalnum(flag)) {
xasprintf(cause, "invalid flag -%c", flag);
args_free(args);
return (NULL);
}
found = strchr(parse->template, flag);
if (found == NULL) {
xasprintf(cause, "unknown flag -%c", flag);
args_free(args);
return (NULL);
}
Expand All @@ -167,12 +170,22 @@ args_parse(const struct args_parse *parse, struct args_value *values,
args_set(args, flag, NULL);
continue;
}
new = xcalloc(1, sizeof *value);
new = xcalloc(1, sizeof *new);
if (*string != '\0') {
new->type = ARGS_STRING;
new->string = xstrdup(string);
} else {
if (i == count) {
xasprintf(cause,
"-%c expects an argument",
flag);
args_free(args);
return (NULL);
}
if (values[i].type != ARGS_STRING) {
xasprintf(cause,
"-%c argument must be a string",
flag);
args_free(args);
return (NULL);
}
Expand All @@ -192,14 +205,60 @@ args_parse(const struct args_parse *parse, struct args_value *values,
s = args_value_as_string(value);
log_debug("%s: %u = %s", __func__, i, s);

if (parse->cb != NULL) {
type = parse->cb(args, args->count, cause);
if (type == ARGS_PARSE_INVALID) {
args_free(args);
return (NULL);
}
} else
type = ARGS_PARSE_STRING;

args->values = xrecallocarray(args->values,
args->count, args->count + 1, sizeof *args->values);
args_copy_value(&args->values[args->count++], value);
new = &args->values[args->count++];

switch (type) {
case ARGS_PARSE_INVALID:
fatalx("unexpected argument type");
case ARGS_PARSE_STRING:
if (value->type != ARGS_STRING) {
xasprintf(cause,
"argument %u must be \"string\"",
args->count);
args_free(args);
return (NULL);
}
args_copy_value(new, value);
break;
case ARGS_PARSE_COMMANDS_OR_STRING:
args_copy_value(new, value);
break;
case ARGS_PARSE_COMMANDS:
if (value->type != ARGS_COMMANDS) {
xasprintf(cause,
"argument %u must be { commands }",
args->count);
args_free(args);
return (NULL);
}
args_copy_value(new, value);
break;
}
}
}

if ((parse->lower != -1 && args->count < (u_int)parse->lower) ||
(parse->upper != -1 && args->count > (u_int)parse->upper)) {
if (parse->lower != -1 && args->count < (u_int)parse->lower) {
xasprintf(cause,
"too few arguments (need at least %u)",
parse->lower);
args_free(args);
return (NULL);
}
if (parse->upper != -1 && args->count > (u_int)parse->upper) {
xasprintf(cause,
"too many arguments (need at most %u)",
parse->upper);
args_free(args);
return (NULL);
}
Expand Down Expand Up @@ -254,15 +313,25 @@ args_free(struct args *args)
void
args_vector(struct args *args, int *argc, char ***argv)
{
struct args_value *value;
u_int i;
char *s;
u_int i;

*argc = 0;
*argv = NULL;

for (i = 0; i < args->count; i++) {
value = &args->values[i];
cmd_append_argv(argc, argv, args_value_as_string(value));
switch (args->values[i].type) {
case ARGS_NONE:
break;
case ARGS_STRING:
cmd_append_argv(argc, argv, args->values[i].string);
break;
case ARGS_COMMANDS:
s = cmd_list_print(args->values[i].cmdlist, 0);
cmd_append_argv(argc, argv, s);
free(s);
break;
}
}
}

Expand Down
18 changes: 15 additions & 3 deletions usr.bin/tmux/cmd-bind-key.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd-bind-key.c,v 1.43 2021/08/23 11:48:21 nicm Exp $ */
/* $OpenBSD: cmd-bind-key.c,v 1.44 2021/08/25 08:51:55 nicm Exp $ */

/*
* Copyright (c) 2007 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -27,20 +27,32 @@
* Bind a key to a command.
*/

static enum cmd_retval cmd_bind_key_exec(struct cmd *, struct cmdq_item *);
static enum args_parse_type cmd_bind_key_args_parse(struct args *, u_int,
char **);
static enum cmd_retval cmd_bind_key_exec(struct cmd *,
struct cmdq_item *);

const struct cmd_entry cmd_bind_key_entry = {
.name = "bind-key",
.alias = "bind",

.args = { "nrN:T:", 1, -1, NULL },
.args = { "nrN:T:", 1, -1, cmd_bind_key_args_parse },
.usage = "[-nr] [-T key-table] [-N note] key "
"[command [arguments]]",

.flags = CMD_AFTERHOOK,
.exec = cmd_bind_key_exec
};

static enum args_parse_type
cmd_bind_key_args_parse(__unused struct args *args, u_int idx,
__unused char **cause)
{
if (idx == 1)
return (ARGS_PARSE_COMMANDS_OR_STRING);
return (ARGS_PARSE_STRING);
}

static enum cmd_retval
cmd_bind_key_exec(struct cmd *self, struct cmdq_item *item)
{
Expand Down
21 changes: 15 additions & 6 deletions usr.bin/tmux/cmd-command-prompt.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd-command-prompt.c,v 1.61 2021/08/25 06:36:05 nicm Exp $ */
/* $OpenBSD: cmd-command-prompt.c,v 1.62 2021/08/25 08:51:55 nicm Exp $ */

/*
* Copyright (c) 2008 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -29,8 +29,10 @@
* Prompt for command in client.
*/

static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);
static enum args_parse_type cmd_command_prompt_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_command_prompt_exec(struct cmd *,
struct cmdq_item *);

static int cmd_command_prompt_callback(struct client *, void *,
const char *, int);
Expand All @@ -40,7 +42,7 @@ const struct cmd_entry cmd_command_prompt_entry = {
.name = "command-prompt",
.alias = NULL,

.args = { "1bFkiI:Np:t:T:", 0, 1, NULL },
.args = { "1bFkiI:Np:t:T:", 0, 1, cmd_command_prompt_args_parse },
.usage = "[-1bFkiN] [-I inputs] [-p prompts] " CMD_TARGET_CLIENT_USAGE
" [-T type] [template]",

Expand Down Expand Up @@ -68,6 +70,13 @@ struct cmd_command_prompt_cdata {
char **argv;
};

static enum args_parse_type
cmd_command_prompt_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}

static enum cmd_retval
cmd_command_prompt_exec(struct cmd *self, struct cmdq_item *item)
{
Expand Down Expand Up @@ -197,8 +206,8 @@ cmd_command_prompt_callback(struct client *c, void *data, const char *s,
return (1);

out:
if (item != NULL)
cmdq_continue(item);
if (item != NULL)
cmdq_continue(item);
return (0);
}

Expand Down
17 changes: 13 additions & 4 deletions usr.bin/tmux/cmd-confirm-before.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd-confirm-before.c,v 1.49 2021/08/23 12:33:55 nicm Exp $ */
/* $OpenBSD: cmd-confirm-before.c,v 1.50 2021/08/25 08:51:55 nicm Exp $ */

/*
* Copyright (c) 2009 Tiago Cunha <[email protected]>
Expand Down Expand Up @@ -28,8 +28,10 @@
* Asks for confirmation before executing a command.
*/

static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);
static enum args_parse_type cmd_confirm_before_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_confirm_before_exec(struct cmd *,
struct cmdq_item *);

static int cmd_confirm_before_callback(struct client *, void *,
const char *, int);
Expand All @@ -39,7 +41,7 @@ const struct cmd_entry cmd_confirm_before_entry = {
.name = "confirm-before",
.alias = "confirm",

.args = { "bp:t:", 1, 1, NULL },
.args = { "bp:t:", 1, 1, cmd_confirm_before_args_parse },
.usage = "[-b] [-p prompt] " CMD_TARGET_CLIENT_USAGE " command",

.flags = CMD_CLIENT_TFLAG,
Expand All @@ -51,6 +53,13 @@ struct cmd_confirm_before_data {
struct cmd_list *cmdlist;
};

static enum args_parse_type
cmd_confirm_before_args_parse(__unused struct args *args, __unused u_int idx,
__unused char **cause)
{
return (ARGS_PARSE_COMMANDS_OR_STRING);
}

static enum cmd_retval
cmd_confirm_before_exec(struct cmd *self, struct cmdq_item *item)
{
Expand Down
42 changes: 34 additions & 8 deletions usr.bin/tmux/cmd-display-menu.c
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* $OpenBSD: cmd-display-menu.c,v 1.31 2021/08/23 08:17:41 nicm Exp $ */
/* $OpenBSD: cmd-display-menu.c,v 1.32 2021/08/25 08:51:55 nicm Exp $ */

/*
* Copyright (c) 2019 Nicholas Marriott <[email protected]>
Expand Down Expand Up @@ -28,16 +28,18 @@
* Display a menu on a client.
*/

static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);
static enum args_parse_type cmd_display_menu_args_parse(struct args *,
u_int, char **);
static enum cmd_retval cmd_display_menu_exec(struct cmd *,
struct cmdq_item *);
static enum cmd_retval cmd_display_popup_exec(struct cmd *,
struct cmdq_item *);

const struct cmd_entry cmd_display_menu_entry = {
.name = "display-menu",
.alias = "menu",

.args = { "c:t:OT:x:y:", 1, -1, NULL },
.args = { "c:t:OT:x:y:", 1, -1, cmd_display_menu_args_parse },
.usage = "[-O] [-c target-client] " CMD_TARGET_PANE_USAGE " [-T title] "
"[-x position] [-y position] name key command ...",

Expand All @@ -53,15 +55,39 @@ const struct cmd_entry cmd_display_popup_entry = {

.args = { "BCc:d:Eh:t:w:x:y:", 0, -1, NULL },
.usage = "[-BCE] [-c target-client] [-d start-directory] [-h height] "
CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [command]",
CMD_TARGET_PANE_USAGE " [-w width] "
"[-x position] [-y position] [shell-command]",

.target = { 't', CMD_FIND_PANE, 0 },

.flags = CMD_AFTERHOOK|CMD_CLIENT_CFLAG,
.exec = cmd_display_popup_exec
};

static enum args_parse_type
cmd_display_menu_args_parse(struct args *args, u_int idx, __unused char **cause)
{
u_int i = 0;
enum args_parse_type type = ARGS_PARSE_STRING;

for (;;) {
type = ARGS_PARSE_STRING;
if (i == idx)
break;
if (*args_string(args, i++) == '\0')
continue;

type = ARGS_PARSE_STRING;
if (i++ == idx)
break;

type = ARGS_PARSE_COMMANDS_OR_STRING;
if (i++ == idx)
break;
}
return (type);
}

static int
cmd_display_menu_get_position(struct client *tc, struct cmdq_item *item,
struct args *args, u_int *px, u_int *py, u_int w, u_int h)
Expand Down
Loading

0 comments on commit e4c0b81

Please sign in to comment.