rescue: Rewrite virt-rescue in C.

This commit is contained in:
Richard W.M. Jones
2010-11-26 11:36:50 +00:00
parent 076a9726e6
commit a6054bf90f
10 changed files with 731 additions and 127 deletions

4
.gitignore vendored
View File

@@ -283,6 +283,10 @@ regressions/test1.img
regressions/test2.img
regressions/test.err
regressions/test.out
rescue/stamp-virt-rescue.pod
rescue/virt-rescue
rescue/virt-rescue.1
rescue/virt-rescue.static
ruby/bindtests.rb
ruby/examples/guestfs-ruby.3
ruby/examples/stamp-guestfs-ruby.pod

View File

@@ -148,6 +148,9 @@ python/
regressions/
Regression tests.
rescue/
'virt-rescue' command and documentation.
ruby/
Ruby bindings.

View File

@@ -36,7 +36,7 @@ SUBDIRS += gnulib/tests capitests regressions test-tool
SUBDIRS += fish
# virt-tools in C.
SUBDIRS += cat df inspector
SUBDIRS += cat df inspector rescue
# Language bindings.
if HAVE_PERL
@@ -225,5 +225,7 @@ bindist:
cp df/virt-df.static $(BINTMPDIR)$(bindir)/virt-df
$(MAKE) -C inspector virt-inspector.static
cp inspector/virt-inspector.static $(BINTMPDIR)$(bindir)/virt-inspector
$(MAKE) -C rescue virt-rescue.static
cp rescue/virt-rescue.static $(BINTMPDIR)$(bindir)/virt-rescue
(cd $(BINTMPDIR) && tar cf - .) | \
gzip -c -9 > libguestfs-$(VERSION)-$(host_cpu).tar.gz

View File

@@ -869,6 +869,7 @@ AC_CONFIG_FILES([Makefile
csharp/Makefile
cat/Makefile
df/Makefile
rescue/Makefile
ocaml/META perl/Makefile.PL])
AC_OUTPUT

View File

@@ -126,6 +126,7 @@ regressions/rhbz501893.c
regressions/test-launch-race.pl
regressions/test-lvm-mapping.pl
regressions/test-noexec-stack.pl
rescue/virt-rescue.c
ruby/ext/guestfs/_guestfs.c
src/actions.c
src/appliance.c
@@ -145,7 +146,6 @@ tools/virt-edit.pl
tools/virt-list-filesystems.pl
tools/virt-list-partitions.pl
tools/virt-make-fs.pl
tools/virt-rescue.pl
tools/virt-resize.pl
tools/virt-tar.pl
tools/virt-win-reg.pl

67
rescue/Makefile.am Normal file
View File

@@ -0,0 +1,67 @@
# libguestfs virt-rescue
# Copyright (C) 2010 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \
run-rescue-locally \
virt-rescue.pod
CLEANFILES = stamp-virt-rescue.pod
bin_PROGRAMS = virt-rescue
SHARED_SOURCE_FILES = \
../fish/inspect.c \
../fish/keys.c \
../fish/options.h \
../fish/options.c \
../fish/virt.c
virt_rescue_SOURCES = \
$(SHARED_SOURCE_FILES) \
virt-rescue.c
virt_rescue_CFLAGS = \
-I$(top_srcdir)/src -I$(top_builddir)/src \
-I$(top_srcdir)/fish \
-I$(srcdir)/../gnulib/lib -I../gnulib/lib \
-DLOCALEBASEDIR=\""$(datadir)/locale"\" \
$(WARN_CFLAGS) $(WERROR_CFLAGS)
virt_rescue_LDADD = \
$(top_builddir)/src/libguestfs.la \
../gnulib/lib/libgnu.la
# Manual pages and HTML files for the website.
man_MANS = virt-rescue.1
noinst_DATA = $(top_builddir)/html/virt-rescue.1.html
virt-rescue.1 $(top_builddir)/html/virt-rescue.1.html: stamp-virt-rescue.pod
stamp-virt-rescue.pod: virt-rescue.pod
$(top_srcdir)/podwrapper.sh \
--man virt-rescue.1 \
--html $(top_builddir)/html/virt-rescue.1.html \
$<
touch $@
# Build a partly-static binary (for the binary distribution).
virt-rescue.static$(EXEEXT): $(virt_rescue_OBJECTS) $(virt_rescue_DEPENDENCIES)
$(top_srcdir)/relink-static.sh \
$(virt_rescue_LINK) $(virt_rescue_OBJECTS) -static $(virt_rescue_LDADD) $(virt_rescue_LIBS) $(LIBVIRT_LIBS) $(LIBXML2_LIBS) -lpcre -lhivex -lmagic -lz -lm

