[Libguestfs] [PATCH v6 22/41] daemon: Reimplement ‘mount’, ‘mount_ro’, ‘mount_options’, ‘mount_vfs’ APIs in OCaml.

Richard W.M. Jones
Thu, 15 Jun 2017 17:06:12 -0000

Some of the oldest and most core APIs, reimplemented.

This also moves the strange ‘mount_vfs_nochroot’ function into
btrfs.c.
---
 daemon/Makefile.am        |  2 +
 daemon/btrfs.c            | 43 ++++++++++++++++++++
 daemon/daemon.h           |  6 ---
 daemon/mount.c            | 99 -----------------------------------------------
 daemon/mount.ml           | 62 +++++++++++++++++++++++++++++
 daemon/mount.mli          | 22 +++++++++++
 generator/actions_core.ml |  4 ++
 generator/daemon.ml       |  3 +-
 8 files changed, 135 insertions(+), 106 deletions(-)

diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index e0c770b76..ae31bf356 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -265,6 +265,7 @@ SOURCES_MLI = \
 	file.mli \
 	is.mli \
 	link.mli \
+	mount.mli \
 	mountable.mli \
 	utils.mli

@@ -279,6 +280,7 @@ SOURCES_ML = \
 	file.ml \
 	is.ml \
 	link.ml \
+	mount.ml \
 	callbacks.ml \
 	daemon.ml

diff --git a/daemon/btrfs.c b/daemon/btrfs.c
index 5f1e5d1d0..4f52b71e8 100644
--- a/daemon/btrfs.c
+++ b/daemon/btrfs.c
@@ -37,6 +37,7 @@ GUESTFSD_EXT_CMD(str_btrfs, btrfs);
 GUESTFSD_EXT_CMD(str_btrfstune, btrfstune);
 GUESTFSD_EXT_CMD(str_btrfsck, btrfsck);
 GUESTFSD_EXT_CMD(str_mkfs_btrfs, mkfs.btrfs);
+GUESTFSD_EXT_CMD(str_mount, mount);
 GUESTFSD_EXT_CMD(str_umount, umount);
 GUESTFSD_EXT_CMD(str_btrfsimage, btrfs-image);

@@ -387,6 +388,48 @@ do_btrfs_subvolume_create (const char *dest, const char
*qgroupid)
   return 0;
 }

