summaryrefslogtreecommitdiffstats
path: root/perl-install/install_any.pm
blob: bfbf626510a5773c17f7a7ffb870d4e9d8b5243e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
package install_any;

use diagnostics;
use strict;
use vars qw(@ISA %EXPORT_TAGS @EXPORT_OK);

@ISA = qw(Exporter);
%EXPORT_TAGS = (
    all => [ qw(getNextStep spawnSync spawnShell addToBeDone) ],
);
@EXPORT_OK = map { @$_ } values %EXPORT_TAGS;

#-######################################################################################
#- misc imports
#-######################################################################################
use common qw(:common :system :functional);
use commands;
use run_program;
use partition_table qw(:types);
use fsedit;
use detect_devices;
use pkgs;
use fs;
use log;


#-######################################################################################
#- Functions
#-######################################################################################
sub relGetFile($) {
    local $_ = $_[0];
    my $dir = m|/| ? "mdkinst" :
      (member($_, qw(compss compssList depslist hdlist)) ? "base" : "RPMS");
    $_ = "Mandrake/$dir/$_";
    s/i386/i586/;
    $_;
}
sub getFile($) {
    local $^W = 0;
    if ($::o->{method} && $::o->{method} eq "ftp") {
	require 'ftp.pm';
	*install_any::getFile = \&ftp::getFile;
    } else {
	*install_any::getFile = sub($) {
	    open getFile, "/tmp/rhimage/" . relGetFile($_[0]) or return;
	    \*getFile;
	};
    }
    goto &getFile;
}

sub kernelVersion {
    local $_ = readlink("$::o->{prefix}/boot/vmlinuz") || $::testing && "vmlinuz-2.2.testversion" or die "I couldn't find the kernel package!";
    first(/vmlinuz-(.*)/);
}


sub getNextStep {
    my ($s) = $::o->{steps}{first};
    $s = $::o->{steps}{$s}{next} while $::o->{steps}{$s}{done};
    $s;
}

sub spawnSync {
    return if $::o->{localInstall} || $::testing;
    fork and return;
    while (1) { sleep(30); sync(); }
}

sub spawnShell {
    return if $::o->{localInstall} || $::testing;

    -x "/bin/sh" or die "cannot open shell - /usr/bin/sh doesn't exist";

    fork and return;

    local *F;
    sysopen F, "/dev/tty2", 2 or die "cannot open /dev/tty2 -- no shell will be provided";

    open STDIN, "<&F" or die '';
    open STDOUT, ">&F" or die '';
    open STDERR, ">&F" or die '';
    close F;

    c::setsid();

    ioctl(STDIN, c::TIOCSCTTY(), 0) or warn "could not set new controlling tty: $!";

    exec {"/bin/sh"} "-/bin/sh" or log::l("exec of /bin/sh failed: $!");
}

sub shells($) {
    my ($o) = @_;
    my @l = grep { -x "$o->{prefix}$_" } @{$o->{shells}};
    @l ? @l : "/bin/bash";
}

sub getAvailableSpace {
    my ($o) = @_;

    do { $_->{mntpoint} eq '/usr' and return $_->{size} * 512 } foreach @{$o->{fstab}};
    do { $_->{mntpoint} eq '/'    and return $_->{size} * 512 } foreach @{$o->{fstab}};

    if ($::testing) {
	log::l("taking 200MB for testing");
	return 200 << 20;
    }
    die "missing root partition";
}

