virt-make-fs: Use Sys::Guestfs::Lib::feature_available helper function.
[libguestfs.git] / tools / virt-resize
1 #!/usr/bin/perl -w
2 # virt-resize
3 # Copyright (C) 2010 Red Hat Inc.
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 use warnings;
20 use strict;
21
22 use Sys::Guestfs;
23 use Fcntl qw(S_ISREG SEEK_SET);
24 use POSIX qw(floor);
25 use Pod::Usage;
26 use Getopt::Long;
27 use Data::Dumper;
28 use Locale::TextDomain 'libguestfs';
29
30 $Data::Dumper::Sortkeys = 1;
31
32 die __"virt-resize: sorry this program does not work on a 32 bit host\n"
33     if ~1 == 4294967294;
34
35 =encoding utf8
36
37 =head1 NAME
38
39 virt-resize - Resize a virtual machine disk
40
41 =head1 SYNOPSIS
42
43  virt-resize [--resize /dev/sdaN=[+/-]<size>[%]] [--expand /dev/sdaN]
44    [--shrink /dev/sdaN] [--ignore /dev/sdaN] [--delete /dev/sdaN] [...]
45    indisk outdisk
46
47 =head1 DESCRIPTION
48
49 Virt-resize is a tool which can resize a virtual machine disk, making
50 it larger or smaller overall, and resizing or deleting any partitions
51 contained within.
52
53 Virt-resize B<cannot> resize disk images in-place.  Virt-resize
54 B<should not> be used on live virtual machines - for consistent
55 results, shut the virtual machine down before resizing it.
56
57 If you are not familiar with the associated tools:
58 L<virt-list-partitions(1)>,
59 L<virt-list-filesystems(1)> and
60 L<virt-df(1)>,
61 we recommend you go and read those manual pages first.
62
63 =head2 BASIC USAGE
64
65 This describes the common case where you want to expand an image to
66 give your guest more space.  Shrinking images is considerably more
67 complicated (unfortunately).
68
69 =over 4
70
71 =item 1. Locate disk image
72
73 Locate the disk image that you want to resize.  It could be in a local
74 file or device.  If the guest is managed by libvirt, you can use
75 C<virsh dumpxml> like this to find the disk image name:
76
77  # virsh dumpxml guestname | xpath /domain/devices/disk/source
78  Found 1 nodes:
79  -- NODE --
80  <source dev="/dev/vg/lv_guest" />
81
82 =item 2. Look at current sizing
83
84 Use L<virt-list-partitions(1)> to display the current partitions and
85 sizes:
86
87  # virt-list-partitions -lh /dev/vg/lv_guest
88  /dev/sda1 ext3 101.9M
89  /dev/sda2 pv 7.9G
90
91 (This example is a virtual machine with an 8 GB disk which we would
92 like to expand up to 10 GB).
93
94 =item 3. Create destination disk
95
96 Virt-resize cannot do in-place disk modifications.  You have to have
97 space to store the resized destination disk.
98
99 To store the resized disk image in a file, create a file of a suitable
100 size:
101
102  # rm -f outdisk
103  # truncate -s 10G outdisk
104
105 Use L<lvcreate(1)> to create a logical volume:
106
107  # lvcreate -L 10G -n lv_name vg_name
108
109 Or use L<virsh(1)> vol-create-as to create a libvirt storage volume:
110
111  # virsh pool-list
112  # virsh vol-create-as poolname newvol 10G
113
114 =item 4. Resize
115
116  virt-resize indisk outdisk
117
118 This command just copies disk image C<indisk> to disk image C<outdisk>
119 I<without> resizing or changing any existing partitions.  If
120 C<outdisk> is larger, then an extra, empty partition is created at the
121 end of the disk covering the extra space.  If C<outdisk> is smaller,
122 then it will give an error.
123
124 To resize, you need to pass extra options (for the full list see the
125 L</OPTIONS> section below).
126
127 L</--expand> is the most useful option.  It expands the named
128 partition within the disk to fill any extra space:
129
130  virt-resize --expand /dev/sda2 indisk outdisk
131
132 (In this case, an extra partition is I<not> created at the end of the
133 disk, because there will be no unused space).
134
135 If /dev/sda2 in the image contains a filesystem or LVM PV, then
136 this content is B<not> automatically resized.  You can resize it
137 afterwards either using L<guestfish(1)> (offline) or using commands
138 inside the guest (online resizing).
139
140 L</--resize> is the other commonly used option.  The following would
141 increase the size of /dev/sda1 by 200M, and expand /dev/sda2
142 to fill the rest of the available space:
143
144  virt-resize --resize /dev/sda1=+200M --expand /dev/sda2 \
145    indisk outdisk
146
147 Other options are covered below.
148
149 =item 5. Test
150
151 Thoroughly test the new disk image I<before> discarding the old one.
152
153 If you are using libvirt, edit the XML to point at the new disk:
154
155  # virsh edit guestname
156
157 Change E<lt>source ...E<gt>, see
158 L<http://libvirt.org/formatdomain.html#elementsDisks>
159
160 Then start up the domain with the new, resized disk:
161
162  # virsh start guestname
163
164 and check that it still works.
165
166 Note that to see the extra space in the guest, you may need to use
167 guest commands to resize PVs, LVs and/or filesystems to fit the extra
168 space available.  Three common guest commands for doing this for Linux
169 guests are L<pvresize(8)>, L<lvresize(8)> and L<resize2fs(8)>.  It is
170 also possible to do this offline (eg. for scripting changes) using
171 L<guestfish(1)>.
172
173 =back
174
175 =head1 OPTIONS
176
177 =over 4
178
179 =cut
180
181 my $help;
182
183 =item B<--help>
184
185 Display help.
186
187 =cut
188
189 my $version;
190
191 =item B<--version>
192
193 Display version number and exit.
194
195 =cut
196
197 my @resize;
198
199 =item B<--resize part=size>
200
201 Resize the named partition (expanding or shrinking it) so that it has
202 the given size.
203
204 C<size> can be expressed as an absolute number followed by
205 b/K/M/G/T/P/E to mean bytes, Kilobytes, Megabytes, Gigabytes,
206 Terabytes, Petabytes or Exabytes; or as a percentage of the current
207 size; or as a relative number or percentage.  For example:
208
209  --resize /dev/sda2=10G
210
211  --resize /dev/sda4=90%
212
213  --resize /dev/sda2=+1G
214
215  --resize /dev/sda2=-200M
216
217  --resize /dev/sda1=+128K
218
219  --resize /dev/sda1=+10%
220
221  --resize /dev/sda1=-10%
222
223 You can increase the size of any partition.
224
225 You can I<only> B<decrease> the size of partitions that contain
226 filesystems or PVs which have already been shrunk.  Virt-resize will
227 check this has been done before proceeding, or else will print an
228 error (see also C<--resize-force>).
229
230 You can give this option multiple times.
231
232 =cut
233
234 my @resize_force;
235
236 =item B<--resize-force part=size>
237
238 This is the same as C<--resize> except that it will let you decrease
239 the size of any partition.  Generally this means you will lose any
240 data which was at the end of the partition you shrink, but you may not
241 care about that (eg. if shrinking an unused partition, or if you can
242 easily recreate it such as a swap partition).
243
244 See also the C<--ignore> option.
245
246 =cut
247
248 my $expand;
249
250 =item B<--expand part>
251
252 Expand the named partition so it uses up all extra space (space left
253 over after any other resize changes that you request have been done).
254
255 Any filesystem inside the partition is I<not> expanded.  You will need
256 to expand the filesystem (or PV) to fit the extra space either using
257 L<guestfish(1)> (offline) or online guest tools.
258
259 Note that you cannot use C<--expand> and C<--shrink> together.
260
261 =cut
262
263 my $shrink;
264
265 =item B<--shrink part>
266
267 Shrink the named partition until the overall disk image fits in the
268 destination.  The named partition B<must> contain a filesystem or PV
269 which has already been shrunk using another tool (eg. L<guestfish(1)>
270 or other online tools).  Virt-resize will check this and give an error
271 if it has not been done.
272
273 The amount by which the overall disk must be shrunk (after carrying
274 out all other operations requested by the user) is called the
275 "deficit".  For example, a straight copy (assume no other operations)
276 from a 5GB disk image to a 4GB disk image results in a 1GB deficit.
277 In this case, virt-resize would give an error unless the user
278 specified a partition to shrink and that partition had more than a
279 gigabyte of free space.
280
281 Note that you cannot use C<--expand> and C<--shrink> together.
282
283 =cut
284
285 my @ignore;
286
287 =item B<--ignore part>
288
289 Ignore the named partition.  Effectively this means the partition is
290 allocated on the destination disk, but the content is not copied
291 across from the source disk.  The content of the partition will be
292 blank (all zero bytes).
293
294 You can give this option multiple times.
295
296 =cut
297
298 my @delete;
299
300 =item B<--delete part>
301
302 Delete the named partition.  It would be more accurate to describe
303 this as "don't copy it over", since virt-resize doesn't do in-place
304 changes and the original disk image is left intact.
305
306 Note that when you delete a partition, then anything contained in the
307 partition is also deleted.  Furthermore, this causes any partitions
308 that come after to be I<renumbered>, which can easily make your guest
309 unbootable.
310
311 You can give this option multiple times.
312
313 =cut
314
315 my $copy_boot_loader = 1;
316
317 =item B<--no-copy-boot-loader>
318
319 By default, virt-resize copies over some sectors at the start of the
320 disk (up to the beginning of the first partition).  Commonly these
321 sectors contain the Master Boot Record (MBR) and the boot loader, and
322 are required in order for the guest to boot correctly.
323
324 If you specify this flag, then this initial copy is not done.  You may
325 need to reinstall the boot loader in this case.
326
327 =cut
328
329 my $extra_partition = 1;
330 my $min_extra_partition = 10 * 1024 * 1024; # see below
331
332 =item B<--no-extra-partition>
333
334 By default, virt-resize creates an extra partition if there is any
335 extra, unused space after all resizing has happened.  Use this option
336 to prevent the extra partition from being created.  If you do this
337 then the extra space will be inaccessible until you run fdisk, parted,
338 or some other partitioning tool in the guest.
339
340 Note that if the surplus space is smaller than 10 MB, no extra
341 partition will be created.
342
343 =cut
344
345 my $debug;
346
347 =item B<-d> | B<--debug>
348
349 Enable debugging messages.
350
351 =cut
352
353 my $dryrun;
354
355 =item B<-n> | B<--dryrun>
356
357 Print a summary of what would be done, but don't do anything.
358
359 =cut
360
361 my $quiet;
362
363 =item B<-q> | B<--quiet>
364
365 Don't print the summary.
366
367 =back
368
369 =cut
370
371 GetOptions ("help|?" => \$help,
372             "version" => \$version,
373             "resize=s" => \@resize,
374             "resize-force=s" => \@resize_force,
375             "expand=s" => \$expand,
376             "shrink=s" => \$shrink,
377             "ignore=s" => \@ignore,
378             "delete=s" => \@delete,
379             "copy-boot-loader!" => \$copy_boot_loader,
380             "extra-partition!" => \$extra_partition,
381             "d|debug" => \$debug,
382             "n|dryrun" => \$dryrun,
383             "q|quiet" => \$quiet,
384     ) or pod2usage (2);
385 pod2usage (1) if $help;
386 if ($version) {
387     my $g = Sys::Guestfs->new ();
388     my %h = $g->version ();
389     print "$h{major}.$h{minor}.$h{release}$h{extra}\n";
390     exit
391 }
392
393 die "virt-resize [--options] indisk outdisk\n" unless @ARGV == 2;
394
395 # Check in and out images exist.
396 my $infile = $ARGV[0];
397 my $outfile = $ARGV[1];
398 die __x("virt-resize: {file}: does not exist or is not readable\n", file => $infile)
399     unless -r $infile;
400 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)
401     unless -w $outfile;
402
403 my @s;
404 @s = stat $infile;
405 my $insize = S_ISREG ($s[2]) ? $s[7] : host_blockdevsize ($infile);
406 @s = stat $outfile;
407 my $outsize = S_ISREG ($s[2]) ? $s[7] : host_blockdevsize ($outfile);
408
409 if ($debug) {
410     print "$infile size $insize bytes\n";
411     print "$outfile size $outsize bytes\n";
412 }
413
414 die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
415         file => $infile, sz => $insize)
416     if $insize < 64 * 512;
417 die __x("virt-resize: {file}: file is too small to be a disk image ({sz} bytes)\n",
418         file => $outfile, sz => $outsize)
419     if $outsize < 64 * 512;
420
421 # Copy the boot loader across.
422 do_copy_boot_loader () if $copy_boot_loader;
423
424 sub do_copy_boot_loader
425 {
426     print "copying boot loader ...\n" if $debug;
427     open IFILE, $infile or die "$infile: $!";
428     my $s;
429     my $r = sysread (IFILE, $s, 64 * 512) or die "$infile: $!";
430     die "$infile: short read" if $r < 64 * 512;
431     open OFILE, "+<$outfile" or die "$outfile: $!";
432     sysseek OFILE, 0, SEEK_SET or die "$outfile: seek: $!";
433     $r = syswrite (OFILE, $s, 64 * 512) or die "$outfile: $!";
434     die "$outfile: short write" if $r < 64 * 512;
435 }
436
437 # Add them to the handle and launch the appliance.
438 my $g;
439 launch_guestfs ();
440
441 sub launch_guestfs
442 {
443     $g = Sys::Guestfs->new ();
444     $g->set_trace (1) if $debug;
445     $g->add_drive_ro ($infile);
446     $g->add_drive ($outfile);
447     $g->launch ();
448 }
449
450 my $sectsize = $g->blockdev_getss ("/dev/sdb");
451
452 # Get the partitions on the source disk.
453 my @partitions;
454 my %partitions;
455 check_source_disk ();
456
457 sub check_source_disk
458 {
459     local $_;
460
461     # Partitions and PVs.
462     my @p = $g->part_list ("/dev/sda");
463     foreach (@p) {
464         my $name = "/dev/sda" . $_->{part_num};
465         push @partitions, $name;
466
467         my %h = %$_;
468         $h{name} = $name;
469         $partitions{$name} = \%h;
470     }
471 }
472
473 # Examine each partition.
474 my @pvs_full = $g->pvs_full ();
475 examine_partition ($_) foreach @partitions;
476
477 sub examine_partition
478 {
479     local $_;
480     my $part = shift;
481
482     # What is it?
483     my $type = "unknown";
484     eval {
485         $type = $g->vfs_type ($part);
486     };
487     $partitions{$part}->{type} = $type;
488
489     # Can we get the actual size of this object (ie. to find out if it
490     # is smaller than the container for shrinking)?
491     my $fssize;
492     if ($type eq "LVM2_member") { # LVM PV
493         foreach (@pvs_full) {
494             $fssize = $_->{pv_size}
495               if canonicalize ($_->{pv_name}) eq $part;
496         }
497     } else {                    # Something mountable?
498         eval {
499             $g->mount_ro ($part, "/");
500
501             my %stat = $g->statvfs ("/");
502             $fssize = $stat{bsize} * $stat{blocks};
503         };
504
505         eval {
506             $g->umount_all ();
507         };
508     }
509
510     # This might be undef if we didn't successfully find the size.  In
511     # that case user won't be allowed to shrink this partition except
512     # by forcing it.
513     $partitions{$part}->{fssize} = $fssize;
514 }
515
516 if ($debug) {
517     print "partitions found: ", join (", ", @partitions), "\n";
518     foreach my $part (@partitions) {
519         print "$part:\n";
520         foreach (sort keys %{$partitions{$part}}) {
521             print("\t", $_, " = ",
522                   defined ($partitions{$part}->{$_})
523                   ? $partitions{$part}->{$_} : "undef",
524                   "\n");
525         }
526     }
527 }
528
529 sub find_partition
530 {
531     local $_ = shift;
532     my $option = shift;
533
534     $_ = "/dev/$_" unless $_ =~ m{^/dev};
535     $_ = canonicalize ($_);
536
537     unless (exists $partitions{$_}) {
538         die __x("{p}: partition not found in the source disk image, when using the '{opt}' command line option\n",
539                 p => $_,
540                 opt => $option)
541     }
542
543     if ($partitions{$_}->{ignore}) {
544         die __x("{p}: partition ignored, you cannot use it in another command line argument\n",
545                 p => $_)
546     }
547     if ($partitions{$_}->{delete}) {
548         die __x("{p}: partition deleted, you cannot use it in another command line argument\n",
549                 p => $_)
550     }
551
552     return $_;
553 }
554
555 # Handle --ignore.
556 do_ignore ($_) foreach @ignore;
557
558 sub do_ignore
559 {
560     local $_ = shift;
561     $_ = find_partition ($_, "--ignore");
562     $partitions{$_}->{ignore} = 1;
563 }
564
565 # Handle --delete.
566 do_delete ($_) foreach @delete;
567
568 sub do_delete
569 {
570     local $_ = shift;
571     $_ = find_partition ($_, "--delete");
572     $partitions{$_}->{delete} = 1;
573 }
574
575 # Handle --resize and --resize-force.
576 do_resize ($_, 0, "--resize") foreach @resize;
577 do_resize ($_, 1, "--resize-force") foreach @resize_force;
578
579 sub do_resize
580 {
581     local $_ = shift;
582     my $force = shift;
583     my $option = shift;
584
585     # Argument is "part=size" ...
586     my ($part, $sizefield) = split /=/, $_, 2;
587     $part = find_partition ($part, $option);
588
589     if (exists $partitions{$part}->{newsize}) {
590         die __x("{p}: this partition has already been marked for resizing\n",
591                 p => $part);
592     }
593
594     # Parse the size field.
595     my $oldsize = $partitions{$part}->{part_size};
596     my $newsize;
597     if (!defined ($sizefield) || $sizefield eq "") {
598         die __x("{p}: missing size field in {o} option\n",
599                 p => $part, o => $option);
600     } elsif ($sizefield =~ /^([.\d]+)([bKMGTPE])$/) {
601         $newsize = sizebytes ($1, $2);
602     } elsif ($sizefield =~ /^\+([.\d]+)([bKMGTPE])$/) {
603         my $incr = sizebytes ($1, $2);
604         $newsize = $oldsize + $incr;
605     } elsif ($sizefield =~ /^-([.\d]+)([bKMGTPE])$/) {
606         my $decr = sizebytes ($1, $2);
607         $newsize = $oldsize - $decr;
608     } elsif ($sizefield =~ /^([.\d]+)%$/) {
609         $newsize = $oldsize * $1 / 100;
610     } elsif ($sizefield =~ /^\+([.\d]+)%$/) {
611         $newsize = $oldsize + $oldsize * $1 / 100;
612     } elsif ($sizefield =~ /^-([.\d]+)%$/) {
613         $newsize = $oldsize - $oldsize * $1 / 100;
614     } else {
615         die __x("{p}: {f}: cannot parse size field\n",
616                 p => $part, f => $sizefield)
617     }
618
619     $newsize > 0 or
620         die __x("{p}: new size is zero or negative\n", p => $part);
621
622     mark_partition_for_resize ($part, $oldsize, $newsize, $force, $option);
623 }
624
625 sub mark_partition_for_resize
626 {
627     local $_;
628     my $part = shift;
629     my $oldsize = shift;
630     my $newsize = shift;
631     my $force = shift;
632     my $option = shift;
633
634     # Do nothing if the size is the same.
635     return if $oldsize == $newsize;
636
637     my $bigger = $newsize > $oldsize;
638
639     # Check there is space to shrink this.
640     unless ($bigger || $force) {
641         if (! $partitions{$part}->{fssize} ||
642             $partitions{$part}->{fssize} > $newsize) {
643             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",
644                     p => $part);
645         }
646     }
647
648     $partitions{$part}->{newsize} = $newsize;
649 }
650
651 # Handle --expand and --shrink.
652 my $surplus;
653 if (defined $expand && defined $shrink) {
654     die __"virt-resize: you cannot use options --expand and --shrink together\n"
655 }
656 if (defined $expand || defined $shrink) {
657     calculate_surplus ();
658
659     if ($debug) {
660         print "surplus before --expand or --shrink: $surplus (",
661           human_size ($surplus), ")\n";
662     }
663
664     do_expand () if $expand;
665     do_shrink () if $shrink;
666 }
667
668 # (Re-)calculate surplus after doing expand or shrink.
669 calculate_surplus ();
670
671 # Add up the total space required on the target so far, compared
672 # to the size of the target.  We end up with a surplus or deficit.
673 sub calculate_surplus
674 {
675     local $_;
676
677     # We need some overhead for partitioning.  Worst case would be for
678     # EFI partitioning + massive per-partition alignment.
679     my $overhead = $sectsize * (2 * 64 + (64 * (@partitions + 1)) + 128);
680
681     my $required = 0;
682     foreach (@partitions) {
683         if ($partitions{$_}->{newsize}) {
684             $required += $partitions{$_}->{newsize}
685         } else {
686             $required += $partitions{$_}->{part_size}
687         }
688     }
689
690     # Compare that to the actual target disk.
691     $surplus = $outsize - ($required + $overhead);
692 }
693
694 sub do_expand
695 {
696     local $_;
697
698     unless ($surplus > 0) {
699         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",
700                 h => human_size (-$surplus));
701     }
702
703     my $part = find_partition ($expand, "--expand");
704     my $oldsize = $partitions{$part}->{part_size};
705     mark_partition_for_resize ($part, $oldsize, $oldsize + $surplus,
706                                0, "--expand");
707 }
708
709 sub do_shrink
710 {
711     local $_;
712
713     unless ($surplus < 0) {
714         die __"virt-resize: error: cannot use --shrink because there is no deficit\n(see 'deficit' in the virt-resize(1) man page)\n"
715     }
716
717     my $part = find_partition ($shrink, "--shrink");
718     my $oldsize = $partitions{$part}->{part_size};
719     mark_partition_for_resize ($part, $oldsize, $oldsize + $surplus,
720                                0, "--shrink");
721 }
722
723 # Print summary.
724 print_summary () unless $quiet;
725
726 sub print_summary
727 {
728     local $_;
729     print __"Summary of changes:\n";
730
731     foreach my $part (@partitions) {
732         if ($partitions{$part}->{ignore}) {
733             print __x("{p}: partition will be ignored", p => $part);
734         } elsif ($partitions{$part}->{delete}) {
735             print __x("{p}: partition will be deleted", p => $part);
736         } elsif ($partitions{$part}->{newsize}) {
737             print __x("{p}: partition will be resized from {oldsize} to {newsize}",
738                       p => $part,
739                       oldsize => human_size ($partitions{$part}->{part_size}),
740                       newsize => human_size ($partitions{$part}->{newsize}));
741         } else {
742             print __x("{p}: partition will be left alone", p => $part);
743         }
744         print "\n"
745     }
746
747     if ($surplus > 0) {
748         print __x("There is a surplus of {spl} bytes ({h}).\n",
749                   spl => $surplus,
750                   h => human_size ($surplus));
751         if ($extra_partition) {
752             if ($surplus >= $min_extra_partition) {
753                 print __"An extra partition will be created for the surplus.\n";
754             } else {
755                 print __"The surplus space is not large enough for an extra partition to be created\nand so it will just be ignored.\n";
756             }
757         } else {
758             print __"The surplus space will be ignored.  Run a partitioning program in the guest\nto partition this extra space if you want.\n";
759         }
760     } elsif ($surplus < 0) {
761         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",
762                 def => -$surplus,
763                 h => human_size (-$surplus));
764     }
765 }
766
767 exit 0 if $dryrun;
768
769 # Repartition the target disk.
770 my $nextpart = 1;
771 my $parttype;
772 repartition ();
773
774 sub repartition
775 {
776     local $_;
777
778     if ($copy_boot_loader) {
779         $parttype = $g->part_get_parttype ("/dev/sdb");
780         print "partition table type: $parttype\n" if $debug;
781     } else {
782         # Didn't copy over the initial boot loader, so we need
783         # to make a new partition type here.
784         $parttype = "efi";
785     }
786
787     # Delete any existing partitions on the destination disk.
788     $g->part_init ("/dev/sdb", $parttype);
789
790     my $start = 64;
791
792     # Create the new partitions.
793     foreach my $part (@partitions) {
794         unless ($partitions{$part}->{delete}) {
795             # Size in sectors.
796             my $size;
797             if ($partitions{$part}->{newsize}) {
798                 $size = ($partitions{$part}->{newsize} + $sectsize - 1)
799                     / $sectsize;
800             } else {
801                 $size = ($partitions{$part}->{part_size} + $sectsize - 1)
802                     / $sectsize;
803             }
804
805             # Create it.
806             my ($target, $end) = add_partition ($start, $size);
807             $partitions{$part}->{target} = $target;
808
809             # Start of next partition + alignment.
810             $start = $end + 1;
811             $start = ($start + 63) & ~63;
812         }
813     }
814
815     # Create surplus partition.
816     if ($extra_partition && $surplus >= $min_extra_partition) {
817         add_partition ($start, $outsize / $sectsize - 64 - $start);
818     }
819 }
820
821 # Add a partition.
822 sub add_partition
823 {
824     local $_;
825     my $start = shift;
826     my $size = shift;
827
828     my ($target, $end);
829
830     if ($nextpart <= 3 || $parttype ne "msdos") {
831         $target = "/dev/sdb$nextpart";
832         $end = $start + $size - 1;
833         $g->part_add ("/dev/sdb", "primary", $start, $end);
834         $nextpart++;
835     } else {
836         if ($nextpart == 4) {
837             $g->part_add ("/dev/sdb", "extended", $start, -1);
838             $nextpart++;
839             $start += 64;
840         }
841         $target = "/dev/sdb$nextpart";
842         $end = $start + $size - 1;
843         $g->part_add ("/dev/sdb", "logical", $start, $end);
844         $nextpart++;
845     }
846
847     return ($target, $end);
848 }
849
850 # Copy over the data.
851 copy_data ();
852
853 sub copy_data
854 {
855     foreach my $part (@partitions)
856     {
857         unless ($partitions{$part}->{ignore}) {
858             my $target = $partitions{$part}->{target};
859             if ($target) {
860                 my $oldsize = $partitions{$part}->{part_size};
861                 my $newsize;
862                 if ($partitions{$part}->{newsize}) {
863                     $newsize = $partitions{$part}->{newsize};
864                 } else {
865                     $newsize = $partitions{$part}->{part_size};
866                 }
867
868                 if (!$quiet && !$debug) {
869                     local $| = 1;
870                     print "Copying $part ...";
871                 }
872
873                 $g->copy_size ($part, $target,
874                                $newsize < $oldsize ? $newsize : $oldsize);
875
876                 if (!$quiet && !$debug) {
877                     print " done\n"
878                 }
879             }
880         }
881     }
882 }
883
884 exit 0;
885
886 sub sizebytes
887 {
888     local $_ = shift;
889     my $unit = shift;
890
891     $_ *= 1024 if $unit =~ /[KMGTPE]/;
892     $_ *= 1024 if $unit =~ /[MGTPE]/;
893     $_ *= 1024 if $unit =~ /[GTPE]/;
894     $_ *= 1024 if $unit =~ /[TPE]/;
895     $_ *= 1024 if $unit =~ /[PE]/;
896     $_ *= 1024 if $unit =~ /[E]/;
897
898     return floor($_);
899 }
900
901 # Convert a number of bytes to a human-readable number.
902 sub human_size
903 {
904     local $_ = shift;
905
906     my $sgn = "";
907     if ($_ < 0) {
908         $sgn = "-";
909         $_ = -$_;
910     }
911
912     $_ /= 1024;
913
914     if ($_ < 1024) {
915         sprintf "%s%dK", $sgn, $_;
916     } elsif ($_ < 1024 * 1024) {
917         sprintf "%s%.1fM", $sgn, ($_ / 1024);
918     } else {
919         sprintf "%s%.1fG", $sgn, ($_ / 1024 / 1024);
920     }
921 }
922
923 # Return the size in bytes of a HOST block device.
924 sub host_blockdevsize
925 {
926     local $_;
927     my $dev = shift;
928
929     open BD, "PATH=/usr/sbin:/sbin:\$PATH blockdev --getsize64 $dev |"
930         or die "blockdev: $!";
931     $_ = <BD>;
932     chomp $_;
933     $_;
934 }
935
936 # The reverse of device name translation, see
937 # BLOCK DEVICE NAMING in guestfs(3).
938 sub canonicalize
939 {
940     local $_ = shift;
941
942     if (m{^/dev/[hv]d([a-z]\d)$}) {
943         return "/dev/sd$1";
944     }
945     $_;
946 }
947
948 =head1 SEE ALSO
949
950 L<virt-list-partitions(1)>,
951 L<virt-list-filesystems(1)>,
952 L<virt-df(1)>,
953 L<guestfs(3)>,
954 L<guestfish(1)>,
955 L<lvm(8)>,
956 L<pvresize(8)>,
957 L<lvresize(8)>,
958 L<resize2fs(8)>,
959 L<virsh(1)>,
960 L<Sys::Guestfs(3)>,
961 L<http://libguestfs.org/>.
962
963 =head1 AUTHOR
964
965 Richard W.M. Jones L<http://et.redhat.com/~rjones/>
966
967 =head1 COPYRIGHT
968
969 Copyright (C) 2010 Red Hat Inc.
970
971 This program is free software; you can redistribute it and/or modify
972 it under the terms of the GNU General Public License as published by
973 the Free Software Foundation; either version 2 of the License, or
974 (at your option) any later version.
975
976 This program is distributed in the hope that it will be useful,
977 but WITHOUT ANY WARRANTY; without even the implied warranty of
978 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
979 GNU General Public License for more details.
980
981 You should have received a copy of the GNU General Public License
982 along with this program; if not, write to the Free Software
983 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.