diff options
Diffstat (limited to 'perl-install/bootloader.pm')
| -rw-r--r-- | perl-install/bootloader.pm | 914 | 
1 files changed, 632 insertions, 282 deletions
diff --git a/perl-install/bootloader.pm b/perl-install/bootloader.pm index 52ecdc89f..2451df253 100644 --- a/perl-install/bootloader.pm +++ b/perl-install/bootloader.pm @@ -1,4 +1,4 @@ -package bootloader; # $Id$ +package bootloader;  use diagnostics;  use strict; @@ -19,10 +19,27 @@ use partition_table::raw;  use run_program;  use modules; -#-##################################################################################### -#- Functions -#-##################################################################################### -my $vmlinuz_regexp = 'vmlinuz|win4lin'; +=head1 SYNOPSYS + +B<bootloader> enables to configure various boot loaders (LILO, GRUB Legacy, GRUB2, ...) + +Example of usage: + +    $all_hds = fsedit::get_hds(); +    fs::get_raw_hds('', $all_hds); +    fs::get_info_from_fstab($all_hds); +    $fstab = [ fs::get::fstab($all_hds) ]; +    $bootloader = bootloader::read($all_hds); +    (...) +    bootloader::action($bootloader, 'write', $all_hds); + +=head1 Functions + +=over + +=cut + +my $vmlinuz_regexp = 'vmlinu[xz]|win4lin|uImage';  my $decompose_vmlinuz_name = qr/((?:$vmlinuz_regexp).*?)-(\d+\.\d+.*)/;  sub expand_vmlinuz_symlink { @@ -43,9 +60,9 @@ sub vmlinuz2kernel_str {      {   	basename => $basename,  	version => $version,  -	$version =~ /([\d.]*)-(\D.*)-((\d+|0\.rc\d+.*)(mdk|mdv|mnb))$/ ? #- eg: 2.6.22.5-server-1mdv +	$version =~ /([\d.]*)-(\D.*)-((\d+|0\.rc\d+.*)\.mga.*)$/ ? #- eg: 3.0.0-1.mga2  	  (ext => $2, version_no_ext => "$1-$3") : -	$version =~ /(.*md[kv])-?(.*)/ ? #- (old) eg: 2.6.17-13mdventerprise +	$version =~ /(.*mga)-?(.*)/ ? #- (old) eg: 2.6.17-13mdventerprise  	  (ext => $2, version_no_ext => $1) : (version_no_ext => $version),      };  } @@ -57,7 +74,7 @@ sub kernel_str2short_name {  sub basename2initrd_basename {      my ($basename) = @_; -    $basename =~ s!vmlinuz-?!!; #- here we do not use $vmlinuz_regexp since we explictly want to keep all that is not "vmlinuz" +    $basename =~ s!(vmlinu[zx]|uImage)-?!!; #- here we do not use $vmlinuz_regexp since we explicitly want to keep all that is not "vmlinuz"      'initrd' . ($basename ? "-$basename" : '');      }  sub kernel_str2vmlinuz_long { @@ -106,10 +123,29 @@ sub get_label {      undef;  } +=item mkinitrd($kernel_version, $bootloader, $entry, $initrd) + +Regenerates kernel's initrd. + +=cut +  sub mkinitrd {      my ($kernel_version, $bootloader, $entry, $initrd) = @_; -    $::testing || -e "$::prefix/$initrd" and return $initrd; +    my $dir = dirname($initrd); +    if ($::testing) { +      log::l("Skipping initrd generation: testing mode"); +      return $initrd; +    } elsif (-e "$::prefix/$initrd") { +      log::l("Skipping initrd generation: already exists"); +      return $initrd; +    } elsif ($initrd =~ /\(hd/) { +      log::l("Skipping initrd generation: unrecognized partition"); +      return $initrd; +    } elsif (!-d "$::prefix/$dir") { +      log::l("Skipping initrd generation: dir doesn't exist (probably !mounted foreign part)"); +      return $initrd; +    }      # for /boot on dos partitions when installing on loopback file on dos partition      my $loop_boot = fs::loopback::prepare_boot(); @@ -119,9 +155,12 @@ sub mkinitrd {  		   if_($::isInstall, "-v"), "-f", $initrd, $kernel_version,   		   if_($entry->{initrd_options}, split(' ', $entry->{initrd_options})),  		  ); -    if (!run_program::rooted($::prefix, 'mkinitrd', @options)) { + +    my $err; +    if (!run_program::rooted($::prefix, 'mkinitrd', '2>', \$err, @options)) {  	unlink("$::prefix/$initrd"); -	die "mkinitrd failed:\n(mkinitrd @options)"; +	log::explanations("mkinitrd failed:\n(mkinitrd @options)\nError: <$err>"); +	die "mkinitrd failed:\n(mkinitrd @options)\nError: $err";      }      add_boot_splash($initrd, $entry->{vga} || $bootloader->{vga}); @@ -130,6 +169,13 @@ sub mkinitrd {      -e "$::prefix/$initrd" && $initrd;  } +=item rebuild_initrd($kernel_version, $bootloader, $entry, $initrd) + +Saves the old initrd then regenerate it. +If it fails, restore the old initrd. + +=cut +  sub rebuild_initrd {      my ($kernel_version, $bootloader, $entry, $initrd) = @_; @@ -161,11 +207,25 @@ sub add_boot_splash {  sub update_splash {      my ($bootloader) = @_; +    my %real_initrd_entries;      foreach (@{$bootloader->{entries}}) { -	add_boot_splash($_->{initrd}, $_->{vga} || $bootloader->{vga}) if $_->{initrd}; +	if ($_->{initrd} && $_->{vga}) { +	    my $initrd = expand_symlinks($_->{initrd}); +	    $real_initrd_entries{$initrd} = $_; +	} +    } +    foreach (values %real_initrd_entries) { +        log::l("add boot splash to $_->{initrd}\n"); +	add_boot_splash($_->{initrd}, $_->{vga} || $bootloader->{vga});      }  } +=item read($all_hds) + +Reads bootloader config by calling the proper read_XYZ function. + +=cut +  sub read {      my ($all_hds) = @_;      my $fstab = [ fs::get::fstab($all_hds) ]; @@ -188,7 +248,7 @@ sub read {  	    if (m!/fd\d+$!) {  		warn "not checking the method on floppy, assuming $main_method is right\n";  		$main_method; -	    } elsif (member($main_method, qw(yaboot cromwell silo))) { +	    } elsif (member($main_method, qw(cromwell uboot))) {  		#- not checking, there's only one bootloader anyway :)  		$main_method;  	    } elsif (my $type = partition_table::raw::typeOfMBR($_)) { @@ -198,6 +258,20 @@ sub read {  	} @devs;  	if ($type eq $main_method) { +	    return $bootloader if read_($bootloader); +	} +    } +    # still no boot loader found? let's check for ESP if using UEFI:  +    if (is_uefi()) { +	if (-f "/boot/EFI/EFI/mageia/grubx64.efi") { +	    my $bootloader = bootloader::read_grub2(); +	    return $bootloader if read_($bootloader); +	} +    } +} + +sub read_ { +    my ($bootloader) = @_;  	    my @prefered_entries = map { get_label($_, $bootloader) } $bootloader->{default}, 'linux';  	    if (my $default = find { $_ && $_->{type} eq 'image' } (@prefered_entries, @{$bootloader->{entries}})) { @@ -208,10 +282,92 @@ sub read {  		$bootloader->{default_options} = {};  	    }  	    return $bootloader; +} + + +=item is_grub2_already_crypted($password) + +Returns whether grub2 password is already encrypted or not + +=cut + +sub is_grub2_already_crypted { +    my ($password) = @_; +    $password =~ /grub.pbkdf2.sha512/; +} + +=item read_grub2 ($o_fstab) + +Read back GRUB2 config + +=cut + +sub read_grub2() { +    my %bootloader = read_grub2_install_sh(); +    return if is_empty_hash_ref(\%bootloader) & !-s "$::prefix/boot/grub2/grub.cfg"; +    my %h = getVarsFromSh("$::prefix/etc/default/grub"); +    $bootloader{timeout} = $h{GRUB_TIMEOUT}; +    # on first run (during installer) or when migrating from grub-legacy or lilo: +    $bootloader{default_append} ||= $::isInstall ? get_grub2_append(\%bootloader) : $h{GRUB_CMDLINE_LINUX_DEFAULT}; +    $bootloader{entries} = []; +    my $entry; +    my $f = "$::prefix/boot/grub2/grub.cfg"; +    my @menus; +    foreach (cat_utf8($f)) { +	next if /^#/; +	if (/menuentry\s+['"]([^']+)["']/) { +	    $entry = { label => $1, real_label => join('>', @menus, $1) }; +	} elsif (/linux\s+(\S+)\s+(.*)?/ || /module\s+(\S+vmlinu\S+)\s+(.*)?/) { +	    $entry->{type} = 'image'; +	    @$entry{qw(kernel_or_dev append)} = ($1, $2); +	    my ($vga, $other) = partition { /^vga=/ } split(' ', $entry->{append}); +	    if (@$vga) { +	        $entry->{vga} = $vga->[0] =~ /vga=(.*)/ && $1; +	        $entry->{append} = join(' ', @$other); +	    } +	} elsif (/initrd\s+(\S+)/ || /module\s+(\S+initrd\S+)\s+(.*)?/) { +	    $entry->{initrd} = $1; +	} elsif (/^submenu\s+['"]([^']+)["']/) { +	    push @menus, $1; +	} elsif (/}/) { +	    if ($entry) { +		push @{$bootloader{entries}}, $entry; +		undef $entry; +	    } else { +		pop @menus; +	    }  	}      } + +    # get default entry: +    foreach (run_program::rooted_get_stdout($::prefix, qw(grub2-editenv list))) { +	$bootloader{default} = $1 if /saved_entry=(.*)/; +	$bootloader{default} =~ s/.*>//; # strip full menu entry path +    } + +    # Get password prior to run update-grub2: +    $bootloader{password} = { getVarsFromSh(get_grub2_users()) }->{GRUB2_PASSWORD}; + +    $bootloader{method} = cat_($f) =~ /set theme=.*maggy/ ? 'grub2-graphic' : 'grub2'; +    \%bootloader; +} + +sub read_grub2_install_sh() { +    my $s = cat_(get_grub2_install_sh()); +    my %h; +    if ($s =~ m!(/dev/\S+)!m) { +	$h{boot} = $1; +    } +    $h{no_esp_or_mbr} = $s =~ m!--grub-setup=/bin/true!; +    %h;  } +=item read_grub($fstab) + +Reads back Grub Legacy config. + +=cut +  sub read_grub {      my ($fstab) = @_; @@ -228,10 +384,22 @@ sub read_grub {      $bootloader;  } -# adapts device.map (aka $grub2dev) when for example hda is now sda -# nb:  -# - $boot_part comes from /boot/grub/install.sh "root (hd...)" line -# - $grub2dev is /boot/grub/device.map + +=item _may_fix_grub2dev($fstab, $grub2dev, $boot_part) + +Adapts device.map (aka $grub2dev) when for example hda is now sda. +nb: + +=over 4 + +=item * $boot_part comes from C</boot/grub/install.sh> "C<root (hd...)>" line + +=item * $grub2dev is C</boot/grub/device.map> + +=back + +=cut +  sub _may_fix_grub2dev {      my ($fstab, $grub2dev, $boot_part) = @_; @@ -258,6 +426,12 @@ sub _may_fix_grub2dev {      $grub2dev->{$hd_grub} = $real_boot_dev;  } +=item read_grub_install_sh() { + +Reads "config" from /boot/grub/install.sh (mainly used partitions) + +=cut +  sub read_grub_install_sh() {      my $s = cat_("$::prefix/boot/grub/install.sh");      my %h; @@ -323,11 +497,24 @@ sub _parse_grub_menu_lst() {      %b;  } + +=item is_already_crypted($password) + +Returns whether grub password is already encrypted or not + +=cut +  sub is_already_crypted {      my ($password) = @_;      $password =~ /^--md5 (.*)/;  } +=item read_grub_menu_lst($fstab, $grub2dev) + +Read config from /boot/grub/menu.lst + +=cut +  sub read_grub_menu_lst {      my ($fstab, $grub2dev) = @_; @@ -363,7 +550,7 @@ sub read_grub_menu_lst {  	    $e->{append} = join(' ', grep { !/^BOOT_IMAGE=/ } split(' ', $e->{append}));  	    $e->{root} = $1 if $e->{append} =~ s/root=(\S*)\s*//;  	    eval { $e->{kernel_or_dev} = grub2file($kernel, $grub2dev, $fstab, $e) }; -	    $e->{keep_verbatim} = 1 unless $e->{kernel_or_dev} && dirname($e->{kernel_or_dev}) eq '/boot'; +	    $e->{keep_verbatim} = 1 if !$e->{kernel_or_dev} || dirname($e->{kernel_or_dev}) ne '/boot';  	}  	my ($vga, $other) = partition { /^vga=/ } split(' ', $e->{append});  	if (@$vga) { @@ -383,42 +570,15 @@ sub read_grub_menu_lst {      \%b;  } -sub yaboot2dev { -    my ($of_path) = @_; -    find { dev2yaboot($_) eq $of_path } map { "/dev/$_->{dev}" } fs::proc_partitions::read_raw(); -} - -# assumes file is in /boot -# to do: use yaboot2dev for files as well -#- example of of_path: /pci@f4000000/ata-6@d/disk@0:3,/initrd-2.6.8.1-8mdk.img -sub yaboot2file { -    my ($of_path) = @_; -     -    if ($of_path =~ /,/) { -	"$::prefix/boot/" . basename($of_path); -    } else { -	yaboot2dev($of_path); -    } -} - -sub read_silo() { -    my $bootloader = read_lilo_like("/boot/silo.conf", sub { -					my ($f) = @_; -					"/boot$f"; -				    }); -    $bootloader->{method} = 'silo'; -    $bootloader; +# FIXME: actually read back previous conf +sub read_uboot() { +    +{ method => 'uboot' };  }  sub read_cromwell() { -    my %b; -    $b{method} = 'cromwell'; -    \%b; -} -sub read_yaboot() {  -    my $bootloader = read_lilo_like("/etc/yaboot.conf", \&yaboot2file); -    $bootloader->{method} = 'yaboot'; -    $bootloader; +    +{ method => 'cromwell' };  } + +  sub read_lilo() {      my $bootloader = read_lilo_like("/etc/lilo.conf", sub { $_[0] }); @@ -523,7 +683,7 @@ sub suggest_onmbr {      if (my $type = partition_table::raw::typeOfMBR($hd->{device})) {  	if (member($type, qw(dos dummy empty))) {  	    $unsafe = 0; -	} elsif (!member($type, qw(lilo grub))) { +	} elsif (!member($type, qw(lilo grub grub2))) {  	    $onmbr = 0;  	}  	log::l("bootloader::suggest_onmbr: type $type, onmbr $onmbr, unsafe $unsafe"); @@ -531,16 +691,28 @@ sub suggest_onmbr {      ($onmbr, $unsafe);  } -# list of places where we can install the bootloader + +=item allowed_boot_parts($bootloader, $all_hds) + +Returns list of places where we can install the bootloader when not in UEFI mode +(in UEFI mode, grub2 automatically look for the ESP). + +=cut +  sub allowed_boot_parts {      my ($bootloader, $all_hds) = @_;      ( -     @{$all_hds->{hds}}, # MBR +     ( # GPT disks w/o a BIOS boot partition do not have free space for grub2 to embed: +      grep { c::get_disk_type($_->{file}) ne 'gpt' || +		 any { isBIOS_GRUB($_) } map { partition_table::get_normal_parts($_) } $_; +      } @{$all_hds->{hds}}), # MBR       if_($bootloader->{method} =~ /lilo/,  	 grep { $_->{level} eq '1' } @{$all_hds->{raids}}  	), -     (grep { !isFat_or_NTFS($_) } fs::get::fstab($all_hds)), # filesystems except those who do not leave space for our bootloaders +     (if_(main_method($bootloader->{method}) ne 'grub2', +	  grep { !isFat_or_NTFS($_) } fs::get::fstab($all_hds)), # filesystems except those who do not leave space for our bootloaders +     ),       detect_devices::floppies(),      );  } @@ -572,7 +744,7 @@ sub add_entry {      my $to_add = $v;      my $label = $v->{label}; -    for (my $i = 0; $i < 10;) { +    for (my $i = 0; $i < 100;) {  	my $conflicting = get_label($label, $bootloader);  	$to_add->{label} = $label; @@ -643,18 +815,6 @@ sub _do_the_symlink {        or cp_af("$::prefix/boot/$long_name", "$::prefix$link");  } -sub cmp_kernel_versions { -    my ($va, $vb) = @_; -    my $rel_a = $va =~ s/-(.*)$// && $1; -    my $rel_b = $vb =~ s/-(.*)$// && $1; -    ($va, $vb) = map { [ split /[.-]/ ] } $va, $vb; -    my $r = 0; -    mapn_ { -	$r ||= $_[0] <=> $_[1]; -    } $va, $vb; -    $r || $rel_a <=> $rel_b || $rel_a cmp $rel_b; -} -  # for lilo & xen  sub get_mbootpack_filename {      my ($entry) = @_; @@ -715,15 +875,10 @@ sub add_kernel {  	    #- perImageAppend contains resume=/dev/xxx which we don't want  	    @$dict = grep { $_->[0] ne 'resume' } @$dict;  	} -	if (-e "$::prefix/sbin/udev" && cmp_kernel_versions($kernel_str->{version_no_ext}, '2.6.8') >= 0) { -	    log::l("it is a recent kernel, so we remove any existing devfs= kernel option to enable udev"); -	    @$dict = grep { $_->[0] ne 'devfs' } @$dict; -	}  	$v->{append} = pack_append($simple, $dict);      } -    #- new versions of yaboot do not handle symlinks -    $b_nolink ||= arch() =~ /ppc/; +    $b_no_initrd //= arch() =~ /arm/;      $b_nolink ||= $kernel_str->{use_long_name}; @@ -742,17 +897,23 @@ sub add_kernel {      if (!$b_nolink) {  	$v->{kernel_or_dev} = '/boot/' . kernel_str2vmlinuz_short($kernel_str); -	_do_the_symlink($bootloader, $v->{kernel_or_dev}, $vmlinuz_long); +	    _do_the_symlink($bootloader, $v->{kernel_or_dev}, $vmlinuz_long);  	if ($v->{initrd}) {  	    $v->{initrd} = '/boot/' . kernel_str2initrd_short($kernel_str); -	    _do_the_symlink($bootloader, $v->{initrd}, $initrd_long); +		_do_the_symlink($bootloader, $v->{initrd}, $initrd_long);  	}      }      add_entry($bootloader, $v);  } +=item rebuild_initrds($bootloader) + +Rebuilds all initrds + +=cut +  sub rebuild_initrds {      my ($bootloader) = @_; @@ -868,7 +1029,12 @@ sub set_append_netprofile {      $e->{append} = pack_append($simple, $dict);  } -# used when a bootloader $entry has been modified (eg: $entry->{vga}) +=item configure_entry($bootloader, $entry) + +Used when a bootloader $entry has been modified (eg: $entry->{vga}) + +=cut +  sub configure_entry {      my ($bootloader, $entry) = @_;      $entry->{type} eq 'image' or return; @@ -886,24 +1052,18 @@ sub get_kernels_and_labels_before_kernel_remove {      map { kernel_str2label($_) => $_ } get_kernel_labels(\@kernels);  } -sub get_kernels_and_labels { -    my ($b_prefer_24) = @_; -    get_kernel_labels([ installed_vmlinuz() ], $b_prefer_24); +sub get_kernels_and_labels() { +    get_kernel_labels([ installed_vmlinuz() ]);  }  sub get_kernel_labels { -    my ($kernels, $b_prefer_24) = @_; +    my ($kernels) = @_;      my @kernels_str =  -      sort { cmp_kernel_versions($b->{version_no_ext}, $a->{version_no_ext}) }  +      sort { common::cmp_kernel_versions($b->{version_no_ext}, $a->{version_no_ext}) }         grep { -d "$::prefix/lib/modules/$_->{version}" }        map { vmlinuz2kernel_str($_) } @$kernels; -    if ($b_prefer_24) { -	my ($kernel_24, $other) = partition { $_->{ext} eq '' && $_->{version} =~ /^\Q2.4/ } @kernels_str; -	@kernels_str = (@$kernel_24, @$other); -    } -      my %labels;      foreach (@kernels_str) {  	if ($labels{$_->{ext}}) { @@ -930,12 +1090,6 @@ sub short_ext {      $short_ext || $kernel_str->{ext};  } -# deprecated, only for compatibility (nov 2007) -sub sanitize_ver {     -    my ($_name, $kernel_str) = @_; -    _sanitize_ver($kernel_str); -} -  sub _sanitize_ver {      my ($kernel_str) = @_; @@ -959,11 +1113,16 @@ sub _sanitize_ver {      $return;  } -# for lilo +=item suggest_message_text($bootloader) + +Provides a description text for Lilo + +=cut +  sub suggest_message_text {      my ($bootloader) = @_; -    if (!$bootloader->{message} && !$bootloader->{message_text} && arch() !~ /ia64/) { +    if (!$bootloader->{message} && !$bootloader->{message_text}) {  	my $msg_en =  #-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)  N_("Welcome to the operating system chooser! @@ -973,7 +1132,7 @@ wait for default boot.  ");  	my $msg = translate($msg_en); -	#- use the english version if more than 40% of 8bits chars +	#- use the English version if more than 40% of 8bits chars  	#- else, use the translation but force a conversion to ascii  	#- to be sure there won't be undisplayable characters  	if (int(grep { $_ & 0x80 } unpack "c*", $msg) / length($msg) > 0.4) { @@ -991,11 +1150,9 @@ sub suggest {      my $root_part = fs::get::root($fstab);      my $root = isLoopback($root_part) ? '/dev/loop7' : fs::wild_device::from_part('', $root_part);      my $boot = fs::get::root($fstab, 'boot')->{device}; -    #- PPC xfs module requires enlarged initrd -    my $xfsroot = $root_part->{fs_type} eq 'xfs';      my $mbr; -    # If installing onto an USB drive, put the mbr there, else on the first non removable drive +    # If installing onto an USB drive, put the MBR there, else on the first non removable drive      if ($root_part->{is_removable}) {          $mbr = fs::get::part2hd($root_part, $all_hds);      } else { @@ -1003,33 +1160,18 @@ sub suggest {      }      my ($onmbr, $unsafe) = $bootloader->{crushMbr} ? (1, 0) : suggest_onmbr($mbr); -    add2hash_($bootloader, arch() =~ /ppc/ ? -	{ -	 defaultos => "linux", -	 entries => [], -	 'init-message' => "Welcome to Mandriva Linux!", -	 delay => 30,	#- OpenFirmware delay -	 timeout => 50, -	 enableofboot => 1, -	 enablecdboot => 1, -	   if_(detect_devices::get_mac_model() =~ /IBM/, -	 boot => "/dev/sda1", -           ), -	 xfsroot => $xfsroot, -	} : +    add2hash_($bootloader,  	{  	 bootUnsafe => $unsafe,  	 entries => [],  	 timeout => $onmbr && 10,  	 nowarn => 1, -	   if_(arch() !~ /ia64/,  	 boot => "/dev/" . ($onmbr ? $mbr->{device} : $boot),  	 map => "/boot/map",  	 compact => 1,      	 'large-memory' => 1,  	 color => 'black/cyan yellow/cyan',  	 'menu-scheme' => 'wb:bw:wb:bw' -         ),  	});      suggest_message_text($bootloader); @@ -1042,6 +1184,7 @@ sub suggest {      }      my @kernels = get_kernels_and_labels() or die "no kernel installed"; +    log::l("found kernels: ", join(', ', map { $_->{version} } @kernels));      my %old_kernels = map { vmlinuz2version($_->{kernel_or_dev}) => 1 } @{$bootloader->{entries}};      @kernels = grep { !$old_kernels{$_->{version}} } @kernels; @@ -1054,7 +1197,8 @@ sub suggest {  	       {  		root => $root,  		if_($options{vga_fb}, vga => $options{vga_fb}), #- using framebuffer -		if_($options{vga_fb} && $options{quiet}, append => "splash=silent"), +		if_($options{vga_fb} && $options{splash}, append => "splash noiswmd"), +		if_($options{quiet}, append => "splash quiet noiswmd"),  	       });  	if ($options{vga_fb} && $e->{label} eq 'linux') { @@ -1063,19 +1207,9 @@ sub suggest {      }      add_kernel($bootloader, $kernels[0], -	       { root => $root, label => 'failsafe', append => 'failsafe' }) +	       { root => $root, label => 'failsafe', append => 'failsafe noiswmd' })        if @kernels; -    if (arch() =~ /ppc/) { -	#- if we identified a MacOS partition earlier - add it -	if (defined $partition_table::mac::macos_part) { -	    add_entry($bootloader, -		      { -		       type => "macos", -		       kernel_or_dev => $partition_table::mac::macos_part -		      }); -	} -    } elsif (arch() !~ /ia64/) {  	#- search for dos (or windows) boot partition. Do not look in extended partitions!  	my @windows_boot_parts =  	  grep { $_->{active} @@ -1094,7 +1228,6 @@ sub suggest {  		       makeactive => 1,  		      });  	} @windows_boot_parts; -    }      my @preferred = map { "linux-$_" } 'p3-smp-64GB', 'secure', 'enterprise', 'smp', 'i686-up-4GB';      if (my $preferred = find { get_label($_, $bootloader) } @preferred) { @@ -1105,13 +1238,27 @@ sub suggest {  				    method_choices($all_hds, 0)); # or best if no valid one is installed      if (main_method($bootloader->{method}) eq 'grub') { +	my %processed_entries = {};  	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}, -	    }); +	    my %h = ( +		     type => 'grub_configfile', +		     label => $c->{name}, +		     kernel_or_dev => "/dev/$c->{bootpart}{device}", +		     configfile => $c->{grub_conf}, +		    ); +	    if ($c->{root}) { +		my $key = "$c->{name} - $c->{linux} - $c->{initrd}"; +		next if $processed_entries{$key}; +		$processed_entries{$key} = 1; +		add_entry($bootloader, { +		    %h, +		    linux => $c->{linux}, +		    initrd => $c->{initrd}, +		    root => $c->{root}, +		}); +	    } else { +		add_entry($bootloader, \%h); +	    }  	}      }  } @@ -1144,26 +1291,50 @@ sub method2text {      my ($method) = @_;      +{  	'lilo-menu'    => N("LILO with text menu"), +	'grub2-graphic' => N("GRUB2 with graphical menu"), +	'grub2'        => N("GRUB2 with text menu"),  	'grub-graphic' => N("GRUB with graphical menu"),  	'grub-menu'    => N("GRUB with text menu"), -	'yaboot'       => N("Yaboot"), -	'silo'         => N("SILO"),      }->{$method};  } + +=item method_choices_raw($b_prefix_mounted) + +Returns list of bootloaders. + +method_choices_raw(1) will return the list of installed boot loaders. + +method_choices_raw(0) will return the list of all boot loaders supported by drakboot. + +Returns: ("grub2", "grub2-graphic") + +=cut +  sub method_choices_raw {      my ($b_prefix_mounted) = @_;      detect_devices::is_xbox() ? 'cromwell' : -    arch() =~ /ppc/ ? 'yaboot' :  -    arch() =~ /ia64/ ? 'lilo' :  -    arch() =~ /sparc/ ? 'silo' :  -      ( -       if_(!$b_prefix_mounted || whereis_binary('grub', $::prefix),  +    arch() =~ /arm/ ? 'uboot' : +       if_(!$b_prefix_mounted || whereis_binary('grub2-reboot', $::prefix),  +	   'grub2-graphic', 'grub2'), +      # only grub2 works on UEFI: +      # lilo & grub-legacy do not suppport new ext4/xfs format and are unmainted so only allow them on upgrade: +      if_(!is_uefi() && !($::isInstall && !$::o->{isUpgrade}), ( +       if_(!$b_prefix_mounted || whereis_binary('grub', $::prefix) && -f "$::prefix/boot/grub/install.sh",   	   'grub-graphic', 'grub-menu'), -       if_(!$b_prefix_mounted || whereis_binary('lilo', $::prefix),  +       if_(!$b_prefix_mounted || whereis_binary('lilo', $::prefix) && -f "$::prefix/etc/lilo.conf",   	   'lilo-menu'), -      ); +      ));  } + +=item method_choices($all_hds, $b_prefix_mounted) + +Returns list of supported bootloaders according to what is detected. + +Like method_choices_raw(), the $b_prefix_mounted parameter enables to return the list of either installed supported methods or the list of all supported boot loaders. + +=cut +  sub method_choices {      my ($all_hds, $b_prefix_mounted) = @_;      my $fstab = [ fs::get::fstab($all_hds) ]; @@ -1172,11 +1343,20 @@ sub method_choices {      my $have_dmraid = find { fs::type::is_dmraid($_) } @{$all_hds->{hds}};      grep { -	!(/lilo/ && (isLoopback($root_part) || $have_dmraid)) -	  && !(/grub/ && isRAID($boot_part)) -	  && !(/grub-graphic/ && cat_("/proc/cmdline") =~ /console=ttyS/); +	!(/lilo/ && (isLoopback($root_part) || $have_dmraid))			# LILO doesn't work fake raid +	  && (/grub2/ || $boot_part->{fs_type} ne 'btrfs')			# Only grub2 works on btrfs +	  && !(/grub2?-graphic/ && cat_("/proc/cmdline") =~ /console=ttyS/);	# No Gfx mode on console      } method_choices_raw($b_prefix_mounted);  } + +=item main_method_choices($b_prefix_mounted) + +Returns list of supported bootloaders, not distinging text/gfx mode. + +Like method_choices_raw(), the $b_prefix_mounted parameter enables to return the list of either installed supported methods or the list of all supported boot loaders. + +=cut +  sub main_method_choices {      my ($b_prefix_mounted) = @_;      uniq(map { main_method($_) } method_choices_raw($b_prefix_mounted)); @@ -1199,125 +1379,23 @@ sub keytable {      -r "$::prefix/$f" && $f;  } - -sub create_link_source() { -    #- we simply do it for all kernels :) -    #- so this can be used in %post of kernel and also of kernel-source -    foreach (all("$::prefix/usr/src")) { -	my ($version) = /^linux-(\d+\.\d+.*)/ or next; -	foreach (glob("$::prefix/lib/modules/$version*")) { -	    -d $_ or next; -	    log::l("creating symlink $_/build"); -	    symlink "/usr/src/linux-$version", "$_/build"; -	    log::l("creating symlink $_/source"); -	    symlink "/usr/src/linux-$version", "$_/source"; -	} -    } -} - -sub dev2yaboot { -    my ($dev) = @_; - -    devices::make("$::prefix$dev"); #- create it in the chroot - -    my $of_dev; -    run_program::rooted_or_die($::prefix, "/usr/sbin/ofpath", ">", \$of_dev, $dev); -    chomp($of_dev); -    log::l("OF Device: $of_dev"); -    $of_dev; -} -  sub check_enough_space() {      my $e = "$::prefix/boot/.enough_space";      output $e, 1; -s $e or die N("not enough room in /boot");      unlink $e;  } -sub write_yaboot { -    my ($bootloader, $all_hds) = @_; - -    my $fstab = [ fs::get::fstab($all_hds) ];  - -    my $file2yaboot = sub { -	my ($part, $file) = fs::get::file2part($fstab, $_[0]); -	dev2yaboot('/dev/' . $part->{device}) . "," . $file; -    }; - -    #- do not write yaboot.conf for old-world macs -    my $mac_type = detect_devices::get_mac_model(); -    return if $mac_type =~ /Power Macintosh/; - -    $bootloader->{prompt} ||= $bootloader->{timeout}; - -    if ($bootloader->{message_text}) { -	eval { output("$::prefix/boot/message", $bootloader->{message_text}) } -	  and $bootloader->{message} = '/boot/message'; -    } - -    my @conf; - -    if (!get_label($bootloader->{default}, $bootloader)) { -	log::l("default bootloader entry $bootloader->{default} is invalid, choosing another one"); -	$bootloader->{default} = $bootloader->{entries}[0]{label}; -    } -    push @conf, "# yaboot.conf - generated by DrakX/drakboot"; -    push @conf, "# WARNING: do not forget to run ybin after modifying this file\n"; -    push @conf, "default=" . make_label_lilo_compatible($bootloader->{default}) if $bootloader->{default}; -    push @conf, sprintf('init-message="\n%s\n"', $bootloader->{'init-message'}) if $bootloader->{'init-message'}; - -    if ($bootloader->{boot}) { -	push @conf, "boot=$bootloader->{boot}"; -	push @conf, "ofboot=" . dev2yaboot($bootloader->{boot}) if $mac_type !~ /IBM/; -    } else { -	die "no bootstrap partition defined."; -    } - -    push @conf, map { "$_=$bootloader->{$_}" } grep { $bootloader->{$_} } (qw(delay timeout), if_($mac_type !~ /IBM/, 'defaultos')); -    push @conf, "install=/usr/lib/yaboot/yaboot"; -    if ($mac_type =~ /IBM/) { -	push @conf, 'nonvram'; -    } else { -	push @conf, 'magicboot=/usr/lib/yaboot/ofboot'; -	push @conf, grep { $bootloader->{$_} } qw(enablecdboot enableofboot); -    } -    foreach my $entry (@{$bootloader->{entries}}) { - -	if ($entry->{type} eq "image") { -	    push @conf, "$entry->{type}=" . $file2yaboot->($entry->{kernel_or_dev}); -	    my @entry_conf; -	    push @entry_conf, "label=" . make_label_lilo_compatible($entry->{label}); -	    push @entry_conf, "root=$entry->{root}"; -	    push @entry_conf, "initrd=" . $file2yaboot->($entry->{initrd}) if $entry->{initrd}; -	    #- xfs module on PPC requires larger initrd - say 6MB? -	    push @entry_conf, "initrd-size=6144" if $bootloader->{xfsroot}; -	    push @entry_conf, qq(append=" $entry->{append}") if $entry->{append}; -	    push @entry_conf, grep { $entry->{$_} } qw(read-write read-only); -	    push @conf, map { "\t$_" } @entry_conf; -	} else { -	    my $of_dev = dev2yaboot($entry->{kernel_or_dev}); -	    push @conf, "$entry->{type}=$of_dev"; -	} -    } -    my $f = "$::prefix/etc/yaboot.conf"; -    log::l("writing yaboot config to $f"); -    renamef($f, "$f.old"); -    output($f, map { "$_\n" } @conf); +sub install_uboot {  +    my ($_bootloader, $_all_hds) = @_; +    log::l("uboot - nothing to install...");  } - -sub install_yaboot { -    my ($bootloader, $all_hds) = @_; -    log::l("Installing boot loader..."); -    write_yaboot($bootloader, $all_hds); -    when_config_changed_yaboot($bootloader); +sub write_uboot {  +    my ($_bootloader, $_all_hds) = @_; +    log::l("uboot - nothing to write...");  } -sub when_config_changed_yaboot { -    my ($bootloader) = @_; -    $::testing and return; -    if (defined $partition_table::mac::new_bootstrap) { -	run_program::run("hformat", $bootloader->{boot}) or die "hformat failed"; -    }	 -    my $error; -    run_program::rooted($::prefix, "/usr/sbin/ybin", "2>", \$error) or die "ybin failed: $error"; +sub when_config_changed_uboot { +    my ($_bootloader) = @_; +    #- do not do anything  }  sub install_cromwell {  @@ -1330,7 +1408,7 @@ sub write_cromwell {  }  sub when_config_changed_cromwell {      my ($_bootloader) = @_; -    log::l("XBox/Cromwell - nothing to do..."); +    #- do not do anything  }  sub simplify_label { @@ -1519,7 +1597,7 @@ sub install_raw_lilo {  sub when_config_changed_lilo {      my ($bootloader) = @_; -    if (!$::testing && arch() !~ /ia64/ && $bootloader->{method} =~ /lilo/) { +    if (!$::testing && $bootloader->{method} =~ /lilo/) {  	log::l("Installing boot loader on $bootloader->{boot}...");  	install_raw_lilo($bootloader->{force_lilo_answer});      } @@ -1602,8 +1680,14 @@ sub write_grub_device_map {  	   (map_index { "(hd$::i) /dev/$_->{device}\n" } @$sorted_hds));  } -# parses things like "(hd0,4)/boot/vmlinuz" -# returns: ("hd0", 4, "boot/vmlinuz") +=item parse_grub_file($grub_file) + +Parses things like "C<(hd0,4)/boot/vmlinuz>" + +Returns: ("hd0", 4, "boot/vmlinuz") + +=cut +  sub parse_grub_file {      my ($grub_file) = @_;      my ($grub_dev, $rel_file) = $grub_file =~ m!\((.*?)\)/?(.*)! or return; @@ -1611,8 +1695,14 @@ sub parse_grub_file {      ($hd, $part, $rel_file);  } -# takes things like "(hd0,4)/boot/vmlinuz" -# returns: ("/dev/sda5", "boot/vmlinuz") +=item grub2dev_and_file($grub_file, $grub2dev, $o_block_device) + +Takes things like "C<(hd0,4)/boot/vmlinuz>" + +Returns: ("/dev/sda5", "boot/vmlinuz") + +=cut +  sub grub2dev_and_file {      my ($grub_file, $grub2dev, $o_block_device) = @_;      my ($hd, $part, $rel_file) = parse_grub_file($grub_file) or return; @@ -1621,16 +1711,34 @@ sub grub2dev_and_file {      my $device = '/dev/' . ($part eq '' ? $grub2dev->{$hd} : devices::prefix_for_dev($grub2dev->{$hd}) . $part);      $device, $rel_file;  } -# takes things like "(hd0,4)/boot/vmlinuz" -# returns: "/dev/sda5" + +=item grub2devd($grub_file, $grub2dev, $o_block_device) + +Takes things like "C<(hd0,4)/boot/vmlinuz>" + +Returns: "/dev/sda5" + +=cut +  sub grub2dev {      my ($grub_file, $grub2dev, $o_block_device) = @_;      first(grub2dev_and_file($grub_file, $grub2dev, $o_block_device));  } -# replaces -# - "/vmlinuz" with "/boot/vmlinuz" when "root" or "rootnoverify" is set for the entry -# - "(hdX,Y)" in "(hdX,Y)/boot/vmlinuz..." by appropriate path if possible/needed +=item grub2file($grub_file, $grub2dev, $fstab, $o_entry) + +Replaces + +=over 4 + +=item * "C</vmlinuz>" with "C</boot/vmlinuz>" when "root" or "rootnoverify" is set for the entry + +=item * "C<(hdX,Y)>" in "C<(hdX,Y)/boot/vmlinuz...>" by appropriate path if possible/needed + +=back + +=cut +  sub grub2file {      my ($grub_file, $grub2dev, $fstab, $o_entry) = @_; @@ -1703,6 +1811,130 @@ sub crypt_grub_password {      chomp_($res);  } +sub get_grub2_first_entry { +    my ($bootloader) = @_; +    # set default parameters: +    my ($entry) = grep { $_->{kernel_or_dev} =~ /vmlin/ } @{$bootloader->{entries}}; +    $entry; +} + +sub get_grub2_append { +    my ($bootloader) = @_; +    # get default parameters from first entry: +    my ($entry) = get_grub2_first_entry($bootloader); +    my $append = $entry->{append}; +    if (my $vga = $entry->{vga} || $bootloader->{vga}) { +	$append .= " vga=$vga"; +    } +    $append =~ s/root=\S+//g; +    $append =~ s/\bro\b//g; +    $append =~ s/\s+/ /g; +    $append; +} + +sub crypt_grub2_password { +    my ($password) = @_; +    require IPC::Open2; +    local $ENV{LC_ALL} = 'C'; +    my ($his_out, $his_in); +    my $pid = IPC::Open2::open2($his_out, $his_in, "$::prefix/bin/grub2-mkpasswd-pbkdf2"); + +    my ($line, $res); +    while (sysread($his_out, $line, 100)) { +        if ($line =~ /enter.*password:/i) { +            syswrite($his_in, "$password\n"); +        } else { +            chomp($line); +            $res .= $line if $line; +        } +    } +    $res =~ s/^PBKDF2 hash of your password is //; +    waitpid($pid, 0); +    my $status = $? >> 8; +    die "failed to encrypt password (status=$status)" if $status != 0; +    chomp_($res); +} + +sub write_grub2_sysconfig { +    my ($bootloader, $_all_hds, $o_backup_extension) = @_; + +    # Set password prior to run update-grub2: +    my $pw_f = get_grub2_users(); +    if ($bootloader->{password}) { +	if (!is_grub2_already_crypted($bootloader->{password})) { +	    $bootloader->{password} = crypt_grub2_password($bootloader->{password}); +        } +	output_with_perm($pw_f, 0600, "GRUB2_PASSWORD=$bootloader->{password}"); +    } else { +	unlink($pw_f); +    } + +    my $f = "$::prefix/etc/default/grub"; +    my %conf = getVarsFromSh($f); + +    $conf{GRUB_CMDLINE_LINUX_DEFAULT} = $bootloader->{default_append} || get_grub2_append($bootloader); +    $conf{GRUB_GFXPAYLOAD_LINUX} = 'auto' if is_uefi(); +    $conf{GRUB_DISABLE_RECOVERY} = 'false'; # for 'failsafe' entry +    $conf{GRUB_DEFAULT} ||= 'saved'; # for default entry but do not overwrite user choice +    $conf{GRUB_SAVEDEFAULT} ||= 'true'; # for default entry but do not overwrite user choice +    $conf{GRUB_TIMEOUT} = $bootloader->{timeout}; +    renamef($f, $f . ($o_backup_extension || '.old')); +    setVarsInSh($f, \%conf); +} + +sub write_grub2_default_entry { +    my ($bootloader, $_all_hds, $o_backup_extension) = @_; + +    my $default = $bootloader->{default}; +    # menu entry must be identified by its full path. eg: "submenu1>submenu2>title": +    if (my $def = find { $_->{label} eq $bootloader->{default} } @{$bootloader->{entries}}) { +	$default = $def->{real_label} if $def->{real_label}; +    } + +    # set default entry: +    eval { +	my $f2 = "$::prefix/boot/grub2/grubenv"; +	cp_af($f2, $f2 . ($o_backup_extension || '.old')); +	my $error; +	run_program::rooted($::prefix, 'grub2-set-default', '2>', \$error, $default) or die "grub2-set-default failed: $error"; +    }; +    if (my $err = $@) { +	log::l("error while running grub2-set-default: $err"); +    } +} + +sub write_grub2() { +    my $error; + +    my $f1 = "$::prefix/boot/grub2/grub.cfg"; +    renamef($f1, $f1 . '.old'); +    run_program::rooted($::prefix, 'update-grub2', '2>', \$error) or die "update-grub2 failed: $error"; +    log::l("update-grub2 logs: $error"); + +    check_enough_space(); +} + +sub get_grub2_users() { +    "$::prefix/boot/grub2/user.cfg"; +} + +sub get_grub2_install_sh() { +    "$::prefix/boot/grub2/install.sh"; +} + +sub write_grub2_install_sh    { +    my ($bootloader, $o_backup_extension) = @_; +    my $f = get_grub2_install_sh(); +    my $boot = $bootloader->{boot}; +    my @options; +    if (is_uefi()) { +	push @options, qw(--bootloader-id=tmp --no-nvram) if $bootloader->{no_esp_or_mbr}; +    } else { +	@options = $bootloader->{no_esp_or_mbr} ? ('--grub-setup=/bin/true', $boot) : $boot; +    } +    renamef($f, $f . ($o_backup_extension || '.old')); +    output_with_perm($f, 0755, join(' ', 'grub2-install', @options)); +}  sub write_grub {      my ($bootloader, $all_hds, $o_backup_extension) = @_; @@ -1735,7 +1967,7 @@ sub write_grub {  	$bootloader->{terminal} ||= "--timeout=" . ($bootloader->{timeout} || 0) . " console serial";      } elsif ($bootloader->{method} eq 'grub-graphic') {  	my $bin = '/usr/sbin/grub-gfxmenu'; -	if ($bootloader->{gfxmenu} eq '' && -x "$::prefix/usr/sbin/grub-gfxmenu") { +	if ($bootloader->{gfxmenu} eq '' && -x "$::prefix$bin") {  	    my $locale = $::o->{locale} || do { require lang; lang::read() };  	    run_program::rooted($::prefix, $bin, '--lang', $locale->{lang}, '--update-gfxmenu');  	    $bootloader->{gfxmenu} ||= '/boot/gfxmenu'; @@ -1786,7 +2018,18 @@ sub write_grub {  		       if_($entry->{'read-write'}, 'rw'),  		       if_($vga && $vga ne "normal", "vga=$vga"));  		push @conf, "module " . $_ foreach @{$entry->{modules} || []}; -		push @conf, join(' ', $entry->{xen} ? 'module' : 'initrd', $file2grub->($entry->{initrd})) if $entry->{initrd}; +		if ($entry->{initrd}) { +		    # split partition from initrd path and place +		    # it to a separate 'root' entry. +		    # Grub2's mkconfig takes initrd entry 'as is', +		    # but grub2 fails to load smth like '(hd0,1)/boot/initrd' taken from grub-legacy +		    my $initrd_path = $file2grub->($entry->{initrd}); +		    if ($initrd_path =~ /^(\([^\)]+\))/) { +			push @conf, "root $1"; +			$initrd_path =~ s/^(\([^\)]+\))//; +		    } +		    push @conf, join(' ', $entry->{xen} ? 'module' : 'initrd', $initrd_path); +		}  	    } else {  		my $dev = eval { device_string2grub($entry->{kernel_or_dev}, \@legacy_floppies, \@sorted_hds) };  		if (!$dev) { @@ -1795,7 +2038,9 @@ sub write_grub {  		}  		push @conf, $title;  		push @conf, grep { $entry->{$_} } 'lock'; -		push @conf, join(' ', $entry->{rootnoverify} ? 'rootnoverify' : 'root', $dev); +		if ($entry->{type} ne 'grub_configfile' || $entry->{configfile} !~ /grub\.cfg/ || !$entry->{root}) { +		    push @conf, join(' ', $entry->{rootnoverify} ? 'rootnoverify' : 'root', $dev); +		}  		if ($entry->{table}) {  		    if (my $hd = fs::get::device2part($entry->{table}, \@sorted_hds)) { @@ -1810,8 +2055,12 @@ sub write_grub {  		    push @conf, map_each { "map ($::b) ($::a)" } %{$entry->{mapdrive}};  		}  		push @conf, "makeactive" if $entry->{makeactive}; -		if ($entry->{type} eq 'grub_configfile') { +		# grub.cfg is grub2 config, can't use it as configfile for grub-legacy +		if ($entry->{type} eq 'grub_configfile' && $entry->{configfile} !~ /grub\.cfg/) {  		    push @conf, "configfile $entry->{configfile}"; +		} elsif ($entry->{linux}) { +		    push @conf, "root $entry->{root}", "kernel $entry->{linux}"; +		    push @conf, "initrd $entry->{initrd}" if $entry->{initrd};  		} else {  		    push @conf, "chainloader +1";  		} @@ -1878,6 +2127,24 @@ sub restore_previous_MBR_bootloader {      output($dev, scalar cat_(_dev_to_MBR_backup($dev)));  } +sub install_grub2 { +    my ($bootloader, $all_hds) = @_; +    write_grub2_sysconfig($bootloader, $all_hds); +    write_grub2(); +    write_grub2_default_entry($bootloader, $all_hds); +    write_grub2_install_sh($bootloader, '.old'); +    install_raw_grub2(); +} + +sub install_raw_grub2() { +    my $error; +    my $f = '/boot/grub2/install.sh'; +    if (!run_program::rooted($::prefix, "sh", "2>", \$error, $f)) { +	log::explanations("grub2-install failed:\n(" . cat_($f) . ")\nError: <$error>"); +	die "grub2-install failed: $error"; +    } +} +  sub install_grub {      my ($bootloader, $all_hds) = @_; @@ -1910,6 +2177,11 @@ sub install_raw_grub() {      run_program::rooted($::prefix, "sh", "2>", \$error, '/boot/grub/install.sh') or die "grub failed: $error";  } +sub when_config_changed_grub2 { +    my ($_bootloader) = @_; +    #- do not do anything +} +  sub when_config_changed_grub {      my ($_bootloader) = @_;      #- do not do anything @@ -1917,6 +2189,16 @@ sub when_config_changed_grub {      update_copy_in_boot($_) foreach glob($::prefix . boot_copies_dir() . '/*.link');  } +=item action($bootloader, $action, @para) + +Calls the C<$action> function with @para parameters: + +   $actions->($bootloader, @para) + +If needed, the function name will be resolved to call a boot loader specific function (eg: for LILO/GRUB/...) + +=cut +  sub action {      my ($bootloader, $action, @para) = @_; @@ -1925,30 +2207,85 @@ sub action {      $f->($bootloader, @para);  } +=item install($bootloader, $all_hds) + +Writes back the boot loader config. Calls the proper write_XYZ() function. + +=cut +  sub install {      my ($bootloader, $all_hds) = @_; -    if (my $part = fs::get::device2part($bootloader->{boot}, [ fs::get::fstab($all_hds) ])) { -	die N("You can not install the bootloader on a %s partition\n", $part->{fs_type}) -	  if $part->{fs_type} eq 'xfs'; -    } -    $bootloader->{keytable} = keytable($bootloader->{keytable}); +    $bootloader->{keytable} = keytable($bootloader->{keytable}) if $bootloader->{method} eq 'lilo';      action($bootloader, 'install', $all_hds);  }  sub ensure_pkg_is_installed {      my ($do_pkgs, $bootloader) = @_; +    my %suppl = ( +	# method => [ 'pkg_name', 'file_to_test' ], +	'grub-graphic' => [ qw(mageia-gfxboot-theme /usr/share/gfxboot/themes/Mageia/boot/message) ], +	'grub2-graphic' => [ qw(grub2-mageia-theme /boot/grub2/themes/maggy/theme.txt) ], +    );      my $main_method = main_method($bootloader->{method}); -    if ($main_method eq 'grub' || $main_method eq 'lilo') { +    if ($main_method eq 'grub2') { +	my $pkg = is_uefi() ? 'grub2-efi' : 'grub2'; +	my $prefix = is_uefi() ? (arch() eq 'x86_64' ? 'x86_64-efi' : 'i386-efi') : 'i386-pc'; +	$do_pkgs->ensure_is_installed($pkg, "/usr/lib/grub/$prefix/ext2.mod", 1) or return 0; +    } elsif (member($main_method, qw(grub grub2 lilo))) {  	$do_pkgs->ensure_binary_is_installed($main_method, $main_method, 1) or return 0; -	if ($bootloader->{method} eq 'grub-graphic') { -	    $do_pkgs->ensure_is_installed('mandriva-gfxboot-theme', '/usr/share/gfxboot/themes/Mandriva/boot/message', 1) or return 0; -	} +    } +    # Install gfx theme if needed: +    if (my $pkg = $suppl{$bootloader->{method}}) { +	$do_pkgs->ensure_is_installed(@$pkg, 1) or return 0;      }      1;  } +sub parse_grub2_config { +    my ($l, $grubcfg, $part) = @_; + +    my ($linux, $menuentry, $root, $root_dev, $initrd); + +    foreach (cat_($grubcfg)) { +	chomp; +	if (/^menuentry\s+['"]([^']+)["']/) { +	    if ($menuentry && $root) { +		my $parttype = partition_table::raw::typeOfMBR($root_dev); +		if ((!$parttype || $parttype eq "empty") && $linux) { +	    	    push @$l, { menuentry => $menuentry, bootpart => $part, root => $root, linux => $linux, initrd => $initrd, grub_conf => $grubcfg }; +		} +	    } +	    $menuentry = $1; +	    $root = $linux = undef; +	} elsif (/set root='(\([^\)]+\))'/) { +	    $root = $1; + +	    if ($root =~ /\(([^,]+),msdos(\d+)\)/) { +		my $dev_title = "/" . $1; +		my $part_num = $2; +		my $dec_part_num = $part_num-1; +		$dev_title =~ s!hd!dev/sd!; +		$dev_title =~ tr/0123456789/abcdefghi/; + +	        $root_dev = $part_num ? $dev_title . $part_num : $dev_title; +               $root =~ s/msdos$part_num/$dec_part_num/; +	    } +	} elsif (/^\s+linux\s+(.+)/) { +	    $linux = $1; +	} elsif (/^\s+initrd\s+(.+)/) { +	    $initrd = $1; +	} +    } +} + +=item find_other_distros_grub_conf($fstab) + +Returns a list of other distros' grub.conf + +=cut +  sub find_other_distros_grub_conf {      my ($fstab) = @_; @@ -1967,6 +2304,15 @@ sub find_other_distros_grub_conf {  	    my $f = find { -e "$handle->{dir}$bootdir/$_" } 'grub.conf', 'grub/menu.lst' or next;  	    push @l, { bootpart => $part, bootdir => $bootdir, grub_conf => "$bootdir/$f" };  	} +	foreach my $bootdir ('', '/boot', '/boot/grub', '/boot/grub2') { +	    my $f = find { -e "$handle->{dir}$bootdir/$_" } 'grub.cfg' or next; +	    my $parttype = partition_table::raw::typeOfMBR($part->{device}); +	    if (!$parttype || $parttype eq "empty") { +		parse_grub2_config(\@l, "$handle->{dir}/$bootdir/$f", $part); +	    } else { +	        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}; @@ -2063,10 +2409,14 @@ sub update_for_renumbered_partitions {      } $main_method ? $main_method : ('lilo', 'grub');      if (intersection(\@needed, [ map { $_->{name} } @changed_configs ])) { -	$in->ask_warn('', N("The bootloader can not be installed correctly. You have to boot rescue and choose \"%s\"",  +	$in->ask_warn('', N("The bootloader cannot be installed correctly. You have to boot rescue and choose \"%s\"",   			    N("Re-install Boot Loader")));      }      1;  } +=back + +=cut +  1;  | 
