[Libguestfs] [PATCH v3 6/7] rescue: Implement -m and -i options.

Richard W.M. Jones rjones at redhat.com
Sat Mar 4 15:11:05 UTC 2017


`virt-rescue -a disk -i' does the right thing.

`-m' was previously an alternate form of `--memsize'.  By sniffing the
parameter we can make `-m MB' continue to work, while also allowing
`-m' to be used as a short form for the `--mount' option.

This also removes most of the description of `--suggest' from the man
page, since it is no longer needed.
---
 appliance/init         | 12 +++++--
 rescue/Makefile.am     |  3 +-
 rescue/rescue.c        | 87 +++++++++++++++++++++++++++++++++++++-------------
 rescue/virt-rescue.pod | 80 ++++++++++++++++++++++++++++------------------
 4 files changed, 126 insertions(+), 56 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 28a62ce..7548607 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>
@@ -37,9 +36,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"
 
@@ -87,7 +88,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"
-              "  -m|--memsize MB      Set memory size in megabytes\n"
+              "  -i|--inspector       Automatically mount filesystems\n"
+              "  -m|--mount dev[:mnt[:opts[:fstype]] Mount dev on mnt (if omitted, /)\n"
+              "  --memsize MB         Set memory size in megabytes\n"
               "  --network            Enable network\n"
               "  -r|--ro              Access read-only\n"
               "  --scratch[=N]        Add scratch disk(s)\n"
@@ -116,7 +119,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 },
@@ -124,8 +127,10 @@ 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 },
-    { "memsize", 1, 0, 'm' },
+    { "mount", 1, 0, 'm' },
+    { "memsize", 1, 0, 0 },
     { "network", 0, 0, 0 },
     { "ro", 0, 0, 'r' },
     { "rw", 0, 0, 'w' },
@@ -140,13 +145,16 @@ 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;
   int option_index;
   int network = 0;
   const char *append = NULL;
-  int memsize = 0;
+  int memsize = 0, m;
   int smp = 0;
   int suggest = 0;
   char *append_full;
@@ -204,6 +212,10 @@ 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, "memsize")) {
+        if (sscanf (optarg, "%d", &memsize) != 1)
+          error (EXIT_FAILURE, 0,
+                 _("could not parse memory size '%s'"), optarg);
       } else
         error (EXIT_FAILURE, 0,
                _("unknown long option: %s (%d)"),
@@ -222,10 +234,19 @@ 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,
-               _("could not parse memory size '%s'"), optarg);
+      /* For backwards compatibility with virt-rescue <= 1.36, we
+       * must handle -m <number> as a synonym for --memsize.
+       */
+      if (sscanf (optarg, "%d", &m) == 1)
+        memsize = m;
+      else {
+        OPTION_m;
+      }
       break;
 
     case 'r':
@@ -296,7 +317,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);
@@ -340,12 +360,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
@@ -355,21 +369,50 @@ 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)
     exit (EXIT_FAILURE);
 
   /* 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));
 
   /* Put stdin in raw mode so that we can receive ^C and other
    * special keys.
diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
index b8aa326..b651f84 100644
--- a/rescue/virt-rescue.pod
+++ b/rescue/virt-rescue.pod
@@ -6,9 +6,7 @@ virt-rescue - Run a rescue shell on a virtual machine
 
  virt-rescue [--options] -d domname
 
- virt-rescue [--options] -a disk.img [-a disk.img ...]
-
- virt-rescue --suggest (-d domname | -a disk.img ...)
+ virt-rescue [--options] -a disk.img [-a disk.img ...] [-i]
 
 Old style:
 
@@ -26,13 +24,13 @@ machine or disk image.
 You can run virt-rescue on any virtual machine known to libvirt, or
 directly on disk image(s):
 
- virt-rescue -d GuestName
+ virt-rescue -d GuestName -i
 
- virt-rescue --ro -a /path/to/disk.img
+ virt-rescue --ro -a /path/to/disk.img -i
 
  virt-rescue -a /dev/sdc
 
-For live VMs you I<must> use the --ro option.
+For live VMs you I<must> use the I<--ro> option.
 
 When you run virt-rescue on a virtual machine or disk image, you are
 placed in an interactive bash shell where you can use many ordinary
@@ -41,26 +39,10 @@ rescue appliance.  You must mount the virtual machine's filesystems by
 hand.  There is an empty directory called F</sysroot> where you can
 mount filesystems.
 
-You can get virt-rescue to suggest mount commands for you by using the
-I<--suggest> option (in another terminal):
-
- $ virt-rescue --suggest -d Fedora15
- Inspecting the virtual machine or disk image ...
- 
- This disk contains one or more operating systems.  You can use these
- mount commands in virt-rescue (at the ><rescue> prompt) to mount the
- filesystems.
- 
- # /dev/vg_f15x32/lv_root is the root of a linux operating system
- # type: linux, distro: fedora, version: 15.0
- # Fedora release 15 (Lovelock)
- 
- mount /dev/vg_f15x32/lv_root /sysroot/
- mount /dev/vda1 /sysroot/boot
- mount --bind /dev /sysroot/dev
- mount --bind /dev/pts /sysroot/dev/pts
- mount --bind /proc /sysroot/proc
- mount --bind /sys /sysroot/sys
+To automatically mount the virtual machine's filesystems under
+F</sysroot> use the I<-i> option.  This uses libguestfs inspection to
+find the filesystems and mount them in the right place.  You can also
+mount filesystems individually using the I<-m> option.
 
 Another way is to list the logical volumes (with L<lvs(8)>) and
 partitions (with L<parted(8)>) and mount them by hand:
@@ -170,7 +152,15 @@ 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<-m> MB
+=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<--memsize> MB
 
@@ -179,6 +169,33 @@ 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<-m> dev[:mountpoint[:options[:fstype]]]
+
+=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>.
@@ -217,9 +234,10 @@ Enable N E<ge> 2 virtual CPUs in the rescue appliance.
 
 =item B<--suggest>
 
-Inspect the disk image and suggest what mount commands should be used
-to mount the disks.  You should use the I<--suggest> option in a
-second terminal, then paste the commands into another virt-rescue.
+This option was used in older versions of virt-rescue to suggest what
+commands you could use to mount filesystems under F</sysroot>.  For
+the current version of virt-rescue, it is easier to use the I<-i>
+option instead.
 
 This option implies I<--ro> and is safe to use even if the guest is up
 or if another virt-rescue is running.
@@ -240,7 +258,7 @@ Display version number and exit.
 
 =item B<--rw>
 
-This changes the I<-a> and I<-d> options so that disks are
+This changes the I<-a>, I<-d> and I<-m> options so that disks are
 added and mounts are done read-write.
 
 See L<guestfish(1)/OPENING DISKS FOR READ AND WRITE>.
-- 
2.9.3




More information about the Libguestfs mailing list