xref: /linux/tools/net/ynl/ynltool/main.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1b02d2290SJakub Kicinski // SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2b02d2290SJakub Kicinski /* Copyright (C) 2017-2018 Netronome Systems, Inc. */
3b02d2290SJakub Kicinski /* Copyright Meta Platforms, Inc. and affiliates */
4b02d2290SJakub Kicinski 
5b02d2290SJakub Kicinski #include <ctype.h>
6b02d2290SJakub Kicinski #include <errno.h>
7b02d2290SJakub Kicinski #include <getopt.h>
8b02d2290SJakub Kicinski #include <stdio.h>
9b02d2290SJakub Kicinski #include <stdlib.h>
10b02d2290SJakub Kicinski #include <string.h>
11b02d2290SJakub Kicinski #include <stdarg.h>
12b02d2290SJakub Kicinski 
13b02d2290SJakub Kicinski #include "main.h"
14b02d2290SJakub Kicinski 
15b02d2290SJakub Kicinski const char *bin_name;
16b02d2290SJakub Kicinski static int last_argc;
17b02d2290SJakub Kicinski static char **last_argv;
18b02d2290SJakub Kicinski static int (*last_do_help)(int argc, char **argv);
19b02d2290SJakub Kicinski json_writer_t *json_wtr;
20b02d2290SJakub Kicinski bool pretty_output;
21b02d2290SJakub Kicinski bool json_output;
22b02d2290SJakub Kicinski 
23b02d2290SJakub Kicinski static void __attribute__((noreturn)) clean_and_exit(int i)
24b02d2290SJakub Kicinski {
25b02d2290SJakub Kicinski 	if (json_output)
26b02d2290SJakub Kicinski 		jsonw_destroy(&json_wtr);
27b02d2290SJakub Kicinski 
28b02d2290SJakub Kicinski 	exit(i);
29b02d2290SJakub Kicinski }
30b02d2290SJakub Kicinski 
31b02d2290SJakub Kicinski void usage(void)
32b02d2290SJakub Kicinski {
33b02d2290SJakub Kicinski 	last_do_help(last_argc - 1, last_argv + 1);
34b02d2290SJakub Kicinski 
35b02d2290SJakub Kicinski 	clean_and_exit(-1);
36b02d2290SJakub Kicinski }
37b02d2290SJakub Kicinski 
38b02d2290SJakub Kicinski static int do_help(int argc __attribute__((unused)),
39b02d2290SJakub Kicinski 		   char **argv __attribute__((unused)))
40b02d2290SJakub Kicinski {
41b02d2290SJakub Kicinski 	if (json_output) {
42b02d2290SJakub Kicinski 		jsonw_null(json_wtr);
43b02d2290SJakub Kicinski 		return 0;
44b02d2290SJakub Kicinski 	}
45b02d2290SJakub Kicinski 
46b02d2290SJakub Kicinski 	fprintf(stderr,
47b02d2290SJakub Kicinski 		"Usage: %s [OPTIONS] OBJECT { COMMAND | help }\n"
48b02d2290SJakub Kicinski 		"       %s version\n"
49b02d2290SJakub Kicinski 		"\n"
50*3f0a638dSJakub Kicinski 		"       OBJECT := { page-pool | qstats }\n"
51b02d2290SJakub Kicinski 		"       " HELP_SPEC_OPTIONS "\n"
52b02d2290SJakub Kicinski 		"",
53b02d2290SJakub Kicinski 		bin_name, bin_name);
54b02d2290SJakub Kicinski 
55b02d2290SJakub Kicinski 	return 0;
56b02d2290SJakub Kicinski }
57b02d2290SJakub Kicinski 
58b02d2290SJakub Kicinski static int do_version(int argc __attribute__((unused)),
59b02d2290SJakub Kicinski 		      char **argv __attribute__((unused)))
60b02d2290SJakub Kicinski {
61b02d2290SJakub Kicinski 	if (json_output) {
62b02d2290SJakub Kicinski 		jsonw_start_object(json_wtr);
63b02d2290SJakub Kicinski 		jsonw_name(json_wtr, "version");
64b02d2290SJakub Kicinski 		jsonw_printf(json_wtr, SRC_VERSION);
65b02d2290SJakub Kicinski 		jsonw_end_object(json_wtr);
66b02d2290SJakub Kicinski 	} else {
67b02d2290SJakub Kicinski 		printf("%s " SRC_VERSION "\n", bin_name);
68b02d2290SJakub Kicinski 	}
69b02d2290SJakub Kicinski 	return 0;
70b02d2290SJakub Kicinski }
71b02d2290SJakub Kicinski 
72b02d2290SJakub Kicinski static const struct cmd commands[] = {
73b02d2290SJakub Kicinski 	{ "help",	do_help },
74124dac9bSJakub Kicinski 	{ "page-pool",	do_page_pool },
75*3f0a638dSJakub Kicinski 	{ "qstats",	do_qstats },
76b02d2290SJakub Kicinski 	{ "version",	do_version },
77b02d2290SJakub Kicinski 	{ 0 }
78b02d2290SJakub Kicinski };
79b02d2290SJakub Kicinski 
80b02d2290SJakub Kicinski int cmd_select(const struct cmd *cmds, int argc, char **argv,
81b02d2290SJakub Kicinski 	       int (*help)(int argc, char **argv))
82b02d2290SJakub Kicinski {
83b02d2290SJakub Kicinski 	unsigned int i;
84b02d2290SJakub Kicinski 
85b02d2290SJakub Kicinski 	last_argc = argc;
86b02d2290SJakub Kicinski 	last_argv = argv;
87b02d2290SJakub Kicinski 	last_do_help = help;
88b02d2290SJakub Kicinski 
89b02d2290SJakub Kicinski 	if (argc < 1 && cmds[0].func)
90b02d2290SJakub Kicinski 		return cmds[0].func(argc, argv);
91b02d2290SJakub Kicinski 
92b02d2290SJakub Kicinski 	for (i = 0; cmds[i].cmd; i++) {
93b02d2290SJakub Kicinski 		if (is_prefix(*argv, cmds[i].cmd)) {
94b02d2290SJakub Kicinski 			if (!cmds[i].func) {
95b02d2290SJakub Kicinski 				p_err("command '%s' is not available", cmds[i].cmd);
96b02d2290SJakub Kicinski 				return -1;
97b02d2290SJakub Kicinski 			}
98b02d2290SJakub Kicinski 			return cmds[i].func(argc - 1, argv + 1);
99b02d2290SJakub Kicinski 		}
100b02d2290SJakub Kicinski 	}
101b02d2290SJakub Kicinski 
102b02d2290SJakub Kicinski 	help(argc - 1, argv + 1);
103b02d2290SJakub Kicinski 
104b02d2290SJakub Kicinski 	return -1;
105b02d2290SJakub Kicinski }
106b02d2290SJakub Kicinski 
107b02d2290SJakub Kicinski bool is_prefix(const char *pfx, const char *str)
108b02d2290SJakub Kicinski {
109b02d2290SJakub Kicinski 	if (!pfx)
110b02d2290SJakub Kicinski 		return false;
111b02d2290SJakub Kicinski 	if (strlen(str) < strlen(pfx))
112b02d2290SJakub Kicinski 		return false;
113b02d2290SJakub Kicinski 
114b02d2290SJakub Kicinski 	return !memcmp(str, pfx, strlen(pfx));
115b02d2290SJakub Kicinski }
116b02d2290SJakub Kicinski 
117b02d2290SJakub Kicinski /* Last argument MUST be NULL pointer */
118b02d2290SJakub Kicinski int detect_common_prefix(const char *arg, ...)
119b02d2290SJakub Kicinski {
120b02d2290SJakub Kicinski 	unsigned int count = 0;
121b02d2290SJakub Kicinski 	const char *ref;
122b02d2290SJakub Kicinski 	char msg[256];
123b02d2290SJakub Kicinski 	va_list ap;
124b02d2290SJakub Kicinski 
125b02d2290SJakub Kicinski 	snprintf(msg, sizeof(msg), "ambiguous prefix: '%s' could be '", arg);
126b02d2290SJakub Kicinski 	va_start(ap, arg);
127b02d2290SJakub Kicinski 	while ((ref = va_arg(ap, const char *))) {
128b02d2290SJakub Kicinski 		if (!is_prefix(arg, ref))
129b02d2290SJakub Kicinski 			continue;
130b02d2290SJakub Kicinski 		count++;
131b02d2290SJakub Kicinski 		if (count > 1)
132b02d2290SJakub Kicinski 			strncat(msg, "' or '", sizeof(msg) - strlen(msg) - 1);
133b02d2290SJakub Kicinski 		strncat(msg, ref, sizeof(msg) - strlen(msg) - 1);
134b02d2290SJakub Kicinski 	}
135b02d2290SJakub Kicinski 	va_end(ap);
136b02d2290SJakub Kicinski 	strncat(msg, "'", sizeof(msg) - strlen(msg) - 1);
137b02d2290SJakub Kicinski 
138b02d2290SJakub Kicinski 	if (count >= 2) {
139b02d2290SJakub Kicinski 		p_err("%s", msg);
140b02d2290SJakub Kicinski 		return -1;
141b02d2290SJakub Kicinski 	}
142b02d2290SJakub Kicinski 
143b02d2290SJakub Kicinski 	return 0;
144b02d2290SJakub Kicinski }
145b02d2290SJakub Kicinski 
146b02d2290SJakub Kicinski void p_err(const char *fmt, ...)
147b02d2290SJakub Kicinski {
148b02d2290SJakub Kicinski 	va_list ap;
149b02d2290SJakub Kicinski 
150b02d2290SJakub Kicinski 	va_start(ap, fmt);
151b02d2290SJakub Kicinski 	if (json_output) {
152b02d2290SJakub Kicinski 		jsonw_start_object(json_wtr);
153b02d2290SJakub Kicinski 		jsonw_name(json_wtr, "error");
154b02d2290SJakub Kicinski 		jsonw_vprintf_enquote(json_wtr, fmt, ap);
155b02d2290SJakub Kicinski 		jsonw_end_object(json_wtr);
156b02d2290SJakub Kicinski 	} else {
157b02d2290SJakub Kicinski 		fprintf(stderr, "Error: ");
158b02d2290SJakub Kicinski 		vfprintf(stderr, fmt, ap);
159b02d2290SJakub Kicinski 		fprintf(stderr, "\n");
160b02d2290SJakub Kicinski 	}
161b02d2290SJakub Kicinski 	va_end(ap);
162b02d2290SJakub Kicinski }
163b02d2290SJakub Kicinski 
164b02d2290SJakub Kicinski void p_info(const char *fmt, ...)
165b02d2290SJakub Kicinski {
166b02d2290SJakub Kicinski 	va_list ap;
167b02d2290SJakub Kicinski 
168b02d2290SJakub Kicinski 	if (json_output)
169b02d2290SJakub Kicinski 		return;
170b02d2290SJakub Kicinski 
171b02d2290SJakub Kicinski 	va_start(ap, fmt);
172b02d2290SJakub Kicinski 	vfprintf(stderr, fmt, ap);
173b02d2290SJakub Kicinski 	fprintf(stderr, "\n");
174b02d2290SJakub Kicinski 	va_end(ap);
175b02d2290SJakub Kicinski }
176b02d2290SJakub Kicinski 
177b02d2290SJakub Kicinski int main(int argc, char **argv)
178b02d2290SJakub Kicinski {
179b02d2290SJakub Kicinski 	static const struct option options[] = {
180b02d2290SJakub Kicinski 		{ "json",	no_argument,	NULL,	'j' },
181b02d2290SJakub Kicinski 		{ "help",	no_argument,	NULL,	'h' },
182b02d2290SJakub Kicinski 		{ "pretty",	no_argument,	NULL,	'p' },
183b02d2290SJakub Kicinski 		{ "version",	no_argument,	NULL,	'V' },
184b02d2290SJakub Kicinski 		{ 0 }
185b02d2290SJakub Kicinski 	};
186b02d2290SJakub Kicinski 	bool version_requested = false;
187b02d2290SJakub Kicinski 	int opt, ret;
188b02d2290SJakub Kicinski 
189b02d2290SJakub Kicinski 	setlinebuf(stdout);
190b02d2290SJakub Kicinski 
191b02d2290SJakub Kicinski 	last_do_help = do_help;
192b02d2290SJakub Kicinski 	pretty_output = false;
193b02d2290SJakub Kicinski 	json_output = false;
194b02d2290SJakub Kicinski 	bin_name = "ynltool";
195b02d2290SJakub Kicinski 
196b02d2290SJakub Kicinski 	opterr = 0;
197b02d2290SJakub Kicinski 	while ((opt = getopt_long(argc, argv, "Vhjp",
198b02d2290SJakub Kicinski 				  options, NULL)) >= 0) {
199b02d2290SJakub Kicinski 		switch (opt) {
200b02d2290SJakub Kicinski 		case 'V':
201b02d2290SJakub Kicinski 			version_requested = true;
202b02d2290SJakub Kicinski 			break;
203b02d2290SJakub Kicinski 		case 'h':
204b02d2290SJakub Kicinski 			return do_help(argc, argv);
205b02d2290SJakub Kicinski 		case 'p':
206b02d2290SJakub Kicinski 			pretty_output = true;
207b02d2290SJakub Kicinski 			/* fall through */
208b02d2290SJakub Kicinski 		case 'j':
209b02d2290SJakub Kicinski 			if (!json_output) {
210b02d2290SJakub Kicinski 				json_wtr = jsonw_new(stdout);
211b02d2290SJakub Kicinski 				if (!json_wtr) {
212b02d2290SJakub Kicinski 					p_err("failed to create JSON writer");
213b02d2290SJakub Kicinski 					return -1;
214b02d2290SJakub Kicinski 				}
215b02d2290SJakub Kicinski 				json_output = true;
216b02d2290SJakub Kicinski 			}
217b02d2290SJakub Kicinski 			jsonw_pretty(json_wtr, pretty_output);
218b02d2290SJakub Kicinski 			break;
219b02d2290SJakub Kicinski 		default:
220b02d2290SJakub Kicinski 			p_err("unrecognized option '%s'", argv[optind - 1]);
221b02d2290SJakub Kicinski 			if (json_output)
222b02d2290SJakub Kicinski 				clean_and_exit(-1);
223b02d2290SJakub Kicinski 			else
224b02d2290SJakub Kicinski 				usage();
225b02d2290SJakub Kicinski 		}
226b02d2290SJakub Kicinski 	}
227b02d2290SJakub Kicinski 
228b02d2290SJakub Kicinski 	argc -= optind;
229b02d2290SJakub Kicinski 	argv += optind;
230b02d2290SJakub Kicinski 	if (argc < 0)
231b02d2290SJakub Kicinski 		usage();
232b02d2290SJakub Kicinski 
233b02d2290SJakub Kicinski 	if (version_requested)
234b02d2290SJakub Kicinski 		ret = do_version(argc, argv);
235b02d2290SJakub Kicinski 	else
236b02d2290SJakub Kicinski 		ret = cmd_select(commands, argc, argv, do_help);
237b02d2290SJakub Kicinski 
238b02d2290SJakub Kicinski 	if (json_output)
239b02d2290SJakub Kicinski 		jsonw_destroy(&json_wtr);
240b02d2290SJakub Kicinski 
241b02d2290SJakub Kicinski 	return ret;
242b02d2290SJakub Kicinski }
243