main.c 11 KB

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