mirror of
https://github.com/libguestfs/libguestfs.git
synced 2026-03-21 22:53:37 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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).
|
||||
*/
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user