+++ /dev/null
-#!/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 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.
-
-=head2 BASIC USAGE
-
-This describes the common case where you want to expand an image to
-give your guest more space. Shrinking images is considerably more
-complicated (unfortunately).
-
-=over 4
-
-=item 1. Locate disk image
-
-Locate the disk image that you want to resize. It could be in a local
-file or device. 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 2. Look at current sizing
-
-Use L<virt-list-partitions(1)> to display the current partitions and
-sizes:
-
- # virt-list-partitions -lh /dev/vg/lv_guest
- /dev/sda1 ext3 101.9M
- /dev/sda2 pv 7.9G
-
-(This example is a virtual machine with an 8 GB disk which we would
-like to expand up to 10 GB).
-
-=item 3. Create destination disk
-
-Virt-resize cannot do in-place disk modifications. You have to have
-space to store the resized destination disk.
-
-To store the resized disk image in a file, create a file of a suitable
-size:
-
- # rm -f outdisk
- # truncate -s 10G outdisk
-
-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 4. Resize
-
- 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.
-
-To resize, you need to pass 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).
-
-If /dev/sda2 in the image contains a filesystem or LVM PV, then
-this content is B<not> automatically resized. You can resize it
-afterwards either using L<guestfish(1)> (offline) or using commands
-inside the guest (online resizing).
-
-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
-
-Other options are covered below.
-
-=item 5. 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.
-
-Note that to see the extra space in the guest, you may need to use
-guest commands to resize PVs, LVs and/or filesystems to fit the extra
-space available. Three common guest commands for doing this for Linux
-guests are L<pvresize(8)>, L<lvresize(8)> and L<resize2fs(8)>. It is
-also possible to do this offline (eg. for scripting changes) using
-L<guestfish(1)>.
-
-=back
-
-=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.
-
-You can I<only> B<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).
-
-Any filesystem inside the partition is I<not> expanded. You will need
-to expand the filesystem (or PV) to fit the extra space either using
-L<guestfish(1)> (offline) or online guest tools.
-
-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 $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,
- "d|debug" => \$debug,
- "n|dryrun" => \$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";
-}
-
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
- file => $infile, sz => $insize)
- if $insize < 64 * 512;
-die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
- file => $outfile, sz => $outsize)
- if $outsize < 64 * 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, 64 * 512) or die "$infile: $!";
- die "$infile: short read" if $r < 64 * 512;
- open OFILE, "+<$outfile" or die "$outfile: $!";
- sysseek OFILE, 0, SEEK_SET or die "$outfile: seek: $!";
- $r = syswrite (OFILE, $s, 64 * 512) or die "$outfile: $!";
- die "$outfile: short write" if $r < 64 * 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;
- $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;
-}
-
-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.
-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;
-}
-
-# 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 + (64 * (@partitions + 1)) + 128);
-
- 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", p => $part);
- } elsif ($partitions{$part}->{delete}) {
- print __x("{p}: partition will be deleted", p => $part);
- } elsif ($partitions{$part}->{newsize}) {
- print __x("{p}: partition will be resized from {oldsize} to {newsize}",
- p => $part,
- oldsize => human_size ($partitions{$part}->{part_size}),
- newsize => human_size ($partitions{$part}->{newsize}));
- } else {
- print __x("{p}: partition will be left alone", p => $part);
- }
- print "\n"
- }
-
- 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");
- print "partition table type: $parttype\n" if $debug;
- } else {
- # Didn't copy over the initial boot loader, so we need
- # to make a new partition type here.
- $parttype = "efi";
- }
-
- # Delete any existing partitions on the destination disk.
- $g->part_init ("/dev/sdb", $parttype);
-
- my $start = 64;
-
- # 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) = add_partition ($start, $size);
- $partitions{$part}->{target} = $target;
-
- # 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);
-
- if ($nextpart <= 3 || $parttype ne "msdos") {
- $target = "/dev/sdb$nextpart";
- $end = $start + $size - 1;
- $g->part_add ("/dev/sdb", "primary", $start, $end);
- $nextpart++;
- } else {
- if ($nextpart == 4) {
- $g->part_add ("/dev/sdb", "extended", $start, -1);
- $nextpart++;
- $start += 64;
- }
- $target = "/dev/sdb$nextpart";
- $end = $start + $size - 1;
- $g->part_add ("/dev/sdb", "logical", $start, $end);
- $nextpart++;
- }
-
- return ($target, $end);
-}
-
-# 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 "Copying $part ...";
- }
-
- $g->copy_size ($part, $target,
- $newsize < $oldsize ? $newsize : $oldsize);
-
- if (!$quiet && !$debug) {
- print " done\n"
- }
- }
- }
- }
-}
-
-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 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<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.