package lilo; use common qw(:common :file); use partition_table qw(:types); use log; use fsedit; use detect_devices; use partition_table_raw; use run_program; use modules; %vga_modes = ( "Ask at boot" => 'ask', "Normal" => 'normal', "80x50" => '0x0f01', "80x43" => '0x0f02', "80x28" => '0x0f03', "80x30" => '0x0f04', "80x34" => '0x0f05', "80x60" => '0x0f06', ); sub mkinitrd($$$) { my ($prefix, $kernelVersion, $initrdImage) = @_; $::testing and return; modules::load('loop'); run_program::rooted($prefix, "mkinitrd", "-f", $initrdImage, "--ifneeded", $kernelVersion) or unlink("$prefix/$initrdImage"); -e "$prefix/$initrdImage" or die "mkinitrd failed"; } sub mkbootdisk($$$;$) { my ($prefix, $kernelVersion, $dev, $append) = @_; modules::load('loop'); my @l = qw(mkbootdisk --noprompt); push @l, "--appendargs", $append if $append; run_program::rooted($prefix, @l, "--device", "/dev/$dev", $kernelVersion) or die "mkbootdisk failed"; } sub read($$) { my ($prefix, $file) = @_; my $global = 1; my ($e, $v, $f); my %b; foreach (cat_("$prefix$file")) { ($_, $v) = /^\s*(.*?)\s*(?:=\s*(.*?))?\s*$/; if (/^(image|other)$/) { $b{entries}{$v} = $e = { type => $_ }; $global = 0; } elsif ($global) { $b{$_} = $v || 1; } else { if ((/map-drive/ .. /to/) && /to/) { $e->{mapdrive}{$e->{'map-drive'}} = $v; } else { $e->{$_} = $v || 1; } } } delete $b{timeout} unless $b{prompt}; $b{timeout} = $b{timeout} / 10 if $b{timeout}; $b{message} = cat_("$prefix$b{message}") if $b{message}; \%b; } sub suggest_onmbr($) { my ($hds) = @_; my $type = partition_table_raw::typeOfMBR($hds->[0]{device}); !$type || member($type, qw(dos dummy lilo empty)), !$type; } sub add_entry($$$) { my ($entries, $image, $v) = @_; my (%usedold, $freeold); do { $usedold{$1 || 0} = 1 if $_->{label} =~ /^old ([^_]*)_/x } foreach (values %$entries); foreach (0..scalar keys %usedold) { exists $usedold{$_} or $freeold = $_ || '', last } do { $_->{label} = "old${freeold}_$_->{label}" if $_->{label} eq $v->{label} } foreach (values %$entries); $entries->{$image} = $v; } sub add_kernel($$$$$) { my ($prefix, $lilo, $kernelVersion, $specific, $v) = @_; my $ext = $specific && "-$specific"; my ($vmlinuz, $image, $initrdImage) = ("vmlinuz-$kernelVersion$specific", "/boot/vmlinuz$ext", "/boot/initrd$ext.img"); if (-e "$prefix/boot/$vmlinuz") { { my $f = "initrd-$kernelVersion$specific.img"; eval { mkinitrd($prefix, "$kernelVersion$specific", "/boot/$f") }; undef $initrdImage if $@; symlinkf $f, "$prefix$initrdImage" if $initrdImage; } add2hash($v, { type => 'image', label => 'linux', initrd => $initrdImage, append => $lilo->{perImageAppend}, }); symlinkf "$vmlinuz", "$prefix/$image" if $specific; add_entry($lilo->{entries}, $image, $v); 1; } else { log::l("unable to find kernel image $prefix/boot/$vmlinuz"); 0; } } sub suggest($$$$$) { my ($prefix, $lilo, $hds, $fstab, $kernelVersion) = @_; my $root = fsedit::get_root($fstab)->{device}; my ($onmbr, $unsafe) = $lilo->{crushMbr} ? (1, 0) : suggest_onmbr($hds); add2hash_($lilo, { boot => "/dev/" . ($onmbr ? $hds->[0]{device} : fsedit::get_root($fstab, 'boot')->{device}), bootUnsafe => $unsafe, map => "/boot/map", default => "linux", timeout => $onmbr && 5, install => "/boot/boot.b", }); $lilo->{disk} ||= "/dev/$hds->[0]{device} bios=0x80" if $hds->[0]{device} =~ /^hd[be]$/; if (!$lilo->{message} || $lilo->{message} eq "1") { $lilo->{message} = join('', cat_("$prefix/boot/message")); if (!$lilo->{message}) { my $msg_en = __("Welcome to LILO the operating system chooser! To list the possible choices, press . To load one of them, write its name and press or wait %d seconds for default boot. "); my $msg = translate($msg_en); $msg = $msg_en if int(grep { $_ & 0x80 } unpack "c*", $msg) / length($msg) > 0.2; $lilo->{message} = sprintf $msg, $lilo->{timeout}; } } my $isSecure = -e "$prefix/boot/vmlinuz-${kernelVersion}secure"; my $isSMP = detect_devices::hasSMP(); if ($isSMP && !-e "$prefix/boot/vmlinuz-${kernelVersion}smp") { log::l("SMP machine, but no SMP kernel found") unless $isSecure; $isSMP = 0; } add_kernel($prefix, $lilo, $kernelVersion, $isSecure ? 'secure' : 'smp', { label => 'linux', root => "/dev/$root", }) if $isSecure || $isSMP; add_kernel($prefix, $lilo, $kernelVersion, '', { label => $isSecure || $isSMP ? 'linux-up' : 'linux', root => "/dev/$root", }); my ($dos, $win) = 0, 0; foreach (@$hds) { foreach (@{$_->{primary}{normal}}) { add_entry($lilo->{entries}, "/dev/$_->{device}", { type => 'other', label => isDos($_) ? "dos" . ($dos++ ? $dos : '') : "windows" . ($win++ ? $win : '') , table => "/dev/$_->{rootDevice}", }) if isFat($_) && isFat({ type => fsedit::typeOfPart($_->{device}) }); } } add_entry($lilo->{entries}, '/dev/fd0', { type => 'other', label => 'floppy', unsafe => 1 }); } sub keytable($$) { my ($prefix, $f) = @_; local $_ = $f; if ($_ && !/\.klt$/) { $f = "/boot/$_.klt"; run_program::rooted($prefix, "keytab-lilo.pl", ">", $f, $_) or undef $f; } $f && -r "$prefix/$f" && $f; } sub install($$) { my ($prefix, $lilo) = @_; $lilo->{prompt} = $lilo->{timeout}; $lilo->{keytable} = keytable($prefix, $lilo->{keytable}); if ($lilo->{message}) { local *F; open F, ">$prefix/boot/message" and print F $lilo->{message} or $lilo->{message} = 0; } { local *F; local $\ = "\n"; my $f = "$prefix/etc/lilo.conf"; open F, ">$f" or die "cannot create lilo config file: $f"; log::l("writing lilo config to $f"); $lilo->{$_} and print F "$_=$lilo->{$_}" foreach qw(boot map install vga default append keytable disk); $lilo->{$_} and print F $_ foreach qw(linear compact prompt restricted); print F "timeout=", round(10 * $lilo->{timeout}) if $lilo->{timeout}; print F "message=/boot/message" if $lilo->{message}; while (my ($v, $e) = each %{$lilo->{entries}}) { print F "$e->{type}=$v"; print F "\tlabel=$e->{label}"; if ($e->{type} eq "image") { print F "\troot=$e->{root}"; print F "\tinitrd=$e->{initrd}" if $e->{initrd}; print F "\tappend=\"$1\"" if $e->{append} =~ /^\s*"?(.*?)"?\s*$/; print F "\tvga=$e->{vga}" if $e->{vga}; print F "\tread-write" if $e->{'read-write'}; print F "\tread-only" if !$e->{'read-write'}; } else { print F "\ttable=$e->{table}" if $e->{table}; print F "\tunsafe" if $e->{unsafe} && !$e->{table}; $e->{mapdrive} ||= { '0x80' => '0x81', '0x81' => '0x80' } if $e->{table} && $lilo->{boot} !~ /$e->{table}/; while (my ($from, $to) = each %{$e->{mapdrive} || {}}) { print F "\tmap-drive=$from"; print F "\t to=$to"; } } } } log::l("Installing boot loader..."); $::testing and return; run_program::rooted($prefix, "lilo", "2>", "/tmp/.error") or die "lilo failed"; unlink "$prefix/tmp/.error"; } 1; #