ia64/xen-unstable

view tools/blktap2/vhd/lib/vhd-util-scan.c @ 19817:b7f73a7f3078

blktap2: portability fixes for NetBSD

- Use standard off_t and lseek() instead of non-portable off64_t and
lseek64()
- Use uuid API as documented in DCE 1.1 RPC specification
- Add NetBSD implementation for blk_getimagesize() and
blk_getsectorsize()
- Use blk_getimagesize() and blk_getsectorsize()
- Fix uuid header check

Signed-off-by: Christoph Egger <Christoph.Egger@amd.com>
Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Tue Jun 23 17:24:14 2009 +0100 (2009-06-23)
parents 1c627434605e
children
line source
1 /* Copyright (c) 2008, XenSource Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
6 * * Redistributions of source code must retain the above copyright
7 * notice, this list of conditions and the following disclaimer.
8 * * Redistributions in binary form must reproduce the above copyright
9 * notice, this list of conditions and the following disclaimer in the
10 * documentation and/or other materials provided with the distribution.
11 * * Neither the name of XenSource Inc. nor the names of its contributors
12 * may be used to endorse or promote products derived from this software
13 * without specific prior written permission.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
16 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
17 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
18 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
19 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
23 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
24 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
28 #include <glob.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34 #include <unistd.h>
35 #include <fnmatch.h>
36 #include <libgen.h> /* for basename() */
38 #include "list.h"
39 #include "libvhd.h"
40 #include "lvm-util.h"
42 #define VHD_SCAN_FAST 0x01
43 #define VHD_SCAN_PRETTY 0x02
44 #define VHD_SCAN_VOLUME 0x04
45 #define VHD_SCAN_NOFAIL 0x08
46 #define VHD_SCAN_VERBOSE 0x10
47 #define VHD_SCAN_PARENTS 0x20
49 #define VHD_TYPE_RAW_FILE 0x01
50 #define VHD_TYPE_VHD_FILE 0x02
51 #define VHD_TYPE_RAW_VOLUME 0x04
52 #define VHD_TYPE_VHD_VOLUME 0x08
54 static inline int
55 target_volume(uint8_t type)
56 {
57 return (type == VHD_TYPE_RAW_VOLUME || type == VHD_TYPE_VHD_VOLUME);
58 }
60 static inline int
61 target_vhd(uint8_t type)
62 {
63 return (type == VHD_TYPE_VHD_FILE || type == VHD_TYPE_VHD_VOLUME);
64 }
66 struct target {
67 char name[VHD_MAX_NAME_LEN];
68 char device[VHD_MAX_NAME_LEN];
69 uint64_t size;
70 uint64_t start;
71 uint64_t end;
72 uint8_t type;
73 };
75 struct iterator {
76 int cur;
77 int cur_size;
78 int max_size;
79 struct target *targets;
80 };
82 struct vhd_image {
83 char *name;
84 char *parent;
85 uint64_t capacity;
86 off_t size;
87 uint8_t hidden;
88 int error;
89 char *message;
91 struct target *target;
93 struct list_head sibling;
94 struct list_head children;
95 struct vhd_image *parent_image;
96 };
98 struct vhd_scan {
99 int cur;
100 int size;
102 int lists_cur;
103 int lists_size;
105 struct vhd_image **images;
106 struct vhd_image **lists;
107 };
109 static int flags;
110 static struct vg vg;
111 static struct vhd_scan scan;
113 static int
114 vhd_util_scan_pretty_allocate_list(int cnt)
115 {
116 int i;
117 struct vhd_image *list;
119 memset(&scan, 0, sizeof(scan));
121 scan.lists_cur = 1;
122 scan.lists_size = 10;
124 scan.lists = calloc(scan.lists_size, sizeof(struct vhd_image *));
125 if (!scan.lists)
126 goto fail;
128 scan.lists[0] = calloc(cnt, sizeof(struct vhd_image));
129 if (!scan.lists[0])
130 goto fail;
132 scan.images = calloc(cnt, sizeof(struct vhd_image *));
133 if (!scan.images)
134 goto fail;
136 for (i = 0; i < cnt; i++)
137 scan.images[i] = scan.lists[0] + i;
139 scan.cur = 0;
140 scan.size = cnt;
142 return 0;
144 fail:
145 if (scan.lists) {
146 free(scan.lists[0]);
147 free(scan.lists);
148 }
150 free(scan.images);
151 memset(&scan, 0, sizeof(scan));
152 return -ENOMEM;
153 }
155 static void
156 vhd_util_scan_pretty_free_list(void)
157 {
158 int i;
160 if (scan.lists) {
161 for (i = 0; i < scan.lists_cur; i++)
162 free(scan.lists[i]);
163 free(scan.lists);
164 }
166 free(scan.images);
167 memset(&scan, 0, sizeof(scan));
168 }
170 static int
171 vhd_util_scan_pretty_add_image(struct vhd_image *image)
172 {
173 int i;
174 struct vhd_image *img;
176 for (i = 0; i < scan.cur; i++) {
177 img = scan.images[i];
178 if (!strcmp(img->name, image->name))
179 return 0;
180 }
182 if (scan.cur >= scan.size) {
183 struct vhd_image *new, **list;
185 if (scan.lists_cur >= scan.lists_size) {
186 list = realloc(scan.lists, scan.lists_size * 2 *
187 sizeof(struct vhd_image *));
188 if (!list)
189 return -ENOMEM;
191 scan.lists_size *= 2;
192 scan.lists = list;
193 }
195 new = calloc(scan.size, sizeof(struct vhd_image));
196 if (!new)
197 return -ENOMEM;
199 scan.lists[scan.lists_cur++] = new;
200 scan.size *= 2;
202 list = realloc(scan.images, scan.size *
203 sizeof(struct vhd_image *));
204 if (!list)
205 return -ENOMEM;
207 scan.images = list;
208 for (i = 0; i + scan.cur < scan.size; i++)
209 scan.images[i + scan.cur] = new + i;
210 }
212 img = scan.images[scan.cur];
213 INIT_LIST_HEAD(&img->sibling);
214 INIT_LIST_HEAD(&img->children);
216 img->capacity = image->capacity;
217 img->size = image->size;
218 img->hidden = image->hidden;
219 img->error = image->error;
220 img->message = image->message;
222 img->name = strdup(image->name);
223 if (!img->name)
224 goto fail;
226 if (image->parent) {
227 img->parent = strdup(image->parent);
228 if (!img->parent)
229 goto fail;
230 }
232 scan.cur++;
233 return 0;
235 fail:
236 free(img->name);
237 free(img->parent);
238 memset(img, 0, sizeof(*img));
239 return -ENOMEM;
240 }
242 static int
243 vhd_util_scan_pretty_image_compare(const void *lhs, const void *rhs)
244 {
245 struct vhd_image *l, *r;
247 l = *(struct vhd_image **)lhs;
248 r = *(struct vhd_image **)rhs;
250 return strcmp(l->name, r->name);
251 }
253 static void
254 vhd_util_scan_print_image_indent(struct vhd_image *image, int tab)
255 {
256 char *pad, *name, *pmsg, *parent;
258 pad = (tab ? " " : "");
259 name = image->name;
260 parent = (image->parent ? : "none");
262 if ((flags & VHD_SCAN_PRETTY) && image->parent && !image->parent_image)
263 pmsg = " (not found in scan)";
264 else
265 pmsg = "";
267 if (!(flags & VHD_SCAN_VERBOSE)) {
268 name = basename(image->name);
269 if (image->parent)
270 parent = basename(image->parent);
271 }
273 if (image->error)
274 printf("%*svhd=%s scan-error=%d error-message='%s'\n",
275 tab, pad, image->name, image->error, image->message);
276 else
277 printf("%*svhd=%s capacity=%"PRIu64" size=%"PRIu64" hidden=%u "
278 "parent=%s%s\n", tab, pad, name, image->capacity,
279 image->size, image->hidden, parent, pmsg);
280 }
282 static void
283 vhd_util_scan_pretty_print_tree(struct vhd_image *image, int depth)
284 {
285 struct vhd_image *img, *tmp;
287 vhd_util_scan_print_image_indent(image, depth * 3);
289 list_for_each_entry_safe(img, tmp, &image->children, sibling)
290 if (!img->hidden)
291 vhd_util_scan_pretty_print_tree(img, depth + 1);
293 list_for_each_entry_safe(img, tmp, &image->children, sibling)
294 if (img->hidden)
295 vhd_util_scan_pretty_print_tree(img, depth + 1);
297 free(image->name);
298 free(image->parent);
300 image->name = NULL;
301 image->parent = NULL;
302 }
304 static void
305 vhd_util_scan_pretty_print_images(void)
306 {
307 int i;
308 struct vhd_image *image, **parentp, *parent, *keyp, key;
310 qsort(scan.images, scan.cur, sizeof(scan.images[0]),
311 vhd_util_scan_pretty_image_compare);
313 for (i = 0; i < scan.cur; i++) {
314 image = scan.images[i];
316 if (!image->parent) {
317 image->parent_image = NULL;
318 continue;
319 }
321 memset(&key, 0, sizeof(key));
322 key.name = image->parent;
323 keyp = &key;
325 parentp = bsearch(&keyp, scan.images, scan.cur,
326 sizeof(scan.images[0]),
327 vhd_util_scan_pretty_image_compare);
328 if (!parentp) {
329 image->parent_image = NULL;
330 continue;
331 }
333 parent = *parentp;
334 image->parent_image = parent;
335 list_add_tail(&image->sibling, &parent->children);
336 }
338 for (i = 0; i < scan.cur; i++) {
339 image = scan.images[i];
341 if (image->parent_image || !image->hidden)
342 continue;
344 vhd_util_scan_pretty_print_tree(image, 0);
345 }
347 for (i = 0; i < scan.cur; i++) {
348 image = scan.images[i];
350 if (!image->name || image->parent_image)
351 continue;
353 vhd_util_scan_pretty_print_tree(image, 0);
354 }
356 for (i = 0; i < scan.cur; i++) {
357 image = scan.images[i];
359 if (!image->name)
360 continue;
362 vhd_util_scan_pretty_print_tree(image, 0);
363 }
364 }
366 static void
367 vhd_util_scan_print_image(struct vhd_image *image)
368 {
369 int err;
371 if (!image->error && (flags & VHD_SCAN_PRETTY)) {
372 err = vhd_util_scan_pretty_add_image(image);
373 if (!err)
374 return;
376 if (!image->error) {
377 image->error = err;
378 image->message = "allocating memory";
379 }
380 }
382 vhd_util_scan_print_image_indent(image, 0);
383 }
385 static int
386 vhd_util_scan_error(const char *file, int err)
387 {
388 struct vhd_image image;
390 memset(&image, 0, sizeof(image));
391 image.name = (char *)file;
392 image.error = err;
393 image.message = "failure scanning target";
395 vhd_util_scan_print_image(&image);
397 /*
398 if (flags & VHD_SCAN_NOFAIL)
399 return 0;
400 */
402 return err;
403 }
405 static vhd_parent_locator_t *
406 vhd_util_scan_get_parent_locator(vhd_context_t *vhd)
407 {
408 int i;
409 vhd_parent_locator_t *loc;
411 loc = NULL;
413 for (i = 0; i < 8; i++) {
414 if (vhd->header.loc[i].code == PLAT_CODE_MACX) {
415 loc = vhd->header.loc + i;
416 break;
417 }
419 if (vhd->header.loc[i].code == PLAT_CODE_W2RU)
420 loc = vhd->header.loc + i;
422 if (!loc && vhd->header.loc[i].code != PLAT_CODE_NONE)
423 loc = vhd->header.loc + i;
424 }
426 return loc;
427 }
429 static inline int
430 copy_name(char *dst, const char *src)
431 {
432 if (snprintf(dst, VHD_MAX_NAME_LEN, "%s", src) < VHD_MAX_NAME_LEN)
433 return 0;
435 return -ENAMETOOLONG;
436 }
438 /*
439 * LVHD stores realpath(parent) in parent locators, so
440 * /dev/<vol-group>/<lv-name> becomes /dev/mapper/<vol--group>-<lv--name>
441 */
442 static int
443 vhd_util_scan_extract_volume_name(char *dst, const char *src)
444 {
445 int err;
446 char copy[VHD_MAX_NAME_LEN], *name, *s, *c;
448 name = strrchr(src, '/');
449 if (!name)
450 name = (char *)src;
452 /* convert single dashes to slashes, double dashes to single dashes */
453 for (c = copy, s = name; *s != '\0'; s++, c++) {
454 if (*s == '-') {
455 if (s[1] != '-')
456 *c = '/';
457 else {
458 s++;
459 *c = '-';
460 }
461 } else
462 *c = *s;
463 }
465 *c = '\0';
466 c = strrchr(copy, '/');
467 if (c == name) {
468 /* unrecognized format */
469 strcpy(dst, src);
470 return -EINVAL;
471 }
473 strcpy(dst, ++c);
474 return 0;
475 }
477 static int
478 vhd_util_scan_get_volume_parent(vhd_context_t *vhd, struct vhd_image *image)
479 {
480 int err;
481 char name[VHD_MAX_NAME_LEN];
482 vhd_parent_locator_t *loc, copy;
484 if (flags & VHD_SCAN_FAST) {
485 err = vhd_header_decode_parent(vhd,
486 &vhd->header, &image->parent);
487 if (!err)
488 goto found;
489 }
491 loc = vhd_util_scan_get_parent_locator(vhd);
492 if (!loc)
493 return -EINVAL;
495 copy = *loc;
496 copy.data_offset += image->target->start;
497 err = vhd_parent_locator_read(vhd, &copy, &image->parent);
498 if (err)
499 return err;
501 found:
502 err = vhd_util_scan_extract_volume_name(name, image->parent);
503 if (!err)
504 return copy_name(image->parent, name);
506 return 0;
507 }
509 static int
510 vhd_util_scan_get_parent(vhd_context_t *vhd, struct vhd_image *image)
511 {
512 int i, err;
513 vhd_parent_locator_t *loc;
515 if (!target_vhd(image->target->type)) {
516 image->parent = NULL;
517 return 0;
518 }
520 loc = NULL;
522 if (target_volume(image->target->type))
523 return vhd_util_scan_get_volume_parent(vhd, image);
525 if (flags & VHD_SCAN_FAST) {
526 err = vhd_header_decode_parent(vhd,
527 &vhd->header, &image->parent);
528 if (!err)
529 return 0;
530 } else {
531 /*
532 * vhd_parent_locator_get checks for the existence of the
533 * parent file. if this call succeeds, all is well; if not,
534 * we'll try to return whatever string we have before failing
535 * outright.
536 */
537 err = vhd_parent_locator_get(vhd, &image->parent);
538 if (!err)
539 return 0;
540 }
542 loc = vhd_util_scan_get_parent_locator(vhd);
543 if (!loc)
544 return -EINVAL;
546 return vhd_parent_locator_read(vhd, loc, &image->parent);
547 }
549 static int
550 vhd_util_scan_get_hidden(vhd_context_t *vhd, struct vhd_image *image)
551 {
552 int err, hidden;
554 err = 0;
555 hidden = 0;
557 if (target_vhd(image->target->type))
558 err = vhd_hidden(vhd, &hidden);
559 else
560 hidden = 1;
562 if (err)
563 return err;
565 image->hidden = hidden;
566 return 0;
567 }
569 static int
570 vhd_util_scan_get_size(vhd_context_t *vhd, struct vhd_image *image)
571 {
572 image->size = image->target->size;
574 if (target_vhd(image->target->type))
575 image->capacity = vhd->footer.curr_size;
576 else
577 image->capacity = image->size;
579 return 0;
580 }
582 static int
583 vhd_util_scan_open_file(vhd_context_t *vhd, struct vhd_image *image)
584 {
585 int err, vhd_flags;
587 if (!target_vhd(image->target->type))
588 return 0;
590 vhd_flags = VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED;
591 if (flags & VHD_SCAN_FAST)
592 vhd_flags |= VHD_OPEN_FAST;
594 err = vhd_open(vhd, image->name, vhd_flags);
595 if (err) {
596 vhd->file = NULL;
597 image->message = "opening file";
598 image->error = err;
599 return image->error;
600 }
602 return 0;
603 }
605 static int
606 vhd_util_scan_read_volume_headers(vhd_context_t *vhd, struct vhd_image *image)
607 {
608 int err;
609 char *buf;
610 size_t size;
611 struct target *target;
613 buf = NULL;
614 target = image->target;
615 size = sizeof(vhd_footer_t) + sizeof(vhd_header_t);
617 err = posix_memalign((void **)&buf, VHD_SECTOR_SIZE, size);
618 if (err) {
619 buf = NULL;
620 image->message = "allocating image";
621 image->error = -err;
622 goto out;
623 }
625 err = vhd_seek(vhd, target->start, SEEK_SET);
626 if (err) {
627 image->message = "seeking to headers";
628 image->error = err;
629 goto out;
630 }
632 err = vhd_read(vhd, buf, size);
633 if (err) {
634 image->message = "reading headers";
635 image->error = err;
636 goto out;
637 }
639 memcpy(&vhd->footer, buf, sizeof(vhd_footer_t));
640 vhd_footer_in(&vhd->footer);
641 err = vhd_validate_footer(&vhd->footer);
642 if (err) {
643 image->message = "invalid footer";
644 image->error = err;
645 goto out;
646 }
648 /* lvhd vhds should always be dynamic */
649 if (vhd_type_dynamic(vhd)) {
650 if (vhd->footer.data_offset != sizeof(vhd_footer_t))
651 err = vhd_read_header_at(vhd, &vhd->header,
652 vhd->footer.data_offset +
653 target->start);
654 else {
655 memcpy(&vhd->header,
656 buf + sizeof(vhd_footer_t),
657 sizeof(vhd_header_t));
658 vhd_header_in(&vhd->header);
659 err = vhd_validate_header(&vhd->header);
660 }
662 if (err) {
663 image->message = "reading header";
664 image->error = err;
665 goto out;
666 }
668 vhd->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT;
669 vhd->bm_secs = secs_round_up_no_zero(vhd->spb >> 3);
670 }
672 out:
673 free(buf);
674 return image->error;
675 }
677 static int
678 vhd_util_scan_open_volume(vhd_context_t *vhd, struct vhd_image *image)
679 {
680 int err;
681 struct target *target;
683 target = image->target;
684 memset(vhd, 0, sizeof(*vhd));
685 vhd->oflags = VHD_OPEN_RDONLY | VHD_OPEN_FAST;
687 if (target->end - target->start < 4096) {
688 image->message = "device too small";
689 image->error = -EINVAL;
690 return image->error;
691 }
693 vhd->file = strdup(image->name);
694 if (!vhd->file) {
695 image->message = "allocating device";
696 image->error = -ENOMEM;
697 return image->error;
698 }
700 vhd->fd = open(target->device, O_RDONLY | O_DIRECT | O_LARGEFILE);
701 if (vhd->fd == -1) {
702 free(vhd->file);
703 vhd->file = NULL;
705 image->message = "opening device";
706 image->error = -errno;
707 return image->error;
708 }
710 if (target_vhd(target->type))
711 return vhd_util_scan_read_volume_headers(vhd, image);
713 return 0;
714 }
716 static int
717 vhd_util_scan_open(vhd_context_t *vhd, struct vhd_image *image)
718 {
719 struct target *target;
721 target = image->target;
723 if (target_volume(image->target->type) || !(flags & VHD_SCAN_PRETTY))
724 image->name = target->name;
725 else {
726 image->name = realpath(target->name, NULL);
727 if (!image->name) {
728 image->name = target->name;
729 image->message = "resolving name";
730 image->error = -errno;
731 return image->error;
732 }
733 }
735 if (target_volume(target->type))
736 return vhd_util_scan_open_volume(vhd, image);
737 else
738 return vhd_util_scan_open_file(vhd, image);
739 }
741 static int
742 vhd_util_scan_init_file_target(struct target *target,
743 const char *file, uint8_t type)
744 {
745 int err;
746 struct stat stats;
748 err = stat(file, &stats);
749 if (err == -1)
750 return -errno;
752 err = copy_name(target->name, file);
753 if (err)
754 return err;
756 err = copy_name(target->device, file);
757 if (err)
758 return err;
760 target->type = type;
761 target->start = 0;
762 target->size = stats.st_size;
763 target->end = stats.st_size;
765 return 0;
766 }
768 static int
769 vhd_util_scan_init_volume_target(struct target *target,
770 struct lv *lv, uint8_t type)
771 {
772 int err;
774 if (lv->first_segment.type != LVM_SEG_TYPE_LINEAR)
775 return -ENOSYS;
777 err = copy_name(target->name, lv->name);
778 if (err)
779 return err;
781 err = copy_name(target->device, lv->first_segment.device);
782 if (err)
783 return err;
785 target->type = type;
786 target->size = lv->size;
787 target->start = lv->first_segment.pe_start;
788 target->end = target->start + lv->first_segment.pe_size;
790 return 0;
791 }
793 static int
794 iterator_init(struct iterator *itr, int cnt, struct target *targets)
795 {
796 memset(itr, 0, sizeof(*itr));
798 itr->targets = malloc(sizeof(struct target) * cnt);
799 if (!itr->targets)
800 return -ENOMEM;
802 memcpy(itr->targets, targets, sizeof(struct target) * cnt);
804 itr->cur = 0;
805 itr->cur_size = cnt;
806 itr->max_size = cnt;
808 return 0;
809 }
811 static struct target *
812 iterator_next(struct iterator *itr)
813 {
814 if (itr->cur == itr->cur_size)
815 return NULL;
817 return itr->targets + itr->cur++;
818 }
820 static int
821 iterator_add_file(struct iterator *itr,
822 struct target *target, const char *parent, uint8_t type)
823 {
824 int i;
825 struct target *t;
826 char *lname, *rname;
828 for (i = 0; i < itr->cur_size; i++) {
829 t = itr->targets + i;
830 lname = basename((char *)t->name);
831 rname = basename((char *)parent);
833 if (!strcmp(lname, rname))
834 return -EEXIST;
835 }
837 return vhd_util_scan_init_file_target(target, parent, type);
838 }
840 static int
841 iterator_add_volume(struct iterator *itr,
842 struct target *target, const char *parent, uint8_t type)
843 {
844 int i, err;
845 struct lv *lv;
847 lv = NULL;
848 err = -ENOENT;
850 for (i = 0; i < itr->cur_size; i++)
851 if (!strcmp(parent, itr->targets[i].name))
852 return -EEXIST;
854 for (i = 0; i < vg.lv_cnt; i++) {
855 err = fnmatch(parent, vg.lvs[i].name, FNM_PATHNAME);
856 if (err != FNM_NOMATCH) {
857 lv = vg.lvs + i;
858 break;
859 }
860 }
862 if (err && err != FNM_PATHNAME)
863 return err;
865 if (!lv)
866 return -ENOENT;
868 return vhd_util_scan_init_volume_target(target, lv, type);
869 }
871 static int
872 iterator_add(struct iterator *itr, const char *parent, uint8_t type)
873 {
874 int err;
875 struct target *target;
877 if (itr->cur_size == itr->max_size) {
878 struct target *new;
880 new = realloc(itr->targets,
881 sizeof(struct target) *
882 itr->max_size * 2);
883 if (!new)
884 return -ENOMEM;
886 itr->max_size *= 2;
887 itr->targets = new;
888 }
890 target = itr->targets + itr->cur_size;
892 if (target_volume(type))
893 err = iterator_add_volume(itr, target, parent, type);
894 else
895 err = iterator_add_file(itr, target, parent, type);
897 if (err)
898 memset(target, 0, sizeof(*target));
899 else
900 itr->cur_size++;
902 return (err == -EEXIST ? 0 : err);
903 }
905 static void
906 iterator_free(struct iterator *itr)
907 {
908 free(itr->targets);
909 memset(itr, 0, sizeof(*itr));
910 }
912 static void
913 vhd_util_scan_add_parent(struct iterator *itr,
914 vhd_context_t *vhd, struct vhd_image *image)
915 {
916 int err;
917 uint8_t type;
919 if (vhd_parent_raw(vhd))
920 type = target_volume(image->target->type) ?
921 VHD_TYPE_RAW_VOLUME : VHD_TYPE_RAW_FILE;
922 else
923 type = target_volume(image->target->type) ?
924 VHD_TYPE_VHD_VOLUME : VHD_TYPE_VHD_FILE;
926 err = iterator_add(itr, image->parent, type);
927 if (err)
928 vhd_util_scan_error(image->parent, err);
929 }
931 static int
932 vhd_util_scan_targets(int cnt, struct target *targets)
933 {
934 int ret, err;
935 vhd_context_t vhd;
936 struct iterator itr;
937 struct target *target;
938 struct vhd_image image;
940 ret = 0;
941 err = 0;
943 err = iterator_init(&itr, cnt, targets);
944 if (err)
945 return err;
947 while ((target = iterator_next(&itr))) {
948 memset(&vhd, 0, sizeof(vhd));
949 memset(&image, 0, sizeof(image));
951 image.target = target;
953 err = vhd_util_scan_open(&vhd, &image);
954 if (err) {
955 ret = -EAGAIN;
956 goto end;
957 }
959 err = vhd_util_scan_get_size(&vhd, &image);
960 if (err) {
961 ret = -EAGAIN;
962 image.message = "getting physical size";
963 image.error = err;
964 goto end;
965 }
967 err = vhd_util_scan_get_hidden(&vhd, &image);
968 if (err) {
969 ret = -EAGAIN;
970 image.message = "checking 'hidden' field";
971 image.error = err;
972 goto end;
973 }
975 if (vhd.footer.type == HD_TYPE_DIFF) {
976 err = vhd_util_scan_get_parent(&vhd, &image);
977 if (err) {
978 ret = -EAGAIN;
979 image.message = "getting parent";
980 image.error = err;
981 goto end;
982 }
983 }
985 end:
986 vhd_util_scan_print_image(&image);
988 if (flags & VHD_SCAN_PARENTS && image.parent)
989 vhd_util_scan_add_parent(&itr, &vhd, &image);
991 if (vhd.file)
992 vhd_close(&vhd);
993 if (image.name != target->name)
994 free(image.name);
995 free(image.parent);
997 if (err && !(flags & VHD_SCAN_NOFAIL))
998 break;
999 }
1001 iterator_free(&itr);
1003 if (flags & VHD_SCAN_NOFAIL)
1004 return ret;
1006 return err;
1009 static int
1010 vhd_util_scan_targets_pretty(int cnt, struct target *targets)
1012 int err;
1014 err = vhd_util_scan_pretty_allocate_list(cnt);
1015 if (err) {
1016 printf("scan failed: no memory\n");
1017 return -ENOMEM;
1020 err = vhd_util_scan_targets(cnt, targets);
1022 vhd_util_scan_pretty_print_images();
1023 vhd_util_scan_pretty_free_list();
1025 return ((flags & VHD_SCAN_NOFAIL) ? 0 : err);
1028 static int
1029 vhd_util_scan_find_file_targets(int cnt, char **names,
1030 const char *filter,
1031 struct target **_targets, int *_total)
1033 glob_t g;
1034 struct target *targets;
1035 int i, globs, err, total;
1037 total = cnt;
1038 globs = 0;
1039 *_total = 0;
1040 *_targets = NULL;
1042 memset(&g, 0, sizeof(g));
1044 if (filter) {
1045 int gflags = ((flags & VHD_SCAN_FAST) ? GLOB_NOSORT : 0);
1047 errno = 0;
1048 err = glob(filter, gflags, vhd_util_scan_error, &g);
1050 switch (err) {
1051 case GLOB_NOSPACE:
1052 err = -ENOMEM;
1053 break;
1054 case GLOB_ABORTED:
1055 err = -EIO;
1056 break;
1057 case GLOB_NOMATCH:
1058 err = -errno;
1059 break;
1062 if (err) {
1063 vhd_util_scan_error(filter, err);
1064 return err;
1067 globs = g.gl_pathc;
1068 total += globs;
1071 targets = calloc(total, sizeof(struct target));
1072 if (!targets) {
1073 err = -ENOMEM;
1074 goto out;
1077 for (i = 0; i < g.gl_pathc; i++) {
1078 err = vhd_util_scan_init_file_target(targets + i,
1079 g.gl_pathv[i],
1080 VHD_TYPE_VHD_FILE);
1081 if (err) {
1082 vhd_util_scan_error(g.gl_pathv[i], err);
1083 if (!(flags & VHD_SCAN_NOFAIL))
1084 goto out;
1088 for (i = 0; i + globs < total; i++) {
1089 err = vhd_util_scan_init_file_target(targets + i + globs,
1090 names[i],
1091 VHD_TYPE_VHD_FILE);
1092 if (err) {
1093 vhd_util_scan_error(names[i], err);
1094 if (!(flags & VHD_SCAN_NOFAIL))
1095 goto out;
1099 err = 0;
1100 *_total = total;
1101 *_targets = targets;
1103 out:
1104 if (err)
1105 free(targets);
1106 if (filter)
1107 globfree(&g);
1109 return err;
1112 static inline void
1113 swap_volume(struct lv *lvs, int dst, int src)
1115 struct lv copy, *ldst, *lsrc;
1117 if (dst == src)
1118 return;
1120 lsrc = lvs + src;
1121 ldst = lvs + dst;
1123 memcpy(&copy, ldst, sizeof(copy));
1124 memcpy(ldst, lsrc, sizeof(*ldst));
1125 memcpy(lsrc, &copy, sizeof(copy));
1128 static int
1129 vhd_util_scan_sort_volumes(struct lv *lvs, int cnt,
1130 const char *filter, int *_matches)
1132 struct lv *lv;
1133 int i, err, matches;
1135 matches = 0;
1136 *_matches = 0;
1138 if (!filter)
1139 return 0;
1141 for (i = 0; i < cnt; i++) {
1142 lv = lvs + i;
1144 err = fnmatch(filter, lv->name, FNM_PATHNAME);
1145 if (err) {
1146 if (err != FNM_NOMATCH) {
1147 vhd_util_scan_error(lv->name, err);
1148 if (!(flags & VHD_SCAN_NOFAIL))
1149 return err;
1152 continue;
1155 swap_volume(lvs, matches++, i);
1158 *_matches = matches;
1159 return 0;
1162 static int
1163 vhd_util_scan_find_volume_targets(int cnt, char **names,
1164 const char *volume, const char *filter,
1165 struct target **_targets, int *_total)
1167 struct target *targets;
1168 int i, err, total, matches;
1170 *_total = 0;
1171 *_targets = NULL;
1172 targets = NULL;
1174 err = lvm_scan_vg(volume, &vg);
1175 if (err)
1176 return err;
1178 err = vhd_util_scan_sort_volumes(vg.lvs, vg.lv_cnt,
1179 filter, &matches);
1180 if (err)
1181 goto out;
1183 total = matches;
1184 for (i = 0; i < cnt; i++) {
1185 err = vhd_util_scan_sort_volumes(vg.lvs + total,
1186 vg.lv_cnt - total,
1187 names[i], &matches);
1188 if (err)
1189 goto out;
1191 total += matches;
1194 targets = calloc(total, sizeof(struct target));
1195 if (!targets) {
1196 err = -ENOMEM;
1197 goto out;
1200 for (i = 0; i < total; i++) {
1201 err = vhd_util_scan_init_volume_target(targets + i,
1202 vg.lvs + i,
1203 VHD_TYPE_VHD_VOLUME);
1204 if (err) {
1205 vhd_util_scan_error(vg.lvs[i].name, err);
1206 if (!(flags & VHD_SCAN_NOFAIL))
1207 goto out;
1211 err = 0;
1212 *_total = total;
1213 *_targets = targets;
1215 out:
1216 if (err)
1217 free(targets);
1218 return err;
1221 static int
1222 vhd_util_scan_find_targets(int cnt, char **names,
1223 const char *volume, const char *filter,
1224 struct target **targets, int *total)
1226 if (flags & VHD_SCAN_VOLUME)
1227 return vhd_util_scan_find_volume_targets(cnt, names,
1228 volume, filter,
1229 targets, total);
1230 return vhd_util_scan_find_file_targets(cnt, names,
1231 filter, targets, total);
1234 int
1235 vhd_util_scan(int argc, char **argv)
1237 int c, ret, err, cnt;
1238 char *filter, *volume;
1239 struct target *targets;
1241 cnt = 0;
1242 ret = 0;
1243 err = 0;
1244 flags = 0;
1245 filter = NULL;
1246 volume = NULL;
1247 targets = NULL;
1249 optind = 0;
1250 while ((c = getopt(argc, argv, "m:fcl:pavh")) != -1) {
1251 switch (c) {
1252 case 'm':
1253 filter = optarg;
1254 break;
1255 case 'f':
1256 flags |= VHD_SCAN_FAST;
1257 break;
1258 case 'c':
1259 flags |= VHD_SCAN_NOFAIL;
1260 break;
1261 case 'l':
1262 volume = optarg;
1263 flags |= VHD_SCAN_VOLUME;
1264 break;
1265 case 'p':
1266 flags |= VHD_SCAN_PRETTY;
1267 break;
1268 case 'a':
1269 flags |= VHD_SCAN_PARENTS;
1270 break;
1271 case 'v':
1272 flags |= VHD_SCAN_VERBOSE;
1273 break;
1274 case 'h':
1275 goto usage;
1276 default:
1277 err = -EINVAL;
1278 goto usage;
1282 if (!filter && argc - optind == 0) {
1283 err = -EINVAL;
1284 goto usage;
1287 if (flags & VHD_SCAN_PRETTY)
1288 flags &= ~VHD_SCAN_FAST;
1290 err = vhd_util_scan_find_targets(argc - optind, argv + optind,
1291 volume, filter, &targets, &cnt);
1292 if (err) {
1293 printf("scan failed: %d\n", err);
1294 return err;
1297 if (!cnt)
1298 return 0;
1300 if (flags & VHD_SCAN_PRETTY)
1301 err = vhd_util_scan_targets_pretty(cnt, targets);
1302 else
1303 err = vhd_util_scan_targets(cnt, targets);
1305 free(targets);
1306 lvm_free_vg(&vg);
1308 return ((flags & VHD_SCAN_NOFAIL) ? 0 : err);
1310 usage:
1311 printf("usage: [OPTIONS] FILES\n"
1312 "options: [-m match filter] [-f fast] [-c continue on failure] "
1313 "[-l LVM volume] [-p pretty print] [-a scan parents] "
1314 "[-v verbose] [-h help]\n");
1315 return err;