[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH] inspection: Handle MD device s in fstab



This patch fixes inspection when fstab contains devices md devices
specified as /dev/mdN. The appliance creates these devices without reference to
the guest's mdadm.conf so, for e.g. /dev/md0 in the guest will often be created
as /dev/md127 in the appliance. With this patch, we match the uuids of detected
md devices against uuids specified in mdadm.conf, and map them appropriately
when we encounter them in fstab.

The test in this patch also checks that devices specified by their md name, e.g.
/dev/md/boot, work correctly, although the patch isn't required for devices
specified this way.
---
 regressions/Makefile.am              |    1 +
 regressions/test-inspect-fstab-md.sh |   65 ++++++
 src/inspect.c                        |   22 ++-
 src/inspect_fs_unix.c                |  411 ++++++++++++++++++++++++++++++----
 4 files changed, 456 insertions(+), 43 deletions(-)
 create mode 100755 regressions/test-inspect-fstab-md.sh

diff --git a/regressions/Makefile.am b/regressions/Makefile.am
index c75d54a..e7ebc6f 100644
--- a/regressions/Makefile.am
+++ b/regressions/Makefile.am
@@ -44,6 +44,7 @@ TESTS = \
 	test-guestfish-escapes.sh \
 	test-guestfish-tilde.sh \
 	test-inspect-fstab.sh \
+	test-inspect-fstab-md.sh \
 	test-launch-race.pl \
 	test-list-filesystems.sh \
 	test-list-md-devices.sh \
diff --git a/regressions/test-inspect-fstab-md.sh b/regressions/test-inspect-fstab-md.sh
new file mode 100755
index 0000000..d541ef4
--- /dev/null
+++ b/regressions/test-inspect-fstab-md.sh
@@ -0,0 +1,65 @@
+#!/bin/bash -
+# libguestfs
+# Copyright (C) 2011 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Test the handling of MD devices specified in /etc/fstab
+
+set -e
+export LANG=C
+
+guestfish=../fish/guestfish
+
+rm -f test1.img test.fstab test.output
+
+# First, test the regular fedora image, which specifies /boot as /dev/md0
+cp ../images/fedora-md1.img test1.img
+cp ../images/fedora-md2.img test2.img
+
+$guestfish -i test[12].img <<'EOF' | sort > test.output
+  exists /boot/grub/grub.conf
+EOF
+
+if [ "$(cat test.output)" != "true" ]; then
+    echo "$0: /boot not correctly mounted (/dev/md0)"
+    exit 1
+fi
+
+# Test inspection when /boot is specfied as /dev/md/boot
+cat <<'EOF' > test.fstab
+/dev/VG/Root / ext2 default 0 0
+/dev/md/boot /boot ext2 default 0 0
+EOF
+
+$guestfish -a test1.img -a test2.img <<'EOF'
+  run
+  mount-options "" /dev/VG/Root /
+  upload test.fstab /etc/fstab
+EOF
+
+$guestfish -i test[12].img <<'EOF' | sort > test.output
+  exists /boot/grub/grub.conf
+EOF
+
+if [ "$(cat test.output)" != "true" ]; then
+    echo "$0: error: /boot not correctly mounted (/dev/md/boot)"
+    cat test.output
+    exit 1
+fi
+
+rm test.fstab
+rm test[12].img
+rm test.output
diff --git a/src/inspect.c b/src/inspect.c
index 1b41be5..f9b8298 100644
--- a/src/inspect.c
+++ b/src/inspect.c
@@ -61,8 +61,7 @@ guestfs__inspect_os (guestfs_h *g)
    * information to the handle.
    */
   /* Look to see if any devices directly contain filesystems (RHBZ#590167). */
-  char **devices;
-  devices = guestfs_list_devices (g);
+  char **devices = guestfs_list_devices (g);
   if (devices == NULL)
     return NULL;
 
@@ -77,8 +76,7 @@ guestfs__inspect_os (guestfs_h *g)
   guestfs___free_string_list (devices);
 
   /* Look at all partitions. */
-  char **partitions;
-  partitions = guestfs_list_partitions (g);
+  char **partitions = guestfs_list_partitions (g);
   if (partitions == NULL) {
     guestfs___free_inspect_info (g);
     return NULL;
@@ -93,6 +91,22 @@ guestfs__inspect_os (guestfs_h *g)
   }
   guestfs___free_string_list (partitions);
 
