summaryrefslogtreecommitdiffstats
path: root/perl-install/pkgs.pm
Commit message (Expand)AuthorAgeFilesLines
* fix typo (thanks titi)Olivier Blin2008-10-021-1/+1
* use a minimum rpmsrate level of 5 when netbook/nettop/low_resources systems a...Olivier Blin2008-10-021-1/+1
* use functions to get rpmsrate levelsOlivier Blin2008-10-021-2/+7
* move rpmsrate values in variablesOlivier Blin2008-09-231-0/+2
* fix network packages detectionOlivier Blin2008-09-181-1/+1
* keep all settings (for next commit)Olivier Blin2008-09-181-1/+2
* indent and space fixesOlivier Blin2008-09-171-12/+12
* improve phrasing (from Fred and Adam)Olivier Blin2008-09-051-2/+2
* merge remove-unused-hardware-packages and remove-unselected-localesOlivier Blin2008-09-051-0/+41
* extract detect_unselected_locale_packages functionOlivier Blin2008-09-051-0/+10
* extract detect_unused_hardware_packages functionOlivier Blin2008-09-051-0/+8
* rename as detect_rpmsrate_hardware_packagesOlivier Blin2008-08-181-2/+2
* use rpmsrate when detecting hardware packages outside of installOlivier Blin2008-08-181-0/+1
* fix indentationOlivier Blin2008-08-181-3/+3
* allow to detect network drivers for running system (when not maching all hard...Olivier Blin2008-08-181-1/+8
* allow to detect graphical drivers for running system (when not maching all ha...Olivier Blin2008-08-181-2/+10
* split graphical and network packages detection codeOlivier Blin2008-08-181-3/+15
* move hardware packages detection code in pkgsOlivier Blin2008-08-181-0/+23
* pass optional o_match_all_hardware optionOlivier Blin2008-08-181-4/+6
* remove useless requireOlivier Blin2008-08-181-1/+0
* support reading rpmsrate in chroot (could be useful for live installs)Olivier Blin2008-08-181-1/+1
* space fixOlivier Blin2008-08-181-1/+1
* remove useless isStandalone checks (we already check isInstall in one case, a...Olivier Blin2008-08-181-2/+2
* move rpmsrate functions in pkgs moduleOlivier Blin2008-08-181-0/+11
* add $line_nb in messagePascal Rigaux2008-03-141-2/+2
* add $line_nb in messagePascal Rigaux2008-03-141-1/+1
* kill some "used undefined variable" warningsPascal Rigaux2007-09-141-1/+1
* re-sync after the big svn lossPascal Rigaux2007-05-181-1486/+31
* re-sync after the big svn lossPascal Rigaux2007-05-181-0/+1598
* re-sync after the big svn lossPascal Rigaux2007-04-251-1598/+0
* fix selected_leaves() dropping all packages in a circular referencePascal Rigaux2006-01-241-6/+11
* package lsb is requiring many locales though we don't want it to be installedPascal Rigaux2005-12-131-2/+9
* (bestKernelPackage) install i586 kernel flavor for live systemsThierry Vignaud2005-12-071-0/+1
* fix rpmsrate negations when not installing a live systemOlivier Blin2005-11-211-4/+4
* (read_rpmsrate) do not match CAT_(KDE|GNOME|...) and ignore ! whileThierry Vignaud2005-11-211-5/+4
* (read_rpmsrate) let "build_live_system" mode be selected by auto config fileThierry Vignaud2005-11-211-1/+1
* (read_rpmsrate) install all hardware related packages when building a live sy...Thierry Vignaud2005-11-211-0/+1
* Fix test for dangling symlinkRafael Garcia-Suarez2005-10-201-1/+1
* Comment fixRafael Garcia-Suarez2005-09-261-1/+1
* don't warn lisa (which is installed by default)Pascal Rigaux2005-09-201-1/+4
* URPM/Resolve.pm diff 1.109: "Remove the return value of compute_installed_fla...Pascal Rigaux2005-09-161-1/+9
* - call installCallback() on "open" tooPascal Rigaux2005-09-151-0/+2
* add upgrade script for conectivaPascal Rigaux2005-09-141-10/+21
* do have all useful info in selected leaves, including base packages,Pascal Rigaux2005-09-141-1/+1
* do log the prefered choice (esp. to debug lilo vs grub)Pascal Rigaux2005-09-141-1/+1
* have same rpm config as when installing pkgsPascal Rigaux2005-09-091-1/+4
* At some point, an empty hashref is autovivified in $packages->{medium}.Rafael Garcia-Suarez2005-09-051-1/+2
* - new functionality: upgrade_by_removing_pkgs, enabled when upgrading redhat ...Pascal Rigaux2005-09-021-0/+81
* Workaround : Don't call method directlyRafael Garcia-Suarez2005-09-021-1/+1
* rename pkgs::rpmDbOpenForInstall() to pkgs::open_rpm_db_rw()Pascal Rigaux2005-09-021-3/+3
87'>587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 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
package install::install2; # $Id: install2.pm 255825 2009-04-08 11:54:23Z tv $

use diagnostics;
use strict;
use vars qw($o);

BEGIN { $::isInstall = 1 }

#-######################################################################################
#- misc imports
#-######################################################################################
use install::steps_list;
use common;
use install::any 'addToBeDone';
use install::steps;
use install::any;
use lang;
use keyboard;
use mouse;
use devices;
use partition_table;
use modules;
use detect_devices;
use run_program;
use any;
use log;
use fs;
use fs::any;

#-#######################################################################################
#-$O
#-the big struct which contain, well everything (globals + the interactive methods ...)
#-if you want to do a kickstart file, you just have to add all the required fields (see for example
#-the variable $default)
#-#######################################################################################
$o = $::o = {
#    bootloader => { linear => 0, message => 1, timeout => 5, restricted => 0 },
#-    packages   => [ qw() ],
    partitioning => { clearall => 0, eraseBadPartitions => 0, auto_allocate => 0 }, #-, readonly => 0 },
    authentication => { blowfish => 1, shadow => 1 },
    locale         => { lang => 'en_US' },
#-    isUpgrade    => 0,
    toRemove     => [],
    toSave       => [],
#-    simple_themes => 1,

    timezone => {
#-                   timezone => "Europe/Paris",
#-                   UTC      => 1,
                },
#-    superuser => { password => 'a', shell => '/bin/bash', realname => 'God' },
#-    user => { name => 'foo', password => 'bar', home => '/home/foo', shell => '/bin/bash', realname => 'really, it is foo' },

#-    keyboard => 'de',
#-    display => "192.168.1.19:1",
    steps        => \%install::steps_list::installSteps,
    orderedSteps => \@install::steps_list::orderedInstallSteps,

    #- for the list of fields available, see network/network.pm
    net => {
	    #- network => { HOSTNAME => 'abcd' },
	    #- resolv => { DOMAINNAME => 'foo.xyz' },
	    #- ifcfg => {
	    #-   eth0 => { DEVICE => "eth0", IPADDR => '1.2.3.4', NETMASK => '255.255.255.128' }
	    #- },
	    },

#-step : the current one
#-prefix
#-mouse
#-keyboard
#-netc
#-methods
#-packages compss

};


sub installStepsCall {
    my ($o, $auto, $fun, @args) = @_;
    $fun = "install::steps::$fun" if $auto;
    $o->$fun(@args);
}
sub getNextStep {
    my ($o) = @_;
    find { !$o->{steps}{$_}{done} && $o->{steps}{$_}{reachable} } @{$o->{orderedSteps}};
}

#-######################################################################################
#- Steps Functions
#- each step function are called with two arguments : clicked(because if you are a
#- beginner you can force the the step) and the entered number
#-######################################################################################

#------------------------------------------------------------------------------
sub selectLanguage {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'selectLanguage');
}

sub acceptLicense {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'acceptLicense');
}

#------------------------------------------------------------------------------
sub selectMouse {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'selectMouse');

    addToBeDone { mouse::write($o->do_pkgs, $o->{mouse}) if !$o->{isUpgrade} } 'installPackages';
}

