summaryrefslogtreecommitdiffstats
path: root/perl-install/share/po/Makefile
Commit message (Expand)AuthorAgeFilesLines
* adjust Makefile to fit doc module zh_cnFunda Wang2004-08-221-0/+1
* fix drakxtools buildThierry Vignaud2004-08-201-1/+0
* - don't use compssUsers anymore, use compssUsers.plPascal Rigaux2004-08-131-1/+0
* adapt to new directories layout:Pascal Rigaux2004-07-261-0/+1
* remove checking "$" in po strings, perl_checker takes care of this correctlyPascal Rigaux2004-01-211-3/+0
* get translated strings in directory gi/perl-install to have xxx.pm instead of...Pascal Rigaux2004-01-091-4/+5
* add mdk_totem in poPascal Rigaux2003-12-011-1/+1
* add move.pmGuillaume Cottenceau2003-11-201-1/+1
* allow move to build & install drakx mo files (using sudo)Pascal Rigaux2003-11-181-3/+5
* don't remove some po's from drakxtools, only from installPascal Rigaux2003-09-181-5/+1
* Arabic and Farsi po files not used at install, as therePablo Saratxaga2003-09-181-1/+2
* do not translate in arabic during install since there's no font availablePascal Rigaux2003-09-021-1/+1
* updated Welsh, Icelandic, Italian, NorwegianPablo Saratxaga2003-03-101-1/+1
* revert Pablo's breaking po's installation :)Guillaume Cottenceau2003-02-191-1/+1
* updated pot filePablo Saratxaga2003-02-181-1/+1
* remove drakpxe exception since fpons has at lease fixed "fpons sucks"Thierry Vignaud2003-02-031-1/+1
* since fpons don't care about fixing drakxtools build broken byThierry Vignaud2003-01-271-1/+1
* don't yell when checking for "$" in DrakX.pot and only finding "\$"Pascal Rigaux2003-01-161-1/+1
* use "perl_checker --generate-pot" instead of fake_c + xgettextPascal Rigaux2002-12-101-8/+2
* updated po filesPablo Saratxaga2002-12-051-2/+2
* replace "_" with "N" and "__" with "N_"Pascal Rigaux2002-11-061-1/+1
* enabled ro.poPablo Saratxaga2002-09-031-2/+2
* workaround missing entities in spanishPascal Rigaux2002-08-291-0/+1
* adapt to new manual cvs dirsPascal Rigaux2002-08-291-2/+2
* - update help.pm based on the xml manualPascal Rigaux2002-07-221-1/+1
* fake make so that its builtin rule to create file from file.sh doesn'tThierry Vignaud2002-07-091-0/+4
* make the "clean" rule less verbosePascal Rigaux2002-07-041-1/+1
* updated Welsh filePablo Saratxaga2002-02-231-1/+1
* updated pot filePablo Saratxaga2002-02-211-1/+1
* make a difference between PMS and ALLPMS. For install, only use PMSPascal Rigaux2002-02-211-1/+1
* allow me to work with a symlink to doc in this directoryStefan Siegel2002-02-171-2/+8
* (clean): remove .memdumpPascal Rigaux2002-02-171-1/+1
* Instead of temporary removingfiles from CVS put a rule in Makefile toPablo Saratxaga2002-02-141-1/+4
* updated Spanish file; merged help-* filesPablo Saratxaga2002-01-111-1/+1
* - rename help-*.po by help-*.potPascal Rigaux2001-09-101-3/+3
* xml help handling/enhancing for multi-langsPascal Rigaux2001-09-091-1/+1
* xml help handling/enhancing for multi-langsPascal Rigaux2001-09-091-5/+6
* new helpPascal Rigaux2001-09-071-1/+1
* fix utf8 translation of xml filePascal Rigaux2001-08-301-1/+1
* fetch directly the latest drakx-help.xmlPascal Rigaux2001-08-261-3/+4
* auto-generates help.pm from xml doc done by doc teamPascal Rigaux2001-08-241-0/+3
* check presence of '$' in DrakX.potPascal Rigaux2001-08-211-0/+3
* po->mo is no longer gonna be nasty with usPascal Rigaux2001-08-121-1/+1
* (install): build mo'sPascal Rigaux2001-07-251-1/+1
* do not use the po's directly. Use mo's through gettextPascal Rigaux2001-07-231-9/+24
* externalize the pm 2 pm_.c in fake_c.plPascal Rigaux2001-07-201-1/+1
* yet even better i18n strings extractionPascal Rigaux2001-07-021-3/+3
* - fix to add some missing messagesPascal Rigaux2001-07-021-2/+11
* fix yet again DrakX.pot makingPascal Rigaux2001-05-161-1/+1
* fix messages to i18n extractingPascal Rigaux2001-05-151-1/+1
'n608' href='#n608'>608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971
package bootloader; # $Id$

use diagnostics;
use strict;
use vars qw(%vga_modes);

#-######################################################################################
#- misc imports
#-######################################################################################
use common qw(:common :file :functional :system);
use partition_table qw(:types);
use log;
use any;
use fsedit;
use devices;
use loopback;
use commands;
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',
 "100x30" => '0x0122',
 "640x480 in 16 bits (FrameBuffer only)" => 785,
 "800x600 in 16 bits (FrameBuffer only)" => 788,
 "1024x768 in 16 bits (FrameBuffer only)" => 791,
 "1280x1024 in 16 bits (FrameBuffer only)" => 794,
);

