[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[Libguestfs] [PATCH 3/3] mountable: Implement Mountable support for all apis which take it



A Mountable is passed from the library to the daemon as a string. The daemon
stub parses it into a mountable_t, which it passes to the implementation.

Update all implementations which now take a mountable_t.
---
 daemon/blkid.c      | 36 ++++++++++++++++++++++++++++++------
 daemon/daemon.h     | 39 +++++++++++++++++++++++++++++++++++++++
 daemon/ext2.c       | 15 ++++++++++++---
 daemon/guestfsd.c   | 42 ++++++++++++++++++++++++++++++++++++++++++
 daemon/labels.c     | 19 +++++++++++++++++--
 daemon/mount.c      | 52 +++++++++++++++++++++++++++++++++++++++++++---------
 generator/c.ml      | 12 +++++++++++-
 generator/daemon.ml | 11 ++++++++---
 8 files changed, 202 insertions(+), 24 deletions(-)

diff --git a/daemon/blkid.c b/daemon/blkid.c
index b6bc22d..429a005 100644
--- a/daemon/blkid.c
+++ b/daemon/blkid.c
@@ -69,21 +69,45 @@ get_blkid_tag (const char *device, const char *tag)
 }
 
 char *
-do_vfs_type (const char *device)
+do_vfs_type (const mountable_t *mountable)
 {
-  return get_blkid_tag (device, "TYPE");
+  switch (mountable->type) {
+    case MOUNTABLE_DEVICE:
+      return get_blkid_tag (mountable->desc.device, "TYPE");
+    case MOUNTABLE_BTRFSVOL:
+      return strdup("btrfs");
+    default:
+      reply_with_error ("Unknown mountable type: %i", mountable->type);
+      return NULL;
+  }
 }
 
 char *
-do_vfs_label (const char *device)
+do_vfs_label (const mountable_t *mountable)
 {
-  return get_blkid_tag (device, "LABEL");
+  switch (mountable->type) {
+    case MOUNTABLE_DEVICE:
+      return get_blkid_tag (mountable->desc.device, "LABEL");
+    case MOUNTABLE_BTRFSVOL:
+      return get_blkid_tag (mountable->desc.btrfsvol.device, "LABEL");
+    default:
+      reply_with_error ("Unknown mountable type: %i", mountable->type);
+      return NULL;
+  }
 }
 
 char *
-do_vfs_uuid (const char *device)
+do_vfs_uuid (const mountable_t *mountable)
 {
-  return get_blkid_tag (device, "UUID");
+  switch (mountable->type) {
+    case MOUNTABLE_DEVICE:
+      return get_blkid_tag (mountable->desc.device, "UUID");
+    case MOUNTABLE_BTRFSVOL:
+      return get_blkid_tag (mountable->desc.btrfsvol.device, "UUID");
+    default:
+      reply_with_error ("Unknown mountable type: %i", mountable->type);
+      return NULL;
+  }
 }
 
 /* RHEL5 blkid doesn't have the -p (low-level probing) option and the
diff --git a/daemon/daemon.h b/daemon/daemon.h
index df1ba3a..8f5015a 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -47,6 +47,24 @@ extern int xwrite (int sock, const void *buf, size_t len)
 extern int xread (int sock, void *buf, size_t len)
   __attribute__((__warn_unused_result__));
 
+/* Mountables */
+
+typedef enum {
+  MOUNTABLE_DEVICE,
+  MOUNTABLE_BTRFSVOL
+} mountable_type_t;
+
+typedef struct {
+  mountable_type_t type;
+  union {
+    const char *device;
+    struct {
+      const char *device;
+      const char *volume;
+    } btrfsvol;
+  } desc;
+} mountable_t;
+
 /* Growable strings buffer. */
 struct stringsbuf {
   char **argv;
@@ -114,6 +132,8 @@ extern void trim (char *str);
 
 extern int device_name_translation (char *device);
 
+extern int parse_btrfsvol (char *desc, mountable_t *mountable);
+
 extern int prog_exists (const char *prog);
 
 extern void udev_settle (void);
@@ -320,6 +340,25 @@ is_zero (const char *buffer, size_t size)
     }                                                                   \
   } while (0)
 
