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.
This commit is contained in:
Matthew Booth
2013-01-24 10:10:13 +00:00
parent d5817537fa
commit 47b929b789
8 changed files with 173 additions and 29 deletions

View File

@@ -67,21 +67,21 @@ 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");
return get_blkid_tag (mountable->device, "TYPE");
}
char *
do_vfs_label (const char *device)
do_vfs_label (const mountable_t *mountable)
{
return get_blkid_tag (device, "LABEL");
return get_blkid_tag (mountable->device, "LABEL");
}
char *
do_vfs_uuid (const char *device)
do_vfs_uuid (const mountable_t *mountable)
{
return get_blkid_tag (device, "UUID");
return get_blkid_tag (mountable->device, "UUID");
}
/* RHEL5 blkid doesn't have the -p (low-level probing) option and the

View File

@@ -49,6 +49,19 @@ 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;
const char *device;
const char *volume;
} mountable_t;
/* Growable strings buffer. */
struct stringsbuf {
char **argv;
@@ -116,6 +129,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);
@@ -330,6 +345,32 @@ is_zero (const char *buffer, size_t size)
} \
} while (0)
/* All functions that take a mountable argument must call this macro.
* It parses the mountable into a mountable_t, ensures any
* underlying device exists, and does device name translation
* (described in the guestfs(3) manpage).
*
* Note that the "string" argument may be modified.
*/
#define RESOLVE_MOUNTABLE(string,mountable,cancel_stmt,fail_stmt) \
do { \
if (STRPREFIX ((string), "btrfsvol:")) { \
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).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.
*

View File

@@ -116,13 +116,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.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.device = device;
return do_vfs_label (&mountable);
}
int
@@ -143,7 +149,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.device = device;
return do_vfs_uuid (&mountable);
}
/* If the filesystem is not mounted, run e2fsck -f on it unconditionally. */

View File

@@ -358,6 +358,13 @@ read_cmdline (void)
/* Return true iff device is the root device (and therefore should be
* ignored from the point of view of user calls).
*/
static int
is_root_device_stat (struct stat *statbuf)
{
if (statbuf->st_rdev == root_device) return 1;
return 0;
}
int
is_root_device (const char *device)
{
@@ -366,9 +373,8 @@ is_root_device (const char *device)
perror (device);
return 0;
}
if (statbuf.st_rdev == root_device)
return 1;
return 0;
return is_root_device_stat (&statbuf);
}
/* Turn "/path" into "/sysroot/path".
@@ -1164,6 +1170,57 @@ 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';
struct stat statbuf;
if (stat (device, &statbuf) == -1) {
perror (device);
return -1;
}
if (!S_ISDIR (statbuf.st_mode) &&
!is_root_device_stat(&statbuf) &&
device_name_translation (device) == 0)
{
volume = slash + 1;
break;
}
*slash = '/';
}
if (!volume) return -1;
mountable->device = device;
mountable->volume = volume;
return 0;
}
/* Check program exists and is executable on $PATH. Actually, we
* just assume PATH contains the default entries (see main() above).
*/

View File

@@ -71,21 +71,21 @@ 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)
{
int r;
/* How we set the label depends on the filesystem type. */
CLEANUP_FREE char *vfs_type = do_vfs_type (device);
CLEANUP_FREE char *vfs_type = do_vfs_type (mountable);
if (vfs_type == NULL)
return -1;
if (STREQ (vfs_type, "ext2") || STREQ (vfs_type, "ext3")
|| STREQ (vfs_type, "ext4"))
r = e2label (device, label);
r = e2label (mountable->device, label);
else if (STREQ (vfs_type, "ntfs"))
r = ntfslabel (device, label);
r = ntfslabel (mountable->device, label);
else {
reply_with_error ("don't know how to set the label for '%s' filesystems",

View File

@@ -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;
CLEANUP_FREE char *mp = NULL;
@@ -149,12 +149,34 @@ do_mount_vfs (const char *options, const char *vfstype,
return -1;
}
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;
}
}
}
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);
if (r == -1) {
reply_with_error ("%s on %s (options: '%s'): %s",
device, mountpoint, options, error);
@@ -165,22 +187,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. */

View File

@@ -121,12 +121,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
@@ -160,6 +166,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
@@ -176,6 +183,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)

View File

@@ -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