diff options
Diffstat (limited to 'perl-install/bootloader.pm')
-rw-r--r-- | perl-install/bootloader.pm | 87 |
1 files changed, 86 insertions, 1 deletions
diff --git a/perl-install/bootloader.pm b/perl-install/bootloader.pm index d7435cd7e..3267be9d9 100644 --- a/perl-install/bootloader.pm +++ b/perl-install/bootloader.pm @@ -1025,6 +1025,17 @@ sub suggest { } $bootloader->{default} ||= "linux"; $bootloader->{method} ||= first(method_choices($all_hds, 1)); + + if (main_method($bootloader->{method}) eq 'grub') { + foreach my $c (find_other_distros_grub_conf($fstab)) { + add_entry($bootloader, { + type => 'grub_configfile', + label => $c->{name}, + kernel_or_dev => "/dev/$c->{bootpart}{device}", + configfile => $c->{grub_conf}, + }); + } + } } sub detect_main_method { @@ -1333,6 +1344,9 @@ sub write_lilo { warn "mbootpack is required for xen but unavailable, skipping\n"; next; } + if ($entry->{type} eq 'grub_configfile') { + next; + } push @conf, "$entry->{type}=" . $file2fullname->($mbootpack_file || $entry->{kernel_or_dev}); my @entry_conf; @@ -1650,7 +1664,11 @@ sub write_grub { push @conf, map_each { "map ($::b) ($::a)" } %{$entry->{mapdrive}}; } push @conf, "makeactive" if $entry->{makeactive}; - push @conf, "chainloader +1"; + if ($entry->{type} eq 'grub_configfile') { + push @conf, "configfile $entry->{configfile}"; + } else { + push @conf, "chainloader +1"; + } } } my $f = "$::prefix/boot/grub/menu.lst"; @@ -1785,6 +1803,73 @@ sub ensure_pkg_is_installed { 1; } +sub find_other_distros_grub_conf { + my ($fstab) = @_; + + my @unknown_true_fs = + grep { isTrueLocalFS($_) && + (!$_->{mntpoint} || !member($_->{mntpoint}, '/home', fs::type::directories_needed_to_boot())); + } @$fstab; + + log::l("looking for configured grub on partitions " . join(' ', map { $_->{device} } @unknown_true_fs)); + + my @l; + foreach my $part (@unknown_true_fs) { + my $handle = any::inspect($part, $::prefix) or next; + + foreach my $bootdir ('', '/boot') { + my $f = find { -e "$handle->{dir}$bootdir/$_" } 'grub.conf', 'grub/menu.lst' or next; + push @l, { bootpart => $part, bootdir => $bootdir, grub_conf => "$bootdir/$f" }; + } + if (my $f = common::release_file($handle->{dir})) { + my $h = common::parse_release_file($handle->{dir}, $f, $part); + $h->{name} = $h->{release}; + push @l, $h; + } elsif ($handle && -e "$handle->{dir}/etc/issue") { + my ($s, $dropped) = cat_("$handle->{dir}/etc/issue") =~ /^([^\\\n]*)(.*)/; + log::l("found /etc/issue: $s (removed: $dropped)"); + push @l, { name => $s, part => $part }; + } + } + my $root; + my $set_root = sub { + my ($v) = @_; + $root and log::l("don't know what to do with $root->{name} ($root->{part}{device})"); + $root = $v; + }; + my @found; + while (my $e = shift @l) { + if ($e->{name}) { + $set_root->($e); + } else { + if (@l && $l[0]{name}) { + $set_root->(shift @l); + } + + my $ok; + if ($root && $root->{part} == $e->{bootpart} && $e->{bootdir}) { + # easy case: /boot is not a separate partition + $ok = 1; + } elsif ($root && $root->{part} != $e->{bootpart} && !$e->{bootdir}) { + log::l("associating '/' $root->{part}{device} with '/boot' $e->{bootpart}{device}"); + $ok = 1; + } + if ($ok) { + add2hash($e, $root); + undef $root; + push @found, $e; + } elsif ($root) { + log::l("weird case, skipping grub conf from $e->{bootpart}{device}, keeping '/' from $root->{part}{device}"); + } else { + log::l("could not recognise the distribution for $e->{grub_conf} in $e->{bootpart}{device}"); + } + } + } + $set_root->(undef); + + @found; +} + sub update_for_renumbered_partitions { my ($in, $renumbering, $all_hds) = @_; |