+  /* Look at MD devices. */
+  char **mds = guestfs_list_md_devices (g);
+  if (mds == NULL) {
+    guestfs___free_inspect_info (g);
+    return NULL;
+  }
+
+  for (i = 0; mds[i] != NULL; ++i) {
+    if (guestfs___check_for_filesystem_on (g, mds[i], 0, i+1) == -1) {
+      guestfs___free_string_list (mds);
+      guestfs___free_inspect_info (g);
+      return NULL;
+    }
+  }
+  guestfs___free_string_list (mds);
+
   /* Look at all LVs. */
   if (guestfs___feature_available (g, "lvm2")) {
     char **lvs;
diff --git a/src/inspect_fs_unix.c b/src/inspect_fs_unix.c
index 6b1a05b..08efdf6 100644
--- a/src/inspect_fs_unix.c
+++ b/src/inspect_fs_unix.c
@@ -38,6 +38,8 @@
 #include "c-ctype.h"
 #include "ignore-value.h"
 #include "xstrtol.h"
+#include "hash.h"
+#include "hash-pjw.h"
 
 #include "guestfs.h"
 #include "guestfs-internal.h"
@@ -65,6 +67,7 @@ static pcre *re_major_minor;
 static pcre *re_aug_seq;
 static pcre *re_xdev;
 static pcre *re_cciss;
+static pcre *re_mdN;
 static pcre *re_first_partition;
 static pcre *re_freebsd;
 static pcre *re_netbsd;
@@ -110,6 +113,7 @@ compile_regexps (void)
   COMPILE (re_aug_seq, "/\\d+$", 0);
   COMPILE (re_xdev, "^/dev/(h|s|v|xv)d([a-z]+)(\\d*)$", 0);
   COMPILE (re_cciss, "^/dev/(cciss/c\\d+d\\d+)(?:p(\\d+))?$", 0);
+  COMPILE (re_mdN, "^(/dev/md\\d+)$", 0);
   COMPILE (re_freebsd, "^/dev/ad(\\d+)s(\\d+)([a-z])$", 0);
   COMPILE (re_netbsd, "^NetBSD (\\d+)\\.(\\d+)", 0);
 }
@@ -131,6 +135,7 @@ free_regexps (void)
   pcre_free (re_aug_seq);
   pcre_free (re_xdev);
   pcre_free (re_cciss);
+  pcre_free (re_mdN);
   pcre_free (re_freebsd);
   pcre_free (re_netbsd);
 }
@@ -141,9 +146,23 @@ static int check_hostname_redhat (guestfs_h *g, struct inspect_fs *fs);
 static int check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs);
 static int check_fstab (guestfs_h *g, struct inspect_fs *fs);
 static int add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
-                            const char *spec, const char *mp);
-static char *resolve_fstab_device (guestfs_h *g, const char *spec);
-static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename, int (*f) (guestfs_h *, struct inspect_fs *));
+                            const char *spec, const char *mp,
+                            Hash_table *md_map);
+static char *resolve_fstab_device (guestfs_h *g, const char *spec,
+                                   Hash_table *md_map);
+static int inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char **configfiles, int (*f) (guestfs_h *, struct inspect_fs *));
+
+static size_t uuid_hash(const void *x, size_t table_size);
+static bool uuid_cmp(const void *x, const void *y);
+static void md_uuid_free(void *x);
+static bool parse_uuid(const char *str, uint32_t *uuid);
+
+static size_t mdadm_app_hash(const void *x, size_t table_size);
+static bool mdadm_app_cmp(const void *x, const void *y);
+static void mdadm_app_free(void *x);
+
+static bool map_app_md_devices (guestfs_h *g, Hash_table **map);
+static bool map_md_devices(guestfs_h *g, Hash_table **map);
 
 /* Set fs->product_name to the first line of the release file. */
 static int
@@ -446,7 +465,8 @@ guestfs___check_linux_root (guestfs_h *g, struct inspect_fs *fs)
    * which filesystems are used by the operating system and how they
    * are mounted.
    */
