xref: /kernel/linux/linux-6.6/tools/bpf/bpftool/main.c (revision 62306a36)
162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
262306a36Sopenharmony_ci/* Copyright (C) 2017-2018 Netronome Systems, Inc. */
362306a36Sopenharmony_ci
462306a36Sopenharmony_ci#include <ctype.h>
562306a36Sopenharmony_ci#include <errno.h>
662306a36Sopenharmony_ci#include <getopt.h>
762306a36Sopenharmony_ci#include <linux/bpf.h>
862306a36Sopenharmony_ci#include <stdio.h>
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <string.h>
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#include <bpf/bpf.h>
1362306a36Sopenharmony_ci#include <bpf/btf.h>
1462306a36Sopenharmony_ci#include <bpf/hashmap.h>
1562306a36Sopenharmony_ci#include <bpf/libbpf.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "main.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define BATCH_LINE_LEN_MAX 65536
2062306a36Sopenharmony_ci#define BATCH_ARG_NB_MAX 4096
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ciconst char *bin_name;
2362306a36Sopenharmony_cistatic int last_argc;
2462306a36Sopenharmony_cistatic char **last_argv;
2562306a36Sopenharmony_cistatic int (*last_do_help)(int argc, char **argv);
2662306a36Sopenharmony_cijson_writer_t *json_wtr;
2762306a36Sopenharmony_cibool pretty_output;
2862306a36Sopenharmony_cibool json_output;
2962306a36Sopenharmony_cibool show_pinned;
3062306a36Sopenharmony_cibool block_mount;
3162306a36Sopenharmony_cibool verifier_logs;
3262306a36Sopenharmony_cibool relaxed_maps;
3362306a36Sopenharmony_cibool use_loader;
3462306a36Sopenharmony_cistruct btf *base_btf;
3562306a36Sopenharmony_cistruct hashmap *refs_table;
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_cistatic void __noreturn clean_and_exit(int i)
3862306a36Sopenharmony_ci{
3962306a36Sopenharmony_ci	if (json_output)
4062306a36Sopenharmony_ci		jsonw_destroy(&json_wtr);
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci	exit(i);
4362306a36Sopenharmony_ci}
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_civoid usage(void)
4662306a36Sopenharmony_ci{
4762306a36Sopenharmony_ci	last_do_help(last_argc - 1, last_argv + 1);
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	clean_and_exit(-1);
5062306a36Sopenharmony_ci}
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_cistatic int do_help(int argc, char **argv)
5362306a36Sopenharmony_ci{
5462306a36Sopenharmony_ci	if (json_output) {
5562306a36Sopenharmony_ci		jsonw_null(json_wtr);
5662306a36Sopenharmony_ci		return 0;
5762306a36Sopenharmony_ci	}
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	fprintf(stderr,
6062306a36Sopenharmony_ci		"Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n"
6162306a36Sopenharmony_ci		"       %s batch file FILE\n"
6262306a36Sopenharmony_ci		"       %s version\n"
6362306a36Sopenharmony_ci		"\n"
6462306a36Sopenharmony_ci		"       OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter }\n"
6562306a36Sopenharmony_ci		"       " HELP_SPEC_OPTIONS " |\n"
6662306a36Sopenharmony_ci		"                    {-V|--version} }\n"
6762306a36Sopenharmony_ci		"",
6862306a36Sopenharmony_ci		bin_name, bin_name, bin_name);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return 0;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_cistatic int do_batch(int argc, char **argv);
7462306a36Sopenharmony_cistatic int do_version(int argc, char **argv);
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_cistatic const struct cmd commands[] = {
7762306a36Sopenharmony_ci	{ "help",	do_help },
7862306a36Sopenharmony_ci	{ "batch",	do_batch },
7962306a36Sopenharmony_ci	{ "prog",	do_prog },
8062306a36Sopenharmony_ci	{ "map",	do_map },
8162306a36Sopenharmony_ci	{ "link",	do_link },
8262306a36Sopenharmony_ci	{ "cgroup",	do_cgroup },
8362306a36Sopenharmony_ci	{ "perf",	do_perf },
8462306a36Sopenharmony_ci	{ "net",	do_net },
8562306a36Sopenharmony_ci	{ "feature",	do_feature },
8662306a36Sopenharmony_ci	{ "btf",	do_btf },
8762306a36Sopenharmony_ci	{ "gen",	do_gen },
8862306a36Sopenharmony_ci	{ "struct_ops",	do_struct_ops },
8962306a36Sopenharmony_ci	{ "iter",	do_iter },
9062306a36Sopenharmony_ci	{ "version",	do_version },
9162306a36Sopenharmony_ci	{ 0 }
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci#ifndef BPFTOOL_VERSION
9562306a36Sopenharmony_ci/* bpftool's major and minor version numbers are aligned on libbpf's. There is
9662306a36Sopenharmony_ci * an offset of 6 for the version number, because bpftool's version was higher
9762306a36Sopenharmony_ci * than libbpf's when we adopted this scheme. The patch number remains at 0
9862306a36Sopenharmony_ci * for now. Set BPFTOOL_VERSION to override.
9962306a36Sopenharmony_ci */
10062306a36Sopenharmony_ci#define BPFTOOL_MAJOR_VERSION (LIBBPF_MAJOR_VERSION + 6)
10162306a36Sopenharmony_ci#define BPFTOOL_MINOR_VERSION LIBBPF_MINOR_VERSION
10262306a36Sopenharmony_ci#define BPFTOOL_PATCH_VERSION 0
10362306a36Sopenharmony_ci#endif
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cistatic void
10662306a36Sopenharmony_ciprint_feature(const char *feature, bool state, unsigned int *nb_features)
10762306a36Sopenharmony_ci{
10862306a36Sopenharmony_ci	if (state) {
10962306a36Sopenharmony_ci		printf("%s %s", *nb_features ? "," : "", feature);
11062306a36Sopenharmony_ci		*nb_features = *nb_features + 1;
11162306a36Sopenharmony_ci	}
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic int do_version(int argc, char **argv)
11562306a36Sopenharmony_ci{
11662306a36Sopenharmony_ci#ifdef HAVE_LIBBFD_SUPPORT
11762306a36Sopenharmony_ci	const bool has_libbfd = true;
11862306a36Sopenharmony_ci#else
11962306a36Sopenharmony_ci	const bool has_libbfd = false;
12062306a36Sopenharmony_ci#endif
12162306a36Sopenharmony_ci#ifdef HAVE_LLVM_SUPPORT
12262306a36Sopenharmony_ci	const bool has_llvm = true;
12362306a36Sopenharmony_ci#else
12462306a36Sopenharmony_ci	const bool has_llvm = false;
12562306a36Sopenharmony_ci#endif
12662306a36Sopenharmony_ci#ifdef BPFTOOL_WITHOUT_SKELETONS
12762306a36Sopenharmony_ci	const bool has_skeletons = false;
12862306a36Sopenharmony_ci#else
12962306a36Sopenharmony_ci	const bool has_skeletons = true;
13062306a36Sopenharmony_ci#endif
13162306a36Sopenharmony_ci	bool bootstrap = false;
13262306a36Sopenharmony_ci	int i;
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	for (i = 0; commands[i].cmd; i++) {
13562306a36Sopenharmony_ci		if (!strcmp(commands[i].cmd, "prog")) {
13662306a36Sopenharmony_ci			/* Assume we run a bootstrap version if "bpftool prog"
13762306a36Sopenharmony_ci			 * is not available.
13862306a36Sopenharmony_ci			 */
13962306a36Sopenharmony_ci			bootstrap = !commands[i].func;
14062306a36Sopenharmony_ci			break;
14162306a36Sopenharmony_ci		}
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	if (json_output) {
14562306a36Sopenharmony_ci		jsonw_start_object(json_wtr);	/* root object */
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci		jsonw_name(json_wtr, "version");
14862306a36Sopenharmony_ci#ifdef BPFTOOL_VERSION
14962306a36Sopenharmony_ci		jsonw_printf(json_wtr, "\"%s\"", BPFTOOL_VERSION);
15062306a36Sopenharmony_ci#else
15162306a36Sopenharmony_ci		jsonw_printf(json_wtr, "\"%d.%d.%d\"", BPFTOOL_MAJOR_VERSION,
15262306a36Sopenharmony_ci			     BPFTOOL_MINOR_VERSION, BPFTOOL_PATCH_VERSION);
15362306a36Sopenharmony_ci#endif
15462306a36Sopenharmony_ci		jsonw_name(json_wtr, "libbpf_version");
15562306a36Sopenharmony_ci		jsonw_printf(json_wtr, "\"%d.%d\"",
15662306a36Sopenharmony_ci			     libbpf_major_version(), libbpf_minor_version());
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci		jsonw_name(json_wtr, "features");
15962306a36Sopenharmony_ci		jsonw_start_object(json_wtr);	/* features */
16062306a36Sopenharmony_ci		jsonw_bool_field(json_wtr, "libbfd", has_libbfd);
16162306a36Sopenharmony_ci		jsonw_bool_field(json_wtr, "llvm", has_llvm);
16262306a36Sopenharmony_ci		jsonw_bool_field(json_wtr, "skeletons", has_skeletons);
16362306a36Sopenharmony_ci		jsonw_bool_field(json_wtr, "bootstrap", bootstrap);
16462306a36Sopenharmony_ci		jsonw_end_object(json_wtr);	/* features */
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci		jsonw_end_object(json_wtr);	/* root object */
16762306a36Sopenharmony_ci	} else {
16862306a36Sopenharmony_ci		unsigned int nb_features = 0;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci#ifdef BPFTOOL_VERSION
17162306a36Sopenharmony_ci		printf("%s v%s\n", bin_name, BPFTOOL_VERSION);
17262306a36Sopenharmony_ci#else
17362306a36Sopenharmony_ci		printf("%s v%d.%d.%d\n", bin_name, BPFTOOL_MAJOR_VERSION,
17462306a36Sopenharmony_ci		       BPFTOOL_MINOR_VERSION, BPFTOOL_PATCH_VERSION);
17562306a36Sopenharmony_ci#endif
17662306a36Sopenharmony_ci		printf("using libbpf %s\n", libbpf_version_string());
17762306a36Sopenharmony_ci		printf("features:");
17862306a36Sopenharmony_ci		print_feature("libbfd", has_libbfd, &nb_features);
17962306a36Sopenharmony_ci		print_feature("llvm", has_llvm, &nb_features);
18062306a36Sopenharmony_ci		print_feature("skeletons", has_skeletons, &nb_features);
18162306a36Sopenharmony_ci		print_feature("bootstrap", bootstrap, &nb_features);
18262306a36Sopenharmony_ci		printf("\n");
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	return 0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ciint cmd_select(const struct cmd *cmds, int argc, char **argv,
18862306a36Sopenharmony_ci	       int (*help)(int argc, char **argv))
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	unsigned int i;
19162306a36Sopenharmony_ci
19262306a36Sopenharmony_ci	last_argc = argc;
19362306a36Sopenharmony_ci	last_argv = argv;
19462306a36Sopenharmony_ci	last_do_help = help;
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (argc < 1 && cmds[0].func)
19762306a36Sopenharmony_ci		return cmds[0].func(argc, argv);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	for (i = 0; cmds[i].cmd; i++) {
20062306a36Sopenharmony_ci		if (is_prefix(*argv, cmds[i].cmd)) {
20162306a36Sopenharmony_ci			if (!cmds[i].func) {
20262306a36Sopenharmony_ci				p_err("command '%s' is not supported in bootstrap mode",
20362306a36Sopenharmony_ci				      cmds[i].cmd);
20462306a36Sopenharmony_ci				return -1;
20562306a36Sopenharmony_ci			}
20662306a36Sopenharmony_ci			return cmds[i].func(argc - 1, argv + 1);
20762306a36Sopenharmony_ci		}
20862306a36Sopenharmony_ci	}
20962306a36Sopenharmony_ci
21062306a36Sopenharmony_ci	help(argc - 1, argv + 1);
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	return -1;
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cibool is_prefix(const char *pfx, const char *str)
21662306a36Sopenharmony_ci{
21762306a36Sopenharmony_ci	if (!pfx)
21862306a36Sopenharmony_ci		return false;
21962306a36Sopenharmony_ci	if (strlen(str) < strlen(pfx))
22062306a36Sopenharmony_ci		return false;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	return !memcmp(str, pfx, strlen(pfx));
22362306a36Sopenharmony_ci}
22462306a36Sopenharmony_ci
22562306a36Sopenharmony_ci/* Last argument MUST be NULL pointer */
22662306a36Sopenharmony_ciint detect_common_prefix(const char *arg, ...)
22762306a36Sopenharmony_ci{
22862306a36Sopenharmony_ci	unsigned int count = 0;
22962306a36Sopenharmony_ci	const char *ref;
23062306a36Sopenharmony_ci	char msg[256];
23162306a36Sopenharmony_ci	va_list ap;
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg);
23462306a36Sopenharmony_ci	va_start(ap, arg);
23562306a36Sopenharmony_ci	while ((ref = va_arg(ap, const char *))) {
23662306a36Sopenharmony_ci		if (!is_prefix(arg, ref))
23762306a36Sopenharmony_ci			continue;
23862306a36Sopenharmony_ci		count++;
23962306a36Sopenharmony_ci		if (count > 1)
24062306a36Sopenharmony_ci			strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1);
24162306a36Sopenharmony_ci		strncat(msg, ref, sizeof(msg) - strlen(msg) - 1);
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci	va_end(ap);
24462306a36Sopenharmony_ci	strncat(msg, "'", sizeof(msg) - strlen(msg) - 1);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (count >= 2) {
24762306a36Sopenharmony_ci		p_err("%s", msg);
24862306a36Sopenharmony_ci		return -1;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return 0;
25262306a36Sopenharmony_ci}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_civoid fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
25562306a36Sopenharmony_ci{
25662306a36Sopenharmony_ci	unsigned char *data = arg;
25762306a36Sopenharmony_ci	unsigned int i;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	for (i = 0; i < n; i++) {
26062306a36Sopenharmony_ci		const char *pfx = "";
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci		if (!i)
26362306a36Sopenharmony_ci			/* nothing */;
26462306a36Sopenharmony_ci		else if (!(i % 16))
26562306a36Sopenharmony_ci			fprintf(f, "\n");
26662306a36Sopenharmony_ci		else if (!(i % 8))
26762306a36Sopenharmony_ci			fprintf(f, "  ");
26862306a36Sopenharmony_ci		else
26962306a36Sopenharmony_ci			pfx = sep;
27062306a36Sopenharmony_ci
27162306a36Sopenharmony_ci		fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
27262306a36Sopenharmony_ci	}
27362306a36Sopenharmony_ci}
27462306a36Sopenharmony_ci
27562306a36Sopenharmony_ci/* Split command line into argument vector. */
27662306a36Sopenharmony_cistatic int make_args(char *line, char *n_argv[], int maxargs, int cmd_nb)
27762306a36Sopenharmony_ci{
27862306a36Sopenharmony_ci	static const char ws[] = " \t\r\n";
27962306a36Sopenharmony_ci	char *cp = line;
28062306a36Sopenharmony_ci	int n_argc = 0;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	while (*cp) {
28362306a36Sopenharmony_ci		/* Skip leading whitespace. */
28462306a36Sopenharmony_ci		cp += strspn(cp, ws);
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci		if (*cp == '\0')
28762306a36Sopenharmony_ci			break;
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci		if (n_argc >= (maxargs - 1)) {
29062306a36Sopenharmony_ci			p_err("too many arguments to command %d", cmd_nb);
29162306a36Sopenharmony_ci			return -1;
29262306a36Sopenharmony_ci		}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci		/* Word begins with quote. */
29562306a36Sopenharmony_ci		if (*cp == '\'' || *cp == '"') {
29662306a36Sopenharmony_ci			char quote = *cp++;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci			n_argv[n_argc++] = cp;
29962306a36Sopenharmony_ci			/* Find ending quote. */
30062306a36Sopenharmony_ci			cp = strchr(cp, quote);
30162306a36Sopenharmony_ci			if (!cp) {
30262306a36Sopenharmony_ci				p_err("unterminated quoted string in command %d",
30362306a36Sopenharmony_ci				      cmd_nb);
30462306a36Sopenharmony_ci				return -1;
30562306a36Sopenharmony_ci			}
30662306a36Sopenharmony_ci		} else {
30762306a36Sopenharmony_ci			n_argv[n_argc++] = cp;
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci			/* Find end of word. */
31062306a36Sopenharmony_ci			cp += strcspn(cp, ws);
31162306a36Sopenharmony_ci			if (*cp == '\0')
31262306a36Sopenharmony_ci				break;
31362306a36Sopenharmony_ci		}
31462306a36Sopenharmony_ci
31562306a36Sopenharmony_ci		/* Separate words. */
31662306a36Sopenharmony_ci		*cp++ = 0;
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci	n_argv[n_argc] = NULL;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	return n_argc;
32162306a36Sopenharmony_ci}
32262306a36Sopenharmony_ci
32362306a36Sopenharmony_cistatic int do_batch(int argc, char **argv)
32462306a36Sopenharmony_ci{
32562306a36Sopenharmony_ci	char buf[BATCH_LINE_LEN_MAX], contline[BATCH_LINE_LEN_MAX];
32662306a36Sopenharmony_ci	char *n_argv[BATCH_ARG_NB_MAX];
32762306a36Sopenharmony_ci	unsigned int lines = 0;
32862306a36Sopenharmony_ci	int n_argc;
32962306a36Sopenharmony_ci	FILE *fp;
33062306a36Sopenharmony_ci	char *cp;
33162306a36Sopenharmony_ci	int err = 0;
33262306a36Sopenharmony_ci	int i;
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (argc < 2) {
33562306a36Sopenharmony_ci		p_err("too few parameters for batch");
33662306a36Sopenharmony_ci		return -1;
33762306a36Sopenharmony_ci	} else if (argc > 2) {
33862306a36Sopenharmony_ci		p_err("too many parameters for batch");
33962306a36Sopenharmony_ci		return -1;
34062306a36Sopenharmony_ci	} else if (!is_prefix(*argv, "file")) {
34162306a36Sopenharmony_ci		p_err("expected 'file', got: %s", *argv);
34262306a36Sopenharmony_ci		return -1;
34362306a36Sopenharmony_ci	}
34462306a36Sopenharmony_ci	NEXT_ARG();
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	if (!strcmp(*argv, "-"))
34762306a36Sopenharmony_ci		fp = stdin;
34862306a36Sopenharmony_ci	else
34962306a36Sopenharmony_ci		fp = fopen(*argv, "r");
35062306a36Sopenharmony_ci	if (!fp) {
35162306a36Sopenharmony_ci		p_err("Can't open file (%s): %s", *argv, strerror(errno));
35262306a36Sopenharmony_ci		return -1;
35362306a36Sopenharmony_ci	}
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	if (json_output)
35662306a36Sopenharmony_ci		jsonw_start_array(json_wtr);
35762306a36Sopenharmony_ci	while (fgets(buf, sizeof(buf), fp)) {
35862306a36Sopenharmony_ci		cp = strchr(buf, '#');
35962306a36Sopenharmony_ci		if (cp)
36062306a36Sopenharmony_ci			*cp = '\0';
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci		if (strlen(buf) == sizeof(buf) - 1) {
36362306a36Sopenharmony_ci			errno = E2BIG;
36462306a36Sopenharmony_ci			break;
36562306a36Sopenharmony_ci		}
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_ci		/* Append continuation lines if any (coming after a line ending
36862306a36Sopenharmony_ci		 * with '\' in the batch file).
36962306a36Sopenharmony_ci		 */
37062306a36Sopenharmony_ci		while ((cp = strstr(buf, "\\\n")) != NULL) {
37162306a36Sopenharmony_ci			if (!fgets(contline, sizeof(contline), fp) ||
37262306a36Sopenharmony_ci			    strlen(contline) == 0) {
37362306a36Sopenharmony_ci				p_err("missing continuation line on command %d",
37462306a36Sopenharmony_ci				      lines);
37562306a36Sopenharmony_ci				err = -1;
37662306a36Sopenharmony_ci				goto err_close;
37762306a36Sopenharmony_ci			}
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci			cp = strchr(contline, '#');
38062306a36Sopenharmony_ci			if (cp)
38162306a36Sopenharmony_ci				*cp = '\0';
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci			if (strlen(buf) + strlen(contline) + 1 > sizeof(buf)) {
38462306a36Sopenharmony_ci				p_err("command %d is too long", lines);
38562306a36Sopenharmony_ci				err = -1;
38662306a36Sopenharmony_ci				goto err_close;
38762306a36Sopenharmony_ci			}
38862306a36Sopenharmony_ci			buf[strlen(buf) - 2] = '\0';
38962306a36Sopenharmony_ci			strcat(buf, contline);
39062306a36Sopenharmony_ci		}
39162306a36Sopenharmony_ci
39262306a36Sopenharmony_ci		n_argc = make_args(buf, n_argv, BATCH_ARG_NB_MAX, lines);
39362306a36Sopenharmony_ci		if (!n_argc)
39462306a36Sopenharmony_ci			continue;
39562306a36Sopenharmony_ci		if (n_argc < 0) {
39662306a36Sopenharmony_ci			err = n_argc;
39762306a36Sopenharmony_ci			goto err_close;
39862306a36Sopenharmony_ci		}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		if (json_output) {
40162306a36Sopenharmony_ci			jsonw_start_object(json_wtr);
40262306a36Sopenharmony_ci			jsonw_name(json_wtr, "command");
40362306a36Sopenharmony_ci			jsonw_start_array(json_wtr);
40462306a36Sopenharmony_ci			for (i = 0; i < n_argc; i++)
40562306a36Sopenharmony_ci				jsonw_string(json_wtr, n_argv[i]);
40662306a36Sopenharmony_ci			jsonw_end_array(json_wtr);
40762306a36Sopenharmony_ci			jsonw_name(json_wtr, "output");
40862306a36Sopenharmony_ci		}
40962306a36Sopenharmony_ci
41062306a36Sopenharmony_ci		err = cmd_select(commands, n_argc, n_argv, do_help);
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_ci		if (json_output)
41362306a36Sopenharmony_ci			jsonw_end_object(json_wtr);
41462306a36Sopenharmony_ci
41562306a36Sopenharmony_ci		if (err)
41662306a36Sopenharmony_ci			goto err_close;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci		lines++;
41962306a36Sopenharmony_ci	}
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	if (errno && errno != ENOENT) {
42262306a36Sopenharmony_ci		p_err("reading batch file failed: %s", strerror(errno));
42362306a36Sopenharmony_ci		err = -1;
42462306a36Sopenharmony_ci	} else {
42562306a36Sopenharmony_ci		if (!json_output)
42662306a36Sopenharmony_ci			printf("processed %d commands\n", lines);
42762306a36Sopenharmony_ci	}
42862306a36Sopenharmony_cierr_close:
42962306a36Sopenharmony_ci	if (fp != stdin)
43062306a36Sopenharmony_ci		fclose(fp);
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	if (json_output)
43362306a36Sopenharmony_ci		jsonw_end_array(json_wtr);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return err;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_ciint main(int argc, char **argv)
43962306a36Sopenharmony_ci{
44062306a36Sopenharmony_ci	static const struct option options[] = {
44162306a36Sopenharmony_ci		{ "json",	no_argument,	NULL,	'j' },
44262306a36Sopenharmony_ci		{ "help",	no_argument,	NULL,	'h' },
44362306a36Sopenharmony_ci		{ "pretty",	no_argument,	NULL,	'p' },
44462306a36Sopenharmony_ci		{ "version",	no_argument,	NULL,	'V' },
44562306a36Sopenharmony_ci		{ "bpffs",	no_argument,	NULL,	'f' },
44662306a36Sopenharmony_ci		{ "mapcompat",	no_argument,	NULL,	'm' },
44762306a36Sopenharmony_ci		{ "nomount",	no_argument,	NULL,	'n' },
44862306a36Sopenharmony_ci		{ "debug",	no_argument,	NULL,	'd' },
44962306a36Sopenharmony_ci		{ "use-loader",	no_argument,	NULL,	'L' },
45062306a36Sopenharmony_ci		{ "base-btf",	required_argument, NULL, 'B' },
45162306a36Sopenharmony_ci		{ 0 }
45262306a36Sopenharmony_ci	};
45362306a36Sopenharmony_ci	bool version_requested = false;
45462306a36Sopenharmony_ci	int opt, ret;
45562306a36Sopenharmony_ci
45662306a36Sopenharmony_ci	setlinebuf(stdout);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci#ifdef USE_LIBCAP
45962306a36Sopenharmony_ci	/* Libcap < 2.63 hooks before main() to compute the number of
46062306a36Sopenharmony_ci	 * capabilities of the running kernel, and doing so it calls prctl()
46162306a36Sopenharmony_ci	 * which may fail and set errno to non-zero.
46262306a36Sopenharmony_ci	 * Let's reset errno to make sure this does not interfere with the
46362306a36Sopenharmony_ci	 * batch mode.
46462306a36Sopenharmony_ci	 */
46562306a36Sopenharmony_ci	errno = 0;
46662306a36Sopenharmony_ci#endif
46762306a36Sopenharmony_ci
46862306a36Sopenharmony_ci	last_do_help = do_help;
46962306a36Sopenharmony_ci	pretty_output = false;
47062306a36Sopenharmony_ci	json_output = false;
47162306a36Sopenharmony_ci	show_pinned = false;
47262306a36Sopenharmony_ci	block_mount = false;
47362306a36Sopenharmony_ci	bin_name = "bpftool";
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	opterr = 0;
47662306a36Sopenharmony_ci	while ((opt = getopt_long(argc, argv, "VhpjfLmndB:l",
47762306a36Sopenharmony_ci				  options, NULL)) >= 0) {
47862306a36Sopenharmony_ci		switch (opt) {
47962306a36Sopenharmony_ci		case 'V':
48062306a36Sopenharmony_ci			version_requested = true;
48162306a36Sopenharmony_ci			break;
48262306a36Sopenharmony_ci		case 'h':
48362306a36Sopenharmony_ci			return do_help(argc, argv);
48462306a36Sopenharmony_ci		case 'p':
48562306a36Sopenharmony_ci			pretty_output = true;
48662306a36Sopenharmony_ci			/* fall through */
48762306a36Sopenharmony_ci		case 'j':
48862306a36Sopenharmony_ci			if (!json_output) {
48962306a36Sopenharmony_ci				json_wtr = jsonw_new(stdout);
49062306a36Sopenharmony_ci				if (!json_wtr) {
49162306a36Sopenharmony_ci					p_err("failed to create JSON writer");
49262306a36Sopenharmony_ci					return -1;
49362306a36Sopenharmony_ci				}
49462306a36Sopenharmony_ci				json_output = true;
49562306a36Sopenharmony_ci			}
49662306a36Sopenharmony_ci			jsonw_pretty(json_wtr, pretty_output);
49762306a36Sopenharmony_ci			break;
49862306a36Sopenharmony_ci		case 'f':
49962306a36Sopenharmony_ci			show_pinned = true;
50062306a36Sopenharmony_ci			break;
50162306a36Sopenharmony_ci		case 'm':
50262306a36Sopenharmony_ci			relaxed_maps = true;
50362306a36Sopenharmony_ci			break;
50462306a36Sopenharmony_ci		case 'n':
50562306a36Sopenharmony_ci			block_mount = true;
50662306a36Sopenharmony_ci			break;
50762306a36Sopenharmony_ci		case 'd':
50862306a36Sopenharmony_ci			libbpf_set_print(print_all_levels);
50962306a36Sopenharmony_ci			verifier_logs = true;
51062306a36Sopenharmony_ci			break;
51162306a36Sopenharmony_ci		case 'B':
51262306a36Sopenharmony_ci			base_btf = btf__parse(optarg, NULL);
51362306a36Sopenharmony_ci			if (!base_btf) {
51462306a36Sopenharmony_ci				p_err("failed to parse base BTF at '%s': %d\n",
51562306a36Sopenharmony_ci				      optarg, -errno);
51662306a36Sopenharmony_ci				return -1;
51762306a36Sopenharmony_ci			}
51862306a36Sopenharmony_ci			break;
51962306a36Sopenharmony_ci		case 'L':
52062306a36Sopenharmony_ci			use_loader = true;
52162306a36Sopenharmony_ci			break;
52262306a36Sopenharmony_ci		default:
52362306a36Sopenharmony_ci			p_err("unrecognized option '%s'", argv[optind - 1]);
52462306a36Sopenharmony_ci			if (json_output)
52562306a36Sopenharmony_ci				clean_and_exit(-1);
52662306a36Sopenharmony_ci			else
52762306a36Sopenharmony_ci				usage();
52862306a36Sopenharmony_ci		}
52962306a36Sopenharmony_ci	}
53062306a36Sopenharmony_ci
53162306a36Sopenharmony_ci	argc -= optind;
53262306a36Sopenharmony_ci	argv += optind;
53362306a36Sopenharmony_ci	if (argc < 0)
53462306a36Sopenharmony_ci		usage();
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	if (version_requested)
53762306a36Sopenharmony_ci		return do_version(argc, argv);
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_ci	ret = cmd_select(commands, argc, argv, do_help);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ci	if (json_output)
54262306a36Sopenharmony_ci		jsonw_destroy(&json_wtr);
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci	btf__free(base_btf);
54562306a36Sopenharmony_ci
54662306a36Sopenharmony_ci	return ret;
54762306a36Sopenharmony_ci}
548