Commit c51a6379 authored by Daniel Borkmann's avatar Daniel Borkmann

Merge branch 'bpf-bpftool-batch-improvements'

Quentin Monnet says:

====================
Several enhancements for bpftool batch mode are introduced in this series.

More specifically, input files for batch mode gain support for:
  * comments (starting with '#'),
  * continuation lines (after a line ending with '\'),
  * arguments enclosed between quotes.

Also, make bpftool able to read from standard input when "-" is provided as
input file name.
====================
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parents 56b112f1 668da745
...@@ -46,6 +46,9 @@ ...@@ -46,6 +46,9 @@
#include "main.h" #include "main.h"
#define BATCH_LINE_LEN_MAX 65536
#define BATCH_ARG_NB_MAX 4096
const char *bin_name; const char *bin_name;
static int last_argc; static int last_argc;
static char **last_argv; static char **last_argv;
...@@ -157,6 +160,54 @@ void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep) ...@@ -157,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 int do_batch(int argc, char **argv);
static const struct cmd cmds[] = { static const struct cmd cmds[] = {
...@@ -171,11 +222,12 @@ static const struct cmd cmds[] = { ...@@ -171,11 +222,12 @@ static const struct cmd cmds[] = {
static int do_batch(int argc, char **argv) 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; unsigned int lines = 0;
char *n_argv[4096];
char buf[65536];
int n_argc; int n_argc;
FILE *fp; FILE *fp;
char *cp;
int err; int err;
int i; int i;
...@@ -191,7 +243,10 @@ static int do_batch(int argc, char **argv) ...@@ -191,7 +243,10 @@ static int do_batch(int argc, char **argv)
} }
NEXT_ARG(); NEXT_ARG();
fp = fopen(*argv, "r"); if (!strcmp(*argv, "-"))
fp = stdin;
else
fp = fopen(*argv, "r");
if (!fp) { if (!fp) {
p_err("Can't open file (%s): %s", *argv, strerror(errno)); p_err("Can't open file (%s): %s", *argv, strerror(errno));
return -1; return -1;
...@@ -200,27 +255,45 @@ static int do_batch(int argc, char **argv) ...@@ -200,27 +255,45 @@ static int do_batch(int argc, char **argv)
if (json_output) if (json_output)
jsonw_start_array(json_wtr); jsonw_start_array(json_wtr);
while (fgets(buf, sizeof(buf), fp)) { while (fgets(buf, sizeof(buf), fp)) {
cp = strchr(buf, '#');
if (cp)
*cp = '\0';
if (strlen(buf) == sizeof(buf) - 1) { if (strlen(buf) == sizeof(buf) - 1) {
errno = E2BIG; errno = E2BIG;
break; break;
} }
n_argc = 0; /* Append continuation lines if any (coming after a line ending
n_argv[n_argc] = strtok(buf, " \t\n"); * with '\' in the batch file).
*/
while (n_argv[n_argc]) { while ((cp = strstr(buf, "\\\n")) != NULL) {
n_argc++; if (!fgets(contline, sizeof(contline), fp) ||
if (n_argc == ARRAY_SIZE(n_argv)) { strlen(contline) == 0) {
p_err("line %d has too many arguments, skip", p_err("missing continuation line on command %d",
lines); lines);
n_argc = 0; err = -1;
break; 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;
} }
n_argv[n_argc] = strtok(NULL, " \t\n"); buf[strlen(buf) - 2] = '\0';
strcat(buf, contline);
} }
n_argc = make_args(buf, n_argv, BATCH_ARG_NB_MAX, lines);
if (!n_argc) if (!n_argc)
continue; continue;
if (n_argc < 0)
goto err_close;
if (json_output) { if (json_output) {
jsonw_start_object(json_wtr); jsonw_start_object(json_wtr);
...@@ -247,11 +320,12 @@ static int do_batch(int argc, char **argv) ...@@ -247,11 +320,12 @@ static int do_batch(int argc, char **argv)
p_err("reading batch file failed: %s", strerror(errno)); p_err("reading batch file failed: %s", strerror(errno));
err = -1; err = -1;
} else { } else {
p_info("processed %d lines", lines); p_info("processed %d commands", lines);
err = 0; err = 0;
} }
err_close: err_close:
fclose(fp); if (fp != stdin)
fclose(fp);
if (json_output) if (json_output)
jsonw_end_array(json_wtr); jsonw_end_array(json_wtr);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment