#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"
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;
static void compile_regexps (void) __attribute__((constructor));
static void free_regexps (void) __attribute__((destructor));
COMPILE (re_scientific_linux_no_minor,
"Scientific Linux.*release (\\d+)", 0);
COMPILE (re_major_minor, "(\\d+)\\.(\\d+)", 0);
- COMPILE (re_aug_seq, "/\\d+$", 0);
- COMPILE (re_xdev, "^/dev/(?:h|s|v|xv)d([a-z]\\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);
}
static void
pcre_free (re_scientific_linux);
pcre_free (re_scientific_linux_no_minor);
pcre_free (re_major_minor);
- 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);
}
static void check_architecture (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 *));
+
+/* Hash structure for uuid->path lookups */
+typedef struct md_uuid {
+ uint32_t uuid[4];
+ char *path;
+} md_uuid;
+
+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 int parse_uuid(const char *str, uint32_t *uuid);
+
+/* Hash structure for path(mdadm)->path(appliance) lookup */
+typedef struct {
+ char *mdadm;
+ char *app;
+} mdadm_app;
+
+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 int map_app_md_devices (guestfs_h *g, Hash_table **map);
+static int map_md_devices(guestfs_h *g, Hash_table **map);
/* Set fs->product_name to the first line of the release file. */
static int
fs->distro = OS_DISTRO_MANDRIVA;
r = 1;
}
+ else if (fs->distro == 0 &&
+ STREQ (lines[i], "DISTRIB_ID=\"Mageia\"")) {
+ fs->distro = OS_DISTRO_MAGEIA;
+ r = 1;
+ }
else if (STRPREFIX (lines[i], "DISTRIB_RELEASE=")) {
char *major, *minor;
if (match2 (g, &lines[i][16], re_major_minor, &major, &minor)) {
if (guestfs___parse_major_minor (g, fs) == -1)
return -1;
}
+ else if (guestfs_exists (g, "/etc/ttylinux-target") > 0) {
+ fs->distro = OS_DISTRO_TTYLINUX;
+
+ fs->product_name = guestfs___first_line_of_file (g, "/etc/ttylinux-target");
+ if (fs->product_name == NULL)
+ return -1;
+
+ if (guestfs___parse_major_minor (g, fs) == -1)
+ return -1;
+ }
+ else if (guestfs_exists (g, "/etc/SuSE-release") > 0) {
+ fs->distro = OS_DISTRO_OPENSUSE;
+
+ if (parse_release_file (g, fs, "/etc/SuSE-release") == -1)
+ return -1;
+
+ if (guestfs___parse_major_minor (g, fs) == -1)
+ return -1;
+ }
+
skip_release_checks:;
* 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. */
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. */
return 0;
}
+/* The currently mounted device is maybe to be a *BSD root. */
+int
+guestfs___check_netbsd_root (guestfs_h *g, struct inspect_fs *fs)
+{
+
+ if (guestfs_exists (g, "/etc/release") > 0) {
+ char *major, *minor;
+ if (parse_release_file (g, fs, "/etc/release") == -1)
+ return -1;
+
+ if (match2 (g, fs->product_name, re_netbsd, &major, &minor)) {
+ fs->type = OS_TYPE_NETBSD;
+ fs->major_version = guestfs___parse_unsigned_int (g, major);
+ free (major);
+ if (fs->major_version == -1) {
+ free (minor);
+ return -1;
+ }
+ fs->minor_version = guestfs___parse_unsigned_int (g, minor);
+ free (minor);
+ if (fs->minor_version == -1)
+ return -1;
+ }
+ } else {
+ return -1;
+ }
+
+ /* Determine the architecture. */
+ check_architecture (g, fs);
+
+ /* We already know /etc/fstab exists because it's part of the test above. */
+ const char *configfiles[] = { "/etc/fstab", NULL };
+ if (inspect_with_augeas (g, fs, configfiles, check_fstab) == -1)
+ return -1;
+
+ /* Determine hostname. */
+ if (check_hostname_unix (g, fs) == -1)
+ return -1;
+
+ return 0;
+}
+
+/* The currently mounted device may be a Hurd root. Hurd has distros
+ * just like Linux.
+ */
+int
+guestfs___check_hurd_root (guestfs_h *g, struct inspect_fs *fs)
+{
+ int r;
+
+ fs->type = OS_TYPE_HURD;
+
+ if (guestfs_exists (g, "/etc/debian_version") > 0) {
+ fs->distro = OS_DISTRO_DEBIAN;
+
+ if (parse_release_file (g, fs, "/etc/debian_version") == -1)
+ return -1;
+
+ if (guestfs___parse_major_minor (g, fs) == -1)
+ return -1;
+ }
+
+ /* Arch Hurd also exists, but inconveniently it doesn't have
+ * the normal /etc/arch-release file. XXX
+ */
+
+ /* Determine the architecture. */
+ check_architecture (g, fs);
+
+ /* XXX Check for /etc/fstab. */
+
+ /* Determine hostname. */
+ if (check_hostname_unix (g, fs) == -1)
+ return -1;
+
+ return 0;
+}
+
static void
check_architecture (guestfs_h *g, struct inspect_fs *fs)
{
{
switch (fs->type) {
case OS_TYPE_LINUX:
+ case OS_TYPE_HURD:
/* Red Hat-derived would be in /etc/sysconfig/network, and
* Debian-derived in the file /etc/hostname. Very old Debian and
* SUSE use /etc/HOSTNAME. It's best to just look for each of
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;
}
break;
case OS_TYPE_FREEBSD:
+ case OS_TYPE_NETBSD:
/* /etc/rc.conf contains the hostname, but there is no Augeas lens
* for this file.
*/
static int
check_fstab (guestfs_h *g, struct inspect_fs *fs)
{
- char **lines = guestfs_aug_ls (g, "/files/etc/fstab");
- if (lines == NULL)
- return -1;
+ char **entries, **entry;
+ char augpath[256];
+ char *spec, *mp;
+ int r;
+
+ /* Generate a map of MD device paths listed in /etc/mdadm.conf to MD device
+ * paths in the guestfs appliance */
+ Hash_table *md_map;
+ if (map_md_devices (g, &md_map) == -1) return -1;
+
+ entries = guestfs_aug_match (g, "/files/etc/fstab/*[label() != '#comment']");
+ if (entries == NULL) goto error;
- if (lines[0] == NULL) {
+ if (entries[0] == NULL) {
error (g, _("could not parse /etc/fstab or empty file"));
- guestfs___free_string_list (lines);
- return -1;
+ goto error;
}
- size_t i;
- char augpath[256];
- for (i = 0; lines[i] != NULL; ++i) {
- /* Ignore comments. Only care about sequence lines which
- * match m{/\d+$}.
- */
- 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;
- }
-
- 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;
- }
+ for (entry = entries; *entry != NULL; entry++) {
+ snprintf (augpath, sizeof augpath, "%s/spec", *entry);
+ spec = guestfs_aug_get (g, augpath);
+ if (spec == NULL) goto error;
- int r = add_fstab_entry (g, fs, spec, mp);
+ snprintf (augpath, sizeof augpath, "%s/file", *entry);
+ mp = guestfs_aug_get (g, augpath);
+ if (mp == NULL) {
free (spec);
- free (mp);
-
- if (r == -1) {
- guestfs___free_string_list (lines);
- return -1;
- }
+ goto error;
}
+
+ r = add_fstab_entry (g, fs, spec, mp, md_map);
+ free (spec);
+ free (mp);
+
+ if (r == -1) goto error;
}
- guestfs___free_string_list (lines);
+ if (md_map) hash_free (md_map);
+ guestfs___free_string_list (entries);
return 0;
+
+error:
+ if (md_map) hash_free (md_map);
+ if (entries) guestfs___free_string_list (entries);
+ return -1;
}
/* Add a filesystem and possibly a mountpoint entry for
*/
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/") ||
else if (STRPREFIX (spec, "LABEL="))
device = guestfs_findfs_label (g, &spec[6]);
/* Ignore "/.swap" (Pardus) and pseudo-devices like "tmpfs". */
+ else if (STREQ (spec, "/dev/root"))
+ /* Resolve /dev/root to the current device. */
+ 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.
return 0;
}
+/* 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 int
+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 0;
+
+ return -1;
+}
+
+/* Create a mapping of uuids to appliance md device names */
+static int
+map_app_md_devices (guestfs_h *g, Hash_table **map)
+{
+ char **mds = NULL;
+ int n = 0;
+
+ /* A hash mapping uuids to md device names */
+ *map = hash_initialize(16, NULL, uuid_hash, uuid_cmp, md_uuid_free);
+ if (*map == NULL) g->abort_cb();
+
+ mds = guestfs_list_md_devices(g);
+ if (mds == NULL) goto error;
+
+ for (char **md = mds; *md != NULL; md++) {
+ char **detail = guestfs_md_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) == -1) {
+ /* Invalid UUID is weird, but not fatal. */
+ debug(g, "inspect-os: guestfs_md_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_insert_if_absent(*map, entry, &matched)) {
+ case -1:
+ g->abort_cb();
+
+ case 0:
+ /* Duplicate uuid in for md device is weird, but not fatal. */
+ debug(g, "inspect-os: md devices %s and %s have the same uuid",
+ ((md_uuid *)matched)->path, entry->path);
+ md_uuid_free(entry);
+ break;
+
+ default:
+ n++;
+ }
+ }
+
+ guestfs___free_string_list(detail);
+ }
+
+ guestfs___free_string_list(mds);
+
+ return n;
+
+error:
+ hash_free(*map); *map = NULL;
+ guestfs___free_string_list(mds);
+
+ return -1;
+}
+
+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 int
+map_md_devices(guestfs_h *g, Hash_table **map)
+{
+ Hash_table *app_map = NULL;
+ char **matches = NULL;
+ *map = NULL;
+
+ /* Get a map of md device uuids to their device names in the appliance */
+ int n_app_md_devices = map_app_md_devices(g, &app_map);
+ if (n_app_md_devices == -1) goto error;
+
+ /* Nothing to do if there are no md devices */
+ if (n_app_md_devices == 0) {
+ hash_free(app_map);
+ return 0;
+ }
+
+ /* Get all arrays listed in mdadm.conf */
+ matches = guestfs_aug_match(g, "/files/etc/mdadm.conf/array");
+ if (!matches) goto error;
+
+ /* Log a debug message if we've got md devices, but nothing in mdadm.conf */
+ if (matches[0] == NULL) {
+ debug(g, "Appliance has MD devices, but augeas returned no array matches "
+ "in mdadm.conf");
+ guestfs___free_string_list(matches);
+ hash_free(app_map);
+ return 0;
+ }
+
+ *map = hash_initialize(16, NULL, mdadm_app_hash, mdadm_app_cmp,
+ mdadm_app_free);
+ if (!*map) g->abort_cb();
+
+ for (char **match = matches; *match != NULL; match++) {
+ /* Get device name and uuid for each array */
+ char *dev_path = safe_asprintf(g, "%s/devicename", *match);
+ char *dev = guestfs_aug_get(g, dev_path);
+ free(dev_path);
+ if (!dev) goto error;
+
+ char *uuid_path = safe_asprintf(g, "%s/uuid", *match);
+ char *uuid = guestfs_aug_get(g, uuid_path);
+ free(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) == -1) {
+ /* Invalid uuid. Weird, but not fatal. */
+ debug(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_insert_if_absent(*map, entry, NULL)) {
+ case -1:
+ g->abort_cb();
+
+ case 0:
+ /* Duplicate uuid in for md device is weird, but not fatal. */
+ debug(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);
+
+ return 0;
+
+error:
+ if (app_map) hash_free(app_map);
+ if (matches) guestfs___free_string_list(matches);
+ if (*map) hash_free(*map);
+
+ return -1;
+}
+
/* 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
* 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 *a1;
char *device = NULL;
- char *bsddisk, *bsdslice, *bsdpart;
+ char *type, *slice, *disk, *part;
if (STRPREFIX (spec, "/dev/mapper/")) {
/* LVM2 does some strange munging on /dev/mapper paths for VGs and
*/
device = guestfs_lvm_canonical_lv_name (g, spec);
}
- else if ((a1 = match1 (g, spec, re_xdev)) != NULL) {
+ else if (match3 (g, spec, re_xdev, &type, &disk, &part)) {
+ /* type: (h|s|v|xv)
+ * disk: ([a-z]+)
+ * part: (\d*) */
+ char **devices = guestfs_list_devices (g);
+ if (devices == NULL)
+ return NULL;
+
+ /* Check any hints we were passed for a non-heuristic mapping */
+ char *name = safe_asprintf (g, "%sd%s", type, disk);
+ size_t i = 0;
+ struct drive *drive = g->drives;
+ while (drive) {
+ if (drive->name && STREQ(drive->name, name)) {
+ device = safe_asprintf (g, "%s%s", devices[i], part);
+ break;
+ }
+
+ i++; drive = drive->next;
+ }
+ free (name);
+
+ /* Guess the appliance device name if we didn't find a matching hint */
+ if (!device) {
+ /* Count how many disks the libguestfs appliance has */
+ size_t count;
+ for (count = 0; devices[count] != NULL; count++)
+ ;
+
+ /* Calculate the numerical index of the disk */
+ i = disk[0] - 'a';
+ for (char *p = disk + 1; *p != '\0'; p++) {
+ i += 1; i *= 26;
+ i += *p - 'a';
+ }
+
+ /* Check the index makes sense wrt the number of disks the appliance has.
+ * If it does, map it to an appliance disk. */
+ if (i < count) {
+ device = safe_asprintf (g, "%s%s", devices[i], part);
+ }
+ }
+
+ free (type);
+ free (disk);
+ free (part);
+ guestfs___free_string_list (devices);
+ }
+ else if (match2 (g, spec, re_cciss, &disk, &part)) {
+ /* disk: (cciss/c\d+d\d+)
+ * part: (\d+)? */
char **devices = guestfs_list_devices (g);
if (devices == NULL)
return NULL;
- size_t count;
- for (count = 0; devices[count] != NULL; count++)
- ;
+ /* Check any hints we were passed for a non-heuristic mapping */
+ size_t i = 0;
+ struct drive *drive = g->drives;
+ while (drive) {
+ if (drive->name && STREQ(drive->name, disk)) {
+ if (part) {
+ device = safe_asprintf (g, "%s%s", devices[i], part);
+ } else {
+ device = safe_strdup (g, devices[i]);
+ }
+ break;
+ }
- size_t i = a1[0] - 'a'; /* a1[0] is always [a-z] because of regex. */
- if (i < count) {
- size_t len = strlen (devices[i]) + strlen (a1) + 16;
- device = safe_malloc (g, len);
- snprintf (device, len, "%s%s", devices[i], &a1[1]);
+ i++; drive = drive->next;
}
- free (a1);
+ /* We don't try to guess mappings for cciss devices */
+
+ free (disk);
+ free (part);
guestfs___free_string_list (devices);
}
- else if (match3 (g, spec, re_freebsd, &bsddisk, &bsdslice, &bsdpart)) {
+ else if (md_map && (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);
+
+ free(disk);
+ }
+ 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
* FreeBSD "partitions" are exposed as quasi-extended partitions
* numbered from 5 in Linux. I have no idea what happens when you
* have multiple "slices" (the FreeBSD term for MBR partitions).
*/
- int disk = guestfs___parse_unsigned_int (g, bsddisk);
- int slice = guestfs___parse_unsigned_int (g, bsdslice);
- int part = bsdpart[0] - 'a' /* counting from 0 */;
- free (bsddisk);
- free (bsdslice);
- free (bsdpart);
-
- if (disk == -1 || disk > 26 ||
- slice <= 0 || slice > 1 /* > 4 .. see comment above */ ||
- part < 0 || part >= 26)
- goto out;
-
- device = safe_asprintf (g, "/dev/sd%c%d", disk + 'a', part + 5);
+ int disk_i = guestfs___parse_unsigned_int (g, disk);
+ int slice_i = guestfs___parse_unsigned_int (g, slice);
+ int part_i = part[0] - 'a' /* counting from 0 */;
+ free (disk);
+ free (slice);
+ free (part);
+
+ if (disk_i != -1 && disk_i <= 26 &&
+ slice_i > 0 && slice_i <= 1 /* > 4 .. see comment above */ &&
+ part_i >= 0 && part_i < 26) {
+ device = safe_asprintf (g, "/dev/sd%c%d", disk_i + 'a', part_i + 5);
+ }
}
- out:
/* Didn't match device pattern, return original spec unchanged. */
if (device == NULL)
device = safe_strdup (g, 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.
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;