sub setPackages($$) {
    my ($o, $install_classes) = @_;

    if ($o->{packages}) {
	$_->{selected} = 0 foreach values %{$o->{packages}};
    } else {
	my $useHdlist = $o->{method} !~ /nfs|hd/ || $o->{isUpgrade};
	$useHdlist = 0;
	eval { $o->{packages} = pkgs::psUsingHdlist() }  if $useHdlist;
	$o->{packages} = pkgs::psUsingDirectory() if !$useHdlist || $@;

	pkgs::getDeps($o->{packages});

	$o->{compss} = pkgs::readCompss($o->{packages});
	$o->{compssListLevels} = pkgs::readCompssList($o->{packages}, $o->{compss});
	$o->{compssListLevels} ||= $install_classes;
	push @{$o->{base}}, "kernel-smp" if detect_devices::hasSMP();
	push @{$o->{base}}, "kernel-pcmcia-cs" if $o->{pcmcia};
    }

    #- this will be done if necessary in the selectPackagesToUpgrade,
    #- move the selection here ? this will remove the little window.
    unless ($o->{isUpgrade}) {
	do {
	    my $p = $o->{packages}{$_} or log::l("missing base package $_"), next;
	    pkgs::select($o->{packages}, $p, 1);
	} foreach @{$o->{base}};
    }

    pkgs::setShowFromCompss($o->{compss}, $o->{installClass}, $o->{lang});
    ($o->{packages_}{ind}, $o->{packages_}{select_level}) = pkgs::setSelectedFromCompssList($o->{compssListLevels}, $o->{packages}, getAvailableSpace($o) * 0.7, $o->{installClass}, $o->{lang}, $o->{isUpgrade});
}

sub selectPackagesToUpgrade($) {
    my ($o) = @_;

    pkgs::selectPackagesToUpgrade($o->{packages}, $o->{prefix}, $o->{base});
}

sub addToBeDone(&$) {
    my ($f, $step) = @_;

    return &$f() if $::o->{steps}{$step}{done};

    push @{$::o->{steps}{$step}{toBeDone}}, $f;
}

sub install_cpio($$) {
    my ($dir, $name) = @_;

    return "$dir/$name" if -e "$dir/$name";

    my $cpio = "$dir.cpio.bz2";
    -e $cpio or return;

    eval { commands::rm("-r", $dir) };
    mkdir $dir, 0755;
    run_program::run("cd $dir ; bzip2 -cd $cpio | cpio -id $name $name/*");
    "$dir/$name";
}

