[Libguestfs] [PATCH 3/4] Handle block remaps in grub and grub2 files

Mike Latimer
Thu, 31 Oct 2013 20:14:06 -0000

---
 lib/Sys/VirtConvert/Converter/Linux.pm | 61 ++++++++++++++++++++++++++++++----
 1 file changed, 54 insertions(+), 7 deletions(-)

diff --git a/lib/Sys/VirtConvert/Converter/Linux.pm
b/lib/Sys/VirtConvert/Converter/Linux.pm
index 344d89b..531d72b 100644
--- a/lib/Sys/VirtConvert/Converter/Linux.pm
+++ b/lib/Sys/VirtConvert/Converter/Linux.pm
@@ -673,7 +673,7 @@ sub convert

     my $display = _get_display_driver($g, $root);
     _configure_display_driver($g, $root, $config, $meta, $grub, $driver);
-    _remap_block_devices($meta, $virtio, $g, $root);
+    _remap_block_devices($meta, $virtio, $g, $root, $grub);
     _configure_kernel_modules($g, $virtio);
     _configure_boot($kernel, $virtio, $g, $root, $grub);

@@ -2251,7 +2251,7 @@ sub _rpmvercmp

 sub _remap_block_devices
 {
-    my ($meta, $virtio, $g, $root) = @_;
+    my ($meta, $virtio, $g, $root, $grub) = @_;

     my @devices = map { $_->{device} } @{$meta->{disks}};
     @devices = sort { scsi_first_cmp($a, $b) } @devices;
@@ -2338,13 +2338,46 @@ sub _remap_block_devices
     }

     eval {
-        # Update bare device references in fstab and grub's device.map
-        foreach my $spec ($g->aug_match('/files/etc/fstab/*/spec'),
-
$g->aug_match('/files/boot/grub/device.map/*'.
-                                            '[label() !=
"#comment"]'))
+        my @checklist;
+        my @matchlist;
+        my $grub2_remap;
+
+        # Add standard configuration files to the checklist
+        push (@checklist, '/files/etc/fstab/*/spec');
+
+        # Add grub or grub2 files to the checklist
+        if (defined($grub->{grub_conf})) {
+            push (@checklist,
"/files$grub->{grub_conf}/*/kernel/root");
+            push (@checklist,
"/files$grub->{grub_conf}/*/kernel/resume");
+            push (@checklist, '/files/boot/grub/device.map/*'.
+                              '[label() != "#comment"]');
+        }
+        elsif (defined($grub->{cfg})) {
+            push (@checklist,
'/files/etc/sysconfig/grub/GRUB_CMDLINE_LINUX');
+            push (@checklist, '/files/etc/default/grub/'.
+                              'GRUB_CMDLINE_LINUX_DEFAULT');
+        }
+
+        # Search through all checklist entries and add matches to a matchlist
+        foreach my $entry (@checklist) {
+            push (@matchlist, $g->aug_match($entry));
+        }
+
+        # Update device references for every entry in the matchlist
+        foreach my $spec (@matchlist)
         {
             my $device = $g->aug_get($spec);

+            # If this is a grub2 environment, isolate 'resume=' value
+            my $grub2_start;
+            my $grub2_end;
+            if (($spec =~ /.*GRUB_CMDLINE.*/) &&
+                    ($device =~ /(.*resume=)(\S+)(\s.*)/)) {
+                $grub2_start = $1;
+                $device = $2;
+                $grub2_end = $3;
+            }
+
             # Match device names and partition numbers
             my $name; my $part;
             foreach my $r (qr{^/dev/(cciss/c\d+d\d+)(?:p(\d+))?$},
@@ -2366,7 +2399,9 @@ sub _remap_block_devices
             # about. The user will have to fix this post-conversion.
             if (!exists($map{$name})) {
                 my $warned = 0;
-                for my $file ('/etc/fstab',
'/boot/grub/device.map') {
+                for my $file ('/etc/fstab',
'/boot/grub/device.map',
+                              '/boot/grub/menu.lst',
'/etc/sysconfig/grub',
+                              '/etc/default/grub') {
                     if ($spec =~ m{^/files$file}) {
                         logmsg WARN, __x('{file} references unknown device
'.
                                          '{device}. This entry must be
'.
@@ -2389,10 +2424,22 @@ sub _remap_block_devices

             my $mapped = '/dev/'.$map{$name};
             $mapped .= $part if defined($part);
+
+            # If this is a grub2 entry, rebuild the entire entry
+            if ($spec =~ /.*GRUB_CMDLINE.*/) {
+                $mapped = $grub2_start.$mapped.$grub2_end;
+                $grub2_remap = 1;
+            }
+
             $g->aug_set($spec, $mapped);
         }

         $g->aug_save();
+
+        # Re-generate the grub2 config if grub2 files were changed
+        if (defined($grub2_remap)) {
+            $g->command(['grub2-mkconfig', '-o',
$grub->{cfg}]);
+        }
     };

     augeas_error($g, $@) if ($@);
--
1.8.1.4