Richard W.M. Jones
2017-Mar-03 15:15 UTC
[Libguestfs] [PATCH] rescue: Implement --mount and -i options.
Depends on the previous 5 patches that modified virt-rescue to work without direct mode: https://www.redhat.com/archives/libguestfs/2017-March/msg00017.html Rich.
Richard W.M. Jones
2017-Mar-03 15:15 UTC
[Libguestfs] [PATCH] rescue: Implement --mount and -i options.
`virt-rescue -a disk -i' does the right thing. --- appliance/init | 12 +++++++-- rescue/Makefile.am | 3 ++- rescue/rescue.c | 68 ++++++++++++++++++++++++++++++++++++++------------ rescue/virt-rescue.pod | 35 ++++++++++++++++++++++++++ 4 files changed, 99 insertions(+), 19 deletions(-) diff --git a/appliance/init b/appliance/init index fa42c2b..b951857 100755 --- a/appliance/init +++ b/appliance/init @@ -180,6 +180,10 @@ else # We need a daemon, even in virt-rescue. $cmd & + # XXX This gives a bit of time for virt-rescue to connect to the + # daemon and mount any filesystems. + sleep 2 + # Get name of the serial port, from console= passed by libguestfs. guestfs_serial=$(grep -Eo 'console=[^[:space:]]+' /proc/cmdline | sed s/console=//) @@ -208,8 +212,12 @@ else echo "Welcome to virt-rescue, the libguestfs rescue shell." echo echo "Note: The contents of / (root) are the rescue appliance." - echo "You have to mount the guest's partitions under /sysroot" - echo "before you can examine them." + if ! test -d "/sysroot/dev"; then + echo "You have to mount the guest's partitions under /sysroot" + echo "before you can examine them." + else + echo "Use 'cd /sysroot' or 'chroot /sysroot' to see guest filesystems." + fi echo run_bash_with_ctty echo diff --git a/rescue/Makefile.am b/rescue/Makefile.am index 99d4b79..c83c434 100644 --- a/rescue/Makefile.am +++ b/rescue/Makefile.am @@ -35,7 +35,7 @@ virt_rescue_CPPFLAGS = \ -I$(top_srcdir)/common/utils -I$(top_builddir)/common/utils \ -I$(top_srcdir)/lib -I$(top_builddir)/lib \ -I$(top_srcdir)/common/options -I$(top_builddir)/common/options \ - -I$(top_srcdir)/fish \ + -I$(top_srcdir)/common/windows -I$(top_builddir)/common/windows \ -I$(srcdir)/../gnulib/lib -I../gnulib/lib virt_rescue_CFLAGS = \ @@ -43,6 +43,7 @@ virt_rescue_CFLAGS = \ $(LIBXML2_CFLAGS) virt_rescue_LDADD = \ + $(top_builddir)/common/windows/libwindows.la \ $(top_builddir)/common/options/liboptions.la \ $(top_builddir)/common/utils/libutils.la \ $(top_builddir)/lib/libguestfs.la \ diff --git a/rescue/rescue.c b/rescue/rescue.c index 556c344..6f19634 100644 --- a/rescue/rescue.c +++ b/rescue/rescue.c @@ -23,7 +23,6 @@ #include <string.h> #include <inttypes.h> #include <unistd.h> -#include <fcntl.h> #include <getopt.h> #include <errno.h> #include <error.h> @@ -36,9 +35,11 @@ #include "full-write.h" #include "getprogname.h" #include "ignore-value.h" +#include "nonblocking.h" #include "xvasprintf.h" #include "guestfs.h" +#include "windows.h" #include "options.h" #include "display-options.h" @@ -83,7 +84,9 @@ usage (int status) " -d|--domain guest Add disks from libvirt guest\n" " --format[=raw|..] Force disk format for -a option\n" " --help Display brief help\n" + " -i|--inspector Automatically mount filesystems\n" " -m|--memsize MB Set memory size in megabytes\n" + " --mount dev[:mnt[:opts[:fstype]] Mount dev on mnt (if omitted, /)\n" " --network Enable network\n" " -r|--ro Access read-only\n" " --scratch[=N] Add scratch disk(s)\n" @@ -112,7 +115,7 @@ main (int argc, char *argv[]) enum { HELP_OPTION = CHAR_MAX + 1 }; - static const char options[] = "a:c:d:m:rvVwx"; + static const char options[] = "a:c:d:im:rvVwx"; static const struct option long_options[] = { { "add", 1, 0, 'a' }, { "append", 1, 0, 0 }, @@ -120,7 +123,9 @@ main (int argc, char *argv[]) { "domain", 1, 0, 'd' }, { "format", 2, 0, 0 }, { "help", 0, 0, HELP_OPTION }, + { "inspector", 0, 0, 'i' }, { "long-options", 0, 0, 0 }, + { "mount", 1, 0, 0 /* not 'm' because memsize used it earlier */ }, { "memsize", 1, 0, 'm' }, { "network", 0, 0, 0 }, { "ro", 0, 0, 'r' }, @@ -136,6 +141,9 @@ main (int argc, char *argv[]) }; struct drv *drvs = NULL; struct drv *drv; + struct mp *mps = NULL; + struct mp *mp; + char *p; const char *format = NULL; bool format_consumed = true; int c; @@ -193,6 +201,8 @@ main (int argc, char *argv[]) _("--scratch parameter '%s' should be >= 1"), optarg); add_scratch_disks (n, &drvs); } + } else if (STREQ (long_options[option_index].name, "mount")) { + OPTION_m; } else error (EXIT_FAILURE, 0, _("unknown long option: %s (%d)"), @@ -211,6 +221,10 @@ main (int argc, char *argv[]) OPTION_d; break; + case 'i': + OPTION_i; + break; + case 'm': if (sscanf (optarg, "%d", &memsize) != 1) error (EXIT_FAILURE, 0, @@ -285,7 +299,6 @@ main (int argc, char *argv[]) * options parsing code. Assert here that they have known-good * values. */ - assert (inspector == 0); assert (keys_from_stdin == 0); assert (echo_keys == 0); assert (live == 0); @@ -329,12 +342,6 @@ main (int argc, char *argv[]) exit (EXIT_FAILURE); free (append_full); - /* Add drives. */ - add_drives (drvs, 'a'); - - /* Free up data structures, no longer needed after this point. */ - free_drives (drvs); - /* Add an event handler to print "log messages". These will be the * output of the appliance console during launch and shutdown. * After launch, we will read the console messages directly from the @@ -344,9 +351,41 @@ main (int argc, char *argv[]) GUESTFS_EVENT_APPLIANCE, 0, NULL) == -1) exit (EXIT_FAILURE); - /* Run the appliance. */ + /* Do the guest drives and mountpoints. */ + add_drives (drvs, 'a'); if (guestfs_launch (g) == -1) exit (EXIT_FAILURE); + if (inspector) + inspect_mount (); + mount_mps (mps); + + free_drives (drvs); + free_mps (mps); + + /* Also bind-mount /dev etc under /sysroot, if -i was given. */ + if (inspector) { + CLEANUP_FREE_STRING_LIST char **roots; + int windows; + + roots = guestfs_inspect_get_roots (g); + windows = roots && roots[0] && is_windows (g, roots[0]); + if (!windows) { + const char *cmd[5] = { "mount", "--rbind", NULL, NULL, NULL }; + char *r; + + cmd[2] = "/dev"; cmd[3] = "/sysroot/dev"; + r = guestfs_debug (g, "sh", (char **) cmd); + free (r); + + cmd[2] = "/proc"; cmd[3] = "/sysroot/proc"; + r = guestfs_debug (g, "sh", (char **) cmd); + free (r); + + cmd[2] = "/sys"; cmd[3] = "/sysroot/sys"; + r = guestfs_debug (g, "sh", (char **) cmd); + free (r); + } + } sock = guestfs_internal_get_console_socket (g); if (sock == -1) @@ -367,12 +406,9 @@ main (int argc, char *argv[]) } /* Try to set all sockets to non-blocking. */ - if (fcntl (STDIN_FILENO, F_SETFL, O_NONBLOCK) == -1) - perror ("could not set stdin to non-blocking"); - if (fcntl (STDOUT_FILENO, F_SETFL, O_NONBLOCK) == -1) - perror ("could not set stdout to non-blocking"); - if (fcntl (sock, F_SETFL, O_NONBLOCK) == -1) - perror ("could not set console socket to non-blocking"); + ignore_value (set_nonblocking_flag (STDIN_FILENO, 1)); + ignore_value (set_nonblocking_flag (STDOUT_FILENO, 1)); + ignore_value (set_nonblocking_flag (sock, 1)); /* Restore the tty settings when the process exits. */ atexit (restore_tty); diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod index b8aa326..745e540 100644 --- a/rescue/virt-rescue.pod +++ b/rescue/virt-rescue.pod @@ -170,6 +170,16 @@ If you have untrusted raw-format guest disk images, you should use this option to specify the disk format. This avoids a possible security problem with malicious guests (CVE-2010-3851). +=item B<-i> + +=item B<--inspector> + +Using L<virt-inspector(1)> code, inspect the disks looking for +an operating system and mount filesystems as they would be +mounted on the real virtual machine. + +The filesystems are mounted on F</sysroot> in the rescue environment. + =item B<-m> MB =item B<--memsize> MB @@ -179,6 +189,31 @@ default is set by libguestfs and is small but adequate for running system tools. The occasional program might need more memory. The parameter is specified in megabytes. +=item B<--mount> dev[:mountpoint[:options[:fstype]]] + +Mount the named partition or logical volume on the given mountpoint +B<in the guest> (this has nothing to do with mountpoints in the host). + +If the mountpoint is omitted, it defaults to F</>. You have to mount +something on F</>. + +The filesystems are mounted under F</sysroot> in the rescue environment. + +The third (and rarely used) part of the mount parameter is the list of +mount options used to mount the underlying filesystem. If this is not +given, then the mount options are either the empty string or C<ro> +(the latter if the I<--ro> flag is used). By specifying the mount +options, you override this default choice. Probably the only time you +would use this is to enable ACLs and/or extended attributes if the +filesystem can support them: + + -m /dev/sda1:/:acl,user_xattr + +The fourth part of the parameter is the filesystem driver to use, such +as C<ext3> or C<ntfs>. This is rarely needed, but can be useful if +multiple drivers are valid for a filesystem (eg: C<ext2> and C<ext3>), +or if libguestfs misidentifies a filesystem. + =item B<--network> Enable QEMU user networking in the guest. See L</NETWORK>. -- 2.9.3