#------------------------------------------------------------------------------
sub setupSCSI {
    my ($auto) = @_;

    installStepsCall($o, $auto, 'setupSCSI');
}

#------------------------------------------------------------------------------
sub selectKeyboard {
    my ($auto) = @_;

    my $force;
    if (my $keyboard = keyboard::read()) {
	$o->{keyboard} = $keyboard; #- for uprade
    } elsif ($o->{isUpgrade}) {
	#- oops, the keyboard config is wrong, forcing prompt and writing
	$force = 1;
    }

    installStepsCall($o, $auto, 'selectKeyboard', $force);
}

#------------------------------------------------------------------------------
sub selectInstallClass {
    my ($auto) = @_;

    installStepsCall($o, $auto, 'selectInstallClass');

    if ($o->{isUpgrade}) {
	@{$o->{orderedSteps}} = uniq(map {
	    $_ eq 'selectInstallClass' ? ($_, 'doPartitionDisks', 'formatPartitions') : $_;
	} @{$o->{orderedSteps}});
    }
}

#------------------------------------------------------------------------------
sub doPartitionDisks {
    my ($auto) = @_;
    $o->{steps}{formatPartitions}{done} = 0;
    installStepsCall($o, $auto, 'doPartitionDisksBefore');
    installStepsCall($o, $auto, 'doPartitionDisks');
    installStepsCall($o, $auto, 'doPartitionDisksAfter');
}