sub getHds {
    my ($o) = @_;
    my ($ok, $ok2) = 1;

  getHds: 
    $o->{hds} = catch_cdie { fsedit::hds([ detect_devices::hds() ], $o->{partitioning}) }
      sub {
	$o->ask_warn(_("Error"),
_("I can't read your partition table, it's too corrupted for me :(
I'll try to go on blanking bad partitions")) unless $o->{partitioning}{readonly};
	$ok = 0; 1 
    };

    if (is_empty_array_ref($o->{hds}) && $o->{autoSCSI}) {
	$o->setupSCSI; #- ask for an unautodetected scsi card
	goto getHds;
    }

    ($o->{hds}, $o->{fstab}, $ok2) = fsedit::verifyHds($o->{hds}, $o->{partitioning}{readonly}, $ok);

    fs::check_mounted($o->{fstab});

    $o->ask_warn('', 
_("DiskDrake failed to read correctly the partition table.
Continue at your own risk!")) if !$ok2 && $ok && !$o->{partitioning}{readonly};

    $ok2;
}

sub searchAndMount4Upgrade {
    my ($o) = @_;
    my ($root, $found);

    #- try to find the partition where the system is installed if beginner
    #- else ask the user the right partition, and test it after.
    getHds($o);

    #- get all ext2 partition that may be root partition.
    my %Parts = my %parts = map { $_->{device} => $_ } grep { isExt2($_) } @{$o->{fstab}};
    while (keys(%parts) > 0) {
	$root = $::beginner ? first(%parts) : $o->selectRootPartition(keys %parts);
	$root = delete $parts{$root};

	my $r; unless ($r = $root->{realMntpoint}) {
	    $r = $o->{prefix};
	    $root->{mntpoint} = "/"; 
	    log::l("trying to mount root partition $root->{device}");
	    eval { fs::mount_part($root, $o->{prefix}, 'readonly') };
	    $r = "/*ERROR*" if $@;
	}
	$found = -d "$r/etc/sysconfig" && [ fs::read_fstab("$r/etc/fstab") ];

	unless ($root->{realMntpoint}) {
	    log::l("umounting non root partition $root->{device}");
	    eval { fs::umount_part($root, $o->{prefix}) };
	}

	last if !is_empty_array_ref($found);

	delete $root->{mntpoint};
	$o->ask_warn(_("Information"), 
		     _("%s: This is not a root partition, please select another one.", $root->{device})) unless $::beginner;
    }
    is_empty_array_ref($found) and die _("No root partition found");
	
    log::l("Found root partition : $root->{device}");
    $o->{prefix} = $root->{mntpoint};

    #- test if the partition has to be fschecked and remounted rw.
    unless ($root->{realMntpoint}) {
	delete $root->{mntpoint};
	($Parts{$_->{device}} || {})->{mntpoint} = $_->{mntpoint} foreach @$found;

	#- TODO fsck, create check_mount_all ?
	fs::mount_all([ grep { isExt2($_) || isSwap($_) } @{$o->{fstab}} ], $o->{prefix});
    }
}
n> basename2initrd_basename { my ($basename) = @_; $basename =~ s!vmlinuz-?!!; #- here we don't 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->{basename}) . '-' . $kernel->{version} . '.img'; } sub kernel_str2vmlinuz_short { my ($kernel) = @_; if ($kernel->{use_long_name}) { kernel_str2vmlinuz_long($kernel); } else { my $ext = $kernel->{ext} ? "-$kernel->{ext}" : ''; $kernel->{basename} . $ext; } } sub kernel_str2initrd_short { my ($kernel) = @_; if ($kernel->{use_long_name}) { kernel_str2initrd_long($kernel); } else { my $ext = $kernel->{ext} ? "-$kernel->{ext}" : ''; basename2initrd_basename($kernel->{basename}) . $ext . '.img'; } } sub vmlinuz2kernel_str { my ($vmlinuz) = @_; my ($basename, $version) = expand_vmlinuz_symlink($vmlinuz) =~ /$decompose_vmlinuz_name/ or return; { basename => $basename, version => $version, $version =~ /(.*mdk)-?(.*)/ ? (ext => $2, version_no_ext => $1) : (version_no_ext => $version), }; } sub kernel_str2label { my ($kernel) = @_; $kernel->{use_long_name} ? sanitize_ver("linux-$kernel->{version}") : $kernel->{ext} ? "linux$kernel->{ext}" : 'linux'; } 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, $initrd, $o_vga) = @_; $::testing || -e "$::prefix/$initrd" and return 1; my $loop_boot = loopback::prepare_boot(); my $o_resolution = $o_vga && do { require Xconfig::resolution_and_depth; my $res = Xconfig::resolution_and_depth::from_bios($o_vga); $res && $res->{X}; }; modules::load('loop'); if (!run_program::rooted($::prefix, "mkinitrd", "-v", "-f", $initrd, "--ifneeded", $kernel_version, if_($o_resolution, '--splash' => $o_resolution))) { unlink("$::prefix/$initrd"); die "mkinitrd failed"; } loopback::save_boot($loop_boot); -e "$::prefix/$initrd"; } sub read { my ($fstab) = @_; my @methods = method_choices_raw(); foreach my $main_method (uniq(map { main_method($_) } @methods)) { my $f = $bootloader::{"read_$main_method"} or die "unknown bootloader method $main_method (read)"; my $bootloader = $f->($fstab); my $type = partition_table::raw::typeOfMBR($bootloader->{boot}); if ($type eq $main_method) { return $bootloader; } } } sub read_grub { my ($fstab) = @_; my $global = 1; my ($e, %b); my $grub2dev = read_grub_device_map(); my $menu_lst_file = "$::prefix/boot/grub/menu.lst"; -e $menu_lst_file or return; foreach (cat_($menu_lst_file)) { chomp; s/^\s*//; s/\s*$//; next if /^#/ || /^$/; my ($keyword, $v) = split(' ', $_, 2) or warn qq(unknown line in /boot/grub/menu.lst: "$_"\n), next; if ($keyword eq 'title') { push @{$b{entries}}, $e = { label => $v }; $global = 0; } elsif ($global) { $b{$keyword} = $v eq '' ? 1 : grub2file($v, $grub2dev, $fstab); } else { if ($keyword eq 'kernel') { $e->{type} = 'image'; (my $kernel, $e->{append}) = split(' ', $v, 2); $e->{root} = $1 if $e->{append} =~ s/root=(\S*)\s*//; $e->{kernel_or_dev} = grub2file($kernel, $grub2dev, $fstab); } elsif ($keyword eq 'root') { $e->{type} = 'other'; if ($v =~ /,/) { $e->{table} = grub2dev($v, $grub2dev, 1); } else { $e->{unsafe} = 1; } $e->{kernel_or_dev} = grub2dev($v, $grub2dev); $e->{append} = ""; } elsif ($keyword eq 'initrd') { $e->{initrd} = grub2file($v, $grub2dev, $fstab); } } } foreach (cat_("$::prefix/boot/grub/install.sh")) { $b{boot} = grub2dev($1, $grub2dev) if /\s+d\s+(\(.*?\))/; } #- sanitize foreach (@{$b{entries}}) { my ($vga, $other) = partition { /^vga=/ } split(' ', $_->{append}); if (@$vga) { $_->{vga} = $vga->[0] =~ /vga=(.*)/ && $1; $_->{append} = join(' ', @$other); } } $b{nowarn} = 1; # handle broken installkernel -r: $b{default} = min($b{default}, scalar(@{$b{entries}}) - 1); $b{default} = $b{entries}[$b{default}]{label}; $b{method} = 'grub'; \%b; } sub read_yaboot() { &read_lilo } sub read_lilo() { my $file = sprintf("$::prefix/etc/%s.conf", arch() =~ /ppc/ ? 'yaboot' : 'lilo'); my $global = 1; my ($e, $v); my %b; -e $file or return; foreach (cat_($file)) { next if /^\s*#/ || /^\s*$/; ($_, $v) = /^\s*([^=\s]+)\s*(?:=\s*(.*?))?\s*$/ or log::l("unknown line in $file: $_"), next; if (/^(image|other)$/) { if (arch() =~ /ppc/) { $v =~ s/hd:\d+,//g; } push @{$b{entries}}, $e = { type => $_, kernel_or_dev => $v }; $global = 0; } elsif ($global) { if ($_ eq 'disk' && $v =~ /(\S+)\s+bios\s*=\s*(\S+)/) { $b{bios}{$1} = $2; } elsif ($_ eq 'bios') { $b{bios}{$b{disk}} = $v; } elsif ($_ eq 'init-message') { $v =~ s/\\n//g; $v =~ s/"//g; $b{'init-message'} = $v; } else { $b{$_} = $v eq '' ? 1 : $v; } } else { if ((/map-drive/ .. /to/) && /to/) { $e->{mapdrive}{$e->{'map-drive'}} = $v; } else { if (arch() =~ /ppc/) { $v =~ s/hd:\d+,//g; $v =~ s/"//g; } $e->{$_} = $v || 1 if !member($_, 'read-only'); } } } if (arch() !~ /ppc/) { delete $b{timeout} unless $b{prompt}; sub remove_quotes_and_spaces { local ($_) = @_; s/^\s*//; s/\s*$//; s/^"(.*?)"$/$1/; $_; } $_->{append} = remove_quotes_and_spaces($_->{append}) foreach \%b, @{$b{entries}}; $_->{label} = remove_quotes_and_spaces($_->{label}) foreach @{$b{entries}}; $b{default} = remove_quotes_and_spaces($b{default}) if $b{default}; $b{timeout} = $b{timeout} / 10 if $b{timeout}; $b{method} = 'lilo-' . (member($b{install}, 'text', 'menu', 'graphic') ? $b{install} : 'graphic'); delete $b{message}; } if (my $default = find { $_ && $_->{append} } get_label($b{default}, \%b), @{$b{entries}}) { $b{perImageAppend} ||= $default->{append}; } #- cleanup duplicate labels & bad entries (in case file is corrupted) my %seen; @{$b{entries}} = grep { !$seen{$_->{label}}++ } grep { $_->{type} ne 'image' || -e "$::prefix$_->{kernel_or_dev}" } @{$b{entries}}; \%b; } 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))) { $onmbr = 0; } log::l("bootloader::suggest_onmbr: type $type, onmbr $onmbr, unsafe $unsafe"); } ($onmbr, $unsafe); } sub same_entries { my ($a, $b) = @_; foreach (uniq(keys %$a, keys %$b)) { if ($_ eq 'label') { next; } elsif ($_ eq 'append') { next if join(' ', sort split(' ', $a->{$_})) eq join(' ', sort split(' ', $b->{$_})) } 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} don't have same $_: $a->{$_} ne $b->{$_}"); return; } 1; } sub add_entry { my ($bootloader, $v) = @_; my $to_add = $v; foreach my $label ($v->{label}, map { 'old' . $_ . '_' . $v->{label} } ('', 2..10)) { 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}}; } 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; } die 'add_entry'; } sub add_kernel { my ($bootloader, $kernel_str, $nolink, $v) = @_; #- new versions of yaboot don't handle symlinks $nolink ||= arch() =~ /ppc/; $nolink ||= $kernel_str->{use_long_name}; my $vmlinuz_long = kernel_str2vmlinuz_long($kernel_str); my $image = "/boot/$vmlinuz_long"; -e "$::prefix$image" or log::l("unable to find kernel image $::prefix$image"), return; if (!$nolink) { $image = '/boot/' . kernel_str2vmlinuz_short($kernel_str); symlinkf($vmlinuz_long, "$::prefix$image") or cp_af("$::prefix/boot/$vmlinuz_long", "$::prefix$image"); } log::l("adding $image"); my $initrd_long = kernel_str2initrd_long($kernel_str); my $initrd = "/boot/$initrd_long"; mkinitrd($kernel_str->{version}, $initrd, $v->{vga}) or undef $initrd; if ($initrd && !$nolink) { $initrd = '/boot/' . kernel_str2initrd_short($kernel_str); symlinkf($initrd_long, "$::prefix$initrd") or cp_af("$::prefix/boot/$initrd_long", "$::prefix$initrd"); } my $label = kernel_str2label($kernel_str); add2hash($v, { type => 'image', label => $label, kernel_or_dev => $image, initrd => $initrd, }); $v->{append} = normalize_append("$bootloader->{perImageAppend} $v->{append}"); add_entry($bootloader, $v); } 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); } sub unpack_append { my ($s) = @_; my @l = split(' ', $s); [ 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 eq 'mem' ? "$k=$v" : $k } reverse @$dict) ]; join(' ', @$simple, map { "$_->[0]=$_->[1]" } @$dict); } sub normalize_append { my ($s) = @_; my ($simple, $dict) = unpack_append($s); pack_append($simple, $dict); } sub append__mem_is_memsize { $_[0] =~ /^\d+[kM]?$/i } sub get_append { my ($b, $key) = @_; my ($simple, $dict) = unpack_append($b->{perImageAppend}); if (member($key, @$simple)) { return 1; } my @l = map { $_->[1] } grep { $_->[0] eq $key } @$dict; #- suppose we want the memsize @l = grep { append__mem_is_memsize($_) } @l if $key eq 'mem'; log::l("more than one $key in $b->{perImageAppend}") if @l > 1; $l[0]; } sub modify_append { my ($b, $f) = @_; foreach (\$b->{perImageAppend}, map { \$_->{append} } grep { $_->{type} eq 'image' } @{$b->{entries}}) { my ($simple, $dict) = unpack_append($$_); $f->($simple, $dict); $$_ = pack_append($simple, $dict); log::l("modify_append: $$_"); } } sub remove_append_simple { my ($b, $key) = @_; modify_append($b, sub { my ($simple, $_dict) = @_; @$simple = grep { $_ ne $key } @$simple; }); } sub set_append { my $has_val = @_ > 2; my ($b, $key, $val) = @_; modify_append($b, sub { my ($simple, $dict) = @_; if ($has_val) { @$dict = grep { $_->[0] ne $key || $key eq 'mem' && append__mem_is_memsize($_->[1]) != append__mem_is_memsize($val) } @$dict; push @$dict, [ $key, $val ] if !($val eq '' || $key eq 'mem' && !$val); } else { @$simple = grep { $_ ne $key } @$simple; push @$simple, $key; } }); } sub may_append { my ($b, $key, $val) = @_; set_append($b, $key, $val) if !get_append($b, $key); } sub configure_entry { my ($entry) = @_; $entry->{type} eq 'image' or return; if (my $kernel_str = vmlinuz2kernel_str($entry->{kernel_or_dev})) { $entry->{initrd} ||= '/boot/' . kernel_str2initrd_short($kernel_str); mkinitrd($kernel_str->{version}, $entry->{initrd}, $entry->{vga}) or undef $entry->{initrd}; } } 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 get_kernels_and_labels { my ($b_prefer_24) = @_; my @kernels = installed_vmlinuz(); require pkgs; my @kernels_str = sort { c::rpmvercmp($b->{version_no_ext}, $a->{version_no_ext}) } grep { -d "$::prefix/lib/modules/$_->{version}" } map { vmlinuz2kernel_str($_) } @kernels; if ($b_prefer_24) { my ($kernel_24, $other) = partition { $_->{ext} eq '' && $_->{version} =~ /^\Q2.4/ } @kernels_str; @kernels_str = (@$kernel_24, @$other); } $kernels_str[0]{ext} = ''; my %labels; foreach (@kernels_str) { if ($labels{$_->{ext}}) { $_->{use_long_name} = 1; } else { $labels{$_->{ext}} = 1; } } @kernels_str; } # sanitize_ver: long function when it could be shorter but we are sure # to catch everything and can be readable if we want to # add new scheme name. # DUPLICATED from /usr/share/loader/common.pm sub sanitize_ver { my ($string) = @_; my ($main_version, undef, $extraversion, $rest) = $string =~ m!(\d+\.\d+\.\d+)(-((?:pre|rc)\d+))?(.*)!; if (my ($mdkver, $cpu, $nproc, $mem) = $rest =~ m|-(.+)-(.+)-(.+)-(.+)|) { $rest = "$cpu$nproc$mem-$mdkver"; } my $return = "$main_version$extraversion$rest"; $return =~ s|\.||g; $return =~ s|mdk||; $return =~ s|64GB|64G|; $return =~ s|4GB|4G|; $return =~ s|secure|sec|; $return =~ s|enterprise|ent|; $return; } sub suggest { my ($bootloader, $hds, %options) = @_; my $fstab = [ fsedit::get_fstab(@$hds) ]; my $root_part = fsedit::get_root($fstab); my $root = '/dev/' . (isLoopback($root_part) ? 'loop7' : $root_part->{device}); my $boot = fsedit::get_root($fstab, 'boot')->{device}; #- PPC xfs module requires enlarged initrd my $xfsroot = isThisFs("xfs", $root_part); my ($onmbr, $unsafe) = $bootloader->{crushMbr} ? (1, 0) : suggest_onmbr($hds->[0]); add2hash_($bootloader, arch() =~ /ppc/ ? { defaultos => "linux", entries => [], 'init-message' => "Welcome to Mandrakelinux!", delay => 30, #- OpenFirmware delay timeout => 50, enableofboot => 1, enablecdboot => 1, useboot => $boot, xfsroot => $xfsroot, } : { bootUnsafe => $unsafe, entries => [], timeout => $onmbr && 10, nowarn => 1, if_(arch() !~ /ia64/, boot => "/dev/" . ($onmbr ? $hds->[0]{device} : fsedit::get_root($fstab, 'boot')->{device}), map => "/boot/map", color => 'black/cyan yellow/cyan', ), }); if (!$bootloader->{message} || $bootloader->{message} eq "1") { 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 20% of 8bits chars $msg = $msg_en if int(grep { $_ & 0x80 } unpack "c*", $msg) / length($msg) > 0.2; $bootloader->{message} = $msg; } 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($bootloader, 'console' => $s); any::set_login_serial_console($port, $speed); } #- add a restore entry if installation is done from disk, in order to allow redoing it. if (my $hd_install_path = any::hdInstallPath()) { my ($cmdline, $vga); if ($::restore && -e "/tmp/image/boot/vmlinuz" && -e "/tmp/image/boot/all.rdz" && ($cmdline = cat_("/tmp/image/boot/grub/menu.lst") =~ m|kernel \S+/boot/vmlinuz (.*)$|m)) { #- cmdline should'n have any reference to vga=... $cmdline =~ s/vga=(\S+)//g and $vga = $1; log::l("copying kernel and stage1 install to $::prefix/boot/restore"); eval { mkdir "$::prefix/boot/restore"; cp_af("/tmp/image/boot/vmlinuz", "$::prefix/boot/restore/vmlinuz"); cp_af("/tmp/image/boot/all.rdz", "$::prefix/boot/restore/all.rdz") }; unless ($@) { log::l("adding a restore bootloader entry on $hd_install_path (remapped to $::prefix/boot/restore)"); add_entry($bootloader, { type => 'image', label => 'restore', kernel_or_dev => "/boot/restore/vmlinuz", initrd => "/boot/restore/all.rdz", append => "$cmdline recovery", #- the restore entry is a recovery entry if_($vga, vga => $vga), }); } } else { log::l("no restore bootloader need to be used on $hd_install_path"); } } my @kernels = get_kernels_and_labels() or die "no kernel installed"; foreach my $kernel (@kernels) { add_kernel($bootloader, $kernel, 0, { root => $root, if_($options{vga_fb} && $kernel->{ext} eq '', vga => $options{vga_fb}), #- using framebuffer if_($options{vga_fb} && $options{quiet}, append => "splash=silent"), }); if ($options{vga_fb} && $kernel->{ext} eq '') { add_kernel($bootloader, $kernel, 0, { root => $root, label => 'linux-nonfb' }); } } #- remove existing libsafe, don't care if the previous one was modified by the user? @{$bootloader->{entries}} = grep { $_->{label} ne 'failsafe' } @{$bootloader->{entries}}; add_kernel($bootloader, $kernels[0], 0, { root => $root, label => 'failsafe', append => 'devfs=nomount failsafe' }); if (arch() =~ /ppc/) { #- if we identified a MacOS partition earlier - add it if (defined $partition_table::mac::macos_part) { add_entry($bootloader, { label => "macos", kernel_or_dev => $partition_table::mac::macos_part }); } } elsif (arch() !~ /ia64/) { #- search for dos (or windows) boot partition. Don't look in extended partitions! my @windows_boot_parts = grep { isFat_or_NTFS($_) && isFat_or_NTFS({ type => fsedit::typeOfPart($_->{device}) }) } map { @{$_->{primary}{normal}} } @$hds; each_index { add_entry($bootloader, { type => 'other', kernel_or_dev => "/dev/$_->{device}", label => 'windows' . ($::i || ''), table => "/dev/$_->{rootDevice}" }); } @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($fstab)); } sub detect_main_method { my ($fstab) = @_; my $bootloader = &read($fstab); $bootloader && main_method($bootloader->{method}); } sub main_method { my ($method) = @_; $method =~ /(\w+)/ && $1; } sub method2text { my ($method) = @_; +{ 'lilo-graphic' => N("LILO with graphical menu"), 'lilo-menu' => N("LILO with text menu"), 'grub' => N("Grub"), 'yaboot' => N("Yaboot"), }->{$method}; } sub method_choices_raw() { arch() =~ /ppc/ ? 'yaboot' : ( if_(whereis_binary('lilo'), 'lilo-graphic', 'lilo-menu'), if_(whereis_binary('grub'), 'grub'), ); } sub method_choices { my ($fstab) = @_; grep { !(/lilo/ && isLoopback(fsedit::get_root($fstab))) && !(/lilo-graphic/ && detect_devices::matching_desc('ProSavageDDR')) && !(/grub/ && isRAID(fsedit::get_root($fstab))); } method_choices_raw(); } 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, { type => 'other', kernel_or_dev => '/dev/fd0', label => 'floppy', unsafe => 1 }); } 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 has_profiles { my ($b) = @_; to_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 ($unix_dev) = @_; my $of_dev; run_program::rooted_or_die($::prefix, "/usr/sbin/ofpath", ">", \$of_dev, $unix_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 install_yaboot { my ($bootloader, $_hds) = @_; $bootloader->{prompt} = $bootloader->{timeout}; if ($bootloader->{message}) { eval { output("$::prefix/boot/message", $bootloader->{message}) } or $bootloader->{message} = 0; } { my @conf; push @conf, "#yaboot.conf - generated by DrakX"; push @conf, qq(init-message="\\n$bootloader->{'init-message'}\\n") if $bootloader->{'init-message'}; if ($bootloader->{boot}) { push @conf, "boot=$bootloader->{boot}"; push @conf, "ofboot=", get_of_dev($bootloader->{boot}) } else { die "no bootstrap partition defined." } push @conf, map { "$_=$bootloader->{$_}" } grep { $bootloader->{$_} } qw(delay timeout defaultos default); push @conf, "install=/usr/lib/yaboot/yaboot"; push @conf, "magicboot=/usr/lib/yaboot/ofboot"; push @conf, grep { $bootloader->{$_} } qw(enablecdboot enableofboot); #- push @conf, "nonvram"; my $boot = "/dev/" . $bootloader->{useboot} if $bootloader->{useboot}; foreach (@{$bootloader->{entries}}) { if ($_->{type} eq "image") { my $of_dev = ''; if ($boot !~ /$_->{root}/ && $boot) { $of_dev = get_of_dev($boot); push @conf, "$_->{type}=$of_dev," . substr($_->{kernel_or_dev}, 5); } else { $of_dev = get_of_dev($_->{root}); push @conf, "$_->{type}=$of_dev,$_->{kernel_or_dev}"; } push @conf, "\tlabel=", make_label_lilo_compatible($_->{label}); push @conf, "\troot=$_->{root}"; if ($boot !~ /$_->{root}/ && $boot) { push @conf, "\tinitrd=$of_dev," . substr($_->{initrd}, 5) if $_->{initrd}; } else { push @conf, "\tinitrd=$of_dev,$_->{initrd}" if $_->{initrd}; } #- xfs module on PPC requires larger initrd - say 6MB? push @conf, "\tinitrd-size=6144" if $bootloader->{xfsroot}; push @conf, qq(\tappend=" $_->{append}") if $_->{append}; push @conf, "\tread-write" if $_->{'read-write'}; push @conf, "\tread-only" if !$_->{'read-write'}; } else { my $of_dev = get_of_dev($_->{kernel_or_dev}); push @conf, "$_->{label}=$of_dev"; } } my $f = "$::prefix/etc/yaboot.conf"; log::l("writing yaboot config to $f"); output($f, map { "$_\n" } @conf); } log::l("Installing boot loader..."); my $f = "$::prefix/tmp/of_boot_dev"; my $of_dev = get_of_dev($bootloader->{boot}); output($f, "$of_dev\n"); $::testing and return; if (defined $install_steps_interactive::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 make_label_lilo_compatible { my ($label) = @_; $label = substr($label, 0, 31); #- lilo doesn't handle more than 31 char long labels $label =~ s/ /_/g; #- lilo does not support blank character in image names, labels or aliases qq("$label"); } sub write_lilo_conf { my ($bootloader, $hds) = @_; $bootloader->{prompt} = $bootloader->{timeout}; my $file2fullname = sub { my ($file) = @_; if (arch() =~ /ia64/) { my $fstab = [ fsedit::get_fstab(@$hds) ];