xref: /OK3568_Linux_fs/kernel/tools/bpf/bpftool/main.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2*4882a593Smuzhiyun /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3*4882a593Smuzhiyun 
4*4882a593Smuzhiyun #include <ctype.h>
5*4882a593Smuzhiyun #include <errno.h>
6*4882a593Smuzhiyun #include <getopt.h>
7*4882a593Smuzhiyun #include <linux/bpf.h>
8*4882a593Smuzhiyun #include <stdio.h>
9*4882a593Smuzhiyun #include <stdlib.h>
10*4882a593Smuzhiyun #include <string.h>
11*4882a593Smuzhiyun 
12*4882a593Smuzhiyun #include <bpf/bpf.h>
13*4882a593Smuzhiyun #include <bpf/libbpf.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include "main.h"
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #define BATCH_LINE_LEN_MAX 65536
18*4882a593Smuzhiyun #define BATCH_ARG_NB_MAX 4096
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun const char *bin_name;
21*4882a593Smuzhiyun static int last_argc;
22*4882a593Smuzhiyun static char **last_argv;
23*4882a593Smuzhiyun static int (*last_do_help)(int argc, char **argv);
24*4882a593Smuzhiyun json_writer_t *json_wtr;
25*4882a593Smuzhiyun bool pretty_output;
26*4882a593Smuzhiyun bool json_output;
27*4882a593Smuzhiyun bool show_pinned;
28*4882a593Smuzhiyun bool block_mount;
29*4882a593Smuzhiyun bool verifier_logs;
30*4882a593Smuzhiyun bool relaxed_maps;
31*4882a593Smuzhiyun struct pinned_obj_table prog_table;
32*4882a593Smuzhiyun struct pinned_obj_table map_table;
33*4882a593Smuzhiyun struct pinned_obj_table link_table;
34*4882a593Smuzhiyun struct obj_refs_table refs_table;
35*4882a593Smuzhiyun 
clean_and_exit(int i)36*4882a593Smuzhiyun static void __noreturn clean_and_exit(int i)
37*4882a593Smuzhiyun {
38*4882a593Smuzhiyun 	if (json_output)
39*4882a593Smuzhiyun 		jsonw_destroy(&json_wtr);
40*4882a593Smuzhiyun 
41*4882a593Smuzhiyun 	exit(i);
42*4882a593Smuzhiyun }
43*4882a593Smuzhiyun 
usage(void)44*4882a593Smuzhiyun void usage(void)
45*4882a593Smuzhiyun {
46*4882a593Smuzhiyun 	last_do_help(last_argc - 1, last_argv + 1);
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun 	clean_and_exit(-1);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun 
do_help(int argc,char ** argv)51*4882a593Smuzhiyun static int do_help(int argc, char **argv)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun 	if (json_output) {
54*4882a593Smuzhiyun 		jsonw_null(json_wtr);
55*4882a593Smuzhiyun 		return 0;
56*4882a593Smuzhiyun 	}
57*4882a593Smuzhiyun 
58*4882a593Smuzhiyun 	fprintf(stderr,
59*4882a593Smuzhiyun 		"Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n"
60*4882a593Smuzhiyun 		"       %s batch file FILE\n"
61*4882a593Smuzhiyun 		"       %s version\n"
62*4882a593Smuzhiyun 		"\n"
63*4882a593Smuzhiyun 		"       OBJECT := { prog | map | link | cgroup | perf | net | feature | btf | gen | struct_ops | iter }\n"
64*4882a593Smuzhiyun 		"       " HELP_SPEC_OPTIONS "\n"
65*4882a593Smuzhiyun 		"",
66*4882a593Smuzhiyun 		bin_name, bin_name, bin_name);
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun 	return 0;
69*4882a593Smuzhiyun }
70*4882a593Smuzhiyun 
do_version(int argc,char ** argv)71*4882a593Smuzhiyun static int do_version(int argc, char **argv)
72*4882a593Smuzhiyun {
73*4882a593Smuzhiyun #ifdef HAVE_LIBBFD_SUPPORT
74*4882a593Smuzhiyun 	const bool has_libbfd = true;
75*4882a593Smuzhiyun #else
76*4882a593Smuzhiyun 	const bool has_libbfd = false;
77*4882a593Smuzhiyun #endif
78*4882a593Smuzhiyun #ifdef BPFTOOL_WITHOUT_SKELETONS
79*4882a593Smuzhiyun 	const bool has_skeletons = false;
80*4882a593Smuzhiyun #else
81*4882a593Smuzhiyun 	const bool has_skeletons = true;
82*4882a593Smuzhiyun #endif
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	if (json_output) {
85*4882a593Smuzhiyun 		jsonw_start_object(json_wtr);	/* root object */
86*4882a593Smuzhiyun 
87*4882a593Smuzhiyun 		jsonw_name(json_wtr, "version");
88*4882a593Smuzhiyun 		jsonw_printf(json_wtr, "\"%s\"", BPFTOOL_VERSION);
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 		jsonw_name(json_wtr, "features");
91*4882a593Smuzhiyun 		jsonw_start_object(json_wtr);	/* features */
92*4882a593Smuzhiyun 		jsonw_bool_field(json_wtr, "libbfd", has_libbfd);
93*4882a593Smuzhiyun 		jsonw_bool_field(json_wtr, "skeletons", has_skeletons);
94*4882a593Smuzhiyun 		jsonw_end_object(json_wtr);	/* features */
95*4882a593Smuzhiyun 
96*4882a593Smuzhiyun 		jsonw_end_object(json_wtr);	/* root object */
97*4882a593Smuzhiyun 	} else {
98*4882a593Smuzhiyun 		unsigned int nb_features = 0;
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun 		printf("%s v%s\n", bin_name, BPFTOOL_VERSION);
101*4882a593Smuzhiyun 		printf("features:");
102*4882a593Smuzhiyun 		if (has_libbfd) {
103*4882a593Smuzhiyun 			printf(" libbfd");
104*4882a593Smuzhiyun 			nb_features++;
105*4882a593Smuzhiyun 		}
106*4882a593Smuzhiyun 		if (has_skeletons)
107*4882a593Smuzhiyun 			printf("%s skeletons", nb_features++ ? "," : "");
108*4882a593Smuzhiyun 		printf("\n");
109*4882a593Smuzhiyun 	}
110*4882a593Smuzhiyun 	return 0;
111*4882a593Smuzhiyun }
112*4882a593Smuzhiyun 
cmd_select(const struct cmd * cmds,int argc,char ** argv,int (* help)(int argc,char ** argv))113*4882a593Smuzhiyun int cmd_select(const struct cmd *cmds, int argc, char **argv,
114*4882a593Smuzhiyun 	       int (*help)(int argc, char **argv))
115*4882a593Smuzhiyun {
116*4882a593Smuzhiyun 	unsigned int i;
117*4882a593Smuzhiyun 
118*4882a593Smuzhiyun 	last_argc = argc;
119*4882a593Smuzhiyun 	last_argv = argv;
120*4882a593Smuzhiyun 	last_do_help = help;
121*4882a593Smuzhiyun 
122*4882a593Smuzhiyun 	if (argc < 1 && cmds[0].func)
123*4882a593Smuzhiyun 		return cmds[0].func(argc, argv);
124*4882a593Smuzhiyun 
125*4882a593Smuzhiyun 	for (i = 0; cmds[i].cmd; i++) {
126*4882a593Smuzhiyun 		if (is_prefix(*argv, cmds[i].cmd)) {
127*4882a593Smuzhiyun 			if (!cmds[i].func) {
128*4882a593Smuzhiyun 				p_err("command '%s' is not supported in bootstrap mode",
129*4882a593Smuzhiyun 				      cmds[i].cmd);
130*4882a593Smuzhiyun 				return -1;
131*4882a593Smuzhiyun 			}
132*4882a593Smuzhiyun 			return cmds[i].func(argc - 1, argv + 1);
133*4882a593Smuzhiyun 		}
134*4882a593Smuzhiyun 	}
135*4882a593Smuzhiyun 
136*4882a593Smuzhiyun 	help(argc - 1, argv + 1);
137*4882a593Smuzhiyun 
138*4882a593Smuzhiyun 	return -1;
139*4882a593Smuzhiyun }
140*4882a593Smuzhiyun 
is_prefix(const char * pfx,const char * str)141*4882a593Smuzhiyun bool is_prefix(const char *pfx, const char *str)
142*4882a593Smuzhiyun {
143*4882a593Smuzhiyun 	if (!pfx)
144*4882a593Smuzhiyun 		return false;
145*4882a593Smuzhiyun 	if (strlen(str) < strlen(pfx))
146*4882a593Smuzhiyun 		return false;
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 	return !memcmp(str, pfx, strlen(pfx));
149*4882a593Smuzhiyun }
150*4882a593Smuzhiyun 
151*4882a593Smuzhiyun /* Last argument MUST be NULL pointer */
detect_common_prefix(const char * arg,...)152*4882a593Smuzhiyun int detect_common_prefix(const char *arg, ...)
153*4882a593Smuzhiyun {
154*4882a593Smuzhiyun 	unsigned int count = 0;
155*4882a593Smuzhiyun 	const char *ref;
156*4882a593Smuzhiyun 	char msg[256];
157*4882a593Smuzhiyun 	va_list ap;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg);
160*4882a593Smuzhiyun 	va_start(ap, arg);
161*4882a593Smuzhiyun 	while ((ref = va_arg(ap, const char *))) {
162*4882a593Smuzhiyun 		if (!is_prefix(arg, ref))
163*4882a593Smuzhiyun 			continue;
164*4882a593Smuzhiyun 		count++;
165*4882a593Smuzhiyun 		if (count > 1)
166*4882a593Smuzhiyun 			strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1);
167*4882a593Smuzhiyun 		strncat(msg, ref, sizeof(msg) - strlen(msg) - 1);
168*4882a593Smuzhiyun 	}
169*4882a593Smuzhiyun 	va_end(ap);
170*4882a593Smuzhiyun 	strncat(msg, "'", sizeof(msg) - strlen(msg) - 1);
171*4882a593Smuzhiyun 
172*4882a593Smuzhiyun 	if (count >= 2) {
173*4882a593Smuzhiyun 		p_err("%s", msg);
174*4882a593Smuzhiyun 		return -1;
175*4882a593Smuzhiyun 	}
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	return 0;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
fprint_hex(FILE * f,void * arg,unsigned int n,const char * sep)180*4882a593Smuzhiyun void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
181*4882a593Smuzhiyun {
182*4882a593Smuzhiyun 	unsigned char *data = arg;
183*4882a593Smuzhiyun 	unsigned int i;
184*4882a593Smuzhiyun 
185*4882a593Smuzhiyun 	for (i = 0; i < n; i++) {
186*4882a593Smuzhiyun 		const char *pfx = "";
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 		if (!i)
189*4882a593Smuzhiyun 			/* nothing */;
190*4882a593Smuzhiyun 		else if (!(i % 16))
191*4882a593Smuzhiyun 			fprintf(f, "\n");
192*4882a593Smuzhiyun 		else if (!(i % 8))
193*4882a593Smuzhiyun 			fprintf(f, "  ");
194*4882a593Smuzhiyun 		else
195*4882a593Smuzhiyun 			pfx = sep;
196*4882a593Smuzhiyun 
197*4882a593Smuzhiyun 		fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
198*4882a593Smuzhiyun 	}
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
201*4882a593Smuzhiyun /* Split command line into argument vector. */
make_args(char * line,char * n_argv[],int maxargs,int cmd_nb)202*4882a593Smuzhiyun static int make_args(char *line, char *n_argv[], int maxargs, int cmd_nb)
203*4882a593Smuzhiyun {
204*4882a593Smuzhiyun 	static const char ws[] = " \t\r\n";
205*4882a593Smuzhiyun 	char *cp = line;
206*4882a593Smuzhiyun 	int n_argc = 0;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	while (*cp) {
209*4882a593Smuzhiyun 		/* Skip leading whitespace. */
210*4882a593Smuzhiyun 		cp += strspn(cp, ws);
211*4882a593Smuzhiyun 
212*4882a593Smuzhiyun 		if (*cp == '\0')
213*4882a593Smuzhiyun 			break;
214*4882a593Smuzhiyun 
215*4882a593Smuzhiyun 		if (n_argc >= (maxargs - 1)) {
216*4882a593Smuzhiyun 			p_err("too many arguments to command %d", cmd_nb);
217*4882a593Smuzhiyun 			return -1;
218*4882a593Smuzhiyun 		}
219*4882a593Smuzhiyun 
220*4882a593Smuzhiyun 		/* Word begins with quote. */
221*4882a593Smuzhiyun 		if (*cp == '\'' || *cp == '"') {
222*4882a593Smuzhiyun 			char quote = *cp++;
223*4882a593Smuzhiyun 
224*4882a593Smuzhiyun 			n_argv[n_argc++] = cp;
225*4882a593Smuzhiyun 			/* Find ending quote. */
226*4882a593Smuzhiyun 			cp = strchr(cp, quote);
227*4882a593Smuzhiyun 			if (!cp) {
228*4882a593Smuzhiyun 				p_err("unterminated quoted string in command %d",
229*4882a593Smuzhiyun 				      cmd_nb);
230*4882a593Smuzhiyun 				return -1;
231*4882a593Smuzhiyun 			}
232*4882a593Smuzhiyun 		} else {
233*4882a593Smuzhiyun 			n_argv[n_argc++] = cp;
234*4882a593Smuzhiyun 
235*4882a593Smuzhiyun 			/* Find end of word. */
236*4882a593Smuzhiyun 			cp += strcspn(cp, ws);
237*4882a593Smuzhiyun 			if (*cp == '\0')
238*4882a593Smuzhiyun 				break;
239*4882a593Smuzhiyun 		}
240*4882a593Smuzhiyun 
241*4882a593Smuzhiyun 		/* Separate words. */
242*4882a593Smuzhiyun 		*cp++ = 0;
243*4882a593Smuzhiyun 	}
244*4882a593Smuzhiyun 	n_argv[n_argc] = NULL;
245*4882a593Smuzhiyun 
246*4882a593Smuzhiyun 	return n_argc;
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun static int do_batch(int argc, char **argv);
250*4882a593Smuzhiyun 
251*4882a593Smuzhiyun static const struct cmd cmds[] = {
252*4882a593Smuzhiyun 	{ "help",	do_help },
253*4882a593Smuzhiyun 	{ "batch",	do_batch },
254*4882a593Smuzhiyun 	{ "prog",	do_prog },
255*4882a593Smuzhiyun 	{ "map",	do_map },
256*4882a593Smuzhiyun 	{ "link",	do_link },
257*4882a593Smuzhiyun 	{ "cgroup",	do_cgroup },
258*4882a593Smuzhiyun 	{ "perf",	do_perf },
259*4882a593Smuzhiyun 	{ "net",	do_net },
260*4882a593Smuzhiyun 	{ "feature",	do_feature },
261*4882a593Smuzhiyun 	{ "btf",	do_btf },
262*4882a593Smuzhiyun 	{ "gen",	do_gen },
263*4882a593Smuzhiyun 	{ "struct_ops",	do_struct_ops },
264*4882a593Smuzhiyun 	{ "iter",	do_iter },
265*4882a593Smuzhiyun 	{ "version",	do_version },
266*4882a593Smuzhiyun 	{ 0 }
267*4882a593Smuzhiyun };
268*4882a593Smuzhiyun 
do_batch(int argc,char ** argv)269*4882a593Smuzhiyun static int do_batch(int argc, char **argv)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	char buf[BATCH_LINE_LEN_MAX], contline[BATCH_LINE_LEN_MAX];
272*4882a593Smuzhiyun 	char *n_argv[BATCH_ARG_NB_MAX];
273*4882a593Smuzhiyun 	unsigned int lines = 0;
274*4882a593Smuzhiyun 	int n_argc;
275*4882a593Smuzhiyun 	FILE *fp;
276*4882a593Smuzhiyun 	char *cp;
277*4882a593Smuzhiyun 	int err = 0;
278*4882a593Smuzhiyun 	int i;
279*4882a593Smuzhiyun 
280*4882a593Smuzhiyun 	if (argc < 2) {
281*4882a593Smuzhiyun 		p_err("too few parameters for batch");
282*4882a593Smuzhiyun 		return -1;
283*4882a593Smuzhiyun 	} else if (!is_prefix(*argv, "file")) {
284*4882a593Smuzhiyun 		p_err("expected 'file', got: %s", *argv);
285*4882a593Smuzhiyun 		return -1;
286*4882a593Smuzhiyun 	} else if (argc > 2) {
287*4882a593Smuzhiyun 		p_err("too many parameters for batch");
288*4882a593Smuzhiyun 		return -1;
289*4882a593Smuzhiyun 	}
290*4882a593Smuzhiyun 	NEXT_ARG();
291*4882a593Smuzhiyun 
292*4882a593Smuzhiyun 	if (!strcmp(*argv, "-"))
293*4882a593Smuzhiyun 		fp = stdin;
294*4882a593Smuzhiyun 	else
295*4882a593Smuzhiyun 		fp = fopen(*argv, "r");
296*4882a593Smuzhiyun 	if (!fp) {
297*4882a593Smuzhiyun 		p_err("Can't open file (%s): %s", *argv, strerror(errno));
298*4882a593Smuzhiyun 		return -1;
299*4882a593Smuzhiyun 	}
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	if (json_output)
302*4882a593Smuzhiyun 		jsonw_start_array(json_wtr);
303*4882a593Smuzhiyun 	while (fgets(buf, sizeof(buf), fp)) {
304*4882a593Smuzhiyun 		cp = strchr(buf, '#');
305*4882a593Smuzhiyun 		if (cp)
306*4882a593Smuzhiyun 			*cp = '\0';
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 		if (strlen(buf) == sizeof(buf) - 1) {
309*4882a593Smuzhiyun 			errno = E2BIG;
310*4882a593Smuzhiyun 			break;
311*4882a593Smuzhiyun 		}
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun 		/* Append continuation lines if any (coming after a line ending
314*4882a593Smuzhiyun 		 * with '\' in the batch file).
315*4882a593Smuzhiyun 		 */
316*4882a593Smuzhiyun 		while ((cp = strstr(buf, "\\\n")) != NULL) {
317*4882a593Smuzhiyun 			if (!fgets(contline, sizeof(contline), fp) ||
318*4882a593Smuzhiyun 			    strlen(contline) == 0) {
319*4882a593Smuzhiyun 				p_err("missing continuation line on command %d",
320*4882a593Smuzhiyun 				      lines);
321*4882a593Smuzhiyun 				err = -1;
322*4882a593Smuzhiyun 				goto err_close;
323*4882a593Smuzhiyun 			}
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 			cp = strchr(contline, '#');
326*4882a593Smuzhiyun 			if (cp)
327*4882a593Smuzhiyun 				*cp = '\0';
328*4882a593Smuzhiyun 
329*4882a593Smuzhiyun 			if (strlen(buf) + strlen(contline) + 1 > sizeof(buf)) {
330*4882a593Smuzhiyun 				p_err("command %d is too long", lines);
331*4882a593Smuzhiyun 				err = -1;
332*4882a593Smuzhiyun 				goto err_close;
333*4882a593Smuzhiyun 			}
334*4882a593Smuzhiyun 			buf[strlen(buf) - 2] = '\0';
335*4882a593Smuzhiyun 			strcat(buf, contline);
336*4882a593Smuzhiyun 		}
337*4882a593Smuzhiyun 
338*4882a593Smuzhiyun 		n_argc = make_args(buf, n_argv, BATCH_ARG_NB_MAX, lines);
339*4882a593Smuzhiyun 		if (!n_argc)
340*4882a593Smuzhiyun 			continue;
341*4882a593Smuzhiyun 		if (n_argc < 0) {
342*4882a593Smuzhiyun 			err = n_argc;
343*4882a593Smuzhiyun 			goto err_close;
344*4882a593Smuzhiyun 		}
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		if (json_output) {
347*4882a593Smuzhiyun 			jsonw_start_object(json_wtr);
348*4882a593Smuzhiyun 			jsonw_name(json_wtr, "command");
349*4882a593Smuzhiyun 			jsonw_start_array(json_wtr);
350*4882a593Smuzhiyun 			for (i = 0; i < n_argc; i++)
351*4882a593Smuzhiyun 				jsonw_string(json_wtr, n_argv[i]);
352*4882a593Smuzhiyun 			jsonw_end_array(json_wtr);
353*4882a593Smuzhiyun 			jsonw_name(json_wtr, "output");
354*4882a593Smuzhiyun 		}
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		err = cmd_select(cmds, n_argc, n_argv, do_help);
357*4882a593Smuzhiyun 
358*4882a593Smuzhiyun 		if (json_output)
359*4882a593Smuzhiyun 			jsonw_end_object(json_wtr);
360*4882a593Smuzhiyun 
361*4882a593Smuzhiyun 		if (err)
362*4882a593Smuzhiyun 			goto err_close;
363*4882a593Smuzhiyun 
364*4882a593Smuzhiyun 		lines++;
365*4882a593Smuzhiyun 	}
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 	if (errno && errno != ENOENT) {
368*4882a593Smuzhiyun 		p_err("reading batch file failed: %s", strerror(errno));
369*4882a593Smuzhiyun 		err = -1;
370*4882a593Smuzhiyun 	} else {
371*4882a593Smuzhiyun 		if (!json_output)
372*4882a593Smuzhiyun 			printf("processed %d commands\n", lines);
373*4882a593Smuzhiyun 	}
374*4882a593Smuzhiyun err_close:
375*4882a593Smuzhiyun 	if (fp != stdin)
376*4882a593Smuzhiyun 		fclose(fp);
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 	if (json_output)
379*4882a593Smuzhiyun 		jsonw_end_array(json_wtr);
380*4882a593Smuzhiyun 
381*4882a593Smuzhiyun 	return err;
382*4882a593Smuzhiyun }
383*4882a593Smuzhiyun 
main(int argc,char ** argv)384*4882a593Smuzhiyun int main(int argc, char **argv)
385*4882a593Smuzhiyun {
386*4882a593Smuzhiyun 	static const struct option options[] = {
387*4882a593Smuzhiyun 		{ "json",	no_argument,	NULL,	'j' },
388*4882a593Smuzhiyun 		{ "help",	no_argument,	NULL,	'h' },
389*4882a593Smuzhiyun 		{ "pretty",	no_argument,	NULL,	'p' },
390*4882a593Smuzhiyun 		{ "version",	no_argument,	NULL,	'V' },
391*4882a593Smuzhiyun 		{ "bpffs",	no_argument,	NULL,	'f' },
392*4882a593Smuzhiyun 		{ "mapcompat",	no_argument,	NULL,	'm' },
393*4882a593Smuzhiyun 		{ "nomount",	no_argument,	NULL,	'n' },
394*4882a593Smuzhiyun 		{ "debug",	no_argument,	NULL,	'd' },
395*4882a593Smuzhiyun 		{ 0 }
396*4882a593Smuzhiyun 	};
397*4882a593Smuzhiyun 	int opt, ret;
398*4882a593Smuzhiyun 
399*4882a593Smuzhiyun 	setlinebuf(stdout);
400*4882a593Smuzhiyun 
401*4882a593Smuzhiyun #ifdef USE_LIBCAP
402*4882a593Smuzhiyun 	/* Libcap < 2.63 hooks before main() to compute the number of
403*4882a593Smuzhiyun 	 * capabilities of the running kernel, and doing so it calls prctl()
404*4882a593Smuzhiyun 	 * which may fail and set errno to non-zero.
405*4882a593Smuzhiyun 	 * Let's reset errno to make sure this does not interfere with the
406*4882a593Smuzhiyun 	 * batch mode.
407*4882a593Smuzhiyun 	 */
408*4882a593Smuzhiyun 	errno = 0;
409*4882a593Smuzhiyun #endif
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	last_do_help = do_help;
412*4882a593Smuzhiyun 	pretty_output = false;
413*4882a593Smuzhiyun 	json_output = false;
414*4882a593Smuzhiyun 	show_pinned = false;
415*4882a593Smuzhiyun 	block_mount = false;
416*4882a593Smuzhiyun 	bin_name = argv[0];
417*4882a593Smuzhiyun 
418*4882a593Smuzhiyun 	hash_init(prog_table.table);
419*4882a593Smuzhiyun 	hash_init(map_table.table);
420*4882a593Smuzhiyun 	hash_init(link_table.table);
421*4882a593Smuzhiyun 
422*4882a593Smuzhiyun 	opterr = 0;
423*4882a593Smuzhiyun 	while ((opt = getopt_long(argc, argv, "Vhpjfmnd",
424*4882a593Smuzhiyun 				  options, NULL)) >= 0) {
425*4882a593Smuzhiyun 		switch (opt) {
426*4882a593Smuzhiyun 		case 'V':
427*4882a593Smuzhiyun 			return do_version(argc, argv);
428*4882a593Smuzhiyun 		case 'h':
429*4882a593Smuzhiyun 			return do_help(argc, argv);
430*4882a593Smuzhiyun 		case 'p':
431*4882a593Smuzhiyun 			pretty_output = true;
432*4882a593Smuzhiyun 			/* fall through */
433*4882a593Smuzhiyun 		case 'j':
434*4882a593Smuzhiyun 			if (!json_output) {
435*4882a593Smuzhiyun 				json_wtr = jsonw_new(stdout);
436*4882a593Smuzhiyun 				if (!json_wtr) {
437*4882a593Smuzhiyun 					p_err("failed to create JSON writer");
438*4882a593Smuzhiyun 					return -1;
439*4882a593Smuzhiyun 				}
440*4882a593Smuzhiyun 				json_output = true;
441*4882a593Smuzhiyun 			}
442*4882a593Smuzhiyun 			jsonw_pretty(json_wtr, pretty_output);
443*4882a593Smuzhiyun 			break;
444*4882a593Smuzhiyun 		case 'f':
445*4882a593Smuzhiyun 			show_pinned = true;
446*4882a593Smuzhiyun 			break;
447*4882a593Smuzhiyun 		case 'm':
448*4882a593Smuzhiyun 			relaxed_maps = true;
449*4882a593Smuzhiyun 			break;
450*4882a593Smuzhiyun 		case 'n':
451*4882a593Smuzhiyun 			block_mount = true;
452*4882a593Smuzhiyun 			break;
453*4882a593Smuzhiyun 		case 'd':
454*4882a593Smuzhiyun 			libbpf_set_print(print_all_levels);
455*4882a593Smuzhiyun 			verifier_logs = true;
456*4882a593Smuzhiyun 			break;
457*4882a593Smuzhiyun 		default:
458*4882a593Smuzhiyun 			p_err("unrecognized option '%s'", argv[optind - 1]);
459*4882a593Smuzhiyun 			if (json_output)
460*4882a593Smuzhiyun 				clean_and_exit(-1);
461*4882a593Smuzhiyun 			else
462*4882a593Smuzhiyun 				usage();
463*4882a593Smuzhiyun 		}
464*4882a593Smuzhiyun 	}
465*4882a593Smuzhiyun 
466*4882a593Smuzhiyun 	argc -= optind;
467*4882a593Smuzhiyun 	argv += optind;
468*4882a593Smuzhiyun 	if (argc < 0)
469*4882a593Smuzhiyun 		usage();
470*4882a593Smuzhiyun 
471*4882a593Smuzhiyun 	ret = cmd_select(cmds, argc, argv, do_help);
472*4882a593Smuzhiyun 
473*4882a593Smuzhiyun 	if (json_output)
474*4882a593Smuzhiyun 		jsonw_destroy(&json_wtr);
475*4882a593Smuzhiyun 
476*4882a593Smuzhiyun 	if (show_pinned) {
477*4882a593Smuzhiyun 		delete_pinned_obj_table(&prog_table);
478*4882a593Smuzhiyun 		delete_pinned_obj_table(&map_table);
479*4882a593Smuzhiyun 		delete_pinned_obj_table(&link_table);
480*4882a593Smuzhiyun 	}
481*4882a593Smuzhiyun 
482*4882a593Smuzhiyun 	return ret;
483*4882a593Smuzhiyun }
484