-  if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1)
+  const char *configfiles[] = { "/etc/fstab", "/etc/mdadm.conf", NULL };
+  if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
     return -1;
 
   /* Determine hostname. */
@@ -479,7 +499,8 @@ guestfs___check_freebsd_root (guestfs_h *g, struct inspect_fs *fs)
   check_architecture (g, fs);
 
   /* We already know /etc/fstab exists because it's part of the test above. */
-  if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1)
+  const char *configfiles[] = { "/etc/fstab", NULL };
+  if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
     return -1;
 
   /* Determine hostname. */
@@ -520,7 +541,8 @@ guestfs___check_netbsd_root (guestfs_h *g, struct inspect_fs *fs)
   check_architecture (g, fs);
 
   /* We already know /etc/fstab exists because it's part of the test above. */
-  if (inspect_with_augeas (g, fs, "/etc/fstab", check_fstab) == -1)
+  const char *configfiles[] = { "/etc/fstab", NULL };
+  if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
     return -1;
 
   /* Determine hostname. */
@@ -583,7 +605,8 @@ check_hostname_unix (guestfs_h *g, struct inspect_fs *fs)
         return -1;
     }
     else if (guestfs_is_file (g, "/etc/sysconfig/network")) {
-      if (inspect_with_augeas (g, fs, "/etc/sysconfig/network",
+      const char *configfiles[] = { "/etc/sysconfig/network", NULL };
+      if (inspect_with_augeas (g, fs, configfiles,
                                check_hostname_redhat) == -1)
         return -1;
     }
@@ -684,14 +707,15 @@ check_hostname_freebsd (guestfs_h *g, struct inspect_fs *fs)
 static int
 check_fstab (guestfs_h *g, struct inspect_fs *fs)
 {
+  Hash_table *md_map;
+  if (!map_md_devices (g, &md_map)) return -1;
+
   char **lines = guestfs_aug_ls (g, "/files/etc/fstab");
-  if (lines == NULL)
-    return -1;
+  if (lines == NULL) goto error;
 
   if (lines[0] == NULL) {
     error (g, _("could not parse /etc/fstab or empty file"));
-    guestfs___free_string_list (lines);
-    return -1;
+    goto error;
   }
 
   size_t i;
@@ -703,32 +727,31 @@ check_fstab (guestfs_h *g, struct inspect_fs *fs)
     if (match (g, lines[i], re_aug_seq)) {
       snprintf (augpath, sizeof augpath, "%s/spec", lines[i]);
       char *spec = guestfs_aug_get (g, augpath);
-      if (spec == NULL) {
-        guestfs___free_string_list (lines);
-        return -1;
-      }
+      if (spec == NULL) goto error;
 
       snprintf (augpath, sizeof augpath, "%s/file", lines[i]);
       char *mp = guestfs_aug_get (g, augpath);
       if (mp == NULL) {
-        guestfs___free_string_list (lines);
         free (spec);
-        return -1;
+        goto error;
       }
 
-      int r = add_fstab_entry (g, fs, spec, mp);
+      int r = add_fstab_entry (g, fs, spec, mp, md_map);
       free (spec);
       free (mp);
 
-      if (r == -1) {
-        guestfs___free_string_list (lines);
-        return -1;
-      }
+      if (r == -1) goto error;
     }
   }
 
+  hash_free (md_map);
   guestfs___free_string_list (lines);
   return 0;
+
+error:
+  hash_free (md_map);
+  if (lines) guestfs___free_string_list (lines);
+  return -1;
 }
 
 /* Add a filesystem and possibly a mountpoint entry for
@@ -741,7 +764,7 @@ check_fstab (guestfs_h *g, struct inspect_fs *fs)
  */
 static int
 add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
-                 const char *spec, const char *mp)
+                 const char *spec, const char *mp, Hash_table *md_map)
 {
   /* Ignore certain mountpoints. */
   if (STRPREFIX (mp, "/dev/") ||
@@ -773,7 +796,7 @@ add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
     device = safe_strdup (g, fs->device);
   else if (STRPREFIX (spec, "/dev/"))
     /* Resolve guest block device names. */
-    device = resolve_fstab_device (g, spec);
+    device = resolve_fstab_device (g, spec, md_map);
 
   /* If we haven't resolved the device successfully by this point,
    * we don't care, just ignore it.
@@ -810,6 +833,273 @@ add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
   return 0;
 }
 
+typedef struct md_uuid {
+  uint32_t uuid[4];
+  char *path;
+} md_uuid;
+
+/* Compute a uuid hash as a simple xor of of its 4 32bit components */
+static size_t
+uuid_hash(const void *x, size_t table_size)
+{
+  const md_uuid *a = x;
+
+  size_t h = a->uuid[0];
+  for (size_t i = 1; i < 4; i++) {
+    h ^= a->uuid[i];
+  }
+
+  return h % table_size;
+}
+
+static bool
+uuid_cmp(const void *x, const void *y)
+{
+  const md_uuid *a = x;
+  const md_uuid *b = y;
+
+  for (size_t i = 0; i < 1; i++) {
+    if (a->uuid[i] != b->uuid[i]) return false;
+  }
+
+  return true;
+}
+
+static void
+md_uuid_free(void *x)
+{
+  md_uuid *a = x;
+  free(a->path);
+  free(a);
+}
+
+/* Taken from parse_uuid in mdadm */
+static bool
+parse_uuid(const char *str, uint32_t *uuid)
+{
+  for (size_t i = 0; i < 4; i++) uuid[i] = 0;
+
+  int hit = 0; /* number of Hex digIT */
+  char c;
+  while ((c = *str++)) {
+    int n;
+    if (c >= '0' && c <= '9')
+      n = c - '0';
+    else if (c >= 'a' && c <= 'f')
+      n = 10 + c - 'a';
+    else if (c >= 'A' && c <= 'F')
+      n = 10 + c - 'A';
+    else if (strchr(":. -", c))
+      continue;
+    else return false;
+
+    if (hit < 32) {
+      uuid[hit / 8] <<= 4;
+      uuid[hit / 8] += n;
+    }
+    hit++;
+  }
+  if (hit == 32) return true;
+
+  return false;
+}
+
+/* Create a mapping of uuids to appliance md device names */
+static bool
+map_app_md_devices (guestfs_h *g, Hash_table **map)
+{
+  int ret = false;
+
+  char **mds = NULL;
+
+  /* A hash mapping uuids to md device names */
+  *map = hash_initialize(16, NULL, uuid_hash, uuid_cmp, md_uuid_free);
+  if (*map == NULL) goto error;
+
+  mds = guestfs_list_md_devices(g);
+  if (mds == NULL) goto error;
+
+  for (char **md = mds; *md != NULL; md++) {
+    char **detail = guestfs_mdadm_detail(g, *md);
+    if (detail == NULL) goto error;
+
+    /* Iterate over keys until we find uuid */
+    char **i;
+    for (i = detail; *i != NULL; i += 2) {
+      if (STREQ(*i, "uuid")) break;
+    }
+
+    /* We found it */
+    if (*i) {
+      /* Next item is the uuid value */
+      i++;
+
+      md_uuid *entry = safe_malloc(g, sizeof(md_uuid));
+      entry->path = safe_strdup(g, *md);
+
+      if (!parse_uuid(*i, entry->uuid)) {
+        /* Invalid UUID is weird, but not fatal. */
+        warning(g, "inspect-os: guestfs_mdadm_detail returned invalid "
+                   "uuid for %s: %s", *md, *i);
+        guestfs___free_string_list(detail);
+        md_uuid_free(entry);
+        continue;
+      }
+
+      const void *matched = NULL;
+      switch (hash_insert0(*map, entry, &matched)) {
+        case -1:
+          g->abort_cb();
+
+        case 0:
+          /* Duplicate uuid in for md device is weird, but not fatal. */
+          warning(g, "inspect-os: md devices %s and %s have the same uuid",
+                  ((md_uuid *)matched)->path, entry->path);
+          md_uuid_free(entry);
+        
+        default:
+          ;;
+      }
+    }
+
+    guestfs___free_string_list(detail);
+  }
+
+  guestfs___free_string_list(mds);
+
+  return true;
+
+error:
+  hash_free(*map); *map = NULL;
+  guestfs___free_string_list(mds);
+
+  return false;
+}
+
+typedef struct {
+  char *mdadm;
+  char *app;
+} mdadm_app;
+
+static size_t
+mdadm_app_hash(const void *x, size_t table_size)
+{
+  const mdadm_app *a = x;
+  return hash_pjw(a->mdadm, table_size);
+}
+
+static bool
+mdadm_app_cmp(const void *x, const void *y)
+{
+  const mdadm_app *a = x;
+  const mdadm_app *b = y;
+
+  return strcmp(a->mdadm, b->mdadm) == 0;
+}
+
+static void
+mdadm_app_free(void *x)
+{
+  mdadm_app *a = x;
+  free(a->mdadm);
+  free(a->app);
+  free(a);
+}
+
+/* Get a map of md device names in mdadm.conf to their device names in the
+ * appliance */
+static bool
+map_md_devices(guestfs_h *g, Hash_table **map)
+{
+  Hash_table *app_map = NULL;
+  char **matches = NULL;
+  char *dev_path = NULL;
+  char *uuid_path = NULL;
+  *map = NULL;
+
+  /* Get a map of md device uuids to their device names in the appliance */
+  if (!map_app_md_devices(g, &app_map)) goto error;
+
+  *map = hash_initialize(16, NULL, mdadm_app_hash, mdadm_app_cmp,
+                                   mdadm_app_free);
+  if (!*map) goto error;
+
+  /* Get all arrays listed in mdadm.conf */
+  matches = guestfs_aug_match(g, "/files/etc/mdadm.conf/array");
+  if (!matches) goto error;
+
+  for (char **match = matches; *match != NULL; match++) {
+    /* Get device name and uuid for each array */
+    dev_path = safe_asprintf(g, "%s/devicename", *match);
+    uuid_path = safe_asprintf(g, "%s/uuid", *match);
+
+    char *dev = guestfs_aug_get(g, dev_path);
+    if (!dev) goto error;
+
+    char *uuid = guestfs_aug_get(g, uuid_path);
+    if (!uuid) {
+      free(dev);
+      goto error;
+    }
+
+    /* Parse the uuid into an md_uuid structure so we can look it up in the
+     * uuid->appliance device map */
+    md_uuid mdadm;
+    mdadm.path = dev;
+    if (!parse_uuid(uuid, mdadm.uuid)) {
+      /* Invalid uuid. Weird, but not fatal. */
+      warning(g, "inspect-os: mdadm.conf contains invalid uuid for %s: %s",
+                 dev, uuid);
+      free(dev);
+      free(uuid);
+      continue;
+    }
+    free(uuid);
+
+    /* If there's a corresponding uuid in the appliance, create a new
+     * entry in the transitive map */
+    md_uuid *app = hash_lookup(app_map, &mdadm);
+    if (app) {
+      mdadm_app *entry = safe_malloc(g, sizeof(mdadm_app));
+      entry->mdadm = dev;
+      entry->app = safe_strdup(g, app->path);
+
+      switch (hash_insert0(*map, entry, NULL)) {
+        case -1:
+          g->abort_cb();
+
+        case 0:
+          /* Duplicate uuid in for md device is weird, but not fatal. */
+          warning(g, "inspect-os: mdadm.conf contains multiple entries for %s",
+                  app->path);
+          mdadm_app_free(entry);
+          continue;
+
+        default:
+          ;;
+      }
+    } else {
+      free(dev);
+    }
+  }
+
+  hash_free(app_map);
+  guestfs___free_string_list(matches);
+  free(dev_path);
+  free(uuid_path);
+
+  return true;
+
+error:
+  if (app_map) hash_free(app_map);
+  if (matches) guestfs___free_string_list(matches);
+  free(dev_path);
+  free(uuid_path);
+  if (*map) hash_free(*map);
+
+  return false;
+}
+
 /* Resolve block device name to the libguestfs device name, eg.
  * /dev/xvdb1 => /dev/vdb1; and /dev/mapper/VG-LV => /dev/VG/LV.  This
  * assumes that disks were added in the same order as they appear to
@@ -817,7 +1107,7 @@ add_fstab_entry (guestfs_h *g, struct inspect_fs *fs,
  * anything we don't recognize unchanged.
  */
 static char *
-resolve_fstab_device (guestfs_h *g, const char *spec)
+resolve_fstab_device (guestfs_h *g, const char *spec, Hash_table *md_map)
 {
   char *device = NULL;
   char *type, *slice, *disk, *part;
@@ -912,6 +1202,13 @@ resolve_fstab_device (guestfs_h *g, const char *spec)
     free (part);
     guestfs___free_string_list (devices);
   }
+  else if ((disk = match1 (g, spec, re_mdN)) != NULL) {
+    mdadm_app entry;
+    entry.mdadm = disk;
+
+    mdadm_app *app = hash_lookup (md_map, &entry);
+    if (app) device = safe_strdup (g, app->app);
+  }
   else if (match3 (g, spec, re_freebsd, &disk, &slice, &part)) {
     /* FreeBSD disks are organized quite differently.  See:
      * http://www.freebsd.org/doc/handbook/disk-organization.html
@@ -946,18 +1243,23 @@ resolve_fstab_device (guestfs_h *g, const char *spec)
  * Augeas is closed.
  */
 static int
-inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename,
+inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs,
+                     const char **configfiles,
                      int (*f) (guestfs_h *, struct inspect_fs *))
 {
-  /* Security: Refuse to do this if filename is too large. */
-  int64_t size = guestfs_filesize (g, filename);
-  if (size == -1)
-    /* guestfs_filesize failed and has already set error in handle */
-    return -1;
-  if (size > MAX_AUGEAS_FILE_SIZE) {
-    error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
-           filename, size);
-    return -1;
+  /* Security: Refuse to do this if a config file is too large. */
+  for (const char **i = configfiles; *i != NULL; i++) {
+    if (guestfs_exists(g, *i) == 0) continue;
+
+    int64_t size = guestfs_filesize (g, *i);
+    if (size == -1)
+      /* guestfs_filesize failed and has already set error in handle */
+      return -1;
+    if (size > MAX_AUGEAS_FILE_SIZE) {
+      error (g, _("size of %s is unreasonably large (%" PRIi64 " bytes)"),
+             *i, size);
+      return -1;
+    }
   }
 
   /* If !feature_available (g, "augeas") then the next call will fail.
@@ -970,11 +1272,42 @@ inspect_with_augeas (guestfs_h *g, struct inspect_fs *fs, const char *filename,
   int r = -1;
 
   /* Tell Augeas to only load one file (thanks Raphaël Pinson). */
-  char buf[strlen (filename) + 64];
-  snprintf (buf, strlen (filename) + 64, "/augeas/load//incl[. != \"%s\"]",
-            filename);
-  if (guestfs_aug_rm (g, buf) == -1)
+#define AUGEAS_LOAD "/augeas/load//incl[. != \""
+#define AUGEAS_LOAD_LEN (strlen(AUGEAS_LOAD))
+  size_t conflen = strlen(configfiles[0]);
+  size_t buflen = AUGEAS_LOAD_LEN + conflen + 1 /* Closing " */;
+  char *buf = safe_malloc(g, buflen + 2 /* Closing ] + null terminator */);
+
+  memcpy(buf, AUGEAS_LOAD, AUGEAS_LOAD_LEN);
+  memcpy(buf + AUGEAS_LOAD_LEN, configfiles[0], conflen);
+  buf[buflen - 1] = '"';
+#undef AUGEAS_LOAD_LEN
+#undef AUGEAS_LOAD
+
+#define EXCL " and . != \""
+#define EXCL_LEN (strlen(EXCL))
+  for (const char **i = &configfiles[1]; *i != NULL; i++) {
+    size_t orig_buflen = buflen;
+    conflen = strlen(*i);
+    buflen += EXCL_LEN + conflen + 1 /* Closing " */;
+    buf = safe_realloc(g, buf, buflen + 2 /* Closing ] + null terminator */);
+    char *s = buf + orig_buflen;
+
+    memcpy(s, EXCL, EXCL_LEN);
+    memcpy(s + EXCL_LEN, *i, conflen);
+    buf[buflen - 1] = '"';
+  }
+#undef EXCL_LEN
+#undef EXCL
+
+  buf[buflen] = ']';
+  buf[buflen + 1] = '\0';
+
+  if (guestfs_aug_rm (g, buf) == -1) {
+    free(buf);
     goto out;
+  }
+  free(buf);
 
   if (guestfs_aug_load (g) == -1)
     goto out;

[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]