[Libguestfs] [PATCH 2/5] Move virt tools (virt-cat, virt-edit etc) into tools/ subdirectory.

Richard W.M. Jones rjones at redhat.com
Mon Oct 19 11:23:20 UTC 2009


-- 
Richard Jones, Virtualization Group, Red Hat http://people.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 945b6e0a085611b45b2ab0752a66e6e60b21666c Mon Sep 17 00:00:00 2001
From: Richard Jones <rjones at redhat.com>
Date: Mon, 19 Oct 2009 10:18:46 +0100
Subject: [PATCH 2/5] Move virt tools (virt-cat, virt-edit etc) into tools/ subdirectory.

This moves the tool programs into a single directory:
  cat/* -> tools/virt-cat
  df/* -> tools/virt-df
  edit/* -> tools/virt-edit
  rescue/* -> tools/virt-rescue

This in itself simplifies the build process because we only need
one Makefile and one copy of 'run-locally'.

'run-*-locally' has become just 'run-locally' and takes an extra
parameter which is the name of the tool, eg:
  run-locally cat [virt-cat params...]

virt-inspector stays in its own directory, because this contains
more than just a single Perl script.
---
 .gitignore                |    5 +-
 HACKING                   |   18 +--
 Makefile.am               |   17 +--
 cat/Makefile.am           |   45 ------
 cat/run-cat-locally       |   52 -------
 cat/virt-cat              |  194 ------------------------
 configure.ac              |   25 +---
 df/Makefile.am            |   45 ------
 df/run-df-locally         |   52 -------
 df/virt-df                |  366 ---------------------------------------------
 edit/Makefile.am          |   45 ------
 edit/run-edit-locally     |   52 -------
 edit/virt-edit            |  210 --------------------------
 po/POTFILES.in            |    8 +-
 rescue/Makefile.am        |   45 ------
 rescue/run-rescue-locally |   53 -------
 rescue/virt-rescue        |  169 ---------------------
 tools/Makefile.am         |   50 ++++++
 tools/run-locally         |   56 +++++++
 tools/virt-cat            |  194 ++++++++++++++++++++++++
 tools/virt-df             |  366 +++++++++++++++++++++++++++++++++++++++++++++
 tools/virt-edit           |  210 ++++++++++++++++++++++++++
 tools/virt-rescue         |  169 +++++++++++++++++++++
 23 files changed, 1066 insertions(+), 1380 deletions(-)
 delete mode 100644 cat/Makefile.am
 delete mode 100755 cat/run-cat-locally
 delete mode 100755 cat/virt-cat
 delete mode 100644 df/Makefile.am
 delete mode 100755 df/run-df-locally
 delete mode 100755 df/virt-df
 delete mode 100644 edit/Makefile.am
 delete mode 100755 edit/run-edit-locally
 delete mode 100755 edit/virt-edit
 delete mode 100644 rescue/Makefile.am
 delete mode 100755 rescue/run-rescue-locally
 delete mode 100755 rescue/virt-rescue
 create mode 100644 tools/Makefile.am
 create mode 100755 tools/run-locally
 create mode 100755 tools/virt-cat
 create mode 100755 tools/virt-df
 create mode 100755 tools/virt-edit
 create mode 100755 tools/virt-rescue

diff --git a/.gitignore b/.gitignore
index 508f13a..4467a63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,7 +23,6 @@ capitests/test*.img
 capitests/tests
 capitests/tests.c
 capitests/test*.tmp
-cat/virt-cat.1
 ChangeLog
 *.class
 *.cma
@@ -47,8 +46,6 @@ daemon/names.c
 daemon/stubs.c
 depcomp
 .deps
-df/virt-df.1
-edit/virt-edit.1
 emptydisk
 examples/hello
 examples/to-xml
@@ -179,7 +176,6 @@ python/guestfs.py
 python/guestfs-py.c
 python/guestfs.pyc
 regressions/test1.img
-rescue/virt-rescue.1
 ruby/bindtests.rb
 ruby/ext/guestfs/extconf.h
 ruby/ext/guestfs/_guestfs.c
@@ -201,6 +197,7 @@ stamp-h1
 test-tool/libguestfs-test-tool.1
 test-tool/libguestfs-test-tool
 test-tool/libguestfs-test-tool-helper
+tools/virt-*.1
 /GNUmakefile
 /maint.mk
 /build-aux
diff --git a/HACKING b/HACKING
index bdb8287..ca5b9a9 100644
--- a/HACKING
+++ b/HACKING
@@ -68,9 +68,6 @@ Directories
 appliance/
         The qemu appliance, build scripts and so on.
 
-cat/
-        The virt-cat tool.
-
 capitests/
         Automated tests of the C API.
 
@@ -80,12 +77,6 @@ contrib/
 daemon/
         The daemon that runs inside the guest and carries out actions.
 
-df/
-        The virt-df tool.
-
-edit/
-        The virt-edit tool.
-
 examples/
         The examples.
 
@@ -125,12 +116,15 @@ python/
 regressions/
         Regression tests.
 
-rescue/
-        The virt-rescue tool.
-
 ruby/
         Ruby bindings.
 
+tools/
+	Command line tools like virt-cat, virt-df, virt-edit and more.
+	In versions <= 1.0.73 these were all in separate directories
+	like cat/, df/, edit/, but since then we moved them all into
+	one directory to simplify builds.
+
 src/
         Source code to the C library.
         Also contains the crucial generator program.
diff --git a/Makefile.am b/Makefile.am
index c4a84f7..73d4f63 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -26,9 +26,14 @@ SUBDIRS = gnulib/lib src daemon appliance fish po examples images \
 if HAVE_PERL
 SUBDIRS += perl
 endif
+
 if HAVE_INSPECTOR
 SUBDIRS += inspector
 endif
+if HAVE_TOOLS
+SUBDIRS += tools
+endif
+
 if HAVE_OCAML
 SUBDIRS += ocaml ocaml/examples
 endif
@@ -44,18 +49,6 @@ endif
 if HAVE_HASKELL
 SUBDIRS += haskell
 endif
-if HAVE_DF
-SUBDIRS += df
-endif
-if HAVE_CAT
-SUBDIRS += cat
-endif
-if HAVE_RESCUE
-SUBDIRS += rescue
-endif
-if HAVE_EDIT
-SUBDIRS += edit
-endif
 
 EXTRA_DIST = \
 	guestfs.pod guestfs-actions.pod guestfs-structs.pod \
diff --git a/cat/Makefile.am b/cat/Makefile.am
deleted file mode 100644
index 6b9a1bb..0000000
--- a/cat/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# libguestfs 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.
-
-EXTRA_DIST = \
-	run-cat-locally \
-	virt-cat
-
-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
-	$(POD2MAN) \
-	  --section 1 \
-	  -c "Virtualization Support" \
-	  --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
-	  $< > $@-t && mv $@-t $@
-
-$(top_builddir)/html/virt-cat.1.html: virt-cat
-	mkdir -p $(top_builddir)/html
-	cd $(top_builddir) && pod2html \
-	  --css 'pod.css' \
-	  --title 'virt-cat, display a file in a virtual machine' \
-	  --htmldir html \
-	  --outfile html/virt-cat.1.html \
-	  cat/$<
-
-endif
diff --git a/cat/run-cat-locally b/cat/run-cat-locally
deleted file mode 100755
index 7c31aaf..0000000
--- a/cat/run-cat-locally
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/perl
-# 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.
-
-# This script sets up the environment so you can run virt-cat in place
-# without needing to do 'make install' first. You can also run virt-cat
-# by creating a symlink to this script and putting it in your path.
-#
-# Use it like this:
-#   ./run-cat-locally [usual virt-cat args ...]
-
-use strict;
-use warnings;
-
-use File::Basename qw(dirname);
-use File::Spec;
-use Cwd qw(abs_path);
-
-my $path = $0;
-
-# Follow symlinks until we get to the real file
-while(-l $path) {
-    my $link = readlink($path) or die "readlink: $path: $!";
-    if(File::Spec->file_name_is_absolute($link)) {
-        $path = $link;
-    } else {
-        $path = File::Spec->catfile(dirname($path), $link);
-    }
-}
-
-# Get the absolute path of the parent directory
-$path = abs_path(dirname($path).'/..');
-
-$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
-$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
-$ENV{PERL5LIB}        = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
-
-exec('perl', $path.'/cat/virt-cat', @ARGV);
diff --git a/cat/virt-cat b/cat/virt-cat
deleted file mode 100755
index 329ba6e..0000000
--- a/cat/virt-cat
+++ /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/configure.ac b/configure.ac
index 2d4cd33..ab42561 100644
--- a/configure.ac
+++ b/configure.ac
@@ -675,18 +675,12 @@ for pm in Pod::Usage Getopt::Long Sys::Virt Data::Dumper XML::Writer Locale::Tex
     fi
 done
 if test "x$missing_perl_modules" = "xyes"; then
-    AC_MSG_WARN([some Perl modules required to compile virt-cat, virt-df, virt-edit, virt-inspector and virt-rescue are missing])
+    AC_MSG_WARN([some Perl modules required to compile virt-inspector and the other virt-* tools are missing])
 fi
 
-AM_CONDITIONAL([HAVE_CAT],
-    [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes"])
-AM_CONDITIONAL([HAVE_DF],
-    [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes"])
-AM_CONDITIONAL([HAVE_EDIT],
-    [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes"])
 AM_CONDITIONAL([HAVE_INSPECTOR],
     [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes"])
-AM_CONDITIONAL([HAVE_RESCUE],
+AM_CONDITIONAL([HAVE_TOOLS],
     [test "x$PERL" != "xno" -a "x$missing_perl_modules" != "xyes"])
 
 dnl Library versioning.
@@ -723,11 +717,8 @@ AC_CONFIG_FILES([Makefile
                  ruby/Makefile ruby/Rakefile
                  java/Makefile
                  haskell/Makefile
-                 cat/Makefile
-                 df/Makefile
-                 edit/Makefile
                  inspector/Makefile
-                 rescue/Makefile
+                 tools/Makefile
                  libguestfs.pc
                  gnulib/lib/Makefile
                  gnulib/tests/Makefile
@@ -755,16 +746,10 @@ echo -n "Java bindings ....................... "
 if test "x$HAVE_JAVA_TRUE" = "x"; then echo "yes"; else echo "no"; fi
 echo -n "Haskell bindings .................... "
 if test "x$HAVE_HASKELL" = "x"; then echo "yes"; else echo "no"; fi
-echo -n "virt-cat ............................ "
-if test "x$HAVE_CAT" = "x"; then echo "yes"; else echo "no"; fi
-echo -n "virt-df ............................. "
-if test "x$HAVE_DF" = "x"; then echo "yes"; else echo "no"; fi
-echo -n "virt-edit ........................... "
-if test "x$HAVE_EDIT" = "x"; then echo "yes"; else echo "no"; fi
 echo -n "virt-inspector ...................... "
 if test "x$HAVE_INSPECTOR" = "x"; then echo "yes"; else echo "no"; fi
-echo -n "virt-rescue ......................... "
-if test "x$HAVE_RESCUE" = "x"; then echo "yes"; else echo "no"; fi
+echo -n "virt-* tools ........................ "
+if test "x$HAVE_TOOLS" = "x"; then echo "yes"; else echo "no"; fi
 echo "supermin appliance .................. $enable_supermin"
 echo
 echo "If any optional component is configured 'no' when you expected 'yes'"
diff --git a/df/Makefile.am b/df/Makefile.am
deleted file mode 100644
index f333f97..0000000
--- a/df/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# libguestfs 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.
-
-EXTRA_DIST = \
-	run-df-locally \
-	virt-df
-
-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
-	$(POD2MAN) \
-	  --section 1 \
-	  -c "Virtualization Support" \
-	  --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
-	  $< > $@-t && mv $@-t $@
-
-$(top_builddir)/html/virt-df.1.html: virt-df
-	mkdir -p $(top_builddir)/html
-	cd $(top_builddir) && pod2html \
-	  --css 'pod.css' \
-	  --title 'virt-df, display free space on virtual filesystems' \
-	  --htmldir html \
-	  --outfile html/virt-df.1.html \
-	  df/$<
-
-endif
diff --git a/df/run-df-locally b/df/run-df-locally
deleted file mode 100755
index 94697b0..0000000
--- a/df/run-df-locally
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/perl
-# 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.
-
-# This script sets up the environment so you can run virt-df in place
-# without needing to do 'make install' first. You can also run virt-df
-# by creating a symlink to this script and putting it in your path.
-#
-# Use it like this:
-#   ./run-df-locally [usual virt-df args ...]
-
-use strict;
-use warnings;
-
-use File::Basename qw(dirname);
-use File::Spec;
-use Cwd qw(abs_path);
-
-my $path = $0;
-
-# Follow symlinks until we get to the real file
-while(-l $path) {
-    my $link = readlink($path) or die "readlink: $path: $!";
-    if(File::Spec->file_name_is_absolute($link)) {
-        $path = $link;
-    } else {
-        $path = File::Spec->catfile(dirname($path), $link);
-    }
-}
-
-# Get the absolute path of the parent directory
-$path = abs_path(dirname($path).'/..');
-
-$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
-$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
-$ENV{PERL5LIB}        = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
-
-exec('perl', $path.'/df/virt-df', @ARGV);
diff --git a/df/virt-df b/df/virt-df
deleted file mode 100755
index 78eb25c..0000000
--- a/df/virt-df
+++ /dev/null
@@ -1,366 +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, but
-read L</NOTE ABOUT CSV FORMAT> below.
-
-=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 NOTE ABOUT CSV FORMAT
-
-Comma-separated values (CSV) is a deceptive format.  It I<seems> like
-it should be easy to parse, but it is definitely not easy to parse.
-
-Myth: Just split fields at commas.  Reality: This does I<not> work
-reliably.  This example has two columns:
-
- "foo,bar",baz
-
-Myth: Read the file one line at a time.  Reality: This does I<not>
-work reliably.  This example has one row:
-
- "foo
- bar",baz
-
-For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
-also packaged in major Linux distributions).
-
-For other languages, use a CSV processing library (eg. C<Text::CSV>
-for Perl or Python's built-in csv library).
-
-Most spreadsheets and databases can import CSV directly.
-
-=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
deleted file mode 100644
index 6afdd62..0000000
--- a/edit/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# libguestfs 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.
-
-EXTRA_DIST = \
-	run-edit-locally \
-	virt-edit
-
-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
-	$(POD2MAN) \
-	  --section 1 \
-	  -c "Virtualization Support" \
-	  --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
-	  $< > $@-t && mv $@-t $@
-
-$(top_builddir)/html/virt-edit.1.html: virt-edit
-	mkdir -p $(top_builddir)/html
-	cd $(top_builddir) && pod2html \
-	  --css 'pod.css' \
-	  --title 'virt-edit, edit a file in a virtual machine' \
-	  --htmldir html \
-	  --outfile html/virt-edit.1.html \
-	  edit/$<
-
-endif
diff --git a/edit/run-edit-locally b/edit/run-edit-locally
deleted file mode 100755
index 127463f..0000000
--- a/edit/run-edit-locally
+++ /dev/null
@@ -1,52 +0,0 @@
-#!/usr/bin/perl
-# 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.
-
-# This script sets up the environment so you can run virt-edit in place
-# without needing to do 'make install' first. You can also run virt-edit
-# by creating a symlink to this script and putting it in your path.
-#
-# Use it like this:
-#   ./run-edit-locally [usual virt-edit args ...]
-
-use strict;
-use warnings;
-
-use File::Basename qw(dirname);
-use File::Spec;
-use Cwd qw(abs_path);
-
-my $path = $0;
-
-# Follow symlinks until we get to the real file
-while(-l $path) {
-    my $link = readlink($path) or die "readlink: $path: $!";
-    if(File::Spec->file_name_is_absolute($link)) {
-        $path = $link;
-    } else {
-        $path = File::Spec->catfile(dirname($path), $link);
-    }
-}
-
-# Get the absolute path of the parent directory
-$path = abs_path(dirname($path).'/..');
-
-$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
-$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
-$ENV{PERL5LIB}        = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
-
-exec('perl', $path.'/edit/virt-edit', @ARGV);
diff --git a/edit/virt-edit b/edit/virt-edit
deleted file mode 100755
index 46e86a1..0000000
--- a/edit/virt-edit
+++ /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/po/POTFILES.in b/po/POTFILES.in
index 7ccadcf..b99493b 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,4 +1,3 @@
-cat/virt-cat
 daemon/augeas.c
 daemon/blockdev.c
 daemon/checksum.c
@@ -55,8 +54,6 @@ daemon/wc.c
 daemon/xattr.c
 daemon/zero.c
 daemon/zerofree.c
-df/virt-df
-edit/virt-edit
 fish/alloc.c
 fish/cmds.c
 fish/completion.c
@@ -81,10 +78,13 @@ perl/lib/Sys/Guestfs.pm
 perl/lib/Sys/Guestfs/Lib.pm
 python/guestfs-py.c
 regressions/test-noexec-stack.pl
-rescue/virt-rescue
 ruby/ext/guestfs/_guestfs.c
 src/guestfs-actions.c
 src/guestfs-bindtests.c
 src/guestfs.c
 test-tool/helper.c
 test-tool/test-tool.c
+tools/virt-cat
+tools/virt-df
+tools/virt-edit
+tools/virt-rescue
diff --git a/rescue/Makefile.am b/rescue/Makefile.am
deleted file mode 100644
index b532e25..0000000
--- a/rescue/Makefile.am
+++ /dev/null
@@ -1,45 +0,0 @@
-# libguestfs 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.
-
-EXTRA_DIST = \
-	run-rescue-locally \
-	virt-rescue
-
-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
-	$(POD2MAN) \
-	  --section 1 \
-	  -c "Virtualization Support" \
-	  --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
-	  $< > $@-t && mv $@-t $@
-
-$(top_builddir)/html/virt-rescue.1.html: virt-rescue
-	mkdir -p $(top_builddir)/html
-	cd $(top_builddir) && pod2html \
-	  --css 'pod.css' \
-	  --title 'virt-rescue, run a rescue shell on a virtual machine' \
-	  --htmldir html \
-	  --outfile html/virt-rescue.1.html \
-	  rescue/$<
-
-endif
diff --git a/rescue/run-rescue-locally b/rescue/run-rescue-locally
deleted file mode 100755
index 18097cf..0000000
--- a/rescue/run-rescue-locally
+++ /dev/null
@@ -1,53 +0,0 @@
-#!/usr/bin/perl
-# 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.
-
-# This script sets up the environment so you can run virt-rescue in
-# place without needing to do 'make install' first. You can also run
-# virt-rescue by creating a symlink to this script and putting it in
-# your path.
-#
-# Use it like this:
-#   ./run-rescue-locally [usual virt-rescue args ...]
-
-use strict;
-use warnings;
-
-use File::Basename qw(dirname);
-use File::Spec;
-use Cwd qw(abs_path);
-
-my $path = $0;
-
-# Follow symlinks until we get to the real file
-while(-l $path) {
-    my $link = readlink($path) or die "readlink: $path: $!";
-    if(File::Spec->file_name_is_absolute($link)) {
-        $path = $link;
-    } else {
-        $path = File::Spec->catfile(dirname($path), $link);
-    }
-}
-
-# Get the absolute path of the parent directory
-$path = abs_path(dirname($path).'/..');
-
-$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
-$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
-$ENV{PERL5LIB}        = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
-
-exec('perl', $path.'/rescue/virt-rescue', @ARGV);
diff --git a/rescue/virt-rescue b/rescue/virt-rescue
deleted file mode 100755
index 9ad2fa4..0000000
--- a/rescue/virt-rescue
+++ /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.
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..d5fc23c
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,50 @@
+# libguestfs virt-* tools
+# 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.
+
+tools = cat df edit rescue
+
+EXTRA_DIST = \
+	run-locally \
+	$(tools:%=virt-%)
+
+if HAVE_TOOLS
+
+bin_SCRIPTS = $(tools:%=virt-%)
+
+# XXX Bug in automake?  If you list virt-cat.1 explicitly, then it
+# builds and installs the man pages.  However if this is removed,
+# then the man pages are neither built nor installed.
+man_MANS = virt-cat.1 $(patsubst %,virt-%.1,$(filter-out cat,$(tools)))
+
+noinst_DATA = $(tools:%=$(top_builddir)/html/virt-%.1.html)
+
+virt-%.1: virt-%
+	$(POD2MAN) \
+	  --section 1 \
+	  -c "Virtualization Support" \
+	  --release "$(PACKAGE_NAME)-$(PACKAGE_VERSION)" \
+	  $< > $@-t && mv $@-t $@
+
+$(top_builddir)/html/virt-%.1.html: virt-%
+	mkdir -p $(top_builddir)/html
+	cd $(top_builddir) && pod2html \
+	  --css 'pod.css' \
+	  --htmldir html \
+	  --outfile html/$<.1.html \
+	  tools/$<
+
+endif
diff --git a/tools/run-locally b/tools/run-locally
new file mode 100755
index 0000000..0bf1c0a
--- /dev/null
+++ b/tools/run-locally
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+# Copyright (C) 2009 Red Hat Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# This script sets up the environment so you can run virt-* tools in
+# place without needing to do 'make install' first. You can also run
+# the tools by creating a symlink to this script and putting it in
+# your path.
+#
+# Use it like this:
+#   ./run-locally tool [usual virt-tool args ...]
+# eg:
+#   ./run-locally cat domname /etc/passwd
+
+use strict;
+use warnings;
+
+use File::Basename qw(dirname);
+use File::Spec;
+use Cwd qw(abs_path);
+
+my $path = $0;
+my $tool = shift @ARGV;
+
+# Follow symlinks until we get to the real file
+while(-l $path) {
+    my $link = readlink($path) or die "readlink: $path: $!";
+    if(File::Spec->file_name_is_absolute($link)) {
+        $path = $link;
+    } else {
+        $path = File::Spec->catfile(dirname($path), $link);
+    }
+}
+
+# Get the absolute path of the parent directory
+$path = abs_path(dirname($path).'/..');
+
+$ENV{LD_LIBRARY_PATH} = $path.'/src/.libs';
+$ENV{LIBGUESTFS_PATH} = $path.'/appliance';
+$ENV{PERL5LIB}        = $path.'/perl/blib/lib:'.$path.'/perl/blib/arch';
+
+print (join " ", ("$path/tools/virt-$tool", @ARGV), "\n");
+exec('perl', "$path/tools/virt-$tool", @ARGV);
diff --git a/tools/virt-cat b/tools/virt-cat
new file mode 100755
index 0000000..329ba6e
--- /dev/null
+++ b/tools/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/tools/virt-df b/tools/virt-df
new file mode 100755
index 0000000..78eb25c
--- /dev/null
+++ b/tools/virt-df
@@ -0,0 +1,366 @@
+#!/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, but
+read L</NOTE ABOUT CSV FORMAT> below.
+
+=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 NOTE ABOUT CSV FORMAT
+
+Comma-separated values (CSV) is a deceptive format.  It I<seems> like
+it should be easy to parse, but it is definitely not easy to parse.
+
+Myth: Just split fields at commas.  Reality: This does I<not> work
+reliably.  This example has two columns:
+
+ "foo,bar",baz
+
+Myth: Read the file one line at a time.  Reality: This does I<not>
+work reliably.  This example has one row:
+
+ "foo
+ bar",baz
+
+For shell scripts, use C<csvtool> (L<http://merjis.com/developers/csv>
+also packaged in major Linux distributions).
+
+For other languages, use a CSV processing library (eg. C<Text::CSV>
+for Perl or Python's built-in csv library).
+
+Most spreadsheets and databases can import CSV directly.
+
+=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/tools/virt-edit b/tools/virt-edit
new file mode 100755
index 0000000..46e86a1
--- /dev/null
+++ b/tools/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/tools/virt-rescue b/tools/virt-rescue
new file mode 100755
index 0000000..9ad2fa4
--- /dev/null
+++ b/tools/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.
-- 
1.6.5.rc2



More information about the Libguestfs mailing list