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