Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016, Citrix Systems, Inc.
3 : : *
4 : : * All rights reserved.
5 : : *
6 : : * Redistribution and use in source and binary forms, with or without
7 : : * modification, are permitted provided that the following conditions are met:
8 : : *
9 : : * 1. Redistributions of source code must retain the above copyright
10 : : * notice, this list of conditions and the following disclaimer.
11 : : * 2. Redistributions in binary form must reproduce the above copyright
12 : : * notice, this list of conditions and the following disclaimer in the
13 : : * documentation and/or other materials provided with the distribution.
14 : : * 3. Neither the name of the copyright holder nor the names of its
15 : : * contributors may be used to endorse or promote products derived from
16 : : * this software without specific prior written permission.
17 : : *
18 : : * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 : : * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 : : * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 : : * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
22 : : * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
23 : : * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
24 : : * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
25 : : * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26 : : * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27 : : * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28 : : * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 : : */
30 : :
31 : : #ifdef HAVE_CONFIG_H
32 : : #include "config.h"
33 : : #endif
34 : :
35 : : #include <errno.h>
36 : : #include <fcntl.h>
37 : : #include <stdio.h>
38 : : #include <stdlib.h>
39 : : #include <sys/types.h>
40 : : #include <sys/stat.h>
41 : : #include <sys/resource.h>
42 : : #include <unistd.h>
43 : : #include <string.h>
44 : :
45 : : #include "libvhd.h"
46 : : #include "vhd-util.h"
47 : : #include "tapdisk-utils.h"
48 : :
49 : : #if 1
50 : : #define DFPRINTF(_f, _a...) fprintf ( stdout, _f , ## _a )
51 : : #else
52 : : #define DFPRINTF(_f, _a...) ((void)0)
53 : : #endif
54 : :
55 : : typedef enum {
56 : : TD_FIELD_HIDDEN = 0,
57 : : TD_FIELD_INVALID = 1
58 : : } td_field_t;
59 : :
60 : : struct vdi_field {
61 : : char *name;
62 : : td_field_t id;
63 : : };
64 : :
65 : : static struct vdi_field td_vdi_fields[TD_FIELD_INVALID] = {
66 : : { .id = TD_FIELD_HIDDEN, .name = "hidden" }
67 : : };
68 : :
69 : : typedef enum {
70 : : TD_CMD_CREATE = 0,
71 : : TD_CMD_SNAPSHOT,
72 : : /* TD_CMD_COALESCE, */
73 : : TD_CMD_QUERY,
74 : : /* TD_CMD_RESIZE, */
75 : : TD_CMD_SET,
76 : : /* TD_CMD_REPAIR, */
77 : : /* TD_CMD_FILL, */
78 : : /* TD_CMD_READ, */
79 : : TD_CMD_INVALID,
80 : : } td_command_t;
81 : :
82 : : struct command {
83 : : td_command_t id;
84 : : char *name;
85 : : int needs_type;
86 : : };
87 : :
88 : : struct command commands[TD_CMD_INVALID] = {
89 : : { .id = TD_CMD_CREATE, .name = "create", .needs_type = 1 },
90 : : { .id = TD_CMD_SNAPSHOT, .name = "snapshot", .needs_type = 1 },
91 : : /* { .id = TD_CMD_COALESCE, .name = "coalesce", .needs_type = 1 }, */
92 : : { .id = TD_CMD_QUERY, .name = "query", .needs_type = 1 },
93 : : /* { .id = TD_CMD_RESIZE, .name = "resize", .needs_type = 1 }, */
94 : : { .id = TD_CMD_SET, .name = "set", .needs_type = 1 },
95 : : /* { .id = TD_CMD_REPAIR, .name = "repair", .needs_type = 1 }, */
96 : : /* { .id = TD_CMD_FILL, .name = "fill", .needs_type = 1 }, */
97 : : /* { .id = TD_CMD_READ, .name = "read", .needs_type = 1 }, */
98 : : };
99 : :
100 : : typedef enum {
101 : : TD_TYPE_VHD = 0,
102 : : TD_TYPE_AIO,
103 : : TD_TYPE_INVALID,
104 : : } td_disk_t;
105 : :
106 : : const char *td_disk_types[TD_TYPE_INVALID] = {
107 : : "vhd",
108 : : "aio",
109 : : };
110 : :
111 : : #define print_commands() \
112 : : do { \
113 : : int i; \
114 : : fprintf(stderr, "COMMAND := { "); \
115 : : fprintf(stderr, "%s", commands[0].name); \
116 : : for (i = 1; i < TD_CMD_INVALID; i++) \
117 : : fprintf(stderr, " | %s", commands[i].name); \
118 : : fprintf(stderr, " }\n"); \
119 : : } while (0)
120 : :
121 : : #define print_disk_types() \
122 : : do { \
123 : : int i; \
124 : : fprintf(stderr, "TYPE := { "); \
125 : : fprintf(stderr, "%s", td_disk_types[0]); \
126 : : for (i = 1; i < TD_TYPE_INVALID; i++) \
127 : : fprintf(stderr, " | %s", td_disk_types[i]); \
128 : : fprintf(stderr, " }\n"); \
129 : : } while (0);
130 : :
131 : : #define print_field_names() \
132 : : do { \
133 : : int i; \
134 : : fprintf(stderr, "FIELD := { "); \
135 : : fprintf(stderr, "%s", td_vdi_fields[0].name); \
136 : : for (i = 1; i < TD_FIELD_INVALID; i++) \
137 : : fprintf(stderr, " | %s", td_vdi_fields[i].name); \
138 : : fprintf(stderr, " }\n"); \
139 : : } while (0)
140 : :
141 : : void
142 : 0 : help(void)
143 : : {
144 : 0 : fprintf(stderr, "Tapdisk Utilities: v1.0.0\n");
145 : 0 : fprintf(stderr, "usage: td-util COMMAND [TYPE] [OPTIONS]\n");
146 : 0 : print_commands();
147 : 0 : print_disk_types();
148 : 0 : exit(-1);
149 : : }
150 : :
151 : : struct command *
152 : 0 : get_command(char *command)
153 : : {
154 : : int i;
155 : :
156 : 0 : for (i = 0; i < TD_CMD_INVALID; i++)
157 : 0 : if (!strcmp(command, commands[i].name))
158 : 0 : return &commands[i];
159 : :
160 : : return NULL;
161 : : }
162 : :
163 : : struct vdi_field *
164 : 0 : get_field(char *field)
165 : : {
166 : : int i;
167 : :
168 : 0 : for (i = 0; i < TD_FIELD_INVALID; i++)
169 : 0 : if (!strcmp(field, td_vdi_fields[i].name))
170 : 0 : return &td_vdi_fields[i];
171 : :
172 : : return NULL;
173 : : }
174 : :
175 : : int
176 : 0 : get_driver_type(char *type)
177 : : {
178 : : int i;
179 : :
180 : 0 : if (strnlen(type, 25) >= 25)
181 : : return -ENAMETOOLONG;
182 : :
183 : 0 : for (i = 0; i < TD_TYPE_INVALID; i++)
184 : 0 : if (!strcmp(type, td_disk_types[i]))
185 : : return i;
186 : :
187 : : return -TD_TYPE_INVALID;
188 : : }
189 : :
190 : : int
191 : 0 : td_create(int type, int argc, char *argv[])
192 : : {
193 : : ssize_t mb;
194 : : uint64_t size;
195 : : char *name, *buf;
196 : 0 : int c, i, fd, sparse = 1, fixedsize = 0;
197 : :
198 : 0 : while ((c = getopt(argc, argv, "hrb")) != -1) {
199 : 0 : switch(c) {
200 : : case 'r':
201 : : sparse = 0;
202 : : break;
203 : : case 'b':
204 : 0 : fixedsize = 1;
205 : 0 : break;
206 : : default:
207 : 0 : fprintf(stderr, "Unknown option %c\n", (char)c);
208 : : case 'h':
209 : : goto usage;
210 : : }
211 : : }
212 : :
213 : 0 : if (optind != (argc - 2))
214 : : goto usage;
215 : :
216 : 0 : mb = 1 << 20;
217 : 0 : size = atoi(argv[optind++]);
218 : 0 : size = size << 20;
219 : 0 : name = argv[optind];
220 : :
221 : 0 : if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
222 : 0 : fprintf(stderr, "Device name too long\n");
223 : 0 : return ENAMETOOLONG;
224 : : }
225 : :
226 : 0 : if (type == TD_TYPE_VHD) {
227 : 0 : int cargc = 0;
228 : : char sbuf[32], *cargv[10];
229 : :
230 : 0 : size >>= 20;
231 : :
232 : : memset(cargv, 0, sizeof(cargv));
233 : : snprintf(sbuf, sizeof(sbuf) - 1, "%"PRIu64, size);
234 : 0 : cargv[cargc++] = "create";
235 : 0 : cargv[cargc++] = "-n";
236 : 0 : cargv[cargc++] = name;
237 : 0 : cargv[cargc++] = "-s";
238 : 0 : cargv[cargc++] = sbuf;
239 : 0 : if (!sparse)
240 : 0 : cargv[cargc++] = "-r";
241 : 0 : if (fixedsize)
242 : 0 : cargv[cargc++] = "-b";
243 : :
244 : 0 : return vhd_util_create(cargc, cargv);
245 : : }
246 : :
247 : : /* generic create */
248 : 0 : if (sparse) {
249 : 0 : fprintf(stderr, "Cannot create sparse %s image\n",
250 : : td_disk_types[type]);
251 : 0 : return EINVAL;
252 : : }
253 : :
254 : 0 : buf = calloc(1, mb);
255 : 0 : if (!buf)
256 : : return ENOMEM;
257 : :
258 : 0 : fd = open(name, O_WRONLY | O_DIRECT | O_CREAT | O_TRUNC, 0644);
259 : 0 : if (fd == -1) {
260 : 0 : free(buf);
261 : 0 : return errno;
262 : : }
263 : :
264 : 0 : size >>= 20;
265 : 0 : for (i = 0; i < size; i++)
266 : 0 : if (write(fd, buf, mb) != mb) {
267 : 0 : close(fd);
268 : 0 : unlink(name);
269 : 0 : free(buf);
270 : 0 : return EIO;
271 : : }
272 : :
273 : 0 : close(fd);
274 : 0 : free(buf);
275 : 0 : return 0;
276 : :
277 : : usage:
278 : 0 : fprintf(stderr, "usage: td-util create %s [-h help] [-r reserve] "
279 : : "[-b file_is_fixed_size] <SIZE(MB)> <FILENAME>\n",
280 : : td_disk_types[type]);
281 : 0 : return EINVAL;
282 : : }
283 : :
284 : : int
285 : 0 : td_snapshot(int type, int argc, char *argv[])
286 : : {
287 : : char *cargv[10];
288 : : int c, err, cargc;
289 : : struct stat stats;
290 : 0 : char *name, *backing, *limit = NULL;
291 : 0 : int fixedsize = 0, rawparent = 0;
292 : :
293 : 0 : if (type != TD_TYPE_VHD) {
294 : 0 : fprintf(stderr, "Cannot create snapshot of %s image type\n",
295 : : td_disk_types[type]);
296 : 0 : return EINVAL;
297 : : }
298 : :
299 : 0 : while ((c = getopt(argc, argv, "hbml:")) != -1) {
300 : 0 : switch(c) {
301 : : case 'b':
302 : : fixedsize = 1;
303 : : break;
304 : : case 'm':
305 : 0 : rawparent = 1;
306 : 0 : break;
307 : : case 'l':
308 : 0 : limit = optarg;
309 : 0 : break;
310 : : case 'h':
311 : : err = 0;
312 : : goto usage;
313 : : default:
314 : 0 : err = EINVAL;
315 : 0 : goto usage;
316 : : }
317 : : }
318 : :
319 : 0 : if (optind != (argc - 2)) {
320 : : err = EINVAL;
321 : : goto usage;
322 : : }
323 : :
324 : 0 : name = argv[optind++];
325 : 0 : backing = argv[optind++];
326 : :
327 : 0 : if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN ||
328 : 0 : strnlen(backing, MAX_NAME_LEN) == MAX_NAME_LEN) {
329 : 0 : fprintf(stderr, "Device name too long\n");
330 : : return ENAMETOOLONG;
331 : : }
332 : :
333 : 0 : if (stat(backing, &stats) == -1) {
334 : 0 : fprintf(stderr, "File %s not found\n", backing);
335 : 0 : return errno;
336 : : }
337 : :
338 : 0 : cargc = 0;
339 : : memset(cargv, 0, sizeof(cargv));
340 : 0 : cargv[cargc++] = "snapshot";
341 : 0 : cargv[cargc++] = "-n";
342 : 0 : cargv[cargc++] = name;
343 : 0 : cargv[cargc++] = "-p";
344 : 0 : cargv[cargc++] = backing;
345 : 0 : if (fixedsize)
346 : 0 : cargv[cargc++] = "-b";
347 : 0 : if (rawparent)
348 : 0 : cargv[cargc++] = "-m";
349 : 0 : if (limit) {
350 : 0 : cargv[cargc++] = "-l";
351 : 0 : cargv[cargc++] = limit;
352 : : }
353 : 0 : return vhd_util_snapshot(cargc, cargv);
354 : :
355 : : usage:
356 : 0 : fprintf(stderr, "usage: td-util snapshot %s [-h help] [-m parent_raw] "
357 : : "[-b file_is_fixed_size] [-l snapshot depth limit] "
358 : : "<FILENAME> <BACKING_FILENAME>\n", td_disk_types[type]);
359 : : return err;
360 : : }
361 : :
362 : : int
363 : 0 : td_coalesce(int type, int argc, char *argv[])
364 : : {
365 : : int c, ret, cargc;
366 : : char *name, *cargv[3];
367 : :
368 : 0 : if (type != TD_TYPE_VHD) {
369 : 0 : fprintf(stderr, "Cannot create snapshot of %s image type\n",
370 : : td_disk_types[type]);
371 : 0 : return EINVAL;
372 : : }
373 : :
374 : 0 : while ((c = getopt(argc, argv, "h")) != -1) {
375 : 0 : switch(c) {
376 : : default:
377 : 0 : fprintf(stderr, "Unknown option %c\n", (char)c);
378 : : case 'h':
379 : : goto usage;
380 : : }
381 : : }
382 : :
383 : 0 : if (optind != (argc - 1))
384 : : goto usage;
385 : :
386 : 0 : name = argv[optind++];
387 : :
388 : 0 : if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
389 : 0 : fprintf(stderr, "Device name too long\n");
390 : : return ENAMETOOLONG;
391 : : }
392 : :
393 : 0 : cargc = 0;
394 : : memset(cargv, 0, sizeof(cargv));
395 : 0 : cargv[cargc++] = "coalesce";
396 : 0 : cargv[cargc++] = "-n";
397 : 0 : cargv[cargc++] = name;
398 : 0 : ret = vhd_util_coalesce(cargc, cargv);
399 : 0 : if (ret)
400 : : printf("coalesce failed: %d\n", ret);
401 : :
402 : 0 : return ret;
403 : :
404 : : usage:
405 : 0 : fprintf(stderr, "usage: td-util coalesce %s [-h help] "
406 : : "<FILENAME>\n", td_disk_types[type]);
407 : : return EINVAL;
408 : : }
409 : :
410 : : int
411 : 0 : td_query(int type, int argc, char *argv[])
412 : : {
413 : : char *name;
414 : 0 : int c, size = 0, parent = 0, fields = 0, depth = 0, err = 0;
415 : 0 : int flags = VHD_OPEN_RDONLY;
416 : :
417 : 0 : while ((c = getopt(argc, argv, "hvpfdb")) != -1) {
418 : 0 : switch(c) {
419 : : case 'v':
420 : : size = 1;
421 : : break;
422 : : case 'p':
423 : 0 : parent = 1;
424 : 0 : break;
425 : : case 'f':
426 : 0 : fields = 1;
427 : 0 : break;
428 : : case 'd':
429 : 0 : depth = 1;
430 : 0 : break;
431 : : case 'h':
432 : : err = 0;
433 : : goto usage;
434 : : case 'b':
435 : 0 : flags |= VHD_OPEN_USE_BKP_FOOTER;
436 : 0 : break;
437 : : default:
438 : 0 : err = EINVAL;
439 : 0 : goto usage;
440 : : }
441 : : }
442 : :
443 : 0 : if (optind != (argc - 1)) {
444 : : err = EINVAL;
445 : : goto usage;
446 : : }
447 : :
448 : 0 : name = argv[optind++];
449 : :
450 : 0 : if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
451 : 0 : fprintf(stderr, "Device name too long\n");
452 : 0 : return ENAMETOOLONG;
453 : : }
454 : :
455 : 0 : if (type == TD_TYPE_VHD) {
456 : : vhd_context_t vhd;
457 : :
458 : 0 : err = vhd_open(&vhd, name, flags);
459 : 0 : if (err) {
460 : : printf("failed opening %s: %d\n", name, err);
461 : 0 : return err;
462 : : }
463 : :
464 : 0 : if (size)
465 : 0 : printf("%"PRIu64"\n", vhd.footer.curr_size >> 20);
466 : :
467 : 0 : if (parent) {
468 : 0 : if (vhd.footer.type != HD_TYPE_DIFF)
469 : : printf("%s has no parent\n", name);
470 : : else {
471 : : char *pname;
472 : :
473 : 0 : err = vhd_parent_locator_get(&vhd, &pname);
474 : 0 : if (err)
475 : : printf("failed getting parent: %d\n",
476 : : err);
477 : : else {
478 : 0 : printf("%s\n", pname);
479 : 0 : free(pname);
480 : : }
481 : : }
482 : : }
483 : :
484 : 0 : if (fields) {
485 : : int ret, hidden;
486 : :
487 : 0 : ret = vhd_hidden(&vhd, &hidden);
488 : 0 : if (ret) {
489 : : printf("failed checking 'hidden' field: %d\n",
490 : : ret);
491 : 0 : err = (err ? : ret);
492 : : } else
493 : 0 : printf("%s: %d\n",
494 : : td_vdi_fields[TD_FIELD_HIDDEN].name,
495 : : hidden);
496 : : }
497 : :
498 : 0 : if (depth) {
499 : : int ret, length;
500 : :
501 : 0 : ret = vhd_chain_depth(&vhd, &length);
502 : 0 : if (ret)
503 : : printf("error checking chain depth: %d\n", ret);
504 : : else
505 : 0 : printf("chain depth: %d\n", length);
506 : :
507 : 0 : err = (err ? : ret);
508 : : }
509 : :
510 : 0 : vhd_close(&vhd);
511 : :
512 : 0 : } else if (type == TD_TYPE_AIO) {
513 : 0 : if (size) {
514 : : int fd;
515 : : uint64_t secs;
516 : : uint32_t ssize;
517 : :
518 : 0 : fd = open(name, O_RDONLY | O_LARGEFILE);
519 : 0 : if (fd == -1) {
520 : 0 : printf("failed opening %s: %d\n", name, errno);
521 : 0 : return -errno;
522 : : }
523 : :
524 : 0 : err = tapdisk_get_image_size(fd, &secs, &ssize);
525 : 0 : close(fd);
526 : :
527 : 0 : if (err) {
528 : : printf("failed getting size for %s: %d\n:",
529 : : name, err);
530 : : return err;
531 : : }
532 : :
533 : 0 : printf("%"PRIu64"\n", secs >> 11);
534 : : }
535 : :
536 : 0 : if (parent)
537 : : printf("%s has no parent\n", name);
538 : :
539 : 0 : if (fields) {
540 : : int i;
541 : :
542 : 0 : for (i = 0; i < TD_FIELD_INVALID; i++)
543 : 0 : printf("%s: 0\n", td_vdi_fields[i].name);
544 : : }
545 : : }
546 : :
547 : 0 : return err;
548 : :
549 : : usage:
550 : 0 : fprintf(stderr, "usage: td-util query %s [-h help] [-v virtsize] "
551 : : "[-p parent] [-f fields] [-b don't trust the footer, use the back-up "
552 : : "one instead] <FILENAME>\n", td_disk_types[type]);
553 : 0 : return err;
554 : : }
555 : :
556 : : int
557 : 0 : td_set_field(int type, int argc, char *argv[])
558 : : {
559 : : int c, cargc;
560 : : struct vdi_field *field;
561 : : char *name, *value, *cargv[7];
562 : :
563 : 0 : if (type != TD_TYPE_VHD) {
564 : 0 : fprintf(stderr, "Cannot set fields of %s images\n",
565 : : td_disk_types[type]);
566 : 0 : return EINVAL;
567 : : }
568 : :
569 : 0 : while ((c = getopt(argc, argv, "h")) != -1) {
570 : 0 : switch(c) {
571 : : default:
572 : 0 : fprintf(stderr, "Unknown option %c\n", (char)c);
573 : : case 'h':
574 : : goto usage;
575 : : }
576 : : }
577 : :
578 : 0 : if (optind != (argc - 3))
579 : : goto usage;
580 : :
581 : 0 : name = argv[optind++];
582 : :
583 : 0 : field = get_field(argv[optind]);
584 : 0 : if (!field || field->id != TD_FIELD_HIDDEN) {
585 : 0 : fprintf(stderr, "Invalid field %s\n", argv[optind]);
586 : : goto usage;
587 : : }
588 : :
589 : 0 : value = argv[++optind];
590 : :
591 : 0 : cargc = 0;
592 : : memset(cargv, 0, sizeof(cargv));
593 : 0 : cargv[cargc++] = "set";
594 : 0 : cargv[cargc++] = "-n";
595 : 0 : cargv[cargc++] = name;
596 : 0 : cargv[cargc++] = "-f";
597 : 0 : cargv[cargc++] = field->name;
598 : 0 : cargv[cargc++] = "-v";
599 : 0 : cargv[cargc++] = value;
600 : 0 : return vhd_util_set_field(cargc, cargv);
601 : :
602 : : usage:
603 : 0 : fprintf(stderr, "usage: td-util set %s [-h help] "
604 : : "<FILENAME> <FIELD> <VALUE>\n", td_disk_types[type]);
605 : 0 : print_field_names();
606 : : return EINVAL;
607 : : }
608 : :
609 : : int
610 : 0 : main(int argc, char *argv[])
611 : : {
612 : : char **cargv;
613 : : struct command *cmd;
614 : 0 : int cargc, i, type = -1, ret = 0;
615 : :
616 : : #ifdef CORE_DUMP
617 : : struct rlimit rlim;
618 : : rlim.rlim_cur = RLIM_INFINITY;
619 : : rlim.rlim_max = RLIM_INFINITY;
620 : : if (setrlimit(RLIMIT_CORE, &rlim) < 0)
621 : : fprintf(stderr, "setrlimit failed: %d\n", errno);
622 : : #endif
623 : :
624 : 0 : if (argc < 2)
625 : 0 : help();
626 : :
627 : 0 : cargc = argc - 1;
628 : 0 : cmd = get_command(argv[1]);
629 : 0 : if (!cmd) {
630 : 0 : fprintf(stderr, "invalid COMMAND %s\n", argv[1]);
631 : 0 : help();
632 : : }
633 : :
634 : 0 : if (cmd->needs_type) {
635 : 0 : if (argc < 3) {
636 : 0 : fprintf(stderr, "td-util %s requires a TYPE\n",
637 : : cmd->name);
638 : 0 : print_disk_types();
639 : 0 : exit(-1);
640 : : }
641 : :
642 : 0 : type = get_driver_type(argv[2]);
643 : 0 : if (type < 0) {
644 : 0 : fprintf(stderr, "invalid TYPE '%s'.\n", argv[2]);
645 : 0 : print_disk_types();
646 : 0 : exit(-1);
647 : : }
648 : 0 : --cargc;
649 : : }
650 : :
651 : 0 : cargv = malloc(sizeof(char *) * cargc);
652 : 0 : if (!cargv)
653 : 0 : exit(ENOMEM);
654 : :
655 : 0 : cargv[0] = cmd->name;
656 : 0 : for (i = 1; i < cargc; i++)
657 : 0 : cargv[i] = argv[i + (argc - cargc)];
658 : :
659 : 0 : switch(cmd->id) {
660 : : case TD_CMD_CREATE:
661 : 0 : ret = td_create(type, cargc, cargv);
662 : 0 : break;
663 : : case TD_CMD_SNAPSHOT:
664 : 0 : ret = td_snapshot(type, cargc, cargv);
665 : 0 : break;
666 : : /*
667 : : case TD_CMD_COALESCE:
668 : : ret = td_coalesce(type, cargc, cargv);
669 : : break;
670 : : */
671 : : case TD_CMD_QUERY:
672 : 0 : ret = td_query(type, cargc, cargv);
673 : 0 : break;
674 : : /*
675 : : case TD_CMD_RESIZE:
676 : : ret = td_resize(type, cargc, cargv);
677 : : break;
678 : : */
679 : : case TD_CMD_SET:
680 : 0 : ret = td_set_field(type, cargc, cargv);
681 : 0 : break;
682 : : /*
683 : : case TD_CMD_REPAIR:
684 : : ret = td_repair(type, cargc, cargv);
685 : : break;
686 : : case TD_CMD_FILL:
687 : : ret = td_fill(type, cargc, cargv);
688 : : break;
689 : : case TD_CMD_READ:
690 : : ret = td_read(type, cargc, cargv);
691 : : break;
692 : : */
693 : : default:
694 : : case TD_CMD_INVALID:
695 : : ret = EINVAL;
696 : : break;
697 : : }
698 : :
699 : 0 : free(cargv);
700 : :
701 : 0 : return (ret >= 0 ? ret : -ret);
702 : : }
|