sub formatPartitions {
    my ($auto) = @_;

    $o->{steps}{choosePackages}{done} = 0;
    installStepsCall($o, $auto, 'choosePartitionsToFormat') if !$o->{isUpgrade} && !$::local_install;
    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') 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("$::prefix/var/lib/rpm") };
    }

    fs::any::prepare_minimal_root();

    install::any::screenshot_dir__and_move();
    install::any::move_compressed_image_to_disk($o);

    any::rotate_logs($::prefix);

    require raid;
    raid::write_conf($o->{all_hds}{raids});
}

#------------------------------------------------------------------------------
sub choosePackages {
    my ($auto) = @_;
    require install::pkgs;

    #- always setPackages as it may have to copy hdlist and synthesis files.
    installStepsCall($o, $auto, 'setPackages');
    installStepsCall($o, $auto, 'choosePackages');
    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.
    install::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} && install::pkgs::packagesToInstall($o->{packages}) > 0;
}

#------------------------------------------------------------------------------
sub installPackages {
    my ($auto) = @_;

    installStepsCall($o, $auto, 'beforeInstallPackages');
    installStepsCall($o, $auto, 'installPackages');
    installStepsCall($o, $auto, 'afterInstallPackages');
}
#------------------------------------------------------------------------------
sub miscellaneous {
    my ($auto) = @_;

    installStepsCall($o, $auto, 'miscellaneousBefore');
    installStepsCall($o, $auto, 'miscellaneous');
    installStepsCall($o, $auto, 'miscellaneousAfter');
}

#------------------------------------------------------------------------------
sub summary {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'summaryBefore') if $o->{steps}{summary}{entered} == 1;
    installStepsCall($o, $auto, 'summary');
    installStepsCall($o, $auto, 'summaryAfter');
}
#------------------------------------------------------------------------------
sub configureNetwork {
    my ($auto) = @_;
    #- get current configuration of network device.
    require network::network;
    eval { network::network::read_net_conf($o->{net}) };
    modules::load_category($o->{modules_conf}, list_modules::ethernet_categories());
    require network::connection::ethernet;
    if (!$o->{isUpgrade}) {
        installStepsCall($o, $auto, 'configureNetwork');
    } else {
        network::connection::ethernet::configure_eth_aliases($o->{modules_conf});
    }
}
#------------------------------------------------------------------------------
sub installUpdates {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'installUpdates');
}
#------------------------------------------------------------------------------
sub configureServices {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'configureServices');
}
#------------------------------------------------------------------------------
sub setRootPassword_addUser {
    my ($auto) = @_;

    installStepsCall($o, $auto, 'setRootPassword_addUser') if !$o->{isUpgrade};
}