+static int
+mount_vfs_nochroot (const char *options, const char *vfstype,
+                    const mountable_t *mountable,
+                    const char *mp, const char *user_mp)
+{
+  CLEANUP_FREE char *options_plus = NULL;
+  const char *device = mountable->device;
+  if (mountable->type == MOUNTABLE_BTRFSVOL) {
+    if (options && strlen (options) > 0) {
+      if (asprintf (&options_plus, "subvol=%s,%s",
+                    mountable->volume, options) == -1) {
+        reply_with_perror ("asprintf");
+        return -1;
+      }
+    }
+    else {
+      if (asprintf (&options_plus, "subvol=%s",
mountable->volume) == -1) {
+        reply_with_perror ("asprintf");
+        return -1;
+      }
+    }
+  }
+
+  CLEANUP_FREE char *error = NULL;
+  int r;
+  if (vfstype)
+    r = command (NULL, &error,
+                 str_mount, "-o", options_plus ? options_plus :
options,
+                 "-t", vfstype, device, mp, NULL);
+  else
+    r = command (NULL, &error,
+                 str_mount, "-o", options_plus ? options_plus :
options,
+                 device, mp, NULL);
+  if (r == -1) {
+    reply_with_error ("%s on %s (options: '%s'): %s",
+                      device, user_mp, options, error);
+    return -1;
+  }
+
+  return 0;
+}
+
 static char *
 mount (const mountable_t *fs)
 {
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 684f9b096..9f4a7f8a6 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -94,12 +94,6 @@ extern void cleanup_free_stringsbuf (void *ptr);
 #define CLEANUP_FREE_STRINGSBUF
 #endif

-/*-- in mount.c --*/
-
-extern int mount_vfs_nochroot (const char *options, const char *vfstype,
-                               const mountable_t *mountable,
-                               const char *mp, const char *user_mp);
-
 /* Growable strings buffer. */
 struct stringsbuf {
   char **argv;
diff --git a/daemon/mount.c b/daemon/mount.c
index 0ad9626a7..962b86079 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -111,105 +111,6 @@ is_device_mounted (const char *device)
   return 0;
 }

-/* The "simple mount" call offers no complex options, you can just
- * mount a device on a mountpoint.  The variations like mount_ro,
- * mount_options and mount_vfs let you set progressively more things.
- *
- * It's tempting to try a direct mount(2) syscall, but that doesn't
- * do any autodetection, so we are better off calling out to
- * /bin/mount.
- */
-
-int
-do_mount_vfs (const char *options, const char *vfstype,
-              const mountable_t *mountable, const char *mountpoint)
-{
-  CLEANUP_FREE char *mp = NULL;
-  struct stat statbuf;
-
-  ABS_PATH (mountpoint, 0, return -1);
-
-  mp = sysroot_path (mountpoint);
-  if (!mp) {
-    reply_with_perror ("malloc");
-    return -1;
-  }
-
-  /* Check the mountpoint exists and is a directory. */
-  if (stat (mp, &statbuf) == -1) {
-    reply_with_perror ("mount: %s", mountpoint);
-    return -1;
-  }
-  if (!S_ISDIR (statbuf.st_mode)) {
-    reply_with_perror ("mount: %s: mount point is not a directory",
mountpoint);
-    return -1;
-  }
-
-  return mount_vfs_nochroot (options, vfstype, mountable, mp, mountpoint);
-}
-
-int
-mount_vfs_nochroot (const char *options, const char *vfstype,
-                    const mountable_t *mountable,
-                    const char *mp, const char *user_mp)
-{
-  CLEANUP_FREE char *options_plus = NULL;
-  const char *device = mountable->device;
-  if (mountable->type == MOUNTABLE_BTRFSVOL) {
-    if (options && strlen (options) > 0) {
-      if (asprintf (&options_plus, "subvol=%s,%s",
-                    mountable->volume, options) == -1) {
-        reply_with_perror ("asprintf");
-        return -1;
-      }
-    }
-
-    else {
-      if (asprintf (&options_plus, "subvol=%s",
mountable->volume) == -1) {
-        reply_with_perror ("asprintf");
-        return -1;
-      }
-    }
-  }
-
-  CLEANUP_FREE char *error = NULL;
-  int r;
-  if (vfstype)
-    r = command (NULL, &error,
-                 str_mount, "-o", options_plus ? options_plus :
options,
-                 "-t", vfstype, device, mp, NULL);
-  else
-    r = command (NULL, &error,
-                 str_mount, "-o", options_plus ? options_plus :
options,
-                 device, mp, NULL);
-  if (r == -1) {
-    reply_with_error ("%s on %s (options: '%s'): %s",
-                      device, user_mp, options, error);
-    return -1;
-  }
-
-  return 0;
-}
-
-int
-do_mount (const mountable_t *mountable, const char *mountpoint)
-{
-  return do_mount_vfs ("", NULL, mountable, mountpoint);
-}
-
-int
-do_mount_ro (const mountable_t *mountable, const char *mountpoint)
-{
-  return do_mount_vfs ("ro", NULL, mountable, mountpoint);
-}
-
-int
-do_mount_options (const char *options, const mountable_t *mountable,
-                  const char *mountpoint)
-{
-  return do_mount_vfs (options, NULL, mountable, mountpoint);
-}
-
 /* Takes optional arguments, consult optargs_bitmask. */
 int
 do_umount (const char *pathordevice,
diff --git a/daemon/mount.ml b/daemon/mount.ml
new file mode 100644
index 000000000..4bb74fb82
--- /dev/null
+++ b/daemon/mount.ml
@@ -0,0 +1,62 @@
+(* 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 Std_utils
+
+open Mountable
+open Utils
+
+let mount_vfs options vfs mountable mountpoint +  let mp = Sysroot.sysroot ()
// mountpoint in
+
+  (* Check the mountpoint exists and is a directory. *)
+  if not (is_directory mp) then
+    failwithf "mount: %s: mount point is not a directory" mountpoint;
+
+  let args = ref [] in
+
+  (* -o options *)
+  (match options, mountable.m_type with
+   | (None | Some ""), (MountableDevice | MountablePath) -> ()
+   | Some options, (MountableDevice | MountablePath) ->
+      push_back args "-o";
+      push_back args options
+   | (None | Some ""), MountableBtrfsVol subvol ->
+      push_back args "-o";
+      push_back args ("subvol=" ^ subvol)
+   | Some options, MountableBtrfsVol subvol ->
+      push_back args "-o";
+      push_back args ("subvol=" ^ subvol ^ "," ^ options)
+  );
+
+  (* -t vfs *)
+  (match vfs with
+   | None | Some "" -> ()
+   | Some t ->
+      push_back args "-t";
+      push_back args t
+  );
+
+  push_back args mountable.m_device;
+  push_back args mp;
+
+  ignore (command "mount" !args)
+
+let mount = mount_vfs None None
+let mount_ro = mount_vfs (Some "ro") None
+let mount_options options = mount_vfs (Some options) None
diff --git a/daemon/mount.mli b/daemon/mount.mli
new file mode 100644
index 000000000..e43d97c42
--- /dev/null
+++ b/daemon/mount.mli
@@ -0,0 +1,22 @@
+(* 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 mount : Mountable.t -> string -> unit
+val mount_ro : Mountable.t -> string -> unit
+val mount_options : string -> Mountable.t -> string -> unit
+val mount_vfs : string option -> string option -> Mountable.t ->
string -> unit
diff --git a/generator/actions_core.ml b/generator/actions_core.ml
index 7d6755fdc..f33bc5320 100644
--- a/generator/actions_core.ml
+++ b/generator/actions_core.ml
@@ -1739,6 +1739,7 @@ let daemon_functions = [
   { defaults with
     name = "mount"; added = (0, 0, 3);
     style = RErr, [String (Mountable, "mountable"); String
(PlainString, "mountpoint")], [];
+    impl = OCaml "Mount.mount";
     tests = [
       InitEmpty, Always, TestResultString (
         [["part_disk"; "/dev/sda"; "mbr"];
@@ -2922,6 +2923,7 @@ If set to true, POSIX ACLs are saved in the output tar.
   { defaults with
     name = "mount_ro"; added = (1, 0, 10);
     style = RErr, [String (Mountable, "mountable"); String
(PlainString, "mountpoint")], [];
+    impl = OCaml "Mount.mount_ro";
     tests = [
       InitBasicFS, Always, TestLastFail (
         [["umount"; "/"; "false";
"false"];
@@ -2941,6 +2943,7 @@ mounts the filesystem with the read-only (I<-o ro>)
flag." };
   { defaults with
     name = "mount_options"; added = (1, 0, 10);
     style = RErr, [String (PlainString, "options"); String
(Mountable, "mountable"); String (PlainString,
"mountpoint")], [];
+    impl = OCaml "Mount.mount_options";
     shortdesc = "mount a guest disk with mount options";
     longdesc = "\
 This is the same as the C<guestfs_mount> command, but it
@@ -2954,6 +2957,7 @@ the filesystem uses)." };
   { defaults with
     name = "mount_vfs"; added = (1, 0, 10);
     style = RErr, [String (PlainString, "options"); String
(PlainString, "vfstype"); String (Mountable, "mountable");
String (PlainString, "mountpoint")], [];
+    impl = OCaml "Mount.mount_vfs";
     shortdesc = "mount a guest disk with mount options and vfstype";
     longdesc = "\
 This is the same as the C<guestfs_mount> command, but it
diff --git a/generator/daemon.ml b/generator/daemon.ml
index ef6086bfe..fd01e5d8a 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -689,7 +689,8 @@ return_string_list (value retv)
       pr "\n";

       (match ret with
-       | RErr -> assert false
+       | RErr ->
+          pr "  CAMLreturnT (int, 0);\n"
        | RInt _ ->
           pr "  CAMLreturnT (int, Int_val (retv));\n"
        | RInt64 _ -> assert false
--
2.13.0