root / drivers / td.c @ abdb293f
History | View | Annotate | Download (14.4 kB)
1 |
/*
|
---|---|
2 |
* Copyright (c) 2007, XenSource Inc.
|
3 |
* Copyright (c) 2010, Citrix Systems, Inc.
|
4 |
*
|
5 |
* All rights reserved.
|
6 |
*
|
7 |
* Redistribution and use in source and binary forms, with or without
|
8 |
* modification, are permitted provided that the following conditions are met:
|
9 |
* * Redistributions of source code must retain the above copyright
|
10 |
* notice, this list of conditions and the following disclaimer.
|
11 |
* * 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 |
* * Neither the name of XenSource Inc. nor the names of its contributors
|
15 |
* may be used to endorse or promote products derived from this software
|
16 |
* 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 |
help(void)
|
143 |
{ |
144 |
fprintf(stderr, "Tapdisk Utilities: v1.0.0\n");
|
145 |
fprintf(stderr, "usage: td-util COMMAND [TYPE] [OPTIONS]\n");
|
146 |
print_commands(); |
147 |
print_disk_types(); |
148 |
exit(-1);
|
149 |
} |
150 |
|
151 |
struct command *
|
152 |
get_command(char *command)
|
153 |
{ |
154 |
int i;
|
155 |
|
156 |
for (i = 0; i < TD_CMD_INVALID; i++) |
157 |
if (!strcmp(command, commands[i].name))
|
158 |
return &commands[i];
|
159 |
|
160 |
return NULL; |
161 |
} |
162 |
|
163 |
struct vdi_field *
|
164 |
get_field(char *field)
|
165 |
{ |
166 |
int i;
|
167 |
|
168 |
for (i = 0; i < TD_FIELD_INVALID; i++) |
169 |
if (!strcmp(field, td_vdi_fields[i].name))
|
170 |
return &td_vdi_fields[i];
|
171 |
|
172 |
return NULL; |
173 |
} |
174 |
|
175 |
int
|
176 |
get_driver_type(char *type)
|
177 |
{ |
178 |
int i;
|
179 |
|
180 |
if (strnlen(type, 25) >= 25) |
181 |
return -ENAMETOOLONG;
|
182 |
|
183 |
for (i = 0; i < TD_TYPE_INVALID; i++) |
184 |
if (!strcmp(type, td_disk_types[i]))
|
185 |
return i;
|
186 |
|
187 |
return -TD_TYPE_INVALID;
|
188 |
} |
189 |
|
190 |
int
|
191 |
td_create(int type, int argc, char *argv[]) |
192 |
{ |
193 |
ssize_t mb; |
194 |
uint64_t size; |
195 |
char *name, *buf;
|
196 |
int c, i, fd, sparse = 1, fixedsize = 0; |
197 |
|
198 |
while ((c = getopt(argc, argv, "hrb")) != -1) { |
199 |
switch(c) {
|
200 |
case 'r': |
201 |
sparse = 0;
|
202 |
break;
|
203 |
case 'b': |
204 |
fixedsize = 1;
|
205 |
break;
|
206 |
default:
|
207 |
fprintf(stderr, "Unknown option %c\n", (char)c); |
208 |
case 'h': |
209 |
goto usage;
|
210 |
} |
211 |
} |
212 |
|
213 |
if (optind != (argc - 2)) |
214 |
goto usage;
|
215 |
|
216 |
mb = 1 << 20; |
217 |
size = atoi(argv[optind++]); |
218 |
size = size << 20;
|
219 |
name = argv[optind]; |
220 |
|
221 |
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
|
222 |
fprintf(stderr, "Device name too long\n");
|
223 |
return ENAMETOOLONG;
|
224 |
} |
225 |
|
226 |
if (type == TD_TYPE_VHD) {
|
227 |
int cargc = 0; |
228 |
char sbuf[32], *cargv[10]; |
229 |
|
230 |
size >>= 20;
|
231 |
|
232 |
memset(cargv, 0, sizeof(cargv)); |
233 |
snprintf(sbuf, sizeof(sbuf) - 1, "%"PRIu64, size); |
234 |
cargv[cargc++] = "create";
|
235 |
cargv[cargc++] = "-n";
|
236 |
cargv[cargc++] = name; |
237 |
cargv[cargc++] = "-s";
|
238 |
cargv[cargc++] = sbuf; |
239 |
if (!sparse)
|
240 |
cargv[cargc++] = "-r";
|
241 |
if (fixedsize)
|
242 |
cargv[cargc++] = "-b";
|
243 |
|
244 |
return vhd_util_create(cargc, cargv);
|
245 |
} |
246 |
|
247 |
/* generic create */
|
248 |
if (sparse) {
|
249 |
fprintf(stderr, "Cannot create sparse %s image\n",
|
250 |
td_disk_types[type]); |
251 |
return EINVAL;
|
252 |
} |
253 |
|
254 |
buf = calloc(1, mb);
|
255 |
if (!buf)
|
256 |
return ENOMEM;
|
257 |
|
258 |
fd = open(name, O_WRONLY | O_DIRECT | O_CREAT | O_TRUNC, 0644);
|
259 |
if (fd == -1) { |
260 |
free(buf); |
261 |
return errno;
|
262 |
} |
263 |
|
264 |
size >>= 20;
|
265 |
for (i = 0; i < size; i++) |
266 |
if (write(fd, buf, mb) != mb) {
|
267 |
close(fd); |
268 |
unlink(name); |
269 |
free(buf); |
270 |
return EIO;
|
271 |
} |
272 |
|
273 |
close(fd); |
274 |
free(buf); |
275 |
return 0; |
276 |
|
277 |
usage:
|
278 |
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 |
return EINVAL;
|
282 |
} |
283 |
|
284 |
int
|
285 |
td_snapshot(int type, int argc, char *argv[]) |
286 |
{ |
287 |
char *cargv[10]; |
288 |
int c, err, cargc;
|
289 |
struct stat stats;
|
290 |
char *name, *backing, *limit = NULL; |
291 |
int fixedsize = 0, rawparent = 0; |
292 |
|
293 |
if (type != TD_TYPE_VHD) {
|
294 |
fprintf(stderr, "Cannot create snapshot of %s image type\n",
|
295 |
td_disk_types[type]); |
296 |
return EINVAL;
|
297 |
} |
298 |
|
299 |
while ((c = getopt(argc, argv, "hbml:")) != -1) { |
300 |
switch(c) {
|
301 |
case 'b': |
302 |
fixedsize = 1;
|
303 |
break;
|
304 |
case 'm': |
305 |
rawparent = 1;
|
306 |
break;
|
307 |
case 'l': |
308 |
limit = optarg; |
309 |
break;
|
310 |
case 'h': |
311 |
err = 0;
|
312 |
goto usage;
|
313 |
default:
|
314 |
err = EINVAL; |
315 |
goto usage;
|
316 |
} |
317 |
} |
318 |
|
319 |
if (optind != (argc - 2)) { |
320 |
err = EINVAL; |
321 |
goto usage;
|
322 |
} |
323 |
|
324 |
name = argv[optind++]; |
325 |
backing = argv[optind++]; |
326 |
|
327 |
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN ||
|
328 |
strnlen(backing, MAX_NAME_LEN) == MAX_NAME_LEN) { |
329 |
fprintf(stderr, "Device name too long\n");
|
330 |
return ENAMETOOLONG;
|
331 |
} |
332 |
|
333 |
if (stat(backing, &stats) == -1) { |
334 |
fprintf(stderr, "File %s not found\n", backing);
|
335 |
return errno;
|
336 |
} |
337 |
|
338 |
cargc = 0;
|
339 |
memset(cargv, 0, sizeof(cargv)); |
340 |
cargv[cargc++] = "snapshot";
|
341 |
cargv[cargc++] = "-n";
|
342 |
cargv[cargc++] = name; |
343 |
cargv[cargc++] = "-p";
|
344 |
cargv[cargc++] = backing; |
345 |
if (fixedsize)
|
346 |
cargv[cargc++] = "-b";
|
347 |
if (rawparent)
|
348 |
cargv[cargc++] = "-m";
|
349 |
if (limit) {
|
350 |
cargv[cargc++] = "-l";
|
351 |
cargv[cargc++] = limit; |
352 |
} |
353 |
return vhd_util_snapshot(cargc, cargv);
|
354 |
|
355 |
usage:
|
356 |
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 |
td_coalesce(int type, int argc, char *argv[]) |
364 |
{ |
365 |
int c, ret, cargc;
|
366 |
char *name, *cargv[3]; |
367 |
|
368 |
if (type != TD_TYPE_VHD) {
|
369 |
fprintf(stderr, "Cannot create snapshot of %s image type\n",
|
370 |
td_disk_types[type]); |
371 |
return EINVAL;
|
372 |
} |
373 |
|
374 |
while ((c = getopt(argc, argv, "h")) != -1) { |
375 |
switch(c) {
|
376 |
default:
|
377 |
fprintf(stderr, "Unknown option %c\n", (char)c); |
378 |
case 'h': |
379 |
goto usage;
|
380 |
} |
381 |
} |
382 |
|
383 |
if (optind != (argc - 1)) |
384 |
goto usage;
|
385 |
|
386 |
name = argv[optind++]; |
387 |
|
388 |
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
|
389 |
fprintf(stderr, "Device name too long\n");
|
390 |
return ENAMETOOLONG;
|
391 |
} |
392 |
|
393 |
cargc = 0;
|
394 |
memset(cargv, 0, sizeof(cargv)); |
395 |
cargv[cargc++] = "coalesce";
|
396 |
cargv[cargc++] = "-n";
|
397 |
cargv[cargc++] = name; |
398 |
ret = vhd_util_coalesce(cargc, cargv); |
399 |
if (ret)
|
400 |
printf("coalesce failed: %d\n", ret);
|
401 |
|
402 |
return ret;
|
403 |
|
404 |
usage:
|
405 |
fprintf(stderr, "usage: td-util coalesce %s [-h help] "
|
406 |
"<FILENAME>\n", td_disk_types[type]);
|
407 |
return EINVAL;
|
408 |
} |
409 |
|
410 |
int
|
411 |
td_query(int type, int argc, char *argv[]) |
412 |
{ |
413 |
char *name;
|
414 |
int c, size = 0, parent = 0, fields = 0, depth = 0, err = 0; |
415 |
|
416 |
while ((c = getopt(argc, argv, "hvpfd")) != -1) { |
417 |
switch(c) {
|
418 |
case 'v': |
419 |
size = 1;
|
420 |
break;
|
421 |
case 'p': |
422 |
parent = 1;
|
423 |
break;
|
424 |
case 'f': |
425 |
fields = 1;
|
426 |
break;
|
427 |
case 'd': |
428 |
depth = 1;
|
429 |
break;
|
430 |
case 'h': |
431 |
err = 0;
|
432 |
goto usage;
|
433 |
default:
|
434 |
err = EINVAL; |
435 |
goto usage;
|
436 |
} |
437 |
} |
438 |
|
439 |
if (optind != (argc - 1)) { |
440 |
err = EINVAL; |
441 |
goto usage;
|
442 |
} |
443 |
|
444 |
name = argv[optind++]; |
445 |
|
446 |
if (strnlen(name, MAX_NAME_LEN) == MAX_NAME_LEN) {
|
447 |
fprintf(stderr, "Device name too long\n");
|
448 |
return ENAMETOOLONG;
|
449 |
} |
450 |
|
451 |
if (type == TD_TYPE_VHD) {
|
452 |
vhd_context_t vhd; |
453 |
|
454 |
err = vhd_open(&vhd, name, VHD_OPEN_RDONLY); |
455 |
if (err) {
|
456 |
printf("failed opening %s: %d\n", name, err);
|
457 |
return err;
|
458 |
} |
459 |
|
460 |
if (size)
|
461 |
printf("%"PRIu64"\n", vhd.footer.curr_size >> 20); |
462 |
|
463 |
if (parent) {
|
464 |
if (vhd.footer.type != HD_TYPE_DIFF)
|
465 |
printf("%s has no parent\n", name);
|
466 |
else {
|
467 |
char *pname;
|
468 |
|
469 |
err = vhd_parent_locator_get(&vhd, &pname); |
470 |
if (err)
|
471 |
printf("failed getting parent: %d\n",
|
472 |
err); |
473 |
else {
|
474 |
printf("%s\n", pname);
|
475 |
free(pname); |
476 |
} |
477 |
} |
478 |
} |
479 |
|
480 |
if (fields) {
|
481 |
int ret, hidden;
|
482 |
|
483 |
ret = vhd_hidden(&vhd, &hidden); |
484 |
if (ret) {
|
485 |
printf("failed checking 'hidden' field: %d\n",
|
486 |
ret); |
487 |
err = (err ? : ret); |
488 |
} else
|
489 |
printf("%s: %d\n",
|
490 |
td_vdi_fields[TD_FIELD_HIDDEN].name, |
491 |
hidden); |
492 |
} |
493 |
|
494 |
if (depth) {
|
495 |
int ret, length;
|
496 |
|
497 |
ret = vhd_chain_depth(&vhd, &length); |
498 |
if (ret)
|
499 |
printf("error checking chain depth: %d\n", ret);
|
500 |
else
|
501 |
printf("chain depth: %d\n", length);
|
502 |
|
503 |
err = (err ? : ret); |
504 |
} |
505 |
|
506 |
vhd_close(&vhd); |
507 |
|
508 |
} else if (type == TD_TYPE_AIO) { |
509 |
if (size) {
|
510 |
int fd;
|
511 |
uint64_t secs; |
512 |
uint32_t ssize; |
513 |
|
514 |
fd = open(name, O_RDONLY | O_LARGEFILE); |
515 |
if (fd == -1) { |
516 |
printf("failed opening %s: %d\n", name, errno);
|
517 |
return -errno;
|
518 |
} |
519 |
|
520 |
err = tapdisk_get_image_size(fd, &secs, &ssize); |
521 |
close(fd); |
522 |
|
523 |
if (err) {
|
524 |
printf("failed getting size for %s: %d\n:",
|
525 |
name, err); |
526 |
return err;
|
527 |
} |
528 |
|
529 |
printf("%"PRIu64"\n", secs >> 11); |
530 |
} |
531 |
|
532 |
if (parent)
|
533 |
printf("%s has no parent\n", name);
|
534 |
|
535 |
if (fields) {
|
536 |
int i;
|
537 |
|
538 |
for (i = 0; i < TD_FIELD_INVALID; i++) |
539 |
printf("%s: 0\n", td_vdi_fields[i].name);
|
540 |
} |
541 |
} |
542 |
|
543 |
return err;
|
544 |
|
545 |
usage:
|
546 |
fprintf(stderr, "usage: td-util query %s [-h help] [-v virtsize] "
|
547 |
"[-p parent] [-f fields] <FILENAME>\n", td_disk_types[type]);
|
548 |
return err;
|
549 |
} |
550 |
|
551 |
int
|
552 |
td_set_field(int type, int argc, char *argv[]) |
553 |
{ |
554 |
int c, cargc;
|
555 |
struct vdi_field *field;
|
556 |
char *name, *value, *cargv[7]; |
557 |
|
558 |
if (type != TD_TYPE_VHD) {
|
559 |
fprintf(stderr, "Cannot set fields of %s images\n",
|
560 |
td_disk_types[type]); |
561 |
return EINVAL;
|
562 |
} |
563 |
|
564 |
while ((c = getopt(argc, argv, "h")) != -1) { |
565 |
switch(c) {
|
566 |
default:
|
567 |
fprintf(stderr, "Unknown option %c\n", (char)c); |
568 |
case 'h': |
569 |
goto usage;
|
570 |
} |
571 |
} |
572 |
|
573 |
if (optind != (argc - 3)) |
574 |
goto usage;
|
575 |
|
576 |
name = argv[optind++]; |
577 |
|
578 |
field = get_field(argv[optind]); |
579 |
if (!field || field->id != TD_FIELD_HIDDEN) {
|
580 |
fprintf(stderr, "Invalid field %s\n", argv[optind]);
|
581 |
goto usage;
|
582 |
} |
583 |
|
584 |
value = argv[++optind]; |
585 |
|
586 |
cargc = 0;
|
587 |
memset(cargv, 0, sizeof(cargv)); |
588 |
cargv[cargc++] = "set";
|
589 |
cargv[cargc++] = "-n";
|
590 |
cargv[cargc++] = name; |
591 |
cargv[cargc++] = "-f";
|
592 |
cargv[cargc++] = field->name; |
593 |
cargv[cargc++] = "-v";
|
594 |
cargv[cargc++] = value; |
595 |
return vhd_util_set_field(cargc, cargv);
|
596 |
|
597 |
usage:
|
598 |
fprintf(stderr, "usage: td-util set %s [-h help] "
|
599 |
"<FILENAME> <FIELD> <VALUE>\n", td_disk_types[type]);
|
600 |
print_field_names(); |
601 |
return EINVAL;
|
602 |
} |
603 |
|
604 |
int
|
605 |
main(int argc, char *argv[]) |
606 |
{ |
607 |
char **cargv;
|
608 |
struct command *cmd;
|
609 |
int cargc, i, type = -1, ret = 0; |
610 |
|
611 |
#ifdef CORE_DUMP
|
612 |
struct rlimit rlim;
|
613 |
rlim.rlim_cur = RLIM_INFINITY; |
614 |
rlim.rlim_max = RLIM_INFINITY; |
615 |
if (setrlimit(RLIMIT_CORE, &rlim) < 0) |
616 |
fprintf(stderr, "setrlimit failed: %d\n", errno);
|
617 |
#endif
|
618 |
|
619 |
if (argc < 2) |
620 |
help(); |
621 |
|
622 |
cargc = argc - 1;
|
623 |
cmd = get_command(argv[1]);
|
624 |
if (!cmd) {
|
625 |
fprintf(stderr, "invalid COMMAND %s\n", argv[1]); |
626 |
help(); |
627 |
} |
628 |
|
629 |
if (cmd->needs_type) {
|
630 |
if (argc < 3) { |
631 |
fprintf(stderr, "td-util %s requires a TYPE\n",
|
632 |
cmd->name); |
633 |
print_disk_types(); |
634 |
exit(-1);
|
635 |
} |
636 |
|
637 |
type = get_driver_type(argv[2]);
|
638 |
if (type < 0) { |
639 |
fprintf(stderr, "invalid TYPE '%s'.\n", argv[2]); |
640 |
print_disk_types(); |
641 |
exit(-1);
|
642 |
} |
643 |
--cargc; |
644 |
} |
645 |
|
646 |
cargv = malloc(sizeof(char *) * cargc); |
647 |
if (!cargv)
|
648 |
exit(ENOMEM); |
649 |
|
650 |
cargv[0] = cmd->name;
|
651 |
for (i = 1; i < cargc; i++) |
652 |
cargv[i] = argv[i + (argc - cargc)]; |
653 |
|
654 |
switch(cmd->id) {
|
655 |
case TD_CMD_CREATE:
|
656 |
ret = td_create(type, cargc, cargv); |
657 |
break;
|
658 |
case TD_CMD_SNAPSHOT:
|
659 |
ret = td_snapshot(type, cargc, cargv); |
660 |
break;
|
661 |
/*
|
662 |
case TD_CMD_COALESCE:
|
663 |
ret = td_coalesce(type, cargc, cargv);
|
664 |
break;
|
665 |
*/
|
666 |
case TD_CMD_QUERY:
|
667 |
ret = td_query(type, cargc, cargv); |
668 |
break;
|
669 |
/*
|
670 |
case TD_CMD_RESIZE:
|
671 |
ret = td_resize(type, cargc, cargv);
|
672 |
break;
|
673 |
*/
|
674 |
case TD_CMD_SET:
|
675 |
ret = td_set_field(type, cargc, cargv); |
676 |
break;
|
677 |
/*
|
678 |
case TD_CMD_REPAIR:
|
679 |
ret = td_repair(type, cargc, cargv);
|
680 |
break;
|
681 |
case TD_CMD_FILL:
|
682 |
ret = td_fill(type, cargc, cargv);
|
683 |
break;
|
684 |
case TD_CMD_READ:
|
685 |
ret = td_read(type, cargc, cargv);
|
686 |
break;
|
687 |
*/
|
688 |
default:
|
689 |
case TD_CMD_INVALID:
|
690 |
ret = EINVAL; |
691 |
break;
|
692 |
} |
693 |
|
694 |
free(cargv); |
695 |
|
696 |
return (ret >= 0 ? ret : -ret); |
697 |
} |