[Libguestfs] [PATCH v2] lvm: support lvm2 older than 2.02.107
Richard W.M. Jones
rjones at redhat.com
Thu Jan 28 15:41:39 UTC 2016
On Thu, Jan 28, 2016 at 04:11:30PM +0100, Pino Toscano wrote:
> lvm2 2.02.107 adds the -S/--select option used in lvs to filter out only
> public LVs (see RHBZ#1278878). To make this work again with versions
> of lvm2 older than that, only on old versions filter out thin layouts
> and compose the resulting device strings ourselves.
>
> The filtering done is much simplier than what "-S lv_role=public" will
> do, but should be good enough for our need.
> ---
> daemon/lvm.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
> 1 file changed, 136 insertions(+), 11 deletions(-)
>
> diff --git a/daemon/lvm.c b/daemon/lvm.c
> index 979cf63..8bef4d5 100644
> --- a/daemon/lvm.c
> +++ b/daemon/lvm.c
> @@ -103,6 +103,85 @@ convert_lvm_output (char *out, const char *prefix)
> return ret.argv;
> }
>
> +/* Filter a colon-separated output of
> + * lvs -o lv_attr,vg_name,lv_name
> + * removing thin layouts, and building the device path as we expect it.
> + *
> + * This is used only when lvm has no -S.
> + */
> +static char **
> +filter_convert_old_lvs_output (char *out)
> +{
> + char *p, *pend;
> + DECLARE_STRINGSBUF (ret);
> +
> + p = out;
> + while (p) {
> + size_t len;
> + char *saveptr;
> + char *lv_attr, *vg_name, *lv_name;
> +
> + pend = strchr (p, '\n'); /* Get the next line of output. */
> + if (pend) {
> + *pend = '\0';
> + pend++;
> + }
> +
> + while (*p && c_isspace (*p)) /* Skip any leading whitespace. */
> + p++;
> +
> + /* Sigh, skip trailing whitespace too. "pvs", I'm looking at you. */
> + len = strlen (p)-1;
> + while (*p && c_isspace (p[len]))
> + p[len--] = '\0';
> +
> + if (!*p) { /* Empty line? Skip it. */
> + skip_line:
> + p = pend;
> + continue;
> + }
> +
> + lv_attr = strtok_r (p, ":", &saveptr);
> + if (!lv_attr)
> + goto skip_line;
> +
> + vg_name = strtok_r (NULL, ":", &saveptr);
> + if (!vg_name)
> + goto skip_line;
> +
> + lv_name = strtok_r (NULL, ":", &saveptr);
> + if (!lv_name)
> + goto skip_line;
> +
> + /* Ignore thin layouts (RHBZ#1278878). */
> + if (lv_attr[0] == 't')
> + goto skip_line;
> +
> + /* Ignore "unknown device" message (RHBZ#1054761). */
> + if (STRNEQ (p, "unknown device")) {
> + char buf[256];
> +
> + snprintf (buf, sizeof buf, "/dev/%s/%s", vg_name, lv_name);
> + if (add_string (&ret, buf) == -1) {
> + free (out);
> + return NULL;
> + }
> + }
> +
> + p = pend;
> + }
> +
> + free (out);
> +
> + if (ret.size > 0)
> + sort_strings (ret.argv, ret.size);
> +
> + if (end_stringsbuf (&ret) == -1)
> + return NULL;
> +
> + return ret.argv;
> +}
> +
> char **
> do_pvs (void)
> {
> @@ -139,26 +218,72 @@ do_vgs (void)
> return convert_lvm_output (out, NULL);
> }
>
> +/* Check whether lvs has -S to filter its output.
> + * It is available only in lvm2 >= 2.02.107.
> + */
> +static int
> +test_lvs_has_S_opt (void)
> +{
> + static int result = -1;
> + if (result != -1)
> + return result;
> +
> + CLEANUP_FREE char *out = NULL;
> + CLEANUP_FREE char *err = NULL;
> +
> + int r = command (&out, &err, str_lvm, "lvs", "--help", NULL);
> + if (r == -1) {
> + reply_with_error ("lvm lvs --help: %s", err);
> + return -1;
> + }
> +
> + if (strstr (out, "-S") == NULL)
> + result = 0;
> + else
> + result = 1;
> +
> + return result;
> +}
> +
> char **
> do_lvs (void)
> {
> char *out;
> CLEANUP_FREE char *err = NULL;
> int r;
> + int has_S = test_lvs_has_S_opt ();
>
> - r = command (&out, &err,
> - str_lvm, "lvs",
> - "-o", "vg_name,lv_name",
> - "-S", "lv_role=public",
> - "--noheadings",
> - "--separator", "/", NULL);
> - if (r == -1) {
> - reply_with_error ("%s", err);
> - free (out);
> + if (has_S < 0)
> return NULL;
> - }
>
> - return convert_lvm_output (out, "/dev/");
> + if (has_S > 0) {
> + r = command (&out, &err,
> + str_lvm, "lvs",
> + "-o", "vg_name,lv_name",
> + "-S", "lv_role=public",
> + "--noheadings",
> + "--separator", "/", NULL);
> + if (r == -1) {
> + reply_with_error ("%s", err);
> + free (out);
> + return NULL;
> + }
> +
> + return convert_lvm_output (out, "/dev/");
> + } else {
> + r = command (&out, &err,
> + str_lvm, "lvs",
> + "-o", "lv_attr,vg_name,lv_name",
> + "--noheadings",
> + "--separator", ":", NULL);
> + if (r == -1) {
> + reply_with_error ("%s", err);
> + free (out);
> + return NULL;
> + }
> +
> + return filter_convert_old_lvs_output (out);
> + }
> }
ACK.
Rich.
--
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-p2v converts physical machines to virtual machines. Boot with a
live CD or over the network (PXE) and turn machines into KVM guests.
http://libguestfs.org/virt-v2v
More information about the Libguestfs
mailing list