+#define RESOLVE_MOUNTABLE(string,mountable,cancel_stmt,fail_stmt)       \
+  do {                                                                  \
+    if (strncmp ((string), "btrfsvol:", strlen ("btrfsvol:")) == 0) {   \
+      if (parse_btrfsvol ((string) + strlen ("btrfsvol:"), &(mountable)) == -1)\
+      {                                                                 \
+        cancel_stmt;                                                    \
+        reply_with_error ("%s: %s: expecting a btrfs volume",           \
+                          __func__, (string));                          \
+        fail_stmt;                                                      \
+      }                                                                 \
+    }                                                                   \
+                                                                        \
+    else {                                                              \
+      mountable.type = MOUNTABLE_DEVICE;                                \
+      mountable.desc.device = (string);                                 \
+      RESOLVE_DEVICE((string), cancel_stmt, fail_stmt);                 \
+    }                                                                   \
+  } while (0)
+
 /* Helper for functions which need either an absolute path in the
  * mounted filesystem, OR a /dev/ device which exists.
  *
diff --git a/daemon/ext2.c b/daemon/ext2.c
index ab879db..94e85f0 100644
--- a/daemon/ext2.c
+++ b/daemon/ext2.c
@@ -127,13 +127,19 @@ do_tune2fs_l (const char *device)
 int
 do_set_e2label (const char *device, const char *label)
 {
-  return do_set_label (device, label);
+  mountable_t mountable;
+  mountable.type = MOUNTABLE_DEVICE;
+  mountable.desc.device = device;
+  return do_set_label (&mountable, label);
 }
 
 char *
 do_get_e2label (const char *device)
 {
-  return do_vfs_label (device);
+  mountable_t mountable;
+  mountable.type = MOUNTABLE_DEVICE;
+  mountable.desc.device = device;
+  return do_vfs_label (&mountable);
 }
 
 int
@@ -156,7 +162,10 @@ do_set_e2uuid (const char *device, const char *uuid)
 char *
 do_get_e2uuid (const char *device)
 {
-  return do_vfs_uuid (device);
+  mountable_t mountable;
+  mountable.type = MOUNTABLE_DEVICE;
+  mountable.desc.device = device;
+  return do_vfs_uuid (&mountable);
 }
 
 /* If the filesystem is not mounted, run e2fsck -f on it unconditionally. */
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 9c1c028..5016780 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -1165,6 +1165,48 @@ device_name_translation (char *device)
   return -1;
 }
 
+/* Parse the mountable descriptor for a btrfs subvolume.  Don't call this
+ * directly - use the RESOLVE_MOUNTABLE macro.
+ *
+ * A btrfs subvolume is given as:
+ *
+ * btrfsvol:/dev/sda3/root
+ *
+ * where /dev/sda3 is a block device containing a btrfs filesystem, and root is
+ * the name of a subvolume on it. This function is passed the string following
+ * 'btrfsvol:'.
+ */
+int
+parse_btrfsvol (char *desc, mountable_t *mountable)
+{
+  mountable->type = MOUNTABLE_BTRFSVOL;
+
+  char *device = desc;
+
+  if (strncmp (device, "/dev/", strlen("/dev/")) == -1)
+    return -1;
+
+  char *volume = NULL;
+  char *slash = device + strlen("/dev/") - 1;
+  while ((slash = strchr (slash + 1, '/'))) {
+    *slash = '\0';
+
+    if (!is_root_device(device) && device_name_translation (device) == 0) {
+      volume = slash + 1;
+      break;
+    }
+
+    *slash = '/';
+  }
+
+  if (!volume) return -1;
+
+  mountable->desc.btrfsvol.device = device;
+  mountable->desc.btrfsvol.volume = volume;
+
+  return 0;
+}
+
 /* Check program exists and is executable on $PATH.  Actually, we
  * just assume PATH contains the default entries (see main() above).
  */
