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