[Libguestfs] [PATCH] Rename virt-[tool].pl as virt-[tool]

Richard W.M. Jones rjones at redhat.com
Wed Sep 23 11:39:09 UTC 2009


As suggested by Dan Berrange in this posting:

https://www.redhat.com/archives/libguestfs/2009-September/msg00155.html

Rich.

-- 
Richard Jones, Emerging Technologies, Red Hat  http://et.redhat.com/~rjones
virt-p2v converts physical machines to virtual machines.  Boot with a
live CD or over the network (PXE) and turn machines into Xen guests.
http://et.redhat.com/~rjones/virt-p2v
-------------- next part --------------
>From b488436cc54288fcae8988493749f2e6c87f274c Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at trick.home.annexia.org>
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<virt-cat> is a command line tool to display the contents of C<file>
+where C<file> exists in the named virtual machine (or disk image).
+
+C<virt-cat> can be used to quickly view a single file.  To edit a
+file, use C<virt-edit>.  For more complex cases you should look at the
+L<guestfish(1)> tool.
+
+=head1 EXAMPLES
+
+Display C</etc/fstab> file from inside the libvirt VM called
+C<mydomain>:
+
+ 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<URI>.  If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly, then libvirt is not used
+at all.
+
+=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<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-edit(1)>,
+L<Sys::Guestfs(3)>,
+L<Sys::Guestfs::Lib(3)>,
+L<Sys::Virt(3)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+
+=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<virt-cat> is a command line tool to display the contents of C<file>
-where C<file> exists in the named virtual machine (or disk image).
-
-C<virt-cat> can be used to quickly view a single file.  To edit a
-file, use C<virt-edit>.  For more complex cases you should look at the
-L<guestfish(1)> tool.
-
-=head1 EXAMPLES
-
-Display C</etc/fstab> file from inside the libvirt VM called
-C<mydomain>:
-
- 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<URI>.  If omitted, then we
-connect to the default libvirt hypervisor.
-
-If you specify guest block devices directly, then libvirt is not used
-at all.
-
-=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<guestfs(3)>,
-L<guestfish(1)>,
-L<virt-edit(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
-
-=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<virt-df> 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<df(1)> command, but for virtual machines, except that
+it also works for Windows virtual machines.
+
+If used without any arguments, C<virt-df> checks with libvirt to get a
+list of all active and inactive guests, and performs a C<df>-type
+operation on each one in turn, printing out the results.
+
+If used with any argument(s), C<virt-df> performs a C<df>-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<virt-df> will I<only work for a
+single guest>.  If you want to run on multiple guests, then you have
+to invoke C<virt-df> 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<df>
+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<URI>.  If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly, then libvirt is not used
+at all.
+
+=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<guestfs(3)>,
+L<guestfish(1)>,
+L<Sys::Guestfs(3)>,
+L<Sys::Guestfs::Lib(3)>,
+L<Sys::Virt(3)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+
+=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<virt-df> 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<df(1)> command, but for virtual machines, except that
-it also works for Windows virtual machines.
-
-If used without any arguments, C<virt-df> checks with libvirt to get a
-list of all active and inactive guests, and performs a C<df>-type
-operation on each one in turn, printing out the results.
-
-If used with any argument(s), C<virt-df> performs a C<df>-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<virt-df> will I<only work for a
-single guest>.  If you want to run on multiple guests, then you have
-to invoke C<virt-df> 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<df>
-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<URI>.  If omitted, then we
-connect to the default libvirt hypervisor.
-
-If you specify guest block devices directly, then libvirt is not used
-at all.
-
-=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<guestfs(3)>,
-L<guestfish(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
-
-=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<virt-edit> is a command line tool to edit C<file> where C<file>
+exists in the named virtual machine (or disk image).
+
+B<Note> you must I<not> 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<virt-cat(1)>.  For more complex
+cases you should look at the L<guestfish(1)> 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<URI>.  If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly, then libvirt is not used
+at all.
+
+=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<EDITOR>
+
+If set, this string is used as the editor.  It may contain arguments,
+eg. C<"emacs -nw">
+
+If not set, C<vi> is used.
+
+=back
+
+=head1 SEE ALSO
+
+L<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-cat(1)>,
+L<Sys::Guestfs(3)>,
+L<Sys::Guestfs::Lib(3)>,
+L<Sys::Virt(3)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+
+=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<virt-edit> is a command line tool to edit C<file> where C<file>
-exists in the named virtual machine (or disk image).
-
-B<Note> you must I<not> 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<virt-cat(1)>.  For more complex
-cases you should look at the L<guestfish(1)> 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<URI>.  If omitted, then we
-connect to the default libvirt hypervisor.
-
-If you specify guest block devices directly, then libvirt is not used
-at all.
-
-=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<EDITOR>
-
-If set, this string is used as the editor.  It may contain arguments,
-eg. C<"emacs -nw">
-
-If not set, C<vi> is used.
-
-=back
-
-=head1 SEE ALSO
-
-L<guestfs(3)>,
-L<guestfish(1)>,
-L<virt-cat(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
-
-=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<virt-inspector> 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<inactive> 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<virt-inspector domname> where C<domname> is
+the libvirt domain (see: C<virsh list --all>).
+
+You can also run virt-inspector directly on disk images from a single
+virtual machine.  Use C<virt-inspector guest.img>.  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</dev/sda>, the second to the guest's C</dev/sdb> and so on.
+
+Virt-inspector can only inspect and report upon I<one domain at a
+time>.  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<URI>.  If omitted,
+then we connect to the default libvirt hypervisor.
+
+Libvirt is only used if you specify a C<domname> 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<guestfish(1)> 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<QUERY MODE> below.
+
+=cut
+
+my $windows_registry;
+
+=item B<--windows-registry>
+
+If this item is passed, I<and> the guest is Windows, I<and> the
+external program C<reged> 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<guestfish(1)> 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<virt-inspector --query>, 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<yes> or C<no>, 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<windows=yes> and C<linux=yes>, 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<guestfs(3)>,
+L<guestfish(1)>,
+L<Sys::Guestfs(3)>,
+L<Sys::Guestfs::Lib(3)>,
+L<Sys::Virt(3)>,
+L<http://libguestfs.org/>.
+
+For Windows registry parsing we require the C<reged> program
+from L<http://home.eunet.no/~pnordahl/ntpasswd/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+
+Matthew Booth L<mbooth at redhat.com>
+
+=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<virt-inspector> 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<inactive> 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<virt-inspector domname> where C<domname> is
-the libvirt domain (see: C<virsh list --all>).
-
-You can also run virt-inspector directly on disk images from a single
-virtual machine.  Use C<virt-inspector guest.img>.  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</dev/sda>, the second to the guest's C</dev/sdb> and so on.
-
-Virt-inspector can only inspect and report upon I<one domain at a
-time>.  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<URI>.  If omitted,
-then we connect to the default libvirt hypervisor.
-
-Libvirt is only used if you specify a C<domname> 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<guestfish(1)> 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<QUERY MODE> below.
-
-=cut
-
-my $windows_registry;
-
-=item B<--windows-registry>
-
-If this item is passed, I<and> the guest is Windows, I<and> the
-external program C<reged> 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<guestfish(1)> 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<virt-inspector --query>, 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<yes> or C<no>, 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<windows=yes> and C<linux=yes>, 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<yes> 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<guestfs(3)>,
-L<guestfish(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://libguestfs.org/>.
-
-For Windows registry parsing we require the C<reged> program
-from L<http://home.eunet.no/~pnordahl/ntpasswd/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
-
-Matthew Booth L<mbooth at redhat.com>
-
-=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<Note> 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<guestfs(3)>.  To get a structured shell, use
+L<guestfish(1)>.
+
+=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<URI>.  If omitted, then we
+connect to the default libvirt hypervisor.
+
+If you specify guest block devices directly, then libvirt is not used
+at all.
+
+=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<guestfs(3)>,
+L<guestfish(1)>,
+L<virt-cat(1)>,
+L<Sys::Guestfs(3)>,
+L<Sys::Guestfs::Lib(3)>,
+L<Sys::Virt(3)>,
+L<http://libguestfs.org/>.
+
+=head1 AUTHOR
+
+Richard W.M. Jones L<http://et.redhat.com/~rjones/>
+
+=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<Note> 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<guestfs(3)>.  To get a structured shell, use
-L<guestfish(1)>.
-
-=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<URI>.  If omitted, then we
-connect to the default libvirt hypervisor.
-
-If you specify guest block devices directly, then libvirt is not used
-at all.
-
-=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<guestfs(3)>,
-L<guestfish(1)>,
-L<virt-cat(1)>,
-L<Sys::Guestfs(3)>,
-L<Sys::Guestfs::Lib(3)>,
-L<Sys::Virt(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.redhat.com/~rjones/>
-
-=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



More information about the Libguestfs mailing list