root / vhd / lib / vhd-util-scan.c @ abdb293f
History | View | Annotate | Download (27.6 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 <glob.h> |
36 |
#include <errno.h> |
37 |
#include <fcntl.h> |
38 |
#include <stdio.h> |
39 |
#include <string.h> |
40 |
#include <stdlib.h> |
41 |
#include <unistd.h> |
42 |
#include <fnmatch.h> |
43 |
#include <limits.h> |
44 |
#include <libgen.h> |
45 |
#include <syslog.h> |
46 |
#include <sys/stat.h> |
47 |
#include <sys/types.h> |
48 |
|
49 |
#include "list.h" |
50 |
#include "libvhd.h" |
51 |
#include "lvm-util.h" |
52 |
|
53 |
#define VHD_SCAN_FAST 0x01 |
54 |
#define VHD_SCAN_PRETTY 0x02 |
55 |
#define VHD_SCAN_VOLUME 0x04 |
56 |
#define VHD_SCAN_NOFAIL 0x08 |
57 |
#define VHD_SCAN_VERBOSE 0x10 |
58 |
#define VHD_SCAN_PARENTS 0x20 |
59 |
#define VHD_SCAN_MARKERS 0x40 |
60 |
|
61 |
#define VHD_TYPE_RAW_FILE 0x01 |
62 |
#define VHD_TYPE_VHD_FILE 0x02 |
63 |
#define VHD_TYPE_RAW_VOLUME 0x04 |
64 |
#define VHD_TYPE_VHD_VOLUME 0x08 |
65 |
|
66 |
#define EPRINTF(_f, _a...) \
|
67 |
do { \
|
68 |
syslog(LOG_INFO, "%s: " _f, __func__, ##_a); \ |
69 |
} while (0) |
70 |
|
71 |
static inline int |
72 |
target_volume(uint8_t type) |
73 |
{ |
74 |
return (type == VHD_TYPE_RAW_VOLUME || type == VHD_TYPE_VHD_VOLUME);
|
75 |
} |
76 |
|
77 |
static inline int |
78 |
target_vhd(uint8_t type) |
79 |
{ |
80 |
return (type == VHD_TYPE_VHD_FILE || type == VHD_TYPE_VHD_VOLUME);
|
81 |
} |
82 |
|
83 |
struct target {
|
84 |
char name[VHD_MAX_NAME_LEN];
|
85 |
char device[VHD_MAX_NAME_LEN];
|
86 |
uint64_t size; |
87 |
uint64_t start; |
88 |
uint64_t end; |
89 |
uint8_t type; |
90 |
}; |
91 |
|
92 |
struct iterator {
|
93 |
int cur;
|
94 |
int cur_size;
|
95 |
int max_size;
|
96 |
struct target *targets;
|
97 |
}; |
98 |
|
99 |
struct vhd_image {
|
100 |
char *name;
|
101 |
char *parent;
|
102 |
uint64_t capacity; |
103 |
off64_t size; |
104 |
uint8_t hidden; |
105 |
char marker;
|
106 |
int error;
|
107 |
char *message;
|
108 |
|
109 |
struct target *target;
|
110 |
|
111 |
struct list_head sibling;
|
112 |
struct list_head children;
|
113 |
struct vhd_image *parent_image;
|
114 |
}; |
115 |
|
116 |
struct vhd_scan {
|
117 |
int cur;
|
118 |
int size;
|
119 |
|
120 |
int lists_cur;
|
121 |
int lists_size;
|
122 |
|
123 |
struct vhd_image **images;
|
124 |
struct vhd_image **lists;
|
125 |
}; |
126 |
|
127 |
static int flags; |
128 |
static struct vg vg; |
129 |
static struct vhd_scan scan; |
130 |
|
131 |
static int |
132 |
vhd_util_scan_pretty_allocate_list(int cnt)
|
133 |
{ |
134 |
int i;
|
135 |
|
136 |
memset(&scan, 0, sizeof(scan)); |
137 |
|
138 |
scan.lists_cur = 1;
|
139 |
scan.lists_size = 10;
|
140 |
|
141 |
scan.lists = calloc(scan.lists_size, sizeof(struct vhd_image *)); |
142 |
if (!scan.lists)
|
143 |
goto fail;
|
144 |
|
145 |
scan.lists[0] = calloc(cnt, sizeof(struct vhd_image)); |
146 |
if (!scan.lists[0]) |
147 |
goto fail;
|
148 |
|
149 |
scan.images = calloc(cnt, sizeof(struct vhd_image *)); |
150 |
if (!scan.images)
|
151 |
goto fail;
|
152 |
|
153 |
for (i = 0; i < cnt; i++) |
154 |
scan.images[i] = scan.lists[0] + i;
|
155 |
|
156 |
scan.cur = 0;
|
157 |
scan.size = cnt; |
158 |
|
159 |
return 0; |
160 |
|
161 |
fail:
|
162 |
if (scan.lists) {
|
163 |
free(scan.lists[0]);
|
164 |
free(scan.lists); |
165 |
} |
166 |
|
167 |
free(scan.images); |
168 |
memset(&scan, 0, sizeof(scan)); |
169 |
return -ENOMEM;
|
170 |
} |
171 |
|
172 |
static void |
173 |
vhd_util_scan_pretty_free_list(void)
|
174 |
{ |
175 |
int i;
|
176 |
|
177 |
if (scan.lists) {
|
178 |
for (i = 0; i < scan.lists_cur; i++) |
179 |
free(scan.lists[i]); |
180 |
free(scan.lists); |
181 |
} |
182 |
|
183 |
free(scan.images); |
184 |
memset(&scan, 0, sizeof(scan)); |
185 |
} |
186 |
|
187 |
static int |
188 |
vhd_util_scan_pretty_add_image(struct vhd_image *image)
|
189 |
{ |
190 |
int i;
|
191 |
struct vhd_image *img;
|
192 |
|
193 |
for (i = 0; i < scan.cur; i++) { |
194 |
img = scan.images[i]; |
195 |
if (!strcmp(img->name, image->name))
|
196 |
return 0; |
197 |
} |
198 |
|
199 |
if (scan.cur >= scan.size) {
|
200 |
struct vhd_image *new, **list;
|
201 |
|
202 |
if (scan.lists_cur >= scan.lists_size) {
|
203 |
list = realloc(scan.lists, scan.lists_size * 2 *
|
204 |
sizeof(struct vhd_image *)); |
205 |
if (!list)
|
206 |
return -ENOMEM;
|
207 |
|
208 |
scan.lists_size *= 2;
|
209 |
scan.lists = list; |
210 |
} |
211 |
|
212 |
new = calloc(scan.size, sizeof(struct vhd_image)); |
213 |
if (!new)
|
214 |
return -ENOMEM;
|
215 |
|
216 |
scan.lists[scan.lists_cur++] = new; |
217 |
scan.size *= 2;
|
218 |
|
219 |
list = realloc(scan.images, scan.size * |
220 |
sizeof(struct vhd_image *)); |
221 |
if (!list)
|
222 |
return -ENOMEM;
|
223 |
|
224 |
scan.images = list; |
225 |
for (i = 0; i + scan.cur < scan.size; i++) |
226 |
scan.images[i + scan.cur] = new + i; |
227 |
} |
228 |
|
229 |
img = scan.images[scan.cur]; |
230 |
INIT_LIST_HEAD(&img->sibling); |
231 |
INIT_LIST_HEAD(&img->children); |
232 |
|
233 |
img->capacity = image->capacity; |
234 |
img->size = image->size; |
235 |
img->hidden = image->hidden; |
236 |
img->marker = image->marker; |
237 |
img->error = image->error; |
238 |
img->message = image->message; |
239 |
|
240 |
img->name = strdup(image->name); |
241 |
if (!img->name)
|
242 |
goto fail;
|
243 |
|
244 |
if (image->parent) {
|
245 |
img->parent = strdup(image->parent); |
246 |
if (!img->parent)
|
247 |
goto fail;
|
248 |
} |
249 |
|
250 |
scan.cur++; |
251 |
return 0; |
252 |
|
253 |
fail:
|
254 |
free(img->name); |
255 |
free(img->parent); |
256 |
memset(img, 0, sizeof(*img)); |
257 |
return -ENOMEM;
|
258 |
} |
259 |
|
260 |
static int |
261 |
vhd_util_scan_pretty_image_compare(const void *lhs, const void *rhs) |
262 |
{ |
263 |
struct vhd_image *l, *r;
|
264 |
|
265 |
l = *(struct vhd_image **)lhs;
|
266 |
r = *(struct vhd_image **)rhs;
|
267 |
|
268 |
return strcmp(l->name, r->name);
|
269 |
} |
270 |
|
271 |
static void |
272 |
vhd_util_scan_print_image_indent(struct vhd_image *image, int tab) |
273 |
{ |
274 |
char *pad, *name, *pmsg, *parent;
|
275 |
|
276 |
pad = (tab ? " " : ""); |
277 |
name = image->name; |
278 |
parent = (image->parent ? : "none");
|
279 |
|
280 |
if ((flags & VHD_SCAN_PRETTY) && image->parent && !image->parent_image)
|
281 |
pmsg = " (not found in scan)";
|
282 |
else
|
283 |
pmsg = "";
|
284 |
|
285 |
if (!(flags & VHD_SCAN_VERBOSE)) {
|
286 |
name = basename(image->name); |
287 |
if (image->parent)
|
288 |
parent = basename(image->parent); |
289 |
} |
290 |
|
291 |
if (image->error)
|
292 |
printf("%*svhd=%s scan-error=%d error-message='%s'\n",
|
293 |
tab, pad, image->name, image->error, image->message); |
294 |
else if (!(flags & VHD_SCAN_MARKERS)) |
295 |
printf("%*svhd=%s capacity=%"PRIu64" size=%"PRIu64" hidden=%u " |
296 |
"parent=%s%s\n", tab, pad, name, image->capacity,
|
297 |
image->size, image->hidden, parent, pmsg); |
298 |
else
|
299 |
printf("%*svhd=%s capacity=%"PRIu64" size=%"PRIu64" hidden=%u " |
300 |
"marker=%u parent=%s%s\n", tab, pad, name,
|
301 |
image->capacity, image->size, image->hidden, |
302 |
(uint8_t)image->marker, parent, pmsg); |
303 |
} |
304 |
|
305 |
static void |
306 |
vhd_util_scan_pretty_print_tree(struct vhd_image *image, int depth) |
307 |
{ |
308 |
struct vhd_image *img, *tmp;
|
309 |
|
310 |
vhd_util_scan_print_image_indent(image, depth * 3);
|
311 |
|
312 |
list_for_each_entry_safe(img, tmp, &image->children, sibling) |
313 |
if (!img->hidden)
|
314 |
vhd_util_scan_pretty_print_tree(img, depth + 1);
|
315 |
|
316 |
list_for_each_entry_safe(img, tmp, &image->children, sibling) |
317 |
if (img->hidden)
|
318 |
vhd_util_scan_pretty_print_tree(img, depth + 1);
|
319 |
|
320 |
free(image->name); |
321 |
free(image->parent); |
322 |
|
323 |
image->name = NULL;
|
324 |
image->parent = NULL;
|
325 |
} |
326 |
|
327 |
static void |
328 |
vhd_util_scan_pretty_print_images(void)
|
329 |
{ |
330 |
int i;
|
331 |
struct vhd_image *image, **parentp, *parent, *keyp, key;
|
332 |
|
333 |
qsort(scan.images, scan.cur, sizeof(scan.images[0]), |
334 |
vhd_util_scan_pretty_image_compare); |
335 |
|
336 |
for (i = 0; i < scan.cur; i++) { |
337 |
image = scan.images[i]; |
338 |
|
339 |
if (!image->parent) {
|
340 |
image->parent_image = NULL;
|
341 |
continue;
|
342 |
} |
343 |
|
344 |
memset(&key, 0, sizeof(key)); |
345 |
key.name = image->parent; |
346 |
keyp = &key; |
347 |
|
348 |
parentp = bsearch(&keyp, scan.images, scan.cur, |
349 |
sizeof(scan.images[0]), |
350 |
vhd_util_scan_pretty_image_compare); |
351 |
if (!parentp) {
|
352 |
image->parent_image = NULL;
|
353 |
continue;
|
354 |
} |
355 |
|
356 |
parent = *parentp; |
357 |
image->parent_image = parent; |
358 |
list_add_tail(&image->sibling, &parent->children); |
359 |
} |
360 |
|
361 |
for (i = 0; i < scan.cur; i++) { |
362 |
image = scan.images[i]; |
363 |
|
364 |
if (image->parent_image || !image->hidden)
|
365 |
continue;
|
366 |
|
367 |
vhd_util_scan_pretty_print_tree(image, 0);
|
368 |
} |
369 |
|
370 |
for (i = 0; i < scan.cur; i++) { |
371 |
image = scan.images[i]; |
372 |
|
373 |
if (!image->name || image->parent_image)
|
374 |
continue;
|
375 |
|
376 |
vhd_util_scan_pretty_print_tree(image, 0);
|
377 |
} |
378 |
|
379 |
for (i = 0; i < scan.cur; i++) { |
380 |
image = scan.images[i]; |
381 |
|
382 |
if (!image->name)
|
383 |
continue;
|
384 |
|
385 |
vhd_util_scan_pretty_print_tree(image, 0);
|
386 |
} |
387 |
} |
388 |
|
389 |
static void |
390 |
vhd_util_scan_print_image(struct vhd_image *image)
|
391 |
{ |
392 |
int err;
|
393 |
|
394 |
if (!image->error && (flags & VHD_SCAN_PRETTY)) {
|
395 |
err = vhd_util_scan_pretty_add_image(image); |
396 |
if (!err)
|
397 |
return;
|
398 |
|
399 |
if (!image->error) {
|
400 |
image->error = err; |
401 |
image->message = "allocating memory";
|
402 |
} |
403 |
} |
404 |
|
405 |
vhd_util_scan_print_image_indent(image, 0);
|
406 |
} |
407 |
|
408 |
static int |
409 |
vhd_util_scan_error(const char *file, int err) |
410 |
{ |
411 |
struct vhd_image image;
|
412 |
|
413 |
memset(&image, 0, sizeof(image)); |
414 |
image.name = (char *)file;
|
415 |
image.error = err; |
416 |
image.message = "failure scanning target";
|
417 |
|
418 |
vhd_util_scan_print_image(&image); |
419 |
|
420 |
/*
|
421 |
if (flags & VHD_SCAN_NOFAIL)
|
422 |
return 0;
|
423 |
*/
|
424 |
|
425 |
return err;
|
426 |
} |
427 |
|
428 |
static vhd_parent_locator_t *
|
429 |
vhd_util_scan_get_parent_locator(vhd_context_t *vhd) |
430 |
{ |
431 |
int i;
|
432 |
vhd_parent_locator_t *loc; |
433 |
|
434 |
loc = NULL;
|
435 |
|
436 |
for (i = 0; i < 8; i++) { |
437 |
if (vhd->header.loc[i].code == PLAT_CODE_MACX) {
|
438 |
loc = vhd->header.loc + i; |
439 |
break;
|
440 |
} |
441 |
|
442 |
if (vhd->header.loc[i].code == PLAT_CODE_W2RU)
|
443 |
loc = vhd->header.loc + i; |
444 |
|
445 |
if (!loc && vhd->header.loc[i].code != PLAT_CODE_NONE)
|
446 |
loc = vhd->header.loc + i; |
447 |
} |
448 |
|
449 |
return loc;
|
450 |
} |
451 |
|
452 |
static inline int |
453 |
copy_name(char *dst, const char *src) |
454 |
{ |
455 |
if (snprintf(dst, VHD_MAX_NAME_LEN, "%s", src) < VHD_MAX_NAME_LEN) |
456 |
return 0; |
457 |
|
458 |
return -ENAMETOOLONG;
|
459 |
} |
460 |
|
461 |
/*
|
462 |
* LVHD stores realpath(parent) in parent locators, so
|
463 |
* /dev/<vol-group>/<lv-name> becomes /dev/mapper/<vol--group>-<lv--name>
|
464 |
*/
|
465 |
static int |
466 |
vhd_util_scan_extract_volume_name(char *dst, const char *src) |
467 |
{ |
468 |
char copy[VHD_MAX_NAME_LEN], *name, *s, *c;
|
469 |
|
470 |
name = strrchr(src, '/');
|
471 |
if (!name)
|
472 |
name = (char *)src;
|
473 |
|
474 |
/* convert single dashes to slashes, double dashes to single dashes */
|
475 |
for (c = copy, s = name; *s != '\0'; s++, c++) { |
476 |
if (*s == '-') { |
477 |
if (s[1] != '-') |
478 |
*c = '/';
|
479 |
else {
|
480 |
s++; |
481 |
*c = '-';
|
482 |
} |
483 |
} else
|
484 |
*c = *s; |
485 |
} |
486 |
|
487 |
*c = '\0';
|
488 |
c = strrchr(copy, '/');
|
489 |
if (c == name) {
|
490 |
/* unrecognized format */
|
491 |
strcpy(dst, src); |
492 |
return -EINVAL;
|
493 |
} |
494 |
|
495 |
strcpy(dst, ++c); |
496 |
return 0; |
497 |
} |
498 |
|
499 |
static int |
500 |
vhd_util_scan_get_volume_parent(vhd_context_t *vhd, struct vhd_image *image)
|
501 |
{ |
502 |
int err;
|
503 |
char name[VHD_MAX_NAME_LEN];
|
504 |
vhd_parent_locator_t *loc, copy; |
505 |
|
506 |
if (flags & VHD_SCAN_FAST) {
|
507 |
err = vhd_header_decode_parent(vhd, |
508 |
&vhd->header, &image->parent); |
509 |
if (!err)
|
510 |
goto found;
|
511 |
} |
512 |
|
513 |
loc = vhd_util_scan_get_parent_locator(vhd); |
514 |
if (!loc)
|
515 |
return -EINVAL;
|
516 |
|
517 |
copy = *loc; |
518 |
copy.data_offset += image->target->start; |
519 |
err = vhd_parent_locator_read(vhd, ©, &image->parent); |
520 |
if (err)
|
521 |
return err;
|
522 |
|
523 |
found:
|
524 |
err = vhd_util_scan_extract_volume_name(name, image->parent); |
525 |
if (!err)
|
526 |
return copy_name(image->parent, name);
|
527 |
|
528 |
return 0; |
529 |
} |
530 |
|
531 |
static int |
532 |
vhd_util_scan_get_parent(vhd_context_t *vhd, struct vhd_image *image)
|
533 |
{ |
534 |
int err;
|
535 |
vhd_parent_locator_t *loc; |
536 |
|
537 |
if (!target_vhd(image->target->type)) {
|
538 |
image->parent = NULL;
|
539 |
return 0; |
540 |
} |
541 |
|
542 |
loc = NULL;
|
543 |
|
544 |
if (target_volume(image->target->type))
|
545 |
return vhd_util_scan_get_volume_parent(vhd, image);
|
546 |
|
547 |
if (flags & VHD_SCAN_FAST) {
|
548 |
err = vhd_header_decode_parent(vhd, |
549 |
&vhd->header, &image->parent); |
550 |
if (!err)
|
551 |
return 0; |
552 |
} else {
|
553 |
/*
|
554 |
* vhd_parent_locator_get checks for the existence of the
|
555 |
* parent file. if this call succeeds, all is well; if not,
|
556 |
* we'll try to return whatever string we have before failing
|
557 |
* outright.
|
558 |
*/
|
559 |
err = vhd_parent_locator_get(vhd, &image->parent); |
560 |
if (!err)
|
561 |
return 0; |
562 |
} |
563 |
|
564 |
loc = vhd_util_scan_get_parent_locator(vhd); |
565 |
if (!loc)
|
566 |
return -EINVAL;
|
567 |
|
568 |
return vhd_parent_locator_read(vhd, loc, &image->parent);
|
569 |
} |
570 |
|
571 |
static int |
572 |
vhd_util_scan_get_hidden(vhd_context_t *vhd, struct vhd_image *image)
|
573 |
{ |
574 |
int err, hidden;
|
575 |
|
576 |
err = 0;
|
577 |
hidden = 0;
|
578 |
|
579 |
if (target_vhd(image->target->type))
|
580 |
err = vhd_hidden(vhd, &hidden); |
581 |
else
|
582 |
hidden = 1;
|
583 |
|
584 |
if (err)
|
585 |
return err;
|
586 |
|
587 |
image->hidden = hidden; |
588 |
return 0; |
589 |
} |
590 |
|
591 |
static int |
592 |
vhd_util_scan_get_marker(vhd_context_t *vhd, struct vhd_image *image)
|
593 |
{ |
594 |
int err;
|
595 |
char marker;
|
596 |
|
597 |
err = 0;
|
598 |
marker = 0;
|
599 |
|
600 |
if (target_vhd(image->target->type) && vhd_has_batmap(vhd))
|
601 |
err = vhd_marker(vhd, &marker); |
602 |
|
603 |
image->marker = marker; |
604 |
return err;
|
605 |
} |
606 |
|
607 |
static int |
608 |
vhd_util_scan_get_size(vhd_context_t *vhd, struct vhd_image *image)
|
609 |
{ |
610 |
image->size = image->target->size; |
611 |
|
612 |
if (target_vhd(image->target->type))
|
613 |
image->capacity = vhd->footer.curr_size; |
614 |
else
|
615 |
image->capacity = image->size; |
616 |
|
617 |
return 0; |
618 |
} |
619 |
|
620 |
static int |
621 |
vhd_util_scan_open_file(vhd_context_t *vhd, struct vhd_image *image)
|
622 |
{ |
623 |
int err, vhd_flags;
|
624 |
|
625 |
if (!target_vhd(image->target->type))
|
626 |
return 0; |
627 |
|
628 |
vhd_flags = VHD_OPEN_RDONLY | VHD_OPEN_IGNORE_DISABLED; |
629 |
if (flags & VHD_SCAN_FAST)
|
630 |
vhd_flags |= VHD_OPEN_FAST; |
631 |
|
632 |
err = vhd_open(vhd, image->name, vhd_flags); |
633 |
if (err) {
|
634 |
vhd->file = NULL;
|
635 |
image->message = "opening file";
|
636 |
image->error = err; |
637 |
return image->error;
|
638 |
} |
639 |
|
640 |
return 0; |
641 |
} |
642 |
|
643 |
static int |
644 |
vhd_util_scan_read_volume_headers(vhd_context_t *vhd, struct vhd_image *image)
|
645 |
{ |
646 |
int err;
|
647 |
void *buf;
|
648 |
size_t size; |
649 |
struct target *target;
|
650 |
|
651 |
buf = NULL;
|
652 |
target = image->target; |
653 |
size = sizeof(vhd_footer_t) + sizeof(vhd_header_t); |
654 |
|
655 |
err = posix_memalign(&buf, VHD_SECTOR_SIZE, size); |
656 |
if (err) {
|
657 |
buf = NULL;
|
658 |
image->message = "allocating image";
|
659 |
image->error = -err; |
660 |
goto out;
|
661 |
} |
662 |
|
663 |
err = vhd_seek(vhd, target->start, SEEK_SET); |
664 |
if (err) {
|
665 |
image->message = "seeking to headers";
|
666 |
image->error = err; |
667 |
goto out;
|
668 |
} |
669 |
|
670 |
err = vhd_read(vhd, buf, size); |
671 |
if (err) {
|
672 |
image->message = "reading headers";
|
673 |
image->error = err; |
674 |
goto out;
|
675 |
} |
676 |
|
677 |
memcpy(&vhd->footer, buf, sizeof(vhd_footer_t));
|
678 |
vhd_footer_in(&vhd->footer); |
679 |
err = vhd_validate_footer(&vhd->footer); |
680 |
if (err) {
|
681 |
image->message = "invalid footer";
|
682 |
image->error = err; |
683 |
goto out;
|
684 |
} |
685 |
|
686 |
/* lvhd vhds should always be dynamic */
|
687 |
if (vhd_type_dynamic(vhd)) {
|
688 |
if (vhd->footer.data_offset != sizeof(vhd_footer_t)) |
689 |
err = vhd_read_header_at(vhd, &vhd->header, |
690 |
vhd->footer.data_offset + |
691 |
target->start); |
692 |
else {
|
693 |
memcpy(&vhd->header, |
694 |
buf + sizeof(vhd_footer_t),
|
695 |
sizeof(vhd_header_t));
|
696 |
vhd_header_in(&vhd->header); |
697 |
err = vhd_validate_header(&vhd->header); |
698 |
} |
699 |
|
700 |
if (err) {
|
701 |
image->message = "reading header";
|
702 |
image->error = err; |
703 |
goto out;
|
704 |
} |
705 |
|
706 |
vhd->spb = vhd->header.block_size >> VHD_SECTOR_SHIFT; |
707 |
vhd->bm_secs = secs_round_up_no_zero(vhd->spb >> 3);
|
708 |
} |
709 |
|
710 |
out:
|
711 |
free(buf); |
712 |
return image->error;
|
713 |
} |
714 |
|
715 |
static int |
716 |
vhd_util_scan_open_volume(vhd_context_t *vhd, struct vhd_image *image)
|
717 |
{ |
718 |
struct target *target;
|
719 |
|
720 |
target = image->target; |
721 |
memset(vhd, 0, sizeof(*vhd)); |
722 |
vhd->oflags = VHD_OPEN_RDONLY | VHD_OPEN_FAST; |
723 |
|
724 |
if (target->end - target->start < 4096) { |
725 |
image->message = "device too small";
|
726 |
image->error = -EINVAL; |
727 |
return image->error;
|
728 |
} |
729 |
|
730 |
vhd->file = strdup(image->name); |
731 |
if (!vhd->file) {
|
732 |
image->message = "allocating device";
|
733 |
image->error = -ENOMEM; |
734 |
return image->error;
|
735 |
} |
736 |
|
737 |
vhd->fd = open(target->device, O_RDONLY | O_DIRECT | O_LARGEFILE); |
738 |
if (vhd->fd == -1) { |
739 |
free(vhd->file); |
740 |
vhd->file = NULL;
|
741 |
|
742 |
image->message = "opening device";
|
743 |
image->error = -errno; |
744 |
return image->error;
|
745 |
} |
746 |
|
747 |
if (target_vhd(target->type))
|
748 |
return vhd_util_scan_read_volume_headers(vhd, image);
|
749 |
|
750 |
return 0; |
751 |
} |
752 |
|
753 |
static int |
754 |
vhd_util_scan_open(vhd_context_t *vhd, struct vhd_image *image)
|
755 |
{ |
756 |
struct target *target;
|
757 |
|
758 |
target = image->target; |
759 |
|
760 |
if (target_volume(image->target->type) || !(flags & VHD_SCAN_PRETTY))
|
761 |
image->name = target->name; |
762 |
else {
|
763 |
char __image_name[PATH_MAX];
|
764 |
|
765 |
image->name = realpath(target->name, __image_name); |
766 |
if (image->name)
|
767 |
image->name = strdup(__image_name); |
768 |
if (!image->name) {
|
769 |
image->name = target->name; |
770 |
image->message = "resolving name";
|
771 |
image->error = -errno; |
772 |
return image->error;
|
773 |
} |
774 |
} |
775 |
|
776 |
if (target_volume(target->type))
|
777 |
return vhd_util_scan_open_volume(vhd, image);
|
778 |
else
|
779 |
return vhd_util_scan_open_file(vhd, image);
|
780 |
} |
781 |
|
782 |
static int |
783 |
vhd_util_scan_init_file_target(struct target *target,
|
784 |
const char *file, uint8_t type) |
785 |
{ |
786 |
int err;
|
787 |
struct stat stats;
|
788 |
|
789 |
err = stat(file, &stats); |
790 |
if (err == -1) |
791 |
return -errno;
|
792 |
|
793 |
err = copy_name(target->name, file); |
794 |
if (err)
|
795 |
return err;
|
796 |
|
797 |
err = copy_name(target->device, file); |
798 |
if (err)
|
799 |
return err;
|
800 |
|
801 |
target->type = type; |
802 |
target->start = 0;
|
803 |
target->size = stats.st_size; |
804 |
target->end = stats.st_size; |
805 |
|
806 |
return 0; |
807 |
} |
808 |
|
809 |
static int |
810 |
vhd_util_scan_init_volume_target(struct target *target,
|
811 |
struct lv *lv, uint8_t type)
|
812 |
{ |
813 |
int err;
|
814 |
|
815 |
if (lv->first_segment.type != LVM_SEG_TYPE_LINEAR)
|
816 |
return -ENOSYS;
|
817 |
|
818 |
err = copy_name(target->name, lv->name); |
819 |
if (err) {
|
820 |
EPRINTF("copy target name failed: '%s'\n", lv->name);
|
821 |
return err;
|
822 |
} |
823 |
|
824 |
err = copy_name(target->device, lv->first_segment.device); |
825 |
if (err) {
|
826 |
EPRINTF("copy target device failed: '%s'\n",
|
827 |
lv->first_segment.device); |
828 |
return err;
|
829 |
} |
830 |
|
831 |
target->type = type; |
832 |
target->size = lv->size; |
833 |
target->start = lv->first_segment.pe_start; |
834 |
target->end = target->start + lv->first_segment.pe_size; |
835 |
|
836 |
return 0; |
837 |
} |
838 |
|
839 |
static int |
840 |
iterator_init(struct iterator *itr, int cnt, struct target *targets) |
841 |
{ |
842 |
memset(itr, 0, sizeof(*itr)); |
843 |
|
844 |
itr->targets = malloc(sizeof(struct target) * cnt); |
845 |
if (!itr->targets)
|
846 |
return -ENOMEM;
|
847 |
|
848 |
memcpy(itr->targets, targets, sizeof(struct target) * cnt); |
849 |
|
850 |
itr->cur = 0;
|
851 |
itr->cur_size = cnt; |
852 |
itr->max_size = cnt; |
853 |
|
854 |
return 0; |
855 |
} |
856 |
|
857 |
static struct target * |
858 |
iterator_next(struct iterator *itr)
|
859 |
{ |
860 |
if (itr->cur == itr->cur_size)
|
861 |
return NULL; |
862 |
|
863 |
return itr->targets + itr->cur++;
|
864 |
} |
865 |
|
866 |
static int |
867 |
iterator_add_file(struct iterator *itr,
|
868 |
struct target *target, const char *parent, uint8_t type) |
869 |
{ |
870 |
int i;
|
871 |
struct target *t;
|
872 |
char *lname, *rname;
|
873 |
|
874 |
for (i = 0; i < itr->cur_size; i++) { |
875 |
t = itr->targets + i; |
876 |
lname = basename((char *)t->name);
|
877 |
rname = basename((char *)parent);
|
878 |
|
879 |
if (!strcmp(lname, rname))
|
880 |
return -EEXIST;
|
881 |
} |
882 |
|
883 |
return vhd_util_scan_init_file_target(target, parent, type);
|
884 |
} |
885 |
|
886 |
static int |
887 |
iterator_add_volume(struct iterator *itr,
|
888 |
struct target *target, const char *parent, uint8_t type) |
889 |
{ |
890 |
int i, err;
|
891 |
struct lv *lv;
|
892 |
|
893 |
lv = NULL;
|
894 |
err = -ENOENT; |
895 |
|
896 |
for (i = 0; i < itr->cur_size; i++) |
897 |
if (!strcmp(parent, itr->targets[i].name))
|
898 |
return -EEXIST;
|
899 |
|
900 |
for (i = 0; i < vg.lv_cnt; i++) { |
901 |
err = fnmatch(parent, vg.lvs[i].name, FNM_PATHNAME); |
902 |
if (err != FNM_NOMATCH) {
|
903 |
lv = vg.lvs + i; |
904 |
break;
|
905 |
} |
906 |
} |
907 |
|
908 |
if (err && err != FNM_PATHNAME)
|
909 |
return err;
|
910 |
|
911 |
if (!lv)
|
912 |
return -ENOENT;
|
913 |
|
914 |
return vhd_util_scan_init_volume_target(target, lv, type);
|
915 |
} |
916 |
|
917 |
static int |
918 |
iterator_add(struct iterator *itr, const char *parent, uint8_t type) |
919 |
{ |
920 |
int err;
|
921 |
struct target *target;
|
922 |
|
923 |
if (itr->cur_size == itr->max_size) {
|
924 |
struct target *new;
|
925 |
|
926 |
new = realloc(itr->targets, |
927 |
sizeof(struct target) * |
928 |
itr->max_size * 2);
|
929 |
if (!new)
|
930 |
return -ENOMEM;
|
931 |
|
932 |
itr->max_size *= 2;
|
933 |
itr->targets = new; |
934 |
} |
935 |
|
936 |
target = itr->targets + itr->cur_size; |
937 |
|
938 |
if (target_volume(type))
|
939 |
err = iterator_add_volume(itr, target, parent, type); |
940 |
else
|
941 |
err = iterator_add_file(itr, target, parent, type); |
942 |
|
943 |
if (err)
|
944 |
memset(target, 0, sizeof(*target)); |
945 |
else
|
946 |
itr->cur_size++; |
947 |
|
948 |
return (err == -EEXIST ? 0 : err); |
949 |
} |
950 |
|
951 |
static void |
952 |
iterator_free(struct iterator *itr)
|
953 |
{ |
954 |
free(itr->targets); |
955 |
memset(itr, 0, sizeof(*itr)); |
956 |
} |
957 |
|
958 |
static void |
959 |
vhd_util_scan_add_parent(struct iterator *itr,
|
960 |
vhd_context_t *vhd, struct vhd_image *image)
|
961 |
{ |
962 |
int err;
|
963 |
uint8_t type; |
964 |
|
965 |
if (vhd_parent_raw(vhd))
|
966 |
type = target_volume(image->target->type) ? |
967 |
VHD_TYPE_RAW_VOLUME : VHD_TYPE_RAW_FILE; |
968 |
else
|
969 |
type = target_volume(image->target->type) ? |
970 |
VHD_TYPE_VHD_VOLUME : VHD_TYPE_VHD_FILE; |
971 |
|
972 |
err = iterator_add(itr, image->parent, type); |
973 |
if (err)
|
974 |
vhd_util_scan_error(image->parent, err); |
975 |
} |
976 |
|
977 |
static int |
978 |
vhd_util_scan_targets(int cnt, struct target *targets) |
979 |
{ |
980 |
int ret, err;
|
981 |
vhd_context_t vhd; |
982 |
struct iterator itr;
|
983 |
struct target *target;
|
984 |
struct vhd_image image;
|
985 |
|
986 |
ret = 0;
|
987 |
err = 0;
|
988 |
|
989 |
err = iterator_init(&itr, cnt, targets); |
990 |
if (err)
|
991 |
return err;
|
992 |
|
993 |
while ((target = iterator_next(&itr))) {
|
994 |
memset(&vhd, 0, sizeof(vhd)); |
995 |
memset(&image, 0, sizeof(image)); |
996 |
|
997 |
image.target = target; |
998 |
|
999 |
err = vhd_util_scan_open(&vhd, &image); |
1000 |
if (err) {
|
1001 |
ret = -EAGAIN; |
1002 |
goto end;
|
1003 |
} |
1004 |
|
1005 |
err = vhd_util_scan_get_size(&vhd, &image); |
1006 |
if (err) {
|
1007 |
ret = -EAGAIN; |
1008 |
image.message = "getting physical size";
|
1009 |
image.error = err; |
1010 |
goto end;
|
1011 |
} |
1012 |
|
1013 |
err = vhd_util_scan_get_hidden(&vhd, &image); |
1014 |
if (err) {
|
1015 |
ret = -EAGAIN; |
1016 |
image.message = "checking 'hidden' field";
|
1017 |
image.error = err; |
1018 |
goto end;
|
1019 |
} |
1020 |
|
1021 |
if (flags & VHD_SCAN_MARKERS) {
|
1022 |
err = vhd_util_scan_get_marker(&vhd, &image); |
1023 |
if (err) {
|
1024 |
ret = -EAGAIN; |
1025 |
image.message = "checking marker";
|
1026 |
image.error = err; |
1027 |
goto end;
|
1028 |
} |
1029 |
} |
1030 |
|
1031 |
if (vhd.footer.type == HD_TYPE_DIFF) {
|
1032 |
err = vhd_util_scan_get_parent(&vhd, &image); |
1033 |
if (err) {
|
1034 |
ret = -EAGAIN; |
1035 |
image.message = "getting parent";
|
1036 |
image.error = err; |
1037 |
goto end;
|
1038 |
} |
1039 |
} |
1040 |
|
1041 |
end:
|
1042 |
vhd_util_scan_print_image(&image); |
1043 |
|
1044 |
if (flags & VHD_SCAN_PARENTS && image.parent)
|
1045 |
vhd_util_scan_add_parent(&itr, &vhd, &image); |
1046 |
|
1047 |
if (vhd.file)
|
1048 |
vhd_close(&vhd); |
1049 |
if (image.name != target->name)
|
1050 |
free(image.name); |
1051 |
free(image.parent); |
1052 |
|
1053 |
if (err && !(flags & VHD_SCAN_NOFAIL))
|
1054 |
break;
|
1055 |
} |
1056 |
|
1057 |
iterator_free(&itr); |
1058 |
|
1059 |
if (flags & VHD_SCAN_NOFAIL)
|
1060 |
return ret;
|
1061 |
|
1062 |
return err;
|
1063 |
} |
1064 |
|
1065 |
static int |
1066 |
vhd_util_scan_targets_pretty(int cnt, struct target *targets) |
1067 |
{ |
1068 |
int err;
|
1069 |
|
1070 |
err = vhd_util_scan_pretty_allocate_list(cnt); |
1071 |
if (err) {
|
1072 |
printf("scan failed: no memory\n");
|
1073 |
return -ENOMEM;
|
1074 |
} |
1075 |
|
1076 |
err = vhd_util_scan_targets(cnt, targets); |
1077 |
|
1078 |
vhd_util_scan_pretty_print_images(); |
1079 |
vhd_util_scan_pretty_free_list(); |
1080 |
|
1081 |
return ((flags & VHD_SCAN_NOFAIL) ? 0 : err); |
1082 |
} |
1083 |
|
1084 |
static int |
1085 |
vhd_util_scan_find_file_targets(int cnt, char **names, |
1086 |
const char *filter, |
1087 |
struct target **_targets, int *_total) |
1088 |
{ |
1089 |
glob_t g; |
1090 |
struct target *targets;
|
1091 |
int i, globs, err, total;
|
1092 |
|
1093 |
total = cnt; |
1094 |
globs = 0;
|
1095 |
*_total = 0;
|
1096 |
*_targets = NULL;
|
1097 |
|
1098 |
memset(&g, 0, sizeof(g)); |
1099 |
|
1100 |
if (filter) {
|
1101 |
int gflags = ((flags & VHD_SCAN_FAST) ? GLOB_NOSORT : 0); |
1102 |
|
1103 |
errno = 0;
|
1104 |
err = glob(filter, gflags, vhd_util_scan_error, &g); |
1105 |
|
1106 |
switch (err) {
|
1107 |
case GLOB_NOSPACE:
|
1108 |
err = -ENOMEM; |
1109 |
break;
|
1110 |
case GLOB_ABORTED:
|
1111 |
err = -EIO; |
1112 |
break;
|
1113 |
case GLOB_NOMATCH:
|
1114 |
err = -errno; |
1115 |
break;
|
1116 |
} |
1117 |
|
1118 |
if (err) {
|
1119 |
vhd_util_scan_error(filter, err); |
1120 |
return err;
|
1121 |
} |
1122 |
|
1123 |
globs = g.gl_pathc; |
1124 |
total += globs; |
1125 |
} |
1126 |
|
1127 |
targets = calloc(total, sizeof(struct target)); |
1128 |
if (!targets) {
|
1129 |
err = -ENOMEM; |
1130 |
goto out;
|
1131 |
} |
1132 |
|
1133 |
for (i = 0; i < g.gl_pathc; i++) { |
1134 |
err = vhd_util_scan_init_file_target(targets + i, |
1135 |
g.gl_pathv[i], |
1136 |
VHD_TYPE_VHD_FILE); |
1137 |
if (err) {
|
1138 |
vhd_util_scan_error(g.gl_pathv[i], err); |
1139 |
if (!(flags & VHD_SCAN_NOFAIL))
|
1140 |
goto out;
|
1141 |
} |
1142 |
} |
1143 |
|
1144 |
for (i = 0; i + globs < total; i++) { |
1145 |
err = vhd_util_scan_init_file_target(targets + i + globs, |
1146 |
names[i], |
1147 |
VHD_TYPE_VHD_FILE); |
1148 |
if (err) {
|
1149 |
vhd_util_scan_error(names[i], err); |
1150 |
if (!(flags & VHD_SCAN_NOFAIL))
|
1151 |
goto out;
|
1152 |
} |
1153 |
} |
1154 |
|
1155 |
err = 0;
|
1156 |
*_total = total; |
1157 |
*_targets = targets; |
1158 |
|
1159 |
out:
|
1160 |
if (err)
|
1161 |
free(targets); |
1162 |
if (filter)
|
1163 |
globfree(&g); |
1164 |
|
1165 |
return err;
|
1166 |
} |
1167 |
|
1168 |
static inline void |
1169 |
swap_volume(struct lv *lvs, int dst, int src) |
1170 |
{ |
1171 |
struct lv copy, *ldst, *lsrc;
|
1172 |
|
1173 |
if (dst == src)
|
1174 |
return;
|
1175 |
|
1176 |
lsrc = lvs + src; |
1177 |
ldst = lvs + dst; |
1178 |
|
1179 |
memcpy(©, ldst, sizeof(copy));
|
1180 |
memcpy(ldst, lsrc, sizeof(*ldst));
|
1181 |
memcpy(lsrc, ©, sizeof(copy));
|
1182 |
} |
1183 |
|
1184 |
static int |
1185 |
vhd_util_scan_sort_volumes(struct lv *lvs, int cnt, |
1186 |
const char *filter, int *_matches) |
1187 |
{ |
1188 |
struct lv *lv;
|
1189 |
int i, err, matches;
|
1190 |
|
1191 |
matches = 0;
|
1192 |
*_matches = 0;
|
1193 |
|
1194 |
if (!filter)
|
1195 |
return 0; |
1196 |
|
1197 |
for (i = 0; i < cnt; i++) { |
1198 |
lv = lvs + i; |
1199 |
|
1200 |
err = fnmatch(filter, lv->name, FNM_PATHNAME); |
1201 |
if (err) {
|
1202 |
if (err != FNM_NOMATCH) {
|
1203 |
EPRINTF("fnmatch failed: '%s', '%s'\n",
|
1204 |
filter, lv->name); |
1205 |
vhd_util_scan_error(lv->name, err); |
1206 |
if (!(flags & VHD_SCAN_NOFAIL))
|
1207 |
return err;
|
1208 |
} |
1209 |
|
1210 |
continue;
|
1211 |
} |
1212 |
|
1213 |
swap_volume(lvs, matches++, i); |
1214 |
} |
1215 |
|
1216 |
*_matches = matches; |
1217 |
return 0; |
1218 |
} |
1219 |
|
1220 |
static int |
1221 |
vhd_util_scan_find_volume_targets(int cnt, char **names, |
1222 |
const char *volume, const char *filter, |
1223 |
struct target **_targets, int *_total) |
1224 |
{ |
1225 |
struct target *targets;
|
1226 |
int i, err, total, matches;
|
1227 |
|
1228 |
*_total = 0;
|
1229 |
*_targets = NULL;
|
1230 |
targets = NULL;
|
1231 |
|
1232 |
err = lvm_scan_vg(volume, &vg); |
1233 |
if (err)
|
1234 |
return err;
|
1235 |
|
1236 |
err = vhd_util_scan_sort_volumes(vg.lvs, vg.lv_cnt, |
1237 |
filter, &matches); |
1238 |
if (err)
|
1239 |
goto out;
|
1240 |
|
1241 |
total = matches; |
1242 |
for (i = 0; i < cnt; i++) { |
1243 |
err = vhd_util_scan_sort_volumes(vg.lvs + total, |
1244 |
vg.lv_cnt - total, |
1245 |
names[i], &matches); |
1246 |
if (err)
|
1247 |
goto out;
|
1248 |
|
1249 |
total += matches; |
1250 |
} |
1251 |
|
1252 |
targets = calloc(total, sizeof(struct target)); |
1253 |
if (!targets) {
|
1254 |
err = -ENOMEM; |
1255 |
goto out;
|
1256 |
} |
1257 |
|
1258 |
for (i = 0; i < total; i++) { |
1259 |
err = vhd_util_scan_init_volume_target(targets + i, |
1260 |
vg.lvs + i, |
1261 |
VHD_TYPE_VHD_VOLUME); |
1262 |
if (err) {
|
1263 |
vhd_util_scan_error(vg.lvs[i].name, err); |
1264 |
if (!(flags & VHD_SCAN_NOFAIL))
|
1265 |
goto out;
|
1266 |
} |
1267 |
} |
1268 |
|
1269 |
err = 0;
|
1270 |
*_total = total; |
1271 |
*_targets = targets; |
1272 |
|
1273 |
out:
|
1274 |
if (err)
|
1275 |
free(targets); |
1276 |
return err;
|
1277 |
} |
1278 |
|
1279 |
static int |
1280 |
vhd_util_scan_find_targets(int cnt, char **names, |
1281 |
const char *volume, const char *filter, |
1282 |
struct target **targets, int *total) |
1283 |
{ |
1284 |
if (flags & VHD_SCAN_VOLUME)
|
1285 |
return vhd_util_scan_find_volume_targets(cnt, names,
|
1286 |
volume, filter, |
1287 |
targets, total); |
1288 |
return vhd_util_scan_find_file_targets(cnt, names,
|
1289 |
filter, targets, total); |
1290 |
} |
1291 |
|
1292 |
int
|
1293 |
vhd_util_scan(int argc, char **argv) |
1294 |
{ |
1295 |
int c, err, cnt;
|
1296 |
char *filter, *volume;
|
1297 |
struct target *targets;
|
1298 |
|
1299 |
cnt = 0;
|
1300 |
err = 0;
|
1301 |
flags = 0;
|
1302 |
filter = NULL;
|
1303 |
volume = NULL;
|
1304 |
targets = NULL;
|
1305 |
|
1306 |
optind = 0;
|
1307 |
while ((c = getopt(argc, argv, "m:fcl:pavMh")) != -1) { |
1308 |
switch (c) {
|
1309 |
case 'm': |
1310 |
filter = optarg; |
1311 |
break;
|
1312 |
case 'f': |
1313 |
flags |= VHD_SCAN_FAST; |
1314 |
break;
|
1315 |
case 'c': |
1316 |
flags |= VHD_SCAN_NOFAIL; |
1317 |
break;
|
1318 |
case 'l': |
1319 |
volume = optarg; |
1320 |
flags |= VHD_SCAN_VOLUME; |
1321 |
break;
|
1322 |
case 'p': |
1323 |
flags |= VHD_SCAN_PRETTY; |
1324 |
break;
|
1325 |
case 'a': |
1326 |
flags |= VHD_SCAN_PARENTS; |
1327 |
break;
|
1328 |
case 'v': |
1329 |
flags |= VHD_SCAN_VERBOSE; |
1330 |
break;
|
1331 |
case 'M': |
1332 |
flags |= VHD_SCAN_MARKERS; |
1333 |
break;
|
1334 |
case 'h': |
1335 |
goto usage;
|
1336 |
default:
|
1337 |
err = -EINVAL; |
1338 |
goto usage;
|
1339 |
} |
1340 |
} |
1341 |
|
1342 |
if (!filter && argc - optind == 0) { |
1343 |
err = -EINVAL; |
1344 |
goto usage;
|
1345 |
} |
1346 |
|
1347 |
if (flags & VHD_SCAN_PRETTY)
|
1348 |
flags &= ~VHD_SCAN_FAST; |
1349 |
|
1350 |
err = vhd_util_scan_find_targets(argc - optind, argv + optind, |
1351 |
volume, filter, &targets, &cnt); |
1352 |
if (err) {
|
1353 |
printf("scan failed: %d\n", err);
|
1354 |
return err;
|
1355 |
} |
1356 |
|
1357 |
if (!cnt)
|
1358 |
return 0; |
1359 |
|
1360 |
if (flags & VHD_SCAN_PRETTY)
|
1361 |
err = vhd_util_scan_targets_pretty(cnt, targets); |
1362 |
else
|
1363 |
err = vhd_util_scan_targets(cnt, targets); |
1364 |
|
1365 |
free(targets); |
1366 |
lvm_free_vg(&vg); |
1367 |
|
1368 |
return ((flags & VHD_SCAN_NOFAIL) ? 0 : err); |
1369 |
|
1370 |
usage:
|
1371 |
printf("usage: [OPTIONS] FILES\n"
|
1372 |
"options: [-m match filter] [-f fast] [-c continue on failure] "
|
1373 |
"[-l LVM volume] [-p pretty print] [-a scan parents] "
|
1374 |
"[-v verbose] [-h help] [-M show markers]\n");
|
1375 |
return err;
|
1376 |
} |