]> git.ipfire.org Git - thirdparty/xfsprogs-dev.git/blob - libxcmd/command.c
xfs: don't set bmapi total block req where minleft is
[thirdparty/xfsprogs-dev.git] / libxcmd / command.c
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Copyright (c) 2003-2005 Silicon Graphics, Inc.
4 * All Rights Reserved.
5 */
6
7 #include "platform_defs.h"
8 #include "command.h"
9 #include "input.h"
10
11 cmdinfo_t *cmdtab;
12 int ncmds;
13
14 static iterfunc_t iter_func;
15 static checkfunc_t check_func;
16
17 struct cmdline {
18 char *cmdline;
19 bool iterate;
20 };
21
22 static int ncmdline;
23 static struct cmdline *cmdline;
24
25 static int
26 compare(const void *a, const void *b)
27 {
28 return strcmp(((const cmdinfo_t *)a)->name,
29 ((const cmdinfo_t *)b)->name);
30 }
31
32 void
33 add_command(
34 const cmdinfo_t *ci)
35 {
36 cmdtab = realloc((void *)cmdtab, ++ncmds * sizeof(*cmdtab));
37 cmdtab[ncmds - 1] = *ci;
38 qsort(cmdtab, ncmds, sizeof(*cmdtab), compare);
39 }
40
41 static int
42 check_command(
43 const cmdinfo_t *ci)
44 {
45 /* always run internal library supplied commands */
46 if (ci->flags & CMD_FLAG_LIBRARY)
47 return 1;
48
49 if (check_func)
50 return check_func(ci);
51 return 1;
52 }
53
54 void
55 add_check_command(
56 checkfunc_t cf)
57 {
58 check_func = cf;
59 }
60
61 int
62 command_usage(
63 const cmdinfo_t *ci)
64 {
65 printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline);
66 return 0;
67 }
68
69 int
70 command(
71 const cmdinfo_t *ct,
72 int argc,
73 char **argv)
74 {
75 char *cmd = argv[0];
76
77 if (!check_command(ct))
78 return 0;
79
80 if (argc-1 < ct->argmin || (ct->argmax != -1 && argc-1 > ct->argmax)) {
81 if (ct->argmax == -1)
82 fprintf(stderr,
83 _("bad argument count %d to %s, expected at least %d arguments\n"),
84 argc-1, cmd, ct->argmin);
85 else if (ct->argmin == ct->argmax)
86 fprintf(stderr,
87 _("bad argument count %d to %s, expected %d arguments\n"),
88 argc-1, cmd, ct->argmin);
89 else
90 fprintf(stderr,
91 _("bad argument count %d to %s, expected between %d and %d arguments\n"),
92 argc-1, cmd, ct->argmin, ct->argmax);
93 return 0;
94 }
95 platform_getoptreset();
96 return ct->cfunc(argc, argv);
97 }
98
99 const cmdinfo_t *
100 find_command(
101 const char *cmd)
102 {
103 cmdinfo_t *ct;
104
105 for (ct = cmdtab; ct < &cmdtab[ncmds]; ct++) {
106 if (strcmp(ct->name, cmd) == 0 ||
107 (ct->altname && strcmp(ct->altname, cmd) == 0))
108 return (const cmdinfo_t *)ct;
109 }
110 return NULL;
111 }
112
113 void
114 add_user_command(char *optarg)
115 {
116 ncmdline++;
117 cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline));
118 if (!cmdline) {
119 perror("realloc");
120 exit(1);
121 }
122 cmdline[ncmdline-1].cmdline = optarg;
123 cmdline[ncmdline-1].iterate = true;
124
125 }
126
127 void
128 add_oneshot_user_command(char *optarg)
129 {
130 ncmdline++;
131 cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline));
132 if (!cmdline) {
133 perror("realloc");
134 exit(1);
135 }
136 cmdline[ncmdline-1].cmdline = optarg;
137 cmdline[ncmdline-1].iterate = false;
138 }
139
140 /*
141 * Run a command, iterating as necessary. Return 0 for success, non-zero
142 * if an error occurred. Errors terminate loop iteration immediately.
143 */
144 static int
145 iterate_command(
146 const cmdinfo_t *ct,
147 int argc,
148 char **argv)
149 {
150 int error = 0;
151 int j;
152
153 /* if there's nothing to iterate, we're done! */
154 if (!iter_func)
155 return 0;
156
157 for (j = iter_func(0); j; j = iter_func(j)) {
158 error = command(ct, argc, argv);
159 if (error)
160 break;
161
162 }
163
164 return error;
165 }
166
167 void
168 add_command_iterator(
169 iterfunc_t func)
170 {
171 iter_func = func;
172 }
173
174 static int
175 process_input(
176 char *input,
177 bool iterate)
178 {
179 char **v;
180 const cmdinfo_t *ct;
181 int c = 0;
182 int error = 0;
183
184 v = breakline(input, &c);
185 if (!c)
186 goto out;
187
188 ct = find_command(v[0]);
189 if (!ct) {
190 fprintf(stderr, _("command \"%s\" not found\n"), v[0]);
191 goto out;
192 }
193
194 /* oneshot commands don't iterate */
195 if (!iterate || (ct->flags & CMD_FLAG_ONESHOT))
196 error = command(ct, c, v);
197 else
198 error = iterate_command(ct, c, v);
199 out:
200 doneline(input, v);
201 return error;
202 }
203
204 void
205 command_loop(void)
206 {
207 char *input;
208 int done = 0;
209 int i;
210
211 if (!cmdline) {
212 /* interactive mode */
213 while (!done) {
214 input = fetchline();
215 if (!input)
216 break;
217 done = process_input(input, false);
218 }
219 return;
220 }
221
222 /* command line mode */
223 for (i = 0; !done && i < ncmdline; i++) {
224 input = strdup(cmdline[i].cmdline);
225 if (!input) {
226 fprintf(stderr,
227 _("cannot strdup command '%s': %s\n"),
228 cmdline[i].cmdline, strerror(errno));
229 exit(1);
230 }
231 done = process_input(input, cmdline[i].iterate);
232 }
233 free(cmdline);
234 return;
235 }
236
237 void
238 report_io_times(
239 const char *verb,
240 struct timeval *t2,
241 long long offset,
242 long long count,
243 long long total,
244 int ops,
245 int compact)
246 {
247 char s1[64], s2[64], ts[64];
248
249 timestr(t2, ts, sizeof(ts), compact ? VERBOSE_FIXED_TIME : 0);
250 if (!compact) {
251 cvtstr((double)total, s1, sizeof(s1));
252 cvtstr(tdiv((double)total, *t2), s2, sizeof(s2));
253 printf(_("%s %lld/%lld bytes at offset %lld\n"),
254 verb, total, count, (long long)offset);
255 printf(_("%s, %d ops; %s (%s/sec and %.4f ops/sec)\n"),
256 s1, ops, ts, s2, tdiv((double)ops, *t2));
257 } else {/* bytes,ops,time,bytes/sec,ops/sec */
258 printf("%lld,%d,%s,%.3f,%.3f\n",
259 total, ops, ts,
260 tdiv((double)total, *t2), tdiv((double)ops, *t2));
261 }
262 }