This implements a few useful escape sequences:
<rescue> ^]?
virt-rescue escape sequences:
^]? - print this message
^]h - print this message
^]i - print inspection data
^]q - quit virt-rescue
^]u - unmount filesystems
^]x - quit virt-rescue
to send the escape key to the rescue shell, type it twice
^]i
root device: /dev/sda3
product name: Fedora 25 (Twenty Five)
type: linux
distro: fedora
^]u
unmounting filesystems ...
[ 21.158558] XFS (sda3): Unmounting Filesystem
---
rescue/rescue.c | 145 ++++++++++++++++++++++++++++++++++++++++++++++++-
rescue/virt-rescue.pod | 65 ++++++++++++++++++++++
2 files changed, 209 insertions(+), 1 deletion(-)
diff --git a/rescue/rescue.c b/rescue/rescue.c
index fb747df..06920c2 100644
--- a/rescue/rescue.c
+++ b/rescue/rescue.c
@@ -20,6 +20,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <string.h>
#include <inttypes.h>
#include <unistd.h>
@@ -32,6 +33,7 @@
#include <assert.h>
#include <libintl.h>
+#include "c-ctype.h"
#include "full-write.h"
#include "getprogname.h"
#include "ignore-value.h"
@@ -61,6 +63,7 @@ const char *libvirt_uri = NULL;
int inspector = 0;
int in_guestfish = 0;
int in_virt_rescue = 1;
+int escape_key = '\x1d'; /* ^] */
/* Old terminal settings. */
static struct termios old_termios;
@@ -115,7 +118,7 @@ main (int argc, char *argv[])
enum { HELP_OPTION = CHAR_MAX + 1 };
- static const char options[] = "a:c:d:im:rvVwx";
+ static const char options[] = "a:c:d:e:im:rvVwx";
static const struct option long_options[] = {
{ "add", 1, 0, 'a' },
{ "append", 1, 0, 0 },
@@ -223,6 +226,24 @@ main (int argc, char *argv[])
OPTION_d;
break;
+ case 'e':
+ if (STREQ (optarg, "none"))
+ escape_key = 0;
+ else if (STRPREFIX (optarg, "^")) {
+ if (strlen (optarg) == 2 &&
+ ((optarg[1] >= 'a' && optarg[1] <= 'z') ||
+ (optarg[1] >= 'A' && optarg[1] <= '_'))) {
+ escape_key = c_toupper (optarg[1]) - '@';
+ }
+ else
+ error (EXIT_FAILURE, 0,
+ _("unrecognized ^-escape in -e option: %s"), optarg);
+ }
+ else
+ error (EXIT_FAILURE, 0,
+ _("unrecognized escape key: %s"), optarg);
+ break;
+
case 'i':
OPTION_i;
break;
@@ -463,6 +484,9 @@ log_message_callback (guestfs_h *g, void *opaque, uint64_t event,
static char rbuf[BUFSIZE]; /* appliance -> local tty */
static char wbuf[BUFSIZE]; /* local tty -> appliance */
+static bool process_escapes (char *buf, size_t *len);
+static void print_escape_key (void);
+
static void
do_rescue (int sock)
{
@@ -524,6 +548,13 @@ do_rescue (int sock)
}
if (n > 0)
wlen += n;
+
+ /* Process escape sequences in the tty input. If the function
+ * returns true, then we exit the loop causing virt-rescue to
+ * exit.
+ */
+ if (escape_key > 0 && process_escapes (wbuf, &wlen))
+ return;
}
/* Log message from appliance. */
@@ -576,6 +607,118 @@ do_rescue (int sock)
}
}
+/* Process escapes in the tty input buffer.
+ *
+ * This function has internal state so that we can handle an escape
+ * sequence split over the end of the buffer. Escape sequences are
+ * removed from the buffer.
+ *
+ * Returns true iff virt-rescue should exit.
+ */
+static bool
+process_escapes (char *buf, size_t *len)
+{
+ size_t i;
+ static bool in_escape = false;
+
+ for (i = 0; i < *len; ++i) {
+ if (!in_escape) {
+ if (buf[i] == escape_key) {
+ /* Drop the escape key from the buffer and go to escape mode. */
+ memmove (&buf[i], &buf[i+1], --(*len));
+ in_escape = 1;
+ }
+ }
+ else /* in escape sequence */ {
+ if (buf[i] == escape_key) /* ^] ^] means send ^] to rescue shell */
+ in_escape = 0;
+ else {
+ switch (buf[i]) {
+ case '?': case 'h':
+ printf ("\r\n");
+ printf (_("virt-rescue escape sequences:\r\n"));
+ print_escape_key (); printf (_("? - print this message\r\n"));
+ print_escape_key (); printf (_("h - print this message\r\n"));
+ if (inspector) {
+ print_escape_key (); printf (_("i - print inspection data\r\n"));
+ }
+ print_escape_key (); printf (_("q - quit virt-rescue\r\n"));
+ print_escape_key (); printf (_("u - unmount filesystems\r\n"));
+ print_escape_key (); printf (_("x - quit virt-rescue\r\n"));
+ printf (_("to send the escape key to the rescue shell, type it
twice\r\n"));
+ break;
+
+ case 'i':
+ if (inspector) {
+ CLEANUP_FREE_STRING_LIST char **roots;
+ size_t i;
+
+ roots = guestfs_inspect_get_roots (g);
+ if (roots) {
+ printf ("\r\n");
+ for (i = 0; roots[i] != NULL; ++i) {
+ const char *root = roots[i];
+ char *str;
+
+ printf (_("root device: %s\r\n"), root);
+ str = guestfs_inspect_get_product_name (g, root);
+ if (str)
+ printf (_(" product name: %s\r\n"), str);
+ free (str);
+ str = guestfs_inspect_get_type (g, root);
+ if (str)
+ printf (_(" type: %s\r\n"), str);
+ free (str);
+ str = guestfs_inspect_get_distro (g, root);
+ if (str)
+ printf (_(" distro: %s\r\n"), str);
+ free (str);
+ }
+ }
+ }
+ break;
+
+ case 'q': case 'x':
+ return true /* exit virt-rescue at once */;
+
+ case 'u':
+ printf ("\r\n");
+ printf (_("unmounting filesystems ...\r\n"));
+ guestfs_umount_all (g);
+ break;
+
+ default:
+ /* Any unrecognized escape sequence will be dropped. We could
+ * be obnoxious and ring the bell. XXX
+ */
+ break;
+ }
+ /* Drop the escape key and return to non-escape mode. */
+ memmove (&buf[i], &buf[i+1], --(*len));
+ in_escape = 0;
+ }
+ }
+ }
+
+ return false /* don't exit */;
+}
+
+static void
+print_escape_key (void)
+{
+ switch (escape_key) {
+ case 0:
+ printf ("none");
+ break;
+ case '\x1'...'\x1f':
+ putchar ('^');
+ putchar (escape_key + '@');
+ break;
+ default:
+ abort ();
+ }
+}
+
static void
restore_tty (void)
{
diff --git a/rescue/virt-rescue.pod b/rescue/virt-rescue.pod
index b651f84..6439b98 100644
--- a/rescue/virt-rescue.pod
+++ b/rescue/virt-rescue.pod
@@ -128,6 +128,29 @@ not used at all.
Add all the disks from the named libvirt guest. Domain UUIDs can be
used instead of names.
+=item B<-e none>
+
+Disable the escape key.
+
+=item B<-e> KEY
+
+Set the escape key to the given key sequence. The default is C<^]>.
+To specify the escape key you can use:
+
+=over 4
+
+=item C<^x>
+
+Control key + C<x> key.
+
+=item C<none>
+
+I<-e none> means there is no escape key, escapes are disabled.
+
+=back
+
+See L</ESCAPE KEY> below for further information.
+
=item B<--format=raw|qcow2|..>
=item B<--format>
@@ -321,6 +344,48 @@ See L<bash(1)> for more details.
=back
+=head1 ESCAPE KEY
+
+Virt-rescue supports various keyboard escape sequences which are
+entered by pressing C<^]> (Control key + C<]> key).
+
+You can change the escape key using the I<-e> option on the command
+line (see above), and you can disable escapes completely using
+I<-e none>. The rest of this section assumes the default escape key.
+
+The following escapes can be used:
+
+=over 4
+
+=item C<^] ?>
+
+=item C<^] h>
+
+Prints a brief help text about escape sequences.
+
+=item C<^] i>
+
+Prints brief libguestfs inspection information for the guest. This
+only works if you used I<-i> on the virt-rescue command line.
+
+=item C<^] q>
+
+=item C<^] x>
+
+Quits virt-rescue immediately.
+
+=item C<^] u>
+
+Unmounts all the filesystems, except for the root (appliance)
+filesystems.
+
+=item C<^] ^]>
+
+Sends the literal character C<^]> (ASCII 0x1d) through to the rescue
+shell.
+
+=back
+
=head1 CAPTURING CORE DUMPS
If you are testing a tool inside virt-rescue and the tool (B<not>
--
2.9.3