#------------------------------------------------------------------------------
sub setupBootloader {
    my ($auto) = @_;
    return if $::local_install;

    $o->{modules_conf}->write;

    installStepsCall($o, $auto, 'setupBootloaderBefore');
    installStepsCall($o, $auto, 'setupBootloader');
}
#------------------------------------------------------------------------------
sub configureX {
    my ($auto) = @_;

    #- done here and also at the end of install2.pm, just in case...
    install::any::write_fstab($o);
    $o->{modules_conf}->write;

    require install::pkgs;
    installStepsCall($o, $auto, 'configureX') if !$::testing && eval { install::pkgs::packageByName($o->{packages}, 'task-x11')->flag_installed } && !$o->{X}{disabled};
}
#------------------------------------------------------------------------------
sub exitInstall {
    my ($auto) = @_;
    installStepsCall($o, $auto, 'exitInstall', getNextStep($::o) eq 'exitInstall');
}

#-######################################################################################
#- Udev Functions
#-######################################################################################

sub start_udev() {
    # Ensure /run is mounted
    mkdir("/run", 0755);
    run_program::run("mount -t tmpfs -o mode=0755,nosuid,nodev tmpfs /run");

    # Fake dracut boot (due to checks employed when running dracut during install)
    # as we know that we'll have the needed metadata in udevadm db due to us
    # starting udev nice and early here.
    mkdir_p("/run/initramfs");

    # Start up udev and trigger cold plugs
    run_program::run("mount", "-t", "devtmpfs", "-o", "mode=0755,nosuid", "devtmpfs", "/dev");
    mkdir("/dev/$_", 0755) foreach qw(pts shm);
    run_program::run("mount", "-t", "devpts", "-o", "gid=5,mode=620,noexec,nosuid", "devpts", "/dev/pts");
    run_program::run("mount", "-t", "tmpfs", "-o", "mode=1777,nosuid,nodev", "tmpfs", "/dev/shm");

    mkdir_p("/run/udev/rules.d");
    $ENV{UDEVRULESD} = "/run/udev/rules.d";
    run_program::run("/lib/udev/udevd", "--daemon", "--resolve-names=never");
    run_program::run("udevadm", "trigger", "--type=subsystems", "--action=add");
    run_program::run("udevadm", "trigger", "--type=devices", "--action=add");
}

sub stop_udev() {
    kill 15, fuzzy_pidofs('udevd');
    sleep(2);
    require fs::mount;
    fs::mount::umount($_) foreach '/dev/pts', '/dev/shm', '/run';
}

#-######################################################################################
#- Other Functions
#-######################################################################################

sub init_local_install {
    my ($o) = @_;
    push @::auto_steps, 
#      'selectLanguage', 'selectKeyboard', 'miscellaneous', 'selectInstallClass',
      'doPartitionDisks', 'formatPartitions';
	fs::mount::usbfs(''); #- do it now so that when_load doesn't do it
	$o->{nomouseprobe} = 1;
	$o->{mouse} = mouse::fullname2mouse('Universal|Any PS/2 & USB mice');
}

sub init_brltty() {
    symlink "/tmp/stage2/$_", $_ foreach "/etc/brltty";
    devices::make($_) foreach $o->{brltty}{device} ? $o->{brltty}{device} : qw(ttyS0 ttyS1);
    devices::make("vcsa");
    run_program::run("brltty");
}

sub step_init {
  my ($o) = @_;
  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 "curses" ?
    	  install::steps_curses->new($o) :
    	    $o->{interactive} eq "gtk" ?
    	  install::steps_gtk->new($o) :
    	    die "unknown install type";
      $o_ and last;

      log::l("$o->{interactive} failed, trying again with curses");
      $o->{interactive} = "curses";
      require install::steps_curses;
  }
  $o;
}

sub read_product_id() {
    my $product_id = cat__(install::any::getFile_($o->{stage2_phys_medium}, "product.id"));
    log::l('product_id: ' . chomp_($product_id));
    $o->{product_id} = common::parse_LDAP_namespace_structure($product_id);
 
    $o->{meta_class} ||= {
        One          => 'desktop',
        Free         => 'download',
        Powerpack    => 'powerpack',
    }->{$o->{product_id}{product}} || 'download';
}