diff --git a/daemon/labels.c b/daemon/labels.c
index ead6b46..e2f045a 100644
--- a/daemon/labels.c
+++ b/daemon/labels.c
@@ -75,16 +75,31 @@ ntfslabel (const char *device, const char *label)
 }
 
 int
-do_set_label (const char *device, const char *label)
+do_set_label (const mountable_t *mountable, const char *label)
 {
   char *vfs_type;
   int r;
 
   /* How we set the label depends on the filesystem type. */
-  vfs_type = do_vfs_type (device);
+  vfs_type = do_vfs_type (mountable);
   if (vfs_type == NULL)
     return -1;
 
+  const char *device;
+  switch (mountable->type) {
+    case MOUNTABLE_DEVICE:
+      device = mountable->desc.device;
+      break;
+    
+    case MOUNTABLE_BTRFSVOL:
+      device = mountable->desc.btrfsvol.device;
+      break;
+
+    default:
+      reply_with_error ("Invalid mountable type %i", mountable->type);
+      return -1;
+  }
+
   if (STREQ (vfs_type, "ext2") || STREQ (vfs_type, "ext3")
       || STREQ (vfs_type, "ext4"))
     r = e2label (device, label);
diff --git a/daemon/mount.c b/daemon/mount.c
index c84faaf..d0c321a 100644
--- a/daemon/mount.c
+++ b/daemon/mount.c
@@ -124,7 +124,7 @@ is_device_mounted (const char *device)
 
 int
 do_mount_vfs (const char *options, const char *vfstype,
-              const char *device, const char *mountpoint)
+              const mountable_t *mountable, const char *mountpoint)
 {
   int r;
   char *mp;
@@ -151,13 +151,47 @@ do_mount_vfs (const char *options, const char *vfstype,
     return -1;
   }
 
+  char *options_plus = NULL;
+  const char *device = NULL;
+  switch (mountable->type) {
+    case MOUNTABLE_DEVICE:
+      device = mountable->desc.device;
+      break;
+
+    case MOUNTABLE_BTRFSVOL:
+      device = mountable->desc.btrfsvol.device;
+      if (options && strlen(options) > 1) {
+        if (asprintf (&options_plus, "subvol=%s,%s",
+                      mountable->desc.btrfsvol.volume, options) == -1)
+        {
+          reply_with_perror ("asprintf");
+          return -1;
+        }
+      } else {
+        if (asprintf (&options_plus, "subvol=%s",
+                      mountable->desc.btrfsvol.volume) == -1)
+        {
+          reply_with_perror ("asprintf");
+          return -1;
+        }
+      }
+      break;
+
+    default:
+      reply_with_error ("Invalid mountable type %i", mountable->type);
+      return -1;
+  }
+
   if (vfstype)
     r = command (NULL, &error,
-                 str_mount, "-o", options, "-t", vfstype, device, mp, NULL);
+                 str_mount, "-o", options_plus ? options_plus : options,
+                 "-t", vfstype, device, mp, NULL);
   else
     r = command (NULL, &error,
-                 str_mount, "-o", options, device, mp, NULL);
+                 str_mount, "-o", options_plus ? options_plus : options,
+                 device, mp, NULL);
   free (mp);
