LCOV - code coverage report
Current view: top level - vhd/lib - vhd-util-scan.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 615 0.0 %
Date: 2026-02-26 14:46:47 Functions: 0 40 0.0 %
Branches: 0 382 0.0 %

           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, &copy, &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(&copy, ldst, sizeof(copy));
    1220                 :            :         memcpy(ldst, lsrc, sizeof(*ldst));
    1221                 :            :         memcpy(lsrc, &copy, 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                 :            : }

Generated by: LCOV version 1.13