summaryrefslogtreecommitdiffstats
path: root/tools/drakx-in-chroot
blob: fbda29eb9c856f198d9a31647533c29c5d3dcc07 (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
#!/usr/bin/perl

use MDK::Common;

my $SLASH_LOCATION = '/tmp/drakx-in-chroot';

my $verbose = 0;
my $prefix_ROOTED = '/mnt';
my $IMAGE_LOCATION_ROOTED = '/tmp/image';
my $STAGE2_LOCATION_ROOTED = '/tmp/stage2';
my $LIVE_LOCATION_REL = 'install/stage2/live/';
my $CLP_LOCATION_REL = 'install/stage2/';
my $CLP_FILE_REL = $CLP_LOCATION_REL . 'mdkinst.clp';
my $AUTO_INSTALL_ROOTED = '/tmp/drakx-in-chroot.cfg.pl';

@ARGV >= 2 or die "usage: drakx-in-chroot <repository> <dir to install to> [options]\n";

(my $repository, my $dir, @ARGV) = @ARGV;
my $STAGE2_LOCATION = $SLASH_LOCATION . $STAGE2_LOCATION_ROOTED;

my $sudo;
if ($>) {
    $sudo = "sudo";
    $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}";
}

undef $ENV{TMPDIR}; # prevent packdrake faillure on creating temporary files

if (-d $SLASH_LOCATION) {
    umount_all() == 0 or die "$SLASH_LOCATION is busy\n";
    sys("$sudo rm -rf $SLASH_LOCATION/var/lib/rpm $SLASH_LOCATION/dev/mapper");
    rm_rf($SLASH_LOCATION);
}

mkdir_p("$SLASH_LOCATION$_") foreach '/dev', '/dev/usb', '/etc', '/var', '/proc', $STAGE2_LOCATION_ROOTED, $IMAGE_LOCATION_ROOTED, $prefix_ROOTED;

sys("$sudo rm -rf $dir") if $ENV{CLEAN};
-e $dir or sys("$sudo mkdir -p $dir");

copy_auto_install_files();

if (-d "$repository/$LIVE_LOCATION_REL") {
    sys("$sudo mount -o bind $repository/$LIVE_LOCATION_REL $STAGE2_LOCATION");
} elsif (-e "$repository/$CLP_FILE_REL") {
    my $dev = find_free_loop();
    sys("$sudo modprobe gzloop");
    sys("$sudo losetup -r -e gz $dev $repository/$CLP_FILE_REL");
    sys("$sudo mount -r $dev $STAGE2_LOCATION");
}

sys("$sudo mount -o bind $dir $SLASH_LOCATION$prefix_ROOTED");
sys("$sudo mount -o bind $repository $SLASH_LOCATION$IMAGE_LOCATION_ROOTED");
sys("$sudo mount -t proc none $SLASH_LOCATION/proc");
create_initial_symlinks();
create_initial_devices();

output("$SLASH_LOCATION/etc/hosts", "127.0.0.1 localhost\n") if ! -e "$SLASH_LOCATION/etc/hosts";

my $Xnest_pid;
if (!-f ($SLASH_LOCATION . $AUTO_INSTALL_ROOTED) && whereis_binary('Xnest')) {
    my $DISPLAY = ':8';
    $Xnest_pid = fork();
    if (!$Xnest_pid) {
	exec 'Xnest', $DISPLAY, '-ac', '-geometry', '800x600' or die "Xnest failed\n";
    }
    $ENV{DISPLAY} = 'localhost' . $DISPLAY;
}

if (my $pid = fork()) {
    waitpid $pid, 0;
    umount_all() == 0 or warn "umounting failed\n";
    $Xnest_pid and kill 15, $Xnest_pid;
} else {
    $ENV{HOME} = '/';
    # to kept sync with gi/mdk-stage1/init.c::env:
    $ENV{LD_LIBRARY_PATH}='/lib:/usr/lib:/mnt/lib:/mnt/usr/lib:/usr/X11R6/lib:/mnt/usr/X11R6/lib:/lib64:/usr/lib64:/usr/X11R6/lib64:/mnt/lib64:/mnt/usr/lib64:/mnt/usr/X11R6/lib64';
    my $cmd = join(' ', "/usr/bin/runinstall2 --local_install", @ARGV);
    exec "$sudo chroot $SLASH_LOCATION $cmd" or die "exec $cmd in $SLASH_LOCATION failed\n";
}

sub system_verbose { warn join(' ', @_), "\n" if $verbose; system(@_) }
sub sys { &system_verbose; $? and die qq(running "@_" failed: $?\n) }

sub find_free_loop() {
    foreach (0..255) {
	my $dev = "/dev/loop$_";
	system("$sudo losetup $dev >/dev/null 2>&1") != 0 or next;
	warn "found free loop $dev\n";
	return $dev;
    }
    die "no free loop found";
}

sub create_initial_symlinks() {
    foreach (cat_or_die("$STAGE2_LOCATION/usr/share/symlinks")) {
	my ($from, $to_) = split;
	my $to = $SLASH_LOCATION . ($to_ || $from);
	$from = "$STAGE2_LOCATION_ROOTED$from" if !$to_;
	if (! -l $to) {
	    symlink $from, $to or die "symlinking $to failed\n";
	}
    }
}

sub create_initial_devices() {
    foreach (cat_or_die("$STAGE2_LOCATION/usr/share/devices")) {
	my ($node, $type, $major, $minor) = split;
	sys("$sudo mknod $SLASH_LOCATION$node $type $major $minor") if ! -e "$SLASH_LOCATION$node";
    }
}

sub umount_all() {
    my $err;
    my @procs = ('/proc/bus/usb', '/proc', '/sys');
    foreach ((map { "$prefix_ROOTED$_" } @procs, ''), @procs, $STAGE2_LOCATION_ROOTED, $IMAGE_LOCATION_ROOTED) {
	my $dir = "$SLASH_LOCATION$_";
	rmdir $dir;
	if (-d $dir) {
	    if (m!/proc/bus/usb! || begins_with($_, $prefix_ROOTED)) {
		system_verbose "$sudo umount $dir 2>/dev/null";
		next;
	    }
	    my ($loop) = cat_('/proc/mounts') =~ m!^(/dev/loop\d+) .*\Q$dir\E !m;
	    system_verbose "$sudo umount $dir";
	    sys("$sudo losetup -d $loop") if $loop;
	}
	rmdir $dir;
	if (-d $dir) {
	    warn "$dir is busy\n";
	    $err++;
	}
    }
    $err;
}

sub copy_auto_install_files() {
    my ($opt);
    my ($auto_install, $defcfg);
    each_index {
        if ($opt eq 'auto_install' && -f $_) {
            $auto_install = $_;
            $_ = $AUTO_INSTALL_ROOTED;
        } elsif ($opt eq 'defcfg' && -f $_) {
            $defcfg = $_;
            $ARGV[$::i-1] = $ARGV[$::i] = undef;
        }
        undef $opt;
        /^--?(.*)/ and $opt = $1;
    } @ARGV;
    #- contatenate auto_install and defcfg files into a new auto_install file in install root
    my @auto_inst = grep { -f $_ } $auto_install, $defcfg;
    output($SLASH_LOCATION . $AUTO_INSTALL_ROOTED, cat_(@auto_inst)) if @auto_inst;
}