Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
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}