Blame SOURCES/0058-rescue-Implement-escape-sequences.patch

a30de4
From 50e044064b4388f11912d96d2eb52aea1b292734 Mon Sep 17 00:00:00 2001
a30de4
From: "Richard W.M. Jones" <rjones@redhat.com>
a30de4
Date: Sat, 4 Mar 2017 11:47:59 +0000
a30de4
Subject: [PATCH] rescue: Implement escape sequences.
a30de4
a30de4
This implements a few useful escape sequences:
a30de4
a30de4
><rescue> ^]?
a30de4
virt-rescue escape sequences:
a30de4
 ^] ? - print this message
a30de4
 ^] h - print this message
a30de4
 ^] q - quit virt-rescue
a30de4
 ^] s - sync the filesystems
a30de4
 ^] u - unmount filesystems
a30de4
 ^] x - quit virt-rescue
a30de4
 ^] z - suspend virt-rescue
a30de4
to pass the escape key through to the rescue shell, type it twice
a30de4
a30de4
^]i
a30de4
a30de4
root device: /dev/sda3
a30de4
  product name: Fedora 25 (Twenty Five)
a30de4
  type: linux
a30de4
  distro: fedora
a30de4
a30de4
^]z
a30de4
[3]+  Stopped                 ./run virt-rescue --scratch
a30de4
$ fg
a30de4
a30de4
><rescue> ^]u
a30de4
a30de4
unmounting filesystems ...
a30de4
[   21.158558] XFS (sda3): Unmounting Filesystem
a30de4
a30de4
(cherry picked from commit 3637c42f4e521eb647d7dfae7f48eb1689d0af54)
a30de4
---
a30de4
 rescue/Makefile.am     |   4 +-
a30de4
 rescue/escape.c        | 302 +++++++++++++++++++++++++++++++++++++++++++++++++
a30de4
 rescue/rescue.c        |  30 ++++-
a30de4
 rescue/rescue.h        |  47 ++++++++
a30de4
 rescue/virt-rescue.pod |  74 ++++++++++++
a30de4
 5 files changed, 454 insertions(+), 3 deletions(-)
a30de4
 create mode 100644 rescue/escape.c
a30de4
 create mode 100644 rescue/rescue.h
a30de4
a30de4
diff --git a/rescue/Makefile.am b/rescue/Makefile.am
a30de4
index c83c43458..eb60bafa4 100644
a30de4
--- a/rescue/Makefile.am
a30de4
+++ b/rescue/Makefile.am
a30de4
@@ -26,7 +26,9 @@ EXTRA_DIST = \
a30de4
 bin_PROGRAMS = virt-rescue
a30de4
 
a30de4
 virt_rescue_SOURCES = \
a30de4
-	rescue.c
a30de4
+	escape.c \
a30de4
+	rescue.c \
a30de4
+	rescue.h
a30de4
 
a30de4
 virt_rescue_CPPFLAGS = \
a30de4
 	-DGUESTFS_WARN_DEPRECATED=1 \
