daemon: debug segv correct use of dereferencing NULL.
[libguestfs.git] / tools / virt-resize
diff --git a/tools/virt-resize b/tools/virt-resize
deleted file mode 100755 (executable)
index 1e8a6c7..0000000
+++ /dev/null
@@ -1,1526 +0,0 @@
-#!/usr/bin/perl -w
-# virt-resize
-# Copyright (C) 2010 Red Hat Inc.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-use warnings;
-use strict;
-
-use Sys::Guestfs;
-use Sys::Guestfs::Lib qw(feature_available);
-use Fcntl qw(S_ISREG SEEK_SET);
-use POSIX qw(floor);
-use Pod::Usage;
-use Getopt::Long;
-use Data::Dumper;
-use Locale::TextDomain 'libguestfs';
-
-$Data::Dumper::Sortkeys = 1;
-
-die __"virt-resize: sorry this program does not work on a 32 bit host\n"
-    if ~1 == 4294967294;
-
-$| = 1;
-
-=encoding utf8
-
-=head1 NAME
-
-virt-resize - Resize a virtual machine disk
-
-=head1 SYNOPSIS
-
- virt-resize [--resize /dev/sdaN=[+/-]<size>[%]]
-   [--expand /dev/sdaN] [--shrink /dev/sdaN]
-   [--ignore /dev/sdaN] [--delete /dev/sdaN] [...] indisk outdisk
-
-=head1 DESCRIPTION
-
-Virt-resize is a tool which can resize a virtual machine disk, making
-it larger or smaller overall, and resizing or deleting any partitions
-contained within.
-
-Virt-resize B<cannot> resize disk images in-place.  Virt-resize
-B<should not> be used on live virtual machines - for consistent
-results, shut the virtual machine down before resizing it.
-
-If you are not familiar with the associated tools:
-L<virt-filesystems(1)> and L<virt-df(1)>, we recommend you go and read
-those manual pages first.
-
-=head1 EXAMPLES
-
-Copy C<olddisk> to C<newdisk>, extending one of the guest's partitions
-to fill the extra 5GB of space.
-
- truncate -r olddisk newdisk; truncate -s +5G newdisk
- virt-filesystems --long --h --all -a olddisk
- # Note "/dev/sda2" is a partition inside the "olddisk" file.
- virt-resize --expand /dev/sda2 olddisk newdisk
-
-As above, but make the /boot partition 200MB bigger, while giving the
-remaining space to /dev/sda2:
-
- virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 olddisk newdisk
-
-As above, but the output format will be uncompressed qcow2:
-
- qemu-img create -f qcow2 newdisk.qcow2 15G
- virt-resize --expand /dev/sda2 olddisk newdisk.qcow2
-
-=head1 DETAILED USAGE
-
-=head2 EXPANDING A VIRTUAL MACHINE DISK
-
-=over 4
-
-=item 1. Shut down the virtual machine
-
-=item 2. Locate input disk image
-
-Locate the input disk image (ie. the file or device on the host
-containing the guest's disk).  If the guest is managed by libvirt, you
-can use C<virsh dumpxml> like this to find the disk image name:
-
- # virsh dumpxml guestname | xpath /domain/devices/disk/source
- Found 1 nodes:
- -- NODE --
- <source dev="/dev/vg/lv_guest" />
-
-=item 3. Look at current sizing
-
-Use L<virt-filesystems(1)> to display the current partitions and
-sizes:
-
- # virt-filesystems --long --parts --blkdevs -h -a /dev/vg/lv_guest
- Name       Type       Size  Parent
- /dev/sda1  partition  101M  /dev/sda
- /dev/sda2  partition  7.9G  /dev/sda
- /dev/sda   device     8.0G  -
-
-(This example is a virtual machine with an 8 GB disk which we would
-like to expand up to 10 GB).
-
-=item 4. Create output disk
-
-Virt-resize cannot do in-place disk modifications.  You have to have
-space to store the resized output disk.
-
-To store the resized disk image in a file, create a file of a suitable
-size:
-
- # rm -f outdisk
- # truncate -s 10G outdisk
-
-Or use L<lvcreate(1)> to create a logical volume:
-
- # lvcreate -L 10G -n lv_name vg_name
-
-Or use L<virsh(1)> vol-create-as to create a libvirt storage volume:
-
- # virsh pool-list
- # virsh vol-create-as poolname newvol 10G
-
-=item 5. Resize
-
-virt-resize takes two mandatory parameters, the input disk (eg. device
-or file) and the output disk.  The output disk is the one created in
-the previous step.
-
- # virt-resize indisk outdisk
-
-This command just copies disk image C<indisk> to disk image C<outdisk>
-I<without> resizing or changing any existing partitions.  If
-C<outdisk> is larger, then an extra, empty partition is created at the
-end of the disk covering the extra space.  If C<outdisk> is smaller,
-then it will give an error.
-
-More realistically you'd want to expand existing partitions in the
-disk image by passing extra options (for the full list see the
-L</OPTIONS> section below).
-
-L</--expand> is the most useful option.  It expands the named
-partition within the disk to fill any extra space:
-
- # virt-resize --expand /dev/sda2 indisk outdisk
-
-(In this case, an extra partition is I<not> created at the end of the
-disk, because there will be no unused space).
-
-L</--resize> is the other commonly used option.  The following would
-increase the size of /dev/sda1 by 200M, and expand /dev/sda2
-to fill the rest of the available space:
-
- # virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 \
-     indisk outdisk
-
-If the expanded partition in the image contains a filesystem or LVM
-PV, then if virt-resize knows how, it will resize the contents, the
-equivalent of calling a command such as L<pvresize(8)>,
-L<resize2fs(8)> or L<ntfsresize(8)>.  However virt-resize does not
-know how to resize some filesystems, so you would have to online
-resize them after booting the guest.  And virt-resize also does not
-resize anything inside an LVM PV, it just resizes the PV itself and
-leaves the user to resize any LVs inside that PV as desired.
-
-Other options are covered below.
-
-=item 6. Test
-
-Thoroughly test the new disk image I<before> discarding the old one.
-
-If you are using libvirt, edit the XML to point at the new disk:
-
- # virsh edit guestname
-
-Change E<lt>source ...E<gt>, see
-L<http://libvirt.org/formatdomain.html#elementsDisks>
-
-Then start up the domain with the new, resized disk:
-
- # virsh start guestname
-
-and check that it still works.  See also the L</NOTES> section below
-for additional information.
-
-=item 7. Resize LVs etc inside the guest
-
-(This can also be done offline using L<guestfish(1)>)
-
-Once the guest has booted you should see the new space available, at
-least for filesystems that virt-resize knows how to resize, and for
-PVs.  The user may need to resize LVs inside PVs, and also resize
-filesystem types that virt-resize does not know how to expand.
-
-=back
-
-=head2 SHRINKING A VIRTUAL MACHINE DISK
-
-Shrinking is somewhat more complex than expanding, and only an
-overview is given here.
-
-Firstly virt-resize will not attempt to shrink any partition content
-(PVs, filesystems).  The user has to shrink content before passing the
-disk image to virt-resize, and virt-resize will check that the content
-has been shrunk properly.
-
-(Shrinking can also be done offline using L<guestfish(1)>)
-
-After shrinking PVs and filesystems, shut down the guest, and proceed
-with steps 3 and 4 above to allocate a new disk image.
-
-Then run virt-resize with any of the C<--shrink> and/or C<--resize>
-options.
-
-=head2 IGNORING OR DELETING PARTITIONS
-
-virt-resize also gives a convenient way to ignore or delete partitions
-when copying from the input disk to the output disk.  Ignoring a
-partition speeds up the copy where you don't care about the existing
-contents of a partition.  Deleting a partition removes it completely,
-but note that it also renumbers any partitions after the one which is
-deleted, which can leave some guests unbootable.
-
-=head2 QCOW2 AND NON-SPARSE RAW FORMATS
-
-If the input disk is in qcow2 format, then you may prefer that the
-output is in qcow2 format as well.  Alternately, virt-resize can
-convert the format on the fly.  The output format is simply determined
-by the format of the empty output container that you provide.  Thus to
-create qcow2 output, use:
-
- qemu-img create [-c] -f qcow2 outdisk [size]
-
-instead of the truncate command (use C<-c> for a compressed disk).
-
-Similarly, to get non-sparse raw output use:
-
- fallocate -l size outdisk
-
-(on older systems that don't have the L<fallocate(1)> command use
-C<dd if=/dev/zero of=outdisk bs=1M count=..>)
-
-=head1 OPTIONS
-
-=over 4
-
-=cut
-
-my $help;
-
-=item B<--help>
-
-Display help.
-
-=cut
-
-my $version;
-
-=item B<--version>
-
-Display version number and exit.
-
-=cut
-
-my @resize;
-
-=item B<--resize part=size>
-
-Resize the named partition (expanding or shrinking it) so that it has
-the given size.
-
-C<size> can be expressed as an absolute number followed by
-b/K/M/G/T/P/E to mean bytes, Kilobytes, Megabytes, Gigabytes,
-Terabytes, Petabytes or Exabytes; or as a percentage of the current
-size; or as a relative number or percentage.  For example:
-
- --resize /dev/sda2=10G
-
- --resize /dev/sda4=90%
-
- --resize /dev/sda2=+1G
-
- --resize /dev/sda2=-200M
-
- --resize /dev/sda1=+128K
-
- --resize /dev/sda1=+10%
-
- --resize /dev/sda1=-10%
-
-You can increase the size of any partition.  Virt-resize will expand
-the direct content of the partition if it knows how (see C<--expand>
-below).
-
-You can only I<decrease> the size of partitions that contain
-filesystems or PVs which have already been shrunk.  Virt-resize will
-check this has been done before proceeding, or else will print an
-error (see also C<--resize-force>).
-
-You can give this option multiple times.
-
-=cut
-
-my @resize_force;
-
-=item B<--resize-force part=size>
-
-This is the same as C<--resize> except that it will let you decrease
-the size of any partition.  Generally this means you will lose any
-data which was at the end of the partition you shrink, but you may not
-care about that (eg. if shrinking an unused partition, or if you can
-easily recreate it such as a swap partition).
-
-See also the C<--ignore> option.
-
-=cut
-
-my $expand;
-
-=item B<--expand part>
-
-Expand the named partition so it uses up all extra space (space left
-over after any other resize changes that you request have been done).
-
-If virt-resize knows how, it will expand the direct content of the
-partition.  For example, if the partition is an LVM PV, it will expand
-the PV to fit (like calling L<pvresize(8)>).  Virt-resize leaves any
-other content it doesn't know about alone.
-
-Currently virt-resize can resize:
-
-=over 4
-
-=item *
-
-ext2, ext3 and ext4 filesystems when they are contained
-directly inside a partition.
-
-=item *
-
-NTFS filesystems contained directly in a partition, if libguestfs was
-compiled with support for NTFS.
-
-The filesystem must have been shut down consistently last time it was
-used.  Additionally, L<ntfsresize(8)> marks the resized filesystem as
-requiring a consistency check, so at the first boot after resizing
-Windows will check the disk.
-
-=item *
-
-LVM PVs (physical volumes).  However virt-resize does I<not>
-resize anything inside the PV.  The user will have to resize
-LVs as desired.
-
-=back
-
-Note that you cannot use C<--expand> and C<--shrink> together.
-
-=cut
-
-my $shrink;
-
-=item B<--shrink part>
-
-Shrink the named partition until the overall disk image fits in the
-destination.  The named partition B<must> contain a filesystem or PV
-which has already been shrunk using another tool (eg. L<guestfish(1)>
-or other online tools).  Virt-resize will check this and give an error
-if it has not been done.
-
-The amount by which the overall disk must be shrunk (after carrying
-out all other operations requested by the user) is called the
-"deficit".  For example, a straight copy (assume no other operations)
-from a 5GB disk image to a 4GB disk image results in a 1GB deficit.
-In this case, virt-resize would give an error unless the user
-specified a partition to shrink and that partition had more than a
-gigabyte of free space.
-
-Note that you cannot use C<--expand> and C<--shrink> together.
-
-=cut
-
-my @ignore;
-
-=item B<--ignore part>
-
-Ignore the named partition.  Effectively this means the partition is
-allocated on the destination disk, but the content is not copied
-across from the source disk.  The content of the partition will be
-blank (all zero bytes).
-
-You can give this option multiple times.
-
-=cut
-
-my @delete;
-
-=item B<--delete part>
-
-Delete the named partition.  It would be more accurate to describe
-this as "don't copy it over", since virt-resize doesn't do in-place
-changes and the original disk image is left intact.
-
-Note that when you delete a partition, then anything contained in the
-partition is also deleted.  Furthermore, this causes any partitions
-that come after to be I<renumbered>, which can easily make your guest
-unbootable.
-
-You can give this option multiple times.
-
-=cut
-
-my @lv_expand;
-
-=item B<--LV-expand logvol>
-
-This takes the logical volume and, as a final step, expands it to fill
-all the space available in its volume group.  A typical usage,
-assuming a Linux guest with a single PV C</dev/sda2> and a root device
-called C</dev/vg_guest/lv_root> would be:
-
- virt-resize indisk outdisk \
-   --expand /dev/sda2 --LV-expand /dev/vg_guest/lv_root
-
-This would first expand the partition (and PV), and then expand the
-root device to fill the extra space in the PV.
-
-The contents of the LV are also resized if virt-resize knows how to do
-that.  You can stop virt-resize from trying to expand the content by
-using the option C<--no-expand-content>.
-
-Use L<virt-filesystems(1)> to list the filesystems in
-the guest.
-
-You can give this option multiple times, I<but> it doesn't
-make sense to do this unless the logical volumes you specify
-are all in different volume groups.
-
-=cut
-
-my $copy_boot_loader = 1;
-
-=item B<--no-copy-boot-loader>
-
-By default, virt-resize copies over some sectors at the start of the
-disk (up to the beginning of the first partition).  Commonly these
-sectors contain the Master Boot Record (MBR) and the boot loader, and
-are required in order for the guest to boot correctly.
-
-If you specify this flag, then this initial copy is not done.  You may
-need to reinstall the boot loader in this case.
-
-=cut
-
-my $extra_partition = 1;
-my $min_extra_partition = 10 * 1024 * 1024; # see below
-
-=item B<--no-extra-partition>
-
-By default, virt-resize creates an extra partition if there is any
-extra, unused space after all resizing has happened.  Use this option
-to prevent the extra partition from being created.  If you do this
-then the extra space will be inaccessible until you run fdisk, parted,
-or some other partitioning tool in the guest.
-
-Note that if the surplus space is smaller than 10 MB, no extra
-partition will be created.
-
-=cut
-
-my $expand_content = 1;
-
-=item B<--no-expand-content>
-
-By default, virt-resize will try to expand the direct contents
-of partitions, if it knows how (see C<--expand> option above).
-
-If you give the C<--no-expand-content> option then virt-resize
-will not attempt this.
-
-=cut
-
-my $debug;
-
-=item B<-d> | B<--debug>
-
-Enable debugging messages.
-
-=cut
-
-my $dryrun;
-
-=item B<-n> | B<--dryrun>
-
-Print a summary of what would be done, but don't do anything.
-
-=cut
-
-my $quiet;
-
-=item B<-q> | B<--quiet>
-
-Don't print the summary.
-
-=cut
-
-my $format;
-
-=item B<--format> raw
-
-Specify the format of the input disk image.  If this flag is not
-given then it is auto-detected from the image itself.
-
-If working with untrusted raw-format guest disk images, you should
-ensure the format is always specified.
-
-Note that this option I<does not> affect the output format.
-See L</QCOW2 AND NON-SPARSE RAW FORMATS>.
-
-=cut
-
-my $output_format;
-
-=item B<--output-format> raw
-
-Specify the format of the output disk image.  If this flag is not
-given then it is auto-detected from the image itself.
-
-If working with untrusted raw-format guest disk images, you should
-ensure the format is always specified.
-
-Note that you still need to create the output disk with the right
-format.  See L</QCOW2 AND NON-SPARSE RAW FORMATS>.
-
-=back
-
-=cut
-
-GetOptions ("help|?" => \$help,
-            "version" => \$version,
-            "resize=s" => \@resize,
-            "resize-force=s" => \@resize_force,
-            "expand=s" => \$expand,
-            "shrink=s" => \$shrink,
-            "ignore=s" => \@ignore,
-            "delete=s" => \@delete,
-            "lv-expand=s" => \@lv_expand,
-            "copy-boot-loader!" => \$copy_boot_loader,
-            "extra-partition!" => \$extra_partition,
-            "expand-content!" => \$expand_content,
-            "d|debug" => \$debug,
-            "n|dryrun|dry-run" => \$dryrun,
-            "q|quiet" => \$quiet,
-            "format=s" => \$format,
-            "output-format=s" => \$output_format,
-    ) 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
-}
-
-die "virt-resize [--options] indisk outdisk\n" unless @ARGV == 2;
-
-# Check in and out images exist.
-my $infile = $ARGV[0];
-my $outfile = $ARGV[1];
-die __x("virt-resize: {file}: does not exist or is not readable\n", file => $infile)
-    unless -r $infile;
-die __x("virt-resize: {file}: does not exist or is not writable\nYou have to create the destination disk before running this program.\nPlease read the virt-resize(1) manpage for more information.\n", file => $outfile)
-    unless -w $outfile;
-
-# Add them to the handle and launch the appliance.
-my $g;
-launch_guestfs ();
-
-sub launch_guestfs
-{
-    $g = Sys::Guestfs->new ();
-    $g->set_trace (1) if $debug;
-    my @args = ($infile);
-    push @args, readonly => 1;
-    push @args, format => $format if defined $format;
-    $g->add_drive_opts (@args);
-    @args = ($outfile);
-    push @args, format => $output_format if defined $output_format;
-    $g->add_drive_opts (@args);
-    $g->set_progress_callback (\&progress_callback) unless $quiet;
-    $g->launch ();
-}
-
-my $sectsize = $g->blockdev_getss ("/dev/sdb");
-
-# Get the size in bytes of each disk.
-#
-# Originally we computed this by looking at the same of the host file,
-# but of course this failed for qcow2 images (RHBZ#633096).  The right
-# way to do it is with $g->blockdev_getsize64.
-my $insize = $g->blockdev_getsize64 ("/dev/sda");
-my $outsize = $g->blockdev_getsize64 ("/dev/sdb");
-
-if ($debug) {
-    print "$infile size $insize bytes\n";
-    print "$outfile size $outsize bytes\n";
-}
-
-# Create a partition table.
-#
-# We *must* do this before copying the bootloader across, and copying
-# the bootloader must be careful not to disturb this partition table
-# (RHBZ#633766).  There are two reasons for this:
-#
-# (1) The 'parted' library is stupid and broken.  In many ways.  In
-# this particular instance the stupid and broken bit is that it
-# overwrites the whole boot sector when initializating a partition
-# table.  (Upstream don't consider this obvious problem to be a bug).
-#
-# (2) GPT has a backup partition table located at the end of the disk.
-# It's non-movable, because the primary GPT contains fixed references
-# to both the size of the disk and the backup partition table at the
-# end.  This would be a problem for any resize that didn't either
-# carefully move the backup GPT (and rewrite those references) or
-# recreate the whole partition table from scratch.
-
-my $parttype;
-create_partition_table ();
-
-sub create_partition_table
-{
-    local $_;
-
-    $parttype = $g->part_get_parttype ("/dev/sda");
-    print "partition table type: $parttype\n" if $debug;
-
-    $g->part_init ("/dev/sdb", $parttype);
-}
-
-# In reality the number of sectors containing boot loader data will be
-# less than this (although Windows 7 defaults to putting the first
-# partition on sector 2048, and has quite a large boot loader).
-#
-# However make this large enough to be sure that we have copied over
-# the boot loader.  We could also do this by looking for the sector
-# offset of the first partition.
-#
-# It doesn't matter if we copy too much.
-my $max_bootloader = 4096 * 512;
-
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
-        file => $infile, sz => $insize)
-    if $insize < $max_bootloader;
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
-        file => $outfile, sz => $outsize)
-    if $outsize < $max_bootloader;
-
-# Copy the boot loader across.
-do_copy_boot_loader () if $copy_boot_loader;
-
-sub do_copy_boot_loader
-{
-    print "copying boot loader ...\n" if $debug;
-
-    # Don't disturb the partition table that we just wrote.
-    # https://secure.wikimedia.org/wikipedia/en/wiki/Master_Boot_Record
-    # https://secure.wikimedia.org/wikipedia/en/wiki/GUID_Partition_Table
-
-    my $bootsect = $g->pread_device ("/dev/sda", 446, 0);
-    die __"virt-resize: short read" if length ($bootsect) < 446;
-
-    $g->pwrite_device ("/dev/sdb", $bootsect, 0);
-
-    my $start = 512;
-    if ($parttype eq "gpt") {
-        # XXX With 4K sectors does GPT just fit more entries in a
-        # sector, or does it always use 34 sectors?
-        $start = 17408;
-    }
-
-    my $loader = $g->pread_device ("/dev/sda", $max_bootloader, $start);
-    die __"virt-resize: short read" if length ($loader) < $max_bootloader;
-
-    $g->pwrite_device ("/dev/sdb", $loader, $start);
-}
-
-my $to_be_expanded = 0;
-
-# Get the partitions on the source disk.
-my @partitions;
-my %partitions;
-check_source_disk ();
-
-sub check_source_disk
-{
-    local $_;
-
-    # Partitions and PVs.
-    my @p = $g->part_list ("/dev/sda");
-    foreach (@p) {
-        my $name = "/dev/sda" . $_->{part_num};
-        push @partitions, $name;
-
-        my %h = %$_;
-        $h{name} = $name;
-        $h{bootable} = $g->part_get_bootable ("/dev/sda", $h{part_num});
-        eval { $h{mbr_id} = $g->part_get_mbr_id ("/dev/sda", $h{part_num}); };
-        $partitions{$name} = \%h;
-    }
-}
-
-# Examine each partition.
-my @pvs_full = $g->pvs_full ();
-examine_partition ($_) foreach @partitions;
-
-sub examine_partition
-{
-    local $_;
-    my $part = shift;
-
-    # What is it?
-    my $type = "unknown";
-    eval {
-        $type = $g->vfs_type ($part);
-    };
-    $partitions{$part}->{type} = $type;
-
-    # Can we get the actual size of this object (ie. to find out if it
-    # is smaller than the container for shrinking)?
-    my $fssize;
-    if ($type eq "LVM2_member") { # LVM PV
-        foreach (@pvs_full) {
-            $fssize = $_->{pv_size}
-              if canonicalize ($_->{pv_name}) eq $part;
-        }
-    } else {                    # Something mountable?
-        eval {
-            $g->mount_ro ($part, "/");
-
-            my %stat = $g->statvfs ("/");
-            $fssize = $stat{bsize} * $stat{blocks};
-        };
-
-        eval {
-            $g->umount_all ();
-        };
-    }
-
-    # This might be undef if we didn't successfully find the size.  In
-    # that case user won't be allowed to shrink this partition except
-    # by forcing it.
-    $partitions{$part}->{fssize} = $fssize;
-
-    # Is it partition content that we know how to expand?
-    $partitions{$part}->{can_expand_content} = 0;
-    if ($expand_content) {
-        if ($type eq "LVM2_member") {
-            $partitions{$part}->{can_expand_content} = 1;
-            $partitions{$part}->{expand_content_method} = "pvresize";
-        } elsif ($type =~ /^ext[234]$/) {
-            $partitions{$part}->{can_expand_content} = 1;
-            $partitions{$part}->{expand_content_method} = "resize2fs";
-        } elsif ($type eq "ntfs" && feature_available ($g, "ntfsprogs")) {
-            $partitions{$part}->{can_expand_content} = 1;
-            $partitions{$part}->{expand_content_method} = "ntfsresize";
-        }
-    }
-}
-
-if ($debug) {
-    print "partitions found: ", join (", ", @partitions), "\n";
-    foreach my $part (@partitions) {
-        print "$part:\n";
-        foreach (sort keys %{$partitions{$part}}) {
-            print("\t", $_, " = ",
-                  defined ($partitions{$part}->{$_})
-                  ? $partitions{$part}->{$_} : "undef",
-                  "\n");
-        }
-    }
-}
-
-# Examine the LVs (for --lv-expand option).
-my @lvs = $g->lvs ();
-my %lvs;
-examine_lv ($_) foreach @lvs;
-mark_lvs_to_expand ();
-
-sub examine_lv
-{
-    local $_ = shift;
-
-    $lvs{$_}->{name} = $_;
-
-    my $type = "unknown";
-    eval {
-        $type = $g->vfs_type ($_);
-    };
-    $lvs{$_}->{type} = $type;
-
-    if ($expand_content) {
-        if ($type =~ /^ext[234]$/) {
-            $lvs{$_}->{can_expand_content} = 1;
-            $lvs{$_}->{expand_content_method} = "resize2fs";
-        } elsif ($type eq "ntfs" && feature_available ($g, "ntfsprogs")) {
-            $lvs{$_}->{can_expand_content} = 1;
-            $lvs{$_}->{expand_content_method} = "ntfsresize";
-        }
-    }
-}
-
-sub mark_lvs_to_expand {
-    local $_;
-
-    foreach (@lv_expand) {
-        die __x("virt-resize: no logical volume called {n}\n",
-                n => $_)
-            unless exists $lvs{$_};
-
-        if ($lvs{$_}->{can_expand_content}) {
-            $lvs{$_}->{will_expand_content} = 1;
-            $to_be_expanded++;
-        }
-    }
-}
-
-sub find_partition
-{
-    local $_ = shift;
-    my $option = shift;
-
-    $_ = "/dev/$_" unless $_ =~ m{^/dev};
-    $_ = canonicalize ($_);
-
-    unless (exists $partitions{$_}) {
-        die __x("{p}: partition not found in the source disk image, when using the '{opt}' command line option\n",
-                p => $_,
-                opt => $option)
-    }
-
-    if ($partitions{$_}->{ignore}) {
-        die __x("{p}: partition ignored, you cannot use it in another command line argument\n",
-                p => $_)
-    }
-    if ($partitions{$_}->{delete}) {
-        die __x("{p}: partition deleted, you cannot use it in another command line argument\n",
-                p => $_)
-    }
-
-    return $_;
-}
-
-# Handle --ignore.
-do_ignore ($_) foreach @ignore;
-
-sub do_ignore
-{
-    local $_ = shift;
-    $_ = find_partition ($_, "--ignore");
-    $partitions{$_}->{ignore} = 1;
-}
-
-# Handle --delete.
-do_delete ($_) foreach @delete;
-
-sub do_delete
-{
-    local $_ = shift;
-    $_ = find_partition ($_, "--delete");
-    $partitions{$_}->{delete} = 1;
-}
-
-# Handle --resize and --resize-force.
-do_resize ($_, 0, "--resize") foreach @resize;
-do_resize ($_, 1, "--resize-force") foreach @resize_force;
-
-sub do_resize
-{
-    local $_ = shift;
-    my $force = shift;
-    my $option = shift;
-
-    # Argument is "part=size" ...
-    my ($part, $sizefield) = split /=/, $_, 2;
-    $part = find_partition ($part, $option);
-
-    if (exists $partitions{$part}->{newsize}) {
-        die __x("{p}: this partition has already been marked for resizing\n",
-                p => $part);
-    }
-
-    # Parse the size field.
-    my $oldsize = $partitions{$part}->{part_size};
-    my $newsize;
-    if (!defined ($sizefield) || $sizefield eq "") {
-        die __x("{p}: missing size field in {o} option\n",
-                p => $part, o => $option);
-    } elsif ($sizefield =~ /^([.\d]+)([bKMGTPE])$/) {
-        $newsize = sizebytes ($1, $2);
-    } elsif ($sizefield =~ /^\+([.\d]+)([bKMGTPE])$/) {
-        my $incr = sizebytes ($1, $2);
-        $newsize = $oldsize + $incr;
-    } elsif ($sizefield =~ /^-([.\d]+)([bKMGTPE])$/) {
-        my $decr = sizebytes ($1, $2);
-        $newsize = $oldsize - $decr;
-    } elsif ($sizefield =~ /^([.\d]+)%$/) {
-        $newsize = $oldsize * $1 / 100;
-    } elsif ($sizefield =~ /^\+([.\d]+)%$/) {
-        $newsize = $oldsize + $oldsize * $1 / 100;
-    } elsif ($sizefield =~ /^-([.\d]+)%$/) {
-        $newsize = $oldsize - $oldsize * $1 / 100;
-    } else {
-        die __x("{p}: {f}: cannot parse size field\n",
-                p => $part, f => $sizefield)
-    }
-
-    $newsize > 0 or
-        die __x("{p}: new size is zero or negative\n", p => $part);
-
-    mark_partition_for_resize ($part, $oldsize, $newsize, $force, $option);
-}
-
-sub mark_partition_for_resize
-{
-    local $_;
-    my $part = shift;
-    my $oldsize = shift;
-    my $newsize = shift;
-    my $force = shift;
-    my $option = shift;
-
-    # Do nothing if the size is the same.
-    return if $oldsize == $newsize;
-
-    my $bigger = $newsize > $oldsize;
-
-    # Check there is space to shrink this.
-    unless ($bigger || $force) {
-        if (! $partitions{$part}->{fssize} ||
-            $partitions{$part}->{fssize} > $newsize) {
-            die __x("{p}: cannot make this partition smaller because it contains a\nfilesystem, physical volume or other content that is larger than the new size.\nYou have to resize the content first, see virt-resize(1).\n",
-                    p => $part);
-        }
-    }
-
-    $partitions{$part}->{newsize} = $newsize;
-
-    if ($partitions{$part}->{can_expand_content} && $bigger) {
-        $partitions{$part}->{will_expand_content} = 1;
-        $to_be_expanded++;
-    }
-}
-
-# Handle --expand and --shrink.
-my $surplus;
-if (defined $expand && defined $shrink) {
-    die __"virt-resize: you cannot use options --expand and --shrink together\n"
-}
-if (defined $expand || defined $shrink) {
-    calculate_surplus ();
-
-    if ($debug) {
-        print "surplus before --expand or --shrink: $surplus (",
-          human_size ($surplus), ")\n";
-    }
-
-    do_expand () if $expand;
-    do_shrink () if $shrink;
-}
-
-# (Re-)calculate surplus after doing expand or shrink.
-calculate_surplus ();
-
-# Add up the total space required on the target so far, compared
-# to the size of the target.  We end up with a surplus or deficit.
-sub calculate_surplus
-{
-    local $_;
-
-    # We need some overhead for partitioning.  Worst case would be for
-    # EFI partitioning + massive per-partition alignment.
-    my $overhead = $sectsize * (
-        2 * 64 +                   # GPT start and end
-        (64 * (@partitions + 1))   # Maximum alignment
-        ) +
-        ($max_bootloader - 64 * 512); # boot loader
-
-    my $required = 0;
-    foreach (@partitions) {
-        if ($partitions{$_}->{newsize}) {
-            $required += $partitions{$_}->{newsize}
-        } else {
-            $required += $partitions{$_}->{part_size}
-        }
-    }
-
-    # Compare that to the actual target disk.
-    $surplus = $outsize - ($required + $overhead);
-}
-
-sub do_expand
-{
-    local $_;
-
-    unless ($surplus > 0) {
-        die __x("virt-resize: error: cannot use --expand when there is no surplus space to\nexpand into.  You need to make the target disk larger by at least {h}.\n",
-                h => human_size (-$surplus));
-    }
-
-    my $part = find_partition ($expand, "--expand");
-    my $oldsize = $partitions{$part}->{part_size};
-    mark_partition_for_resize ($part, $oldsize, $oldsize + $surplus,
-                               0, "--expand");
-}
-
-sub do_shrink
-{
-    local $_;
-
-    unless ($surplus < 0) {
-        die __"virt-resize: error: cannot use --shrink because there is no deficit\n(see 'deficit' in the virt-resize(1) man page)\n"
-    }
-
-    my $part = find_partition ($shrink, "--shrink");
-    my $oldsize = $partitions{$part}->{part_size};
-    mark_partition_for_resize ($part, $oldsize, $oldsize + $surplus,
-                               0, "--shrink");
-}
-
-# Print summary.
-print_summary () unless $quiet;
-
-sub print_summary
-{
-    local $_;
-    print __"Summary of changes:\n";
-
-    foreach my $part (@partitions) {
-        if ($partitions{$part}->{ignore}) {
-            print __x("{p}: partition will be ignored\n", p => $part);
-        } elsif ($partitions{$part}->{delete}) {
-            print __x("{p}: partition will be deleted\n", p => $part);
-        } elsif ($partitions{$part}->{newsize}) {
-            print __x("{p}: partition will be resized from {oldsize} to {newsize}\n",
-                      p => $part,
-                      oldsize => human_size ($partitions{$part}->{part_size}),
-                      newsize => human_size ($partitions{$part}->{newsize}));
-            if ($partitions{$part}->{will_expand_content}) {
-                print __x("{p}: content will be expanded using the '{meth}' method\n",
-                          p => $part,
-                          meth => $partitions{$part}->{expand_content_method});
-            }
-        } else {
-            print __x("{p}: partition will be left alone\n", p => $part);
-        }
-    }
-
-    foreach my $lv (@lv_expand) {
-        print __x("{n}: LV will be expanded to maximum size\n",
-                  n => $lv);
-    }
-
-    foreach my $lv (@lvs) {
-        if ($lvs{$lv}->{will_expand_content}) {
-            print __x("{n}: content will be expanded using the '{meth}' method\n",
-                      n => $lv,
-                      meth => $lvs{$lv}->{expand_content_method});
-        }
-    }
-
-    if ($surplus > 0) {
-        print __x("There is a surplus of {spl} bytes ({h}).\n",
-                  spl => $surplus,
-                  h => human_size ($surplus));
-        if ($extra_partition) {
-            if ($surplus >= $min_extra_partition) {
-                print __"An extra partition will be created for the surplus.\n";
-            } else {
-                print __"The surplus space is not large enough for an extra partition to be created\nand so it will just be ignored.\n";
-            }
-        } else {
-            print __"The surplus space will be ignored.  Run a partitioning program in the guest\nto partition this extra space if you want.\n";
-        }
-    } elsif ($surplus < 0) {
-        die __x("virt-resize: error: there is a deficit of {def} bytes ({h}).\nYou need to make the target disk larger by at least this amount,\nor adjust your resizing requests.\n",
-                def => -$surplus,
-                h => human_size (-$surplus));
-    }
-}
-
-exit 0 if $dryrun;
-
-# Repartition the target disk.
-my $nextpart = 1;
-repartition ();
-
-sub repartition
-{
-    local $_;
-
-    # Work out where to start the first partition.
-    die __"virt-resize: source disk does not have a first partition\n"
-        unless exists ($partitions{"/dev/sda1"});
-    my $start = $partitions{"/dev/sda1"}->{part_start} / $sectsize;
-
-    # Align to 64.
-    $start = ($start + 63) & ~63;
-
-    print "starting to partition from $start\n" if $debug;
-
-    # Create the new partitions.
-    foreach my $part (@partitions) {
-        unless ($partitions{$part}->{delete}) {
-            # Size in sectors.
-            my $size;
-            if ($partitions{$part}->{newsize}) {
-                $size = ($partitions{$part}->{newsize} + $sectsize - 1)
-                    / $sectsize;
-            } else {
-                $size = ($partitions{$part}->{part_size} + $sectsize - 1)
-                    / $sectsize;
-            }
-
-            # Create it.
-            my ($target, $end, $part_num) = add_partition ($start, $size);
-            $partitions{$part}->{target} = $target;
-
-            if ($partitions{$part}->{bootable}) {
-                $g->part_set_bootable ("/dev/sdb", $part_num, 1);
-            }
-
-            if ($partitions{$part}->{mbr_id}) {
-                $g->part_set_mbr_id ("/dev/sdb", $part_num,
-                                     $partitions{$part}->{mbr_id});
-            }
-
-            # Start of next partition + alignment.
-            $start = $end + 1;
-            $start = ($start + 63) & ~63;
-        }
-    }
-
-    # Create surplus partition.
-    if ($extra_partition && $surplus >= $min_extra_partition) {
-        add_partition ($start, $outsize / $sectsize - 64 - $start);
-    }
-}
-
-# Add a partition.
-sub add_partition
-{
-    local $_;
-    my $start = shift;
-    my $size = shift;
-
-    my ($target, $end, $part_num);
-
-    if ($nextpart <= 3 || $parttype ne "msdos") {
-        $target = "/dev/sdb$nextpart";
-        $end = $start + $size - 1;
-        $g->part_add ("/dev/sdb", "primary", $start, $end);
-        $part_num = $nextpart++;
-    } else {
-        if ($nextpart == 4) {
-            $g->part_add ("/dev/sdb", "extended", $start, -1);
-            $part_num = $nextpart++;
-            $start += 64;
-        }
-        $target = "/dev/sdb$nextpart";
-        $end = $start + $size - 1;
-        $g->part_add ("/dev/sdb", "logical", $start, $end);
-        $part_num = $nextpart++;
-    }
-
-    return ($target, $end, $part_num);
-}
-
-# Copy over the data.
-copy_data ();
-
-sub copy_data
-{
-    foreach my $part (@partitions)
-    {
-        unless ($partitions{$part}->{ignore}) {
-            my $target = $partitions{$part}->{target};
-            if ($target) {
-                my $oldsize = $partitions{$part}->{part_size};
-                my $newsize;
-                if ($partitions{$part}->{newsize}) {
-                    $newsize = $partitions{$part}->{newsize};
-                } else {
-                    $newsize = $partitions{$part}->{part_size};
-                }
-
-                if (!$quiet && !$debug) {
-                    print __x("Copying {p} ...\n", p => $part);
-                }
-
-                $g->copy_size ($part, $target,
-                               $newsize < $oldsize ? $newsize : $oldsize);
-            }
-        }
-    }
-}
-
-# After copying the data over we must shut down and restart the
-# appliance in order to expand the content.  The reason for this may
-# not be obvious, but it's because otherwise we'll have duplicate VGs
-# (the old VG(s) and the new VG(s)) which breaks LVM.
-#
-# The restart is only required if we're going to expand something.
-
-if ($to_be_expanded > 0) {
-    restart_appliance ();
-    expand_partitions ();
-    expand_lvs ();
-    expand_lvs_content ();
-}
-
-sub restart_appliance
-{
-    # Sync disk and exit.
-    $g->umount_all ();
-    $g->sync ();
-    undef $g;
-
-    $g = Sys::Guestfs->new ();
-    $g->set_trace (1) if $debug;
-    my @args = ($outfile);
-    push @args, format => $output_format if defined $output_format;
-    $g->add_drive_opts (@args);
-    $g->launch ();
-
-    # Target partitions have changed from /dev/sdb to /dev/sda,
-    # so change them.
-    foreach my $part (@partitions)
-    {
-        my $target = $partitions{$part}->{target};
-        if ($target) {
-            if ($target =~ m{/dev/(.)db(.*)}) {
-                $partitions{$part}->{target} = "/dev/$1da$2";
-            } else {
-                die "internal error: unexpected partition target: $target";
-            }
-        }
-    }
-}
-
-sub expand_partitions
-{
-    foreach my $part (@partitions)
-    {
-        unless ($partitions{$part}->{ignore}) {
-            my $target = $partitions{$part}->{target};
-            if ($target) {
-                # Expand if requested.
-                if ($partitions{$part}->{will_expand_content}) {
-                    if (!$quiet && !$debug) {
-                        print __x("Expanding {p} using the '{meth}' method\n",
-                                  p => $part,
-                                  meth => $partitions{$part}->{expand_content_method});
-                    }
-                    expand_target_partition ($part)
-                }
-            }
-        }
-    }
-}
-
-sub expand_target_partition
-{
-    local $_;
-    my $part = shift;
-
-    # Assertions.
-    die unless $part;
-    die unless $partitions{$part}->{can_expand_content};
-    die unless $partitions{$part}->{will_expand_content};
-    die unless $partitions{$part}->{expand_content_method};
-    die unless $partitions{$part}->{target};
-    die unless $expand_content;
-
-    my $target = $partitions{$part}->{target};
-    my $method = $partitions{$part}->{expand_content_method};
-    if ($method eq "pvresize") {
-        $g->pvresize ($target);
-    }
-    elsif ($method eq "resize2fs") {
-        $g->e2fsck_f ($target);
-        $g->resize2fs ($target);
-    }
-    elsif ($method eq "ntfsresize") {
-        $g->ntfsresize ($target);
-    }
-    else {
-        die "internal error: unknown method: $method";
-    }
-}
-
-sub expand_lvs
-{
-    local $_;
-
-    foreach (@lv_expand) {
-        $g->lvresize_free ($_, 100);
-    }
-}
-
-sub expand_lvs_content
-{
-    local $_;
-
-    foreach (@lvs) {
-        if ($lvs{$_}->{will_expand_content}) {
-            my $method = $lvs{$_}->{expand_content_method};
-            if (!$quiet && !$debug) {
-                print __x("Expanding {p} using the '{meth}' method\n",
-                          p => $_, meth => $method);
-                    }
-            if ($method eq "resize2fs") {
-                $g->e2fsck_f ($_);
-                $g->resize2fs ($_);
-            } elsif ($method eq "ntfsresize") {
-                $g->ntfsresize ($_);
-            } else {
-                die "internal error: unknown method: $method";
-            }
-        }
-    }
-}
-
-# Sync disk and exit.
-$g->umount_all ();
-$g->sync ();
-undef $g;
-
-exit 0;
-
-sub sizebytes
-{
-    local $_ = shift;
-    my $unit = shift;
-
-    $_ *= 1024 if $unit =~ /[KMGTPE]/;
-    $_ *= 1024 if $unit =~ /[MGTPE]/;
-    $_ *= 1024 if $unit =~ /[GTPE]/;
-    $_ *= 1024 if $unit =~ /[TPE]/;
-    $_ *= 1024 if $unit =~ /[PE]/;
-    $_ *= 1024 if $unit =~ /[E]/;
-
-    return floor($_);
-}
-
-# Convert a number of bytes to a human-readable number.
-sub human_size
-{
-    local $_ = shift;
-
-    my $sgn = "";
-    if ($_ < 0) {
-        $sgn = "-";
-        $_ = -$_;
-    }
-
-    $_ /= 1024;
-
-    if ($_ < 1024) {
-        sprintf "%s%dK", $sgn, $_;
-    } elsif ($_ < 1024 * 1024) {
-        sprintf "%s%.1fM", $sgn, ($_ / 1024);
-    } else {
-        sprintf "%s%.1fG", $sgn, ($_ / 1024 / 1024);
-    }
-}
-
-# The reverse of device name translation, see
-# BLOCK DEVICE NAMING in guestfs(3).
-sub canonicalize
-{
-    local $_ = shift;
-
-    if (m{^/dev/[hv]d([a-z]\d*)$}) {
-        return "/dev/sd$1";
-    }
-    $_;
-}
-
-# Not as sophisticated as the guestfish progress bar, because
-# I intend to use an external library for this at some point (XXX).
-sub progress_callback
-{
-    my $proc_nr = shift;
-    my $serial = shift;
-    my $position = shift;
-    my $total = shift;
-
-    my $ratio = $position / $total;
-    if ($ratio < 0) { $ratio = 0 }
-    elsif ($ratio > 1) { $ratio = 1 }
-
-    my $dots = int ($ratio * 76);
-
-    print "[", "#"x$dots, "-"x(76-$dots), "]\r";
-    print "\n" if $ratio == 1;
-}
-
-=head1 NOTES
-
-=head2 "Partition 1 does not end on cylinder boundary."
-
-Virt-resize aligns partitions to multiples of 64 sectors.  Usually
-this means the partitions will not be aligned to the ancient CHS
-geometry.  However CHS geometry is meaningless for disks manufactured
-since the early 1990s, and doubly so for virtual hard drives.
-Alignment of partitions to cylinders is not required by any modern
-operating system.
-
-=head2 RESIZING WINDOWS VIRTUAL MACHINES
-
-In Windows Vista and later versions, Microsoft switched to using a
-separate boot partition.  In these VMs, typically C</dev/sda1> is the
-boot partition and C</dev/sda2> is the main (C:) drive.  We have not
-had any luck resizing the boot partition.  Doing so seems to break the
-guest completely.  However expanding the second partition (ie. C:
-drive) should work.
-
-Windows may initiate a lengthy "chkdsk" on first boot after a resize,
-if NTFS partitions have been expanded.  This is just a safety check
-and (unless it find errors) is nothing to worry about.
-
-=head2 GUEST BOOT STUCK AT "GRUB"
-
-If a Linux guest does not boot after resizing, and the boot is stuck
-after printing C<GRUB> on the console, try reinstalling grub.  This
-sometimes happens on older (RHEL 5-era) guests, for reasons we don't
-fully understand, although we think is to do with partition alignment.
-
- guestfish -i -a newdisk
- ><fs> cat /boot/grub/device.map
- # check the contents of this file are sensible or
- # edit the file if necessary
- ><fs> grub-install / /dev/vda
- ><fs> exit
-
-For more flexible guest reconfiguration, including if you need to
-specify other parameters to grub-install, use L<virt-rescue(1)>.
-
-=head1 ALTERNATIVE TOOLS
-
-There are several proprietary tools for resizing partitions.  We
-won't mention any here.
-
-L<parted(8)> and its graphical shell gparted can do some types of
-resizing operations on disk images.  They can resize and move
-partitions, but I don't think they can do anything with the contents,
-and they certainly don't understand LVM.
-
-L<guestfish(1)> can do everything that virt-resize can do and a lot
-more, but at a much lower level.  You will probably end up
-hand-calculating sector offsets, which is something that virt-resize
-was designed to avoid.  If you want to see the guestfish-equivalent
-commands that virt-resize runs, use the C<--debug> flag.
-
-=head1 SHELL QUOTING
-
-Libvirt guest names can contain arbitrary characters, some of which
-have meaning to the shell such as C<#> and space.  You may need to
-quote or escape these characters on the command line.  See the shell
-manual page L<sh(1)> for details.
-
-=head1 SEE ALSO
-
-L<virt-filesystems(1)>,
-L<virt-df(1)>,
-L<guestfs(3)>,
-L<guestfish(1)>,
-L<lvm(8)>,
-L<pvresize(8)>,
-L<lvresize(8)>,
-L<resize2fs(8)>,
-L<ntfsresize(8)>,
-L<virsh(1)>,
-L<parted(8)>,
-L<truncate(1)>,
-L<fallocate(1)>,
-L<grub(8)>,
-L<grub-install(8)>,
-L<virt-rescue(1)>,
-L<Sys::Guestfs(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://people.redhat.com/~rjones/>
-
-=head1 COPYRIGHT
-
-Copyright (C) 2010 Red Hat Inc.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2 of the License, or
-(at your option) any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.