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