mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
filesystems: Implement parents of MD and VG devices (RHBZ#805070).
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user