blob: 9989a77fdc4ac6a40a7778967f5516b396bc6df4 [file] [log] [blame]
Jakub Kicinski71bb4282017-10-04 20:10:04 -07001/*
2 * Copyright (C) 2017 Netronome Systems, Inc.
3 *
4 * This software is dual licensed under the GNU General License Version 2,
5 * June 1991 as shown in the file COPYING in the top-level directory of this
6 * source tree or the BSD 2-Clause License provided below. You have the
7 * option to license this software under the complete terms of either license.
8 *
9 * The BSD 2-Clause License:
10 *
11 * Redistribution and use in source and binary forms, with or
12 * without modification, are permitted provided that the following
13 * conditions are met:
14 *
15 * 1. Redistributions of source code must retain the above
16 * copyright notice, this list of conditions and the following
17 * disclaimer.
18 *
19 * 2. Redistributions in binary form must reproduce the above
20 * copyright notice, this list of conditions and the following
21 * disclaimer in the documentation and/or other materials
22 * provided with the distribution.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
28 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
29 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
30 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
31 * SOFTWARE.
32 */
33
34/* Author: Jakub Kicinski <kubakici@wp.pl> */
35
36#include <bfd.h>
37#include <ctype.h>
38#include <errno.h>
Quentin Monneta2bc2e52017-10-23 09:24:06 -070039#include <getopt.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070040#include <linux/bpf.h>
Quentin Monnet821cfbb2017-10-19 15:46:26 -070041#include <linux/version.h>
Jakub Kicinski71bb4282017-10-04 20:10:04 -070042#include <stdio.h>
43#include <stdlib.h>
44#include <string.h>
45
46#include <bpf.h>
47
48#include "main.h"
49
50const char *bin_name;
51static int last_argc;
52static char **last_argv;
53static int (*last_do_help)(int argc, char **argv);
Quentin Monnetd35efba2017-10-23 09:24:07 -070054json_writer_t *json_wtr;
55bool pretty_output;
56bool json_output;
Jakub Kicinski71bb4282017-10-04 20:10:04 -070057
58void usage(void)
59{
60 last_do_help(last_argc - 1, last_argv + 1);
61
62 exit(-1);
63}
64
65static int do_help(int argc, char **argv)
66{
67 fprintf(stderr,
68 "Usage: %s OBJECT { COMMAND | help }\n"
69 " %s batch file FILE\n"
Quentin Monnet821cfbb2017-10-19 15:46:26 -070070 " %s version\n"
Jakub Kicinski71bb4282017-10-04 20:10:04 -070071 "\n"
72 " OBJECT := { prog | map }\n",
Quentin Monnet821cfbb2017-10-19 15:46:26 -070073 bin_name, bin_name, bin_name);
Jakub Kicinski71bb4282017-10-04 20:10:04 -070074
75 return 0;
76}
77
Quentin Monnet821cfbb2017-10-19 15:46:26 -070078static int do_version(int argc, char **argv)
79{
80 printf("%s v%d.%d.%d\n", bin_name,
81 LINUX_VERSION_CODE >> 16,
82 LINUX_VERSION_CODE >> 8 & 0xf,
83 LINUX_VERSION_CODE & 0xf);
84 return 0;
85}
86
Jakub Kicinski71bb4282017-10-04 20:10:04 -070087int cmd_select(const struct cmd *cmds, int argc, char **argv,
88 int (*help)(int argc, char **argv))
89{
90 unsigned int i;
91
92 last_argc = argc;
93 last_argv = argv;
94 last_do_help = help;
95
96 if (argc < 1 && cmds[0].func)
97 return cmds[0].func(argc, argv);
98
99 for (i = 0; cmds[i].func; i++)
100 if (is_prefix(*argv, cmds[i].cmd))
101 return cmds[i].func(argc - 1, argv + 1);
102
103 help(argc - 1, argv + 1);
104
105 return -1;
106}
107
108bool is_prefix(const char *pfx, const char *str)
109{
110 if (!pfx)
111 return false;
112 if (strlen(str) < strlen(pfx))
113 return false;
114
115 return !memcmp(str, pfx, strlen(pfx));
116}
117
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700118void fprint_hex(FILE *f, void *arg, unsigned int n, const char *sep)
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700119{
120 unsigned char *data = arg;
121 unsigned int i;
122
123 for (i = 0; i < n; i++) {
124 const char *pfx = "";
125
126 if (!i)
127 /* nothing */;
128 else if (!(i % 16))
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700129 fprintf(f, "\n");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700130 else if (!(i % 8))
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700131 fprintf(f, " ");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700132 else
133 pfx = sep;
134
Quentin Monnet9cbe1f582017-10-19 15:46:19 -0700135 fprintf(f, "%s%02hhx", i ? pfx : "", data[i]);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700136 }
137}
138
139static int do_batch(int argc, char **argv);
140
141static const struct cmd cmds[] = {
142 { "help", do_help },
143 { "batch", do_batch },
144 { "prog", do_prog },
145 { "map", do_map },
Quentin Monnet821cfbb2017-10-19 15:46:26 -0700146 { "version", do_version },
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700147 { 0 }
148};
149
150static int do_batch(int argc, char **argv)
151{
152 unsigned int lines = 0;
153 char *n_argv[4096];
154 char buf[65536];
155 int n_argc;
156 FILE *fp;
157 int err;
Quentin Monnet3aaca6b2017-10-23 09:24:12 -0700158 int i;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700159
160 if (argc < 2) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700161 p_err("too few parameters for batch");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700162 return -1;
163 } else if (!is_prefix(*argv, "file")) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700164 p_err("expected 'file', got: %s", *argv);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700165 return -1;
166 } else if (argc > 2) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700167 p_err("too many parameters for batch");
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700168 return -1;
169 }
170 NEXT_ARG();
171
172 fp = fopen(*argv, "r");
173 if (!fp) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700174 p_err("Can't open file (%s): %s", *argv, strerror(errno));
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700175 return -1;
176 }
177
Quentin Monnet3aaca6b2017-10-23 09:24:12 -0700178 if (json_output)
179 jsonw_start_array(json_wtr);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700180 while (fgets(buf, sizeof(buf), fp)) {
181 if (strlen(buf) == sizeof(buf) - 1) {
182 errno = E2BIG;
183 break;
184 }
185
186 n_argc = 0;
187 n_argv[n_argc] = strtok(buf, " \t\n");
188
189 while (n_argv[n_argc]) {
190 n_argc++;
191 if (n_argc == ARRAY_SIZE(n_argv)) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700192 p_err("line %d has too many arguments, skip",
193 lines);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700194 n_argc = 0;
195 break;
196 }
197 n_argv[n_argc] = strtok(NULL, " \t\n");
198 }
199
200 if (!n_argc)
201 continue;
202
Quentin Monnet3aaca6b2017-10-23 09:24:12 -0700203 if (json_output) {
204 jsonw_start_object(json_wtr);
205 jsonw_name(json_wtr, "command");
206 jsonw_start_array(json_wtr);
207 for (i = 0; i < n_argc; i++)
208 jsonw_string(json_wtr, n_argv[i]);
209 jsonw_end_array(json_wtr);
210 jsonw_name(json_wtr, "output");
211 }
212
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700213 err = cmd_select(cmds, n_argc, n_argv, do_help);
Quentin Monnet3aaca6b2017-10-23 09:24:12 -0700214
215 if (json_output)
216 jsonw_end_object(json_wtr);
217
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700218 if (err)
219 goto err_close;
220
221 lines++;
222 }
223
224 if (errno && errno != ENOENT) {
225 perror("reading batch file failed");
226 err = -1;
227 } else {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700228 p_info("processed %d lines", lines);
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700229 err = 0;
230 }
231err_close:
232 fclose(fp);
233
Quentin Monnet3aaca6b2017-10-23 09:24:12 -0700234 if (json_output)
235 jsonw_end_array(json_wtr);
236
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700237 return err;
238}
239
240int main(int argc, char **argv)
241{
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700242 static const struct option options[] = {
Quentin Monnetd35efba2017-10-23 09:24:07 -0700243 { "json", no_argument, NULL, 'j' },
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700244 { "help", no_argument, NULL, 'h' },
Quentin Monnetd35efba2017-10-23 09:24:07 -0700245 { "pretty", no_argument, NULL, 'p' },
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700246 { "version", no_argument, NULL, 'V' },
247 { 0 }
248 };
Quentin Monnetd35efba2017-10-23 09:24:07 -0700249 int opt, ret;
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700250
251 last_do_help = do_help;
Quentin Monnetd35efba2017-10-23 09:24:07 -0700252 pretty_output = false;
253 json_output = false;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700254 bin_name = argv[0];
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700255
Quentin Monnetd35efba2017-10-23 09:24:07 -0700256 while ((opt = getopt_long(argc, argv, "Vhpj",
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700257 options, NULL)) >= 0) {
258 switch (opt) {
259 case 'V':
260 return do_version(argc, argv);
261 case 'h':
262 return do_help(argc, argv);
Quentin Monnetd35efba2017-10-23 09:24:07 -0700263 case 'p':
264 pretty_output = true;
265 /* fall through */
266 case 'j':
267 json_output = true;
268 break;
Quentin Monneta2bc2e52017-10-23 09:24:06 -0700269 default:
270 usage();
271 }
272 }
273
274 argc -= optind;
275 argv += optind;
276 if (argc < 0)
277 usage();
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700278
Quentin Monnetd35efba2017-10-23 09:24:07 -0700279 if (json_output) {
280 json_wtr = jsonw_new(stdout);
281 if (!json_wtr) {
Quentin Monnet9a5ab8b2017-10-23 09:24:13 -0700282 p_err("failed to create JSON writer");
Quentin Monnetd35efba2017-10-23 09:24:07 -0700283 return -1;
284 }
285 jsonw_pretty(json_wtr, pretty_output);
286 }
287
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700288 bfd_init();
289
Quentin Monnetd35efba2017-10-23 09:24:07 -0700290 ret = cmd_select(cmds, argc, argv, do_help);
291
292 if (json_output)
293 jsonw_destroy(&json_wtr);
294
295 return ret;
Jakub Kicinski71bb4282017-10-04 20:10:04 -0700296}