a30de4
diff --git a/rescue/escape.c b/rescue/escape.c
a30de4
new file mode 100644
a30de4
index 000000000..f7f7d84c4
a30de4
--- /dev/null
a30de4
+++ b/rescue/escape.c
a30de4
@@ -0,0 +1,302 @@
a30de4
+/* virt-rescue
a30de4
+ * Copyright (C) 2010-2017 Red Hat Inc.
a30de4
+ *
a30de4
+ * This program is free software; you can redistribute it and/or modify
a30de4
+ * it under the terms of the GNU General Public License as published by
a30de4
+ * the Free Software Foundation; either version 2 of the License, or
a30de4
+ * (at your option) any later version.
a30de4
+ *
a30de4
+ * This program is distributed in the hope that it will be useful,
a30de4
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
a30de4
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a30de4
+ * GNU General Public License for more details.
a30de4
+ *
a30de4
+ * You should have received a copy of the GNU General Public License
a30de4
+ * along with this program; if not, write to the Free Software
a30de4
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
a30de4
+ */
a30de4
+
a30de4
+#include <config.h>
a30de4
+
a30de4
+#include <stdio.h>
a30de4
+#include <stdlib.h>
a30de4
+#include <stdbool.h>
a30de4
+#include <string.h>
a30de4
+#include <unistd.h>
a30de4
+#include <signal.h>
a30de4
+#include <locale.h>
a30de4
+#include <libintl.h>
a30de4
+
a30de4
+#include "c-ctype.h"
a30de4
+
a30de4
+#include "guestfs.h"
a30de4
+#include "guestfs-internal-frontend.h"
a30de4
+
a30de4
+#include "rescue.h"
a30de4
+
a30de4
+static void print_help (void);
a30de4
+static void print_inspector (void);
a30de4
+static void crlf (void);
a30de4
+static void print_escape_key (void);
a30de4
+
a30de4
+/* Parse the -e parameter from the command line. */
a30de4
+int
a30de4
+parse_escape_key (const char *arg)
a30de4
+{
a30de4
+  size_t len;
a30de4
+
a30de4
+  if (STREQ (arg, "none"))
a30de4
+    return 0;
a30de4
+
a30de4
+  len = strlen (arg);
a30de4
+  if (arg == 0)
a30de4
+    return -1;
a30de4
+
a30de4
+  switch (arg[0]) {
a30de4
+  case '^':
a30de4
+    if (len == 2 &&
a30de4
+        ((arg[1] >= 'a' && arg[1] <= 'z') ||
a30de4
+         (arg[1] >= 'A' && arg[1] <= '_'))) {
a30de4
+      return c_toupper (arg[1]) - '@';
a30de4
+    }
a30de4
+    else
a30de4
+      return -1;
a30de4
+    break;
a30de4
+  }
a30de4
+
a30de4
+  return -1;
a30de4
+}
a30de4
+
a30de4
+/* Print one-line end user description of the escape key.
a30de4
+ *
a30de4
+ * This is printed when virt-rescue starts.
a30de4
+ */
a30de4
+void
a30de4
+print_escape_key_help (void)
a30de4
+{
a30de4
+  crlf ();
a30de4
+  /* Difficult to translate this string. XXX */
a30de4
+  printf ("The virt-rescue escape key is ‘");
a30de4
+  print_escape_key ();
a30de4
+  printf ("’.  Type ‘");
a30de4
+  print_escape_key ();
a30de4
+  printf (" h’ for help.");
a30de4
+  crlf ();
a30de4
+}
a30de4
+
a30de4
+void
a30de4
+init_escape_state (struct escape_state *state)
a30de4
+{
a30de4
+  state->in_escape = false;
a30de4
+}
a30de4
+
a30de4
+/* Process escapes in the tty input buffer.
a30de4
+ *
a30de4
+ * This function has a state parameter so that we can handle an escape
a30de4
+ * sequence split over the end of the buffer.
a30de4
+ *
a30de4
+ * Escape sequences are removed from the buffer.
a30de4
+ *
a30de4
+ * Returns true iff virt-rescue should exit.
a30de4
+ */
a30de4
+bool
a30de4
+process_escapes (struct escape_state *state, char *buf, size_t *len)
a30de4
+{
a30de4
+  size_t i;
a30de4
+
a30de4
+  for (i = 0; i < *len; ++i) {
a30de4
+#define DROP_CURRENT_CHAR() \
a30de4
+    memmove (&buf[i], &buf[i+1], --(*len))
a30de4
+#define PRINT_ESC() \
a30de4
+    do { print_escape_key (); putchar (buf[i]); crlf (); } while (0)
a30de4
+
a30de4
+    if (!state->in_escape) {
a30de4
+      if (buf[i] == escape_key) {
a30de4
+        /* Drop the escape key from the buffer and go to escape mode. */
a30de4
+        DROP_CURRENT_CHAR ();
a30de4
+        state->in_escape = true;
a30de4
+      }
a30de4
+    }
a30de4
+    else /* in escape sequence */ {
a30de4
+      if (buf[i] == escape_key) /* ^] ^] means send ^] to rescue shell */
a30de4
+        state->in_escape = false;
a30de4
+      else {
a30de4
+        switch (buf[i]) {
a30de4
+        case '?': case 'h':
a30de4
+          PRINT_ESC ();
a30de4
+          print_help ();
a30de4
+          break;
a30de4
+
a30de4
+        case 'i':
a30de4
+          PRINT_ESC ();
a30de4
+          print_inspector ();
a30de4
+          break;
a30de4
+
a30de4
+        case 'q': case 'x':
a30de4
+          PRINT_ESC ();
a30de4
+          return true /* exit virt-rescue at once */;
a30de4
+
a30de4
+        case 's':
a30de4
+          PRINT_ESC ();
a30de4
+          printf (_("attempting to sync filesystems ..."));
a30de4
+          crlf ();
a30de4
+          guestfs_sync (g);
a30de4
+          break;
a30de4
+
a30de4
+        case 'u':
a30de4
+          PRINT_ESC ();
a30de4
+          printf (_("unmounting filesystems ..."));
a30de4
+          crlf ();
a30de4
+          guestfs_umount_all (g);
a30de4
+          break;
a30de4
+
a30de4
+        case 'z':
a30de4
+          PRINT_ESC ();
a30de4
+          raise (SIGTSTP);
a30de4
+          break;
a30de4
+
a30de4
+        default:
a30de4
+          /* Any unrecognized escape sequence will be dropped.  We
a30de4
+           * could be obnoxious and ring the bell, but I hate it when
a30de4
+           * programs do that.
a30de4
+           */
a30de4
+          break;
a30de4
+        }
a30de4
+
a30de4
+        /* Drop the escape key and return to non-escape mode. */
a30de4
+        DROP_CURRENT_CHAR ();
a30de4
+        state->in_escape = false;
a30de4
+
a30de4
+        /* The output is line buffered, this is just to make sure
a30de4
+         * everything gets written to stdout before we continue
a30de4
+         * writing to STDOUT_FILENO.
a30de4
+         */
a30de4
+        fflush (stdout);
a30de4
+      }
a30de4
+    } /* in escape sequence */
a30de4
+  } /* for */
a30de4
+
a30de4
+  return false /* don't exit */;
a30de4
+}
a30de4
+
a30de4
+/* This is called when the user types ^] h */
a30de4
+static void
a30de4
+print_help (void)
a30de4
+{
a30de4
+  printf (_("virt-rescue escape sequences:"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" ? - print this message"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" h - print this message"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  if (inspector) {
a30de4
+    putchar (' ');
a30de4
+    print_escape_key ();
a30de4
+    printf (_(" i - print inspection data"));
a30de4
+    crlf ();
a30de4
+  }
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" q - quit virt-rescue"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" s - sync the filesystems"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" u - unmount filesystems"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" x - quit virt-rescue"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  putchar (' ');
a30de4
+  print_escape_key ();
a30de4
+  printf (_(" z - suspend virt-rescue"));
a30de4
+  crlf ();
a30de4
+
a30de4
+  printf (_("to pass the escape key through to the rescue shell, type it twice"));
a30de4
+  crlf ();
a30de4
+}
a30de4
+
a30de4
+/* This is called when the user types ^] i */
a30de4
+static void
a30de4
+print_inspector (void)
a30de4
+{
a30de4
+  CLEANUP_FREE_STRING_LIST char **roots;
a30de4
+  size_t i;
a30de4
+  const char *root;
a30de4
+  char *str;
a30de4
+
a30de4
+  if (inspector) {
a30de4
+    roots = guestfs_inspect_get_roots (g);
a30de4
+    if (roots) {
a30de4
+      crlf ();
a30de4
+      for (i = 0; roots[i] != NULL; ++i) {
a30de4
+        root = roots[i];
a30de4
+        printf (_("root device: %s"), root);
a30de4
+        crlf ();
a30de4
+
a30de4
+        str = guestfs_inspect_get_product_name (g, root);
a30de4
+        if (str) {
a30de4
+          printf (_("  product name: %s"), str);
a30de4
+          crlf ();
a30de4
+        }
a30de4
+        free (str);
a30de4
+
a30de4
+        str = guestfs_inspect_get_type (g, root);
a30de4
+        if (str) {
a30de4
+          printf (_("  type: %s"), str);
a30de4
+          crlf ();
a30de4
+        }
a30de4
+        free (str);
a30de4
+
a30de4
+        str = guestfs_inspect_get_distro (g, root);
a30de4
+        if (str) {
a30de4
+          printf (_("  distro: %s"), str);
a30de4
+          crlf ();
a30de4
+        }
a30de4
+        free (str);
a30de4
+      }
a30de4
+    }
a30de4
+  }
a30de4
+}
a30de4
+
a30de4
+/* Because the terminal is in raw mode, we have to send CR LF instead
a30de4
+ * of printing just \n.
a30de4
+ */
a30de4
+static void
a30de4
+crlf (void)
a30de4
+{
a30de4
+  putchar ('\r');
a30de4
+  putchar ('\n');
a30de4
+}
a30de4
+
a30de4
+static void
a30de4
+print_escape_key (void)
a30de4
+{
a30de4
+  switch (escape_key) {
a30de4
+  case 0:
a30de4
+    printf ("none");
a30de4
+    break;
a30de4
+  case '\x1'...'\x1f':
a30de4
+    putchar ('^');
a30de4
+    putchar (escape_key + '@');
a30de4
+    break;
a30de4
+  default:
a30de4
+    abort ();
a30de4
+  }
a30de4
+}
a30de4
diff --git a/rescue/rescue.c b/rescue/rescue.c
a30de4
index 2b461378d..5281b1161 100644
a30de4
--- a/rescue/rescue.c
a30de4
+++ b/rescue/rescue.c
a30de4
@@ -1,5 +1,5 @@
a30de4
 /* virt-rescue
a30de4
- * Copyright (C) 2010-2012 Red Hat Inc.
a30de4
+ * Copyright (C) 2010-2017 Red Hat Inc.
a30de4
  *
a30de4
  * This program is free software; you can redistribute it and/or modify
a30de4
  * it under the terms of the GNU General Public License as published by
a30de4
@@ -40,10 +40,14 @@
a30de4
 #include "xvasprintf.h"
a30de4
 
a30de4
 #include "guestfs.h"
a30de4
+#include "guestfs-internal-frontend.h"
a30de4
+
a30de4
 #include "windows.h"
a30de4
 #include "options.h"
a30de4
 #include "display-options.h"
a30de4
 
a30de4
+#include "rescue.h"
a30de4
+
a30de4
 static void log_message_callback (guestfs_h *g, void *opaque, uint64_t event, int event_handle, int flags, const char *buf, size_t buf_len, const uint64_t *array, size_t array_len);
a30de4
 static void do_rescue (int sock);
a30de4
 static void raw_tty (void);
a30de4
@@ -65,6 +69,7 @@ const char *libvirt_uri = NULL;
a30de4
 int inspector = 0;
a30de4
 int in_guestfish = 0;
a30de4
 int in_virt_rescue = 1;
a30de4
+int escape_key = '\x1d';        /* ^] */
a30de4
 
a30de4
 /* Old terminal settings. */
a30de4
 static struct termios old_termios;
a30de4
@@ -86,6 +91,7 @@ usage (int status)
a30de4
               "  --append kernelopts  Append kernel options\n"
a30de4
               "  -c|--connect uri     Specify libvirt URI for -d option\n"
a30de4
               "  -d|--domain guest    Add disks from libvirt guest\n"
a30de4
+              "  -e ^x|none           Set or disable escape key (default ^])\n"
a30de4
               "  --format[=raw|..]    Force disk format for -a option\n"
a30de4
               "  --help               Display brief help\n"
a30de4
               "  -i|--inspector       Automatically mount filesystems\n"
a30de4
@@ -119,7 +125,7 @@ main (int argc, char *argv[])
a30de4
 
a30de4
   enum { HELP_OPTION = CHAR_MAX + 1 };
a30de4
 
a30de4
-  static const char options[] = "a:c:d:im:rvVwx";
a30de4
+  static const char options[] = "a:c:d:e:im:rvVwx";
a30de4
   static const struct option long_options[] = {
a30de4
     { "add", 1, 0, 'a' },
a30de4
     { "append", 1, 0, 0 },
a30de4
@@ -226,6 +232,12 @@ main (int argc, char *argv[])
a30de4
       OPTION_d;
a30de4
       break;
a30de4
 
a30de4
+    case 'e':
a30de4
+      escape_key = parse_escape_key (optarg);
a30de4
+      if (escape_key == -1)
a30de4
+        error (EXIT_FAILURE, 0, _("unrecognized escape key: %s"), optarg);
a30de4
+      break;
a30de4
+
a30de4
     case 'i':
a30de4
       OPTION_i;
a30de4
       break;
a30de4
@@ -428,6 +440,10 @@ main (int argc, char *argv[])
a30de4
   signal (SIGTSTP, tstp_handler);
a30de4
   signal (SIGCONT, cont_handler);
a30de4
 
a30de4
+  /* Print the escape key if set. */
a30de4
+  if (escape_key > 0)
a30de4
+    print_escape_key_help ();
a30de4
+
a30de4
   do_rescue (sock);
a30de4
 
a30de4
   restore_tty ();
a30de4
@@ -478,6 +494,9 @@ do_rescue (int sock)
a30de4
 {
a30de4
   size_t rlen = 0;
a30de4
   size_t wlen = 0;
a30de4
+  struct escape_state escape_state;
a30de4
+
a30de4
+  init_escape_state (&escape_state);
a30de4
 
a30de4
   while (sock >= 0 || rlen > 0) {
a30de4
     struct pollfd fds[3];
a30de4
@@ -534,6 +553,13 @@ do_rescue (int sock)
a30de4
       }
a30de4
       if (n > 0)
a30de4
         wlen += n;
a30de4
+
a30de4
+      /* Process escape sequences in the tty input.  If the function
a30de4
+       * returns true, then we exit the loop causing virt-rescue to
a30de4
+       * exit.
a30de4
+       */
a30de4
+      if (escape_key > 0 && process_escapes (&escape_state, wbuf, &wlen))
a30de4
+        return;
a30de4
     }
a30de4
 
a30de4
     /* Log message from appliance. */
a30de4
diff --git a/rescue/rescue.h b/rescue/rescue.h
a30de4
new file mode 100644
a30de4
index 000000000..ccffb5eb3
a30de4
--- /dev/null
a30de4
+++ b/rescue/rescue.h
a30de4
@@ -0,0 +1,47 @@
a30de4
+/* virt-rescue
a30de4
+ * Copyright (C) 2010-2017 Red Hat Inc.
a30de4
+ *
a30de4
+ * This program is free software; you can redistribute it and/or modify
a30de4
+ * it under the terms of the GNU General Public License as published by
a30de4
+ * the Free Software Foundation; either version 2 of the License, or
a30de4
+ * (at your option) any later version.
a30de4
+ *
a30de4
+ * This program is distributed in the hope that it will be useful,
a30de4
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
a30de4
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
a30de4
+ * GNU General Public License for more details.
a30de4
+ *
a30de4
+ * You should have received a copy of the GNU General Public License
a30de4
+ * along with this program; if not, write to the Free Software
a30de4
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
a30de4
+ */
a30de4
+
a30de4
+#ifndef RESCUE_H
a30de4
+#define RESCUE_H
a30de4
+
a30de4
+#include <stdbool.h>
a30de4
+
a30de4
+#include "guestfs.h"
a30de4
+
a30de4
+extern guestfs_h *g;
a30de4
+extern int read_only;
a30de4
+extern int live;
a30de4
+extern int verbose;
a30de4
+extern int keys_from_stdin;
a30de4
+extern int echo_keys;
a30de4
+extern const char *libvirt_uri;
a30de4
+extern int inspector;
a30de4
+extern int in_guestfish;
a30de4
+extern int in_virt_rescue;
a30de4
+extern int escape_key;
a30de4
+
a30de4
+/* escape.c */
a30de4
+struct escape_state {
a30de4
+  bool in_escape;
a30de4
+};
a30de4
+extern void init_escape_state (struct escape_state *state);
a30de4
+extern bool process_escapes (struct escape_state *state, char *buf, size_t *len);
a30de4
+extern int parse_escape_key (const char *);
a30de4
+extern void print_escape_key_help (void);
a30de4
+
a30de4
+#endif /* RESCUE_H */
a30de4
diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
a30de4
index b651f84e7..bd6f954e9 100644
a30de4
--- a/rescue/virt-rescue.pod
a30de4
+++ b/rescue/virt-rescue.pod
a30de4
@@ -128,6 +128,29 @@ not used at all.
a30de4
 Add all the disks from the named libvirt guest.  Domain UUIDs can be
a30de4
 used instead of names.
a30de4
 
a30de4
+=item B<-e none>
a30de4
+
a30de4
+Disable the escape key.
a30de4
+
a30de4
+=item B<-e> KEY
a30de4
+
a30de4
+Set the escape key to the given key sequence.  The default is C<^]>.
a30de4
+To specify the escape key you can use:
a30de4
+
a30de4
+=over 4
a30de4
+
a30de4
+=item C<^x>
a30de4
+
a30de4
+Control key + C<x> key.
a30de4
+
a30de4
+=item C<none>
a30de4
+
a30de4
+I<-e none> means there is no escape key, escapes are disabled.
a30de4
+
a30de4
+=back
a30de4
+
a30de4
+See L</ESCAPE KEY> below for further information.
a30de4
+
a30de4
 =item B<--format=raw|qcow2|..>
a30de4
 
a30de4
 =item B<--format>
a30de4
@@ -321,6 +344,57 @@ See L<bash(1)> for more details.
a30de4
 
a30de4
 =back
a30de4
 
a30de4
+=head1 ESCAPE KEY
a30de4
+
a30de4
+Virt-rescue supports various keyboard escape sequences which are
a30de4
+entered by pressing C<^]> (Control key + C<]> key).
a30de4
+
a30de4
+You can change the escape key using the I<-e> option on the command
a30de4
+line (see above), and you can disable escapes completely using
a30de4
+I<-e none>.  The rest of this section assumes the default escape key.
a30de4
+
a30de4
+The following escapes can be used:
a30de4
+
a30de4
+=over 4
a30de4
+
a30de4
+=item C<^] ?>
a30de4
+
a30de4
+=item C<^] h>
a30de4
+
a30de4
+Prints a brief help text about escape sequences.
a30de4
+
a30de4
+=item C<^] i>
a30de4
+
a30de4
+Prints brief libguestfs inspection information for the guest.  This
a30de4
+only works if you used I<-i> on the virt-rescue command line.
a30de4
+
a30de4
+=item C<^] q>
a30de4
+
a30de4
+=item C<^] x>
a30de4
+
a30de4
+Quits virt-rescue immediately.
a30de4
+
a30de4
+=item C<^] s>
a30de4
+
a30de4
+Synchronize the filesystems (sync).
a30de4
+
a30de4
+=item C<^] u>
a30de4
+
a30de4
+Unmounts all the filesystems, except for the root (appliance)
a30de4
+filesystems.
a30de4
+
a30de4
+=item C<^] z>
a30de4
+
a30de4
+Suspend virt-rescue (like pressing C<^Z> except that it affects
a30de4
+virt-rescue rather than the program inside the rescue shell).
a30de4
+
a30de4
+=item C<^] ^]>
a30de4
+
a30de4
+Sends the literal character C<^]> (ASCII 0x1d) through to the rescue
a30de4
+shell.
a30de4
+
a30de4
+=back
a30de4
+
a30de4
 =head1 CAPTURING CORE DUMPS
a30de4
 
a30de4
 If you are testing a tool inside virt-rescue and the tool (B<not>
a30de4
-- 
a30de4
2.14.3
a30de4