debuggers.hg

view tools/blktap2/drivers/td.c @ 22848:6341fe0f4e5a

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