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

Generated by: LCOV version 1.13