>From b488436cc54288fcae8988493749f2e6c87f274c Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Wed, 23 Sep 2009 12:37:26 +0100 Subject: [PATCH] Rename virt-[tool].pl as virt-[tool] --- Makefile.am | 8 +- cat/Makefile.am | 12 +- cat/virt-cat | 194 ++++++++++ cat/virt-cat.pl | 194 ---------- df/Makefile.am | 12 +- df/virt-df | 341 +++++++++++++++++ df/virt-df.pl | 341 ----------------- edit/Makefile.am | 12 +- edit/virt-edit | 210 +++++++++++ edit/virt-edit.pl | 210 ----------- inspector/Makefile.am | 12 +- inspector/virt-inspector | 874 +++++++++++++++++++++++++++++++++++++++++++ inspector/virt-inspector.pl | 874 ------------------------------------------- po/POTFILES.in | 10 +- rescue/Makefile.am | 12 +- rescue/virt-rescue | 169 +++++++++ rescue/virt-rescue.pl | 169 --------- 17 files changed, 1820 insertions(+), 1834 deletions(-) create mode 100755 cat/virt-cat delete mode 100755 cat/virt-cat.pl create mode 100755 df/virt-df delete mode 100755 df/virt-df.pl create mode 100755 edit/virt-edit delete mode 100755 edit/virt-edit.pl create mode 100755 inspector/virt-inspector delete mode 100755 inspector/virt-inspector.pl create mode 100755 rescue/virt-rescue delete mode 100755 rescue/virt-rescue.pl diff --git a/Makefile.am b/Makefile.am index 0f478a9..98ee48a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -164,7 +164,13 @@ dist-hook: # Update the list of translatable files in po/POTFILES.in. all-local: cd $(srcdir); \ - find $(DIST_SUBDIRS) -name '*.c' -o -name '*.pl' -o -name '*.pm' | \ + find $(DIST_SUBDIRS) \ + -name '*.c' -o -name '*.pl' -o -name '*.pm' -o \ + -name 'virt-cat' -o \ + -name 'virt-df' -o \ + -name 'virt-edit' -o \ + -name 'virt-inspector' -o \ + -name 'virt-rescue' | \ grep -v '^perl/blib/' | \ grep -v '^capitests/' | \ grep -v '^daemon/lib/' | \ diff --git a/cat/Makefile.am b/cat/Makefile.am index 5fe320b..c21983d 100644 --- a/cat/Makefile.am +++ b/cat/Makefile.am @@ -16,23 +16,23 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EXTRA_DIST = \ - run-cat-locally \ - virt-cat.pl + run-cat-locally if HAVE_CAT +bin_SCRIPTS = virt-cat man_MANS = virt-cat.1 noinst_DATA = $(top_builddir)/html/virt-cat.1.html -virt-cat.1: virt-cat.pl +virt-cat.1: virt-cat $(POD2MAN) \ --section 1 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t && mv $@-t $@ -$(top_builddir)/html/virt-cat.1.html: virt-cat.pl +$(top_builddir)/html/virt-cat.1.html: virt-cat mkdir -p $(top_builddir)/html cd $(top_builddir) && pod2html \ --css 'pod.css' \ @@ -41,8 +41,4 @@ $(top_builddir)/html/virt-cat.1.html: virt-cat.pl --outfile html/virt-cat.1.html \ cat/$< -install-data-hook: - mkdir -p $(DESTDIR)$(bindir) - install -m 0755 virt-cat.pl $(DESTDIR)$(bindir)/virt-cat - endif diff --git a/cat/virt-cat b/cat/virt-cat new file mode 100755 index 0000000..329ba6e --- /dev/null +++ b/cat/virt-cat @@ -0,0 +1,194 @@ +#!/usr/bin/perl -w +# virt-cat +# 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. + +use warnings; +use strict; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path + inspect_all_partitions inspect_partition + inspect_operating_systems mount_operating_system); +use Pod::Usage; +use Getopt::Long; +use Locale::TextDomain 'libguestfs'; + +=encoding utf8 + +=head1 NAME + +virt-cat - Display a file in a virtual machine + +=head1 SYNOPSIS + + virt-cat [--options] domname file + + virt-cat [--options] disk.img [disk.img ...] file + +=head1 DESCRIPTION + +C is a command line tool to display the contents of C +where C exists in the named virtual machine (or disk image). + +C can be used to quickly view a single file. To edit a +file, use C. For more complex cases you should look at the +L tool. + +=head1 EXAMPLES + +Display C file from inside the libvirt VM called +C: + + virt-cat mydomain /etc/fstab + +List syslog messages from a VM: + + virt-cat mydomain /var/log/messages | tail + +Find out what DHCP IP address a VM acquired: + + virt-cat mydomain /var/log/messages | grep 'dhclient: bound to' | tail + +Find out what packages were recently installed: + + virt-cat mydomain /var/log/yum.log | tail + +Find out who is logged on inside a virtual machine: + + virt-cat mydomain /var/run/utmp > /tmp/utmp + who /tmp/utmp + +or who was logged on: + + virt-cat mydomain /var/log/wtmp > /tmp/wtmp + last -f /tmp/wtmp + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $version; + +=item B<--version> + +Display version number and exit. + +=cut + +my $uri; + +=item B<--connect URI> | B<-c URI> + +If using libvirt, connect to the given I. If omitted, then we +connect to the default libvirt hypervisor. + +If you specify guest block devices directly, then libvirt is not used +at all. + +=back + +=cut + +GetOptions ("help|?" => \$help, + "version" => \$version, + "connect|c=s" => \$uri, + ) 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 +} + +pod2usage (__"virt-cat: no image, VM names or filenames to cat given") + if @ARGV <= 1; + +my $filename = pop @ARGV; + +my $g; +if ($uri) { + $g = open_guest (\@ARGV, address => $uri); +} else { + $g = open_guest (\@ARGV); +} + +$g->launch (); + +# List of possible filesystems. +my @partitions = get_partitions ($g); + +# Now query each one to build up a picture of what's in it. +my %fses = + inspect_all_partitions ($g, \@partitions, + use_windows_registry => 0); + +my $oses = inspect_operating_systems ($g, \%fses); + +my @roots = keys %$oses; +die __"no root device found in this operating system image" if @roots == 0; +die __"multiboot operating systems are not supported by virt-cat" if @roots > 1; +my $root_dev = $roots[0]; + +my $os = $oses->{$root_dev}; +mount_operating_system ($g, $os); + +# Allow this to fail in case eg. the file does not exist. +# NB: https://bugzilla.redhat.com/show_bug.cgi?id=501888 +print $g->download($filename, "/dev/stdout"); + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones L + +=head1 COPYRIGHT + +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. diff --git a/cat/virt-cat.pl b/cat/virt-cat.pl deleted file mode 100755 index 329ba6e..0000000 --- a/cat/virt-cat.pl +++ /dev/null @@ -1,194 +0,0 @@ -#!/usr/bin/perl -w -# virt-cat -# 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. - -use warnings; -use strict; - -use Sys::Guestfs; -use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path - inspect_all_partitions inspect_partition - inspect_operating_systems mount_operating_system); -use Pod::Usage; -use Getopt::Long; -use Locale::TextDomain 'libguestfs'; - -=encoding utf8 - -=head1 NAME - -virt-cat - Display a file in a virtual machine - -=head1 SYNOPSIS - - virt-cat [--options] domname file - - virt-cat [--options] disk.img [disk.img ...] file - -=head1 DESCRIPTION - -C is a command line tool to display the contents of C -where C exists in the named virtual machine (or disk image). - -C can be used to quickly view a single file. To edit a -file, use C. For more complex cases you should look at the -L tool. - -=head1 EXAMPLES - -Display C file from inside the libvirt VM called -C: - - virt-cat mydomain /etc/fstab - -List syslog messages from a VM: - - virt-cat mydomain /var/log/messages | tail - -Find out what DHCP IP address a VM acquired: - - virt-cat mydomain /var/log/messages | grep 'dhclient: bound to' | tail - -Find out what packages were recently installed: - - virt-cat mydomain /var/log/yum.log | tail - -Find out who is logged on inside a virtual machine: - - virt-cat mydomain /var/run/utmp > /tmp/utmp - who /tmp/utmp - -or who was logged on: - - virt-cat mydomain /var/log/wtmp > /tmp/wtmp - last -f /tmp/wtmp - -=head1 OPTIONS - -=over 4 - -=cut - -my $help; - -=item B<--help> - -Display brief help. - -=cut - -my $version; - -=item B<--version> - -Display version number and exit. - -=cut - -my $uri; - -=item B<--connect URI> | B<-c URI> - -If using libvirt, connect to the given I. If omitted, then we -connect to the default libvirt hypervisor. - -If you specify guest block devices directly, then libvirt is not used -at all. - -=back - -=cut - -GetOptions ("help|?" => \$help, - "version" => \$version, - "connect|c=s" => \$uri, - ) 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 -} - -pod2usage (__"virt-cat: no image, VM names or filenames to cat given") - if @ARGV <= 1; - -my $filename = pop @ARGV; - -my $g; -if ($uri) { - $g = open_guest (\@ARGV, address => $uri); -} else { - $g = open_guest (\@ARGV); -} - -$g->launch (); - -# List of possible filesystems. -my @partitions = get_partitions ($g); - -# Now query each one to build up a picture of what's in it. -my %fses = - inspect_all_partitions ($g, \@partitions, - use_windows_registry => 0); - -my $oses = inspect_operating_systems ($g, \%fses); - -my @roots = keys %$oses; -die __"no root device found in this operating system image" if @roots == 0; -die __"multiboot operating systems are not supported by virt-cat" if @roots > 1; -my $root_dev = $roots[0]; - -my $os = $oses->{$root_dev}; -mount_operating_system ($g, $os); - -# Allow this to fail in case eg. the file does not exist. -# NB: https://bugzilla.redhat.com/show_bug.cgi?id=501888 -print $g->download($filename, "/dev/stdout"); - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L, -L. - -=head1 AUTHOR - -Richard W.M. Jones L - -=head1 COPYRIGHT - -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. diff --git a/df/Makefile.am b/df/Makefile.am index 08af772..845edc4 100644 --- a/df/Makefile.am +++ b/df/Makefile.am @@ -16,23 +16,23 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EXTRA_DIST = \ - run-df-locally \ - virt-df.pl + run-df-locally if HAVE_DF +bin_SCRIPTS = virt-df man_MANS = virt-df.1 noinst_DATA = $(top_builddir)/html/virt-df.1.html -virt-df.1: virt-df.pl +virt-df.1: virt-df $(POD2MAN) \ --section 1 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t && mv $@-t $@ -$(top_builddir)/html/virt-df.1.html: virt-df.pl +$(top_builddir)/html/virt-df.1.html: virt-df mkdir -p $(top_builddir)/html cd $(top_builddir) && pod2html \ --css 'pod.css' \ @@ -41,8 +41,4 @@ $(top_builddir)/html/virt-df.1.html: virt-df.pl --outfile html/virt-df.1.html \ df/$< -install-data-hook: - mkdir -p $(DESTDIR)$(bindir) - install -m 0755 virt-df.pl $(DESTDIR)$(bindir)/virt-df - endif diff --git a/df/virt-df b/df/virt-df new file mode 100755 index 0000000..21ba791 --- /dev/null +++ b/df/virt-df @@ -0,0 +1,341 @@ +#!/usr/bin/perl -w +# virt-df +# 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. + +use warnings; +use strict; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path + inspect_all_partitions inspect_partition + inspect_operating_systems mount_operating_system inspect_in_detail); +use Pod::Usage; +use Getopt::Long; +use Data::Dumper; +use File::Temp qw/tempdir/; +use XML::Writer; +use Locale::TextDomain 'libguestfs'; + +=encoding utf8 + +=head1 NAME + +virt-df - Display free space on virtual filesystems + +=head1 SYNOPSIS + + virt-df [--options] + + virt-df [--options] domname + + virt-df [--options] disk.img [disk.img ...] + +=head1 DESCRIPTION + +C is a command line tool to display free space on virtual +machine filesystems. Unlike other tools, it doesn't just display the +amount of space allocated to a virtual machine, but can look inside +the virtual machine to see how much space is really being used. + +It is like the L command, but for virtual machines, except that +it also works for Windows virtual machines. + +If used without any arguments, C checks with libvirt to get a +list of all active and inactive guests, and performs a C-type +operation on each one in turn, printing out the results. + +If used with any argument(s), C performs a C-type +operation on either the single named libvirt domain, or on the disk +image(s) listed on the command line (which must all belong to a single +VM). In this mode (with arguments), C will I. If you want to run on multiple guests, then you have +to invoke C multiple times. + +Use the C<--csv> option to get a format which can be easily parsed by +other programs. Other options are mostly similar to standard C +options. See below for the complete list. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $version; + +=item B<--version> + +Display version number and exit. + +=cut + +my $uri; + +=item B<--connect URI> | B<-c URI> + +If using libvirt, connect to the given I. If omitted, then we +connect to the default libvirt hypervisor. + +If you specify guest block devices directly, then libvirt is not used +at all. + +=cut + +my $csv; + +=item B<--csv> + +Write out the results in CSV format (comma-separated values). +This format can be imported easily into databases and spreadsheets. + +=cut + +my $human; + +=item B<--human-readable> | B<-h> + +Print sizes in human-readable format. + +=cut + +my $inodes; + +=item B<--inodes> | B<-i> + +Print inodes instead of blocks. + +=back + +=cut + +GetOptions ("help|?" => \$help, + "version" => \$version, + "connect|c=s" => \$uri, + "csv" => \$csv, + "human-readable|human|h" => \$human, + "inodes|i" => \$inodes, + ) 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 +} + +# Open the guest handle. + +if (@ARGV == 0) { + my $conn; + + if ($uri) { + $conn = Sys::Virt->new (readonly => 1, address => $uri); + } else { + $conn = Sys::Virt->new (readonly => 1); + } + + my @doms = $conn->list_defined_domains (); + push @doms, $conn->list_domains (); + + my @domnames = map { $_->get_name () } @doms; + + if (@domnames) { + print_title (); + foreach (@domnames) { + do_df ($_); + } + } +} else { + print_title (); + do_df (@ARGV); +} + +sub do_df +{ + my $g; + + if ($uri) { + $g = open_guest (\@_, address => $uri); + } else { + $g = open_guest (\@_); + } + + $g->launch (); + + my @partitions = get_partitions ($g); + + # Think of a printable name for this domain. Just choose the + # first parameter passed to this function, which will work for + # most cases (it'll either be the domain name or the first disk + # image name). + my $domname = $_[0]; + + # Mount each partition in turn, and if mountable, do a statvfs on it. + foreach my $partition (@partitions) { + my %stat; + eval { + $g->mount_ro ($partition, "/"); + %stat = $g->statvfs ("/"); + }; + if (!$@) { + print_stat ($domname, $partition, \%stat); + } + $g->umount_all (); + } +} + +sub print_stat +{ + my $domname = shift; + my $partition = shift; + my $stat = shift; + + my @cols = ($domname, $partition); + + if (!$inodes) { + my $bsize = $stat->{bsize}; # block size + my $blocks = $stat->{blocks}; # total number of blocks + my $bfree = $stat->{bfree}; # blocks free (total) + my $bavail = $stat->{bavail}; # blocks free (for non-root users) + + my $factor = $bsize / 1024; + + push @cols, $blocks*$factor; # total 1K blocks + push @cols, ($blocks-$bfree)*$factor; # total 1K blocks used + push @cols, $bavail*$factor; # total 1K blocks available + + # XXX %used column comes out different from the native 'df' + # program. Need to check how 'df' calculates this. + push @cols, 100.0 - 100.0 * $bavail / $blocks; + + if ($human) { + $cols[2] = human_size ($cols[2]); + $cols[3] = human_size ($cols[3]); + $cols[4] = human_size ($cols[4]); + } + } else { + my $files = $stat->{files}; # total number of inodes + my $ffree = $stat->{ffree}; # inodes free (total) + my $favail = $stat->{favail}; # inodes free (for non-root users) + + push @cols, $files; + push @cols, $files-$ffree; + push @cols, $ffree; + + # XXX %used column comes out different from the native 'df' + # program. Need to check how 'df' calculates this. + push @cols, 100.0 - 100.0 * $favail / $files; + } + + print_cols (@cols); +} + +sub print_title +{ + my @cols = (__"Virtual Machine", __"Filesystem"); + if (!$inodes) { + if (!$human) { + push @cols, __"1K-blocks"; + } else { + push @cols, __"Size"; + } + push @cols, __"Used"; + push @cols, __"Available"; + push @cols, __"Use%"; + } else { + push @cols, __"Inodes"; + push @cols, __"IUsed"; + push @cols, __"IFree"; + push @cols, __"IUse%"; + } + + if (!$csv) { + # ignore $cols[0] in this mode + printf "%-36s%10s %10s %10s %5s\n", + $cols[1], $cols[2], $cols[3], $cols[4], $cols[5]; + } else { + print (join (",", @cols), "\n"); + } +} + +sub print_cols +{ + if (!$csv) { + my $label = sprintf "%s:%s", $_[0], $_[1]; + + printf ("%-36s", $label); + print "\n"," "x36 if length ($label) > 36; + + my $percent = sprintf "%3.1f%%", $_[5]; + printf ("%10s %10s %10s %5s\n", $_[2], $_[3], $_[4], $percent); + } else { + printf ("\"%s\",\"%s\",%d,%d,%d,%.1f%%\n", @_); + } +} + +# Convert a number of 1K blocks to a human-readable number. +sub human_size +{ + local $_ = shift; + + if ($_ < 1024) { + sprintf "%dK", $_; + } elsif ($_ < 1024 * 1024) { + sprintf "%.1fM", ($_ / 1024); + } else { + sprintf "%.1fG", ($_ / 1024 / 1024); + } +} + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones L + +=head1 COPYRIGHT + +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. diff --git a/df/virt-df.pl b/df/virt-df.pl deleted file mode 100755 index 21ba791..0000000 --- a/df/virt-df.pl +++ /dev/null @@ -1,341 +0,0 @@ -#!/usr/bin/perl -w -# virt-df -# 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. - -use warnings; -use strict; - -use Sys::Guestfs; -use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path - inspect_all_partitions inspect_partition - inspect_operating_systems mount_operating_system inspect_in_detail); -use Pod::Usage; -use Getopt::Long; -use Data::Dumper; -use File::Temp qw/tempdir/; -use XML::Writer; -use Locale::TextDomain 'libguestfs'; - -=encoding utf8 - -=head1 NAME - -virt-df - Display free space on virtual filesystems - -=head1 SYNOPSIS - - virt-df [--options] - - virt-df [--options] domname - - virt-df [--options] disk.img [disk.img ...] - -=head1 DESCRIPTION - -C is a command line tool to display free space on virtual -machine filesystems. Unlike other tools, it doesn't just display the -amount of space allocated to a virtual machine, but can look inside -the virtual machine to see how much space is really being used. - -It is like the L command, but for virtual machines, except that -it also works for Windows virtual machines. - -If used without any arguments, C checks with libvirt to get a -list of all active and inactive guests, and performs a C-type -operation on each one in turn, printing out the results. - -If used with any argument(s), C performs a C-type -operation on either the single named libvirt domain, or on the disk -image(s) listed on the command line (which must all belong to a single -VM). In this mode (with arguments), C will I. If you want to run on multiple guests, then you have -to invoke C multiple times. - -Use the C<--csv> option to get a format which can be easily parsed by -other programs. Other options are mostly similar to standard C -options. See below for the complete list. - -=head1 OPTIONS - -=over 4 - -=cut - -my $help; - -=item B<--help> - -Display brief help. - -=cut - -my $version; - -=item B<--version> - -Display version number and exit. - -=cut - -my $uri; - -=item B<--connect URI> | B<-c URI> - -If using libvirt, connect to the given I. If omitted, then we -connect to the default libvirt hypervisor. - -If you specify guest block devices directly, then libvirt is not used -at all. - -=cut - -my $csv; - -=item B<--csv> - -Write out the results in CSV format (comma-separated values). -This format can be imported easily into databases and spreadsheets. - -=cut - -my $human; - -=item B<--human-readable> | B<-h> - -Print sizes in human-readable format. - -=cut - -my $inodes; - -=item B<--inodes> | B<-i> - -Print inodes instead of blocks. - -=back - -=cut - -GetOptions ("help|?" => \$help, - "version" => \$version, - "connect|c=s" => \$uri, - "csv" => \$csv, - "human-readable|human|h" => \$human, - "inodes|i" => \$inodes, - ) 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 -} - -# Open the guest handle. - -if (@ARGV == 0) { - my $conn; - - if ($uri) { - $conn = Sys::Virt->new (readonly => 1, address => $uri); - } else { - $conn = Sys::Virt->new (readonly => 1); - } - - my @doms = $conn->list_defined_domains (); - push @doms, $conn->list_domains (); - - my @domnames = map { $_->get_name () } @doms; - - if (@domnames) { - print_title (); - foreach (@domnames) { - do_df ($_); - } - } -} else { - print_title (); - do_df (@ARGV); -} - -sub do_df -{ - my $g; - - if ($uri) { - $g = open_guest (\@_, address => $uri); - } else { - $g = open_guest (\@_); - } - - $g->launch (); - - my @partitions = get_partitions ($g); - - # Think of a printable name for this domain. Just choose the - # first parameter passed to this function, which will work for - # most cases (it'll either be the domain name or the first disk - # image name). - my $domname = $_[0]; - - # Mount each partition in turn, and if mountable, do a statvfs on it. - foreach my $partition (@partitions) { - my %stat; - eval { - $g->mount_ro ($partition, "/"); - %stat = $g->statvfs ("/"); - }; - if (!$@) { - print_stat ($domname, $partition, \%stat); - } - $g->umount_all (); - } -} - -sub print_stat -{ - my $domname = shift; - my $partition = shift; - my $stat = shift; - - my @cols = ($domname, $partition); - - if (!$inodes) { - my $bsize = $stat->{bsize}; # block size - my $blocks = $stat->{blocks}; # total number of blocks - my $bfree = $stat->{bfree}; # blocks free (total) - my $bavail = $stat->{bavail}; # blocks free (for non-root users) - - my $factor = $bsize / 1024; - - push @cols, $blocks*$factor; # total 1K blocks - push @cols, ($blocks-$bfree)*$factor; # total 1K blocks used - push @cols, $bavail*$factor; # total 1K blocks available - - # XXX %used column comes out different from the native 'df' - # program. Need to check how 'df' calculates this. - push @cols, 100.0 - 100.0 * $bavail / $blocks; - - if ($human) { - $cols[2] = human_size ($cols[2]); - $cols[3] = human_size ($cols[3]); - $cols[4] = human_size ($cols[4]); - } - } else { - my $files = $stat->{files}; # total number of inodes - my $ffree = $stat->{ffree}; # inodes free (total) - my $favail = $stat->{favail}; # inodes free (for non-root users) - - push @cols, $files; - push @cols, $files-$ffree; - push @cols, $ffree; - - # XXX %used column comes out different from the native 'df' - # program. Need to check how 'df' calculates this. - push @cols, 100.0 - 100.0 * $favail / $files; - } - - print_cols (@cols); -} - -sub print_title -{ - my @cols = (__"Virtual Machine", __"Filesystem"); - if (!$inodes) { - if (!$human) { - push @cols, __"1K-blocks"; - } else { - push @cols, __"Size"; - } - push @cols, __"Used"; - push @cols, __"Available"; - push @cols, __"Use%"; - } else { - push @cols, __"Inodes"; - push @cols, __"IUsed"; - push @cols, __"IFree"; - push @cols, __"IUse%"; - } - - if (!$csv) { - # ignore $cols[0] in this mode - printf "%-36s%10s %10s %10s %5s\n", - $cols[1], $cols[2], $cols[3], $cols[4], $cols[5]; - } else { - print (join (",", @cols), "\n"); - } -} - -sub print_cols -{ - if (!$csv) { - my $label = sprintf "%s:%s", $_[0], $_[1]; - - printf ("%-36s", $label); - print "\n"," "x36 if length ($label) > 36; - - my $percent = sprintf "%3.1f%%", $_[5]; - printf ("%10s %10s %10s %5s\n", $_[2], $_[3], $_[4], $percent); - } else { - printf ("\"%s\",\"%s\",%d,%d,%d,%.1f%%\n", @_); - } -} - -# Convert a number of 1K blocks to a human-readable number. -sub human_size -{ - local $_ = shift; - - if ($_ < 1024) { - sprintf "%dK", $_; - } elsif ($_ < 1024 * 1024) { - sprintf "%.1fM", ($_ / 1024); - } else { - sprintf "%.1fG", ($_ / 1024 / 1024); - } -} - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L. - -=head1 AUTHOR - -Richard W.M. Jones L - -=head1 COPYRIGHT - -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. diff --git a/edit/Makefile.am b/edit/Makefile.am index df8ddb7..8489ebb 100644 --- a/edit/Makefile.am +++ b/edit/Makefile.am @@ -16,23 +16,23 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EXTRA_DIST = \ - run-edit-locally \ - virt-edit.pl + run-edit-locally if HAVE_EDIT +bin_SCRIPTS = virt-edit man_MANS = virt-edit.1 noinst_DATA = $(top_builddir)/html/virt-edit.1.html -virt-edit.1: virt-edit.pl +virt-edit.1: virt-edit $(POD2MAN) \ --section 1 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t && mv $@-t $@ -$(top_builddir)/html/virt-edit.1.html: virt-edit.pl +$(top_builddir)/html/virt-edit.1.html: virt-edit mkdir -p $(top_builddir)/html cd $(top_builddir) && pod2html \ --css 'pod.css' \ @@ -41,8 +41,4 @@ $(top_builddir)/html/virt-edit.1.html: virt-edit.pl --outfile html/virt-edit.1.html \ edit/$< -install-data-hook: - mkdir -p $(DESTDIR)$(bindir) - install -m 0755 virt-edit.pl $(DESTDIR)$(bindir)/virt-edit - endif diff --git a/edit/virt-edit b/edit/virt-edit new file mode 100755 index 0000000..46e86a1 --- /dev/null +++ b/edit/virt-edit @@ -0,0 +1,210 @@ +#!/usr/bin/perl -w +# virt-edit +# 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. + +use warnings; +use strict; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path + inspect_all_partitions inspect_partition + inspect_operating_systems mount_operating_system); +use Pod::Usage; +use Getopt::Long; +use File::Temp qw/tempfile/; +use Locale::TextDomain 'libguestfs'; + +=encoding utf8 + +=head1 NAME + +virt-edit - Edit a file in a virtual machine + +=head1 SYNOPSIS + + virt-edit [--options] domname file + + virt-edit [--options] disk.img [disk.img ...] file + +=head1 DESCRIPTION + +C is a command line tool to edit C where C +exists in the named virtual machine (or disk image). + +B you must I use virt-edit on live virtual machines. If +you do this, you risk disk corruption in the VM. + +If you want to just view a file, use L. For more complex +cases you should look at the L tool. + +=head1 EXAMPLES + + virt-edit mydomain /boot/grub/grub.conf + + virt-edit mydomain /etc/passwd + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $version; + +=item B<--version> + +Display version number and exit. + +=cut + +my $uri; + +=item B<--connect URI> | B<-c URI> + +If using libvirt, connect to the given I. If omitted, then we +connect to the default libvirt hypervisor. + +If you specify guest block devices directly, then libvirt is not used +at all. + +=back + +=cut + +GetOptions ("help|?" => \$help, + "version" => \$version, + "connect|c=s" => \$uri, + ) 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 +} + +pod2usage (__"virt-edit: no image, VM names or filenames to edit given") + if @ARGV <= 1; + +my $filename = pop @ARGV; + +my $g; +if ($uri) { + $g = open_guest (\@ARGV, address => $uri, rw => 1); +} else { + $g = open_guest (\@ARGV, rw => 1); +} + +$g->launch (); + +# List of possible filesystems. +my @partitions = get_partitions ($g); + +# Now query each one to build up a picture of what's in it. +my %fses = + inspect_all_partitions ($g, \@partitions, + use_windows_registry => 0); + +my $oses = inspect_operating_systems ($g, \%fses); + +my @roots = keys %$oses; +die __"no root device found in this operating system image" if @roots == 0; +die __"multiboot operating systems are not supported by virt-edit" if @roots > 1; +my $root_dev = $roots[0]; + +my $os = $oses->{$root_dev}; +mount_operating_system ($g, $os, 0); + +my ($fh, $tempname) = tempfile (); + +# Allow this to fail in case eg. the file does not exist. +$g->download($filename, $tempname); + +my $oldctime = (stat ($tempname))[10]; + +my $editor = $ENV{EDITOR}; +$editor ||= "vi"; +system ("$editor $tempname") == 0 + or die "edit failed: $editor: $?"; + +my $newctime = (stat ($tempname))[10]; + +if ($oldctime != $newctime) { + $g->upload ($tempname, $filename) +} else { + print __"File not changed.\n"; +} + +$g->sync (); +$g->umount_all (); + +undef $g; + +exit 0; + +=head1 ENVIRONMENT VARIABLES + +=over 4 + +=item C + +If set, this string is used as the editor. It may contain arguments, +eg. C<"emacs -nw"> + +If not set, C is used. + +=back + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones L + +=head1 COPYRIGHT + +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. diff --git a/edit/virt-edit.pl b/edit/virt-edit.pl deleted file mode 100755 index 46e86a1..0000000 --- a/edit/virt-edit.pl +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/perl -w -# virt-edit -# 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. - -use warnings; -use strict; - -use Sys::Guestfs; -use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path - inspect_all_partitions inspect_partition - inspect_operating_systems mount_operating_system); -use Pod::Usage; -use Getopt::Long; -use File::Temp qw/tempfile/; -use Locale::TextDomain 'libguestfs'; - -=encoding utf8 - -=head1 NAME - -virt-edit - Edit a file in a virtual machine - -=head1 SYNOPSIS - - virt-edit [--options] domname file - - virt-edit [--options] disk.img [disk.img ...] file - -=head1 DESCRIPTION - -C is a command line tool to edit C where C -exists in the named virtual machine (or disk image). - -B you must I use virt-edit on live virtual machines. If -you do this, you risk disk corruption in the VM. - -If you want to just view a file, use L. For more complex -cases you should look at the L tool. - -=head1 EXAMPLES - - virt-edit mydomain /boot/grub/grub.conf - - virt-edit mydomain /etc/passwd - -=head1 OPTIONS - -=over 4 - -=cut - -my $help; - -=item B<--help> - -Display brief help. - -=cut - -my $version; - -=item B<--version> - -Display version number and exit. - -=cut - -my $uri; - -=item B<--connect URI> | B<-c URI> - -If using libvirt, connect to the given I. If omitted, then we -connect to the default libvirt hypervisor. - -If you specify guest block devices directly, then libvirt is not used -at all. - -=back - -=cut - -GetOptions ("help|?" => \$help, - "version" => \$version, - "connect|c=s" => \$uri, - ) 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 -} - -pod2usage (__"virt-edit: no image, VM names or filenames to edit given") - if @ARGV <= 1; - -my $filename = pop @ARGV; - -my $g; -if ($uri) { - $g = open_guest (\@ARGV, address => $uri, rw => 1); -} else { - $g = open_guest (\@ARGV, rw => 1); -} - -$g->launch (); - -# List of possible filesystems. -my @partitions = get_partitions ($g); - -# Now query each one to build up a picture of what's in it. -my %fses = - inspect_all_partitions ($g, \@partitions, - use_windows_registry => 0); - -my $oses = inspect_operating_systems ($g, \%fses); - -my @roots = keys %$oses; -die __"no root device found in this operating system image" if @roots == 0; -die __"multiboot operating systems are not supported by virt-edit" if @roots > 1; -my $root_dev = $roots[0]; - -my $os = $oses->{$root_dev}; -mount_operating_system ($g, $os, 0); - -my ($fh, $tempname) = tempfile (); - -# Allow this to fail in case eg. the file does not exist. -$g->download($filename, $tempname); - -my $oldctime = (stat ($tempname))[10]; - -my $editor = $ENV{EDITOR}; -$editor ||= "vi"; -system ("$editor $tempname") == 0 - or die "edit failed: $editor: $?"; - -my $newctime = (stat ($tempname))[10]; - -if ($oldctime != $newctime) { - $g->upload ($tempname, $filename) -} else { - print __"File not changed.\n"; -} - -$g->sync (); -$g->umount_all (); - -undef $g; - -exit 0; - -=head1 ENVIRONMENT VARIABLES - -=over 4 - -=item C - -If set, this string is used as the editor. It may contain arguments, -eg. C<"emacs -nw"> - -If not set, C is used. - -=back - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L, -L. - -=head1 AUTHOR - -Richard W.M. Jones L - -=head1 COPYRIGHT - -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. diff --git a/inspector/Makefile.am b/inspector/Makefile.am index 6eb3b57..7dd71dc 100644 --- a/inspector/Makefile.am +++ b/inspector/Makefile.am @@ -16,23 +16,23 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EXTRA_DIST = \ - run-inspector-locally \ - virt-inspector.pl + run-inspector-locally if HAVE_INSPECTOR +bin_SCRIPTS = virt-inspector man_MANS = virt-inspector.1 noinst_DATA = $(top_builddir)/html/virt-inspector.1.html -virt-inspector.1: virt-inspector.pl +virt-inspector.1: virt-inspector $(POD2MAN) \ --section 1 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t && mv $@-t $@ -$(top_builddir)/html/virt-inspector.1.html: virt-inspector.pl +$(top_builddir)/html/virt-inspector.1.html: virt-inspector mkdir -p $(top_builddir)/html cd $(top_builddir) && pod2html \ --css 'pod.css' \ @@ -41,8 +41,4 @@ $(top_builddir)/html/virt-inspector.1.html: virt-inspector.pl --outfile html/virt-inspector.1.html \ inspector/$< -install-data-hook: - mkdir -p $(DESTDIR)$(bindir) - install -m 0755 virt-inspector.pl $(DESTDIR)$(bindir)/virt-inspector - endif diff --git a/inspector/virt-inspector b/inspector/virt-inspector new file mode 100755 index 0000000..86b1795 --- /dev/null +++ b/inspector/virt-inspector @@ -0,0 +1,874 @@ +#!/usr/bin/perl -w +# virt-inspector +# 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. + +use warnings; +use strict; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path + inspect_all_partitions inspect_partition + inspect_operating_systems mount_operating_system inspect_in_detail); +use Pod::Usage; +use Getopt::Long; +use Data::Dumper; +use XML::Writer; +use Locale::TextDomain 'libguestfs'; + +# Optional: +eval "use YAML::Any;"; + +=encoding utf8 + +=head1 NAME + +virt-inspector - Display OS version, kernel, drivers, mount points, applications, etc. in a virtual machine + +=head1 SYNOPSIS + + virt-inspector [--connect URI] domname + + virt-inspector guest.img [guest.img ...] + +=head1 DESCRIPTION + +B examines a virtual machine and tries to determine +the version of the OS, the kernel version, what drivers are installed, +whether the virtual machine is fully virtualized (FV) or +para-virtualized (PV), what applications are installed and more. + +Virt-inspector can produce output in several formats, including a +readable text report, and XML for feeding into other programs. + +Virt-inspector should only be run on I virtual machines. +The program tries to determine that the machine is inactive and will +refuse to run if it thinks you are trying to inspect a running domain. + +In the normal usage, use C where C is +the libvirt domain (see: C). + +You can also run virt-inspector directly on disk images from a single +virtual machine. Use C. In rare cases a +domain has several block devices, in which case you should list them +one after another, with the first corresponding to the guest's +C, the second to the guest's C and so on. + +Virt-inspector can only inspect and report upon I. To inspect several virtual machines, you have to run +virt-inspector several times (for example, from a shell script +for-loop). + +Because virt-inspector needs direct access to guest images, it won't +normally work over remote libvirt connections. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $version; + +=item B<--version> + +Display version number and exit. + +=cut + +my $uri; + +=item B<--connect URI> | B<-c URI> + +If using libvirt, connect to the given I. If omitted, +then we connect to the default libvirt hypervisor. + +Libvirt is only used if you specify a C on the +command line. If you specify guest block devices directly, +then libvirt is not used at all. + +=cut + +my $output = "text"; + +=back + +The following options select the output format. Use only one of them. +The default is a readable text report. + +=over 4 + +=item B<--text> (default) + +Plain text report. + +=item B<--none> + +Produce no output at all. + +=item B<--xml> + +If you select I<--xml> then you get XML output which can be fed +to other programs. + +=item B<--yaml> + +If you select I<--yaml> then you get YAML output which can be fed +to other programs. + +=item B<--perl> + +If you select I<--perl> then you get Perl structures output which +can be used directly in another Perl program. + +=item B<--fish> + +=item B<--ro-fish> + +If you select I<--fish> then we print a L command +line which will automatically mount up the filesystems on the +correct mount points. Try this for example: + + guestfish $(virt-inspector --fish guest.img) + +I<--ro-fish> is the same, but the I<--ro> option is passed to +guestfish so that the filesystems are mounted read-only. + +=item B<--query> + +In "query mode" we answer common questions about the guest, such +as whether it is fullvirt or needs a Xen hypervisor to run. + +See section I below. + +=cut + +my $windows_registry; + +=item B<--windows-registry> + +If this item is passed, I the guest is Windows, I the +external program C is available (see SEE ALSO section), then we +attempt to parse the Windows registry. This allows much more +information to be gathered for Windows guests. + +This is quite an expensive and slow operation, so we don't do it by +default. + +=back + +=cut + +GetOptions ("help|?" => \$help, + "version" => \$version, + "connect|c=s" => \$uri, + "text" => sub { $output = "text" }, + "none" => sub { $output = "none" }, + "xml" => sub { $output = "xml" }, + "yaml" => sub { $output = "yaml" }, + "perl" => sub { $output = "perl" }, + "fish" => sub { $output = "fish" }, + "guestfish" => sub { $output = "fish" }, + "ro-fish" => sub { $output = "ro-fish" }, + "ro-guestfish" => sub { $output = "ro-fish" }, + "query" => sub { $output = "query" }, + "windows-registry" => \$windows_registry, + ) 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 +} +pod2usage (__"virt-inspector: no image or VM names given") if @ARGV == 0; + +my $rw = 0; +$rw = 1 if $output eq "fish"; +my $g; +my @images; +if ($uri) { + my ($conn, $dom); + ($g, $conn, $dom, @images) = + open_guest (\@ARGV, rw => $rw, address => $uri); +} else { + my ($conn, $dom); + ($g, $conn, $dom, @images) = + open_guest (\@ARGV, rw => $rw); +} + +$g->launch (); + +=head1 OUTPUT FORMAT + + Operating system(s) + ------------------- + Linux (distro + version) + Windows (version) + | + | + +--- Filesystems ---------- Installed apps --- Kernel & drivers + ----------- -------------- ---------------- + mount point => device List of apps Extra information + mount point => device and versions about kernel(s) + ... and drivers + swap => swap device + (plus lots of extra information + about each filesystem) + +The output of virt-inspector is a complex two-level data structure. + +At the top level is a list of the operating systems installed on the +guest. (For the vast majority of guests, only a single OS is +installed.) The data returned for the OS includes the name (Linux, +Windows), the distribution and version. + +The diagram above shows what we return for each OS. + +With the I<--xml> option the output is mapped into an XML document. +Unfortunately there is no clear schema for this document +(contributions welcome) but you can get an idea of the format by +looking at other documents and as a last resort the source for this +program. + +With the I<--fish> or I<--ro-fish> option the mount points are mapped to +L command line parameters, so that you can go in +afterwards and inspect the guest with everything mounted in the +right place. For example: + + guestfish $(virt-inspector --ro-fish guest.img) + ==> guestfish --ro -a guest.img -m /dev/VG/LV:/ -m /dev/sda1:/boot + +=cut + +# List of possible filesystems. +my @partitions = get_partitions ($g); + +# Now query each one to build up a picture of what's in it. +my %fses = + inspect_all_partitions ($g, \@partitions, + use_windows_registry => $windows_registry); + +#print "fses -----------\n"; +#print Dumper(\%fses); + +my $oses = inspect_operating_systems ($g, \%fses); + +#print "oses -----------\n"; +#print Dumper($oses); + +# Mount up the disks so we can check for applications +# and kernels. Skip this if the output is "*fish" because +# we don't need to know. + +if ($output !~ /.*fish$/) { + my $root_dev; + foreach $root_dev (sort keys %$oses) { + my $os = $oses->{$root_dev}; + mount_operating_system ($g, $os); + inspect_in_detail ($g, $os); + $g->umount_all (); + } +} + +#---------------------------------------------------------------------- +# Output. + +if ($output eq "fish" || $output eq "ro-fish") { + my @osdevs = keys %$oses; + # This only works if there is a single OS. + die __"--fish output is only possible with a single OS\n" if @osdevs != 1; + + my $root_dev = $osdevs[0]; + + if ($output eq "ro-fish") { + print "--ro "; + } + + print "-a $_ " foreach @images; + + my $mounts = $oses->{$root_dev}->{mounts}; + # Have to mount / first. Luckily '/' is early in the ASCII + # character set, so this should be OK. + foreach (sort keys %$mounts) { + print "-m $mounts->{$_}:$_ " if $_ ne "swap" && $_ ne "none"; + } + print "\n" +} + +# Perl output. +elsif ($output eq "perl") { + print Dumper(%$oses); +} + +# YAML output +elsif ($output eq "yaml") { + die __"virt-inspector: no YAML support\n" + unless exists $INC{"YAML/Any.pm"}; + + print Dump(%$oses); +} + +# Plain text output (the default). +elsif ($output eq "text") { + output_text (); +} + +# XML output. +elsif ($output eq "xml") { + output_xml (); +} + +# Query mode. +elsif ($output eq "query") { + output_query (); +} + +sub output_text +{ + output_text_os ($oses->{$_}) foreach sort keys %$oses; +} + +sub output_text_os +{ + my $os = shift; + + print $os->{os}, " " if exists $os->{os}; + print $os->{distro}, " " if exists $os->{distro}; + print $os->{arch}, " " if exists $os->{arch}; + print $os->{major_version} if exists $os->{major_version}; + print ".", $os->{minor_version} if exists $os->{minor_version}; + print " "; + print "on ", $os->{root_device}, ":\n"; + + print __" Mountpoints:\n"; + my $mounts = $os->{mounts}; + foreach (sort keys %$mounts) { + printf " %-30s %s\n", $mounts->{$_}, $_ + } + + print __" Filesystems:\n"; + my $filesystems = $os->{filesystems}; + foreach (sort keys %$filesystems) { + print " $_:\n"; + print " label: $filesystems->{$_}{label}\n" + if exists $filesystems->{$_}{label}; + print " UUID: $filesystems->{$_}{uuid}\n" + if exists $filesystems->{$_}{uuid}; + print " type: $filesystems->{$_}{fstype}\n" + if exists $filesystems->{$_}{fstype}; + print " content: $filesystems->{$_}{content}\n" + if exists $filesystems->{$_}{content}; + } + + if (exists $os->{modprobe_aliases}) { + my %aliases = %{$os->{modprobe_aliases}}; + my @keys = sort keys %aliases; + if (@keys) { + print __" Modprobe aliases:\n"; + foreach (@keys) { + printf " %-30s %s\n", $_, $aliases{$_}->{modulename} + } + } + } + + if (exists $os->{initrd_modules}) { + my %modvers = %{$os->{initrd_modules}}; + my @keys = sort keys %modvers; + if (@keys) { + print __" Initrd modules:\n"; + foreach (@keys) { + my @modules = @{$modvers{$_}}; + print " $_:\n"; + print " $_\n" foreach @modules; + } + } + } + + print __" Applications:\n"; + my @apps = @{$os->{apps}}; + foreach (@apps) { + print " $_->{name} $_->{version}\n" + } + + print __" Kernels:\n"; + my @kernels = @{$os->{kernels}}; + foreach (@kernels) { + print " $_->{version} ($_->{arch})\n"; + my @modules = @{$_->{modules}}; + foreach (@modules) { + print " $_\n"; + } + } + + if (exists $os->{root}->{registry}) { + print __" Windows Registry entries:\n"; + # These are just lumps of text - dump them out. + foreach (@{$os->{root}->{registry}}) { + print "$_\n"; + } + } +} + +sub output_xml +{ + my $xml = new XML::Writer(DATA_MODE => 1, DATA_INDENT => 2); + + $xml->startTag("operatingsystems"); + output_xml_os ($oses->{$_}, $xml) foreach sort keys %$oses; + $xml->endTag("operatingsystems"); + + $xml->end(); +} + +sub output_xml_os +{ + my ($os, $xml) = @_; + + $xml->startTag("operatingsystem"); + + foreach ( [ "name" => "os" ], + [ "distro" => "distro" ], + [ "arch" => "arch" ], + [ "major_version" => "major_version" ], + [ "minor_version" => "minor_version" ], + [ "package_format" => "package_format" ], + [ "package_management" => "package_management" ], + [ "root" => "root_device" ] ) { + $xml->dataElement($_->[0], $os->{$_->[1]}) if exists $os->{$_->[1]}; + } + + $xml->startTag("mountpoints"); + my $mounts = $os->{mounts}; + foreach (sort keys %$mounts) { + $xml->dataElement("mountpoint", $_, "dev" => $mounts->{$_}); + } + $xml->endTag("mountpoints"); + + $xml->startTag("filesystems"); + my $filesystems = $os->{filesystems}; + foreach (sort keys %$filesystems) { + $xml->startTag("filesystem", "dev" => $_); + + foreach my $field ( [ "label" => "label" ], + [ "uuid" => "uuid" ], + [ "type" => "fstype" ], + [ "content" => "content" ], + [ "spec" => "spec" ] ) { + $xml->dataElement($field->[0], $filesystems->{$_}{$field->[1]}) + if exists $filesystems->{$_}{$field->[1]}; + } + + $xml->endTag("filesystem"); + } + $xml->endTag("filesystems"); + + if (exists $os->{modprobe_aliases}) { + my %aliases = %{$os->{modprobe_aliases}}; + my @keys = sort keys %aliases; + if (@keys) { + $xml->startTag("modprobealiases"); + foreach (@keys) { + $xml->startTag("alias", "device" => $_); + + foreach my $field ( [ "modulename" => "modulename" ], + [ "augeas" => "augeas" ], + [ "file" => "file" ] ) { + $xml->dataElement($field->[0], $aliases{$_}->{$field->[1]}); + } + + $xml->endTag("alias"); + } + $xml->endTag("modprobealiases"); + } + } + + if (exists $os->{initrd_modules}) { + my %modvers = %{$os->{initrd_modules}}; + my @keys = sort keys %modvers; + if (@keys) { + $xml->startTag("initrds"); + foreach (@keys) { + my @modules = @{$modvers{$_}}; + $xml->startTag("initrd", "version" => $_); + $xml->dataElement("module", $_) foreach @modules; + $xml->endTag("initrd"); + } + $xml->endTag("initrds"); + } + } + + $xml->startTag("applications"); + my @apps = @{$os->{apps}}; + foreach (@apps) { + $xml->startTag("application"); + $xml->dataElement("name", $_->{name}); + $xml->dataElement("version", $_->{version}); + $xml->endTag("application"); + } + $xml->endTag("applications"); + + if(defined($os->{boot}) && defined($os->{boot}->{configs})) { + my $default = $os->{boot}->{default}; + my $configs = $os->{boot}->{configs}; + + $xml->startTag("boot"); + for(my $i = 0; $i < scalar(@$configs); $i++) { + my $config = $configs->[$i]; + + my @attrs = (); + push(@attrs, ("default" => 1)) if($default == $i); + $xml->startTag("config", @attrs); + $xml->dataElement("title", $config->{title}); + $xml->dataElement("kernel", $config->{kernel}->{version}) + if(defined($config->{kernel})); + $xml->dataElement("cmdline", $config->{cmdline}) + if(defined($config->{cmdline})); + $xml->endTag("config"); + } + $xml->endTag("boot"); + } + + $xml->startTag("kernels"); + my @kernels = @{$os->{kernels}}; + foreach (@kernels) { + $xml->startTag("kernel", + "version" => $_->{version}, + "arch" => $_->{arch}); + $xml->startTag("modules"); + my @modules = @{$_->{modules}}; + foreach (@modules) { + $xml->dataElement("module", $_); + } + $xml->endTag("modules"); + $xml->dataElement("path", $_->{path}) if(defined($_->{path})); + $xml->dataElement("package", $_->{package}) if(defined($_->{package})); + $xml->endTag("kernel"); + } + $xml->endTag("kernels"); + + if (exists $os->{root}->{registry}) { + $xml->startTag("windowsregistryentries"); + # These are just lumps of text - dump them out. + foreach (@{$os->{root}->{registry}}) { + $xml->dataElement("windowsregistryentry", $_); + } + $xml->endTag("windowsregistryentries"); + } + + $xml->endTag("operatingsystem"); +} + +=head1 QUERY MODE + +When you use C, the output is a series of +lines of the form: + + windows=no + linux=yes + fullvirt=yes + xen_pv_drivers=no + +(each answer is usually C or C, or the line is completely +missing if we could not determine the answer at all). + +If the guest is multiboot, you can get apparently conflicting answers +(eg. C and C, or a guest which is both +fullvirt and has a Xen PV kernel). This is normal, and just means +that the guest can do both things, although it might require operator +intervention such as selecting a boot option when the guest is +booting. + +This section describes the full range of answers possible. + +=over 4 + +=cut + +sub output_query +{ + output_query_windows (); + output_query_linux (); + output_query_rhel (); + output_query_fedora (); + output_query_debian (); + output_query_fullvirt (); + output_query_xen_domU_kernel (); + output_query_xen_pv_drivers (); + output_query_virtio_drivers (); + output_query_kernel_arch (); + output_query_userspace_arch (); +} + +=item windows=(yes|no) + +Answer C if Microsoft Windows is installed in the guest. + +=cut + +sub output_query_windows +{ + my $windows = "no"; + foreach my $os (keys %$oses) { + $windows="yes" if $oses->{$os}->{os} eq "windows"; + } + print "windows=$windows\n"; +} + +=item linux=(yes|no) + +Answer C if a Linux kernel is installed in the guest. + +=cut + +sub output_query_linux +{ + my $linux = "no"; + foreach my $os (keys %$oses) { + $linux="yes" if $oses->{$os}->{os} eq "linux"; + } + print "linux=$linux\n"; +} + +=item rhel=(yes|no) + +Answer C if the guest contains Red Hat Enterprise Linux. + +=cut + +sub output_query_rhel +{ + my $rhel = "no"; + foreach my $os (keys %$oses) { + $rhel="yes" if ($oses->{$os}->{os} eq "linux" && + $oses->{$os}->{distro} eq "rhel"); + } + print "rhel=$rhel\n"; +} + +=item fedora=(yes|no) + +Answer C if the guest contains the Fedora Linux distribution. + +=cut + +sub output_query_fedora +{ + my $fedora = "no"; + foreach my $os (keys %$oses) { + $fedora="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "fedora"; + } + print "fedora=$fedora\n"; +} + +=item debian=(yes|no) + +Answer C if the guest contains the Debian Linux distribution. + +=cut + +sub output_query_debian +{ + my $debian = "no"; + foreach my $os (keys %$oses) { + $debian="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "debian"; + } + print "debian=$debian\n"; +} + +=item fullvirt=(yes|no) + +Answer C if there is at least one operating system kernel +installed in the guest which runs fully virtualized. Such a guest +would require a hypervisor which supports full system virtualization. + +=cut + +sub output_query_fullvirt +{ + # The assumption is full-virt, unless all installed kernels + # are identified as paravirt. + # XXX Fails on Windows guests. + foreach my $os (keys %$oses) { + foreach my $kernel (@{$oses->{$os}->{kernels}}) { + my $is_pv = $kernel->{version} =~ m/xen/; + unless ($is_pv) { + print "fullvirt=yes\n"; + return; + } + } + } + print "fullvirt=no\n"; +} + +=item xen_domU_kernel=(yes|no) + +Answer C if there is at least one Linux kernel installed in +the guest which is compiled as a Xen DomU (a Xen paravirtualized +guest). + +=cut + +sub output_query_xen_domU_kernel +{ + foreach my $os (keys %$oses) { + foreach my $kernel (@{$oses->{$os}->{kernels}}) { + my $is_xen = $kernel->{version} =~ m/xen/; + if ($is_xen) { + print "xen_domU_kernel=yes\n"; + return; + } + } + } + print "xen_domU_kernel=no\n"; +} + +=item xen_pv_drivers=(yes|no) + +Answer C if the guest has Xen paravirtualized drivers installed +(usually the kernel itself will be fully virtualized, but the PV +drivers have been installed by the administrator for performance +reasons). + +=cut + +sub output_query_xen_pv_drivers +{ + foreach my $os (keys %$oses) { + foreach my $kernel (@{$oses->{$os}->{kernels}}) { + foreach my $module (@{$kernel->{modules}}) { + if ($module =~ m/xen-/) { + print "xen_pv_drivers=yes\n"; + return; + } + } + } + } + print "xen_pv_drivers=no\n"; +} + +=item virtio_drivers=(yes|no) + +Answer C if the guest has virtio paravirtualized drivers +installed. Virtio drivers are commonly used to improve the +performance of KVM. + +=cut + +sub output_query_virtio_drivers +{ + foreach my $os (keys %$oses) { + foreach my $kernel (@{$oses->{$os}->{kernels}}) { + foreach my $module (@{$kernel->{modules}}) { + if ($module =~ m/virtio_/) { + print "virtio_drivers=yes\n"; + return; + } + } + } + } + print "virtio_drivers=no\n"; +} + +=item userspace_arch=(x86_64|...) + +Print the architecture of userspace. + +NB. For multi-boot VMs this can print several lines. + +=cut + +sub output_query_userspace_arch +{ + my %arches; + + foreach my $os (keys %$oses) { + $arches{$oses->{$os}->{arch}} = 1 if exists $oses->{$os}->{arch}; + } + + foreach (sort keys %arches) { + print "userspace_arch=$_\n"; + } +} + +=item kernel_arch=(x86_64|...) + +Print the architecture of the kernel. + +NB. For multi-boot VMs this can print several lines. + +=cut + +sub output_query_kernel_arch +{ + my %arches; + + foreach my $os (keys %$oses) { + foreach my $kernel (@{$oses->{$os}->{kernels}}) { + $arches{$kernel->{arch}} = 1 if exists $kernel->{arch}; + } + } + + foreach (sort keys %arches) { + print "kernel_arch=$_\n"; + } +} + +=back + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L. + +For Windows registry parsing we require the C program +from L. + +=head1 AUTHOR + +Richard W.M. Jones L + +Matthew Booth L + +=head1 COPYRIGHT + +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. diff --git a/inspector/virt-inspector.pl b/inspector/virt-inspector.pl deleted file mode 100755 index 86b1795..0000000 --- a/inspector/virt-inspector.pl +++ /dev/null @@ -1,874 +0,0 @@ -#!/usr/bin/perl -w -# virt-inspector -# 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. - -use warnings; -use strict; - -use Sys::Guestfs; -use Sys::Guestfs::Lib qw(open_guest get_partitions resolve_windows_path - inspect_all_partitions inspect_partition - inspect_operating_systems mount_operating_system inspect_in_detail); -use Pod::Usage; -use Getopt::Long; -use Data::Dumper; -use XML::Writer; -use Locale::TextDomain 'libguestfs'; - -# Optional: -eval "use YAML::Any;"; - -=encoding utf8 - -=head1 NAME - -virt-inspector - Display OS version, kernel, drivers, mount points, applications, etc. in a virtual machine - -=head1 SYNOPSIS - - virt-inspector [--connect URI] domname - - virt-inspector guest.img [guest.img ...] - -=head1 DESCRIPTION - -B examines a virtual machine and tries to determine -the version of the OS, the kernel version, what drivers are installed, -whether the virtual machine is fully virtualized (FV) or -para-virtualized (PV), what applications are installed and more. - -Virt-inspector can produce output in several formats, including a -readable text report, and XML for feeding into other programs. - -Virt-inspector should only be run on I virtual machines. -The program tries to determine that the machine is inactive and will -refuse to run if it thinks you are trying to inspect a running domain. - -In the normal usage, use C where C is -the libvirt domain (see: C). - -You can also run virt-inspector directly on disk images from a single -virtual machine. Use C. In rare cases a -domain has several block devices, in which case you should list them -one after another, with the first corresponding to the guest's -C, the second to the guest's C and so on. - -Virt-inspector can only inspect and report upon I. To inspect several virtual machines, you have to run -virt-inspector several times (for example, from a shell script -for-loop). - -Because virt-inspector needs direct access to guest images, it won't -normally work over remote libvirt connections. - -=head1 OPTIONS - -=over 4 - -=cut - -my $help; - -=item B<--help> - -Display brief help. - -=cut - -my $version; - -=item B<--version> - -Display version number and exit. - -=cut - -my $uri; - -=item B<--connect URI> | B<-c URI> - -If using libvirt, connect to the given I. If omitted, -then we connect to the default libvirt hypervisor. - -Libvirt is only used if you specify a C on the -command line. If you specify guest block devices directly, -then libvirt is not used at all. - -=cut - -my $output = "text"; - -=back - -The following options select the output format. Use only one of them. -The default is a readable text report. - -=over 4 - -=item B<--text> (default) - -Plain text report. - -=item B<--none> - -Produce no output at all. - -=item B<--xml> - -If you select I<--xml> then you get XML output which can be fed -to other programs. - -=item B<--yaml> - -If you select I<--yaml> then you get YAML output which can be fed -to other programs. - -=item B<--perl> - -If you select I<--perl> then you get Perl structures output which -can be used directly in another Perl program. - -=item B<--fish> - -=item B<--ro-fish> - -If you select I<--fish> then we print a L command -line which will automatically mount up the filesystems on the -correct mount points. Try this for example: - - guestfish $(virt-inspector --fish guest.img) - -I<--ro-fish> is the same, but the I<--ro> option is passed to -guestfish so that the filesystems are mounted read-only. - -=item B<--query> - -In "query mode" we answer common questions about the guest, such -as whether it is fullvirt or needs a Xen hypervisor to run. - -See section I below. - -=cut - -my $windows_registry; - -=item B<--windows-registry> - -If this item is passed, I the guest is Windows, I the -external program C is available (see SEE ALSO section), then we -attempt to parse the Windows registry. This allows much more -information to be gathered for Windows guests. - -This is quite an expensive and slow operation, so we don't do it by -default. - -=back - -=cut - -GetOptions ("help|?" => \$help, - "version" => \$version, - "connect|c=s" => \$uri, - "text" => sub { $output = "text" }, - "none" => sub { $output = "none" }, - "xml" => sub { $output = "xml" }, - "yaml" => sub { $output = "yaml" }, - "perl" => sub { $output = "perl" }, - "fish" => sub { $output = "fish" }, - "guestfish" => sub { $output = "fish" }, - "ro-fish" => sub { $output = "ro-fish" }, - "ro-guestfish" => sub { $output = "ro-fish" }, - "query" => sub { $output = "query" }, - "windows-registry" => \$windows_registry, - ) 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 -} -pod2usage (__"virt-inspector: no image or VM names given") if @ARGV == 0; - -my $rw = 0; -$rw = 1 if $output eq "fish"; -my $g; -my @images; -if ($uri) { - my ($conn, $dom); - ($g, $conn, $dom, @images) = - open_guest (\@ARGV, rw => $rw, address => $uri); -} else { - my ($conn, $dom); - ($g, $conn, $dom, @images) = - open_guest (\@ARGV, rw => $rw); -} - -$g->launch (); - -=head1 OUTPUT FORMAT - - Operating system(s) - ------------------- - Linux (distro + version) - Windows (version) - | - | - +--- Filesystems ---------- Installed apps --- Kernel & drivers - ----------- -------------- ---------------- - mount point => device List of apps Extra information - mount point => device and versions about kernel(s) - ... and drivers - swap => swap device - (plus lots of extra information - about each filesystem) - -The output of virt-inspector is a complex two-level data structure. - -At the top level is a list of the operating systems installed on the -guest. (For the vast majority of guests, only a single OS is -installed.) The data returned for the OS includes the name (Linux, -Windows), the distribution and version. - -The diagram above shows what we return for each OS. - -With the I<--xml> option the output is mapped into an XML document. -Unfortunately there is no clear schema for this document -(contributions welcome) but you can get an idea of the format by -looking at other documents and as a last resort the source for this -program. - -With the I<--fish> or I<--ro-fish> option the mount points are mapped to -L command line parameters, so that you can go in -afterwards and inspect the guest with everything mounted in the -right place. For example: - - guestfish $(virt-inspector --ro-fish guest.img) - ==> guestfish --ro -a guest.img -m /dev/VG/LV:/ -m /dev/sda1:/boot - -=cut - -# List of possible filesystems. -my @partitions = get_partitions ($g); - -# Now query each one to build up a picture of what's in it. -my %fses = - inspect_all_partitions ($g, \@partitions, - use_windows_registry => $windows_registry); - -#print "fses -----------\n"; -#print Dumper(\%fses); - -my $oses = inspect_operating_systems ($g, \%fses); - -#print "oses -----------\n"; -#print Dumper($oses); - -# Mount up the disks so we can check for applications -# and kernels. Skip this if the output is "*fish" because -# we don't need to know. - -if ($output !~ /.*fish$/) { - my $root_dev; - foreach $root_dev (sort keys %$oses) { - my $os = $oses->{$root_dev}; - mount_operating_system ($g, $os); - inspect_in_detail ($g, $os); - $g->umount_all (); - } -} - -#---------------------------------------------------------------------- -# Output. - -if ($output eq "fish" || $output eq "ro-fish") { - my @osdevs = keys %$oses; - # This only works if there is a single OS. - die __"--fish output is only possible with a single OS\n" if @osdevs != 1; - - my $root_dev = $osdevs[0]; - - if ($output eq "ro-fish") { - print "--ro "; - } - - print "-a $_ " foreach @images; - - my $mounts = $oses->{$root_dev}->{mounts}; - # Have to mount / first. Luckily '/' is early in the ASCII - # character set, so this should be OK. - foreach (sort keys %$mounts) { - print "-m $mounts->{$_}:$_ " if $_ ne "swap" && $_ ne "none"; - } - print "\n" -} - -# Perl output. -elsif ($output eq "perl") { - print Dumper(%$oses); -} - -# YAML output -elsif ($output eq "yaml") { - die __"virt-inspector: no YAML support\n" - unless exists $INC{"YAML/Any.pm"}; - - print Dump(%$oses); -} - -# Plain text output (the default). -elsif ($output eq "text") { - output_text (); -} - -# XML output. -elsif ($output eq "xml") { - output_xml (); -} - -# Query mode. -elsif ($output eq "query") { - output_query (); -} - -sub output_text -{ - output_text_os ($oses->{$_}) foreach sort keys %$oses; -} - -sub output_text_os -{ - my $os = shift; - - print $os->{os}, " " if exists $os->{os}; - print $os->{distro}, " " if exists $os->{distro}; - print $os->{arch}, " " if exists $os->{arch}; - print $os->{major_version} if exists $os->{major_version}; - print ".", $os->{minor_version} if exists $os->{minor_version}; - print " "; - print "on ", $os->{root_device}, ":\n"; - - print __" Mountpoints:\n"; - my $mounts = $os->{mounts}; - foreach (sort keys %$mounts) { - printf " %-30s %s\n", $mounts->{$_}, $_ - } - - print __" Filesystems:\n"; - my $filesystems = $os->{filesystems}; - foreach (sort keys %$filesystems) { - print " $_:\n"; - print " label: $filesystems->{$_}{label}\n" - if exists $filesystems->{$_}{label}; - print " UUID: $filesystems->{$_}{uuid}\n" - if exists $filesystems->{$_}{uuid}; - print " type: $filesystems->{$_}{fstype}\n" - if exists $filesystems->{$_}{fstype}; - print " content: $filesystems->{$_}{content}\n" - if exists $filesystems->{$_}{content}; - } - - if (exists $os->{modprobe_aliases}) { - my %aliases = %{$os->{modprobe_aliases}}; - my @keys = sort keys %aliases; - if (@keys) { - print __" Modprobe aliases:\n"; - foreach (@keys) { - printf " %-30s %s\n", $_, $aliases{$_}->{modulename} - } - } - } - - if (exists $os->{initrd_modules}) { - my %modvers = %{$os->{initrd_modules}}; - my @keys = sort keys %modvers; - if (@keys) { - print __" Initrd modules:\n"; - foreach (@keys) { - my @modules = @{$modvers{$_}}; - print " $_:\n"; - print " $_\n" foreach @modules; - } - } - } - - print __" Applications:\n"; - my @apps = @{$os->{apps}}; - foreach (@apps) { - print " $_->{name} $_->{version}\n" - } - - print __" Kernels:\n"; - my @kernels = @{$os->{kernels}}; - foreach (@kernels) { - print " $_->{version} ($_->{arch})\n"; - my @modules = @{$_->{modules}}; - foreach (@modules) { - print " $_\n"; - } - } - - if (exists $os->{root}->{registry}) { - print __" Windows Registry entries:\n"; - # These are just lumps of text - dump them out. - foreach (@{$os->{root}->{registry}}) { - print "$_\n"; - } - } -} - -sub output_xml -{ - my $xml = new XML::Writer(DATA_MODE => 1, DATA_INDENT => 2); - - $xml->startTag("operatingsystems"); - output_xml_os ($oses->{$_}, $xml) foreach sort keys %$oses; - $xml->endTag("operatingsystems"); - - $xml->end(); -} - -sub output_xml_os -{ - my ($os, $xml) = @_; - - $xml->startTag("operatingsystem"); - - foreach ( [ "name" => "os" ], - [ "distro" => "distro" ], - [ "arch" => "arch" ], - [ "major_version" => "major_version" ], - [ "minor_version" => "minor_version" ], - [ "package_format" => "package_format" ], - [ "package_management" => "package_management" ], - [ "root" => "root_device" ] ) { - $xml->dataElement($_->[0], $os->{$_->[1]}) if exists $os->{$_->[1]}; - } - - $xml->startTag("mountpoints"); - my $mounts = $os->{mounts}; - foreach (sort keys %$mounts) { - $xml->dataElement("mountpoint", $_, "dev" => $mounts->{$_}); - } - $xml->endTag("mountpoints"); - - $xml->startTag("filesystems"); - my $filesystems = $os->{filesystems}; - foreach (sort keys %$filesystems) { - $xml->startTag("filesystem", "dev" => $_); - - foreach my $field ( [ "label" => "label" ], - [ "uuid" => "uuid" ], - [ "type" => "fstype" ], - [ "content" => "content" ], - [ "spec" => "spec" ] ) { - $xml->dataElement($field->[0], $filesystems->{$_}{$field->[1]}) - if exists $filesystems->{$_}{$field->[1]}; - } - - $xml->endTag("filesystem"); - } - $xml->endTag("filesystems"); - - if (exists $os->{modprobe_aliases}) { - my %aliases = %{$os->{modprobe_aliases}}; - my @keys = sort keys %aliases; - if (@keys) { - $xml->startTag("modprobealiases"); - foreach (@keys) { - $xml->startTag("alias", "device" => $_); - - foreach my $field ( [ "modulename" => "modulename" ], - [ "augeas" => "augeas" ], - [ "file" => "file" ] ) { - $xml->dataElement($field->[0], $aliases{$_}->{$field->[1]}); - } - - $xml->endTag("alias"); - } - $xml->endTag("modprobealiases"); - } - } - - if (exists $os->{initrd_modules}) { - my %modvers = %{$os->{initrd_modules}}; - my @keys = sort keys %modvers; - if (@keys) { - $xml->startTag("initrds"); - foreach (@keys) { - my @modules = @{$modvers{$_}}; - $xml->startTag("initrd", "version" => $_); - $xml->dataElement("module", $_) foreach @modules; - $xml->endTag("initrd"); - } - $xml->endTag("initrds"); - } - } - - $xml->startTag("applications"); - my @apps = @{$os->{apps}}; - foreach (@apps) { - $xml->startTag("application"); - $xml->dataElement("name", $_->{name}); - $xml->dataElement("version", $_->{version}); - $xml->endTag("application"); - } - $xml->endTag("applications"); - - if(defined($os->{boot}) && defined($os->{boot}->{configs})) { - my $default = $os->{boot}->{default}; - my $configs = $os->{boot}->{configs}; - - $xml->startTag("boot"); - for(my $i = 0; $i < scalar(@$configs); $i++) { - my $config = $configs->[$i]; - - my @attrs = (); - push(@attrs, ("default" => 1)) if($default == $i); - $xml->startTag("config", @attrs); - $xml->dataElement("title", $config->{title}); - $xml->dataElement("kernel", $config->{kernel}->{version}) - if(defined($config->{kernel})); - $xml->dataElement("cmdline", $config->{cmdline}) - if(defined($config->{cmdline})); - $xml->endTag("config"); - } - $xml->endTag("boot"); - } - - $xml->startTag("kernels"); - my @kernels = @{$os->{kernels}}; - foreach (@kernels) { - $xml->startTag("kernel", - "version" => $_->{version}, - "arch" => $_->{arch}); - $xml->startTag("modules"); - my @modules = @{$_->{modules}}; - foreach (@modules) { - $xml->dataElement("module", $_); - } - $xml->endTag("modules"); - $xml->dataElement("path", $_->{path}) if(defined($_->{path})); - $xml->dataElement("package", $_->{package}) if(defined($_->{package})); - $xml->endTag("kernel"); - } - $xml->endTag("kernels"); - - if (exists $os->{root}->{registry}) { - $xml->startTag("windowsregistryentries"); - # These are just lumps of text - dump them out. - foreach (@{$os->{root}->{registry}}) { - $xml->dataElement("windowsregistryentry", $_); - } - $xml->endTag("windowsregistryentries"); - } - - $xml->endTag("operatingsystem"); -} - -=head1 QUERY MODE - -When you use C, the output is a series of -lines of the form: - - windows=no - linux=yes - fullvirt=yes - xen_pv_drivers=no - -(each answer is usually C or C, or the line is completely -missing if we could not determine the answer at all). - -If the guest is multiboot, you can get apparently conflicting answers -(eg. C and C, or a guest which is both -fullvirt and has a Xen PV kernel). This is normal, and just means -that the guest can do both things, although it might require operator -intervention such as selecting a boot option when the guest is -booting. - -This section describes the full range of answers possible. - -=over 4 - -=cut - -sub output_query -{ - output_query_windows (); - output_query_linux (); - output_query_rhel (); - output_query_fedora (); - output_query_debian (); - output_query_fullvirt (); - output_query_xen_domU_kernel (); - output_query_xen_pv_drivers (); - output_query_virtio_drivers (); - output_query_kernel_arch (); - output_query_userspace_arch (); -} - -=item windows=(yes|no) - -Answer C if Microsoft Windows is installed in the guest. - -=cut - -sub output_query_windows -{ - my $windows = "no"; - foreach my $os (keys %$oses) { - $windows="yes" if $oses->{$os}->{os} eq "windows"; - } - print "windows=$windows\n"; -} - -=item linux=(yes|no) - -Answer C if a Linux kernel is installed in the guest. - -=cut - -sub output_query_linux -{ - my $linux = "no"; - foreach my $os (keys %$oses) { - $linux="yes" if $oses->{$os}->{os} eq "linux"; - } - print "linux=$linux\n"; -} - -=item rhel=(yes|no) - -Answer C if the guest contains Red Hat Enterprise Linux. - -=cut - -sub output_query_rhel -{ - my $rhel = "no"; - foreach my $os (keys %$oses) { - $rhel="yes" if ($oses->{$os}->{os} eq "linux" && - $oses->{$os}->{distro} eq "rhel"); - } - print "rhel=$rhel\n"; -} - -=item fedora=(yes|no) - -Answer C if the guest contains the Fedora Linux distribution. - -=cut - -sub output_query_fedora -{ - my $fedora = "no"; - foreach my $os (keys %$oses) { - $fedora="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "fedora"; - } - print "fedora=$fedora\n"; -} - -=item debian=(yes|no) - -Answer C if the guest contains the Debian Linux distribution. - -=cut - -sub output_query_debian -{ - my $debian = "no"; - foreach my $os (keys %$oses) { - $debian="yes" if $oses->{$os}->{os} eq "linux" && $oses->{$os}->{distro} eq "debian"; - } - print "debian=$debian\n"; -} - -=item fullvirt=(yes|no) - -Answer C if there is at least one operating system kernel -installed in the guest which runs fully virtualized. Such a guest -would require a hypervisor which supports full system virtualization. - -=cut - -sub output_query_fullvirt -{ - # The assumption is full-virt, unless all installed kernels - # are identified as paravirt. - # XXX Fails on Windows guests. - foreach my $os (keys %$oses) { - foreach my $kernel (@{$oses->{$os}->{kernels}}) { - my $is_pv = $kernel->{version} =~ m/xen/; - unless ($is_pv) { - print "fullvirt=yes\n"; - return; - } - } - } - print "fullvirt=no\n"; -} - -=item xen_domU_kernel=(yes|no) - -Answer C if there is at least one Linux kernel installed in -the guest which is compiled as a Xen DomU (a Xen paravirtualized -guest). - -=cut - -sub output_query_xen_domU_kernel -{ - foreach my $os (keys %$oses) { - foreach my $kernel (@{$oses->{$os}->{kernels}}) { - my $is_xen = $kernel->{version} =~ m/xen/; - if ($is_xen) { - print "xen_domU_kernel=yes\n"; - return; - } - } - } - print "xen_domU_kernel=no\n"; -} - -=item xen_pv_drivers=(yes|no) - -Answer C if the guest has Xen paravirtualized drivers installed -(usually the kernel itself will be fully virtualized, but the PV -drivers have been installed by the administrator for performance -reasons). - -=cut - -sub output_query_xen_pv_drivers -{ - foreach my $os (keys %$oses) { - foreach my $kernel (@{$oses->{$os}->{kernels}}) { - foreach my $module (@{$kernel->{modules}}) { - if ($module =~ m/xen-/) { - print "xen_pv_drivers=yes\n"; - return; - } - } - } - } - print "xen_pv_drivers=no\n"; -} - -=item virtio_drivers=(yes|no) - -Answer C if the guest has virtio paravirtualized drivers -installed. Virtio drivers are commonly used to improve the -performance of KVM. - -=cut - -sub output_query_virtio_drivers -{ - foreach my $os (keys %$oses) { - foreach my $kernel (@{$oses->{$os}->{kernels}}) { - foreach my $module (@{$kernel->{modules}}) { - if ($module =~ m/virtio_/) { - print "virtio_drivers=yes\n"; - return; - } - } - } - } - print "virtio_drivers=no\n"; -} - -=item userspace_arch=(x86_64|...) - -Print the architecture of userspace. - -NB. For multi-boot VMs this can print several lines. - -=cut - -sub output_query_userspace_arch -{ - my %arches; - - foreach my $os (keys %$oses) { - $arches{$oses->{$os}->{arch}} = 1 if exists $oses->{$os}->{arch}; - } - - foreach (sort keys %arches) { - print "userspace_arch=$_\n"; - } -} - -=item kernel_arch=(x86_64|...) - -Print the architecture of the kernel. - -NB. For multi-boot VMs this can print several lines. - -=cut - -sub output_query_kernel_arch -{ - my %arches; - - foreach my $os (keys %$oses) { - foreach my $kernel (@{$oses->{$os}->{kernels}}) { - $arches{$kernel->{arch}} = 1 if exists $kernel->{arch}; - } - } - - foreach (sort keys %arches) { - print "kernel_arch=$_\n"; - } -} - -=back - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L. - -For Windows registry parsing we require the C program -from L. - -=head1 AUTHOR - -Richard W.M. Jones L - -Matthew Booth L - -=head1 COPYRIGHT - -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. diff --git a/po/POTFILES.in b/po/POTFILES.in index f2ffba8..7ccadcf 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -1,4 +1,4 @@ -cat/virt-cat.pl +cat/virt-cat daemon/augeas.c daemon/blockdev.c daemon/checksum.c @@ -55,8 +55,8 @@ daemon/wc.c daemon/xattr.c daemon/zero.c daemon/zerofree.c -df/virt-df.pl -edit/virt-edit.pl +df/virt-df +edit/virt-edit fish/alloc.c fish/cmds.c fish/completion.c @@ -71,7 +71,7 @@ fish/rc.c fish/reopen.c fish/tilde.c fish/time.c -inspector/virt-inspector.pl +inspector/virt-inspector java/com_redhat_et_libguestfs_GuestFS.c ocaml/guestfs_c.c ocaml/guestfs_c_actions.c @@ -81,7 +81,7 @@ perl/lib/Sys/Guestfs.pm perl/lib/Sys/Guestfs/Lib.pm python/guestfs-py.c regressions/test-noexec-stack.pl -rescue/virt-rescue.pl +rescue/virt-rescue ruby/ext/guestfs/_guestfs.c src/guestfs-actions.c src/guestfs-bindtests.c diff --git a/rescue/Makefile.am b/rescue/Makefile.am index 1067c8d..aa8d38a 100644 --- a/rescue/Makefile.am +++ b/rescue/Makefile.am @@ -16,23 +16,23 @@ # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. EXTRA_DIST = \ - run-rescue-locally \ - virt-rescue.pl + run-rescue-locally if HAVE_RESCUE +bin_SCRIPTS = virt-rescue man_MANS = virt-rescue.1 noinst_DATA = $(top_builddir)/html/virt-rescue.1.html -virt-rescue.1: virt-rescue.pl +virt-rescue.1: virt-rescue $(POD2MAN) \ --section 1 \ -c "Virtualization Support" \ --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \ $< > $@-t && mv $@-t $@ -$(top_builddir)/html/virt-rescue.1.html: virt-rescue.pl +$(top_builddir)/html/virt-rescue.1.html: virt-rescue mkdir -p $(top_builddir)/html cd $(top_builddir) && pod2html \ --css 'pod.css' \ @@ -41,8 +41,4 @@ $(top_builddir)/html/virt-rescue.1.html: virt-rescue.pl --outfile html/virt-rescue.1.html \ rescue/$< -install-data-hook: - mkdir -p $(DESTDIR)$(bindir) - install -m 0755 virt-rescue.pl $(DESTDIR)$(bindir)/virt-rescue - endif diff --git a/rescue/virt-rescue b/rescue/virt-rescue new file mode 100755 index 0000000..a44940d --- /dev/null +++ b/rescue/virt-rescue @@ -0,0 +1,169 @@ +#!/usr/bin/perl -w +# virt-rescue +# 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. + +use warnings; +use strict; + +use Sys::Guestfs; +use Sys::Guestfs::Lib qw(open_guest); +use Pod::Usage; +use Getopt::Long; +use Locale::TextDomain 'libguestfs'; + +=encoding utf8 + +=head1 NAME + +virt-rescue - Run a rescue shell on a virtual machine + +=head1 SYNOPSIS + + virt-rescue [--options] domname + + virt-rescue [--options] disk.img [disk.img ...] + +=head1 DESCRIPTION + +virt-rescue gives you a rescue shell and some simple recovery tools +which you can use on a virtual machine disk image. + +After running virt-rescue, what you see under C is the recovery +appliance. You must mount the virtual machine's filesystems by hand, +eg: + + # lvs + LV VG Attr LSize Origin Snap% Move Log Copy% Convert + lv_root vg_f11x64 -wi-a- 8.83G + lv_swap vg_f11x64 -wi-a- 992.00M + # mount /dev/vg_f11x64/lv_root /sysroot + # ls /sysroot + +B that the virtual machine must not be powered on when you use +this tool. Doing so will probably result in disk corruption in the +VM. However if you use the I<--ro> (read only) option, then you can +attach a shell to a running machine, but the results might be strange +or inconsistent. + +This tool is just designed for quick interactive hacking on a virtual +machine. For more structured access to a virtual machine disk image, +you should use L. To get a structured shell, use +L. + +=head1 OPTIONS + +=over 4 + +=cut + +my $help; + +=item B<--help> + +Display brief help. + +=cut + +my $version; + +=item B<--version> + +Display version number and exit. + +=cut + +my $uri; + +=item B<--connect URI> | B<-c URI> + +If using libvirt, connect to the given I. If omitted, then we +connect to the default libvirt hypervisor. + +If you specify guest block devices directly, then libvirt is not used +at all. + +=cut + +my $readonly; + +=item B<--ro> | B<-r> + +Open the image read-only. + +=back + +=cut + +GetOptions ("help|?" => \$help, + "version" => \$version, + "connect|c=s" => \$uri, + "ro|r" => \$readonly, + ) 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 +} + +pod2usage (__"virt-rescue: no image or VM names rescue given") + if @ARGV == 0; + +my @args = (\@ARGV); +push @args, address => $uri if $uri; +push @args, rw => 1 unless $readonly; +my $g = open_guest (@args); + +$g->set_direct (1); +$g->set_append ("guestfs_rescue=1"); + +$g->launch (); + +exit 0; + +=head1 SEE ALSO + +L, +L, +L, +L, +L, +L, +L. + +=head1 AUTHOR + +Richard W.M. Jones L + +=head1 COPYRIGHT + +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. diff --git a/rescue/virt-rescue.pl b/rescue/virt-rescue.pl deleted file mode 100755 index a44940d..0000000 --- a/rescue/virt-rescue.pl +++ /dev/null @@ -1,169 +0,0 @@ -#!/usr/bin/perl -w -# virt-rescue -# 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. - -use warnings; -use strict; - -use Sys::Guestfs; -use Sys::Guestfs::Lib qw(open_guest); -use Pod::Usage; -use Getopt::Long; -use Locale::TextDomain 'libguestfs'; - -=encoding utf8 - -=head1 NAME - -virt-rescue - Run a rescue shell on a virtual machine - -=head1 SYNOPSIS - - virt-rescue [--options] domname - - virt-rescue [--options] disk.img [disk.img ...] - -=head1 DESCRIPTION - -virt-rescue gives you a rescue shell and some simple recovery tools -which you can use on a virtual machine disk image. - -After running virt-rescue, what you see under C is the recovery -appliance. You must mount the virtual machine's filesystems by hand, -eg: - - # lvs - LV VG Attr LSize Origin Snap% Move Log Copy% Convert - lv_root vg_f11x64 -wi-a- 8.83G - lv_swap vg_f11x64 -wi-a- 992.00M - # mount /dev/vg_f11x64/lv_root /sysroot - # ls /sysroot - -B that the virtual machine must not be powered on when you use -this tool. Doing so will probably result in disk corruption in the -VM. However if you use the I<--ro> (read only) option, then you can -attach a shell to a running machine, but the results might be strange -or inconsistent. - -This tool is just designed for quick interactive hacking on a virtual -machine. For more structured access to a virtual machine disk image, -you should use L. To get a structured shell, use -L. - -=head1 OPTIONS - -=over 4 - -=cut - -my $help; - -=item B<--help> - -Display brief help. - -=cut - -my $version; - -=item B<--version> - -Display version number and exit. - -=cut - -my $uri; - -=item B<--connect URI> | B<-c URI> - -If using libvirt, connect to the given I. If omitted, then we -connect to the default libvirt hypervisor. - -If you specify guest block devices directly, then libvirt is not used -at all. - -=cut - -my $readonly; - -=item B<--ro> | B<-r> - -Open the image read-only. - -=back - -=cut - -GetOptions ("help|?" => \$help, - "version" => \$version, - "connect|c=s" => \$uri, - "ro|r" => \$readonly, - ) 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 -} - -pod2usage (__"virt-rescue: no image or VM names rescue given") - if @ARGV == 0; - -my @args = (\@ARGV); -push @args, address => $uri if $uri; -push @args, rw => 1 unless $readonly; -my $g = open_guest (@args); - -$g->set_direct (1); -$g->set_append ("guestfs_rescue=1"); - -$g->launch (); - -exit 0; - -=head1 SEE ALSO - -L, -L, -L, -L, -L, -L, -L. - -=head1 AUTHOR - -Richard W.M. Jones L - -=head1 COPYRIGHT - -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. -- 1.6.2.5