52
rescue/run-rescue-locally Executable file
View File

@@ -0,0 +1,52 @@
#!/usr/bin/perl
# Copyright (C) 2009 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
# This script sets up the environment so you can run virt-* tools in
# place without needing to do 'make install' first. You can also run
# the tools by creating a symlink to this script and putting it in
# your path.
#
# Use it like this:
# ./run-rescue-locally [usual virt-rescue args ...]
use strict;
use warnings;
use File::Basename qw(dirname);
use File::Spec;
use Cwd qw(abs_path);
my $path = $0;
# Follow symlinks until we get to the real file
while(-l $path) {
my $link = readlink($path) or die "readlink: $path: $!";
if(File::Spec->file_name_is_absolute($link)) {
$path = $link;
} else {
$path = File::Spec->catfile(dirname($path), $link);
}
}
# Get the absolute path of the parent directory
$path = abs_path(dirname($path).'/..');
$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
#print (join " ", ("$path/rescue/virt-rescue", @ARGV), "\n");
exec("$path/rescue/virt-rescue", @ARGV);

526
rescue/virt-rescue.c Normal file
View File

@@ -0,0 +1,526 @@
/* virt-rescue
* Copyright (C) 2010 Red Hat Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <assert.h>
#include "progname.h"
#include "xvasprintf.h"
#include "guestfs.h"
#include "options.h"
/* Currently open libguestfs handle. */
guestfs_h *g;
int read_only = 0;
int verbose = 0;
int keys_from_stdin = 0;
int echo_keys = 0;
const char *libvirt_uri = NULL;
int inspector = 0;
static inline char *
bad_cast (char const *s)
{
return (char *) s;
}
static void __attribute__((noreturn))
usage (int status)
{
if (status != EXIT_SUCCESS)
fprintf (stderr, _("Try `%s --help' for more information.\n"),
program_name);
else {
fprintf (stdout,
_("%s: Run a rescue shell on a virtual machine\n"
"Copyright (C) 2009-2010 Red Hat Inc.\n"
"Usage:\n"
" %s [--options] -d domname\n"
" %s [--options] -a disk.img [-a disk.img ...]\n"
"Options:\n"
" -a|--add image Add image\n"
" --append kernelopts Append kernel options\n"
" -c|--connect uri Specify libvirt URI for -d option\n"
" -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"
" --network Enable network\n"
" -r|--ro Access read-only\n"
" --selinux Enable SELinux\n"
" -v|--verbose Verbose messages\n"
" -V|--version Display version and exit\n"
" -x Trace libguestfs API calls\n"
"For more information, see the manpage %s(1).\n"),
program_name, program_name, program_name,
program_name);
}
exit (status);
}
int
main (int argc, char *argv[])
{
/* Set global program name that is not polluted with libtool artifacts. */
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEBASEDIR);
textdomain (PACKAGE);
enum { HELP_OPTION = CHAR_MAX + 1 };
static const char *options = "a:c:d:m:rvVx";
static const struct option long_options[] = {
{ "add", 1, 0, 'a' },
{ "append", 1, 0, 0 },
{ "connect", 1, 0, 'c' },
{ "domain", 1, 0, 'd' },
{ "format", 2, 0, 0 },
{ "help", 0, 0, HELP_OPTION },
{ "memsize", 1, 0, 'm' },
{ "network", 0, 0, 0 },
{ "ro", 0, 0, 'r' },
{ "selinux", 0, 0, 0 },
{ "verbose", 0, 0, 'v' },
{ "version", 0, 0, 'V' },
{ 0, 0, 0, 0 }
};
struct drv *drvs = NULL;
struct drv *drv;
char *p, *file = NULL;
const char *format = NULL;
int c;
int option_index;
int network = 0;
const char *append = NULL;
char *append_full;
int memsize = 0;
g = guestfs_create ();
if (g == NULL) {
fprintf (stderr, _("guestfs_create: failed to create handle\n"));
exit (EXIT_FAILURE);
}
argv[0] = bad_cast (program_name);
for (;;) {
c = getopt_long (argc, argv, options, long_options, &option_index);
if (c == -1) break;
switch (c) {
case 0: /* options which are long only */
if (STREQ (long_options[option_index].name, "selinux")) {
guestfs_set_selinux (g, 1);
} else if (STREQ (long_options[option_index].name, "append")) {
append = optarg;
} else if (STREQ (long_options[option_index].name, "network")) {
network = 1;
} else if (STREQ (long_options[option_index].name, "format")) {
if (!optarg || STREQ (optarg, ""))
format = NULL;
else
format = optarg;
} else {
fprintf (stderr, _("%s: unknown long option: %s (%d)\n"),
program_name, long_options[option_index].name, option_index);
exit (EXIT_FAILURE);
}
break;
case 'a':
OPTION_a;
break;
case 'c':
OPTION_c;
break;
case 'd':
OPTION_d;
break;
case 'h':
usage (EXIT_SUCCESS);
case 'm':
if (sscanf (optarg, "%u", &memsize) != 1) {
fprintf (stderr, _("%s: could not parse memory size '%s'\n"),
program_name, optarg);
exit (EXIT_FAILURE);
}
break;
case 'r':
OPTION_r;
break;
case 'v':
OPTION_v;
break;
case 'V':
OPTION_V;
break;
case 'x':
OPTION_x;
break;
case HELP_OPTION:
usage (EXIT_SUCCESS);
default:
usage (EXIT_FAILURE);
}
}
/* Old-style syntax? There were no -a or -d options in the old
* virt-rescue which is how we detect this.
*/
if (drvs == NULL) {
while (optind < argc) {
if (strchr (argv[optind], '/') ||
access (argv[optind], F_OK) == 0) { /* simulate -a option */
drv = malloc (sizeof (struct drv));
if (!drv) {
perror ("malloc");
exit (EXIT_FAILURE);
}
drv->type = drv_a;
drv->a.filename = argv[optind];
drv->a.format = NULL;
drv->next = drvs;
drvs = drv;
} else { /* simulate -d option */
drv = malloc (sizeof (struct drv));
if (!drv) {
perror ("malloc");
exit (EXIT_FAILURE);
}
drv->type = drv_d;
drv->d.guest = argv[optind];
drv->next = drvs;
drvs = drv;
}
optind++;
}
}
/* These are really constants, but they have to be variables for the
* options parsing code. Assert here that they have known-good
* values.
*/
assert (inspector == 0);
assert (keys_from_stdin == 0);
assert (echo_keys == 0);
/* Must be no extra arguments on the command line. */
if (optind != argc)
usage (EXIT_FAILURE);
/* User must have specified some drives. */
if (drvs == NULL)
usage (EXIT_FAILURE);
/* Setting "direct mode" is required for the rescue appliance. */
guestfs_set_direct (g, 1);
/* Set other features. */
if (memsize > 0)
guestfs_set_memsize (g, memsize);
if (network)
guestfs_set_network (g, 1);
/* Kernel command line must include guestfs_rescue=1 (see
* appliance/init) as well as other options.
*/
append_full = xasprintf ("guestfs_rescue=1%s%s",
append ? " " : "",
append ? append : "");
guestfs_set_append (g, append_full);
free (append_full);
/* Add drives. */
add_drives (drvs, 'a');
/* Free up data structures, no longer needed after this point. */
free_drives (drvs);
/* Run the appliance. This won't return until the user quits the
* appliance.
*/
guestfs_set_error_handler (g, NULL, NULL);
guestfs_launch (g);
/* launch() expects guestfsd to start. However, virt-rescue doesn't
* run guestfsd, so this will always fail with ECHILD when the
* appliance exits unexpectedly.
*/
if (errno != ECHILD) {
fprintf (stderr, "%s: %s\n", program_name, guestfs_last_error (g));
guestfs_close (g);
exit (EXIT_FAILURE);
}
guestfs_close (g);
exit (EXIT_SUCCESS);
}
/* The following was a nice idea, but in fact it doesn't work. This is
* because qemu has some (broken) pty emulation itself.
*/
#if 0
int fd_m, fd_s, r;
pid_t pid;
struct termios tsorig, tsnew;
/* Set up pty. */
fd_m = posix_openpt (O_RDWR);
if (fd_m == -1) {
perror ("posix_openpt");
exit (EXIT_FAILURE);
}
r = grantpt (fd_m);
if (r == -1) {
perror ("grantpt");
exit (EXIT_FAILURE);
}
r = unlockpt (fd_m);
if (r == -1) {
perror ("unlockpt");
exit (EXIT_FAILURE);
}
fd_s = open (ptsname (fd_m), O_RDWR);
if (fd_s == -1) {
perror ("open ptsname");
exit (EXIT_FAILURE);
}
pid = fork ();
if (pid == -1) {
perror ("fork");
exit (EXIT_FAILURE);
}
if (pid == 0) {
/* Child process. */
#if 1
/* Set raw mode. */
r = tcgetattr (fd_s, &tsorig);
tsnew = tsorig;
cfmakeraw (&tsnew);
tcsetattr (fd_s, TCSANOW, &tsnew);
#endif
/* Close the master side of pty and set slave side as
* stdin/stdout/stderr.
*/
close (fd_m);
close (0);
close (1);
close (2);
if (dup (fd_s) == -1 || dup (fd_s) == -1 || dup (fd_s) == -1) {
perror ("dup");
exit (EXIT_FAILURE);
}
close (fd_s);
#if 1
if (setsid () == -1)
perror ("warning: failed to setsid");
if (ioctl (0, TIOCSCTTY, 0) == -1)
perror ("warning: failed to TIOCSCTTY");
#endif
/* Run the appliance. This won't return until the user quits the
* appliance.
*/
guestfs_set_error_handler (g, NULL, NULL);
r = guestfs_launch (g);
/* launch() expects guestfsd to start. However, virt-rescue doesn't
* run guestfsd, so this will always fail with ECHILD when the
* appliance exits unexpectedly.
*/
if (errno != ECHILD) {
fprintf (stderr, "%s: %s\n", program_name, guestfs_last_error (g));
guestfs_close (g);
exit (EXIT_FAILURE);
}
guestfs_close (g);
_exit (EXIT_SUCCESS);
}
/* Parent process continues ... */
/* Close slave side of pty. */
close (fd_s);
/* Set raw mode. */
r = tcgetattr (fd_s, &tsorig);
tsnew = tsorig;
cfmakeraw (&tsnew);
tcsetattr (fd_s, TCSANOW, &tsnew);
/* Send input and output to master side of pty. */
r = multiplex (fd_m);
tcsetattr (fd_s, TCSANOW, &tsorig); /* Restore cooked mode. */
if (r == -1)
exit (EXIT_FAILURE);
if (waitpid (pid, &r, 0) == -1) {
perror ("waitpid");
exit (EXIT_FAILURE);
}
if (!WIFEXITED (r)) {
/* abnormal child exit */
fprintf (stderr, _("%s: unknown child exit status (%d)\n"),
program_name, r);
exit (EXIT_FAILURE);
}
else
exit (WEXITSTATUS (r)); /* normal exit, return child process's status */
}
/* Naive and simple multiplex function. */
static int
multiplex (int fd_m)
{
int r, eof_stdin = 0;
fd_set rfds, wfds;
char tobuf[BUFSIZ], frombuf[BUFSIZ]; /* to/from slave */
size_t tosize = 0, fromsize = 0;
ssize_t n;
size_t count;
long flags_0, flags_1, flags_fd_m;
flags_0 = fcntl (0, F_GETFL);
fcntl (0, F_SETFL, O_NONBLOCK | flags_0);
flags_1 = fcntl (0, F_GETFL);
fcntl (1, F_SETFL, O_NONBLOCK | flags_1);
flags_fd_m = fcntl (0, F_GETFL);
fcntl (fd_m, F_SETFL, O_NONBLOCK | flags_fd_m);
for (;;) {
FD_ZERO (&rfds);
FD_ZERO (&wfds);
/* Still space in to-buffer? If so, we can read from the user. */
if (!eof_stdin && tosize < BUFSIZ)
FD_SET (0, &rfds);
/* Still space in from-buffer? If so, we can read from the slave. */
if (fromsize < BUFSIZ)
FD_SET (fd_m, &rfds);
/* Content in to-buffer? If so, we want to write to the slave. */
if (tosize > 0)
FD_SET (fd_m, &wfds);
/* Content in from-buffer? If so, we want to write to the user. */
if (fromsize > 0)
FD_SET (1, &wfds);
r = select (fd_m+1, &rfds, &wfds, NULL, NULL);
if (r == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
perror ("select");
return -1;
}
/* Input from user: Put it in the to-buffer. */
if (FD_ISSET (0, &rfds)) {
count = BUFSIZ - tosize;
n = read (0, &tobuf[tosize], count);
if (n == -1) {
perror ("read");
return -1;
}
if (n == 0) { /* stdin was closed */
eof_stdin = 1;
/* This is what telnetd does ... */
tobuf[tosize] = '\004';
tosize += 1;
} else
tosize += n;
}
/* Input from slave: Put it in the from-buffer. */
if (FD_ISSET (fd_m, &rfds)) {
count = BUFSIZ - fromsize;
n = read (fd_m, &frombuf[fromsize], count);
if (n == -1) {
if (errno != EIO) /* EIO if slave process dies */
perror ("read");
break;
}
if (n == 0) /* slave closed the connection */
break;
fromsize += n;
}
/* Can write to user. */
if (FD_ISSET (1, &wfds)) {
n = write (1, frombuf, fromsize);
if (n == -1) {
perror ("write");
return -1;
}
memmove (frombuf, &frombuf[n], BUFSIZ - n);
fromsize -= n;
}
/* Can write to slave. */
if (FD_ISSET (fd_m, &wfds)) {
n = write (fd_m, tobuf, tosize);
if (n == -1) {
perror ("write");
return -1;
}
memmove (tobuf, &tobuf[n], BUFSIZ - n);
tosize -= n;
}
} /* for (;;) */
/* We end up here when slave has closed the connection. */
close (fd_m);
/* Restore blocking behaviour. */
fcntl (1, F_SETFL, flags_1);
/* Last chance to write out any remaining data in the buffers, but
* don't bother about errors.
*/
ignore_value (write (1, frombuf, fromsize));
return 0;
}
#endif

