From 06cc7fe7c2951e64cd5e73ea447791c7e6bc3852 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Thu, 1 Mar 2018 20:20:08 -0800 Subject: tools: bpftool: support comments in batch files Replace '#' by '\0' in commands read from batch files in order to avoid processing the remaining part of the line, thus allowing users to use comments in the files. Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 185acfa229b5..79587e6decae 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -176,6 +176,7 @@ static int do_batch(int argc, char **argv) char buf[65536]; int n_argc; FILE *fp; + char *cp; int err; int i; @@ -200,6 +201,10 @@ static int do_batch(int argc, char **argv) if (json_output) jsonw_start_array(json_wtr); while (fgets(buf, sizeof(buf), fp)) { + cp = strchr(buf, '#'); + if (cp) + *cp = '\0'; + if (strlen(buf) == sizeof(buf) - 1) { errno = E2BIG; break; -- cgit v1.2.3 From 65d538dde625d93359ca4e33d2311f8598f423a6 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Thu, 1 Mar 2018 20:20:09 -0800 Subject: tools: bpftool: support continuation lines in batch files Add support for continuation lines, such as in the following example: prog show prog dump xlated \ id 1337 opcodes This patch is based after the code for support for continuation lines from file lib/utils.c from package iproute2. "Lines" in error messages are renamed as "commands", as we count the number of commands (but we ignore empty lines, comments, and do not add continuation lines to the count). Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 79587e6decae..cdee4c3d30c3 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -46,6 +46,9 @@ #include "main.h" +#define BATCH_LINE_LEN_MAX 65536 +#define BATCH_ARG_NB_MAX 4096 + const char *bin_name; static int last_argc; static char **last_argv; @@ -171,9 +174,9 @@ static const struct cmd cmds[] = { static int do_batch(int argc, char **argv) { + char buf[BATCH_LINE_LEN_MAX], contline[BATCH_LINE_LEN_MAX]; + char *n_argv[BATCH_ARG_NB_MAX]; unsigned int lines = 0; - char *n_argv[4096]; - char buf[65536]; int n_argc; FILE *fp; char *cp; @@ -210,13 +213,38 @@ static int do_batch(int argc, char **argv) break; } + /* Append continuation lines if any (coming after a line ending + * with '\' in the batch file). + */ + while ((cp = strstr(buf, "\\\n")) != NULL) { + if (!fgets(contline, sizeof(contline), fp) || + strlen(contline) == 0) { + p_err("missing continuation line on command %d", + lines); + err = -1; + goto err_close; + } + + cp = strchr(contline, '#'); + if (cp) + *cp = '\0'; + + if (strlen(buf) + strlen(contline) + 1 > sizeof(buf)) { + p_err("command %d is too long", lines); + err = -1; + goto err_close; + } + buf[strlen(buf) - 2] = '\0'; + strcat(buf, contline); + } + n_argc = 0; n_argv[n_argc] = strtok(buf, " \t\n"); while (n_argv[n_argc]) { n_argc++; if (n_argc == ARRAY_SIZE(n_argv)) { - p_err("line %d has too many arguments, skip", + p_err("command %d has too many arguments, skip", lines); n_argc = 0; break; @@ -252,7 +280,7 @@ static int do_batch(int argc, char **argv) p_err("reading batch file failed: %s", strerror(errno)); err = -1; } else { - p_info("processed %d lines", lines); + p_info("processed %d commands", lines); err = 0; } err_close: -- cgit v1.2.3 From 416656bbaa57a5be75514498491b7e24c58537c1 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Thu, 1 Mar 2018 20:20:10 -0800 Subject: tools: bpftool: read from stdin when batch file name is "-" Make bpftool read its command list from standard input when the name if the input file is a single dash. Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index cdee4c3d30c3..1da54a9b5ea3 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -195,7 +195,10 @@ static int do_batch(int argc, char **argv) } NEXT_ARG(); - fp = fopen(*argv, "r"); + if (!strcmp(*argv, "-")) + fp = stdin; + else + fp = fopen(*argv, "r"); if (!fp) { p_err("Can't open file (%s): %s", *argv, strerror(errno)); return -1; @@ -284,7 +287,8 @@ static int do_batch(int argc, char **argv) err = 0; } err_close: - fclose(fp); + if (fp != stdin) + fclose(fp); if (json_output) jsonw_end_array(json_wtr); -- cgit v1.2.3 From 668da745af3c29d5742238ef278a1b2055c97e51 Mon Sep 17 00:00:00 2001 From: Quentin Monnet Date: Thu, 1 Mar 2018 20:20:11 -0800 Subject: tools: bpftool: add support for quotations in batch files Improve argument parsing from batch input files in order to support arguments enclosed between single (') or double quotes ("). For example, this command can now be parsed in batch mode: bpftool prog dump xlated id 1337 file "/tmp/my file with spaces" The function responsible for parsing command arguments is copied from its counterpart in lib/utils.c in iproute2 package. Signed-off-by: Quentin Monnet Acked-by: Jakub Kicinski Signed-off-by: Daniel Borkmann --- tools/bpf/bpftool/main.c | 65 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 51 insertions(+), 14 deletions(-) diff --git a/tools/bpf/bpftool/main.c b/tools/bpf/bpftool/main.c index 1da54a9b5ea3..1ec852d21d44 100644 --- a/tools/bpf/bpftool/main.c +++ b/tools/bpf/bpftool/main.c @@ -160,6 +160,54 @@ void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) } } +/* Split command line into argument vector. */ +static int make_args(char *line, char *n_argv[], int maxargs, int cmd_nb) +{ + static const char ws[] = " \t\r\n"; + char *cp = line; + int n_argc = 0; + + while (*cp) { + /* Skip leading whitespace. */ + cp += strspn(cp, ws); + + if (*cp == '\0') + break; + + if (n_argc >= (maxargs - 1)) { + p_err("too many arguments to command %d", cmd_nb); + return -1; + } + + /* Word begins with quote. */ + if (*cp == '\'' || *cp == '"') { + char quote = *cp++; + + n_argv[n_argc++] = cp; + /* Find ending quote. */ + cp = strchr(cp, quote); + if (!cp) { + p_err("unterminated quoted string in command %d", + cmd_nb); + return -1; + } + } else { + n_argv[n_argc++] = cp; + + /* Find end of word. */ + cp += strcspn(cp, ws); + if (*cp == '\0') + break; + } + + /* Separate words. */ + *cp++ = 0; + } + n_argv[n_argc] = NULL; + + return n_argc; +} + static int do_batch(int argc, char **argv); static const struct cmd cmds[] = { @@ -241,22 +289,11 @@ static int do_batch(int argc, char **argv) strcat(buf, contline); } - n_argc = 0; - n_argv[n_argc] = strtok(buf, " \t\n"); - - while (n_argv[n_argc]) { - n_argc++; - if (n_argc == ARRAY_SIZE(n_argv)) { - p_err("command %d has too many arguments, skip", - lines); - n_argc = 0; - break; - } - n_argv[n_argc] = strtok(NULL, " \t\n"); - } - + n_argc = make_args(buf, n_argv, BATCH_ARG_NB_MAX, lines); if (!n_argc) continue; + if (n_argc < 0) + goto err_close; if (json_output) { jsonw_start_object(json_wtr); -- cgit v1.2.3