my %vga_modes2nb = (
 'ask'    => -3,
 'normal' => -1,
#- other entries are identity
);


#-#####################################################################################
#- Functions
#-#####################################################################################

sub get {
    my ($kernel, $bootloader) = @_;
    $_->{kernel_or_dev} && $_->{kernel_or_dev} eq $kernel and return $_ foreach @{$bootloader->{entries}};
    undef;
}
sub get_label {
    my ($label, $bootloader) = @_;
    $_->{label} && $_->{label} eq $label and return $_ foreach @{$bootloader->{entries}};
    undef;
}

sub mkinitrd($$$) {
    my ($prefix, $kernelVersion, $initrdImage) = @_;

    $::testing || -e "$prefix/$initrdImage" and return;

    my $loop_boot = loopback::prepare_boot($prefix);

    modules::load('loop');
    run_program::rooted($prefix, "mkinitrd", "-f", $initrdImage, "--ifneeded", $kernelVersion) or unlink("$prefix/$initrdImage");

    loopback::save_boot($loop_boot);

    -e "$prefix/$initrdImage" or die "mkinitrd failed";
}

sub mkbootdisk($$$;$) {
    my ($prefix, $kernelVersion, $dev, $append) = @_;

    modules::load_multi(arch() =~ /sparc/ ? 'romfs' : (), 'loop');
    my @l = qw(mkbootdisk --noprompt); 
    push @l, "--appendargs", $append if $append;
    if ($dev =~ /fd/) {
	devices::make($dev . 'H1440');
    } else {
	push @l, "--bios", 0, if $dev !~ /fd/;
    }
    run_program::rooted_or_die($prefix, @l, "--device", "/dev/$dev", $kernelVersion);
}

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)$/) {
	    push @{$b{entries}}, $e = { type => $_, kernel_or_dev => $v };
	    $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};
    $_->{append} =~ s/^\s*"?(.*?)"?\s*$/$1/ foreach \%b, @{$b{entries}};
    $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 grub empty)), !$type;
}

sub compare_entries ($$) {
    my ($a, $b) = @_;
    my %entries;

    @entries{keys %$a, keys %$b} = ();
    $a->{$_} eq $b->{$_} and delete $entries{$_} foreach keys %entries;
    scalar keys %entries;
}

sub add_entry($$) {
    my ($entries, $v) = @_;
    my (%usedold, $freeold);

    do { $usedold{$1 || 0} = 1 if $_->{label} =~ /^old([^_]*)_/ } foreach @$entries;
    foreach (0..scalar keys %usedold) { exists $usedold{$_} or $freeold = $_ || '', last }

    foreach (@$entries) {
	if ($_->{label} eq $v->{label}) {
	    compare_entries($_, $v) or return; #- avoid inserting it twice as another entry already exists !
	    $_->{label} = "old${freeold}_$_->{label}";
	}
    }
    push @$entries, $v;
}

sub add_kernel($$$$$) {
    my ($prefix, $lilo, $kernelVersion, $specific, $v) = @_;
    my $ext = $specific && "-$specific"; $specific =~ s/\d+\.\d+|hack//;
    my ($vmlinuz, $image, $initrdImage) = ("vmlinuz-$kernelVersion$specific", "/boot/vmlinuz$ext", "/boot/initrd$ext.img");    
    -e "$prefix/boot/$vmlinuz" or log::l("unable to find kernel image $prefix/boot/$vmlinuz"), return;
    {
	my $f = "initrd-$kernelVersion$specific.img";
	eval { mkinitrd($prefix, "$kernelVersion$specific", "/boot/$f") };
	undef $initrdImage if $@;
	symlinkf $f, "$prefix$initrdImage" or $initrdImage = "/boot/$f"
	  if $initrdImage;
    }
    symlinkf "$vmlinuz", "$prefix/$image" or $image = "/boot/$vmlinuz";
    add2hash($v,
	     {
	      type => 'image',
	      label => 'linux',
	      kernel_or_dev => $image,
	      initrd => $initrdImage,
	      append => $lilo->{perImageAppend},
	     });
    add_entry($lilo->{entries}, $v);
    $v;
}

sub get_append {
    my ($b, $key) = @_;
    ($b->{perImageAppend} =~ /\b$key=(\S*)/)[0];
}
sub add_append {
    my ($b, $key, $val) = @_;

    foreach ({ append => $b->{perImageAppend} }, @{$b->{entries}}) {
	$_->{append} =~ s/\b$key=\S*\s*//;
	$_->{append} =~ s/\s*$/ $key=$val)/ if $val;
    }
}

sub configure_entry($$) {
    my ($prefix, $entry) = @_;
    if ($entry->{type} eq 'image') {
	my $specific_version;
	$entry->{kernel_or_dev} =~ /vmlinu.-(.*)/ and $specific_version = $1;
	readlink("$prefix/$entry->{kernel_or_dev}") =~ /vmlinu.-(.*)/ and $specific_version = $1;

	if ($specific_version) {
	    $entry->{initrd} or $entry->{initrd} = "/boot/initrd-$specific_version.img";
	    unless (-e "$prefix/$entry->{initrd}") {
		eval { mkinitrd($prefix, $specific_version, "$entry->{initrd}") };
		undef $entry->{initrd} if $@;
	    }
	}
    }
    $entry;
}