View File

@@ -1,31 +1,3 @@
#!/usr/bin/perl -w
# virt-rescue
# Copyright (C) 2009-2010 Red Hat Inc.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
use warnings;
use strict;
use Errno;
use Sys::Guestfs;
use Sys::Guestfs::Lib qw(open_guest);
use Pod::Usage;
use Getopt::Long;
use Locale::TextDomain 'libguestfs';
=encoding utf8
=head1 NAME
@@ -34,6 +6,12 @@ virt-rescue - Run a rescue shell on a virtual machine
=head1 SYNOPSIS
virt-rescue [--options] -d domname
virt-rescue [--options] -a disk.img [-a disk.img ...]
Old style:
virt-rescue [--options] domname
virt-rescue [--options] disk.img [disk.img ...]
@@ -58,11 +36,11 @@ machine or disk image.
You can run virt-rescue on any virtual machine known to libvirt, or
directly on disk image(s):
virt-rescue GuestName
virt-rescue -d GuestName
virt-rescue --ro /path/to/disk.img
virt-rescue --ro -a /path/to/disk.img
virt-rescue /dev/sdc
virt-rescue -a /dev/sdc
For live VMs you I<must> use the --ro option.
@@ -104,83 +82,82 @@ use to make scripted changes to guests, use L<guestfish(1)>.
=over 4
=cut
my $help;
=item B<--help>
Display brief help.
=cut
=item B<-a> file
my $version;
=item B<--add> file
=item B<--version>
Add I<file> which should be a disk image from a virtual machine. If
the virtual machine has multiple block devices, you must supply all of
them with separate I<-a> options.
Display version number and exit.
=cut
my $append;
The format of the disk image is auto-detected. To override this and
force a particular format use the I<--format=..> option.
=item B<--append kernelopts>
Pass additional options to the rescue kernel.
=cut
=item B<-c> URI
my $uri;
=item B<--connect URI> | B<-c URI>
=item B<--connect> URI
If using libvirt, connect to the given I<URI>. If omitted, then we
connect to the default libvirt hypervisor.
If you specify guest block devices directly, then libvirt is not used
at all.
If you specify guest block devices directly (I<-a>), then libvirt is
not used at all.
=cut
=item B<-d> guest
my $format;
=item B<--domain> guest
=item B<--format> raw
Add all the disks from the named libvirt guest.
Specify the format of disk images given on the command line. If this
is omitted then the format is autodetected from the content of the
disk image.
=item B<--format=raw|qcow2|..>
If disk images are requested from libvirt, then this program asks
libvirt for this information. In this case, the value of the format
parameter is ignored.
=item B<--format>
If working with untrusted raw-format guest disk images, you should
ensure the format is always specified.
The default for the I<-a> option is to auto-detect the format of the
disk image. Using this forces the disk format for I<-a> options which
follow on the command line. Using I<--format> with no argument
switches back to auto-detection for subsequent I<-a> options.
=cut
For example:
my $memsize;
virt-rescue --format=raw -a disk.img
=item B<--memsize MB> | B<-m MB>
forces raw format (no auto-detection) for C<disk.img>.
virt-rescue --format=raw -a disk.img --format -a another.img
forces raw format (no auto-detection) for C<disk.img> and reverts to
auto-detection for C<another.img>.
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). See also
L</add-drive-opts>.
=item B<-m MB>
=item B<--memsize MB>
Change the amount of memory allocated to the rescue system. The
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.
=cut
my $network;
=item B<--network>
Enable QEMU user networking in the guest.
=cut
=item B<-r>
my $readonly;
=item B<--ro> | B<-r>
=item B<--ro>
Open the image read-only.
@@ -188,69 +165,44 @@ The option must always be used if the disk image or virtual machine
might be running, and is generally recommended in cases where you
don't need write access to the disk.
=cut
my $selinux;
=item B<--selinux>
Enable SELinux in the rescue appliance. You should read
L<guestfs(3)/SELINUX> before using this option.
=item B<-v>
=item B<--verbose>
Enable verbose messages for debugging.
=item B<-V>
=item B<--version>
Display version number and exit.
=item B<-x>
Enable tracing of libguestfs API calls.
=back
=cut
=head1 OLD-STYLE COMMAND LINE ARGUMENTS
GetOptions ("help|?" => \$help,
"version" => \$version,
"append=s" => \$append,
"connect|c=s" => \$uri,
"format=s" => \$format,
"memsize|m=i" => \$memsize,
"network" => \$network,
"ro|r" => \$readonly,
"selinux" => \$selinux,
) or pod2usage (2);
pod2usage (1) if $help;
if ($version) {
my $g = Sys::Guestfs->new ();
my %h = $g->version ();
print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
exit
}
Previous versions of virt-rescue allowed you to write either:
pod2usage (__"virt-rescue: no image or VM names rescue given")
if @ARGV == 0;
virt-rescue disk.img [disk.img ...]
my @args = (\@ARGV);
push @args, address => $uri if $uri;
push @args, rw => 1 unless $readonly;
push @args, format => $format if defined $format;
my $g = open_guest (@args);
or
# Setting "direct mode" is required for the rescue appliance.
$g->set_direct (1);
virt-rescue guestname
# Set other features.
$g->set_selinux (1) if $selinux;
$g->set_memsize ($memsize) if defined $memsize;
$g->set_network (1) if $network;
whereas in this version you should use I<-a> or I<-d> respectively
to avoid the confusing case where a disk image might have the same
name as a guest.
# Set the kernel command line, which must include guestfs_rescue=1
# (see appliance/init).
my $str = "guestfs_rescue=1";
$str .= " $append" if defined $append;
$g->set_append ($str);
# Run the appliance. This won't return until the user quits the
# appliance.
eval { $g->launch (); };
# launch() expects guestfsd to start. However, virt-rescue doesn't run guestfsd,
# so this will always fail with ECHILD when the appliance exits unexpectedly.
die $@ unless $!{ECHILD};
exit 0;
For compatibility the old style is still supported.
=head1 ENVIRONMENT VARIABLES
@@ -269,9 +221,7 @@ manual page L<sh(1)> for details.
L<guestfs(3)>,
L<guestfish(1)>,
L<virt-cat(1)>,
L<Sys::Guestfs(3)>,
L<Sys::Guestfs::Lib(3)>,
L<Sys::Virt(3)>,
L<virt-edit(1)>,
L<http://libguestfs.org/>.
=head1 AUTHOR

View File

@@ -22,7 +22,6 @@ tools = \
list-filesystems \
list-partitions \
make-fs \
rescue \
resize \
tar \
win-reg