]>
Commit | Line | Data |
---|---|---|
959ef981 | 1 | // SPDX-License-Identifier: GPL-2.0 |
e246ba5f | 2 | /* |
da23017d NS |
3 | * Copyright (c) 2003-2005 Silicon Graphics, Inc. |
4 | * All Rights Reserved. | |
e246ba5f | 5 | */ |
dfc130f3 | 6 | |
dcabd4e7 | 7 | #include "platform_defs.h" |
6b803e5a CH |
8 | #include "command.h" |
9 | #include "input.h" | |
e246ba5f NS |
10 | |
11 | cmdinfo_t *cmdtab; | |
12 | int ncmds; | |
13 | ||
ef346a25 | 14 | static iterfunc_t iter_func; |
3d93ccb7 | 15 | static checkfunc_t check_func; |
58a1899a DC |
16 | |
17 | struct cmdline { | |
18 | char *cmdline; | |
19 | bool iterate; | |
20 | }; | |
21 | ||
00ff2b10 ES |
22 | static int ncmdline; |
23 | static struct cmdline *cmdline; | |
3d93ccb7 | 24 | |
e246ba5f | 25 | static int |
3d93ccb7 | 26 | compare(const void *a, const void *b) |
e246ba5f NS |
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)); | |
0babf94f WS |
37 | if (!cmdtab) { |
38 | perror(_("adding libxcmd command")); | |
39 | exit(1); | |
40 | } | |
e246ba5f | 41 | cmdtab[ncmds - 1] = *ci; |
3d93ccb7 NS |
42 | qsort(cmdtab, ncmds, sizeof(*cmdtab), compare); |
43 | } | |
44 | ||
45 | static int | |
46 | check_command( | |
47 | const cmdinfo_t *ci) | |
48 | { | |
92058d25 DC |
49 | /* always run internal library supplied commands */ |
50 | if (ci->flags & CMD_FLAG_LIBRARY) | |
51 | return 1; | |
52 | ||
3d93ccb7 NS |
53 | if (check_func) |
54 | return check_func(ci); | |
55 | return 1; | |
56 | } | |
57 | ||
58 | void | |
59 | add_check_command( | |
60 | checkfunc_t cf) | |
61 | { | |
62 | check_func = cf; | |
e246ba5f NS |
63 | } |
64 | ||
48c46ee3 NS |
65 | int |
66 | command_usage( | |
67 | const cmdinfo_t *ci) | |
68 | { | |
3d93ccb7 | 69 | printf("%s %s -- %s\n", ci->name, ci->args, ci->oneline); |
48c46ee3 NS |
70 | return 0; |
71 | } | |
72 | ||
e246ba5f NS |
73 | int |
74 | command( | |
802d66e3 | 75 | const cmdinfo_t *ct, |
e246ba5f NS |
76 | int argc, |
77 | char **argv) | |
78 | { | |
802d66e3 | 79 | char *cmd = argv[0]; |
e246ba5f | 80 | |
3d93ccb7 | 81 | if (!check_command(ct)) |
48c46ee3 | 82 | return 0; |
802d66e3 | 83 | |
e246ba5f NS |
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 | } | |
c0211f67 | 99 | platform_getoptreset(); |
e246ba5f NS |
100 | return ct->cfunc(argc, argv); |
101 | } | |
102 | ||
103 | const cmdinfo_t * | |
104 | find_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 | } | |
3d93ccb7 NS |
116 | |
117 | void | |
118 | add_user_command(char *optarg) | |
119 | { | |
120 | ncmdline++; | |
58a1899a DC |
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 | ||
131 | void | |
132 | add_oneshot_user_command(char *optarg) | |
133 | { | |
134 | ncmdline++; | |
135 | cmdline = realloc(cmdline, sizeof(struct cmdline) * (ncmdline)); | |
3d93ccb7 NS |
136 | if (!cmdline) { |
137 | perror("realloc"); | |
138 | exit(1); | |
139 | } | |
58a1899a DC |
140 | cmdline[ncmdline-1].cmdline = optarg; |
141 | cmdline[ncmdline-1].iterate = false; | |
3d93ccb7 NS |
142 | } |
143 | ||
7a9b7314 | 144 | /* |
d6ac0462 DC |
145 | * Run a command, iterating as necessary. Return 0 for success, non-zero |
146 | * if an error occurred. Errors terminate loop iteration immediately. | |
7a9b7314 | 147 | */ |
3d93ccb7 | 148 | static int |
ef346a25 | 149 | iterate_command( |
7a9b7314 | 150 | const cmdinfo_t *ct, |
d6ac0462 DC |
151 | int argc, |
152 | char **argv) | |
3d93ccb7 | 153 | { |
d6ac0462 DC |
154 | int error = 0; |
155 | int j; | |
156 | ||
157 | /* if there's nothing to iterate, we're done! */ | |
158 | if (!iter_func) | |
7a9b7314 | 159 | return 0; |
d6ac0462 DC |
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; | |
3d93ccb7 NS |
169 | } |
170 | ||
171 | void | |
ef346a25 DC |
172 | add_command_iterator( |
173 | iterfunc_t func) | |
3d93ccb7 | 174 | { |
ef346a25 | 175 | iter_func = func; |
3d93ccb7 NS |
176 | } |
177 | ||
d6ac0462 DC |
178 | static int |
179 | process_input( | |
180 | char *input, | |
181 | bool iterate) | |
3d93ccb7 | 182 | { |
802d66e3 BN |
183 | char **v; |
184 | const cmdinfo_t *ct; | |
d6ac0462 DC |
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); | |
203 | out: | |
204 | doneline(input, v); | |
205 | return error; | |
206 | } | |
207 | ||
208 | void | |
209 | command_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 | } | |
3d93ccb7 | 225 | |
d6ac0462 | 226 | /* command line mode */ |
3d93ccb7 | 227 | for (i = 0; !done && i < ncmdline; i++) { |
58a1899a | 228 | input = strdup(cmdline[i].cmdline); |
802d66e3 BN |
229 | if (!input) { |
230 | fprintf(stderr, | |
231 | _("cannot strdup command '%s': %s\n"), | |
58a1899a | 232 | cmdline[i].cmdline, strerror(errno)); |
802d66e3 BN |
233 | exit(1); |
234 | } | |
58a1899a | 235 | done = process_input(input, cmdline[i].iterate); |
3d93ccb7 | 236 | } |
d6ac0462 DC |
237 | free(cmdline); |
238 | return; | |
3d93ccb7 | 239 | } |
a9b61ce9 DW |
240 | |
241 | void | |
242 | report_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 | } |