From b8b1b0296b0af8d072f329828ecf004116bfc7d3 Mon Sep 17 00:00:00 2001 From: "Richard W.M. Jones" Date: Mon, 7 Oct 2013 19:53:54 +0100 Subject: [PATCH] daemon: Refactor bind-mount code. This is just code motion. --- daemon/command.c | 112 +++++++++++++++++++++++++++++++++-------------- 1 file changed, 79 insertions(+), 33 deletions(-) diff --git a/daemon/command.c b/daemon/command.c index 99a58c199..b100b145c 100644 --- a/daemon/command.c +++ b/daemon/command.c @@ -20,6 +20,7 @@ #include #include +#include #include #include "guestfs_protocol.h" @@ -31,21 +32,94 @@ GUESTFSD_EXT_CMD(str_mount, mount); GUESTFSD_EXT_CMD(str_umount, umount); +#ifdef HAVE_ATTRIBUTE_CLEANUP +#define CLEANUP_BIND_STATE __attribute__((cleanup(free_bind_state))) +#else +#define CLEANUP_BIND_STATE +#endif + +struct bind_state { + bool mounted; + char *sysroot_dev; + char *sysroot_dev_pts; + char *sysroot_proc; + char *sysroot_sys; + bool dev_ok, dev_pts_ok, proc_ok, sys_ok; +}; + +/* While running the command, bind-mount /dev, /proc, /sys + * into the chroot. However we must be careful to unmount them + * afterwards because otherwise they would interfere with + * future mount and unmount operations. + * + * We deliberately allow these commands to fail silently, BUT + * if a mount fails, don't unmount the corresponding mount. + */ +static int +bind_mount (struct bind_state *bs) +{ + int r; + + memset (bs, 0, sizeof *bs); + + bs->sysroot_dev = sysroot_path ("/dev"); + bs->sysroot_dev_pts = sysroot_path ("/dev/pts"); + bs->sysroot_proc = sysroot_path ("/proc"); + bs->sysroot_sys = sysroot_path ("/sys"); + + if (bs->sysroot_dev == NULL || bs->sysroot_dev_pts == NULL || + bs->sysroot_proc == NULL || bs->sysroot_sys == NULL) { + reply_with_perror ("malloc"); + free (bs->sysroot_dev); + free (bs->sysroot_dev_pts); + free (bs->sysroot_proc); + free (bs->sysroot_sys); + return -1; + } + + r = command (NULL, NULL, str_mount, "--bind", "/dev", bs->sysroot_dev, NULL); + bs->dev_ok = r != -1; + r = command (NULL, NULL, str_mount, "--bind", "/dev/pts", bs->sysroot_dev_pts, NULL); + bs->dev_pts_ok = r != -1; + r = command (NULL, NULL, str_mount, "--bind", "/proc", bs->sysroot_proc, NULL); + bs->proc_ok = r != -1; + r = command (NULL, NULL, str_mount, "--bind", "/sys", bs->sysroot_sys, NULL); + bs->sys_ok = r != -1; + + bs->mounted = true; + + return 0; +} + static inline void umount_ignore_fail (const char *path) { ignore_value (command (NULL, NULL, str_umount, path, NULL)); } +static void +free_bind_state (struct bind_state *bs) +{ + if (bs->mounted) { + if (bs->sys_ok) umount_ignore_fail (bs->sysroot_sys); + free (bs->sysroot_sys); + if (bs->proc_ok) umount_ignore_fail (bs->sysroot_proc); + free (bs->sysroot_proc); + if (bs->dev_pts_ok) umount_ignore_fail (bs->sysroot_dev_pts); + free (bs->sysroot_dev_pts); + if (bs->dev_ok) umount_ignore_fail (bs->sysroot_dev); + free (bs->sysroot_dev); + bs->mounted = false; + } +} + char * do_command (char *const *argv) { char *out; CLEANUP_FREE char *err = NULL; int r; - CLEANUP_FREE char *sysroot_dev = NULL, *sysroot_dev_pts = NULL, - *sysroot_proc = NULL, *sysroot_sys = NULL; - int dev_ok, dev_pts_ok, proc_ok, sys_ok; + CLEANUP_BIND_STATE struct bind_state bind_state = { .mounted = false }; /* We need a root filesystem mounted to do this. */ NEED_ROOT (, return NULL); @@ -59,42 +133,14 @@ do_command (char *const *argv) return NULL; } - /* While running the command, bind-mount /dev, /proc, /sys - * into the chroot. However we must be careful to unmount them - * afterwards because otherwise they would interfere with - * future mount and unmount operations. - * - * We deliberately allow these commands to fail silently, BUT - * if a mount fails, don't unmount the corresponding mount. - */ - sysroot_dev = sysroot_path ("/dev"); - sysroot_dev_pts = sysroot_path ("/dev/pts"); - sysroot_proc = sysroot_path ("/proc"); - sysroot_sys = sysroot_path ("/sys"); - - if (sysroot_dev == NULL || sysroot_dev_pts == NULL || - sysroot_proc == NULL || sysroot_sys == NULL) { - reply_with_perror ("malloc"); + if (bind_mount (&bind_state) == -1) return NULL; - } - - r = command (NULL, NULL, str_mount, "--bind", "/dev", sysroot_dev, NULL); - dev_ok = r != -1; - r = command (NULL, NULL, str_mount, "--bind", "/dev/pts", sysroot_dev_pts, NULL); - dev_pts_ok = r != -1; - r = command (NULL, NULL, str_mount, "--bind", "/proc", sysroot_proc, NULL); - proc_ok = r != -1; - r = command (NULL, NULL, str_mount, "--bind", "/sys", sysroot_sys, NULL); - sys_ok = r != -1; CHROOT_IN; r = commandv (&out, &err, (const char * const *) argv); CHROOT_OUT; - if (sys_ok) umount_ignore_fail (sysroot_sys); - if (proc_ok) umount_ignore_fail (sysroot_proc); - if (dev_pts_ok) umount_ignore_fail (sysroot_dev_pts); - if (dev_ok) umount_ignore_fail (sysroot_dev); + free_bind_state (&bind_state); if (r == -1) { reply_with_error ("%s", err);