[Libguestfs] [PATCH 21/27] daemon: Reimplement ‘findfs_uuid’ and ‘findfs_label’ APIs in OCaml.

Richard W.M. Jones rjones at redhat.com
Fri Jul 14 13:39:29 UTC 2017


This also reimplements the lv_canonical function in OCaml.  We cannot
call the original C function because it calls reply_with_perror which
would break the OCaml bindings.
---
 daemon/Makefile.am        |  3 +-
 daemon/findfs.c           | 94 -----------------------------------------------
 daemon/findfs.ml          | 56 ++++++++++++++++++++++++++++
 daemon/findfs.mli         | 20 ++++++++++
 daemon/lvm.ml             | 28 ++++++++++++++
 daemon/lvm.mli            | 10 +++++
 docs/C_SOURCE_FILES       |  1 -
 generator/actions_core.ml |  2 +
 8 files changed, 118 insertions(+), 96 deletions(-)

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index d239f38ef..a864b6996 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -108,7 +108,6 @@ guestfsd_SOURCES = \
 	ext2.c \
 	fallocate.c \
 	file.c \
-	findfs.c \
 	fill.c \
 	find.c \
 	format.c \
@@ -262,6 +261,7 @@ SOURCES_MLI = \
 	devsparts.mli \
 	file.mli \
 	filearch.mli \
+	findfs.mli \
 	is.mli \
 	ldm.mli \
 	link.mli \
@@ -290,6 +290,7 @@ SOURCES_ML = \
 	ldm.ml \
 	link.ml \
 	lvm.ml \
+	findfs.ml \
 	md.ml \
 	mount.ml \
 	parted.ml \
diff --git a/daemon/findfs.c b/daemon/findfs.c
deleted file mode 100644
index f44137038..000000000
--- a/daemon/findfs.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/* libguestfs - the guestfsd daemon
- * Copyright (C) 2010 Red Hat Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <config.h>
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "daemon.h"
-#include "actions.h"
-
-GUESTFSD_EXT_CMD(str_findfs, findfs);
-
-static char *
-findfs (const char *tag, const char *label_or_uuid)
-{
-  char *out;
-  CLEANUP_FREE char *err = NULL;
-  CLEANUP_FREE char *arg = NULL;
-  int r;
-  size_t len;
-
-  /* Kill the cache file, forcing blkid to reread values from the
-   * original filesystems.  In blkid there is a '-p' option which is
-   * supposed to do this, but (a) it doesn't work and (b) that option
-   * is not supported in RHEL 5.
-   */
-  unlink ("/etc/blkid/blkid.tab");
-  unlink ("/run/blkid/blkid.tab");
-
-  if (asprintf (&arg, "%s=%s", tag, label_or_uuid) == -1) {
-    reply_with_perror ("asprintf");
-    return NULL;
-  }
-
-  r = command (&out, &err, str_findfs, arg, NULL);
-  if (r == -1) {
-    reply_with_error ("%s", err);
-    free (out);
-    return NULL;
-  }
-
-  /* Trim trailing \n if present. */
-  len = strlen (out);
-  if (len > 0 && out[len-1] == '\n')
-    out[len-1] = '\0';
-
-  if (STRPREFIX (out, "/dev/mapper/") || STRPREFIX (out, "/dev/dm-")) {
-    char *canonical;
-    r = lv_canonical (out, &canonical);
-    if (r == -1) {
-      free (out);
-      return NULL;
-    }
-    if (r == 1) {
-      free (out);
-      out = canonical;
-    }
-    /* Ignore the case where r == 0.  /dev/mapper does not correspond
-     * to an LV, so the best we can do is just return it as-is.
-     */
-  }
-
-  return out;                   /* caller frees */
-}
-
-char *
-do_findfs_uuid (const char *uuid)
-{
-  return findfs ("UUID", uuid);
-}
-
-char *
-do_findfs_label (const char *label)
-{
-  return findfs ("LABEL", label);
-}
diff --git a/daemon/findfs.ml b/daemon/findfs.ml
new file mode 100644
index 000000000..8acb72928
--- /dev/null
+++ b/daemon/findfs.ml
@@ -0,0 +1,56 @@
+(* guestfs-inspection
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+open Printf
+open Unix
+
+open Std_utils
+
+open Utils
+
+let rec findfs_uuid uuid =
+  findfs "UUID" uuid
+and findfs_label label =
+  findfs "LABEL"label
+
+and findfs tag str =
+  (* Kill the cache file, forcing blkid to reread values from the
+   * original filesystems.  In blkid there is a '-p' option which is
+   * supposed to do this, but (a) it doesn't work and (b) that option
+   * is not supported in RHEL 5.
+   *)
+  (try unlink "/etc/blkid/blkid.tab" with Unix_error _ -> ());
+  (try unlink "/run/blkid/blkid.tab" with Unix_error _ -> ());
+
+  let out = command "findfs" [ sprintf "%s=%s" tag str ] in
+
+  (* Trim trailing \n if present. *)
+  let out = String.trim out in
+
+  if String.is_prefix out "/dev/mapper/" ||
+     String.is_prefix out "/dev/dm-" then (
+    match Lvm.lv_canonical out with
+    | None ->
+       (* Ignore the case where 'out' doesn't appear to be an LV.
+        * The best we can do is return the original as-is.
+        *)
+       out
+    | Some out -> out
+  )
+  else
+    out
diff --git a/daemon/findfs.mli b/daemon/findfs.mli
new file mode 100644
index 000000000..acef0395c
--- /dev/null
+++ b/daemon/findfs.mli
@@ -0,0 +1,20 @@
+(* guestfs-inspection
+ * Copyright (C) 2009-2017 Red Hat Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *)
+
+val findfs_uuid : string -> string
+val findfs_label : string -> string
diff --git a/daemon/lvm.ml b/daemon/lvm.ml
index 14f0a8578..5dd01d6b2 100644
--- a/daemon/lvm.ml
+++ b/daemon/lvm.ml
@@ -16,6 +16,7 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *)
 
