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