summaryrefslogtreecommitdiffstats
path: root/perl-install/bootloader.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/bootloader.pm')
-rw-r--r--perl-install/bootloader.pm1197
1 files changed, 892 insertions, 305 deletions
diff --git a/perl-install/bootloader.pm b/perl-install/bootloader.pm
index d2761c016..d1d757c3d 100644
--- a/perl-install/bootloader.pm
+++ b/perl-install/bootloader.pm
@@ -1,4 +1,4 @@
-package bootloader; # $Id: bootloader.pm 267511 2010-04-12 12:34:45Z cfergeau $
+package bootloader;
use diagnostics;
use strict;
@@ -19,11 +19,73 @@ use partition_table::raw;
use run_program;
use modules;
-#-#####################################################################################
-#- Functions
-#-#####################################################################################
+=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);
+
+A particular bootloader is handled in separate typical functions that can be called by action() by /sbin/bootloader-config:
+
+
+=head1 VFS aka how to support a bootloader
+
+Most of the code is generic.
+
+A particular bootloader implementation/support is done through a couple functions:
+
+=over 4
+
+=item * read_FOOBAR()
+
+read the config file(s) of the FOOBAR bootloader, returning a $bootloader object
+
+=item * install_FOOBAR($bootloader, $all_hds)
+
+usually call write_FOOBAR() & install_raw_FOOBAR() if existing, aka:
+
+=over 4
+
+=item * updating config files
+
+=item * then reinstalling the bootloader
+
+=back
+
+=item * install_raw_FOOBAR()
+
+Optionnal: Low level installation of the stage1 of the bootloader, usually embedding it in MBR or on ESP, ... (eg: running lilo or /boot/grub*/install.sh)
+
+=item * write_FOOBAR($bootloader, $all_hds)
+
+update the config files, ie when a kernel was installed or removed.
+when_config_changed_FOOBAR() is called right after in case something is needed when config is done (eg: lilo needs to be reinstalled)
+
+=item * when_config_changed_FOOBAR()
+
+Run needed action when config has changed or when initrds were regenerated, ...
+Usually nothing for intelligent bootloaders such as grub-legacy or grub2.
+But eg: lilo needs to rewrite its stage1 (thus it needs to rerun lilo).
+
+=back
+
+=head1 Functions
+
+=over
+
+=cut
+
my $vmlinuz_regexp = 'vmlinu[xz]|win4lin|uImage';
my $decompose_vmlinuz_name = qr/((?:$vmlinuz_regexp).*?)-(\d+\.\d+.*)/;
+my $liblinux_path = '/usr/lib/linux';
sub expand_vmlinuz_symlink {
my ($vmlinuz) = @_;
@@ -57,7 +119,7 @@ sub kernel_str2short_name {
sub basename2initrd_basename {
my ($basename) = @_;
- $basename =~ s!(vmlinu[zx]|uImage)-?!!; #- 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 {
@@ -68,6 +130,10 @@ sub kernel_str2initrd_long {
my ($kernel) = @_;
basename2initrd_basename(kernel_str2short_name($kernel)) . '-' . $kernel->{version} . '.img';
}
+sub kernel_str2liblinux_long {
+ my ($kernel) = @_;
+ $liblinux_path . '-' . $kernel->{version};
+}
sub kernel_str2vmlinuz_short {
my ($kernel) = @_;
if ($kernel->{use_long_name}) {
@@ -84,6 +150,9 @@ sub kernel_str2initrd_short {
basename2initrd_basename(kernel_str2short_name($kernel)) . '.img';
}
}
+sub kernel_str2liblinux_short() {
+ $liblinux_path;
+}
sub kernel_str2label {
my ($kernel, $o_use_long_name) = @_;
@@ -106,6 +175,12 @@ sub get_label {
undef;
}
+=item mkinitrd($kernel_version, $bootloader, $entry, $initrd)
+
+Regenerates kernel's initrd.
+
+=cut
+
sub mkinitrd {
my ($kernel_version, $bootloader, $entry, $initrd) = @_;
@@ -132,9 +207,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});
@@ -143,6 +221,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) = @_;
@@ -187,6 +272,12 @@ sub update_splash {
}
}
+=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) ];
@@ -194,7 +285,7 @@ sub read {
my $f = $bootloader::{"read_$main_method"} or die "unknown bootloader method $main_method (read)";
my $bootloader = $f->($fstab);
- cleanup_entries($bootloader);
+ cleanup_entries($bootloader) if $main_method ne 'refind';
# handle raid-extra-boot (lilo)
my @devs = $bootloader->{boot};
@@ -205,11 +296,21 @@ sub read {
@devs = split(',', $bootloader->{'raid-extra-boot'});
}
+ #- if $bootloader->{boot} is undefined, @devs contains a single undef element
my ($type) = map {
- if (m!/fd\d+$!) {
+ if (is_uefi()) {
+ if (-e "$::prefix/boot/refind_linux.conf") {
+ 'refind';
+ } elsif (-f "$::prefix/boot/EFI/EFI/mageia/grub" . uefi_type() . ".efi" ||
+ $main_method eq 'grub2' && $bootloader->{removable} && -f "$::prefix/boot/EFI/EFI/BOOT/BOOT" . uc(uefi_type()) . ".EFI") {
+ 'grub2';
+ } else {
+ ()
+ }
+ } elsif (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 pmon2000 uboot))) {
+ } elsif (member($main_method, qw(cromwell uboot))) {
#- not checking, there's only one bootloader anyway :)
$main_method;
} elsif (my $type = partition_table::raw::typeOfMBR($_)) {
@@ -219,43 +320,114 @@ sub read {
} @devs;
if ($type eq $main_method) {
+ 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}})) {
$bootloader->{default_options} = $default;
$bootloader->{perImageAppend} ||= $default->{append};
log::l("perImageAppend is now $bootloader->{perImageAppend}");
+ $bootloader->{default_vga} ||= $default->{vga};
+ log::l("default_vga is now $bootloader->{default_vga}");
} else {
$bootloader->{default_options} = {};
}
return $bootloader;
- }
- }
}
-sub read_grub2 {
- my %bootloader = getVarsFromSh("$::prefix/boot/grub2/drakboot.conf");
+
+=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() if -e get_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};
+ # keep suggested perImageAppend and default_vga on first run (during installer) or when migrating from grub-legacy or lilo:
+ my ($vga, $other) = partition { /^vga=/ } split(' ', $h{GRUB_CMDLINE_LINUX_DEFAULT});
+ $bootloader{perImageAppend} ||= join(' ', @$other) if @$other;
+ $bootloader{default_vga} ||= $vga->[0] =~ /vga=(.*)/ && $1 if @$vga;
$bootloader{entries} = [];
my $entry;
- foreach (cat_utf8("$::prefix/boot/grub2/grub.cfg")) {
+ my $f = "$::prefix/boot/grub2/grub.cfg";
+ my @menus;
+ foreach (cat_utf8($f)) {
next if /^#/;
if (/menuentry\s+['"]([^']+)["']/) {
- push @{$bootloader{entries}}, $entry if $entry;
- $entry = { label => $1 };
- } elsif (/linux\s+(\S+)\s+(.*)?/ || /module\s+(\S+vmlinu\S+)\s+(.*)?/) {
+ $entry = { label => $1, real_label => join('>', @menus, $1) };
+ } elsif (/linux(?:16)?\s+([^-]\S+)\s+(.*)?/ || /module\s+(\S+vmlinu\S+)\s+(.*)?/) {
$entry->{type} = 'image';
@$entry{qw(kernel_or_dev append)} = ($1, $2);
- } elsif (/initrd\s+(\S+)/ || /module\s+(\S+initrd\S+)\s+(.*)?/) {
+ my ($vga, $other) = partition { /^vga=/ } split(' ', $entry->{append});
+ if (@$vga) {
+ $entry->{vga} = $vga->[0] =~ /vga=(.*)/ && $1;
+ $entry->{append} = join(' ', @$other);
+ }
+ } elsif (/initrd(?:16)?\s+(\S+)/ || /module\s+(\S+initrd\S+)\s+(.*)?/) {
$entry->{initrd} = $1;
+ } elsif (/submenu\s+['"]([^']+)["']/) {
+ push @menus, $1;
+ } elsif (/^\s*}/) {
+ if ($entry) {
+ push @{$bootloader{entries}}, $entry;
+ undef $entry;
+ } else {
+ pop @menus;
+ }
}
}
- $bootloader{method} = 'grub2';
+ # 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{removable} = $s =~ m!--removable!;
+ %h;
+}
+
+=item read_grub($fstab)
+
+Reads back Grub Legacy config.
+
+=cut
+
sub read_grub {
my ($fstab) = @_;
@@ -272,10 +444,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) = @_;
@@ -302,6 +486,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;
@@ -367,11 +557,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) = @_;
@@ -427,50 +630,122 @@ sub read_grub_menu_lst {
\%b;
}
-sub yaboot2dev {
- my ($of_path) = @_;
- find { dev2yaboot($_) eq $of_path } map { "/dev/$_->{dev}" } fs::proc_partitions::read_raw();
+sub _parse_extlinux_conf() {
+ my $global = 1;
+ my ($e, %b);
+
+ my $f = "$::prefix/boot/extlinux/extlinux.conf";
+ -e $f or return;
+
+ foreach (cat_utf8($f)) {
+ chomp;
+ s/^\s*//; s/\s*$//;
+ next if /^#/ || /^$/;
+ my ($keyword, $v) = split('[ \t=]+', $_, 2) or
+ warn qq(unknown line in $f: "$_"\n), next;
+
+ $keyword = lc($keyword);
+
+ if ($keyword eq 'label') {
+ push @{$b{entries}}, $e = { label => $v };
+ $global = 0;
+ } elsif ($global) {
+ $b{$keyword} = $v;
+ } else {
+ if ($keyword eq 'kernel') {
+ $e->{type} = 'image';
+ $e->{kernel_or_dev} = $v;
+ } else {
+ $e->{$keyword} = $v;
+ }
+ }
+ }
+
+ %b;
+}
+
+sub read_uboot() {
+ my %b = _parse_extlinux_conf();
+
+ $b{method} = 'uboot';
+ $b{timeout} //= 30;
+
+ my $is_raspberry = cat_("/proc/device-tree/model") =~ /^Raspberry Pi/;
+ if ($is_raspberry) {
+ $b{perImageAppend} //= "8250.nr_uarts=1 console=ttyS0,115200 console=tty1 elevator=deadline cma=256M\@512M";
+ }
+
+ $b{perImageAppend} //= $b{entries}[0]{append};
+
+ \%b;
+}
+
+=item read_refind ($fstab)
+
+Read back rEFInd config + C</boot/refind_linux.conf>
+
+=cut
+
+sub read_refind() {
+ my %bootloader = (entries => []);
+ foreach (cat_utf8("$::prefix/boot/refind_linux.conf")) {
+ next if /^#/;
+ my ($label, $append) = /"(.*)"\s*"(.*)"/;
+ my $root = $1 if $append =~ s/root=(\S*)\s*//;
+ my $vga = $1 if $append =~ s/vga=(\S*)\s*//;
+ if ($label && $root) {
+ push @{$bootloader{entries}}, {
+ type => 'image',
+ kernel_or_dev => '/boot/vmlinuz',
+ label => $label,
+ root => $root,
+ append => $append,
+ vga => $vga
+ };
+ }
+ }
+ $bootloader{method} = 'refind';
+ read_refind_config(\%bootloader);
+ \%bootloader;
}
-# 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);
+sub read_refind_config {
+ my ($bootloader) = @_;
+
+ #- These are the rEFInd default values.
+ $bootloader->{use_nvram} = 1;
+ $bootloader->{banner_path} = '';
+ $bootloader->{banner_scale} = 'noscale';
+
+ if (-r "$::prefix/boot/EFI/EFI/refind/refind.conf") {
+ read_refind_conf($bootloader, "$::prefix/boot/EFI/EFI/refind/refind.conf");
+ } elsif (-r "$::prefix/boot/EFI/EFI/BOOT/refind.conf") {
+ read_refind_conf($bootloader, "$::prefix/boot/EFI/EFI/BOOT/refind.conf");
} else {
- yaboot2dev($of_path);
+ #- This is the preferred value if rEFInd is not yet installed,
+ $bootloader->{banner_path} = 'refind_banner.png';
}
}
-sub read_silo() {
- my $bootloader = read_lilo_like("/boot/silo.conf", sub {
- my ($f) = @_;
- "/boot$f";
- });
- $bootloader->{method} = 'silo';
- $bootloader;
+sub read_refind_conf {
+ my ($bootloader, $config_file) = @_;
+ foreach (cat_utf8($config_file)) {
+ if ($_ =~ /^\s*use_nvram\s+(false|off|0)/) {
+ $bootloader->{use_nvram} = 0;
+ } elsif ($_ =~ /^\s*banner\s+(\S*)/) {
+ $bootloader->{banner_path} = $1;
+ } elsif ($_ =~ /^\s*banner_scale\s+(\S*)/) {
+ $bootloader->{banner_scale} = $1;
+ }
+ }
}
# FIXME: actually read back previous conf
-sub read_pmon2000() {
- +{ method => 'pmon2000' };
-}
-sub read_uboot() {
- +{ method => 'uboot' };
-}
sub read_cromwell() {
+{ method => 'cromwell' };
}
-sub read_yaboot() {
- my $bootloader = read_lilo_like("/etc/yaboot.conf", \&yaboot2file);
- $bootloader->{method} = 'yaboot';
- $bootloader;
-}
sub read_lilo() {
my $bootloader = read_lilo_like("/etc/lilo.conf", sub { $_[0] });
@@ -583,16 +858,41 @@ sub suggest_onmbr {
($onmbr, $unsafe);
}
-# list of places where we can install the bootloader
+
+=item allowed_boot_disks($bootloader, $all_hds)
+
+Returns list of disks where we can install the bootloader when not in UEFI mode
+(accounting for misssing BIOS boot partitions on GPT disks)
+in UEFI mode, grub2 automatically look for the ESP).
+
+=cut
+
+sub allowed_boot_disks {
+ my ($all_hds) = @_;
+ # GPT disks w/o a BIOS boot partition do not have free space for grub2 to embed:
+ grep { $_->{pt_table_type} ne 'gpt' ||
+ any { isBIOS_GRUB($_) } map { partition_table::get_normal_parts($_) } $_;
+ } @{$all_hds->{hds}};
+}
+
+=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
+ allowed_boot_disks($all_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(),
);
}
@@ -624,7 +924,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;
@@ -758,10 +1058,6 @@ sub add_kernel {
$v->{append} = pack_append($simple, $dict);
}
- #- new versions of yaboot do not handle symlinks
- $b_nolink ||= arch() =~ /ppc/;
- $b_no_initrd //= arch() =~ /mips|arm/ && !detect_devices::is_mips_gdium();
-
$b_nolink ||= $kernel_str->{use_long_name};
#- do not link /boot/vmlinuz to xen
@@ -777,33 +1073,35 @@ sub add_kernel {
$v->{initrd} = mkinitrd($kernel_str->{version}, $bootloader, $v, "/boot/$initrd_long");
}
+ my $liblinux_long = kernel_str2liblinux_long($kernel_str);
+ if (-d "$::prefix$liblinux_long") {
+ $v->{liblinux} = $v->{fdtdir} = $liblinux_long;
+ }
+
if (!$b_nolink) {
$v->{kernel_or_dev} = '/boot/' . kernel_str2vmlinuz_short($kernel_str);
- if (arch() =~ /mips/) {
- log::l("link $::prefix/boot/$vmlinuz_long -> $::prefix$v->{kernel_or_dev}");
- linkf("$::prefix/boot/$vmlinuz_long", $::prefix . $v->{kernel_or_dev});
- linkf("$::prefix/boot/$vmlinuz_long", $::prefix . $v->{kernel_or_dev} . ".32");
- } else {
_do_the_symlink($bootloader, $v->{kernel_or_dev}, $vmlinuz_long);
- }
if ($v->{initrd}) {
$v->{initrd} = '/boot/' . kernel_str2initrd_short($kernel_str);
- if (arch() =~ /mips/) {
- log::l("link $::prefix/boot/$initrd_long -> $::prefix$v->{initrd}");
- linkf("$::prefix/boot/$initrd_long", $::prefix . $v->{initrd});
- if ($v->{initrd} =~ s/.img$/.gz/) {
- linkf("$::prefix/boot/$initrd_long", $::prefix . $v->{initrd});
- }
- } else {
_do_the_symlink($bootloader, $v->{initrd}, $initrd_long);
- }
+ }
+
+ if ($v->{liblinux}) {
+ $v->{liblinux} = kernel_str2liblinux_short();
+ _do_the_symlink($bootloader, $v->{liblinux}, basename($liblinux_long));
}
}
add_entry($bootloader, $v);
}
+=item rebuild_initrds($bootloader)
+
+Rebuilds all initrds
+
+=cut
+
sub rebuild_initrds {
my ($bootloader) = @_;
@@ -919,7 +1217,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;
@@ -967,20 +1270,12 @@ sub short_ext {
my ($kernel_str) = @_;
my $short_ext = {
- 'i586-up-1GB' => 'i586',
- 'i686-up-4GB' => '4GB',
'xen0' => 'xen',
}->{$kernel_str->{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) = @_;
@@ -988,27 +1283,25 @@ sub _sanitize_ver {
$name = '' if $name eq 'vmlinuz';
my $v = $kernel_str->{version_no_ext};
- if ($v =~ s/-\d+\.mm\././) {
- $name = join(' ', grep { $_ } $name, 'multimedia');
- }
$v =~ s!(md[kv]|mnb)$!!;
$v =~ s!-0\.(pre|rc)(\d+)\.!$1$2-!;
my $return = join(' ', grep { $_ } $name, short_ext($kernel_str), $v);
- length($return) < 30 or $return =~ s!secure!sec!;
- length($return) < 30 or $return =~ s!enterprise!ent!;
- length($return) < 30 or $return =~ s!multimedia!mm!;
-
$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!
@@ -1018,7 +1311,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) {
@@ -1036,45 +1329,28 @@ 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 {
- $mbr = find { !$_->{is_removable} } @{$all_hds->{hds}};
+ $mbr = find { !$_->{is_removable} } allowed_boot_disks($all_hds);
}
my ($onmbr, $unsafe) = $bootloader->{crushMbr} ? (1, 0) : suggest_onmbr($mbr);
- add2hash_($bootloader, arch() =~ /ppc/ ?
- {
- defaultos => "linux",
- entries => [],
- 'init-message' => "Welcome to %s!",
- 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);
@@ -1087,20 +1363,23 @@ 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;
#- remove existing failsafe and linux-nonfb, do not care if the previous one was modified by the user?
- @{$bootloader->{entries}} = grep { !member($_->{label}, qw(failsafe linux-nonfb)) } @{$bootloader->{entries}};
+ #- but only if we are going to add new ones.
+ @{$bootloader->{entries}} = grep { !member($_->{label}, qw(failsafe linux-nonfb)) } @{$bootloader->{entries}}
+ if @kernels;
foreach my $kernel (@kernels) {
my $e = add_kernel($bootloader, $kernel,
{
root => $root,
if_($options{vga_fb}, vga => $options{vga_fb}), #- using framebuffer
- if_($options{vga_fb} && $options{splash}, append => "splash"),
- if_($options{quiet}, append => "splash quiet"),
+ if_($options{vga_fb} && $options{splash}, append => "splash noiswmd audit=0"),
+ if_($options{quiet}, append => "splash quiet noiswmd audit=0"),
});
if ($options{vga_fb} && $e->{label} eq 'linux') {
@@ -1109,23 +1388,13 @@ sub suggest {
}
add_kernel($bootloader, $kernels[0],
- { root => $root, label => 'failsafe', append => 'failsafe' })
+ { root => $root, label => 'failsafe', append => 'failsafe noiswmd audit=0' })
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}
- && isFat_or_NTFS($_) && member(fs::type::fs_type_from_magic($_), 'vfat', 'ntfs', 'ntfs-3g')
+ && isFat_or_NTFS($_) && member(fs::type::fs_type_from_magic($_), qw(vfat ntfs ntfs-3g))
&& !$_->{is_removable}
&& !isRecovery($_);
}
@@ -1140,9 +1409,8 @@ sub suggest {
makeactive => 1,
});
} @windows_boot_parts;
- }
- my @preferred = map { "linux-$_" } 'p3-smp-64GB', 'secure', 'enterprise', 'smp', 'i686-up-4GB';
+ my @preferred = map { "linux-$_" } 'server';
if (my $preferred = find { get_label($_, $bootloader) } @preferred) {
$bootloader->{default} ||= $preferred;
}
@@ -1150,6 +1418,9 @@ sub suggest {
$bootloader->{method} ||= first(method_choices($all_hds, 1), # best installed
method_choices($all_hds, 0)); # or best if no valid one is installed
+ $bootloader->{perImageAppend} = $bootloader->{entries}[0]{append};
+ $bootloader->{default_vga} = $options{vga_fb};
+
if (main_method($bootloader->{method}) eq 'grub') {
my %processed_entries = {};
foreach my $c (find_other_distros_grub_conf($fstab)) {
@@ -1192,6 +1463,7 @@ sub config_files() {
lilo => '/etc/lilo.conf',
grub => '/boot/grub/menu.lst',
grub_install => '/boot/grub/install.sh',
+ uboot => '/boot/extlinux/extlinux.conf',
);
map_each {
@@ -1204,31 +1476,53 @@ sub method2text {
my ($method) = @_;
+{
'lilo-menu' => N("LILO with text menu"),
- 'grub2' => N("GRUB2 with graphical 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"),
+ 'refind' => N("rEFInd with graphical menu"),
+ 'uboot' => N("U-Boot/Extlinux with text menu"),
}->{$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' :
- arch() =~ /mips/ ? 'pmon2000' :
arch() =~ /arm/ ? 'uboot' :
- (
if_(!$b_prefix_mounted || whereis_binary('grub2-reboot', $::prefix),
- 'grub2'),
- if_(!$b_prefix_mounted || whereis_binary('grub', $::prefix),
+ 'grub2-graphic', 'grub2'),
+ if_(uefi_type() eq kernel_uefi_type() && (!$b_prefix_mounted || whereis_binary('refind-install', $::prefix)), 'refind'),
+ # only grub2 & rEFInd work 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} || $::isLiveInstall), (
+ 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) ];
@@ -1237,11 +1531,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));
@@ -1264,151 +1567,59 @@ 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 {
+sub install_uboot {
my ($bootloader, $all_hds) = @_;
+ write_uboot($bootloader, $all_hds);
+ when_config_changed_uboot($bootloader);
+}
- 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;
+sub _write_extlinux_conf {
+ my ($bootloader, $_all_hds) = @_;
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.";
- }
+ my @conf;
+ push @conf, "# File generated by DrakX/drakboot";
+ push @conf, "default " . $bootloader->{default} if $bootloader->{default};
+ push @conf, "timeout " . $bootloader->{timeout} if $bootloader->{timeout};
+ # needed to show boot menu and enable timeout
+ push @conf, "menu title Boot Menu" if $bootloader->{timeout};
- 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}}) {
+ push @conf, "\nlabel $entry->{label}";
+ push @conf, " kernel $entry->{kernel_or_dev}";
+ push @conf, " initrd $entry->{initrd}" if $entry->{initrd};
+ push @conf, " fdtdir $entry->{fdtdir}" if $entry->{fdtdir};
- 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 @append;
+ push @append, "root=" . $entry->{root} if $entry->{root};
+ push @append, $entry->{append} if $entry->{append};
+ push @conf, " append " . join(' ', @append) if @append;
}
- my $f = "$::prefix/etc/yaboot.conf";
- log::l("writing yaboot config to $f");
- renamef($f, "$f.old");
- output($f, map { "$_\n" } @conf);
-}
-sub install_yaboot {
- my ($bootloader, $all_hds) = @_;
- log::l("Installing boot loader...");
- write_yaboot($bootloader, $all_hds);
- when_config_changed_yaboot($bootloader);
-}
-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";
+ my $f = "$::prefix/boot/extlinux/extlinux.conf";
+ log::l("writing extlinux config to $f");
+ renamef($f, $f . '.old');
+ output_with_perm($f, 0600, map { "$_\n" } @conf);
}
-sub install_pmon2000 {
- my ($_bootloader, $_all_hds) = @_;
- log::l("Mips/pmon2000 - nothing to install...");
-}
-sub write_pmon2000 {
- my ($_bootloader, $_all_hds) = @_;
- log::l("Mips/pmon2000 - nothing to write...");
-}
-sub when_config_changed_pmon2000 {
- my ($_bootloader) = @_;
- log::l("Mips/pmon2000 - nothing to do...");
+sub write_uboot {
+ my ($bootloader, $all_hds) = @_;
+ _write_extlinux_conf($bootloader, $all_hds);
}
-sub install_uboot {
- my ($_bootloader, $_all_hds) = @_;
- log::l("uboot - nothing to install...");
-}
-sub write_uboot {
- my ($_bootloader, $_all_hds) = @_;
- log::l("uboot - nothing to write...");
-}
sub when_config_changed_uboot {
my ($_bootloader) = @_;
- log::l("uboot - nothing to do...");
+ #- do not do anything
}
sub install_cromwell {
@@ -1421,7 +1632,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 {
@@ -1610,7 +1821,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});
}
@@ -1693,8 +1904,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;
@@ -1702,8 +1919,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;
@@ -1712,16 +1935,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) = @_;
@@ -1794,25 +2035,145 @@ sub crypt_grub_password {
chomp_($res);
}
-sub write_grub2 {
- my ($bootloader, $_all_hds, $o_backup_extension) = @_;
- my $error;
-
+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);
+
+ my $append = $bootloader->{perImageAppend} || get_grub2_append($bootloader);
+ my $vga = $bootloader->{default_vga};
+ $append .= " vga=$vga" if $append !~ /vga=/ && $vga && $vga ne "normal";
+
$conf{GRUB_CMDLINE_LINUX_DEFAULT} = $append;
- $conf{GRUB_TIMEOUT} = $bootloader->{timeout};
+ $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
+ # special case so that setVarsInSh() doesn't emit the line when timeout is 0
+ $conf{GRUB_TIMEOUT} = $bootloader->{timeout} eq 0 ? "0 " : $bootloader->{timeout};
+ renamef($f, $f . ($o_backup_extension || '.old'));
setVarsInSh($f, \%conf);
+}
- my $grub2_cfg = '/boot/grub2/grub.cfg';
- run_program::rooted($::prefix, 'grub2-mkconfig', '2>', \$error, '-o', $grub2_cfg) or die "grub2-mkconfig failed: $error";
+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 ($bootloader, $o_all_hds, $o_backup_extension) = @_;
+ my $error;
+
+ write_grub2_sysconfig($bootloader, $o_all_hds, $o_backup_extension);
+
+ my $f1 = "$::prefix/boot/grub2/grub.cfg";
+ #- we won't just rename as grub2-mkconfig (more likely os-prober) may fail:
+ cp_af($f1, $f1 . '.old') if -e $f1;
+ #- don't use the update-grub2 script here, it hangs when run by service_harddrake
+ #- during boot because it causes systemd to try to start a user session
+ run_program::rooted($::prefix, 'grub2-mkconfig', '2>', \$error, '-o', '/boot/grub2/grub.cfg') or die "grub2-mkconfig failed: $error";
+ log::l("grub2-mkconfig logs: $error");
+
+ write_grub2_default_entry($bootloader, $o_all_hds, $o_backup_extension);
+ 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()) {
+ if ($bootloader->{no_esp_or_mbr}) {
+ push @options, qw(--bootloader-id=tmp --no-nvram);
+ } elsif ($bootloader->{removable}) {
+ push @options, '--removable';
+ }
+ } 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 {
@@ -2008,16 +2369,22 @@ sub restore_previous_MBR_bootloader {
sub install_grub2 {
my ($bootloader, $all_hds) = @_;
- my $error;
write_grub2($bootloader, $all_hds);
- my $boot = $bootloader->{boot};
- # if (member($boot, map { "/dev/$_->{device}" } @{$all_hds->{hds}}) {
- if ($boot =~ /\d$/) {
- run_program::rooted($::prefix, 'grub2-install', '2>', \$error, '--grub-setup=/bin/true', $boot) or die "grub2-install failed: $error";
- } else {
- run_program::rooted($::prefix, 'grub2-install', '2>', \$error, $boot) or die "grub2-install failed: $error";
+ write_grub2_install_sh($bootloader, '.old');
+ install_raw_grub2();
+}
+
+sub install_raw_grub2() {
+ my $error;
+ my $f = '/boot/grub2/install.sh';
+ my ($right_dir, $bad_dir) = ("$::prefix/boot/EFI/EFI/", "$::prefix/boot/EFI/efi/");
+ if (-e $bad_dir && ! -e $right_dir) {
+ renamef($bad_dir, $right_dir);
+ }
+ if (!run_program::rooted($::prefix, "sh", "2>", \$error, $f)) {
+ log::explanations("grub2-install failed:\n(" . cat_($f) . ")\nError: <$error>");
+ die "grub2-install failed: $error";
}
- setVarsInSh("$::prefix/boot/grub2/drakboot.conf", { boot => $boot });
}
sub install_grub {
@@ -2064,6 +2431,187 @@ sub when_config_changed_grub {
update_copy_in_boot($_) foreach glob($::prefix . boot_copies_dir() . '/*.link');
}
+sub write_refind {
+ my ($bootloader, $_all_hds, $o_backup_extension) = @_;
+
+ my @config;
+
+ foreach my $entry (@{$bootloader->{entries}}) {
+ if ($entry->{type} eq 'image' && $entry->{kernel_or_dev} eq '/boot/vmlinuz') {
+ my $vga = $entry->{vga} || $bootloader->{vga};
+ my $boot_params = join(' ',
+ "root=$entry->{root}",
+ $entry->{append},
+ if_($entry->{'read-write'}, 'rw'),
+ if_($vga && $vga ne "normal", "vga=$vga")
+ );
+ push @config, '"' . $entry->{label} . '" "' . $boot_params . '"';
+ }
+ }
+ if (@config) {
+ my $f = "$::prefix/boot/refind_linux.conf";
+ log::l("writing rEFInd config to $f");
+ renamef($f, $f . ($o_backup_extension || '.old'));
+ output_with_perm($f, 0600, map { "$_\n" } @config);
+ check_enough_space();
+ } else {
+ log::l("config has no entries - rEFInd config file not written");
+ }
+
+ my $default_kernel = readlink("$::prefix/boot/vmlinuz");
+ if ($default_kernel) {
+ if ($bootloader->{use_nvram}) {
+ write_refind_previous_boot_var($default_kernel);
+ } else {
+ write_refind_previous_boot_file($default_kernel, "$::prefix/boot/EFI/EFI/refind");
+ write_refind_previous_boot_file($default_kernel, "$::prefix/boot/EFI/EFI/BOOT");
+ }
+ }
+}
+
+sub write_refind_previous_boot_var {
+ my ($kernel) = @_;
+ my ($efivars, $already_mounted) = mount_efivars();
+ my $previous_boot = "$efivars/PreviousBoot-36d08fa7-cf0b-42f5-8f14-68df73ed3740";
+ run_program::run('chattr', '-i', $previous_boot) if -e $previous_boot;
+ if (open(my $efivar, '>:raw', $previous_boot)) {
+ require Encode;
+ log::l("writing rEFInd PreviousBoot variable");
+ print $efivar "\x07\x00\x00\x00";
+ print $efivar Encode::encode('UTF16-LE', $kernel);
+ print $efivar "\x00\x00";
+ close($efivar);
+ } else {
+ log::l("failed to write rEFInd PreviousBoot variable: $@ ($!)");
+ }
+ run_program::run('umount', $efivars) if !$already_mounted;
+}
+
+sub write_refind_previous_boot_file {
+ my ($kernel, $base_path) = @_;
+ return if ! -e "$base_path/refind.conf" || ! mkdir_p("$base_path/vars");
+ if (open(my $f, '>:raw', "$base_path/vars/PreviousBoot")) {
+ require Encode;
+ log::l("writing rEFInd $base_path/vars/PreviousBoot file");
+ print $f Encode::encode('UTF16-LE', "Boot boot\\$kernel");
+ print $f "\x00\x00";
+ close($f);
+ } else {
+ log::l("failed to write rEFInd $base_path/vars/PreviousBoot file");
+ }
+}
+
+sub install_refind {
+ my ($bootloader, $all_hds) = @_;
+
+ if ($bootloader->{install_mode} ne 'no_install') {
+ my (@options, $error);
+ if ($bootloader->{install_mode} eq 'as_default') {
+ $bootloader->{esp_device} or die "ESP device is unknown";
+ push @options, '--usedefault';
+ push @options, $bootloader->{esp_device};
+ #- refind_install uses lower case file names. If a default bootloader was previously
+ #- created with an upper case file name, Linux won't overwrite it.
+ my $default_fn = "$::prefix/boot/EFI/EFI/BOOT/BOOT" . uc(uefi_type()) . ".EFI";
+ unlink($default_fn) if -e $default_fn;
+ } elsif ($bootloader->{install_mode} eq 'nvram_only') {
+ push @options, '--nvramonly';
+ }
+ run_program::rooted($::prefix, '/sbin/refind-install', '2>', \$error, @options)
+ or die "refind-install failed: $error";
+ }
+
+ #- This file is not used by rEFInd itself. It just defines the paths to the image
+ #- files used for the standard banner choices.
+ my %h = getVarsFromSh("$::prefix/etc/sysconfig/refind");
+
+ my $banner_source;
+ if ($bootloader->{banner_path} eq 'refind_banner.png') {
+ $banner_source = "$::prefix" . $h{REFIND_BANNER};
+ } elsif ($bootloader->{banner_path} eq 'mageia_theme.png') {
+ $banner_source = "$::prefix" . $h{MAGEIA_THEME};
+ }
+ if (defined $banner_source && ! (-f $banner_source && -r $banner_source)) {
+ log::l("$banner_source does not exist or is not readable");
+ $bootloader->{banner_path} = '';
+ $bootloader->{banner_scale} = 'noscale';
+ undef $banner_source;
+ }
+
+ #- Try both possible locations for the main config file.
+ modify_refind_config($bootloader, $banner_source, "$::prefix/boot/EFI/EFI/refind");
+ modify_refind_config($bootloader, $banner_source, "$::prefix/boot/EFI/EFI/BOOT");
+
+ write_refind($bootloader, $all_hds);
+}
+
+sub modify_refind_config {
+ my ($bootloader, $banner_source, $esp_dir) = @_;
+
+ my $config_file = "$esp_dir/refind.conf";
+ return if ! -f $config_file || ! -w $config_file;
+
+ my $use_nvram = $bootloader->{use_nvram} ? 'true' : 'false';
+
+ my $banner_path = $bootloader->{banner_path};
+ cp_f($banner_source, "$esp_dir/$banner_path") if (defined $banner_source);
+
+ my $banner_scale = $bootloader->{banner_scale};
+
+ my @config;
+
+ my %done;
+ foreach (cat_utf8($config_file)) {
+ if ($_ =~ /^#?use_nvram\s/) {
+ if (! $done{use_nvram}) {
+ push @config, "use_nvram $use_nvram\n" ;
+ $done{use_nvram} = 1;
+ }
+ } elsif ($_ =~ /^#?banner\s/) {
+ if (! $done{banner_path}) {
+ if ($banner_path eq '') {
+ push @config, "#banner my_banner.png\n";
+ } else {
+ push @config, "banner $banner_path\n";
+ }
+ $done{banner_path} = 1;
+ }
+ } elsif ($_ =~ /^#?banner_scale\s/) {
+ if (! $done{banner_scale}) {
+ push @config, "banner_scale $banner_scale\n";
+ $done{banner_scale} = 1;
+ }
+ } else {
+ push @config, $_;
+ }
+ }
+
+ if (@config) {
+ log::l("writing rEFInd config to $config_file");
+ renamef($config_file, $config_file . '.old');
+ output_with_perm($config_file, 0600, @config);
+ } else {
+ log::l("config has no entries - rEFInd config file not written");
+ }
+}
+
+sub when_config_changed_refind {
+ my ($_bootloader) = @_;
+ #- do not do anything
+}
+
+=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/...)
+
+This Swiss army knife function is heavily used by eg /sbin/bootloader-config
+
+=cut
+
sub action {
my ($bootloader, $action, @para) = @_;
@@ -2072,28 +2620,57 @@ 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 cannot install the bootloader on a %s partition\n", $part->{fs_type})
- if member($part->{fs_type}, qw(btrfs xfs));
- }
- $bootloader->{keytable} = keytable($bootloader->{keytable});
+ my ($efivars, $already_mounted) = mount_efivars() if is_uefi();
+
+ $bootloader->{keytable} = keytable($bootloader->{keytable}) if $bootloader->{method} eq 'lilo';
action($bootloader, 'install', $all_hds);
+
+ run_program::run('umount', $efivars) if is_uefi() && !$already_mounted;
+}
+
+sub get_grub2_pkg() {
+ my ($prefix, $pkg);
+ if (is_uefi()) {
+ my %convert = (ia32 => 'i386', aa64 => 'arm64', x64 => 'x86_64');
+ my %pkgs = (ia32 => 'x86-32', aa64 => 'aarch-64', x64 => 'x86-64');
+ $prefix = $convert{uefi_type()} . "-efi";
+ $pkg = "grub2-efi(" . $pkgs{uefi_type()} . ")";
+ } else {
+ $prefix = 'i386-pc';
+ $pkg = 'grub2';
+ }
+ ($prefix, $pkg);
}
sub ensure_pkg_is_installed {
my ($do_pkgs, $bootloader) = @_;
- my %pkg = ('grub2' => glob_("/sys/firmware/efi/*") ? 'grub2-efi' : 'grub2');
- my %h = ('grub2' => 'grub2-install');
+ 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 (member($main_method, qw(grub grub2 lilo))) {
- $do_pkgs->ensure_binary_is_installed($pkg{$main_method} || $main_method, $h{$main_method} || $main_method, 1) or return 0;
- if ($bootloader->{method} eq 'grub-graphic') {
- $do_pkgs->ensure_is_installed('mageia-gfxboot-theme', '/usr/share/gfxboot/themes/Mageia/boot/message', 1) or return 0;
- }
+ if ($main_method eq 'grub2') {
+ my ($prefix, $pkg) = get_grub2_pkg();
+ $do_pkgs->ensure_is_installed($pkg, "/usr/lib/grub/$prefix/ext2.mod", 1) or return 0;
+ } elsif ($main_method eq 'refind') {
+ $do_pkgs->ensure_is_installed('refind', '/sbin/refind-install', 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;
+ }
+ # Install gfx theme if needed:
+ if (my $pkg = $suppl{$bootloader->{method}}) {
+ $do_pkgs->ensure_is_installed(@$pkg, 1) or return 0;
}
1;
}
@@ -2135,6 +2712,12 @@ sub parse_grub2_config {
}
}
+=item find_other_distros_grub_conf($fstab)
+
+Returns a list of other distros' grub.conf
+
+=cut
+
sub find_other_distros_grub_conf {
my ($fstab) = @_;
@@ -2264,4 +2847,8 @@ sub update_for_renumbered_partitions {
1;
}
+=back
+
+=cut
+
1;