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