~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to tools/blktap2/vhd/lib/vhd-util-scan.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

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