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 fbbf7f6..0000000
+++ /dev/null
@@ -1,1258 +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;
-
-=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-list-partitions(1)>,
-L<virt-list-filesystems(1)> and
-L<virt-df(1)>,
-we recommend you go and read those manual pages first.
-
-=head1 BASIC 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-list-partitions(1)> to display the current partitions and
-sizes:
-
- # virt-list-partitions -lht /dev/vg/lv_guest
- /dev/sda1 ext3 101.9M
- /dev/sda2 pv 7.9G
- /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.
-
-=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 $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.
-
-=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,
-            "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,
-    ) 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;
-
-my @s;
-@s = stat $infile;
-my $insize = S_ISREG ($s[2]) ? $s[7] : host_blockdevsize ($infile);
-@s = stat $outfile;
-my $outsize = S_ISREG ($s[2]) ? $s[7] : host_blockdevsize ($outfile);
-
-if ($debug) {
-    print "$infile size $insize bytes\n";
-    print "$outfile size $outsize bytes\n";
-}
-
-# 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 $boot_sectors = 4096;
-
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
-        file => $infile, sz => $insize)
-    if $insize < $boot_sectors * 512;
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
-        file => $outfile, sz => $outsize)
-    if $outsize < $boot_sectors * 512;
-
-# 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;
-    open IFILE, $infile or die "$infile: $!";
-    my $s;
-    my $r = sysread (IFILE, $s, $boot_sectors * 512) or die "$infile: $!";
-    die "$infile: short read" if $r < $boot_sectors * 512;
-    open OFILE, "+<$outfile" or die "$outfile: $!";
-    sysseek OFILE, 0, SEEK_SET or die "$outfile: seek: $!";
-    $r = syswrite (OFILE, $s, $boot_sectors * 512) or die "$outfile: $!";
-    die "$outfile: short write" if $r < $boot_sectors * 512;
-}
-
-# 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;
-    $g->add_drive_ro ($infile);
-    $g->add_drive ($outfile);
-    $g->launch ();
-}
-
-my $sectsize = $g->blockdev_getss ("/dev/sdb");
-
-# 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");
-        }
-    }
-}
-
-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.
-my $to_be_expanded = 0;
-
-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
-        ($boot_sectors - 64)       # 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);
-        }
-    }
-
-    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;
-my $parttype;
-repartition ();
-
-sub repartition
-{
-    local $_;
-
-    if ($copy_boot_loader) {
-        $parttype = $g->part_get_parttype ("/dev/sdb");
-    } else {
-        $parttype = "efi";
-    }
-    print "partition table type: $parttype\n" if $debug;
-
-    # Delete any existing partitions on the destination disk,
-    # but leave the bootloader that we copied over intact.
-    if ($copy_boot_loader) {
-        # Delete in reverse as an easy way to deal with extended
-        # partitions.
-        foreach (sort { $b cmp $a } $g->list_partitions ()) {
-            if (m{^/dev/.db(\d+)$}) {
-                $g->part_del ("/dev/sdb", $1);
-            }
-        }
-    } else {
-        # Didn't copy over the initial boot loader, so we need
-        # to make a new partition table here.
-        $g->part_init ("/dev/sdb", $parttype);
-    }
-
-    # 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) {
-                    local $| = 1;
-                    print __x("Copying {p} ...", p => $part);
-                }
-
-                $g->copy_size ($part, $target,
-                               $newsize < $oldsize ? $newsize : $oldsize);
-
-                if (!$quiet && !$debug) {
-                    print " ", __"done", "\n";
-                }
-            }
-        }
-    }
-}
-
-# 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 ();
-}
-
-sub restart_appliance
-{
-    # Sync disk and exit.
-    $g->umount_all ();
-    $g->sync ();
-    undef $g;
-
-    $g = Sys::Guestfs->new ();
-    $g->set_trace (1) if $debug;
-    $g->add_drive ($outfile);
-    $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",
-                                  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";
-    }
-}
-
-# 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);
-    }
-}
-
-# Return the size in bytes of a HOST block device.
-sub host_blockdevsize
-{
-    local $_;
-    my $dev = shift;
-
-    open BD, "PATH=/usr/sbin:/sbin:\$PATH blockdev --getsize64 $dev |"
-        or die "blockdev: $!";
-    $_ = <BD>;
-    chomp $_;
-    $_;
-}
-
-# 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";
-    }
-    $_;
-}
-
-=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.
-
-=head1 SEE ALSO
-
-L<virt-list-partitions(1)>,
-L<virt-list-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<Sys::Guestfs(3)>,
-L<http://libguestfs.org/>.
-
-=head1 AUTHOR
-
-Richard W.M. Jones L<http://et.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.