summaryrefslogtreecommitdiffstats
path: root/files
diff options
context:
space:
mode:
authorThomas Backlund <tmb@mageia.org>2014-01-04 20:39:28 +0100
committerThomas Backlund <tmb@mageia.org>2014-01-04 20:39:28 +0100
commitb67df736b3443c0b0841c8da7f15ad5643ce8ca3 (patch)
tree07d37215c77e66608074c502e7683b317c19abd5 /files
parentd090a8b3f9982f928435fdb444ddb7a870349490 (diff)
downloaddraklive-config-b67df736b3443c0b0841c8da7f15ad5643ce8ca3.tar
draklive-config-b67df736b3443c0b0841c8da7f15ad5643ce8ca3.tar.gz
draklive-config-b67df736b3443c0b0841c8da7f15ad5643ce8ca3.tar.bz2
draklive-config-b67df736b3443c0b0841c8da7f15ad5643ce8ca3.tar.xz
draklive-config-b67df736b3443c0b0841c8da7f15ad5643ce8ca3.zip
add mga3 final build configs
Diffstat (limited to 'files')
-rwxr-xr-xfiles/90mgalive/mgalive-root.sh13
-rwxr-xr-xfiles/90mgalive/module-setup.sh2
-rw-r--r--files/UEFI/EFI/boot/bootx64.efibin0 -> 84120 bytes
-rw-r--r--files/UEFI/loader/entries/01-mga-boot.conf4
-rw-r--r--files/UEFI/loader/entries/02-mga-install.conf4
-rw-r--r--files/UEFI/loader/entries/03-mga-boot-safe.conf4
-rw-r--r--files/UEFI/loader/loader.conf2
-rw-r--r--files/blacklist_ide.conf4
-rw-r--r--files/bootloader.pm2267
-rw-r--r--files/live-dracut.conf2
-rw-r--r--files/live.modprobe.DVD1
-rwxr-xr-xfiles/mga_rpms/update_media.sh42
-rw-r--r--files/pkgs.pm295
13 files changed, 2636 insertions, 4 deletions
diff --git a/files/90mgalive/mgalive-root.sh b/files/90mgalive/mgalive-root.sh
index c03935e..2837cd0 100755
--- a/files/90mgalive/mgalive-root.sh
+++ b/files/90mgalive/mgalive-root.sh
@@ -14,20 +14,27 @@ mkdir -m 0755 -p /live/media
mkdir -m 0755 -p /live/distrib
mkdir -m 0755 -p /live/memory
mkdir -m 0755 -p /live/union
+mkdir -m 0755 -p /run/mgalive/sqfs
# fix udev isohybrid LABEL issues (mga #3334)
# by reading the device we get, stripping away partition number,
# and mount the resulting device
realdev=$(echo $livedev |sed 's,\(/dev/sd[a-z]\)1,\1,g')
-# mount the livecd
-mount -n -t iso9660 -o ro $realdev /live/media
+# mount the live media
+getargbool 0 UEFI && liveuefi="yes"
+if [ -n "$liveuefi" ]; then
+ mount -n -t vfat -o ro $livedev /live/media
+else
+ mount -n -t iso9660 -o ro $realdev /live/media
+fi
LOOPDEV=$( losetup -f )
losetup -r $LOOPDEV /live/media/loopbacks/distrib-lzma.sqfs
mount -n -t squashfs -o ro $LOOPDEV /live/distrib
+mount -n -t squashfs -o ro $LOOPDEV /run/mgalive/sqfs
mount -n -t tmpfs -o mode=755 /live/memory /live/memory
-mount -n -t unionfs -o dirs=/live/memory=rw:/live/distrib=ro unionfs /live/union
+mount -n -t overlayfs -o lowerdir=/live/distrib,upperdir=/live/memory overlayfs /live/union
ln -s /live/union /dev/root
diff --git a/files/90mgalive/module-setup.sh b/files/90mgalive/module-setup.sh
index 19eb0a6..f18e81a 100755
--- a/files/90mgalive/module-setup.sh
+++ b/files/90mgalive/module-setup.sh
@@ -11,7 +11,7 @@ depends() {
}
installkernel() {
- instmods squashfs loop unionfs
+ instmods squashfs loop overlayfs
}
install() {
diff --git a/files/UEFI/EFI/boot/bootx64.efi b/files/UEFI/EFI/boot/bootx64.efi
new file mode 100644
index 0000000..ccedcab
--- /dev/null
+++ b/files/UEFI/EFI/boot/bootx64.efi
Binary files differ
diff --git a/files/UEFI/loader/entries/01-mga-boot.conf b/files/UEFI/loader/entries/01-mga-boot.conf
new file mode 100644
index 0000000..19d5058
--- /dev/null
+++ b/files/UEFI/loader/entries/01-mga-boot.conf
@@ -0,0 +1,4 @@
+title Boot Mageia 3 Live
+linux /boot/vmlinuz
+initrd /boot/cdrom/initrd.gz
+options root=mgalive:LABEL=MGA3LIVE UEFI splash quiet rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 vga=788
diff --git a/files/UEFI/loader/entries/02-mga-install.conf b/files/UEFI/loader/entries/02-mga-install.conf
new file mode 100644
index 0000000..9341727
--- /dev/null
+++ b/files/UEFI/loader/entries/02-mga-install.conf
@@ -0,0 +1,4 @@
+title Install Mageia 3 Live
+linux /boot/vmlinuz
+initrd /boot/cdrom/initrd.gz
+options root=mgalive:LABEL=MGA3LIVE UEFI splash quiet rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 vga=788 install
diff --git a/files/UEFI/loader/entries/03-mga-boot-safe.conf b/files/UEFI/loader/entries/03-mga-boot-safe.conf
new file mode 100644
index 0000000..ef8030e
--- /dev/null
+++ b/files/UEFI/loader/entries/03-mga-boot-safe.conf
@@ -0,0 +1,4 @@
+title Boot Mageia 3 Live (Safe mode)
+linux /boot/vmlinuz
+initrd /boot/cdrom/initrd.gz
+options root=mgalive:LABEL=MGA3LIVE UEFI rd.luks=0 rd.lvm=0 rd.md=0 rd.dm=0 xdriver=vesa
diff --git a/files/UEFI/loader/loader.conf b/files/UEFI/loader/loader.conf
new file mode 100644
index 0000000..da28360
--- /dev/null
+++ b/files/UEFI/loader/loader.conf
@@ -0,0 +1,2 @@
+timeout 10
+default 01-mga-boot
diff --git a/files/blacklist_ide.conf b/files/blacklist_ide.conf
new file mode 100644
index 0000000..7014e3c
--- /dev/null
+++ b/files/blacklist_ide.conf
@@ -0,0 +1,4 @@
+# temp fix for 3395
+blacklist pata_acpi
+# uas broken
+blacklist uas
diff --git a/files/bootloader.pm b/files/bootloader.pm
new file mode 100644
index 0000000..348599e
--- /dev/null
+++ b/files/bootloader.pm
@@ -0,0 +1,2267 @@
+package bootloader; # $Id: bootloader.pm 267511 2010-04-12 12:34:45Z cfergeau $
+
+
+
+
+#-######################################################################################
+#- misc imports
+#-######################################################################################
+use common;
+use fs::type;
+use fs::get;
+use fs::loopback;
+use fs::proc_partitions;
+use log;
+use any;
+use devices;
+use detect_devices;
+use partition_table::raw;
+use run_program;
+use modules;
+
+#-#####################################################################################
+#- Functions
+#-#####################################################################################
+my $vmlinuz_regexp = 'vmlinu[xz]|win4lin|uImage';
+my $decompose_vmlinuz_name = qr/((?:$vmlinuz_regexp).*?)-(\d+\.\d+.*)/;
+
+sub expand_vmlinuz_symlink {
+ my ($vmlinuz) = @_;
+ my $f = $::prefix . ($vmlinuz =~ m!^/! ? $vmlinuz : "/boot/$vmlinuz");
+ -l $f ? readlink($f) : $vmlinuz;
+}
+
+sub installed_vmlinuz_raw() { grep { /^($vmlinuz_regexp)/ } all("$::prefix/boot") }
+sub installed_vmlinuz() { grep { ! -l "$::prefix/boot/$_" } installed_vmlinuz_raw() }
+sub vmlinuz2version {
+ my ($vmlinuz) = @_;
+ expand_vmlinuz_symlink($vmlinuz) =~ /$decompose_vmlinuz_name/ && $2;
+}
+sub vmlinuz2kernel_str {
+ my ($vmlinuz) = @_;
+ my ($basename, $version) = expand_vmlinuz_symlink($vmlinuz) =~ /$decompose_vmlinuz_name/ or return;
+ {
+ basename => $basename,
+ version => $version,
+ $version =~ /([\d.]*)-(\D.*)-((\d+|0\.rc\d+.*)\.mga.*)$/ ? #- eg: 3.0.0-1.mga2
+ (ext => $2, version_no_ext => "$1-$3") :
+ $version =~ /(.*mga)-?(.*)/ ? #- (old) eg: 2.6.17-13mdventerprise
+ (ext => $2, version_no_ext => $1) : (version_no_ext => $version),
+ };
+}
+
+sub kernel_str2short_name {
+ my ($kernel) = @_;
+ $kernel->{basename};
+}
+
+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"
+ 'initrd' . ($basename ? "-$basename" : '');
+}
+sub kernel_str2vmlinuz_long {
+ my ($kernel) = @_;
+ $kernel->{basename} . '-' . $kernel->{version};
+}
+sub kernel_str2initrd_long {
+ my ($kernel) = @_;
+ basename2initrd_basename(kernel_str2short_name($kernel)) . '-' . $kernel->{version} . '.img';
+}
+sub kernel_str2vmlinuz_short {
+ my ($kernel) = @_;
+ if ($kernel->{use_long_name}) {
+ kernel_str2vmlinuz_long($kernel);
+ } else {
+ kernel_str2short_name($kernel);
+ }
+}
+sub kernel_str2initrd_short {
+ my ($kernel) = @_;
+ if ($kernel->{use_long_name}) {
+ kernel_str2initrd_long($kernel);
+ } else {
+ basename2initrd_basename(kernel_str2short_name($kernel)) . '.img';
+ }
+}
+
+sub kernel_str2label {
+ my ($kernel, $o_use_long_name) = @_;
+ if ($o_use_long_name || $kernel->{use_long_name}) {
+ _sanitize_ver($kernel);
+ } else {
+ my $short_name = kernel_str2short_name($kernel);
+ $kernel->{ext} =~ /^xen/ ? 'xen' : ($short_name eq 'vmlinuz' ? 'linux' : $short_name);
+ }
+}
+
+sub get {
+ my ($vmlinuz, $bootloader) = @_;
+ $_->{kernel_or_dev} && $_->{kernel_or_dev} eq $vmlinuz and return $_ foreach @{$bootloader->{entries}};
+ undef;
+}
+sub get_label {
+ my ($label, $bootloader) = @_;
+ $_->{label} && lc(make_label_lilo_compatible($_->{label})) eq lc(make_label_lilo_compatible($label)) and return $_ foreach @{$bootloader->{entries}};
+ undef;
+}
+
+sub mkinitrd {
+ my ($kernel_version, $bootloader, $entry, $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();
+
+ modules::load('loop');
+ my @options = (
+ if_($::isInstall, "-v"), "-f", $initrd, $kernel_version,
+ if_($entry->{initrd_options}, split(' ', $entry->{initrd_options})),
+ );
+ if (!run_program::rooted($::prefix, 'mkinitrd', @options)) {
+ unlink("$::prefix/$initrd");
+ die "mkinitrd failed:\n(mkinitrd @options)";
+ }
+ add_boot_splash($initrd, $entry->{vga} || $bootloader->{vga});
+
+ fs::loopback::save_boot($loop_boot);
+
+ -e "$::prefix/$initrd" && $initrd;
+}
+
+sub rebuild_initrd {
+ my ($kernel_version, $bootloader, $entry, $initrd) = @_;
+
+ my $old = $::prefix . $entry->{initrd} . '.old';
+ unlink $old;
+ rename "$::prefix$initrd", $old;
+ if (!mkinitrd($kernel_version, $bootloader, $entry, $initrd)) {
+ log::l("rebuilding initrd failed, putting back the old one");
+ rename $old, "$::prefix$initrd";
+ }
+}
+
+sub remove_boot_splash {
+ my ($initrd) = @_;
+ run_program::rooted($::prefix, '/usr/share/bootsplash/scripts/remove-boot-splash', $initrd);
+}
+sub add_boot_splash {
+ my ($initrd, $vga) = @_;
+
+ $vga or return;
+
+ eval { require Xconfig::resolution_and_depth } or return;
+ if (my $res = Xconfig::resolution_and_depth::from_bios($vga)) {
+ run_program::rooted($::prefix, '/usr/share/bootsplash/scripts/make-boot-splash', $initrd, $res->{X});
+ } else {
+ log::l("unknown vga bios mode $vga");
+ }
+}
+sub update_splash {
+ my ($bootloader) = @_;
+
+ my %real_initrd_entries;
+ foreach (@{$bootloader->{entries}}) {
+ 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});
+ }
+}
+
+sub read {
+ my ($all_hds) = @_;
+ my $fstab = [ fs::get::fstab($all_hds) ];
+ foreach my $main_method (main_method_choices()) {
+ my $f = $bootloader::{"read_$main_method"} or die "unknown bootloader method $main_method (read)";
+ my $bootloader = $f->($fstab);
+
+ cleanup_entries($bootloader);
+
+ # handle raid-extra-boot (lilo)
+ my @devs = $bootloader->{boot};
+ if ($bootloader->{'raid-extra-boot'} =~ /mbr/ &&
+ (my $md = fs::get::device2part($bootloader->{boot}, $all_hds->{raids}))) {
+ @devs = map { $_->{rootDevice} } @{$md->{disks}};
+ } elsif ($bootloader->{'raid-extra-boot'} =~ m!/dev/!) {
+ @devs = split(',', $bootloader->{'raid-extra-boot'});
+ }
+
+ my ($type) = map {
+ 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 pmon2000 uboot))) {
+ #- not checking, there's only one bootloader anyway :)
+ $main_method;
+ } elsif (my $type = partition_table::raw::typeOfMBR($_)) {
+ warn "typeOfMBR $type on $_ for method $main_method\n" if $ENV{DEBUG};
+ $type;
+ } else { () }
+ } @devs;
+
+ if ($type eq $main_method) {
+ 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}");
+ } else {
+ $bootloader->{default_options} = {};
+ }
+ return $bootloader;
+ }
+ }
+}
+
+sub read_grub2 {
+ my %bootloader = getVarsFromSh("$::prefix/boot/grub2/drakboot.conf");
+ my %h = getVarsFromSh("$::prefix/etc/default/grub");
+ $bootloader{timeout} = $h{GRUB_TIMEOUT};
+ $bootloader{entries} = [];
+ my $entry;
+ foreach (cat_utf8("$::prefix/boot/grub2/grub.cfg")) {
+ 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->{type} = 'image';
+ @$entry{qw(kernel_or_dev append)} = ($1, $2);
+ } elsif (/initrd\s+(\S+)/ || /module\s+(\S+initrd\S+)\s+(.*)?/) {
+ $entry->{initrd} = $1;
+ }
+ }
+
+ $bootloader{method} = 'grub2';
+ \%bootloader;
+}
+
+sub read_grub {
+ my ($fstab) = @_;
+
+ my $grub2dev = read_grub_device_map();
+ my $boot_root = read_grub_install_sh();
+ _may_fix_grub2dev($fstab, $grub2dev, $boot_root->{boot_part});
+
+ my $bootloader = read_grub_menu_lst($fstab, $grub2dev) or return;
+
+ if ($boot_root->{boot}) {
+ $bootloader->{boot} = grub2dev($boot_root->{boot}, $grub2dev);
+ }
+
+ $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
+sub _may_fix_grub2dev {
+ my ($fstab, $grub2dev, $boot_part) = @_;
+
+ $boot_part or log::l("install.sh does not contain 'root (hd...)' line, no way to magically adapt device.map"), return;
+
+ my $real_boot_part = fs::get::root_($fstab, 'boot') or
+ log::l("argh... the fstab given is useless, it doesn't contain '/'"), return;
+
+ my $real_boot_dev = $real_boot_part->{rootDevice} or return; # if /boot is on Linux RAID 1, hope things are all right...
+
+ if (my $prev_boot_part = fs::get::device2part(grub2dev($boot_part, $grub2dev), $fstab)) { # the boot_device as far as grub config files say
+ $real_boot_part == $prev_boot_part and return;
+ }
+
+ log::l("WARNING: we have detected that device.map is inconsistent with the system");
+
+ my ($hd_grub, undef, undef) = parse_grub_file($boot_part); # extract hdX
+ if (my $prev_hd_grub = find { $grub2dev->{$_} eq $real_boot_dev } keys %$grub2dev) {
+ $grub2dev->{$prev_hd_grub} = $grub2dev->{$hd_grub};
+ log::l("swapping result: $hd_grub/$real_boot_dev and $prev_hd_grub/$grub2dev->{$hd_grub}");
+ } else {
+ log::l("argh... can't swap, setting $hd_grub to $real_boot_dev anyway");
+ }
+ $grub2dev->{$hd_grub} = $real_boot_dev;
+}
+
+sub read_grub_install_sh() {
+ my $s = cat_("$::prefix/boot/grub/install.sh");
+ my %h;
+
+ #- matches either:
+ #- setup (hd0)
+ #- install (hd0,0)/boot/grub/stage1 d (hd0) (hd0,0)/boot/grub/stage2 p (hd0,0)/boot/grub/menu.lst
+ if ($s =~ /^(?:setup.*|install\s.*\sd)\s+(\(.*?\))/m) {
+ $h{boot} = $1;
+ }
+ if ($s =~ /^root\s+(\(.*?\))/m) {
+ $h{boot_part} = $1;
+ }
+ \%h;
+}
+
+sub _parse_grub_menu_lst() {
+ my $global = 1;
+ my ($e, %b);
+
+ my $menu_lst_file = "$::prefix/boot/grub/menu.lst";
+ -e $menu_lst_file or return;
+
+ foreach (MDK::Common::File::cat_utf8($menu_lst_file)) {
+ my $verbatim = $_;
+ chomp;
+ s/^\s*//; s/\s*$//;
+ next if /^#/ || /^$/;
+ my ($keyword, $v) = split('[ \t=]+', $_, 2) or
+ warn qq(unknown line in /boot/grub/menu.lst: "$_"\n), next;
+
+ if ($keyword eq 'root') {
+ #- rename to avoid name conflict
+ $keyword = 'grub_root';
+ }
+
+ if ($keyword eq 'title') {
+ push @{$b{entries}}, $e = { label => $v };
+ $global = 0;
+ } elsif ($global) {
+ $b{$keyword} = $v;
+ } else {
+ if ($keyword eq 'kernel') {
+ $e->{type} = 'image';
+ $e->{kernel} = $v;
+ } elsif ($keyword eq 'chainloader') {
+ $e->{type} = 'other';
+ $e->{append} = "";
+ } elsif ($keyword eq 'configfile') {
+ $e->{type} = 'grub_configfile';
+ $e->{configfile} = $v;
+ } elsif ($keyword eq 'map') {
+ $e->{mapdrive}{$2} = $1 if $v =~ m/\((.*)\) \((.*)\)/;
+ } elsif ($keyword eq 'module') {
+ push @{$e->{modules}}, $v;
+ } else {
+ $e->{$keyword} = $v eq '' ? 1 : $v;
+ }
+ }
+ $e and $e->{verbatim} .= $verbatim;
+ }
+
+ %b;
+}
+
+sub is_already_crypted {
+ my ($password) = @_;
+ $password =~ /^--md5 (.*)/;
+}
+
+sub read_grub_menu_lst {
+ my ($fstab, $grub2dev) = @_;
+
+ my %b = _parse_grub_menu_lst();
+
+ foreach my $keyword (grep { $_ ne 'entries' } keys %b) {
+ $b{$keyword} = $b{$keyword} eq '' ? 1 : grub2file($b{$keyword}, $grub2dev, $fstab, \%b);
+ }
+
+ #- sanitize
+ foreach my $e (@{$b{entries}}) {
+ if (member($e->{type}, 'other', 'grub_configfile')) {
+ eval { $e->{kernel_or_dev} = grub2dev($e->{rootnoverify} || $e->{grub_root}, $grub2dev) };
+ $e->{keep_verbatim} = 1 unless $e->{kernel_or_dev};
+ } elsif ($e->{initrd}) {
+ my $initrd;
+ eval { $initrd = grub2file($e->{initrd}, $grub2dev, $fstab, $e) };
+ if ($initrd) {
+ $e->{initrd} = $initrd;
+ } else {
+ $e->{keep_verbatim} = 1;
+ }
+ }
+
+ if ($e->{kernel} =~ /xen/ && @{$e->{modules} || []} == 2 && $e->{modules}[1] =~ /initrd/) {
+ (my $xen, $e->{xen_append}) = split(' ', $e->{kernel}, 2);
+ ($e->{kernel}, my $initrd) = @{delete $e->{modules}};
+ $e->{xen} = grub2file($xen, $grub2dev, $fstab, $e);
+ $e->{initrd} = grub2file($initrd, $grub2dev, $fstab, $e);
+ }
+ if (my $v = delete $e->{kernel}) {
+ (my $kernel, $e->{append}) = split(' ', $v, 2);
+ $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 if !$e->{kernel_or_dev} || dirname($e->{kernel_or_dev}) ne '/boot';
+ }
+ my ($vga, $other) = partition { /^vga=/ } split(' ', $e->{append});
+ if (@$vga) {
+ $e->{vga} = $vga->[0] =~ /vga=(.*)/ && $1;
+ $e->{append} = join(' ', @$other);
+ }
+ }
+
+ $b{nowarn} = 1;
+ # handle broken installkernel -r:
+ if (@{$b{entries}}) {
+ $b{default} = min($b{default}, scalar(@{$b{entries}}) - 1);
+ $b{default} = $b{entries}[$b{default}]{label};
+ }
+ $b{method} = $b{gfxmenu} ? 'grub-graphic' : 'grub-menu';
+
+ \%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_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] });
+
+ delete $bootloader->{timeout} unless $bootloader->{prompt};
+ $bootloader->{timeout} = $bootloader->{timeout} / 10 if $bootloader->{timeout};
+
+ my $submethod = member($bootloader->{install}, 'text', 'menu') ? $bootloader->{install} : 'menu';
+ $bootloader->{method} = "lilo-$submethod";
+
+ $bootloader;
+}
+sub read_lilo_like {
+ my ($file, $filter_file) = @_;
+
+ my $global = 1;
+ my ($e);
+ my %b;
+ -e "$::prefix$file" or return;
+ foreach my $line (cat_("$::prefix$file")) {
+ next if $line =~ /^\s*#/ || $line =~ /^\s*$/;
+ my ($cmd, $v) = $line =~ /^\s*([^=\s]+)\s*(?:=\s*(.*?))?\s*$/ or log::l("unknown line in $file: $line"), next;
+
+ if ($cmd =~ /^(?:image|other|macos|macosx|bsd|darwin)$/) {
+ $v = $filter_file->($v);
+ push @{$b{entries}}, $e = { type => $cmd, kernel_or_dev => $v };
+ $global = 0;
+ } elsif ($global) {
+ if ($cmd eq 'disk' && $v =~ /(\S+)\s+bios\s*=\s*(\S+)/) {
+ $b{bios}{$1} = $2;
+ } elsif ($cmd eq 'bios') {
+ $b{bios}{$b{disk}} = $v;
+ } elsif ($cmd eq 'init-message') {
+ $v =~ s/\\n//g;
+ $v =~ s/"//g;
+ $b{'init-message'} = $v;
+ } else {
+ $b{$cmd} = $v eq '' ? 1 : $v;
+ }
+ } else {
+ if (($cmd eq 'map-drive' .. $cmd eq 'to') && $cmd eq 'to') {
+ $e->{mapdrive}{$e->{'map-drive'}} = $v;
+ } else {
+ if ($cmd eq 'initrd') {
+ $v = $filter_file->($v);
+ }
+ $e->{$cmd} = $v || 1;
+ }
+ }
+ }
+
+ sub remove_quotes_and_spaces {
+ local ($_) = @_;
+ s/^\s*//; s/\s*$//;
+ s/^"(.*?)"$/$1/;
+ s/\\"/"/g;
+ s/^\s*//; s/\s*$//; #- do it again for append=" foo"
+ $_;
+ }
+
+ foreach ('append', 'root', 'default', 'raid-extra-boot') {
+ $b{$_} = remove_quotes_and_spaces($b{$_}) if $b{$_};
+ }
+ foreach my $entry (@{$b{entries}}) {
+ foreach ('append', 'root', 'label') {
+ $entry->{$_} = remove_quotes_and_spaces($entry->{$_}) if $entry->{$_};
+ }
+ if ($entry->{kernel_or_dev} =~ /\bmbootpack\b/) {
+ $entry->{initrd} = $entry->{kernel_or_dev};
+ $entry->{initrd} =~ s/\bmbootpack/initrd/;
+ $entry->{kernel_or_dev} =~ s/\bmbootpack/vmlinuz/;
+ $entry->{kernel_or_dev} =~ s/.img$//;
+ #- assume only xen is configured with mbootpack
+ $entry->{xen} = '/boot/xen.gz';
+ $entry->{root} = $1 if $entry->{append} =~ s/root=(\S*)\s*//;
+ ($entry->{xen_append}, $entry->{append}) = split '\s*--\s*', $entry->{append}, 2;
+ }
+ }
+
+ # cleanup duplicate labels (in case file is corrupted)
+ @{$b{entries}} = uniq_ { $_->{label} } @{$b{entries}};
+
+ \%b;
+}
+
+sub cleanup_entries {
+ my ($bootloader) = @_;
+
+ #- cleanup bad entries (in case file is corrupted)
+ @{$bootloader->{entries}} =
+ grep {
+ my $pb = $_->{type} eq 'image' && !$_->{keep_verbatim} && ! -e "$::prefix$_->{kernel_or_dev}";
+ log::l("dropping bootloader entry $_->{label} since $_->{kernel_or_dev} doesn't exist") if $pb;
+ !$pb;
+ } @{$bootloader->{entries}};
+}
+
+sub suggest_onmbr {
+ my ($hd) = @_;
+
+ my ($onmbr, $unsafe) = (1, 1);
+
+ if (my $type = partition_table::raw::typeOfMBR($hd->{device})) {
+ if (member($type, qw(dos dummy empty))) {
+ $unsafe = 0;
+ } elsif (!member($type, qw(lilo grub grub2))) {
+ $onmbr = 0;
+ }
+ log::l("bootloader::suggest_onmbr: type $type, onmbr $onmbr, unsafe $unsafe");
+ }
+ ($onmbr, $unsafe);
+}
+
+# list of places where we can install the bootloader
+sub allowed_boot_parts {
+ my ($bootloader, $all_hds) = @_;
+ (
+ @{$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
+ detect_devices::floppies(),
+ );
+}
+
+sub same_entries {
+ my ($a, $b) = @_;
+
+ foreach (uniq(keys %$a, keys %$b)) {
+ if (member($_, 'label', 'append', 'mapdrive', 'readonly', 'makeactive', 'verbatim')) {
+ next;
+ } elsif ($_ eq 'grub_root' && (!$a->{$_} || !$b->{$_})) {
+ #- grub_root is mostly internal stuff. if it misses, it's ok
+ next;
+ } else {
+ next if $a->{$_} eq $b->{$_};
+
+ my ($inode_a, $inode_b) = map { (stat "$::prefix$_")[1] } ($a->{$_}, $b->{$_});
+ next if $inode_a && $inode_b && $inode_a == $inode_b;
+ }
+
+ log::l("entries $a->{label} do not have same $_: $a->{$_} ne $b->{$_}");
+ return;
+ }
+ 1;
+}
+
+sub add_entry {
+ my ($bootloader, $v) = @_;
+
+ my $to_add = $v;
+ my $label = $v->{label};
+ for (my $i = 0; $i < 100;) {
+ my $conflicting = get_label($label, $bootloader);
+
+ $to_add->{label} = $label;
+
+ if ($conflicting) {
+ #- replacing $conflicting with $to_add
+ @{$bootloader->{entries}} = map { $_ == $conflicting ? $to_add : $_ } @{$bootloader->{entries}};
+
+ #- we will keep $conflicting, but not with same symlinks if used by the entry to add
+ expand_entry_symlinks($bootloader, $conflicting);
+ } else {
+ #- we have found an unused label
+ push @{$bootloader->{entries}}, $to_add;
+ }
+
+ if (!$conflicting || same_entries($conflicting, $to_add)) {
+ log::l("current labels: " . join(" ", map { $_->{label} } @{$bootloader->{entries}}));
+ return $v;
+ }
+ $to_add = $conflicting;
+
+ if ($to_add->{label} eq 'linux') {
+ $label = kernel_str2label(vmlinuz2kernel_str($to_add->{kernel_or_dev}), 'use_long_name');
+ } else {
+ $label =~ s/^alt\d*_//;
+ $label = 'alt' . ($i++ ? $i : '') . "_$label";
+ }
+ }
+ die 'add_entry';
+}
+
+sub expand_entry_symlinks {
+ my ($bootloader, $entry) = @_;
+
+ foreach my $kind ('kernel_or_dev', 'initrd') {
+ my $old_long_name = $bootloader->{old_long_names} && $bootloader->{old_long_names}{$entry->{$kind}} or next;
+
+ #- replace all the {$kind} using this symlink to the real file
+ log::l("replacing $entry->{$kind} with $old_long_name for bootloader label $entry->{label}");
+ $entry->{$kind} = $old_long_name;
+ }
+}
+
+sub _do_the_symlink {
+ my ($bootloader, $link, $long_name) = @_;
+
+ my $existing_link = readlink("$::prefix$link");
+ if ($existing_link && $existing_link eq $long_name) {
+ #- nothing to do :)
+ return;
+ }
+
+ if ($existing_link) {
+ #- the symlink is going to change!
+ #- replace all the {$kind} using this symlink to the real file
+ my $old_long_name = $existing_link =~ m!^/! ? $existing_link : "/boot/$existing_link";
+ if (-e "$::prefix$old_long_name") {
+ $bootloader->{old_long_names}{$link} = $old_long_name;
+ } else {
+ log::l("ERROR: $link points to $old_long_name which does not exist");
+ }
+ } elsif (-e "$::prefix$link") {
+ log::l("ERROR: $link is not a symbolic link");
+ }
+
+ #- changing the symlink
+ symlinkf($long_name, "$::prefix$link")
+ or cp_af("$::prefix/boot/$long_name", "$::prefix$link");
+}
+
+# for lilo & xen
+sub get_mbootpack_filename {
+ my ($entry) = @_;
+ my $mbootpack_file = $entry->{initrd};
+ $mbootpack_file =~ s/\binitrd/mbootpack/;
+ $entry->{xen} && $mbootpack_file;
+}
+
+# for lilo & xen
+sub build_mbootpack {
+ my ($entry) = @_;
+
+ my $mbootpack = '/usr/bin/mbootpack';
+ -f $::prefix . $entry->{kernel_or_dev} && -f $::prefix . $entry->{initrd} or return;
+
+ my $mbootpack_file = get_mbootpack_filename($entry);
+ -f ($::prefix . $mbootpack_file) and return 1;
+
+ my $error;
+ my $xen_kernel = '/tmp/xen_kernel';
+ my $xen_vmlinux = '/tmp/xen_vmlinux';
+ my $_b = before_leaving { unlink $::prefix . $_ foreach $xen_kernel, $xen_vmlinux };
+ run_program::rooted($::prefix, '/bin/gzip', '>', $xen_kernel, '2>', \$error, '-dc', $entry->{xen})
+ or die "unable to uncompress xen kernel";
+ run_program::rooted($::prefix, '/bin/gzip', '>', $xen_vmlinux, '2>', \$error, '-dc', $entry->{kernel_or_dev})
+ or die "unable to uncompress xen vmlinuz";
+
+ run_program::rooted($::prefix, $mbootpack,
+ "2>", \$error,
+ '-o', $mbootpack_file,
+ '-m', $xen_vmlinux,
+ '-m', $entry->{initrd},
+ $xen_kernel)
+ or die "mbootpack failed: $error";
+
+ 1;
+}
+
+sub add_kernel {
+ my ($bootloader, $kernel_str, $v, $b_nolink, $b_no_initrd) = @_;
+
+ #- eg: for /boot/vmlinuz-2.6.17-13mdvxen0 (pkg kernel-xen0-xxx)
+ #- or /boot/vmlinuz-2.6.18-xen (pkg kernel-xen-uptodate)
+ if ($kernel_str->{version} =~ /xen/ && -f '/boot/xen.gz') {
+ $v->{xen} = '/boot/xen.gz';
+ }
+
+ add2hash($v,
+ {
+ type => 'image',
+ label => kernel_str2label($kernel_str),
+ });
+
+ #- normalize append and handle special options
+ {
+ my ($simple, $dict) = unpack_append("$bootloader->{perImageAppend} $v->{append}");
+ if ($v->{label} eq 'failsafe') {
+ #- perImageAppend contains resume=/dev/xxx which we don't want
+ @$dict = grep { $_->[0] ne 'resume' } @$dict;
+ }
+ $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
+ $b_nolink ||= $v->{xen};
+
+ my $vmlinuz_long = kernel_str2vmlinuz_long($kernel_str);
+ my $initrd_long = kernel_str2initrd_long($kernel_str);
+ $v->{kernel_or_dev} = "/boot/$vmlinuz_long";
+ -e "$::prefix$v->{kernel_or_dev}" or log::l("unable to find kernel image $::prefix$v->{kernel_or_dev}"), return;
+ log::l("adding $v->{kernel_or_dev}");
+
+ if (!$b_no_initrd) {
+ $v->{initrd} = mkinitrd($kernel_str->{version}, $bootloader, $v, "/boot/$initrd_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);
+ }
+ }
+ }
+
+ add_entry($bootloader, $v);
+}
+
+sub rebuild_initrds {
+ my ($bootloader) = @_;
+
+ my %done;
+ foreach my $v (grep { $_->{initrd} } @{$bootloader->{entries}}) {
+ my $kernel_str = vmlinuz2kernel_str($v->{kernel_or_dev}) or next;
+ my $initrd_long = '/boot/' . kernel_str2initrd_long($kernel_str);
+ next if $done{$initrd_long}++;
+
+ rebuild_initrd($kernel_str->{version}, $bootloader, $v, $initrd_long);
+ }
+}
+
+# unused (?)
+sub duplicate_kernel_entry {
+ my ($bootloader, $new_label) = @_;
+
+ get_label($new_label, $bootloader) and return;
+
+ my $entry = { %{ get_label('linux', $bootloader) }, label => $new_label };
+ add_entry($bootloader, $entry);
+}
+
+my $uniq_dict_appends = join('|', qw(acpi pci resume PROFILE XFree));
+
+sub unpack_append {
+ my ($s) = @_;
+ my @l = "$s " =~ /((?:[^"\s]+|".*?")*)\s+/g;
+ [ grep { !/=/ } @l ], [ map { if_(/(.*?)=(.*)/, [$1, $2]) } @l ];
+}
+sub pack_append {
+ my ($simple, $dict) = @_;
+
+ #- normalize
+ $simple = [ reverse(uniq(reverse @$simple)) ];
+ $dict = [ reverse(uniq_ {
+ my ($k, $v) = @$_;
+ $k =~ /^($uniq_dict_appends)$/ ? $k : "$k=$v";
+ } reverse @$dict) ];
+
+ join(' ', @$simple, map { "$_->[0]=$_->[1]" } @$dict);
+}
+
+sub modify_append {
+ my ($b, $f) = @_;
+
+ my @l = grep { $_->{type} eq 'image' && !$_->{keep_verbatim} && !($::isStandalone && $_->{label} eq 'failsafe') } @{$b->{entries}};
+
+ foreach (\$b->{perImageAppend}, map { \$_->{append} } @l) {
+ my ($simple, $dict) = unpack_append($$_);
+ $f->($simple, $dict);
+ $$_ = pack_append($simple, $dict);
+ log::l("modify_append: $$_");
+ }
+}
+
+sub get_append_simple {
+ my ($b, $key) = @_;
+ my ($simple, $_dict) = unpack_append($b->{perImageAppend});
+ member($key, @$simple);
+}
+sub get_append_with_key {
+ my ($b, $key) = @_;
+ my ($_simple, $dict) = unpack_append($b->{perImageAppend});
+ my @l = map { $_->[1] } grep { $_->[0] eq $key } @$dict;
+
+ log::l("more than one $key in $b->{perImageAppend}") if @l > 1;
+ $l[0];
+}
+sub remove_append_simple {
+ my ($b, $key) = @_;
+ modify_append($b, sub {
+ my ($simple, $_dict) = @_;
+ @$simple = grep { $_ ne $key } @$simple;
+ });
+}
+sub set_append_with_key {
+ my ($b, $key, $val) = @_;
+
+ modify_append($b, sub {
+ my ($_simple, $dict) = @_;
+
+ if ($val eq '') {
+ @$dict = grep { $_->[0] ne $key } @$dict;
+ } else {
+ push @$dict, [ $key, $val ];
+ }
+ });
+}
+sub set_append_simple {
+ my ($b, $key) = @_;
+
+ modify_append($b, sub {
+ my ($simple, $_dict) = @_;
+ @$simple = uniq(@$simple, $key);
+ });
+}
+sub may_append_with_key {
+ my ($b, $key, $val) = @_;
+ set_append_with_key($b, $key, $val) if !get_append_with_key($b, $key);
+}
+
+sub get_append_netprofile {
+ my ($e) = @_;
+ my ($simple, $dict) = unpack_append($e->{append});
+ my ($p, $dict_) = partition { $_->[0] eq 'PROFILE' } @$dict;
+ pack_append($simple, $dict_), $p->[0][1];
+}
+sub set_append_netprofile {
+ my ($e, $append, $profile) = @_;
+ my ($simple, $dict) = unpack_append($append);
+ push @$dict, [ 'PROFILE', $profile ] if $profile;
+ $e->{append} = pack_append($simple, $dict);
+}
+
+# used when a bootloader $entry has been modified (eg: $entry->{vga})
+sub configure_entry {
+ my ($bootloader, $entry) = @_;
+ $entry->{type} eq 'image' or return;
+
+ if (my $kernel_str = vmlinuz2kernel_str($entry->{kernel_or_dev})) {
+ $entry->{initrd} =
+ mkinitrd($kernel_str->{version}, $bootloader, $entry,
+ $entry->{initrd} || '/boot/' . kernel_str2initrd_short($kernel_str));
+ }
+}
+
+sub get_kernels_and_labels_before_kernel_remove {
+ my ($to_remove_kernel) = @_;
+ my @kernels = grep { $_ ne $to_remove_kernel } installed_vmlinuz();
+ map { kernel_str2label($_) => $_ } get_kernel_labels(\@kernels);
+}
+
+sub get_kernels_and_labels() {
+ get_kernel_labels([ installed_vmlinuz() ]);
+}
+
+sub get_kernel_labels {
+ my ($kernels) = @_;
+
+ my @kernels_str =
+ sort { common::cmp_kernel_versions($b->{version_no_ext}, $a->{version_no_ext}) }
+ grep { -d "$::prefix/lib/modules/$_->{version}" }
+ map { vmlinuz2kernel_str($_) } @$kernels;
+
+ my %labels;
+ foreach (@kernels_str) {
+ if ($labels{$_->{ext}}) {
+ $_->{use_long_name} = 1;
+ } else {
+ $labels{$_->{ext}} = 1;
+ }
+ }
+
+ $kernels_str[0]{ext} = '';
+
+ @kernels_str;
+}
+
+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) = @_;
+
+ my $name = $kernel_str->{basename};
+ $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
+sub suggest_message_text {
+ my ($bootloader) = @_;
+
+ if (!$bootloader->{message} && !$bootloader->{message_text} && arch() !~ /ia64/) {
+ 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!
+
+Choose an operating system from the list above or
+wait for default boot.
+
+");
+ my $msg = translate($msg_en);
+ #- 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) {
+ $msg = $msg_en;
+ } else {
+ $msg = Locale::gettext::iconv($msg, "utf-8", "ascii//TRANSLIT");
+ }
+ $bootloader->{message_text} = $msg;
+ }
+}
+
+sub suggest {
+ my ($bootloader, $all_hds, %options) = @_;
+ my $fstab = [ fs::get::fstab($all_hds) ];
+ 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 ($root_part->{is_removable}) {
+ $mbr = fs::get::part2hd($root_part, $all_hds);
+ } else {
+ $mbr = find { !$_->{is_removable} } @{$all_hds->{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,
+ } :
+ {
+ 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);
+
+ add2hash_($bootloader, { memsize => $1 }) if cat_("/proc/cmdline") =~ /\bmem=(\d+[KkMm]?)(?:\s.*)?$/;
+ if (my ($s, $port, $speed) = cat_("/proc/cmdline") =~ /console=(ttyS(\d),(\d+)\S*)/) {
+ log::l("serial console $s $port $speed");
+ set_append_with_key($bootloader, console => $s);
+ any::set_login_serial_console($port, $speed);
+ }
+
+ my @kernels = get_kernels_and_labels() or die "no kernel installed";
+
+ 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}};
+
+ 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} && $e->{label} eq 'linux') {
+ add_kernel($bootloader, $kernel, { root => $root, label => 'linux-nonfb' });
+ }
+ }
+
+ add_kernel($bootloader, $kernels[0],
+ { root => $root, label => 'failsafe', append => 'failsafe' })
+ 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')
+ && !$_->{is_removable}
+ && !isRecovery($_);
+ }
+ map { @{$_->{primary}{normal}} } @{$all_hds->{hds}};
+ each_index {
+ add_entry($bootloader,
+ {
+ type => 'other',
+ kernel_or_dev => "/dev/$_->{device}",
+ label => 'windows' . ($::i || ''),
+ table => "/dev/$_->{rootDevice}",
+ 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) {
+ $bootloader->{default} ||= $preferred;
+ }
+ $bootloader->{default} ||= "linux";
+ $bootloader->{method} ||= first(method_choices($all_hds, 1), # best installed
+ 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)) {
+ 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);
+ }
+ }
+ }
+}
+
+sub detect_main_method {
+ my ($all_hds) = @_;
+ my $bootloader = &read($all_hds);
+ $bootloader && main_method($bootloader->{method});
+}
+
+sub main_method {
+ my ($method) = @_;
+ $method =~ /(\w+)/ && $1;
+}
+
+sub config_files() {
+ my %files = (
+ lilo => '/etc/lilo.conf',
+ grub => '/boot/grub/menu.lst',
+ grub_install => '/boot/grub/install.sh',
+ );
+
+ map_each {
+ my $content = cat_("$::prefix/$::b");
+ { main_method => main_method($::a), name => $::a, file => $::b, content => $content };
+ } %files;
+}
+
+sub method2text {
+ my ($method) = @_;
+ +{
+ 'lilo-menu' => N("LILO with text menu"),
+ 'grub2' => N("GRUB2 with graphical menu"),
+ 'grub-graphic' => N("GRUB with graphical menu"),
+ 'grub-menu' => N("GRUB with text menu"),
+ 'yaboot' => N("Yaboot"),
+ 'silo' => N("SILO"),
+ }->{$method};
+}
+
+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('grub', $::prefix),
+ 'grub-graphic', 'grub-menu'),
+ if_(!$b_prefix_mounted || whereis_binary('grub2-reboot', $::prefix),
+ 'grub2'),
+ if_(!$b_prefix_mounted || whereis_binary('lilo', $::prefix),
+ 'lilo-menu'),
+ );
+}
+sub method_choices {
+ my ($all_hds, $b_prefix_mounted) = @_;
+ my $fstab = [ fs::get::fstab($all_hds) ];
+ my $root_part = fs::get::root($fstab);
+ my $boot_part = fs::get::root($fstab, 'boot');
+ 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/);
+ } method_choices_raw($b_prefix_mounted);
+}
+sub main_method_choices {
+ my ($b_prefix_mounted) = @_;
+ uniq(map { main_method($_) } method_choices_raw($b_prefix_mounted));
+}
+sub configured_main_methods() {
+ my @bad_main_methods = map { if_(!$_->{content}, $_->{main_method}) } config_files();
+ difference2([ main_method_choices(1) ], \@bad_main_methods);
+}
+
+# for lilo
+sub keytable {
+ my ($f) = @_;
+ $f or return;
+
+ if ($f !~ /\.klt$/) {
+ my $file = "/boot/$f.klt";
+ run_program::rooted($::prefix, "keytab-lilo.pl", ">", $file, $f) or return;
+ $f = $file;
+ }
+ -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_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";
+}
+
+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 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...");
+}
+
+sub install_cromwell {
+ my ($_bootloader, $_all_hds) = @_;
+ log::l("XBox/Cromwell - nothing to install...");
+}
+sub write_cromwell {
+ my ($_bootloader, $_all_hds) = @_;
+ log::l("XBox/Cromwell - nothing to write...");
+}
+sub when_config_changed_cromwell {
+ my ($_bootloader) = @_;
+ log::l("XBox/Cromwell - nothing to do...");
+}
+
+sub simplify_label {
+ my ($label) = @_;
+
+ length($label) < 31 or $label =~ s/\.//g;
+
+ $label = substr($label, 0, 31); #- lilo does not handle more than 31 char long labels
+ $label =~ s/ /_/g; #- lilo does not support blank character in image names, labels or aliases
+ $label;
+}
+
+sub make_label_lilo_compatible {
+ my ($label) = @_;
+ '"' . simplify_label($label) . '"';
+}
+
+sub write_lilo {
+ my ($bootloader, $all_hds, $o_backup_extension) = @_;
+ $bootloader->{prompt} ||= $bootloader->{timeout};
+
+ my $file2fullname = sub {
+ my ($file) = @_;
+ if (arch() =~ /ia64/) {
+ my $fstab = [ fs::get::fstab($all_hds) ];
+ (my $part, $file) = fs::get::file2part($fstab, $file);
+ my %hds = map_index { $_ => "hd$::i" } map { $_->{device} }
+ sort {
+ my ($a_is_fat, $b_is_fat) = ($a->{fs_type} eq 'vfat', $b->{fs_type} eq 'vfat');
+ $a_is_fat <=> $b_is_fat || $a->{device} cmp $b->{device};
+ } @$fstab;
+ $hds{$part->{device}} . ":" . $file;
+ } else {
+ $file;
+ }
+ };
+
+ my $quotes = sub {
+ my ($s) = @_;
+ $s =~ s/"/\\"/g;
+ qq("$s");
+ };
+
+ my $quotes_if_needed = sub {
+ my ($s) = @_;
+ $s =~ /["=\s]/ ? $quotes->($s) : $s;
+ };
+
+
+ my @sorted_hds = sort_hds_according_to_bios($bootloader, $all_hds);
+
+ if (is_empty_hash_ref($bootloader->{bios} ||= {}) && $all_hds->{hds}[0] != $sorted_hds[0]) {
+ log::l("Since we're booting on $sorted_hds[0]{device}, make it bios=0x80");
+ $bootloader->{bios} = { "/dev/$sorted_hds[0]{device}" => '0x80' };
+ }
+
+ my @conf;
+
+ #- normalize: RESTRICTED and MANDATORY are only valid if PASSWORD is set
+ if ($bootloader->{password}) {
+ # lilo defaults to mandatory, use restricted by default to have
+ # the same behaviour as with grub
+ $bootloader->{restricted} = 1;
+ } else {
+ delete $bootloader->{mandatory} if !$bootloader->{password};
+ delete $bootloader->{restricted} if !$bootloader->{password};
+ }
+ foreach my $entry (@{$bootloader->{entries}}) {
+ delete $entry->{mandatory} if !$entry->{password} && !$bootloader->{password};
+ delete $entry->{restricted} if !$entry->{password} && !$bootloader->{password};
+ }
+ if (get_append_with_key($bootloader, 'console') =~ /ttyS(.*)/) {
+ $bootloader->{serial} ||= $1;
+ }
+
+ 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, "# File generated by DrakX/drakboot";
+ push @conf, "# WARNING: do not forget to run lilo after modifying this file\n";
+ push @conf, "default=" . make_label_lilo_compatible($bootloader->{default}) if $bootloader->{default};
+ push @conf, map { $_ . '=' . $quotes_if_needed->($bootloader->{$_}) } grep { $bootloader->{$_} } qw(boot root map install serial vga keytable raid-extra-boot menu-scheme vmdefault);
+ push @conf, grep { $bootloader->{$_} } qw(linear geometric compact prompt mandatory nowarn restricted static-bios-codes large-memory);
+ push @conf, "append=" . $quotes->($bootloader->{append}) if $bootloader->{append};
+ push @conf, "password=" . $bootloader->{password} if $bootloader->{password}; #- also done by msec
+ push @conf, "timeout=" . round(10 * $bootloader->{timeout}) if $bootloader->{timeout};
+
+ push @conf, "message=$bootloader->{message}" if $bootloader->{message};
+
+ push @conf, "ignore-table" if any { $_->{unsafe} && $_->{table} } @{$bootloader->{entries}};
+
+ push @conf, map_each { "disk=$::a bios=$::b" } %{$bootloader->{bios}};
+
+ foreach my $entry (@{$bootloader->{entries}}) {
+ my $mbootpack_file = get_mbootpack_filename($entry);
+ if ($mbootpack_file && !build_mbootpack($entry)) {
+ warn "mbootpack is required for xen but unavailable, skipping\n";
+ next;
+ }
+ if ($entry->{type} eq 'grub_configfile') {
+ next;
+ }
+
+ push @conf, "$entry->{type}=" . $file2fullname->($mbootpack_file || $entry->{kernel_or_dev});
+ my @entry_conf;
+ push @entry_conf, "label=" . make_label_lilo_compatible($entry->{label}) if $entry->{label};
+
+ if ($entry->{type} eq "image") {
+ push @entry_conf, 'root=' . $quotes_if_needed->($entry->{root}) if $entry->{root} && !$entry->{xen};
+ push @entry_conf, "initrd=" . $file2fullname->($entry->{initrd}) if $entry->{initrd} && !$mbootpack_file;
+ my $append = join(' ', if_($entry->{xen_append}, $entry->{xen_append}),
+ if_($entry->{xen}, '--', 'root=' . $entry->{root}),
+ if_($entry->{append}, $entry->{append}));
+ push @entry_conf, "append=" . $quotes->($append) if $append;
+ push @entry_conf, "vga=$entry->{vga}" if $entry->{vga};
+ push @entry_conf, grep { $entry->{$_} } qw(read-write read-only optional);
+ push @entry_conf, "mandatory" if $entry->{lock};
+ } else {
+ delete $entry->{unsafe} if $entry->{table}; #- we can't have both
+ push @entry_conf, map { "$_=$entry->{$_}" } grep { $entry->{$_} } qw(table boot-as);
+ push @entry_conf, grep { $entry->{$_} } qw(unsafe master-boot);
+
+ if ($entry->{table}) {
+ #- hum, things like table=c: are needed for some os2 cases,
+ #- in that case $hd below is undef
+ my $hd = fs::get::device2part($entry->{table}, $all_hds->{hds});
+ if ($hd && $hd != $sorted_hds[0]) {
+ #- boot off the nth drive, so reverse the BIOS maps
+ my $nb = sprintf("0x%x", 0x80 + (find_index { $hd == $_ } @sorted_hds));
+ $entry->{mapdrive} ||= { '0x80' => $nb, $nb => '0x80' };
+ }
+ }
+ if ($entry->{mapdrive}) {
+ push @entry_conf, map_each { "map-drive=$::a", " to=$::b" } %{$entry->{mapdrive}};
+ }
+ }
+ push @entry_conf, "password=$entry->{password}" if $entry->{password};
+ push @entry_conf, grep { $entry->{$_} } qw(mandatory vmwarn vmdisable);
+
+ push @conf, map { "\t$_" } @entry_conf;
+ }
+ my $f = arch() =~ /ia64/ ? "$::prefix/boot/efi/elilo.conf" : "$::prefix/etc/lilo.conf";
+
+ log::l("writing lilo config to $f");
+ renamef($f, $f . ($o_backup_extension || '.old'));
+ output_with_perm($f, $bootloader->{password} ? 0600 : 0644, map { "$_\n" } @conf);
+}
+
+sub install_lilo {
+ my ($bootloader, $all_hds) = @_;
+
+ if (my ($install) = $bootloader->{method} =~ /lilo-(text|menu)/) {
+ $bootloader->{install} = $install;
+ } else {
+ delete $bootloader->{install};
+ }
+ if ($bootloader->{message_text}) {
+ output("$::prefix/boot/message-text", $bootloader->{message_text});
+ }
+ my $message = "message-text";
+ if (-r "$::prefix/boot/$message") {
+ symlinkf $message, "$::prefix/boot/message";
+ $bootloader->{message} = '/boot/message';
+ }
+
+ #- ensure message does not contain the old graphic format
+ if ($bootloader->{message} && -s "$::prefix$bootloader->{message}" > 65_000) {
+ output("$::prefix$bootloader->{message}", '');
+ }
+
+ write_lilo($bootloader, $all_hds);
+
+ when_config_changed_lilo($bootloader);
+
+ configure_kdm_BootManager('Lilo');
+}
+
+sub install_raw_lilo {
+ my ($o_force_answer) = @_;
+
+ my $error;
+ my $answer = $o_force_answer || '';
+ run_program::rooted($::prefix, "echo $answer | lilo", '2>', \$error) or die "lilo failed: $error";
+}
+
+sub when_config_changed_lilo {
+ my ($bootloader) = @_;
+ if (!$::testing && arch() !~ /ia64/ && $bootloader->{method} =~ /lilo/) {
+ log::l("Installing boot loader on $bootloader->{boot}...");
+ install_raw_lilo($bootloader->{force_lilo_answer});
+ }
+}
+
+#- NB: ide is lower than scsi, this is important for sort_hds_according_to_bios()
+sub hd2bios_kind {
+ my ($hd) = @_;
+ lc(join('_', $hd->{bus}, $hd->{host}));
+}
+
+sub ensafe_first_bios_drive {
+ my ($hds) = @_;
+ mixed_kind_of_disks($hds) || @$hds > 1 && _not_first_bios_drive($hds->[0]);
+}
+sub mixed_kind_of_disks {
+ my ($hds) = @_;
+ (uniq_ { hd2bios_kind($_) } @$hds) > 1;
+}
+sub _not_first_bios_drive {
+ my ($hd) = @_;
+ my $bios = $hd && $hd->{bios_from_edd};
+ $bios && $bios ne '80';
+}
+
+sub sort_hds_according_to_bios {
+ my ($bootloader, $all_hds) = @_;
+ my $boot_hd = fs::get::device2part($bootloader->{first_hd_device} || $bootloader->{boot}, $all_hds->{hds}); #- $boot_hd is undefined when installing on floppy
+ my $boot_kind = $boot_hd && hd2bios_kind($boot_hd);
+
+ my $translate = sub {
+ my ($hd) = @_;
+ my $kind = hd2bios_kind($hd);
+ $boot_hd ? ($hd == $boot_hd ? 0 : $kind eq $boot_kind ? 1 : 2) . "_$kind" : $kind;
+ };
+ sort { $translate->($a) cmp $translate->($b) } @{$all_hds->{hds}};
+}
+
+sub device_string2grub {
+ my ($dev, $legacy_floppies, $sorted_hds) = @_;
+ if (my $device = fs::get::device2part($dev, [ @$sorted_hds, fs::get::hds_fstab(@$sorted_hds) ])) {
+ device2grub($device, $sorted_hds);
+ } elsif (my $floppy = fs::get::device2part($dev, $legacy_floppies)) {
+ my $bios = find_index { $floppy eq $_ } @$legacy_floppies;
+ "(fd$bios)";
+ } else {
+ internal_error("unknown device $dev");
+ }
+}
+sub device2grub {
+ my ($device, $sorted_hds) = @_;
+
+ if (isRAID($device) && $device->{level} == 1) {
+ #- we can take any disk
+ $device = $device->{disks}[0];
+ }
+ my ($hd, $part_nb) =
+ $device->{rootDevice} ?
+ (fs::get::device2part($device->{rootDevice}, $sorted_hds), $device->{device} =~ /(\d+)$/) :
+ $device;
+ my $bios = eval { find_index { $hd eq $_ } @$sorted_hds };
+ if (defined $bios) {
+ my $part_string = defined $part_nb ? ',' . ($part_nb - 1) : '';
+ "(hd$bios$part_string)";
+ } else {
+ undef;
+ }
+}
+
+sub read_grub_device_map() {
+ my %grub2dev = map { m!\((.*)\)\s+/dev/(.*)$! } cat_("$::prefix/boot/grub/device.map");
+ \%grub2dev;
+}
+sub write_grub_device_map {
+ my ($legacy_floppies, $sorted_hds) = @_;
+ my $f = "$::prefix/boot/grub/device.map";
+ renamef($f, "$f.old");
+ output($f,
+ (map_index { "(fd$::i) /dev/$_->{device}\n" } @$legacy_floppies),
+ (map_index { "(hd$::i) /dev/$_->{device}\n" } @$sorted_hds));
+}
+
+# parses things like "(hd0,4)/boot/vmlinuz"
+# returns: ("hd0", 4, "boot/vmlinuz")
+sub parse_grub_file {
+ my ($grub_file) = @_;
+ my ($grub_dev, $rel_file) = $grub_file =~ m!\((.*?)\)/?(.*)! or return;
+ my ($hd, $part) = split(',', $grub_dev);
+ ($hd, $part, $rel_file);
+}
+
+# takes things like "(hd0,4)/boot/vmlinuz"
+# returns: ("/dev/sda5", "boot/vmlinuz")
+sub grub2dev_and_file {
+ my ($grub_file, $grub2dev, $o_block_device) = @_;
+ my ($hd, $part, $rel_file) = parse_grub_file($grub_file) or return;
+ $grub2dev->{$hd} or internal_error("$hd has no mapping in device.map (when translating $grub_file)");
+ $part = $o_block_device ? '' : defined $part && $part + 1; #- grub wants "(hdX,Y)" where lilo just want "hdY+1"
+ 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"
+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
+sub grub2file {
+ my ($grub_file, $grub2dev, $fstab, $o_entry) = @_;
+
+ if ($grub_file =~ m!^/!) {
+ my $root = $o_entry && ($o_entry->{rootnoverify} || $o_entry->{grub_root});
+ $root and $grub_file = "$root$grub_file";
+ }
+
+ if (my ($device, $rel_file) = grub2dev_and_file($grub_file, $grub2dev)) {
+ my $part = fs::get::device2part($device, $fstab);
+ if (my $mntpoint = $part && $part->{mntpoint}) {
+ ($mntpoint eq '/' ? '' : $mntpoint) . '/' . $rel_file;
+ } else {
+ log::l("ERROR: unknown device $device (computed from $grub_file)");
+ $grub_file;
+ }
+ } else {
+ $grub_file;
+ }
+}
+
+sub boot_copies_dir() { '/boot/copied' }
+sub create_copy_in_boot {
+ my ($file) = @_;
+
+ my $s = $file;
+ $s =~ s!/!_!g;
+ my $file2 = boot_copies_dir() . "/$s";
+
+ log::l("$file is not available at boot time, creating a copy ($file2)");
+ mkdir_p(boot_copies_dir());
+ output("$file2.link", $file . "\n");
+ update_copy_in_boot("$file2.link");
+
+ $file2;
+}
+sub update_copy_in_boot {
+ my ($link) = @_;
+ my $orig = chomp_(cat_("$::prefix$link"));
+ (my $dest = $link) =~ s/\.link$// or internal_error("update_copy_in_boot: $link");
+ if (-e "$::prefix$orig") {
+ log::l("updating $dest from $orig");
+ cp_af("$::prefix$orig", "$::prefix$dest");
+ } else {
+ log::l("removing $dest since $orig does not exist anymore");
+ unlink "$::prefix$link", "$::prefix$orig";
+ }
+}
+
+sub crypt_grub_password {
+ my ($password) = @_;
+ require IPC::Open2;
+ local $ENV{LC_ALL} = 'C';
+ my ($his_out, $his_in);
+ my $cmd = ($::prefix ? "chroot $::prefix " : "") . "/sbin/grub-md5-crypt";
+
+ my $pid = IPC::Open2::open2($his_out, $his_in, $cmd);
+
+ my ($line, $res);
+ while (sysread($his_out, $line, 100)) {
+ if ($line =~ /Password/i) {
+ syswrite($his_in, "$password\n");
+ } else {
+ $res = $line;
+ }
+ }
+ waitpid($pid, 0);
+ my $status = $? >> 8;
+ die "failed to encrypt password (status=$status)" if $status != 0;
+ chomp_($res);
+}
+
+sub write_grub2 {
+ my ($bootloader, $_all_hds, $o_backup_extension) = @_;
+ my $error;
+
+ # set default parameters:
+ my ($entry) = grep { $_->{kernel_or_dev} =~ /vmlin/ } @{$bootloader->{entries}};
+ my $append = $entry->{append};
+ $append =~ s/root=\S+//g;
+ $append =~ s/\bro\b//g;
+ $append =~ s/\s+/ /g;
+
+ my $f = "$::prefix/etc/default/grub";
+ my %conf = getVarsFromSh($f);
+ $conf{GRUB_CMDLINE_LINUX_DEFAULT} = $append;
+ $conf{GRUB_TIMEOUT} = $bootloader->{timeout};
+ 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_grub {
+ my ($bootloader, $all_hds, $o_backup_extension) = @_;
+
+ my $fstab = [ fs::get::fstab($all_hds) ];
+ my @legacy_floppies = detect_devices::floppies();
+ my @sorted_hds = sort_hds_according_to_bios($bootloader, $all_hds);
+ write_grub_device_map(\@legacy_floppies, \@sorted_hds);
+
+ my $file2grub; $file2grub = sub {
+ my ($file) = @_;
+ if ($file =~ m!^\(.*\)/!) {
+ $file; #- it's already in grub format
+ } else {
+ my ($part, $rel_file) = fs::get::file2part($fstab, $file, 'keep_simple_symlinks');
+ if (my $grub = device2grub($part, \@sorted_hds)) {
+ $grub . $rel_file;
+ } elsif (!begins_with($file, '/boot/')) {
+ log::l("$file is on device $part->{device} which is not available at boot time. Copying it");
+ $file2grub->(create_copy_in_boot($file));
+ } else {
+ log::l("ERROR: $file is on device $part->{device} which is not available at boot time. Defaulting to a dumb value");
+ "(hd0,0)$file";
+ }
+ }
+ };
+
+ if (get_append_with_key($bootloader, 'console') =~ /ttyS(\d),(\d+)/) {
+ $bootloader->{serial} ||= "--unit=$1 --speed=$2";
+ $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$bin") {
+ my $locale = $::o->{locale} || do { require lang; lang::read() };
+ run_program::rooted($::prefix, $bin, '--lang', $locale->{lang}, '--update-gfxmenu');
+ $bootloader->{gfxmenu} ||= '/boot/gfxmenu';
+ }
+ #- not handled anymore
+ delete $bootloader->{$_} foreach qw(splashimage viewport shade);
+ } else {
+ delete $bootloader->{gfxmenu};
+ }
+
+ my $format = sub { map { "$_ $bootloader->{$_}" } @_ };
+
+ {
+ my @conf;
+
+ if ($bootloader->{password}) {
+ if (!is_already_crypted($bootloader->{password})) {
+ my $encrypted = crypt_grub_password($bootloader->{password});
+ $bootloader->{password} = "--md5 $encrypted";
+ }
+ }
+
+ push @conf, $format->(grep { defined $bootloader->{$_} } qw(timeout));
+ push @conf, $format->(grep { $bootloader->{$_} } qw(color password serial shade terminal viewport background foreground));
+
+ push @conf, map { $_ . ' ' . $file2grub->($bootloader->{$_}) } grep { $bootloader->{$_} } qw(gfxmenu);
+
+ eval {
+ push @conf, "default " . (find_index { $_->{label} eq $bootloader->{default} } @{$bootloader->{entries}});
+ };
+
+ foreach my $entry (@{$bootloader->{entries}}) {
+ my $title = "\ntitle $entry->{label}";
+
+ if ($entry->{keep_verbatim}) {
+ push @conf, '', $entry->{verbatim};
+ } elsif ($entry->{type} eq "image") {
+ push @conf, $title;
+ push @conf, grep { $entry->{$_} } 'lock';
+ push @conf, join(' ', 'kernel', $file2grub->($entry->{xen}), $entry->{xen_append}) if $entry->{xen};
+
+ my $vga = $entry->{vga} || $bootloader->{vga};
+ push @conf, join(' ', $entry->{xen} ? 'module' : 'kernel',
+ $file2grub->($entry->{kernel_or_dev}),
+ $entry->{xen} ? () : 'BOOT_IMAGE=' . simplify_label($entry->{label}),
+ if_($entry->{root}, $entry->{root} =~ /loop7/ ? "root=707" : "root=$entry->{root}"), #- special to workaround bug in kernel (see #ifdef CONFIG_BLK_DEV_LOOP)
+ $entry->{append},
+ if_($entry->{'read-write'}, 'rw'),
+ if_($vga && $vga ne "normal", "vga=$vga"));
+ push @conf, "module " . $_ foreach @{$entry->{modules} || []};
+ 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) {
+ log::l("dropping bad entry $entry->{label} for unknown device $entry->{kernel_or_dev}");
+ next;
+ }
+ push @conf, $title;
+ push @conf, grep { $entry->{$_} } 'lock';
+ 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)) {
+ if (my $bios = find_index { $hd eq $_ } @sorted_hds) {
+ #- boot off the nth drive, so reverse the BIOS maps
+ my $nb = sprintf("0x%x", 0x80 + $bios);
+ $entry->{mapdrive} ||= { '0x80' => $nb, $nb => '0x80' };
+ }
+ }
+ }
+ if ($entry->{mapdrive}) {
+ push @conf, map_each { "map ($::b) ($::a)" } %{$entry->{mapdrive}};
+ }
+ push @conf, "makeactive" if $entry->{makeactive};
+ # 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";
+ }
+ }
+ }
+ my $f = "$::prefix/boot/grub/menu.lst";
+ log::l("writing grub config to $f");
+ renamef($f, $f . ($o_backup_extension || '.old'));
+ output_with_perm($f, 0600, map { "$_\n" } @conf);
+ }
+ {
+ my $f = "$::prefix/boot/grub/install.sh";
+ my $boot_dev = device_string2grub($bootloader->{boot}, \@legacy_floppies, \@sorted_hds);
+ my $files_dev = device2grub(fs::get::root_($fstab, 'boot'), \@sorted_hds);
+ renamef($f, $f . ($o_backup_extension || '.old'));
+ output_with_perm($f, 0755,
+"grub --device-map=/boot/grub/device.map --batch <<EOF
+root $files_dev
+setup --stage2=/boot/grub/stage2 $boot_dev
+quit
+EOF
+");
+ }
+
+ check_enough_space();
+}
+
+sub configure_kdm_BootManager {
+ my ($name) = @_;
+ eval { common::update_gnomekderc_no_create("$::prefix/etc/kde/kdm/kdmrc", 'Shutdown' => (
+ BootManager => $name
+ )) };
+}
+
+sub sync_partition_data_to_disk {
+ my ($part) = @_;
+
+ common::sync();
+
+ if ($part->{fs_type} eq 'xfs') {
+ run_program::rooted($::prefix, 'xfs_freeze', '-f', $part->{mntpoint});
+ run_program::rooted($::prefix, 'xfs_freeze', '-u', $part->{mntpoint});
+ }
+}
+
+sub _dev_to_MBR_backup {
+ my ($dev) = @_;
+ $dev =~ s!/dev/!!;
+ $dev =~ s!/!_!g;
+ "$::prefix/boot/boot.backup.$dev";
+}
+
+sub save_previous_MBR_bootloader {
+ my ($dev) = @_;
+ my $t;
+ open(my $F, $dev);
+ CORE::read($F, $t, 0x1b8); #- up to disk magic
+ output(_dev_to_MBR_backup($dev), $t);
+}
+
+sub restore_previous_MBR_bootloader {
+ my ($dev) = @_;
+ log::l("restoring previous bootloader on $dev");
+ output($dev, scalar cat_(_dev_to_MBR_backup($dev)));
+}
+
+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";
+ }
+ setVarsInSh("$::prefix/boot/grub2/drakboot.conf", { boot => $boot });
+}
+
+sub install_grub {
+ my ($bootloader, $all_hds) = @_;
+
+ write_grub($bootloader, $all_hds);
+
+ if (!$::testing) {
+ if ($bootloader->{previous_boot} && $bootloader->{previous_boot} eq $bootloader->{boot}) {
+ # nothing to do (already installed in {boot})
+ } else {
+ if ($bootloader->{previous_boot}) {
+ restore_previous_MBR_bootloader(delete $bootloader->{previous_boot});
+ }
+ if (fs::get::device2part($bootloader->{boot}, [ fs::get::hds($all_hds) ])) {
+ save_previous_MBR_bootloader($bootloader->{boot});
+ $bootloader->{previous_boot} = $bootloader->{boot};
+ }
+ }
+
+ my @files = grep { /(stage1|stage2|_stage1_5)$/ } glob("$::prefix/lib/grub/*/*");
+ cp_af(@files, "$::prefix/boot/grub");
+ sync_partition_data_to_disk(fs::get::root([ fs::get::fstab($all_hds) ], 'boot'));
+ install_raw_grub();
+ }
+
+ configure_kdm_BootManager('Grub');
+}
+sub install_raw_grub() {
+ log::l("Installing boot loader...");
+ my $error;
+ 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
+
+ update_copy_in_boot($_) foreach glob($::prefix . boot_copies_dir() . '/*.link');
+}
+
+sub action {
+ my ($bootloader, $action, @para) = @_;
+
+ my $main_method = main_method($bootloader->{method});
+ my $f = $bootloader::{$action . '_' . $main_method} or die "unknown bootloader method $bootloader->{method} ($action)";
+ $f->($bootloader, @para);
+}
+
+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});
+ action($bootloader, 'install', $all_hds);
+}
+
+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 $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;
+ }
+ }
+ 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;
+ }
+ }
+}
+
+sub find_other_distros_grub_conf {
+ my ($fstab) = @_;
+
+ my @unknown_true_fs =
+ grep { isTrueLocalFS($_) &&
+ (!$_->{mntpoint} || !member($_->{mntpoint}, '/home', fs::type::directories_needed_to_boot()));
+ } @$fstab;
+
+ log::l("looking for configured grub on partitions " . join(' ', map { $_->{device} } @unknown_true_fs));
+
+ my @l;
+ foreach my $part (@unknown_true_fs) {
+ my $handle = any::inspect($part, $::prefix) or next;
+
+ foreach my $bootdir ('', '/boot') {
+ my $f = find { -e "$handle->{dir}$bootdir/$_" } 'grub.conf', 'grub/menu.lst' or next;
+ push @l, { bootpart => $part, bootdir => $bootdir, grub_conf => "$bootdir/$f" };
+ }
+ 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};
+ push @l, $h;
+ } elsif ($handle && -e "$handle->{dir}/etc/issue") {
+ my ($s, $dropped) = cat_("$handle->{dir}/etc/issue") =~ /^([^\\\n]*)(.*)/;
+ log::l("found /etc/issue: $s (removed: $dropped)");
+ push @l, { name => $s, part => $part };
+ }
+ }
+ my $root;
+ my $set_root = sub {
+ my ($v) = @_;
+ $root and log::l("don't know what to do with $root->{name} ($root->{part}{device})");
+ $root = $v;
+ };
+ my @found;
+ while (my $e = shift @l) {
+ if ($e->{name}) {
+ $set_root->($e);
+ } else {
+ if (@l && $l[0]{name}) {
+ $set_root->(shift @l);
+ }
+
+ my $ok;
+ if ($root && $root->{part} == $e->{bootpart} && $e->{bootdir}) {
+ # easy case: /boot is not a separate partition
+ $ok = 1;
+ } elsif ($root && $root->{part} != $e->{bootpart} && !$e->{bootdir}) {
+ log::l("associating '/' $root->{part}{device} with '/boot' $e->{bootpart}{device}");
+ $ok = 1;
+ }
+ if ($ok) {
+ add2hash($e, $root);
+ undef $root;
+ } elsif ($root) {
+ log::l("weird case for grub conf in $e->{bootpart}{device}, keeping '/' from $root->{part}{device}");
+ } else {
+ log::l("could not recognise the distribution for $e->{grub_conf} in $e->{bootpart}{device}");
+ }
+ $e->{name} ||= "Linux $e->{bootpart}{device}";
+ push @found, $e;
+ }
+ }
+ $set_root->(undef);
+
+ @found;
+}
+
+sub update_for_renumbered_partitions {
+ my ($in, $renumbering, $all_hds) = @_;
+
+ my @configs = grep { $_->{content} } config_files();
+ $_->{new} = $_->{orig} = $_->{content} foreach @configs;
+
+ my @sorted_hds; {
+ my $grub2dev = read_grub_device_map();
+ map_each {
+ $sorted_hds[$1] = fs::get::device2part($::b, $all_hds->{hds}) if $::a =~ /hd(\d+)/;
+ } %$grub2dev;
+ }
+
+ #- NB: we make the changes with an added string inside so that hda5 is only renamed once to hda6
+
+ foreach (@$renumbering) {
+ my ($old, $new) = @$_;
+ log::l("renaming $old -> $new");
+ (my $lnew = $new) =~ s/(\d+)$/__DRAKX_DONE__$1/;
+ $_->{new} =~ s/\b$old/$lnew/g foreach @configs;
+
+ any { $_->{name} eq 'grub' } @configs or next;
+
+ my ($old_grub, $new_grub) = map { device_string2grub($_, [], \@sorted_hds) } $old, $new;
+ log::l("renaming $old_grub -> $new_grub");
+ (my $lnew_grub = $new_grub) =~ s/\)$/__DRAKX_DONE__)/;
+ $_->{new} =~ s/\Q$old_grub/$lnew_grub/g foreach @configs;
+ }
+
+ $_->{new} =~ s/__DRAKX_DONE__//g foreach @configs;
+
+ my @changed_configs = grep { $_->{orig} ne $_->{new} } @configs or return 1; # no need to update
+
+ $in->ask_okcancel('', N("Your bootloader configuration must be updated because partition has been renumbered")) or return;
+
+ foreach (@changed_configs) {
+ renamef("$::prefix/$_->{file}", "$::prefix/$_->{file}.old");
+ output("$::prefix/$_->{file}", $_->{new});
+ }
+
+ my $main_method = detect_main_method($all_hds);
+ my @needed = map {
+ $_ eq 'grub' ? 'grub_install' : $_;
+ } $main_method ? $main_method : ('lilo', 'grub');
+
+ if (intersection(\@needed, [ map { $_->{name} } @changed_configs ])) {
+ $in->ask_warn('', N("The bootloader cannot be installed correctly. You have to boot rescue and choose \"%s\"",
+ N("Re-install Boot Loader")));
+ }
+ 1;
+}
+
+1;
diff --git a/files/live-dracut.conf b/files/live-dracut.conf
index dc239d7..0c644a5 100644
--- a/files/live-dracut.conf
+++ b/files/live-dracut.conf
@@ -12,3 +12,5 @@ compress_l="xz"
filesystems="iso9660 vfat =fs/nls squashfs unionfs"
# fibre channel & iSCSI modules are unneeded on live CD/USB and pull 1MB+ of firmware files
omit_drivers+=" qla1280 qla2xxx qla4xxx "
+# pata_acpi is not wanted on boot
+omit_drivers+=" pata_acpi "
diff --git a/files/live.modprobe.DVD b/files/live.modprobe.DVD
new file mode 100644
index 0000000..5bb2345
--- /dev/null
+++ b/files/live.modprobe.DVD
@@ -0,0 +1 @@
+install usblp /bin/true
diff --git a/files/mga_rpms/update_media.sh b/files/mga_rpms/update_media.sh
new file mode 100755
index 0000000..f200eab
--- /dev/null
+++ b/files/mga_rpms/update_media.sh
@@ -0,0 +1,42 @@
+
+bcdmedia=/home/bcd/build_bcd/pieces/cauldron
+
+rm -f {i586,x86_64}/mga_rpms/{core,nonfree}/*.rpm
+rm -f {i586,x86_64}/mga_rpms/{core,nonfree}/media_info/*
+
+# add broadcom-wl
+cp $bcdmedia/i586/media/nonfree/release/broadcom-wl-common*.rpm i586/mga_rpms/nonfree/
+cp $bcdmedia/i586/media/nonfree/release/broadcom-wl-kernel-*-desktop586-*.rpm i586/mga_rpms/nonfree/
+cp $bcdmedia/i586/media/nonfree/release/broadcom-wl-kernel-desktop586-latest-*.rpm i586/mga_rpms/nonfree/
+
+cp $bcdmedia/x86_64/media/nonfree/release/broadcom-wl-common-*.rpm x86_64/mga_rpms/nonfree/
+cp $bcdmedia/x86_64/media/nonfree/release/broadcom-wl-kernel-*-desktop-*.rpm x86_64/mga_rpms/nonfree/
+cp $bcdmedia/x86_64/media/nonfree/release/broadcom-wl-kernel-desktop-latest-*.rpm x86_64/mga_rpms/nonfree/
+
+# add broadcom wireless configs
+cp $bcdmedia/i586/media/core/release/broadcom-*-config-*.rpm i586/mga_rpms/core/
+cp $bcdmedia/x86_64/media/core/release/broadcom-*-config-*.rpm x86_64/mga_rpms/core/
+
+# add grub2 stuff
+cp $bcdmedia/i586/media/core/release/grub2-2*.rpm i586/mga_rpms/core/
+cp $bcdmedia/i586/media/core/release/grub2-efi-2*.rpm i586/mga_rpms/core/
+cp $bcdmedia/i586/media/core/release/grub2-mageia-theme-*.rpm i586/mga_rpms/core/
+cp $bcdmedia/i586/media/core/release/os-prober-*.rpm i586/mga_rpms/core/
+
+cp $bcdmedia/x86_64/media/core/release/grub2-2*.rpm x86_64/mga_rpms/core/
+cp $bcdmedia/x86_64/media/core/release/grub2-efi-2*.rpm x86_64/mga_rpms/core/
+cp $bcdmedia/x86_64/media/core/release/grub2-mageia-theme-*.rpm x86_64/mga_rpms/core/
+cp $bcdmedia/x86_64/media/core/release/os-prober-*.rpm x86_64/mga_rpms/core/
+
+# add repo pubkeys
+cp $bcdmedia/i586/media/core/release/media_info/pubkey i586/mga_rpms/core/media_info/
+cp $bcdmedia/x86_64/media/core/release/media_info/pubkey x86_64/mga_rpms/core/media_info/
+
+cp $bcdmedia/i586/media/nonfree/release/media_info/pubkey i586/mga_rpms/nonfree/media_info/
+cp $bcdmedia/x86_64/media/nonfree/release/media_info/pubkey x86_64/mga_rpms/nonfree/media_info/
+
+# create hdlists
+genhdlist2 i586/mga_rpms/core
+genhdlist2 i586/mga_rpms/nonfree
+genhdlist2 x86_64/mga_rpms/core
+genhdlist2 x86_64/mga_rpms/nonfree
diff --git a/files/pkgs.pm b/files/pkgs.pm
new file mode 100644
index 0000000..5987da5
--- /dev/null
+++ b/files/pkgs.pm
@@ -0,0 +1,295 @@
+package pkgs; # $Id: pkgs.pm 269470 2010-05-26 09:23:39Z pterjan $
+
+
+
+use common;
+use run_program;
+use detect_devices;
+use log;
+
+sub rpmsrate_rate_max() {
+ 5; # also defined in perl-URPM
+}
+
+sub rpmsrate_rate_default() {
+ detect_devices::need_light_desktop() ? 5 : 4;
+}
+
+sub read_rpmsrate_raw {
+ my ($file) = @_;
+ my $line_nb = 0;
+ my $fatal_error;
+ my (%flags, %rates, @need_to_copy);
+ my (@l);
+ local $_;
+ foreach (cat_($file)) {
+ $line_nb++;
+ /\t/ and die "tabulations not allowed at line $line_nb\n";
+ s/#.*//; # comments
+
+ my ($indent, $data) = /(\s*)(.*)/;
+ next if !$data; # skip empty lines
+
+ @l = grep { $_->[0] < length $indent } @l;
+
+ my @m = @l ? @{$l[-1][1]} : ();
+ my ($t, $flag, @l2);
+ while ($data =~
+ /^((
+ [1-6]
+ |
+ (?: (?: !\s*)? [0-9A-Z_]+(?:".*?")?)
+ (?: \s*\|\|\s* (?: !\s*)? [0-9A-Z_]+(?:".*?")?)*
+ )
+ (?:\s+|$)
+ )(.*)/x) { #@")) {
+ ($t, $flag, $data) = ($1,$2,$3);
+ while ($flag =~ s,^\s*(("[^"]*"|[^"\s]*)*)\s+,$1,) {}
+ push @m, $flag;
+ push @l2, [ length $indent, [ @m ] ];
+ $indent .= $t;
+ }
+ if ($data) {
+ # has packages on same line
+ my ($rates, $flags) = partition { /^\d$/ } @m;
+ my ($rate) = @$rates or die sprintf qq(missing rate for "%s" at line %d (flags are %s)\n), $data, $line_nb, join('&&', @m);
+ foreach my $name (split ' ', $data) {
+ if (uc($name) eq $name) {
+ log::l("$line_nb: $name is parsed as a package name, not as a flag");
+ }
+ if (member('INSTALL', @$flags)) {
+ push @need_to_copy, $name if !member('NOCOPY', @$flags);
+ next; #- do not need to put INSTALL flag for a package.
+ }
+ if (member('PRINTER', @$flags)) {
+ push @need_to_copy, $name;
+ }
+ my @new_flags = @$flags;
+ if (my $previous = $flags{$name}) {
+ my @common = intersection($flags, $previous);
+ my @diff1 = difference2($flags, \@common);
+ my @diff2 = difference2($previous, \@common);
+ if (!@diff1 || !@diff2) {
+ @new_flags = @common;
+ } elsif (@diff1 == 1 && @diff2 == 1) {
+ @new_flags = (@common, join('||', $diff1[0], $diff2[0]));
+ } else {
+ log::l("$line_nb: cannot handle complicate flags for packages appearing twice ($name)");
+ $fatal_error++;
+ }
+ log::l("$line_nb: package $name appearing twice with different rates ($rate != " . $rates{$name} . ")") if $rate != $rates{$name};
+ }
+ $rates{$name} = $rate;
+ $flags{$name} = \@new_flags;
+ }
+ push @l, @l2;
+ } else {
+ push @l, [ $l2[0][0], $l2[-1][1] ];
+ }
+ }
+ $fatal_error and die "$fatal_error fatal errors in rpmsrate";
+ \%rates, \%flags, \@need_to_copy;
+}
+
+sub read_rpmsrate {
+ my ($packages, $rpmsrate_flags_chosen, $file, $match_all_hardware) = @_;
+
+ my ($rates, $flags, $need_to_copy) = read_rpmsrate_raw($file);
+
+ my ($TYPEs, @probeall);
+ if (!$match_all_hardware) {
+ $TYPEs = detect_devices::matching_types();
+ @probeall = detect_devices::probeall();
+ }
+
+ foreach (keys %$flags) {
+ my @flags = @{$flags->{$_}};
+ my $p;
+ if ($::isInstall) {
+ $p = install::pkgs::packageByName($packages, $_) or next;
+ if (my @l = map { /locales-(.*)/ ? qq(LOCALES"$1") : () } $p->requires_nosense) {
+ if (@l > 1) {
+ log::l("ERROR: package $_ is requiring many locales") if !member($_, qw(lsb libreoffice-langpack-br));
+ } else {
+ push @flags, @l;
+ }
+ }
+ }
+
+ @flags = map {
+ my ($user_flags, $known_flags) = partition { /^!?CAT_/ } split('\|\|', $_);
+ my $ok = find {
+ my $inv = s/^!//;
+ return 0 if $::isStandalone && $inv;
+ if (my ($p) = /^HW"(.*)"/) {
+ $match_all_hardware ? 1 : ($inv xor find { $_->{description} =~ /$p/i } @probeall);
+ } elsif (($p) = /^DRIVER"(.*)"/) {
+ $match_all_hardware ? 1 : ($inv xor find { $_->{driver} =~ /$p/i } @probeall);
+ } elsif (($p) = /^TYPE"(.*)"/) {
+ $match_all_hardware ? 1 : ($inv xor $TYPEs->{$p});
+ } elsif (($p) = /^HW_CAT"(.*)"/) {
+ $match_all_hardware ? 1 : ($inv xor detect_devices::probe_category($p));
+ } else { # LOCALES"", SOUND, ...
+ $inv xor $rpmsrate_flags_chosen->{$_};
+ }
+ } @$known_flags;
+ $ok ? 'TRUE' : @$user_flags ? join('||', @$user_flags) : 'FALSE';
+ } @flags;
+
+ @flags = member('FALSE', @flags) ? 'FALSE' : @flags;
+ if ($::isInstall) {
+ $p->set_rate($rates->{$_});
+ $p->set_rflags(@flags);
+ } else {
+ $flags->{$_} = \@flags;
+ }
+ }
+ push @{$packages->{needToCopy} ||= []}, @$need_to_copy if ref($packages);
+ return ($rates, $flags);
+}
+
+
+sub simple_read_rpmsrate {
+ my ($o_match_all_hardware, $o_ignore_flags) = @_;
+ my ($rates, $flags) = read_rpmsrate({}, {}, $::prefix . '/usr/share/meta-task/rpmsrate-raw', $o_match_all_hardware);
+
+ # FIXME: we do not handle !CAT_desktop but we do not care for now:
+ if (!$o_match_all_hardware && $o_ignore_flags) {
+ while (my ($pkg, $pkg_flags) = each %$flags) {
+ my $flags_str = "@$pkg_flags";
+ if ($flags_str =~ /TRUE/ && any { $flags_str =~ /[^!]$_/ } @$o_ignore_flags) {
+ delete $flags->{$pkg};
+ }
+ }
+ }
+
+ grep { member('TRUE', @{$flags->{$_}}) && $rates->{$_} >= 5 } keys %$flags;
+}
+
+sub detect_rpmsrate_hardware_packages {
+ my ($o_match_all_hardware, $ignore_flags) = @_;
+ grep { !/openoffice|java/ } simple_read_rpmsrate($o_match_all_hardware, $ignore_flags);
+}
+
+sub detect_graphical_drivers {
+ my ($do_pkgs, $o_match_all_hardware) = @_;
+ require Xconfig::card;
+ require Xconfig::proprietary;
+
+ my @cards;
+ if ($o_match_all_hardware) {
+ my $all_cards = Xconfig::card::readCardsDB("$ENV{SHARE_PATH}/ldetect-lst/Cards+");
+ @cards = values %$all_cards;
+ } else {
+ @cards = Xconfig::card::probe();
+ }
+
+ my @firmware_pkgs = grep { $_ } uniq(map { $_->{FIRMWARE} } @cards);
+ my @drivers = grep { $_ } uniq(map { $_->{Driver2} } @cards);
+ my @proprietary_pkgs = map { Xconfig::proprietary::pkgs_for_Driver2($_, $do_pkgs) } @drivers;
+ return @firmware_pkgs, @proprietary_pkgs;
+}
+
+sub detect_network_drivers {
+ my ($do_pkgs, $o_match_all_hardware) = @_;
+ require network::connection;
+ require network::thirdparty;
+
+ my @l;
+ foreach my $type (network::connection->get_types) {
+ $type->can('get_thirdparty_settings') or next;
+ my @network_settings;
+ my @all_settings = @{$type->get_thirdparty_settings || []};
+ if ($o_match_all_hardware) {
+ @network_settings = @all_settings;
+ } else {
+ my @connections = $type->get_connections(automatic_only => 1, fast_only => 1);
+ @network_settings = map { network::thirdparty::find_settings(\@all_settings, $_->get_driver) } @connections;
+ }
+ foreach my $settings (@network_settings) {
+ foreach (@network::thirdparty::thirdparty_types) {
+ my @packages = network::thirdparty::get_required_packages($_, $settings);
+ push @l, network::thirdparty::get_available_packages($_, $do_pkgs, @packages);
+ }
+ }
+ }
+ @l;
+}
+
+sub detect_hardware_packages {
+ my ($do_pkgs, $o_match_all_hardware) = @_;
+ my @ignore_flags = $::isInstall ? () : (
+ if_(!$do_pkgs->is_installed('task-kde4-minimal'), "CAT_KDE"),
+ if_(!$do_pkgs->is_installed('task-gnome-minimal'), "CAT_GNOME"),
+ );
+ (
+ ($::isInstall ? () : detect_rpmsrate_hardware_packages($o_match_all_hardware, \@ignore_flags)),
+ detect_graphical_drivers($do_pkgs, $o_match_all_hardware),
+ detect_network_drivers($do_pkgs, $o_match_all_hardware),
+ );
+}
+
+sub detect_unused_hardware_packages {
+ my ($do_pkgs) = @_;
+ my @all_hardware_packages = detect_hardware_packages($do_pkgs, 'match_all_hardware');
+ my @used_hardware_packages = detect_hardware_packages($do_pkgs);
+ my @unneeded_hardware_packages = difference2(\@all_hardware_packages, \@used_hardware_packages);
+ $do_pkgs->are_installed(@unneeded_hardware_packages);
+}
+
+sub detect_unselected_locale_packages {
+ my ($do_pkgs) = @_;
+ require lang;
+ my $locales_prefix = 'locales-';
+ my $locale = lang::read();
+ my $selected_locale = $locales_prefix . lang::locale_to_main_locale($locale->{lang});
+ my @available_locales = $do_pkgs->are_installed($locales_prefix . '*');
+ member($selected_locale, @available_locales) ? difference2(\@available_locales, [ $selected_locale ]) : ();
+}
+
+sub remove_unused_packages {
+ my ($in, $do_pkgs, $o_prefix) = @_;
+
+ my $wait;
+ $wait = $in->wait_message(N("Unused packages removal"), N("Finding unused hardware packages..."));
+ my @unused_hardware_packages = detect_unused_hardware_packages($do_pkgs);
+ undef $wait;
+ $wait = $in->wait_message(N("Unused packages removal"), N("Finding unused localization packages..."));
+ my @unselected_locales = detect_unselected_locale_packages($do_pkgs);
+ undef $wait;
+
+ # Packages to not remove even if they seem unused
+ my @wanted_hardware_packages = qw(gnome-bluetooth gnome-phone-manager kbluetooth bluedevil kppp ppp wireless-tools wpa_supplicant radeon-firmware kernel-firmware-nonfree);
+ @unused_hardware_packages = difference2(\@unused_hardware_packages, \@wanted_hardware_packages);
+
+ @unused_hardware_packages || @unselected_locales or return;
+
+ my $hardware = @unused_hardware_packages;
+ my $locales = @unselected_locales;
+ $in->ask_from(
+ N("Unused packages removal"),
+ N("We have detected that some packages are not needed for your system configuration.") . "\n" .
+ N("We will remove the following packages, unless you choose otherwise:"),
+ [
+ if_(@unused_hardware_packages,
+ { text => N("Unused hardware support"), val => \$hardware, type => "bool" },
+ { label => N("Unused hardware support") . "\n" . join("\n", map { " " . $_ } sort(@unused_hardware_packages)), advanced => 1 },
+ ),
+ if_(@unselected_locales,
+ { text => N("Unused localization"), val => \$locales, type => "bool" },
+ { label => N("Unused localization") . "\n" . join("\n", map { " " . $_ } sort(@unselected_locales)), advanced => 1 },
+ ),
+ ],
+ if_($::isWizard, cancel => N("Skip")),
+ ) && ($hardware || $locales) or return;
+
+ #- we should have some gurpme
+ $wait = $in->wait_message(N("Please wait"), N("Removing packages..."));
+ run_program::rooted($o_prefix, 'urpme', '--auto',
+ if_($hardware, @unused_hardware_packages),
+ if_($locales, @unselected_locales),
+ );
+ #- use script from One to list language files (/usr/share/locale mainly) and remove them?
+}
+
+1;