summaryrefslogtreecommitdiffstats
path: root/cat/virt-filesystems.c
diff options
context:
space:
mode:
authorRichard W.M. Jones <rjones@redhat.com>2012-03-21 10:55:23 +0000
committerRichard W.M. Jones <rjones@redhat.com>2012-03-21 12:08:37 +0000
commit7d2027295fb394dd5d8cbc1e960ea6a47d420225 (patch)
treeadfd6bbdc64f94ab370fb1f8119332cf80acdaae /cat/virt-filesystems.c
parenta8f8af950d5b178a77a3b6423fbbd1ba447858f9 (diff)
downloadlibguestfs-7d2027295fb394dd5d8cbc1e960ea6a47d420225.tar.gz
libguestfs-7d2027295fb394dd5d8cbc1e960ea6a47d420225.tar.xz
libguestfs-7d2027295fb394dd5d8cbc1e960ea6a47d420225.zip
filesystems: Implement parents of MD and VG devices (RHBZ#805070).
Diffstat (limited to 'cat/virt-filesystems.c')
-rw-r--r--cat/virt-filesystems.c239
1 files changed, 223 insertions, 16 deletions
diff --git a/cat/virt-filesystems.c b/cat/virt-filesystems.c
index 42911a8b..1d324637 100644
--- a/cat/virt-filesystems.c
+++ b/cat/virt-filesystems.c
@@ -83,10 +83,14 @@ static int output = 0;
static int columns;
static char *canonical_device (const char *dev);
+
static void do_output_title (void);
static void do_output (void);
static void do_output_end (void);
+static struct guestfs_lvm_pv_list *get_pvs (void);
+static void free_pvs (void);
+
static inline char *
bad_cast (char const *s)
{
@@ -364,6 +368,8 @@ main (int argc, char *argv[])
do_output ();
do_output_end ();
+ free_pvs ();
+
guestfs_close (g);
exit (EXIT_SUCCESS);
@@ -375,9 +381,18 @@ static void do_output_vgs (void);
static void do_output_pvs (void);
static void do_output_partitions (void);
static void do_output_blockdevs (void);
-static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, const char **parents, const char *uuid);
+
+static void write_row (const char *name, const char *type, const char *vfs_type, const char *vfs_label, int mbr_id, int64_t size, char **parents, const char *uuid);
static void write_row_strings (char **strings, size_t len);
+static char **no_parents (void);
+static int is_md (char *device);
+static char **parents_of_md (char *device);
+static char **parents_of_vg (char *vg);
+
+static void free_strings (char **strings);
+static size_t count_strings (char **strings);
+
static void
do_output_title (void)
{
@@ -443,7 +458,7 @@ do_output_filesystems (void)
for (i = 0; fses[i] != NULL; i += 2) {
char *dev, *vfs_label = NULL, *vfs_uuid = NULL;
- const char *parents[1] = { NULL };
+ char **parents;
int64_t size = -1;
/* Skip swap and unknown, unless --extra flag was given. */
@@ -486,9 +501,15 @@ do_output_filesystems (void)
exit (EXIT_FAILURE);
}
+ if (is_md (fses[i]))
+ parents = parents_of_md (fses[i]);
+ else
+ parents = no_parents ();
+
write_row (dev, "filesystem",
fses[i+1], vfs_label, -1, size, parents, vfs_uuid);
+ free_strings (parents);
free (dev);
free (vfs_label);
free (vfs_uuid);
@@ -540,7 +561,7 @@ do_output_lvs (void)
}
write_row (lvs[i], "lv",
- NULL, NULL, -1, size, parents, uuid);
+ NULL, NULL, -1, size, (char **) parents, uuid);
free (uuid);
free (parent_name);
@@ -563,29 +584,55 @@ do_output_vgs (void)
for (i = 0; i < vgs->len; ++i) {
char name[PATH_MAX];
char uuid[33];
- const char *parents[1] = { NULL };
+ char **parents;
strcpy (name, "/dev/");
strcpy (&name[5], vgs->val[i].vg_name);
+
memcpy (uuid, vgs->val[i].vg_uuid, 32);
uuid[32] = '\0';
+
+ parents = parents_of_vg (vgs->val[i].vg_name);
+
write_row (name, "vg",
NULL, NULL, -1, (int64_t) vgs->val[i].vg_size, parents, uuid);
+ free_strings (parents);
}
guestfs_free_lvm_vg_list (vgs);
}
+/* Cache the output of guestfs_pvs_full, since we use it in a few places. */
+static struct guestfs_lvm_pv_list *pvs_ = NULL;
+
+static struct guestfs_lvm_pv_list *
+get_pvs (void)
+{
+ if (pvs_)
+ return pvs_;
+
+ pvs_ = guestfs_pvs_full (g);
+ if (pvs_ == NULL)
+ exit (EXIT_FAILURE);
+
+ return pvs_;
+}
+
+static void
+free_pvs (void)
+{
+ if (pvs_)
+ guestfs_free_lvm_pv_list (pvs_);
+
+ pvs_ = NULL;
+}
+
static void
do_output_pvs (void)
{
- struct guestfs_lvm_pv_list *pvs;
size_t i;
-
- pvs = guestfs_pvs_full (g);
- if (pvs == NULL)
- exit (EXIT_FAILURE);
+ struct guestfs_lvm_pv_list *pvs = get_pvs ();
for (i = 0; i < pvs->len; ++i) {
char *dev;
@@ -597,12 +644,11 @@ do_output_pvs (void)
memcpy (uuid, pvs->val[i].pv_uuid, 32);
uuid[32] = '\0';
write_row (dev, "pv",
- NULL, NULL, -1, (int64_t) pvs->val[i].pv_size, parents, uuid);
+ NULL, NULL, -1, (int64_t) pvs->val[i].pv_size,
+ (char **) parents, uuid);
free (dev);
}
-
- guestfs_free_lvm_pv_list (pvs);
}
static int
@@ -671,7 +717,7 @@ do_output_partitions (void)
}
write_row (dev, "partition",
- NULL, NULL, mbr_id, size, parents, NULL);
+ NULL, NULL, mbr_id, size, (char **) parents, NULL);
free (dev);
free (parent_name);
@@ -694,7 +740,7 @@ do_output_blockdevs (void)
for (i = 0; devices[i] != NULL; ++i) {
int64_t size = -1;
char *dev;
- const char *parents[1] = { NULL };
+ char **parents;
dev = canonical_device (devices[i]);
@@ -704,11 +750,17 @@ do_output_blockdevs (void)
exit (EXIT_FAILURE);
}
+ if (is_md (devices[i]))
+ parents = parents_of_md (devices[i]);
+ else
+ parents = no_parents ();
+
write_row (dev, "device",
NULL, NULL, -1, size, parents, NULL);
free (dev);
free (devices[i]);
+ free_strings (parents);
}
free (devices);
@@ -734,8 +786,143 @@ canonical_device (const char *dev)
return ret;
}
+/* Returns an empty list of parents. Note this must be freed using
+ * free_strings.
+ */
+static char **
+no_parents (void)
+{
+ char **ret;
+
+ ret = malloc (sizeof (char *));
+ if (!ret) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+
+ ret[0] = NULL;
+
+ return ret;
+}
+
+/* XXX Should be a better test than this. */
+static int
+is_md (char *device)
+{
+ char *p;
+
+ if (!STRPREFIX (device, "/dev/md"))
+ return 0;
+
+ p = device + 7;
+ while (*p) {
+ if (!c_isdigit (*p))
+ return 0;
+ p++;
+ }
+
+ return 1;
+}
+
+static char **
+parents_of_md (char *device)
+{
+ struct guestfs_mdstat_list *stats;
+ char **ret;
+ size_t i;
+
+ stats = guestfs_md_stat (g, device);
+ if (!stats)
+ exit (EXIT_FAILURE);
+
+ ret = malloc ((stats->len + 1) * sizeof (char *));
+ if (!ret) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+
+ for (i = 0; i < stats->len; ++i)
+ ret[i] = canonical_device (stats->val[i].mdstat_device);
+
+ ret[stats->len] = NULL;
+
+ guestfs_free_mdstat_list (stats);
+
+ return ret;
+}
+
+/* Specialized PV UUID comparison function.
+ * pvuuid1: from vgpvuuids, this may contain '-' characters which
+ * should be ignored.
+ * pvuuid2: from pvs-full, this is 32 characters long and NOT
+ * terminated by \0
+ */
+static int
+compare_pvuuids (const char *pvuuid1, const char *pvuuid2)
+{
+ size_t i;
+ const char *p = pvuuid1;
+
+ for (i = 0; i < 32; ++i) {
+ while (*p && !c_isalnum (*p))
+ p++;
+ if (!*p)
+ return 0;
+ if (*p != pvuuid2[i])
+ return 0;
+ }
+
+ return 1;
+}
+
+static char **
+parents_of_vg (char *vg)
+{
+ struct guestfs_lvm_pv_list *pvs = get_pvs ();
+ char **pvuuids;
+ char **ret;
+ size_t n, i, j;
+
+ pvuuids = guestfs_vgpvuuids (g, vg);
+ if (!pvuuids)
+ exit (EXIT_FAILURE);
+
+ n = count_strings (pvuuids);
+
+ ret = malloc ((n + 1) * sizeof (char *));
+ if (!ret) {
+ perror ("malloc");
+ exit (EXIT_FAILURE);
+ }
+
+ /* Resolve each PV UUID back to a PV. */
+ for (i = 0; i < n; ++i) {
+ for (j = 0; j < pvs->len; ++j) {
+ if (compare_pvuuids (pvuuids[i], pvs->val[j].pv_uuid) == 0)
+ break;
+ }
+
+ if (j < pvs->len)
+ ret[i] = canonical_device (pvs->val[j].pv_name);
+ else {
+ fprintf (stderr, "%s: warning: unknown PV UUID ignored\n", __func__);
+ ret[i] = strndup (pvuuids[i], 32);
+ if (!ret[i]) {
+ perror ("strndup");
+ exit (EXIT_FAILURE);
+ }
+ }
+ }
+
+ ret[i] = NULL;
+
+ free_strings (pvuuids);
+
+ return ret;
+}
+
static char *
-join_comma (const char **strings)
+join_comma (char **strings)
{
size_t i, count;
char *ret;
@@ -766,7 +953,7 @@ join_comma (const char **strings)
static void
write_row (const char *name, const char *type,
const char *vfs_type, const char *vfs_label, int mbr_id,
- int64_t size, const char **parents, const char *uuid)
+ int64_t size, char **parents, const char *uuid)
{
const char *strings[NR_COLUMNS];
char *parents_str = NULL;
@@ -987,3 +1174,23 @@ do_output_end (void)
}
free (rows);
}
+
+static void
+free_strings (char **strings)
+{
+ size_t i;
+
+ for (i = 0; strings[i] != NULL; ++i)
+ free (strings[i]);
+ free (strings);
+}
+
+static size_t
+count_strings (char **strings)
+{
+ size_t i;
+
+ for (i = 0; strings[i] != NULL; ++i)
+ ;
+ return i;
+}