sub sig_segv_handler() {
    my $msg = "segmentation fault: install crashed (maybe memory is missing?)\n" . backtrace();
    log::l("$msg\n");
    # perl_checker: require UNIVERSAL
    UNIVERSAL::can($o, 'ask_warn') and $o->ask_warn('', $msg);
    setVirtual(1);
    require install::steps_auto_install;
    install::steps_auto_install_non_interactive::errorInStep($o, $msg);
}

sub read_stage1_net_conf() {
    require network::network;
    #- get stage1 network configuration if any.
    log::l('found /tmp/network');
    add2hash($o->{net}{network} ||= {}, 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->{net}{ifcfg}{$l->{DEVICE}} ||= $l;
    }
    my $dsl_device = find { $_->{BOOTPROTO} eq 'adsl_pppoe' } values %{$o->{net}{ifcfg}};
    if ($dsl_device) {
        $o->{net}{type} = 'adsl';
        $o->{net}{net_interface} = $dsl_device->{DEVICE};
        $o->{net}{adsl} = {
            method => 'pppoe',
            device => $dsl_device->{DEVICE},
            ethernet_device => $dsl_device->{DEVICE},
            login => $dsl_device->{USER},
            password => $dsl_device->{PASS},
        };
        %$dsl_device = ();
    } else {
        $o->{net}{type} = 'lan';
        $o->{net}{net_interface} = first(values %{$o->{net}{ifcfg}});
    }
}

#-######################################################################################
#- MAIN
#-######################################################################################
sub main {
    $SIG{SEGV} = \&sig_segv_handler;
    $ENV{PERL_BADLANG} = 1;
    delete $ENV{TERMINFO};
    umask 022;

    $::isWizard = 1;
    $::no_ugtk_init = 1;

    push @::textdomains, 'DrakX', 'drakx-net', 'drakx-kbd-mouse-x11';

    my ($cfg, $patch);
    my %cmdline = map { 
	my ($n, $v) = split /=/;
	$n => defined($v) ? $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->{lang} = $v },
	    flang     => sub { $o->{lang} = $v; push @::auto_steps, 'selectLanguage' },
	    langs     => sub { $o->{locale}{langs} = +{ map { $_ => 1 } split(':', $v) } },
	    method    => sub { $o->{method} = $v },
	    pcmcia    => sub { $o->{pcmcia} = $v },
	    vga16     => sub { $o->{vga16} = $v },
	    vga       => sub { $o->{vga} = $v =~ /0x/ ? hex($v) : $v },
	    step      => sub { $o->{steps}{first} = $v },
	    meta_class => sub { $o->{meta_class} = $v },
	    freedriver => sub { $o->{freedriver} = $v },
	    no_bad_drives => sub { $o->{partitioning}{no_bad_drives} = 1 },
	    nodmraid  => sub { $o->{partitioning}{nodmraid} = 1 },
	    debug_urpmi  => sub { $o->{debug_urpmi} = 1 },
	    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} = "curses" },
	    text      => sub { $o->{interactive} = "curses" },
	    stdio     => sub { $o->{interactive} = "stdio" },
	    use_uuid  => sub { $::no_uuid_by_default = !$v },
	    kickstart => sub { $::auto_install = $v },
	    local_install => sub { $::local_install = 1 },
	    uml_install => sub { $::uml_install = $::local_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 },
	    suppl => sub { $o->{supplmedia} = $v },
	    askmedia => sub { $o->{askmedia} = 1 },
	    restore => sub { $::isRestore = 1 },
	    compsslistlevel => sub { $o->{compssListLevel} = $v },
	}}{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;

    $o->{stage2_phys_medium} = install::media::stage2_phys_medium($o->{method});

    log::l("second stage install running (", install::any::drakx_version($o), ")");

    eval { output('/proc/sys/kernel/modprobe', "\n") } if !$::local_install && !$::testing; #- disable kmod
    eval { fs::mount::mount('none', '/sys', 'sysfs', 1) };
    eval { touch('/root/non-chrooted-marker.DrakX') }; #- helps distinguishing /root and /mnt/root when we don't know if we are chrooted

    if ($::local_install) {
        init_local_install($o);
    } else {
        start_udev();
    }

    $o->{prefix} = $::prefix = $::testing ? "/tmp/test-perl-install" : "/mnt";
    mkdir $::prefix, 0755;

    #-  make sure we do not pick up any gunk from the outside world
    my $remote_path = "$::prefix/sbin:$::prefix/bin:$::prefix/usr/sbin:$::prefix/usr/bin:$::prefix/usr/X11R6/bin";
    $ENV{PATH} = "/usr/bin:/bin:/sbin:/usr/sbin:/usr/X11R6/bin:$remote_path";

    eval { install::any::spawnShell() };

    list_modules::load_default_moddeps();
    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
    read_stage1_net_conf() if -e '/tmp/network';

    #- 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 curses install cuz not enough memory");
 	$o->{interactive} = "curses";
    }

    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} = 'curses';
	$o->{nomouseprobe} = 1;
    }

    # perl_checker: require install::steps_gtk
    # perl_checker: require install::steps_curses
    # 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
    init_brltty() if $o->{brltty};

    devices::make('tty') if $o->{interactive} eq "curses";

    #- 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});
    }

    #- for auto_install compatibility with old $o->{lang},
    #- and also for --lang and --flang
    if ($o->{lang}) {
	put_in_hash($o->{locale}, lang::lang_to_ourlocale($o->{lang}));
    }
    lang::set($o->{locale});

    # keep the result otherwise monitor-edid does not return good results afterwards
    eval { any::monitor_full_edid() };

    $o->{allowFB} = listlength(cat_("/proc/fb"));

    read_product_id() if !$::testing;

    log::l("META_CLASS=$o->{meta_class}");
    $ENV{META_CLASS} = $o->{meta_class}; #- for Ia Ora

    foreach (@::auto_steps) {
	if (my $s = $o->{steps}{/::(.*)/ ? $1 : $_}) {
	    $s->{auto} = $s->{hidden} = 1;
	} else {
	    log::l("ERROR: unknown step $_ in auto_steps");
	}
    }

    $ENV{COLUMNS} ||= 80;
    $ENV{LINES}   ||= 25;
    $::o = $o = step_init($o);

    eval { output('/proc/splash', "verbose\n") };
  
    real_main();
    finish_install();
}

