File Index
Files and directories
Sign in
FILE

main.c

File preview with syntax highlighting.

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