diff options
author | Richard W.M. Jones <[email protected]> | 2012-03-21 10:55:23 +0000 |
---|---|---|
committer | Richard W.M. Jones <[email protected]> | 2012-03-21 12:08:37 +0000 |
commit | 7d2027295fb394dd5d8cbc1e960ea6a47d420225 (patch) | |
tree | adfd6bbdc64f94ab370fb1f8119332cf80acdaae /cat/virt-filesystems.c | |
parent | a8f8af950d5b178a77a3b6423fbbd1ba447858f9 (diff) | |
download | libguestfs-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.c | 239 |
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; +} |