+  free (options_plus);
   if (r == -1) {
     reply_with_error ("%s on %s (options: '%s'): %s",
                       device, mountpoint, options, error);
@@ -170,22 +204,22 @@ do_mount_vfs (const char *options, const char *vfstype,
 }
 
 int
-do_mount (const char *device, const char *mountpoint)
+do_mount (const mountable_t *mountable, const char *mountpoint)
 {
-  return do_mount_vfs ("", NULL, device, mountpoint);
+  return do_mount_vfs ("", NULL, mountable, mountpoint);
 }
 
 int
-do_mount_ro (const char *device, const char *mountpoint)
+do_mount_ro (const mountable_t *mountable, const char *mountpoint)
 {
-  return do_mount_vfs ("ro", NULL, device, mountpoint);
+  return do_mount_vfs ("ro", NULL, mountable, mountpoint);
 }
 
 int
-do_mount_options (const char *options, const char *device,
+do_mount_options (const char *options, const mountable_t *mountable,
                   const char *mountpoint)
 {
-  return do_mount_vfs (options, NULL, device, mountpoint);
+  return do_mount_vfs (options, NULL, mountable, mountpoint);
 }
 
 /* Takes optional arguments, consult optargs_bitmask. */
diff --git a/generator/c.ml b/generator/c.ml
index c20f502..e0fc852 100644
--- a/generator/c.ml
+++ b/generator/c.ml
@@ -109,12 +109,18 @@ let rec generate_prototype ?(extern = true) ?(static = false)
     List.iter (
       function
       | Pathname n
-      | Device n | Mountable n | Dev_or_Path n
+      | Device n | Dev_or_Path n
       | String n
       | OptString n
       | Key n ->
           next ();
           pr "const char *%s" n
+      | Mountable n ->
+          next();
+          if in_daemon then
+            pr "const mountable_t *%s" n
+          else
+            pr "const char *%s" n
       | StringList n | DeviceList n ->
           next ();
           pr "char *const *%s" n
@@ -148,6 +154,7 @@ let rec generate_prototype ?(extern = true) ?(static = false)
 
 (* Generate C call arguments, eg "(handle, foo, bar)" *)
 and generate_c_call_args ?handle ?(implicit_size_ptr = "&size")
+    ?(in_daemon = false)
     (ret, args, optargs) =
   pr "(";
   let comma = ref false in
@@ -164,6 +171,9 @@ and generate_c_call_args ?handle ?(implicit_size_ptr = "&size")
     | BufferIn n ->
         next ();
         pr "%s, %s_size" n n
+    | Mountable n ->
+        next ();
+        pr (if in_daemon then "&%s" else "%s") n
     | arg ->
         next ();
         pr "%s" (name_of_argt arg)
diff --git a/generator/daemon.ml b/generator/daemon.ml
index a7096a1..094fe6d 100644
--- a/generator/daemon.ml
+++ b/generator/daemon.ml
@@ -38,6 +38,7 @@ let generate_daemon_actions_h () =
   pr "\n";
 
   pr "#include \"guestfs_protocol.h\"\n";
+  pr "#include \"daemon.h\"\n";
   pr "\n";
 
   List.iter (
@@ -111,11 +112,12 @@ and generate_daemon_actions () =
         pr "  struct guestfs_%s_args args;\n" name;
         List.iter (
           function
-          | Device n | Mountable n | Dev_or_Path n
+          | Device n | Dev_or_Path n
           | Pathname n
           | String n
           | Key n
           | OptString n -> pr "  char *%s;\n" n
+          | Mountable n -> pr "  mountable_t %s;\n" n
           | StringList n | DeviceList n -> pr "  char **%s;\n" n
           | Bool n -> pr "  int %s;\n" n
           | Int n -> pr "  int %s;\n" n
@@ -205,10 +207,13 @@ and generate_daemon_actions () =
               pr_args n;
               pr "  ABS_PATH (%s, %s, goto done);\n"
                 n (if is_filein then "cancel_receive ()" else "");
-          | Device n | Mountable n ->
+          | Device n ->
               pr_args n;
               pr "  RESOLVE_DEVICE (%s, %s, goto done);\n"
                 n (if is_filein then "cancel_receive ()" else "");
+          | Mountable n ->
+              pr "  RESOLVE_MOUNTABLE(args.%s, %s, %s, goto done);\n"
+                n n (if is_filein then "cancel_receive ()" else "");
           | Dev_or_Path n ->
               pr_args n;
               pr "  REQUIRE_ROOT_OR_RESOLVE_DEVICE (%s, %s, goto done);\n"
@@ -257,7 +262,7 @@ and generate_daemon_actions () =
             (function FileIn _ | FileOut _ -> false | _ -> true) args in
         let style = ret, args' @ args_of_optargs optargs, [] in
         pr "  r = do_%s " name;
-        generate_c_call_args style;
+        generate_c_call_args ~in_daemon:true style;
         pr ";\n" in
 
       (match ret with
-- 
1.8.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]