psss / rpms / libguestfs

Forked from rpms/libguestfs 5 years ago
Clone
Blob Blame History Raw
From d06da519b443796d83d1f7bd5424b5299b4cb9ad Mon Sep 17 00:00:00 2001
From: Pino Toscano <ptoscano@redhat.com>
Date: Thu, 28 Jan 2016 15:38:11 +0100
Subject: [PATCH 1/2] lvm: support lvm2 older than 2.02.107

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.

(cherry picked from commit f9e8f3b2d2cf1acdf9573faceb844b8d50bae69d)
---
 daemon/lvm.c | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 136 insertions(+), 11 deletions(-)

diff --git a/daemon/lvm.c b/daemon/lvm.c
index cf8e0e5..501c967 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;
+
+  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);
   }
-
-  return convert_lvm_output (out, "/dev/");
 }
 
 /* These were so complex to implement that I ended up auto-generating
-- 
2.5.0