sub dev2prompath { #- SPARC only
    my ($dev) = @_;
    my ($wd, $num) = $dev =~ /^(.*\D)(\d*)$/;
    require c;
    $dev = c::disk2PromPath($wd) and $dev = $dev =~ /^sd\(/ ? "$dev$num" : "$dev;$num";
    $dev;
}

sub suggest {
    my ($prefix, $lilo, $hds, $fstab, $kernelVersion, $vga_fb) = @_;
    my $root_part = fsedit::get_root($fstab);
    my $root = isLoopback($root_part) ? "loop7" : $root_part->{device};
    my $boot = fsedit::get_root($fstab, 'boot')->{device};
    my $partition = first($boot =~ /\D*(\d*)/);

    require c; c::initSilo() if arch() =~ /sparc/;

    my ($onmbr, $unsafe) = $lilo->{crushMbr} ? (1, 0) : suggest_onmbr($hds);
    add2hash_($lilo, arch() =~ /sparc/ ?
	{
	 default => "linux",
	 entries => [],
	 timeout => 5,
	 use_partition => 0, #- we should almost always have a whole disk partition.
	 root          => "/dev/$root",
	 partition     => $partition || 1,
	 boot          => $root eq $boot && "/boot", #- this helps for getting default partition for silo.
	} : arch =~ /ppc/ ?
	{
	 defaultos => "linux",
	 default => "linux",
	 entries => [],
	 initmsg => "Welcome to Mandrake Linux!",
	 delay => 30,	#- OpenFirmware delay
	 timeout => 50,
	 enableofboot => 1,
	 enablecdboot => 1,
	 useboot => $boot,
	} :
	{
	 bootUnsafe => $unsafe,
	 default => "linux",
	 lba32 => 1,
	 entries => [],
	 timeout => $onmbr && 5,
	   if_(arch() !~ /ia64/,
	 boot => "/dev/" . ($onmbr ? $hds->[0]{device} : fsedit::get_root($fstab, 'boot')->{device}),
	 map => "/boot/map",
	 install => "/boot/boot.b",
         ),
	});

    if (!$lilo->{message} || $lilo->{message} eq "1") {
	$lilo->{message} = join('', cat_("$prefix/boot/message"));
	if (!$lilo->{message}) {
	    my $msg_en =
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
__("Welcome to %s the operating system chooser!

Choose an operating system in the list above or
wait %d seconds for default boot.

");
	    my $msg = translate($msg_en);
	    #- use the english version if more than 20% of 8bits chars
	    $msg = $msg_en if int(grep { $_ & 0x80 } unpack "c*", $msg) / length($msg) > 0.2;
	    $lilo->{message} = sprintf $msg, arch() =~ /sparc/ ? "SILO" : "LILO", $lilo->{timeout};
	}
    }


    add2hash_($lilo, { getVarsFromSh("$prefix/etc/sysconfig/system") }); #- for CLEAN_TMP
    add2hash_($lilo, { memsize => $1 }) if cat_("/proc/cmdline") =~ /mem=(\S+)/;

    #- give more priority to secure kernel because if the user want security, he will got it...
    my $isSecure = -e "$prefix/boot/vmlinuz-${kernelVersion}secure";
    my $isEnterprise = -e "$prefix/boot/vmlinuz-${kernelVersion}enterprise";

    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;
    }
    my $entry = add_kernel($prefix, $lilo, $kernelVersion,
			   $isSecure ? 'secure' : $isEnterprise ? 'enterprise' : $isSMP ? 'smp' : '',
	       {
		label => 'linux',
		root  => "/dev/$root",
		if_($vga_fb, vga => $vga_fb), #- using framebuffer
	       });
    add_kernel($prefix, $lilo, $kernelVersion, '',
	       {
		label => $isSecure || $isEnterprise || $isSMP ? 'linux-up' : 'linux-nonfb',
		root  => "/dev/$root",
	       }) if $isSecure || $isEnterprise || $isSMP || $vga_fb;
    my $failsafe = add_kernel($prefix, $lilo, $kernelVersion, '',
	       {
		label => 'failsafe',
		root  => "/dev/$root",
	       });
    $entry->{append} .= " quiet" if $vga_fb;
    $failsafe->{append} .= " failsafe" if $failsafe && !$lilo->{password};

    #- manage older kernel if installed.
    foreach (qw(2.2 hack)) {
	my $hasOld = -e "$prefix/boot/vmlinuz-$_";
	if ($hasOld) {
	    my $oldVersion = first(readlink("$prefix/boot/vmlinuz-$_") =~ /vmlinuz-(.*mdk)/);
	    my $oldSecure = -e "$prefix/boot/vmlinuz-${_}secure";
	    my $oldSMP = $isSMP && -e "$prefix/boot/vmlinuz-${_}smp";

	    add_kernel($prefix, $lilo, $oldVersion, $oldSecure ? "${_}secure" : $oldSMP ? "${_}smp" : $_,
		       {
			label => "linux-$_",
			root  => "/dev/$root",
			$vga_fb ? ( vga => $vga_fb) : (), #- using framebuffer
		       });
	    add_kernel($prefix, $lilo, $oldVersion, $_,
		       {
			label => $oldSecure || $oldSMP ? "linux-${_}up" : "linux-${_}nonfb",
			root  => "/dev/$root",
		       }) if $oldSecure || $oldSMP || $vga_fb;
	    my $entry = add_kernel($prefix, $lilo, $oldVersion, $_,
		       {
			label => "failsafe-$_",
			root  => "/dev/$root",
		       });
	    $entry->{append} .= " failsafe" if $entry && !$lilo->{password};
	}
    }

    if (arch() =~ /sparc/) {
	#- search for SunOS, it could be a really better approach to take into account
	#- partition type for mounting point.
	my $sunos = 0;
	foreach (@$hds) {
	    foreach (@{$_->{primary}{normal}}) {
		my $path = $_->{device} =~ m|^/| && $_->{device} !~ m|^/dev/| ? $_->{device} : dev2prompath($_->{device});
		add_entry($lilo->{entries},
			  {
			   type => 'other',
			   kernel_or_dev => $path,
			   label => "sunos"   . ($sunos++ ? $sunos : ''),
			  }) if $path && isSunOS($_) && type2name($_->{type}) =~ /root/i;
	    }
	}
    } elsif (arch() =~ /ppc/) {
	#- if we identified a MacOS partition earlier - add it
	if (defined $partition_table_mac'macos_part) {
	    add_entry($lilo->{entries},
		      {
		       label => "macos",
		       kernel_or_dev => $partition_table_mac'macos_part
		      });
	}
    } else {
	#- search for dos (or windows) boot partition. Don't look in extended partitions!
	my %nbs;
	foreach (@$hds) {
	    foreach (@{$_->{primary}{normal}}) {
		my $label = isNT($_) ? 'NT' : isDos($_) ? 'dos' : 'windows';
		add_entry($lilo->{entries},
			  {
			   type => 'other',
			   kernel_or_dev => "/dev/$_->{device}",
			   label => $label . ($nbs{$label}++ ? $nbs{$label} : ''),
			   table => "/dev/$_->{rootDevice}",
			   unsafe => 1
			  }) if isNT($_) || isFat($_) && isFat({ type => fsedit::typeOfPart($_->{device}) });
	    }
	}
    }
    my %l = (
	     yaboot => bool(arch() =~ /ppc/),
	     silo => bool(arch() =~ /sparc/),
	     lilo => bool(arch() !~ /sparc|ppc/) && !isLoopback(fsedit::get_root($fstab)),
	     grub => bool(arch() !~ /sparc|ppc/ && availableRamMB() < 800), #- don't use grub if more than 800MB
	     loadlin => bool(arch() !~ /sparc|ppc/) && -e "/initrd/loopfs/lnx4win",
	    );
    unless ($lilo->{methods}) {
	$lilo->{methods} ||= { map { $_ => 1 } grep { $l{$_} } keys %l };
	if ($lilo->{methods}{lilo} && -e "$prefix/boot/lilo-graphic") {
	    $lilo->{methods}{lilo} = "lilo-graphic";
	    exists $lilo->{methods}{grub} and $lilo->{methods}{grub} = undef;
	}
    }
}

sub suggest_floppy {
    my ($bootloader) = @_;

    my $floppy = detect_devices::floppy() or return;
    $floppy eq 'fd0' or log::l("suggest_floppy: not adding $floppy"), return;

    add_entry($bootloader->{entries},
      {
       type => 'other',
       kernel_or_dev => '/dev/fd0',
       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 has_profiles { bool(get_label("office", $b)) }
sub set_profiles {
    my ($b, $want_profiles) = @_;

    my $office = get_label("office", $b);
    if ($want_profiles xor $office) {
	my $e = get_label("linux", $b);
	if ($want_profiles) {
	    push @{$b->{entries}}, { %$e, label => "office", append => "$e->{append} prof=Office" };
	    $e->{append} .= " prof=Home";
	} else {
	    # remove profiles
	    $e->{append} =~ s/\s*prof=\w+//;
	    @{$b->{entries}} = grep { $_ != $office } @{$b->{entries}};
	}
    }

}

sub get_of_dev($$) {
	my ($prefix, $unix_dev) = @_;
	#- don't care much for this - need to run ofpath rooted, and I need the result
	#- In test mode, just run on "/", otherwise you can't get to the /proc files		
	if ($::testing) {
		$prefix = "";
	}
	run_program::rooted_or_die($prefix, "/usr/local/sbin/ofpath $unix_dev", ">", "/tmp/ofpath");
	open(FILE, "$prefix/tmp/ofpath") || die "Can't open $prefix/tmp/ofpath";
	my $of_dev = "";
	local $_ = "";
	while (<FILE>){
		$of_dev = $_;
	}
	chop($of_dev);
	my @del_file = ($prefix . "/tmp/ofpath");
	unlink (@del_file);
	log::l("OF Device: $of_dev");
	$of_dev;
}

sub install_yaboot($$$) {
    my ($prefix, $lilo, $fstab, $hds) = @_;
    $lilo->{prompt} = $lilo->{timeout};

    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/yaboot.conf";
	open F, ">$f" or die "cannot create yaboot config file: $f";
	log::l("writing yaboot config to $f");

	print F "#yaboot.conf - generated by DrakX";
	print F "init-message=\"\\n$lilo->{initmsg}\\n\"" if $lilo->{initmsg};

	if ($lilo->{boot}) {
	    print F "boot=$lilo->{boot}";
	    my $of_dev = get_of_dev($prefix, $lilo->{boot});
	    print F "ofboot=$of_dev";
	} else {
	    die "no bootstrap partition defined."
	}
	
	$lilo->{$_} and print F "$_=$lilo->{$_}" foreach qw(delay timeout);
	print F "install=/usr/local/lib/yaboot/yaboot";
	print F "magicboot=/usr/local/lib/yaboot/ofboot";
	$lilo->{$_} and print F $_ foreach qw(enablecdboot enableofboot);
	$lilo->{$_} and print F "$_=$lilo->{$_}" foreach qw(defaultos default);
	print F "nonvram";
	my $boot = "/dev/" . $lilo->{useboot} if $lilo->{useboot};
		
	foreach (@{$lilo->{entries}}) {

	    if ($_->{type} eq "image") {
		my $of_dev = '';
		if ($boot !~ /$_->{root}/) {
		    $of_dev = get_of_dev($prefix, $boot);
		    print F "$_->{type}=$of_dev," . substr($_->{kernel_or_dev}, 5);
		} else {
		    $of_dev = get_of_dev($prefix, $_->{root});    			
		    print F "$_->{type}=$of_dev,$_->{kernel_or_dev}";
		}
		print F "\tlabel=", substr($_->{label}, 0, 15); #- lilo doesn't handle more than 15 char long labels
		print F "\troot=$_->{root}";
		if ($boot !~ /$_->{root}/) {
		    print F "\tinitrd=$of_dev," . substr($_->{initrd}, 5) if $_->{initrd};
		} else {
		    print F "\tinitrd=$of_dev,$_->{initrd}" if $_->{initrd};
		}
		print F "\tappend=\"$_->{append}\"" if $_->{append};
		print F "\tread-write" if $_->{'read-write'};
		print F "\tread-only" if !$_->{'read-write'};
	    } else {
		my $of_dev = get_of_dev($prefix, $_->{kernel_or_dev});
		print F "$_->{label}=$of_dev";		
	    }
	}
    }
    log::l("Installing boot loader...");
    my $f = "$prefix/tmp/of_boot_dev";
    my $of_dev = get_of_dev($prefix, $lilo->{boot});
    output($f, "$of_dev\n");  
    $::testing and return;
    if (defined $install_steps_interactive::new_bootstrap) {
	run_program::run("hformat", "$lilo->{boot}") or die "hformat failed";
    }	
    run_program::rooted($prefix, "/sbin/ybin", "2>", "/tmp/.error") or die "ybin failed";
    unlink "$prefix/tmp/.error";	
}

sub install_silo($$$) {
    my ($prefix, $silo, $fstab) = @_;
    my $boot = fsedit::get_root($fstab, 'boot')->{device};
    my ($wd, $num) = $boot =~ /^(.*\D)(\d*)$/;

    #- setup boot promvars for.
    require c;
    if ($boot =~ /^md/) {
	#- get all mbr devices according to /boot are listed,
	#- then join all zero based partition translated to prom with ';'.
	#- keep bootdev with the first of above.
	log::l("/boot is present on raid partition which is not currently supported for promvars");
    } else {
	if (!$silo->{use_partition}) {
	    foreach (@$fstab) {
		if (!$_->{start} && $_->{device} =~ /$wd/) {
		    $boot = $_->{device};
		    log::l("found a zero based partition in $wd as $boot");
		    last;
		}
	    }
	}
	$silo->{bootalias} = c::disk2PromPath($boot);
	$silo->{bootdev} = $silo->{bootalias};
        log::l("preparing promvars for device=$boot");
    }
    c::hasAliases() or log::l("clearing promvars alias as non supported"), $silo->{bootalias} = '';

    if ($silo->{message}) {
	local *F;
	open F, ">$prefix/boot/message" and print F $silo->{message} or $silo->{message} = 0;
    }
    {
	local *F;
        local $\ = "\n";
	my $f = "$prefix/boot/silo.conf"; #- always write the silo.conf file in /boot ...
	symlinkf "../boot/silo.conf", "$prefix/etc/silo.conf"; #- ... and make a symlink from /etc.
	open F, ">$f" or die "cannot create silo config file: $f";
	log::l("writing silo config to $f");

	$silo->{$_} and print F "$_=$silo->{$_}" foreach qw(partition root default append);
	$silo->{$_} and print F $_ foreach qw(restricted);
	#- print F "password=", $silo->{password} if $silo->{restricted} && $silo->{password}; #- done by msec
	print F "timeout=", round(10 * $silo->{timeout}) if $silo->{timeout};
	print F "message=$silo->{boot}/message" if $silo->{message};

	foreach (@{$silo->{entries}}) {#my ($v, $e) = each %{$silo->{entries}}) {
	    my $type = "$_->{type}=$_->{kernel_or_dev}"; $type =~ s|/boot|$silo->{boot}|;
	    print F $type;
	    print F "\tlabel=$_->{label}";

	    if ($_->{type} eq "image") {
		my $initrd = $_->{initrd}; $initrd =~ s|/boot|$silo->{boot}|;
		print F "\tpartition=$_->{partition}" if $_->{partition};
		print F "\troot=$_->{root}" if $_->{root};
		print F "\tinitrd=$initrd" if $_->{initrd};
		print F "\tappend=\"$1\"" if $_->{append} =~ /^\s*"?(.*?)"?\s*$/;
		print F "\tread-write" if $_->{'read-write'};
		print F "\tread-only" if !$_->{'read-write'};
	    }
	}
    }
    log::l("Installing boot loader...");
    $::testing and return;
    run_program::rooted($prefix, "silo", "2>", "/tmp/.error", $silo->{use_partition} ? ("-t") : ()) or 
        run_program::rooted($prefix, "silo", "2>", "/tmp/.error", "-p", "2", $silo->{use_partition} ? ("-t") : ()) or 
	    die "silo failed";
    unlink "$prefix/tmp/.error";

    #- try writing in the prom.
    log::l("setting promvars alias=$silo->{bootalias} bootdev=$silo->{bootdev}");
    require c;
    c::setPromVars($silo->{bootalias}, $silo->{bootdev});
}

sub install_lilo ($$) {
    my ($prefix, $lilo, $fstab, $hds) = @_;
    $lilo->{prompt} = $lilo->{timeout};

    my $file2fullname = sub {
	my ($file) = @_;
	if (arch() =~ /ia64/) {
	    (my $part, $file) = fsedit::file2part($prefix, $fstab, $file);
	    my %hds = map_index { $_ => "hd$::i" } sort map { $_->{device} } @$hds;
	    #- FUCK TO THE GUY WHICH DOESN'T DO perl -cw bootloader.pm #$dev2efi->{$part->{device}} . ":" . $file;
	} else {
	    $file
	}
    };

    #- try to use a specific stage2 if defined and present.
    -e "$prefix/boot/$lilo->{methods}{lilo}" and symlinkf $lilo->{methods}{lilo}, "$prefix/boot/lilo";
    log::l("stage2 of lilo used is " . readlink "$prefix/boot/lilo");

    if ($lilo->{methods}{lilo} eq "lilo-graphic") {
	-e "$prefix/boot/$lilo->{methods}{lilo}/message" and symlinkf "$lilo->{methods}{lilo}/message", "$prefix/boot/message";
    }  else  {
	-e "$prefix/boot/message" and unlink "$prefix/boot/message";
	print "-->$prefix/boot/messag<--\n";
	
	my $msg_en =
	  #-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
__("Welcome to %s the operating system chooser!

Choose an operating system in the list above or
wait %d seconds for default boot.

");
	my $msg = translate($msg_en);
	#- use the english version if more than 20% of 8bits chars
	$msg = $msg_en if int(grep { $_ & 0x80 } unpack "c*", $msg) / length($msg) > 0.2;
	$msg = sprintf $msg, arch() =~ /sparc/ ? "SILO" : "LILO", $lilo->{timeout};
 	local *F;
	open F, ">$prefix/boot/message" and print F $msg;
    }
    {
	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);
	$lilo->{$_} and print F $_ foreach qw(linear lba32 compact prompt restricted);
	#- print F "password=", $lilo->{password} if $lilo->{restricted} && $lilo->{password}; #- done by msec
	print F "timeout=", round(10 * $lilo->{timeout}) if $lilo->{timeout};

	my $dev = $hds->[0]{device};
	my %dev2bios = map_index { $_ => $::i } dev2bios($hds, $lilo->{boot});
	if ($dev2bios{$dev}) {
	    my %bios2dev = reverse %dev2bios;
	    print  F "disk=/dev/$bios2dev{0} bios=0x80";
	    printf F "disk=/dev/$dev bios=0x%x", 0x80 + $dev2bios{$dev};
	} elsif ($dev =~ /hd[bde]/) {
	    print F "disk=/dev/$dev bios=0x80";
	}

	print F "message=/boot/message";
	print F "menu-scheme=wb:bw:wb:bw";

	foreach (@{$lilo->{entries}}) {
	    print F "$_->{type}=$_->{kernel_or_dev}";
	    my $label = substr($_->{label}, 0, 15); #- lilo doesn't handle more than 15 char long labels
	    $label =~ s/\s/_/g; #- lilo doesn't like spaces
	    print F "\tlabel=$label"; 

	    if ($_->{type} eq "image") {		
		print F "\troot=", $file2fullname->($_->{root});
		print F "\tinitrd=", $file2fullname->($_->{initrd}) if $_->{initrd};
		print F "\tappend=\"$_->{append}\"" if $_->{append};
		print F "\tvga=$_->{vga}" if $_->{vga};
		print F "\tread-write" if $_->{'read-write'};
		print F "\tread-only" if !$_->{'read-write'};
	    } else {
		print F "\ttable=$_->{table}" if $_->{table};
		print F "\tunsafe" if $_->{unsafe} && !$_->{table};
		
		if (my ($dev) = $_->{table} =~ m|/dev/(.*)|) {
		    if ($dev2bios{$dev}) {
			#- boot off the nth drive, so reverse the BIOS maps
			my $nb = sprintf("0x%x", 0x80 + $dev2bios{$dev});
			$_->{mapdrive} ||= { '0x80' => $nb, $nb => '0x80' }; 
		    }
		}
		while (my ($from, $to) = each %{$_->{mapdrive} || {}}) {
		    print F "\tmap-drive=$from";
		    print F "\t   to=$to";
		}
	    }
	}
    }

    log::l("Installing boot loader...");
    $::testing and return;
    run_program::rooted_or_die($prefix, "lilo", "2>", "/tmp/.error");
    unlink "$prefix/tmp/.error";
}

sub dev2bios {
    my ($hds, $where) = @_;
    my @dev = map { $_->{device} } @$hds;
    member($where, @dev) or ($where) = @dev; #- if not on mbr, 

    s/h(d[e-g])/x$1/ foreach $where, @dev; #- emulates ultra66 as xd_

    my $start = substr($where, 0, 2);

    my $translate = sub {
	$_ eq $where ? "aaa" : #- if exact match, value it first
	  /^$start(.*)/ ? "ad$1" : #- if same class (ide/scsi/ultra66), value it before other classes
	    $_;
    };
    @dev = map { $_->[0] }
           sort { $a->[1] cmp $b->[1] }
	   map { [ $_, &$translate ] } @dev;

    s/x(d.)/h$1/ foreach @dev; #- switch back;

    @dev;
}

sub dev2grub {
    my ($dev, $dev2bios) = @_;
    $dev =~ m|^(/dev/)?(...)(.*)$| or die "dev2grub (bad device $dev), caller is " . join(":", caller());
    my $grub = $dev2bios->{$2} or die "dev2grub ($2)";
    "($grub" . ($3 && "," . ($3 - 1)) . ")";
}

sub install_grub {
    my ($prefix, $lilo, $fstab, $hds) = @_;
    my %dev2bios = (
      (map_index { $_ => "fd$::i" } detect_devices::floppies()),
      (map_index { $_ => "hd$::i" } dev2bios($hds, $lilo->{boot})),
    );

    {
	my %bios2dev = reverse %dev2bios;
	output "$prefix/boot/grub/device.map", 
	  join '', map { "($_) /dev/$bios2dev{$_}\n" } sort keys %bios2dev;
    }
    my $bootIsReiser = isReiserfs(fsedit::get_root($fstab, 'boot'));
    my $file2grub = sub {	
	#- FUCK TO THE GUY WHICH DOESN'T DO perl -cw bootloader.pm #my ($part, $file) = fsedit::file2part($prefix, $fstab, $file);
	#- FUCK TO THE GUY WHICH DOESN'T DO perl -cw bootloader.pm #dev2grub($part->{device}, \%dev2bios) . $file;
    };
    {
	local *F;
        local $\ = "\n";
	my $f = "$prefix/boot/grub/menu.lst";
	open F, ">$f" or die "cannot create grub config file: $f";
	log::l("writing grub config to $f");

	$lilo->{$_} and print F "$_ $lilo->{$_}" foreach qw(timeout);

	print F "color black/cyan yellow/cyan";
	print F "i18n ", $file2grub->("/boot/grub/messages");
	print F "keytable ", $file2grub->($lilo->{keytable}) if $lilo->{keytable};
	#- since we use notail in reiserfs, altconfigfile is broken :-(
	unless ($bootIsReiser) {
	    print F "altconfigfile ", $file2grub->(my $once = "/boot/grub/menu.once");
	    output "$prefix$once", " " x 100;
	}

	map_index {
	    print F "default $::i" if $_->{label} eq $lilo->{default};
	} @{$lilo->{entries}};

	foreach (@{$lilo->{entries}}) {
	    print F "\ntitle $_->{label}";

	    if ($_->{type} eq "image") {
		my $vga = $_->{vga} || $lilo->{vga};
		printf F "kernel %s root=%s %s%s%s\n",
		  $file2grub->($_->{kernel_or_dev}),
		  $_->{root} =~ /loop7/ ? "707" : $_->{root}, #- special to workaround bug in kernel (see #ifdef CONFIG_BLK_DEV_LOOP)
		  $_->{append},
		  $_->{'read-write'} && " rw",
		  $vga && $vga ne "normal" && " vga=$vga";
		print F "initrd ", $file2grub->($_->{initrd}) if $_->{initrd};
	    } else {
		print F "root ", dev2grub($_->{kernel_or_dev}, \%dev2bios);
		if ($_->{kernel_or_dev} !~ /fd/) {
		    #- boot off the second drive, so reverse the BIOS maps
		    $_->{mapdrive} ||= { '0x80' => '0x81', '0x81' => '0x80' } 
		      if $_->{table} && $lilo->{boot} !~ /$_->{table}/;
	    
		    map_each { print F "map ($::b) ($::a)" } %{$_->{mapdrive} || {}};

		    print F "makeactive";
		}
		print F "chainloader +1";
	    }
	}
    }
    my $hd = fsedit::get_root($fstab, 'boot')->{rootDevice};

    my $dev = dev2grub($lilo->{boot}, \%dev2bios);
    my ($s1, $s2, $m) = map { $file2grub->("/boot/grub/$_") } qw(stage1 stage2 menu.lst);
    my $f = "/boot/grub/install.sh";
    output "$prefix$f",
"grub --device-map=/boot/grub/device.map --batch <<EOF
install $s1 d $dev $s2 p $m
quit
EOF
";

     output "$prefix/boot/grub/messages", map { substr(translate($_) . "\n", 0, 78) } ( #- ensure the translated messages are not too big the hard way
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
#-PO: and keep them smaller than 79 chars long
__("Welcome to GRUB the operating system chooser!"),
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
#-PO: and keep them smaller than 79 chars long
__("Use the %c and %c keys for selecting which entry is highlighted."),
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
#-PO: and keep them smaller than 79 chars long
__("Press enter to boot the selected OS, \'e\' to edit the"),
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
#-PO: and keep them smaller than 79 chars long
__("commands before booting, or \'c\' for a command-line."),
#-PO: these messages will be displayed at boot time in the BIOS, use only ASCII (7bit)
#-PO: and keep them smaller than 79 chars long
__("The highlighted entry will be booted automatically in %d seconds."),
);
   
    my $e = "$prefix/boot/.enough_space";
    output $e, 1; -s $e or die _("not enough room in /boot");
    unlink $e;

    log::l("Installing boot loader...");
    $::testing and return;
    symlink "$prefix/boot", "/boot";
    run_program::run("sh", $f) or die "grub installation failed";
    unlink "$prefix/tmp/.error.grub", "/boot";
}

sub lnx4win_file { 
    my $lilo = shift;
    map { local $_ = $_; s,/,\\,g; "$lilo->{boot_drive}:\\lnx4win$_" } @_;
}

sub loadlin_cmd {
    my ($prefix, $lilo) = @_;
    my $e = get_label("linux", $lilo) || first(grep { $_->{type} eq "image" } @{$lilo->{entries}});

    commands::cp("$prefix$e->{kernel_or_dev}", "$prefix/boot/vmlinuz") unless -e "$prefix/boot/vmlinuz";
    commands::cp("$prefix$e->{initrd}", "$prefix/boot/initrd.img") unless -e "$prefix/boot/initrd.img";

    $e->{label}, sprintf"%s %s initrd=%s root=%s $e->{append}", 
      lnx4win_file($lilo, "/loadlin.exe", "/boot/vmlinuz", "/boot/initrd.img"),
	$e->{root} =~ /loop7/ ? "0707" : $e->{root}; #- special to workaround bug in kernel (see #ifdef CONFIG_BLK_DEV_LOOP)
}

sub install_loadlin {
    my ($prefix, $lilo, $fstab) = @_;

    my $boot;
    ($boot) = grep { $lilo->{boot} eq "/dev/$_->{device}" } @$fstab;
    ($boot) = grep { loopback::carryRootLoopback($_) } @$fstab unless $boot && $boot->{device_windobe};
    ($boot) = grep { isFat($_) } @$fstab unless $boot && $boot->{device_windobe};
    log::l("loadlin device is $boot->{device} (windobe $boot->{device_windobe})");
    $lilo->{boot_drive} = $boot->{device_windobe};

    my ($winpart) = grep { $_->{device_windobe} eq 'C' } @$fstab;
    log::l("winpart is $winpart->{device}");
    my $winhandle = any::inspect($winpart, $prefix, 'rw');
    my $windrive = $winhandle->{dir};
    log::l("windrive is $windrive");

    my ($label, $cmd) = loadlin_cmd($prefix, $lilo);

    #install_loadlin_config_sys($lilo, $windrive, $label, $cmd);
    #install_loadlin_desktop($lilo, $windrive);

    output "/initrd/loopfs/lnx4win/linux.bat", unix2dos(
'@echo off
echo Mandrake Linux
smartdrv /C
' . "$cmd\n");

}

sub install_loadlin_config_sys {
    my ($lilo, $windrive, $label, $cmd) = @_;

    my $config_sys = "$windrive/config.sys";
    local $_ = cat_($config_sys);
    output "$windrive/config.mdk", $_ if $_;
    
    my $timeout = $lilo->{timeout} || 1;

    $_ = "
[Menu]
menuitem=Windows
menudefault=Windows,$timeout

[Windows]
" . $_ if !/^\Q[Menu]/m;

    #- remove existing entry
    s/^menuitem=$label\s*//mi;    
    s/\n\[$label\].*?(\n\[|$)/$1/si;

    #- add entry
    s/(.*\nmenuitem=[^\n]*)/$1\nmenuitem=$label/s;

    $_ .= "
[$label]
shell=$cmd
";
    output $config_sys, unix2dos($_);
}

sub install_loadlin_desktop {
    my ($lilo, $windrive) = @_;
    my $windir = lc(cat_("$windrive/msdos.sys") =~ /^WinDir=.:\\(\S+)/m ? $1 : "windows");

#-PO: "Desktop" and "Start Menu" are the name of the directories found in c:\windows
#-PO: so you may need to put them in English or in a different language if MS-windows doesn't exist in your language
    foreach (__("Desktop"),
#-PO: "Desktop" and "Start Menu" are the name of the directories found in c:\windows 
	     __("Start Menu")) {
        my $d = "$windrive/$windir/" . translate($_);
        -d $d or $d = "$windrive/$windir/$_";
        -d $d or log::l("can't find windows $d directory"), next;
        output "$d/Linux4Win.url", unix2dos(sprintf 
q([InternetShortcut]
URL=file:\lnx4win\lnx4win.exe
WorkingDirectory=%s
IconFile=%s
IconIndex=0
), lnx4win_file($lilo, "/", "/lnx4win.ico"));
    }
}


sub install {
    my ($prefix, $lilo, $fstab, $hds) = @_;

    {
	my $f = "$prefix/etc/sysconfig/system";
	setVarsInSh($f, add2hash_({ CLEAN_TMP => $lilo->{CLEAN_TMP} }, { getVarsFromSh($f) }));
    }
    $lilo->{keytable} = keytable($prefix, $lilo->{keytable});

    my %l = grep_each { $::b } %{$lilo->{methods}};
    my @rcs = map {
	my $f = $bootloader::{"install_$_"} or die "unknown bootloader method $_";
	eval { $f->(@_) };
	$@;
    } reverse sort keys %l; #- reverse sort for having grub installed after lilo if both are there.
    
    return if grep { !$_ } @rcs; #- at least one worked?
    die first(map { $_ } @rcs);
}

#-######################################################################################
#- Wonderful perl :(
#-######################################################################################
1; #