sub real_main() {
    #-the main cycle
    MAIN: for ($o->{step} = $o->{steps}{first};; $o->{step} = getNextStep($o)) {
	$o->{steps}{$o->{step}}{entered}++;
	$o->enteringStep($o->{step});
	eval {
	    &{$install::install2::{$o->{step}}}($o->{steps}{$o->{step}}{auto});
	};
	my $err = $@;
	$o->kill_action;
	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';
    }
}

sub finish_install() {
    unlink $install::any::compressed_image_on_disk;
    install::media::clean_postinstall_rpms();
    install::media::log_sizes();
    install::any::remove_advertising();
    install::any::write_fstab($o);
    $o->{modules_conf}->write;
    detect_devices::install_addons($::prefix);

    install::any::adjust_files_mtime_to_timezone();

    #- make sure failed upgrade will not hurt too much.
    install::steps::cleanIfFailedUpgrade($o);

    -e "$::prefix/usr/sbin/urpmi.update" or eval { rm_rf("$::prefix/var/lib/urpmi") };

    system("chroot", $::prefix, "bash", "-c", $o->{postInstallBeforeReboot}) if $o->{postInstallBeforeReboot};

    #- copy latest log files
    eval { cp_af("/tmp/$_", "$::prefix/root/drakx") foreach qw(ddebug.log stage1.log) };

    #- ala pixel? :-) [fpons]
    common::sync(); common::sync();

    stop_udev() if !$::local_install;
    log::l("installation complete, leaving");
    log::l("files still open by install2: ", readlink($_)) foreach glob_("/proc/self/fd/*");
    print "\n" x 80 if !$::local_install;
}

1;