+ my $p = XML::XPath->new (xml => $xml);
+ my @disks = $p->findnodes ('//devices/disk/source/@dev');
+ push (@disks, $p->findnodes ('//devices/disk/source/@file'));
+
+ # Code in Sys::Guestfs::Lib dies here if there are no disks at all.
+
+ return map { $_->getData } @disks;
+}
+
+# Sort the domains by name for display.
+@domains = sort { $a->{name} cmp $b->{name} } @domains;
+
+# Since we got this far, we're somewhat sure we're going to
+# get to print the result, so display the title.
+print_title ();
+
+# To minimize the number of times we have to launch the appliance,
+# shuffle as many domains together as we can, but not exceeding 26
+# disks per request. (26 = # of letters in the English alphabet, and
+# we are only confident that /dev/sd[a-z] will work because of various
+# limits).
+my $n = 0;
+my @request = ();
+while (@domains) {
+ while (@domains) {
+ my $c = @{$domains[0]->{disks}};
+ last if $n + $c > 26;
+ push @request, shift @domains;
+ }
+ multi_df (@request);
+}
+
+sub multi_df
+{
+ local $_;
+ my $g = Sys::Guestfs->new ();
+
+ my ($d, $disk);
+
+ foreach $d (@_) {
+ foreach $disk (@{$d->{disks}}) {
+ $g->add_drive_ro ($disk);
+ }