package any; # $Id$
use diagnostics;
use strict;
#-######################################################################################
#- misc imports
#-######################################################################################
use common;
use detect_devices;
use partition_table;
use fs::type;
use lang;
use run_program;
use devices;
use modules;
use log;
use fs;
use c;
sub facesdir() {
"$::prefix/usr/share/mdk/faces/";
}
sub face2png {
my ($face) = @_;
facesdir() . $face . ".png";
}
sub facesnames() {
my $dir = facesdir();
my @l = grep { /^[A-Z]/ } all($dir);
map { if_(/(.*)\.png/, $1) } (@l ? @l : all($dir));
}
sub addKdmIcon {
my ($user, $icon) = @_;
my $dest = "$::prefix/usr/share/faces/$user.png";
eval { cp_af(facesdir() . $icon . ".png", $dest) } if $icon;
}
sub alloc_user_faces {
my ($users) = @_;
my @m = my @l = facesnames();
foreach (grep { !$_->{icon} || $_->{icon} eq "automagic" } @$users) {
$_->{auto_icon} = splice(@m, rand(@m), 1); #- known biased (see cookbook for better)
log::l("auto_icon is $_->{auto_icon}");
@m = @l unless @m;
}
}
sub create_user {
my ($u, $isMD5) = @_;
my @existing = stat("$::prefix/home/$u->{name}");
if (!getpwnam($u->{name})) {
my $uid = $u->{uid} || $existing[4];
if ($uid && getpwuid($uid)) {
undef $uid; #- suggested uid already in use
}
my $gid = $u->{gid} || $existing[5] || int getgrnam($u->{name});
if ($gid) {
if (getgrgid($gid)) {
undef $gid if getgrgid($gid) ne $u->{name};
} else {
run_program::rooted($::prefix, 'groupadd', '-g', $gid, $u->{name});
}
}
require authentication;
run_program::raw({ root => $::prefix, sensitive_arguments => 1 },
'adduser',
'-p', authentication::user_crypted_passwd($u, $isMD5),
if_($uid, '-u', $uid), if_($gid, '-g', $gid),
if_($u->{realname}, '-c', $u->{realname}),
if_($u->{home}, '-d', $u->{home}),
if_($u->{shell}, '-s', $u->{shell}),
$u->{name});
}
my (undef, undef, $uid, $gid, undef, undef, undef, $home) = getpwnam($u->{name});
if (@existing && $::isInstall && ($uid != $existing[4] || $gid != $existing[5])) {
log::l("chown'ing $home from $existing[4].$existing[5] to $uid.$gid");
require commands;
eval { commands::chown_("-r", "$uid.$gid", "$::prefix$home") };
}
}
sub add_users {
my ($users, $authentication) = @_;
alloc_user_faces($users);
foreach (@$users) {
create_user($_, $authentication->{md5});
run_program::rooted($::prefix, "usermod", "-G", join(",", @{$_->{groups}}), $_->{name}) if !is_empty_array_ref($_->{groups});
addKdmIcon($_->{name}, delete $_->{auto_icon} || $_->{icon});
}
}
sub hdInstallPath() {
my $tail = first(readlink("/tmp/image") =~ m|^(?:/tmp/)?hdimage/*(.*)|);
my $head = first(readlink("/tmp/hdimage") =~ m|$::prefix(.*)|);
log::l("search HD install path, tail=$tail, head=$head, tail defined=" . to_bool(defined $tail));
defined $tail && ($head ? "$head/$tail" : "/mnt/hd/$tail");
}
sub install_acpi_pkgs {
my ($do_pkgs, $b) = @_;
my $acpi = bootloader::get_append_with_key($b, 'acpi');
if (!member($acpi, 'off', 'ht')) {
$do_pkgs->install('acpi', 'acpid') if !(-x "$::prefix/usr/bin/acpi" && -x "$::prefix/usr/sbin/acpid");
}
}
sub setupBootloader {
my ($in, $b, $all_hds, $fstab, $security) = @_;
require bootloader;
general:
{
local $::Wizard_no_previous = 1 if $::isStandalone;
setupBootloader__general($in, $b, $all_hds, $fstab, $security) or return 0;
}
setupBootloader__boot_bios_drive($in, $b, $all_hds->{hds}) or goto general;
{
local $::Wizard_finished = 1 if $::isStandalone;
setupBootloader__entries($in, $b, $all_hds, $fstab) or goto general;
}
1;
}
sub installBootloader {
my ($in, $b, $all_hds) = @_;
return if detect_devices::is_xbox();
install_acpi_pkgs($in->do_pkgs, $b);
eval { run_program::rooted($::prefix, 'echo | lilo -u') } if $::isInstall && !$::o->{isUpgrade} && -e "$::prefix/etc/lilo.conf" && glob("$::prefix/boot/boot.*");
retry:
eval {
my $_w = $in->wait_message(N("Please wait"), N("Bootloader installation in progress"));
bootloader::install($b, $all_hds);
};
if (my $err = $@) {
$err =~ /wizcancel/ and return;
$err =~ s/^\w+ failed// or die;
$err = formatError($err);
while ($err =~ s/^Warning:.*//m) {}
if (my ($dev) = $err =~ /^Reference:\s+disk\s+"(.*?)".*^Is the above disk an NT boot disk?/ms) {
if ($in->ask_yesorno('',
formatAlaTeX(N("LILO wants to assign a new Volume ID to drive %s. However, changing
the Volume ID of a Windows NT, 2000, or XP boot disk is a fatal Windows error.
This caution does not apply to Windows 95 or 98, or to NT data disks.
Assign a new Volume ID?", $dev)))) {
$b->{force_lilo_answer} = 'n';
} else {
$b->{'static-bios-codes'} = 1;
}
goto retry;
} else {
$in->ask_warn('', [ N("Installation of bootloader failed. The following error occurred:"), $err ]);
return;
}
} elsif (arch() =~ /ppc/) {
if (detect_devices::get_mac_model() !~ /IBM/) {
my $of_boot = bootloader::dev2yaboot($b->{boot});
$in->ask_warn('', N("You may need to change your Open Firmware boot-device to\n enable the bootloader. If you do not see the bootloader prompt at\n reboot, hold down Command-Option-O-F at reboot and enter:\n setenv boot-device %s,\\\\:tbxi\n Then type: shut-down\nAt your next boot you should see the bootloader prompt.", $of_boot));
}
}
1;
}
sub setupBootloader_simple {
my ($in, $b, $all_hds, $fstab, $security) = @_;
my $hds = $all_hds->{hds};
require bootloader;
my $mixed_kind_of_disks = bootloader::mixed_kind_of_disks($hds);
#- full expert questions when there is 2 kind of disks
#- it would need a semi_auto asking on which drive the bios boots...
$mixed_kind_of_disks || $b->{bootUnsafe} || arch() =~ /ppc/ or return 1; #- default is good enough
if (!$mixed_kind_of_disks && arch() !~ /ia64/) {
setupBootloader__mbr_or_not($in, $b, $hds, $fstab) or return 0;
} else {
general:
setupBootloader__general($in, $b, $all_hds, $fstab, $security) or return 0;
}
setupBootloader__boot_bios_drive($in, $b, $hds) or goto general;
1;
}
sub setupBootloader__boot_bios_drive {
my ($in, $b, $hds) = @_;
bootloader::mixed_kind_of_disks($hds) &&
$b->{boot} =~ /\d$/ && #- on a partition
is_empty_hash_ref($b->{bios}) && #- some bios mapping already there
arch() !~ /ppc/ or return 1;
log::l("mixed_kind_of_disks");
my $hd = $in->ask_from_listf('', N("You decided to install the bootloader on a partition.
This implies you already have a bootloader on the hard drive you boot (eg: System Commander).
On which drive are you booting?"), \&partition_table::description, $hds) or return 0;
log::l("mixed_kind_of_disks chosen $hd->{device}");
$b->{first_hd_device} = "/dev/$hd->{device}";
1;
}
sub setupBootloader__mbr_or_not {
my ($in, $b, $hds, $fstab) = @_;
if (arch() =~ /ppc/) {
if (defined $partition_table::mac::bootstrap_part) {
$b->{boot} = $partition_table::mac::bootstrap_part;
log::l("set bootstrap to $b->{boot}");
} else {
die "no bootstrap partition - yaboot.conf creation failed";
}
} else {
my $floppy = detect_devices::floppy();
my @l = (
[ N("First sector of drive (MBR)") => '/dev/' . $hds->[0]{device} ],
[ N("First sector of the root partition") => '/dev/' . fs::get::root($fstab, 'boot')->{device} ],
if_($floppy,
[ N("On Floppy") => "/dev/$floppy" ],
),
[ N("Skip") => '' ],
);
my $default = find { $_->[1] eq $b->{boot} } @l;
$in->ask_from_({ title => N("LILO/grub Installation"),
messages => N("Where do you want to install the bootloader?"),
interactive_help_id => 'setupBootloaderBeginner',
},
[ { val => \$default, list => \@l, format => sub { $_[0][0] }, type => 'list' } ]);
my $new_boot = $default->[1] or return;
#- remove bios mapping if the user changed the boot device
delete $b->{bios} if $new_boot ne $b->{boot};
$b->{boot} = $new_boot;
}
1;
}
sub setupBootloader__general {
my ($in, $b, $all_hds, $fstab, $security) = @_;
return if detect_devices::is_xbox();
my @method_choices = bootloader::method_choices($all_hds);
my $prev_force_acpi = my $force_acpi = bootloader::get_append_with_key($b, 'acpi') !~ /off|ht/;
my $prev_force_noapic = my $force_noapic = bootloader::get_append_simple($b, 'noapic');
my $prev_force_nolapic = my $force_nolapic = bootloader::get_append_simple($b, 'nolapic');
my $memsize = bootloader::get_append_memsize($b);
my $prev_clean_tmp = my $clean_tmp = any { $_->{mntpoint} eq '/tmp' } @{$all_hds->{special} ||= []};
my $prev_boot = $b->{boot};
$b->{password2} ||= $b->{password} ||= '';
$::Wizard_title = N("Boot Style Configuration");
if (arch() !~ /ppc/) {
$in->ask_from_({ messages => N("Bootloader main options"),
title => N("Bootloader main options"),
icon => 'banner-bootL',
interactive_help_id => 'setupBootloader',
callbacks => {
complete => sub {
!$memsize || $memsize =~ /^\d+K$/ || $memsize =~ s/^(\d+)M?$/$1M/i or $in->ask_warn('', N("Give the ram size in MB")), return 1;
#- $security > 4 && length($b->{password}) < 6 and $in->ask_warn('', N("At this level of security, a password (and a good one) in lilo is requested")), return 1;
$b->{restricted} && !$b->{password} and $in->ask_warn('', N("Option ``Restrict command line options'' is of no use without a password")), return 1;
$b->{password} eq $b->{password2} or !$b->{restricted} or $in->ask_warn('', [ N("The passwords do not match"), N("Please try again") ]), return 1;
0;
},
},
}, [
{ label => N("Bootloader to use"), val => \$b->{method}, list => \@method_choices, format => \&bootloader::method2text },
if_(arch() !~ /ia64/,
{ label => N("Boot device"), val => \$b->{boot}, list => [ map { "/dev/$_->{device}" } bootloader::allowed_boot_parts($b, $all_hds) ], not_edit => !$::expert },
),
{ label => N("Delay before booting default image"), val => \$b->{timeout} },
{ text => N("Enable ACPI"), val => \$force_acpi, type => 'bool' },
if_(!$force_nolapic,
{ text => N("Force no APIC"), val => \$force_noapic, type => 'bool' },
),
{ text => N("Force No Local APIC"), val => \$force_nolapic, type => 'bool' },
if_($security >= 4 || $b->{password} || $b->{restricted},
{ label => N("Password"), val => \$b->{password}, hidden => 1 },
{ label => N("Password (again)"), val => \$b->{password2}, hidden => 1 },
{ text => N("Restrict command line options"), val => \$b->{restricted}, type => "bool", text => N("restrict") },
),
{ text => N("Clean /tmp at each boot"), val => \$clean_tmp, type => 'bool', advanced => 1 },
{ label => N("Precise RAM size if needed (found %d MB)", availableRamMB()), val => \$memsize, advanced => 1 },
]) or return 0;
} else {
$b->{boot} = $partition_table::mac::bootstrap_part;
$in->ask_from_({ messages => N("Bootloader main options"),
title => N("Bootloader main options"),
icon => 'banner-bootL',
interactive_help_id => 'setupYabootGeneral',
}, [
{ label => N("Bootloader to use"), val => \$b->{method}, list => \@method_choices, format => \&bootloader::method2text },
{ label => N("Init Message"), val => \$b->{'init-message'} },
{ label => N("Boot device"), val => \$b->{boot}, list => [ map { "/dev/$_" } (map { $_->{device} } (grep { isAppleBootstrap($_) } @$fstab)) ], not_edit => !$::expert },
{ label => N("Open Firmware Delay"), val => \$b->{delay} },
{ label => N("Kernel Boot Timeout"), val => \$b->{timeout} },
{ label => N("Enable CD Boot?"), val => \$b->{enablecdboot}, type => "bool" },
{ label => N("Enable OF Boot?"), val => \$b->{enableofboot}, type => "bool" },
{ label => N("Default OS?"), val => \$b->{defaultos}, list => [ 'linux', 'macos', 'macosx', 'darwin' ] },
]) or return 0;
}
#- remove bios mapping if the user changed the boot device
delete $b->{bios} if $b->{boot} ne $prev_boot;
if ($b->{boot} =~ m!/dev/md\d+$!) {
$b->{'raid-extra-boot'} = 'mbr';
} else {
delete $b->{'raid-extra-boot'} if $b->{'raid-extra-boot'} eq 'mbr';
}
if ($b->{method} eq 'grub') {
$in->do_pkgs->ensure_binary_is_installed('grub', "grub", 1) or return 0;
}
bootloader::suggest_message_text($b) if ! -e "$::prefix/boot/message-text"; #- in case we switch from grub to lilo
bootloader::set_append_memsize($b, $memsize);
if ($prev_force_acpi != $force_acpi) {
bootloader::set_append_with_key($b, acpi => ($force_acpi ? '' : 'ht'));
}
if ($prev_force_noapic != $force_noapic) {
($force_noapic ? \&bootloader::set_append_simple : \&bootloader::remove_append_simple)->($b, 'noapic');
}
if ($prev_force_nolapic != $force_nolapic) {
($force_nolapic ? \&bootloader::set_append_simple : \&bootloader::remove_append_simple)->($b, 'nolapic');
}
if ($prev_clean_tmp != $clean_tmp) {
if ($clean_tmp && !fs::get::has_mntpoint('/tmp', $all_hds)) {
push @{$all_hds->{special}}, { device => 'none', mntpoint => '/tmp', fs_type => 'tmpfs' };
} else {
@{$all_hds->{special}} = grep { $_->{mntpoint} ne '/tmp' } @{$all_hds->{special}};
}
}
1;
}
sub setupBootloader__entries {
my ($in, $b, $_all_hds, $fstab) = @_;
require Xconfig::resolution_and_depth;
my $Modify = sub {
require network::network; #- to list network profiles
my ($e) = @_;
my $default = my $old_default = $e->{label} eq $b->{default};
my $vga = Xconfig::resolution_and_depth::from_bios($e->{vga});
my ($append, $netprofile) = bootloader::get_append_netprofile($e);
my @l;
if ($e->{type} eq "image") {
@l = (
{ label => N("Image"), val => \$e->{kernel_or_dev}, list => [ map { "/boot/$_" } bootloader::installed_vmlinuz() ], not_edit => 0 },
{ label => N("Root"), val => \$e->{root}, list => [ map { "/dev/$_->{device}" } @$fstab ], not_edit => !$::expert },
{ label => N("Append"), val => \$append },
if_(arch() !~ /ppc|ia64/,
{ label => N("Video mode"), val => \$vga, list => [ '', Xconfig::resolution_and_depth::bios_vga_modes() ], format => \&Xconfig::resolution_and_depth::to_string, advanced => 1 },
),
{ label => N("Initrd"), val => \$e->{initrd}, list => [ map { if_(/^initrd/, "/boot/$_") } all("$::prefix/boot") ], not_edit => 0, advanced => 1 },
{ label => N("Network profile"), val => \$netprofile, list => [ sort(uniq('', $netprofile, network::network::netprofile_list())) ], advanced => 1 },
);
} else {
@l = (
{ label => N("Root"), val => \$e->{kernel_or_dev}, list => [ map { "/dev/$_->{device}" } @$fstab, detect_devices::floppies() ], not_edit => !$::expert },
);
}
if (arch() !~ /ppc/) {
@l = (
{ label => N("Label"), val => \$e->{label} },
@l,
{ text => N("Default"), val => \$default, type => 'bool' },
);
} else {
unshift @l, { label => N("Label"), val => \$e->{label}, list => ['macos', 'macosx', 'darwin'] };
if ($e->{type} eq "image") {
@l = ({ label => N("Label"), val => \$e->{label} },
$::expert ? @l[1..4] : (@l[1..2], { label => N("Append"), val => \$append }),
if_($::expert, { label => N("Initrd-size"), val => \$e->{initrdsize}, list => [ '', '4096', '8192', '16384', '24576' ] }),
if_($::expert, $l[5]),
{ label => N("NoVideo"), val => \$e->{novideo}, type => 'bool' },
{ text => N("Default"), val => \$default, type => 'bool' }
);
}
}
$in->ask_from_(
{
interactive_help_id => arch() =~ /ppc/ ? 'setupYabootAddEntry' : 'setupBootloaderAddEntry',
callbacks => {
complete => sub {
$e->{label} or $in->ask_warn('', N("Empty label not allowed")), return 1;
$e->{kernel_or_dev} or $in->ask_warn('', $e->{type} eq 'image' ? N("You must specify a kernel image") : N("You must specify a root partition")), return 1;
member(lc $e->{label}, map { lc $_->{label} } grep { $_ != $e } @{$b->{entries}}) and $in->ask_warn('', N("This label is already used")), return 1;
0;
} } }, \@l) or return;
$b->{default} = $old_default || $default ? $default && $e->{label} : $b->{default};
$e->{vga} = ref($vga) ? $vga->{bios} : $vga;
bootloader::set_append_netprofile($e, $append, $netprofile);
bootloader::configure_entry($e); #- hack to make sure initrd file are built.
1;
};
my $Add = sub {
my @labels = map { $_->{label} } @{$b->{entries}};
my ($e, $prefix);
if ($in->ask_from_list_('', N("Which type of entry do you want to add?"),
[ N_("Linux"), arch() =~ /sparc/ ? N_("Other OS (SunOS...)") : arch() =~ /ppc/ ?
N_("Other OS (MacOS...)") : N_("Other OS (Windows...)") ]
) eq "Linux") {
$e = { type => 'image',
root => '/dev/' . fs::get::root($fstab)->{device}, #- assume a good default.
};
$prefix = "linux";
} else {
$e = { type => 'other' };
$prefix = arch() =~ /sparc/ ? "sunos" : arch() =~ /ppc/ ? "macos" : "windows";
}
$e->{label} = $prefix;
for (my $nb = 0; member($e->{label}, @labels); $nb++) {
$e->{label} = "$prefix-$nb";
}
$Modify->($e) or return;
bootloader::add_entry($b, $e);
$e;
};
my $Remove = sub {
my ($e) = @_;
delete $b->{default} if $b->{default} eq $e->{label};
@{$b->{entries}} = grep { $_ != $e } @{$b->{entries}};
1;
};
my @prev_entries = @{$b->{entries}};
if ($in->ask_from__add_modify_remove('',
N("Here are the entries on your boot menu so far.
You can create additional entries or change the existing ones."), [ {
format => sub {
my ($e) = @_;
ref($e) ?
"$e->{label} ($e->{kernel_or_dev})" . ($b->{default} eq $e->{label} && " *") :
translate($e);
}, list => $b->{entries},
} ], Add => $Add, Modify => $Modify, Remove => $Remove)) {
1;
} else {
@{$b->{entries}} = @prev_entries;
'';
}
}
sub get_autologin() {
my %desktop = getVarsFromSh("$::prefix/etc/sysconfig/desktop");
my $desktop = $desktop{DESKTOP} || 'KDE';
my $autologin = do {
if (($desktop{DISPLAYMANAGER} || $desktop) eq 'GNOME') {
my %conf = read_gnomekderc("$::prefix/etc/X11/gdm/gdm.conf", 'daemon');
text2bool($conf{AutomaticLoginEnable}) && $conf{AutomaticLogin};
} else { # KDM / MdkKDM
my %conf = read_gnomekderc("$::prefix/usr/share/config/kdm/kdmrc", 'X-:0-Core');
text2bool($conf{AutoLoginEnable}) && $conf{AutoLoginUser};
}
};
{ autologin => $autologin, desktop => $desktop };
}
sub set_autologin {
my ($o_user, $o_wm) = @_;
log::l("set_autologin $o_user $o_wm");
my $autologin = bool2text($o_user);
#- Configure KDM / MDKKDM
eval { update_gnomekderc("$::prefix/usr/share/config/kdm/kdmrc", 'X-:0-Core' => (
AutoLoginEnable => $autologin,
AutoLoginUser => $o_user,
)) };
#- Configure GDM
eval { update_gnomekderc("$::prefix/etc/X11/gdm/gdm.conf", daemon => (
AutomaticLoginEnable => $autologin,
AutomaticLogin => $o_user,
)) };
my $xdm_autologin_cfg = "$::prefix/etc/sysconfig/autologin";
if (member($o_wm, 'KDE', 'GNOME')) {
unlink $xdm_autologin_cfg;
} else {
setVarsInShMode($xdm_autologin_cfg, 0644,
{ USER => $o_user, AUTOLOGIN => bool2yesno($o_user), EXEC => '/usr/X11R6/bin/startx.autologin' });
}
if ($o_user) {
my $home = (getpwnam($o_user))[7];
set_window_manager($home, $o_wm);
}
}
sub set_window_manager {
my ($home, $wm) = @_;
log::l("set_window_manager $home $wm");
my $p_home = "$::prefix$home";
#- for KDM/GDM
my $wm_number = sessions_with_order()->{$wm} || '';
update_gnomekderc("$p_home/.dmrc", 'Desktop', Session => "$wm_number$wm");
my $user = find { $home eq $_->[7] } list_passwd();
chown($user->[2], $user->[3], "$p_home/.dmrc");
#- for startx/autologin
{
my %l = getVarsFromSh("$p_home/.desktop");
$l{DESKTOP} = $wm;
setVarsInSh("$p_home/.desktop", \%l);
}
}
sub rotate_log {
my ($f) = @_;
if (-e $f) {
my $i = 1;
for (; -e "$f$i" || -e "$f$i.gz"; $i++) {}
rename $f, "$f$i";
}
}
sub rotate_logs {
my ($prefix) = @_;
rotate_log("$prefix/root/drakx/$_") foreach qw(ddebug.log install.log);
}
sub writeandclean_ldsoconf {
my ($prefix) = @_;
my $file = "$prefix/etc/ld.so.conf";
my @l = chomp_(cat_($file));
my @default = ('/lib', '/usr/lib'); #- no need to have /lib and /usr/lib in ld.so.conf
my @suggest = ('/usr/X11R6/lib', '/usr/lib/qt3/lib'); #- needed for upgrade where package renaming can cause this to disappear
if (arch() =~ /x86_64/) {
@default = map { $_, $_ . '64' } @default;
@suggest = map { $_, $_ . '64' } @suggest;
}
push @l, grep { -d "$::prefix$_" } @suggest;
@l = difference2(\@l, \@default);
log::l("writeandclean_ldsoconf");
output($file, map { "$_\n" } uniq(@l));
}
sub shells() {
grep { -x "$::prefix$_" } chomp_(cat_("$::prefix/etc/shells"));
}
sub inspect {
my ($part, $o_prefix, $b_rw) = @_;
isMountableRW($part) || !$b_rw && isOtherAvailableFS($part) or return;
my $dir = $::isInstall ? "/tmp/inspect_tmp_dir" : "/root/.inspect_tmp_dir";
if ($part->{isMounted}) {
$dir = ($o_prefix || '') . $part->{mntpoint};
} elsif ($part->{notFormatted} && !$part->{isFormatted}) {
$dir = '';
} else {
mkdir $dir, 0700;
eval { fs::mount::mount(fs::wild_device::from_part('', $part), $dir, $part->{fs_type}, !$b_rw) };
$@ and return;
}
my $h = before_leaving {
if (!$part->{isMounted} && $dir) {
fs::mount::umount($dir);
unlink($dir);
}
};
$h->{dir} = $dir;
$h;
}
sub ask_user_one {
my ($in, $users, $security, $u, %options) = @_;
my @icons = facesnames();
my %high_security_groups = (
xgrp => N("access to X programs"),
rpm => N("access to rpm tools"),
wheel => N("allow \"su\""),
adm => N("access to administrative files"),
ntools => N("access to network tools"),
ctools => N("access to compilation tools"),
);
$u->{password2} ||= $u->{password} ||= '';
$u->{shell} ||= '/bin/bash';
my $names = @$users ? N("(already added %s)", join(", ", map { $_->{realname} || $_->{name} } @$users)) : '';
my %groups;
my $verif = sub {
$u->{password} eq $u->{password2} or $in->ask_warn('', [ N("The passwords do not match"), N("Please try again") ]), return 1,2;
$security > 3 && length($u->{password}) < 6 and $in->ask_warn('', N("This password is too simple")), return 1,2;
$u->{name} or $in->ask_warn('', N("Please give a user name")), return 1,0;
$u->{name} =~ /^[a-z]+?[a-z0-9_-]*?$/ or $in->ask_warn('', N("The user name must contain only lower cased letters, numbers, `-' and `_'")), return 1,0;
length($u->{name}) <= 32 or $in->ask_warn('', N("The user name is too long")), return 1,0;
member($u->{name}, 'root', map { $_->{name} } @$users) and $in->ask_warn('', N("This user name has already been added")), return 1,0;
foreach ([ $u->{uid}, N("User ID") ],
[ $u->{gid}, N("Group ID") ]) {
my ($id, $name) = @$_;
$id or next;
$id =~ /^\d+$/ or $in->ask_warn('', N("%s must be a number", $name)), return 1;
$id >= 500 or $in->ask_yesorno('', N("%s should be above 500. Accept anyway?", $name)) or return 1;
}
return 0;
};
my $ret = $in->ask_from_(
{ title => N("Add user"),
icon => 'banner-adduser',
messages => N("Enter a user\n%s", $options{additional_msg} || $names),
interactive_help_id => 'addUser',
focus_first => 1,
if_(!$::isInstall, ok => N("Done")),
cancel => $options{noaccept} ? '' : N("Accept user"),
callbacks => {
focus_out => sub {
if ($_[0] eq '0') {
$u->{name} ||= lc first($u->{realname} =~ /([a-zA-Z0-9_-]+)/);
}
},
complete => sub { $u->{name} ? &$verif : 0 },
canceled => $verif,
ok_disabled => sub { $security >= 4 && !@$users || $options{needauser} && !$u->{name} },
} }, [
{ label => N("Real name"), val => \$u->{realname} },
{ label => N("Login name"), val => \$u->{name} },
{ label => N("Password"),val => \$u->{password}, hidden => 1 },
{ label => N("Password (again)"), val => \$u->{password2}, hidden => 1 },
{ label => N("Shell"), val => \$u->{shell}, list => [ shells() ], not_edit => !$::expert, advanced => 1 },
{ label => N("User ID"), val => \$u->{uid}, advanced => 1 },
{ label => N("Group ID"), val => \$u->{gid}, advanced => 1 },
if_($security <= 3 && !$options{noicons} && @icons,
{ label => N("Icon"), val => \ ($u->{icon} ||= 'default'), list => \@icons, icon2f => \&face2png, format => \&translate },
),
if_($security > 3,
map {
{ label => $_, val => \$groups{$_}, text => $high_security_groups{$_}, type => 'bool' };
} keys %high_security_groups,
),
],
);
$u->{groups} = [ grep { $groups{$_} } keys %groups ];
push @$users, $u if $u->{name};
return $ret;
}
sub ask_users {
my ($in, $users, $security, $suggested_names) = @_;
while (1) {
my $u = {};
$u->{name} = shift @$suggested_names;
ask_user_one($in, $users, $security, $u) and return;
}
}
sub sessions() {
split(' ', run_program::rooted_get_stdout($::prefix, '/usr/sbin/chksession', '-l'));
}
sub sessions_with_order() {
my %h = map { /(.*)=(.*)/ } split(' ', run_program::rooted_get_stdout($::prefix, '/usr/sbin/chksession', '-L'));
\%h;
}
sub autologin {
my ($o, $in) = @_;
my @wm = sessions();
my @users = map { $_->{name} } @{$o->{users} || []};
if (member('KDE', @wm) && @users == 1 && $o->{meta_class} eq 'desktop') {
$o->{desktop} = 'KDE';
$o->{autologin} = $users[0];
} elsif (@wm > 1 && @users && !$o->{authentication}{NIS} && $o->{security} <= 2) {
my $use_autologin = @users == 1;
$in->ask_from_(
{ title => N("Autologin"),
messages => N("I can set up your computer to automatically log on one user.") },
[ { text => N("Use this feature"), val => \$use_autologin, type => 'bool' },
{ label => N("Choose the default user:"), val => \$o->{autologin}, list => \@users, disabled => sub { !$use_autologin } },
{ label => N("Choose the window manager to run:"), val => \$o->{desktop}, list => \@wm, disabled => sub { !$use_autologin } } ]
);
delete $o->{autologin} if !$use_autologin;
} else {
delete $o->{autologin};
}
}
sub selectLanguage_install {
my ($in, $locale) = @_;
my $common = { messages => N("Please choose a language to use."),
title => N("Language choice"),
icon => 'banner-languages.png',
interactive_help_id => 'selectLanguage' };
my $lang = $locale->{lang};
my $langs = $locale->{langs} ||= {};
my $using_images = $in->isa('interactive::gtk') && !$::o->{vga16};
my %name2l = map { lang::l2name($_) => $_ } lang::list_langs();
my $listval2val = sub { $_[0] =~ /\|(.*)/ ? $1 : $_[0] };
#- since gtk version will use images (function image2f) we need to sort differently
my $sort_func = $using_images ? \&lang::l2transliterated : \&lang::l2name;
my @langs = sort { $sort_func->($a) cmp $sort_func->($b) } lang::list_langs();
if (@langs > 15) {
my $add_location = sub {
my ($l) = @_;
map { "$_|$l" } lang::l2location($l);
};
@langs = map { $add_location->($_) } @langs;
#- to create the default value, use the first location for that value :/
$lang = first($add_location->($lang));
}
my $last_utf8 = $locale->{utf8};
add2hash($common, { cancel => '',
advanced_messages => formatAlaTeX(N("Mandriva Linux can support multiple languages. Select
the languages you would like to install. They will be available
when your installation is complete and you restart your system.")),
advanced_label => N("Multi languages"),
callbacks => { advanced => sub { $langs->{$listval2val->($lang)} = 1 },
changed => sub {
if ($last_utf8 == $locale->{utf8}) {
$last_utf8 = $locale->{utf8} = lang::utf8_should_be_needed({ lang => $listval2val->($lang), langs => $langs });
} else {
$last_utf8 = -1; #- disable auto utf8 once touched
}
} } });
$in->ask_from_($common, [
{ val => \$lang, separator => '|',
if_($using_images, image2f => sub { $name2l{$_[0]} =~ /^[a-z]/ && "langs/lang-$name2l{$_[0]}" }),
format => sub { $_[0] =~ /(.*\|)(.*)/ ? $1 . lang::l2name($2) : lang::l2name($_[0]) },
list => \@langs, sort => 0 },
if_(!$::move,
{ val => \$locale->{utf8}, type => 'bool', text => N("Use Unicode by default"), advanced => 1 },
{ val => \$langs->{all}, type => 'bool', text => N("All languages"), advanced => 1 },
map {
{ val => \$langs->{$_->[0]}, type => 'bool', disabled => sub { $langs->{all} },
text => $_->[1], advanced => 1,
image => "langs/lang-$_->[0]",
};
} sort { $a->[1] cmp $b->[1] } map { [ $_, $sort_func->($_) ] } lang::list_langs(),
),
]) or return;
%$langs = grep_each { $::b } %$langs; #- clean hash
$langs->{$listval2val->($lang)} = 1;
#- convert to the default locale for asked language
$locale->{lang} = $listval2val->($lang);
}
sub selectLanguage_standalone {
my ($in, $locale) = @_;
my $common = { messages => N("Please choose a language to use."),
title => N("Language choice"),
interactive_help_id => 'selectLanguage' };
my @langs = sort { lang::l2name($a) cmp lang::l2name($b) } lang::list_langs(exclude_non_installed => 1);
die 'one lang only' if @langs == 1;
$in->ask_from_($common, [
{ val => \$locale->{lang}, type => 'list',
format => sub { lang::l2name($_[0]) }, list => \@langs },
{ val => \$locale->{utf8}, type => 'bool', text => N("Use Unicode by default"), advanced => 1 },
]);
}
sub selectLanguage_and_more_standalone {
my ($in, $locale) = @_;
eval {
local $::isWizard = 1;
language:
# keep around previous settings so that selectLanguage can keep UTF-8 flag:
local $::Wizard_no_previous = 1;
my $old_lang = $locale->{lang};
selectLanguage_standalone($in, $locale);
$locale->{IM} = lang::get_default_im($locale->{lang}) if $old_lang ne $locale->{lang};
undef $::Wizard_no_previous;
selectCountry($in, $locale) or goto language;
};
if ($@) {
if ($@ =~ /^one lang only/) {
selectCountry($in, $locale) or $in->exit(0);
} elsif ($@ !~ /wizcancel/) {
die;
} else {
$in->exit(0);
}
}
}
sub selectCountry {
my ($in, $locale) = @_;
my $country = $locale->{country};
my @countries = lang::list_countries(exclude_non_installed => !$::isInstall);
my @best = uniq map {
my $h = lang::analyse_locale_name($_);
if_($h->{main} eq lang::locale_to_main_locale($locale->{lang}) && $h->{country},
$h->{country});
} @lang::locales;
@best == 1 and @best = ();
my ($other, $ext_country);
member($country, @best) or ($ext_country, $country) = ($country, $ext_country);
$in->ask_from_(
{ title => N("Country / Region"),
icon => 'banner-languages',
messages => N("Please choose your country."),
interactive_help_id => 'selectCountry',
if_(@best, advanced_messages => N("Here is the full list of available countries")),
advanced_label => @best ? N("Other Countries") : N("Advanced"),
advanced_state => $ext_country && scalar(@best),
callbacks => { changed => sub { $_[0] != 2 and $other = $_[0] == 1 } },
},
[ if_(@best, { val => \$country, type => 'list', format => \&lang::c2name,
list => \@best, sort => 1 }),
{ val => \$ext_country, type => 'list', format => \&lang::c2name,
list => [ @countries ], advanced => scalar(@best) },
{ val => \$locale->{IM}, type => 'combo', label => N("Input method:"),
sort => 0, separator => '|',
list => [ '', sort(lang::get_ims()) ],
format => sub { $_[0] ? uc($_[0] =~ /(.*)\+(.*)/ ? "$1|$1+$2" : $_[0]) : N("None") },
advanced => !$locale->{IM},
},
]) or return;
$locale->{country} = $other || !@best ? $ext_country : $country;
}
sub set_login_serial_console {
my ($port, $speed) = @_;
my $line = "s$port:12345:respawn:/sbin/getty ttyS$port DT$speed ansi\n";
substInFile { s/^s$port:.*//; $_ = $line if eof } "$::prefix/etc/inittab";
}
sub report_bug {
my (@other) = @_;
sub header { "
********************************************************************************
* $_[0]
********************************************************************************";
}
join '', map { chomp; "$_\n" }
header("lspci"), detect_devices::stringlist(),
header("pci_devices"), cat_("/proc/bus/pci/devices"),
header("dmidecode"), `dmidecode`,
header("fdisk"), arch() =~ /ppc/ ? `pdisk -l` : `fdisk -l`,
header("scsi"), cat_("/proc/scsi/scsi"),
header("/sys/bus/scsi/devices"), `ls -l /sys/bus/scsi/devices`,
header("lsmod"), cat_("/proc/modules"),
header("cmdline"), cat_("/proc/cmdline"),
header("pcmcia: stab"), cat_("$::prefix/var/lib/pcmcia/stab") || cat_("$::prefix/var/run/stab"),
header("usb"), cat_("/proc/bus/usb/devices"),
header("partitions"), cat_("/proc/partitions"),
header("cpuinfo"), cat_("/proc/cpuinfo"),
header("syslog"), cat_("/tmp/syslog") || cat_("$::prefix/var/log/syslog"),
header("monitor_full_edid"), monitor_full_edid(),
header("stage1.log"), cat_("/tmp/stage1.log") || cat_("$::prefix/root/drakx/stage1.log"),
header("ddebug.log"), cat_("/tmp/ddebug.log") || cat_("$::prefix/root/drakx/ddebug.log"),
header("install.log"), cat_("$::prefix/root/drakx/install.log"),
header("fstab"), cat_("$::prefix/etc/fstab"),
header("modules.conf"), cat_("$::prefix/etc/modules.conf"),
header("lilo.conf"), cat_("$::prefix/etc/lilo.conf"),
header("menu.lst"), cat_("$::prefix/boot/grub/menu.lst"),
header("XF86Config"), cat_("$::prefix/etc/X11/XF86Config"),
header("/etc/modules"), cat_("$::prefix/etc/modules"),
header("sysconfig/i18n"), cat_("$::prefix/etc/sysconfig/i18n"),
map_index { even($::i) ? header($_) : $_ } @other;
}
sub devfssymlinkf {
my ($if_struct, $of) = @_;
my $if = $if_struct->{device};
my $devfs_if = $if_struct->{devfs_device};
$devfs_if ||= devices::to_devfs($if);
$devfs_if ||= $if;
#- example: $of is mouse, $if is usbmouse, $devfs_if is input/mouse0
output_p("$::prefix/etc/devfs/conf.d/$of.conf",
"REGISTER ^$devfs_if\$ CFUNCTION GLOBAL mksymlink $devfs_if $of
UNREGISTER ^$devfs_if\$ CFUNCTION GLOBAL unlink $of
");
output_p("$::prefix/etc/devfs/conf.d/$if.conf",
"REGISTER ^$devfs_if\$ CFUNCTION GLOBAL mksymlink $devfs_if $if
UNREGISTER ^$devfs_if\$ CFUNCTION GLOBAL unlink $if
") if $devfs_if ne $if && $if !~ /^hd[a-z]/ && $if !~ /^sr/ && $if !~ /^sd[a-z]/;
#- add a specific udev script, we can't do it with a udev rule,
#- eg, ttySL0 is a symlink
output_with_perm("$::prefix/etc/udev/conf.d/$of.conf", 0755, "ln -sf $if /dev/$of\n")
if $of !~ /dvd|mouse/;
#- when creating a symlink on the system, use devfs name if devfs is mounted
symlinkf($devfs_if, "$::prefix/dev/$if") if $devfs_if ne $if && detect_devices::dev_is_devfs();
symlinkf($if, "$::prefix/dev/$of");
}
sub devfs_rawdevice {
my ($if_struct, $of) = @_;
my $devfs_if = $if_struct->{devfs_device};
$devfs_if ||= devices::to_devfs($if_struct->{device});
$devfs_if ||= $if_struct->{device};
output_p("$::prefix/etc/devfs/conf.d/$of.conf",
"REGISTER ^$devfs_if\$ EXECUTE /etc/dynamic/scripts/rawdevice.script add /dev/$devfs_if /dev/$of
UNREGISTER ^$devfs_if\$ EXECUTE /etc/dynamic/scripts/rawdevice.script del /dev/$of
");
}
sub fix_broken_alternatives {
my ($force_default) = @_;
#- fix bad update-alternatives that may occurs after upgrade (and sometimes for install too).
-d "$::prefix/etc/alternatives" or return;
foreach (all("$::prefix/etc/alternatives")) {
if ($force_default) {
log::l("setting alternative $_");
} else {
next if run_program::rooted($::prefix, 'test', '-e', "/etc/alternatives/$_");
log::l("fixing broken alternative $_");
}
run_program::rooted($::prefix, 'update-alternatives', '--auto', $_);
}
}
sub fileshare_config {
my ($in, $type) = @_; #- $type is 'nfs', 'smb' or ''
my $file = '/etc/security/fileshare.conf';
my %conf = getVarsFromSh($file);
my @l = (N_("No sharing"), N_("Allow all users"), N_("Custom"));
my $restrict = exists $conf{RESTRICT} ? text2bool($conf{RESTRICT}) : 1;
my $r = $in->ask_from_list_('fileshare',
N("Would you like to allow users to share some of their directories?
Allowing this will permit users to simply click on \"Share\" in konqueror and nautilus.
\"Custom\" permit a per-user granularity.
"),
\@l, $l[$restrict ? (getgrnam('fileshare') ? 2 : 0) : 1]) or return;
$restrict = $r ne $l[1];
my $custom = $r eq $l[2];
if ($r ne $l[0]) {
require services;
my %types = (
nfs => [ 'nfs-utils', 'nfs',
N("NFS: the traditional Unix file sharing system, with less support on Mac and Windows.")
],
smb => [ 'samba-server', 'smb',
N("SMB: a file sharing system used by Windows, Mac OS X and many modern Linux systems.")
],
);
my %l;
if ($type) {
%l = ($type => 1);
} else {
%l = map_each { $::a => services::starts_on_boot($::b->[1]) } %types;
$in->ask_from_({ messages => N("You can export using NFS or SMB. Please select which you would like to use."),
callbacks => { ok_disabled => sub { !any { $_ } values %l } },
},
[ map { { text => $types{$_}[2], val => \$l{$_}, type => 'bool' } } keys %l ]) or return;
}
foreach (keys %types) {
my ($pkg, $service, $_descr) = @{$types{$_}};
my $file = "/etc/init.d/$service";
if ($l{$_}) {
$in->do_pkgs->ensure_is_installed($pkg, $file) or return;
services::start($service);
services::start_service_on_boot($service);
} elsif (-e $file) {
services::stop($service);
services::do_not_start_service_on_boot($service);
}
}
}
$conf{RESTRICT} = bool2yesno($restrict);
setVarsInSh($file, \%conf);
if ($custom) {
run_program::rooted($::prefix, 'groupadd', '-r', 'fileshare');
if ($in->ask_from_no_check(
{
-e '/usr/sbin/userdrake' ? (ok => N("Launch userdrake"), cancel => N("Close")) : (cancel => ''),
messages =>
N("The per-user sharing uses the group \"fileshare\".
You can use userdrake to add a user to this group.")
}, [])) {
run_program::run('userdrake');
}
}
}
sub monitor_full_edid() {
return if $::noauto;
devices::make('zero');
my ($vbe, $edid);
run_program::raw({ timeout => 20 },
'monitor-edid', '>', \$edid, '2>', \$vbe,
'-v', '--perl', if_($::isStandalone, '--try-in-console'));
if ($::isInstall) {
foreach (['edid', \$edid], ['vbe', \$vbe]) {
my ($name, $val) = @$_;
if (-e "/tmp/$name") {
my $old = cat_("/tmp/$name");
if (length($$val) < length($old)) {
log::l("new $name is worse, keeping the previous one");
$$val = $old;
} elsif (length($$val) > length($old)) {
log::l("new $name is better, dropping the previous one");
}
}
output("/tmp/$name", $$val);
}
}
($edid, $vbe);
}
sub running_window_manager() {
my @window_managers = qw(kwin gnome-session icewm wmaker afterstep fvwm fvwm2 fvwm95 mwm twm enlightenment xfce blackbox sawfish olvwm fluxbox);
foreach (@window_managers) {
my @pids = fuzzy_pidofs(qr/\b$_\b/) or next;
return wantarray() ? ($_, @pids) : $_;
}
undef;
}
sub ask_window_manager_to_logout {
my ($wm) = @_;
my %h = (
'kwin' => "dcop kdesktop default logout",
'gnome-session' => "gnome-session-save --kill",
'icewm' => "killall -QUIT icewm",
);
my $cmd = $h{$wm} or return;
if ($wm eq 'gnome-session') {
#- NB: consolehelper does not destroy $HOME whereas kdesu does
#- for gnome, we use consolehelper, so below works
$ENV{ICEAUTHORITY} ||= "$ENV{HOME}/.ICEauthority";
} elsif ($wm eq 'kwin' && $> == 0) {
#- we can not use dcop when we are root
$cmd = "su $ENV{USER} -c '$cmd'";
}
system($cmd);
1;
}
sub ask_window_manager_to_logout_then_do {
my ($wm, $pid, $action) = @_;
if (fork()) {
ask_window_manager_to_logout($wm);
return;
}
open STDIN, "/dev/null";
open STDERR, ">&STDERR";
c::setsid();
exec 'perl', '-e', q(
my ($wm, $pid, $action) = @ARGV;
my $nb;
for ($nb = 30; $nb && -e "/proc/$pid"; $nb--) { sleep 1 }
system($action) if $nb;
), $wm, $pid, $action;
}
sub alloc_raw_device {
my ($prefix, $device) = @_;
my $used = 0;
my $raw_dev;
substInFile {
$used = max($used, $1) if m|^\s*/dev/raw/raw(\d+)|;
if (eof) {
$raw_dev = "raw/raw" . ($used + 1);
$_ .= "/dev/$raw_dev /dev/$device\n";
}
} "$prefix/etc/sysconfig/rawdevices";
$raw_dev;
}
sub config_dvd {
my ($prefix, $have_devfsd) = @_;
#- can not have both a devfs and a non-devfs config
#- the /etc/sysconfig/rawdevices solution gives errors with devfs
my @dvds = grep { detect_devices::isDvdDrive($_) } detect_devices::cdroms() or return;
log::l("configuring DVD: " . join(" ", map { $_->{device} } @dvds));
#- create /dev/dvd symlink
each_index {
devfssymlinkf($_, 'dvd' . ($::i ? $::i + 1 : ''));
devfs_rawdevice($_, 'rdvd' . ($::i ? $::i + 1 : '')) if $have_devfsd;
} @dvds;
if (!$have_devfsd) {
my $raw_dev = alloc_raw_device($prefix, 'dvd');
symlink($raw_dev, "$prefix/dev/rdvd");
}
}
sub config_mtools {
my ($prefix) = @_;
my $file = "$prefix/etc/mtools.conf";
-e $file or return;
my ($f1, $f2) = detect_devices::floppies_dev();
substInFile {
s|drive a: file="(.*?)"|drive a: file="/dev/$f1"|;
s|drive b: file="(.*?)"|drive b: file="/dev/$f2"| if $f2;
} $file;
}
1;
b">@_;
installStepsCall($o, $auto, 'selectInstallClass', $clicked);
if ($o->{isUpgrade}) {
$o->{keepConfiguration} and @{$o->{orderedSteps}} = grep { !/selectMouse|selectKeyboard|miscellaneous|setRootPassword|addUser|configureNetwork|installUpdates|summary|configureServices|configureX/ } @{$o->{orderedSteps}};
}
}
#------------------------------------------------------------------------------
sub doPartitionDisks {
my ($_clicked, $_ent_number, $auto) = @_;
$o->{steps}{formatPartitions}{done} = 0;
installStepsCall($o, $auto, 'doPartitionDisksBefore');
installStepsCall($o, $auto, 'doPartitionDisks');
installStepsCall($o, $auto, 'doPartitionDisksAfter');
}
sub formatPartitions {
my ($_clicked, $_ent_number, $auto) = @_;
$o->{steps}{choosePackages}{done} = 0;
installStepsCall($o, $auto, 'choosePartitionsToFormat', $o->{fstab}) if !$o->{isUpgrade};
my $want_root_formated = fs::get::root($o->{fstab})->{toFormat};
if ($want_root_formated) {
foreach ('/usr') {
my $part = fs::get::mntpoint2part($_, $o->{fstab}) or next;
$part->{toFormat} or die N("You must also format %s", $_);
}
}
installStepsCall($o, $auto, 'formatMountPartitions', $o->{fstab}) if !$::testing;
if ($want_root_formated) {
#- we formatted /, ensure /var/lib/rpm is cleaned otherwise bad things can happen
#- (especially when /var is *not* formatted)
eval { rm_rf("$o->{prefix}/var/lib/rpm") };
}
mkdir "$o->{prefix}/$_", 0755 foreach
qw(dev etc etc/profile.d etc/rpm etc/sysconfig etc/sysconfig/console
etc/sysconfig/network-scripts etc/sysconfig/console/consolefonts
etc/sysconfig/console/consoletrans
home mnt tmp var var/tmp var/lib var/lib/rpm var/lib/urpmi);
mkdir "$o->{prefix}/$_", 0700 foreach qw(root root/tmp root/drakx);
devices::make("$o->{prefix}/dev/null");
chmod 0666, "$o->{prefix}/dev/null";
eval { fs::mount('none', "$o->{prefix}/proc", 'proc') };
eval { fs::mount('none', "$o->{prefix}/proc/bus/usb", 'usbdevfs') };
eval { fs::mount('none', "$o->{prefix}/sys", 'sysfs') };
common::screenshot_dir__and_move();
any::rotate_logs($o->{prefix});
if (any { $_->{usb_media_type} && any { $_->{mntpoint} } partition_table::get_normal_parts($_) } @{$o->{all_hds}{hds}}) {
log::l("we use a usb-storage based drive, so keep it as a normal scsi_hostadapter");
} else {
log::l("we do not need usb-storage for booting system, rely on hotplug");
#- when usb-storage is in scsi_hostadapter,
#- hotplug + scsimon do not load sd_mod/sr_mod when needed
#- (eg: when plugging a usb key)
$o->{modules_conf}->remove_probeall('scsi_hostadapter', 'usb-storage');
}
require raid;
raid::prepare_prefixed($o->{all_hds}{raids});
#- needed by lilo
if (my @vgs = map { $_->{VG_name} } @{$o->{all_hds}{lvms}}) {
cp_af("/dev/$_", "$::prefix/dev") foreach 'mapper', @vgs;
}
}
#------------------------------------------------------------------------------
sub choosePackages {
my ($_clicked, $ent_number, $auto) = @_;
require pkgs;
#- always setPackages as it may have to copy hdlist and synthesis files.
installStepsCall($o, $auto, 'setPackages', $o->{isUpgrade} && $ent_number == 1);
installStepsCall($o, $auto, 'choosePackages', $o->{packages}, $o->{compssUsers}, $ent_number == 1);
my @flags = map_each { if_($::b, $::a) } %{$o->{rpmsrate_flags_chosen}};
log::l("rpmsrate_flags_chosen's: ", join(' ', sort @flags));
#- check pre-condition that basesystem package must be selected.
pkgs::packageByName($o->{packages}, 'basesystem')->flag_available or die "basesystem package not selected";
#- check if there are packages that need installation.
$o->{steps}{installPackages}{done} = 0 if $o->{steps}{installPackages}{done} && pkgs::packagesToInstall($o->{packages}) > 0;
}
#------------------------------------------------------------------------------
sub installPackages {
my ($_clicked, $ent_number, $auto) = @_;
installStepsCall($o, $auto, 'readBootloaderConfigBeforeInstall') if $ent_number == 1;
installStepsCall($o, $auto, 'beforeInstallPackages');
installStepsCall($o, $auto, 'installPackages');
installStepsCall($o, $auto, 'afterInstallPackages');
}
#------------------------------------------------------------------------------
sub miscellaneous {
my ($clicked, $_ent_number, $auto) = @_;
installStepsCall($o, $auto, 'miscellaneousBefore', $clicked);
installStepsCall($o, $auto, 'miscellaneous', $clicked);
installStepsCall($o, $auto, 'miscellaneousAfter', $clicked);
}
#------------------------------------------------------------------------------
sub summary {
my ($_clicked, $ent_number, $auto) = @_;
installStepsCall($o, $auto, 'summaryBefore');
installStepsCall($o, $auto, 'summary', $ent_number == 1);
installStepsCall($o, $auto, 'summaryAfter');
}
#------------------------------------------------------------------------------
sub configureNetwork {
my ($_clicked, $_ent_number, $auto) = @_;
#- get current configuration of network device.
require network::network;
eval { network::network::read_all_conf($o->{prefix}, $o->{netc}, $o->{intf}) };
installStepsCall($o, $auto, 'configureNetwork') if !$o->{isUpgrade};
}
#------------------------------------------------------------------------------
sub installUpdates {
my ($_clicked, $_ent_number, $auto) = @_;
installStepsCall($o, $auto, 'installUpdates') if $o->{meta_class} ne 'firewall';
}
#------------------------------------------------------------------------------
sub configureServices {
my ($clicked, $_ent_number, $auto) = @_;
installStepsCall($o, $auto, 'configureServices', $clicked);
}
#------------------------------------------------------------------------------
sub setRootPassword {
my ($clicked, $_ent_number, $auto) = @_;
return if $o->{isUpgrade};
installStepsCall($o, $auto, 'setRootPassword', $clicked);
}
#------------------------------------------------------------------------------
sub addUser {
my ($clicked, $_ent_number, $auto) = @_;
installStepsCall($o, $auto, 'addUser', $clicked) if !$o->{isUpgrade};
}
#------------------------------------------------------------------------------
sub setupBootloader {
my ($_clicked, $ent_number, $auto) = @_;
return if $::uml_install;
$o->{modules_conf}->write;
installStepsCall($o, $auto, 'setupBootloaderBefore') if $ent_number == 1;
installStepsCall($o, $auto, 'setupBootloader', $ent_number);
eval { install_any::set_security($o) };
}
#------------------------------------------------------------------------------
sub configureX {
my ($_clicked, $_ent_number, $auto) = @_;
#- done here and also at the end of install2.pm, just in case...
install_any::write_fstab($o);
$o->{modules_conf}->write;
require pkgs;
installStepsCall($o, $auto, 'configureX') if !$::testing && eval { pkgs::packageByName($o->{packages}, 'xorg-x11')->flag_installed } && !$o->{X}{disabled};
}
#------------------------------------------------------------------------------
sub exitInstall {
my ($_clicked, $_xent_number, $auto) = @_;
installStepsCall($o, $auto, 'exitInstall', getNextStep($::o) eq 'exitInstall');
}
sub start_i810fb() {
my ($vga) = cat_('/proc/cmdline') =~ /vga=(\S+)/;
return if !$vga || listlength(cat_('/proc/fb'));
my %vga_to_xres = (0x311 => '640', 0x314 => '800', 0x317 => '1024');
my $xres = $vga_to_xres{$vga} || '800';
log::l("trying to load i810fb module with xres <$xres> (vga was <$vga>)");
eval { modules::load('intel-agp') };
eval {
any::ddcxinfos(); # keep the result otherwise ddcxinfos does not return good results afterwards
my $opt = "xres=$xres hsync1=32 hsync2=48 vsync1=50 vsync2=70 vram=2 bpp=16 accel=1 mtrr=1"; #- this sucking i810fb does not accept floating point numbers in hsync!
modules::load_with_options([ 'i810fb' ], { i810fb => $opt });
};
}
#-######################################################################################
#- MAIN
#-######################################################################################
sub main {
$SIG{SEGV} = sub {
my $msg = "segmentation fault: seems like memory is missing as the install crashes"; log::l($msg);
$o->ask_warn('', $msg);
setVirtual(1);
require install_steps_auto_install;
install_steps_auto_install_non_interactive::errorInStep($o, $msg);
};
$ENV{PERL_BADLANG} = 1;
$ENV{LD_ASSUME_KERNEL} = '2.4.1';
delete $ENV{TERMINFO};
umask 022;
$::isInstall = 1;
$::isWizard = 1;
$::no_ugtk_init = 1;
$::expert = 0;
#- c::unlimit_core() unless $::testing;
my ($cfg, $patch, @auto);
my %cmdline = map {
my ($n, $v) = split '=';
$n => $v || 1;
} split ' ', cat_("/proc/cmdline");
my $opt; foreach (@_) {
if (/^--?(.*)/) {
$cmdline{$opt} = 1 if $opt;
$opt = $1;
} else {
$cmdline{$opt} = $_ if $opt;
$opt = '';
}
} $cmdline{$opt} = 1 if $opt;
#- from stage1
put_in_hash(\%ENV, { getVarsFromSh('/tmp/env') });
exists $ENV{$_} and $cmdline{lc($_)} = $ENV{$_} foreach qw(METHOD PCMCIA KICKSTART);
map_each {
my ($n, $v) = @_;
my $f = ${{
lang => sub { $o->{locale}{lang} = $v },
flang => sub { $o->{locale}{lang} = $v; push @auto, 'selectLanguage' },
method => sub { $o->{method} = $v },
pcmcia => sub { $o->{pcmcia} = $v },
vga16 => sub { $o->{vga16} = $v },
vga => sub { $o->{vga} = $v },
step => sub { $o->{steps}{first} = $v },
meta_class => sub { $o->{meta_class} = $v },
freedriver => sub { $o->{freedriver} = $v },
readonly => sub { $o->{partitioning}{readonly} = $v ne "0" },
display => sub { $o->{display} = $v },
askdisplay => sub { print "Please enter the X11 display to perform the install on ? "; $o->{display} = chomp_(scalar(<STDIN>)) },
security => sub { $o->{security} = $v },
noauto => sub { $::noauto = 1 },
testing => sub { $::testing = 1 },
patch => sub { $patch = 1 },
defcfg => sub { $cfg = $v },
newt => sub { $o->{interactive} = "newt" },
text => sub { $o->{interactive} = "newt" },
stdio => sub { $o->{interactive} = "stdio" },
kickstart => sub { $::auto_install = $v },
uml_install => sub { $::uml_install = 1 },
auto_install => sub { $::auto_install = $v },
simple_themes => sub { $o->{simple_themes} = 1 },
theme => sub { $o->{theme} = $v },
doc => sub { $o->{doc} = 1 }, #- will be used to know that we're running for the doc team,
#- e.g. we want screenshots with a good B&W contrast
useless_thing_accepted => sub { $o->{useless_thing_accepted} = 1 },
alawindows => sub { $o->{security} = 0; $o->{partitioning}{clearall} = 1; $o->{bootloader}{crushMbr} = 1 },
fdisk => sub { $o->{partitioning}{fdisk} = 1 },
nomouseprobe => sub { $o->{nomouseprobe} = $v },
updatemodules => sub { $o->{updatemodules} = 1 },
move => sub { $::move = 1 },
globetrotter => sub { $::move = 1; $::globetrotter = 1 },
}}{lc $n}; &$f if $f;
} %cmdline;
if ($::testing) {
$ENV{SHARE_PATH} ||= "/export/install/stage2/live/usr/share";
$ENV{SHARE_PATH} = "/usr/share" if !-e $ENV{SHARE_PATH};
} else {
$ENV{SHARE_PATH} ||= "/usr/share";
}
undef $::auto_install if $cfg;
if (!$::testing) {
unlink $_ foreach "/modules/modules.mar", "/sbin/stage1";
}
log::openLog(($::testing || $o->{localInstall}) && 'debug.log');
log::l("second stage install running (", any::drakx_version(), ")");
eval { output('/proc/sys/kernel/modprobe', '') } if !$::testing; #- disable kmod, otherwise we get a different behaviour in kernel vs kernel-BOOT
eval { fs::mount('none', '/sys', 'sysfs', 1) };
if ($::move) {
require move;
move::init($o);
}
cp_f(glob('/stage1/tmp/*'), '/tmp');
#- free up stage1 memory
eval { fs::umount($_) } foreach qw(/stage1/proc/bus/usb /stage1/proc /stage1);
$o->{prefix} = $::prefix = $::testing ? "/tmp/test-perl-install" : $::move ? "" : "/mnt";
mkdir $o->{prefix}, 0755;
devices::make("/dev/zero"); #- needed by ddcxinfos
#- make sure we do not pick up any gunk from the outside world
my $remote_path = "$o->{prefix}/sbin:$o->{prefix}/bin:$o->{prefix}/usr/sbin:$o->{prefix}/usr/bin:$o->{prefix}/usr/X11R6/bin";
$ENV{PATH} = "/usr/bin:/bin:/sbin:/usr/sbin:/usr/X11R6/bin:$remote_path";
eval { spawnShell() };
modules::load_dependencies(($::testing ? ".." : "") . "/modules/modules.dep");
require modules::any_conf;
require modules::modules_conf;
$o->{modules_conf} = modules::modules_conf::read(modules::any_conf::vnew(), '/tmp/modules.conf');
modules::read_already_loaded($o->{modules_conf});
#- done before auto_install is called to allow the -IP feature on auto_install file name
if (-e '/tmp/network') {
require network::network;
#- get stage1 network configuration if any.
log::l('found /tmp/network');
$o->{netc} ||= {};
add2hash($o->{netc}, network::network::read_conf('/tmp/network'));
if (my ($file) = glob_('/tmp/ifcfg-*')) {
log::l("found network config file $file");
my $l = network::network::read_interface_conf($file);
$o->{intf}{$l->{DEVICE}} ||= $l;
}
if (-e '/etc/resolv.conf') {
my $file = '/etc/resolv.conf';
log::l("found network config file $file");
add2hash($o->{netc}, network::network::read_resolv_conf($file));
}
}
#- done after module dependencies are loaded for "vfat depends on fat"
if ($::auto_install) {
if ($::auto_install =~ /-IP(\.pl)?$/) {
my ($ip) = cat_('/tmp/stage1.log') =~ /configuring device (?!lo)\S+ ip: (\S+)/;
my $normalized_ip = join('', map { sprintf "%02X", $_ } split('\.', $ip));
$::auto_install =~ s/-IP(\.pl)?$/-$normalized_ip$1/;
}
require install_steps_auto_install;
eval { $o = $::o = install_any::loadO($o, $::auto_install) };
if ($@) {
if ($o->{useless_thing_accepted}) { #- Pixel's hack to be able to fail through
log::l("error using auto_install, continuing");
undef $::auto_install;
} else {
install_steps_auto_install_non_interactive::errorInStep($o, "Error using auto_install\n" . formatError($@));
}
} else {
log::l("auto install config file loaded successfully");
#- normalize for people not using our special scheme
foreach (@{$o->{manualFstab} || []}) {
$_->{device} =~ s!^/dev/!!;
}
}
}
$o->{interactive} ||= 'gtk' if !$::auto_install;
if ($o->{interactive} eq "gtk" && availableMemory() < 22 * 1024) {
log::l("switching to newt install cuz not enough memory");
$o->{interactive} = "newt";
}
if (my ($s) = cat_("/proc/cmdline") =~ /brltty=(\S*)/) {
my ($driver, $device, $table) = split(',', $s);
$table = "text.$table.tbl" if $table !~ /\.tbl$/;
log::l("brltty option $driver $device $table");
$o->{brltty} = { driver => $driver, device => $device, table => $table };
$o->{interactive} = 'newt';
$o->{nomouseprobe} = 1;
}
# perl_checker: require install_steps_gtk
# perl_checker: require install_steps_newt
# perl_checker: require install_steps_stdio
require "install_steps_$o->{interactive}.pm" if $o->{interactive};
#- needed before accessing floppy (in case of usb floppy)
modules::load_category($o->{modules_conf}, 'bus/usb');
#- oem patch should be read before to still allow patch or defcfg.
eval { $o = $::o = install_any::loadO($o, "install/patch-oem.pl"); log::l("successfully read oem patch") };
#- patch should be read after defcfg in order to take precedance.
eval { $o = $::o = install_any::loadO($o, $cfg); log::l("successfully read default configuration: $cfg") } if $cfg;
eval { $o = $::o = install_any::loadO($o, "patch"); log::l("successfully read patch") } if $patch;
eval { modules::load("af_packet") };
require harddrake::sound;
harddrake::sound::configure_sound_slots($o->{modules_conf});
#- need to be after oo-izing $o
if ($o->{brltty}) {
symlink "/tmp/stage2/$_", $_ foreach "/etc/brltty";
eval { modules::load("serial") };
devices::make($_) foreach $o->{brltty}{device} ? $o->{brltty}{device} : qw(ttyS0 ttyS1);
devices::make("vcsa");
run_program::run("brltty");
}
#- needed very early for install_steps_gtk
if (!$::testing) {
eval { $o->{mouse} = mouse::detect($o->{modules_conf}) } if !$o->{mouse} && !$o->{nomouseprobe};
mouse::load_modules($o->{mouse});
}
$o->{locale}{lang} = lang::set($o->{locale}) if $o->{locale}{lang} ne 'en_US' && !$::move; #- mainly for defcfg
start_i810fb();
$o->{allowFB} = listlength(cat_("/proc/fb"));
if (!$::move && !$::testing && !$o->{meta_class}) {
my $VERSION = cat__(install_any::getFile("VERSION")) or do { print "VERSION file missing\n"; sleep 5 };
my @classes = qw(powerpackplus powerpack desktop download server firewall);
if (my $meta_class = find { $VERSION =~ /$_/i } @classes) {
$o->{meta_class} = $meta_class;
}
$o->{distro_type} = 'community' if $VERSION =~ /community/i;
$o->{distro_type} = 'cooker' if $VERSION =~ /cooker/i;
}
$o->{meta_class} eq 'discovery' and $o->{meta_class} = 'desktop';
$o->{meta_class} eq 'powerpackplus' and $o->{meta_class} = 'server';
log::l("meta_class $o->{meta_class}");
foreach (@auto) {
my $s = $o->{steps}{/::(.*)/ ? $1 : $_} or next;
$s->{auto} = $s->{hidden} = 1;
}
my $o_;
while (1) {
$o_ = $::auto_install ?
install_steps_auto_install->new($o) :
$o->{interactive} eq "stdio" ?
install_steps_stdio->new($o) :
$o->{interactive} eq "newt" ?
install_steps_newt->new($o) :
$o->{interactive} eq "gtk" ?
install_steps_gtk->new($o) :
die "unknown install type";
$o_ and last;
$o->{interactive} = "newt";
require install_steps_newt;
}
$::o = $o = $o_;
#-the main cycle
my $clicked = 0;
MAIN: for ($o->{step} = $o->{steps}{first};; $o->{step} = getNextStep($o)) {
$o->{steps}{$o->{step}}{entered}++;
$o->enteringStep($o->{step});
eval {
&{$install2::{$o->{step}}}($clicked || $o->{steps}{$o->{step}}{noauto},
$o->{steps}{$o->{step}}{entered},
$clicked ? 0 : $o->{steps}{$o->{step}}{auto});
};
my $err = $@;
$o->kill_action;
$clicked = 0;
if ($err) {
local $_ = $err;
$o->kill_action;
if (!/^already displayed/) {
eval { $o->errorInStep($_) };
$o->{steps}{$o->{step}}{auto} = 0;
$err = $@;
$err and next;
}
$o->{step} = $o->{steps}{$o->{step}}{onError};
next MAIN unless $o->{steps}{$o->{step}}{reachable}; #- sanity check: avoid a step not reachable on error.
redo MAIN;
}
$o->{steps}{$o->{step}}{done} = 1;
$o->leavingStep($o->{step});
last if $o->{step} eq 'exitInstall';
}
install_any::clean_postinstall_rpms();
install_any::log_sizes($o);
install_any::remove_advertising($o);
install_any::write_fstab($o);
$o->{modules_conf}->write;
detect_devices::install_addons($o->{prefix});
#- mainly for auto_install's
#- do not use run_program::xxx because it does not leave stdin/stdout unchanged
system("bash", "-c", $o->{postInstallNonRooted}) if $o->{postInstallNonRooted};
system("chroot", $o->{prefix}, "bash", "-c", $o->{postInstall}) if $o->{postInstall};
install_any::ejectCdrom();
#- to ensure linuxconf does not cry against those files being in the future
foreach ('/etc/modules.conf', '/etc/crontab', '/etc/sysconfig/mouse', '/etc/sysconfig/network', '/etc/X11/fs/config') {
my $now = time() - 24 * 60 * 60;
utime $now, $now, "$o->{prefix}/$_";
}
install_any::killCardServices();
#- make sure failed upgrade will not hurt too much.
install_steps::cleanIfFailedUpgrade($o);
-e "$o->{prefix}/usr/sbin/urpmi.update" or eval { rm_rf("$o->{prefix}/var/lib/urpmi") };
#- copy latest log files
eval { cp_af("/tmp/$_", "$o->{prefix}/root/drakx") foreach qw(ddebug.log stage1.log) };
#- ala pixel? :-) [fpons]
common::sync(); common::sync();
log::l("installation complete, leaving");
log::l("files still open by install2: ", readlink($_)) foreach glob_("/proc/self/fd/*");
print "\n" x 80;
}
1;