+open Unix
 open Printf
 
 open Std_utils
@@ -93,3 +94,30 @@ and filter_convert_old_lvs_output out =
   ) lines in
 
   List.sort compare lines
+
+(* Convert a non-canonical LV path like /dev/mapper/vg-lv or /dev/dm-0
+ * to a canonical one.
+ *
+ * This is harder than it should be.  A LV device like /dev/VG/LV is
+ * really a symlink to a device-mapper device like /dev/dm-0.  However
+ * at the device-mapper (kernel) level, nothing is really known about
+ * LVM (a userspace concept).  Therefore we use a convoluted method to
+ * determine this, by listing out known LVs and checking whether the
+ * rdev (major/minor) of the device we are passed matches any of them.
+ *
+ * Note use of 'stat' instead of 'lstat' so that symlinks are fully
+ * resolved.
+ *)
+let lv_canonical device =
+  let stat1 = stat device in
+  let lvs = lvs () in
+  try
+    Some (
+      List.find (
+        fun lv ->
+          let stat2 = stat lv in
+          stat1.st_rdev = stat2.st_rdev
+      ) lvs
+    )
+  with
+  | Not_found -> None
diff --git a/daemon/lvm.mli b/daemon/lvm.mli
index 1cf61ecfb..7cde16ebb 100644
--- a/daemon/lvm.mli
+++ b/daemon/lvm.mli
@@ -19,3 +19,13 @@
 val available : unit -> bool
 
 val lvs : unit -> string list
+
+val lv_canonical : string -> string option
+(** Convert a non-canonical LV path like /dev/mapper/vg-lv or /dev/dm-0
+    to a canonical one.
+
+    On error this raises an exception.  There are two possible non-error
+    return cases:
+
+    Some lv = conversion was successful, returning the canonical LV
+    None = input path was not an LV, it could not be made canonical *)
diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES
index 74588d488..8bdb40da9 100644
--- a/docs/C_SOURCE_FILES
+++ b/docs/C_SOURCE_FILES
@@ -103,7 +103,6 @@ daemon/fallocate.c
 daemon/file.c
 daemon/fill.c
 daemon/find.c
-daemon/findfs.c
 daemon/format.c
 daemon/fs-min-size.c
 daemon/fsck.c
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index b1e2559e0..0a967f76d 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -5746,6 +5746,7 @@ returns true iff this is the case." };
   { defaults with
     name = "findfs_uuid"; added = (1, 5, 3);
     style = RString (RDevice, "device"), [String (PlainString, "uuid")], [];
+    impl = OCaml "Findfs.findfs_uuid";
     shortdesc = "find a filesystem by UUID";
     longdesc = "\
 This command searches the filesystems and returns the one
@@ -5757,6 +5758,7 @@ To find the UUID of a filesystem, use C<guestfs_vfs_uuid>." };
   { defaults with
     name = "findfs_label"; added = (1, 5, 3);
     style = RString (RDevice, "device"), [String (PlainString, "label")], [];
+    impl = OCaml "Findfs.findfs_label";
     shortdesc = "find a filesystem by label";
     longdesc = "\
 This command searches the filesystems and returns the one
-- 
2.13.2




More information about the Libguestfs mailing list