filesystems: Implement parents of MD and VG devices (RHBZ#805070).

This commit is contained in:
Richard W.M. Jones
2012-03-21 10:55:23 +00:00
parent a8f8af950d
commit 7d2027295f

View File

@@ -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;
}