[Libguestfs] [PATCH] rescue: Implement --mount and -i options.

Richard W.M. Jones rjones at redhat.com
Fri Mar 3 15:15:56 UTC 2017


`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




More information about the Libguestfs mailing list