summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorOlivier Blin <oblin@mandriva.com>2008-10-29 00:06:53 +0000
committerOlivier Blin <oblin@mandriva.com>2008-10-29 00:06:53 +0000
commitad0fa345dc453d2aaeaea17e62d6328ca398779a (patch)
tree4cdd7481135a1a13c8ff5f9e1738410e0504404a /lib
parent8539aef9ee6138cd81d385c75a2c222870ab5a98 (diff)
downloaddraklive-ad0fa345dc453d2aaeaea17e62d6328ca398779a.tar
draklive-ad0fa345dc453d2aaeaea17e62d6328ca398779a.tar.gz
draklive-ad0fa345dc453d2aaeaea17e62d6328ca398779a.tar.bz2
draklive-ad0fa345dc453d2aaeaea17e62d6328ca398779a.tar.xz
draklive-ad0fa345dc453d2aaeaea17e62d6328ca398779a.zip
move initrd code in new MDV::Draklive::Initrd module
Diffstat (limited to 'lib')
-rw-r--r--lib/MDV/Draklive/Initrd.pm280
1 files changed, 280 insertions, 0 deletions
diff --git a/lib/MDV/Draklive/Initrd.pm b/lib/MDV/Draklive/Initrd.pm
new file mode 100644
index 0000000..95755b6
--- /dev/null
+++ b/lib/MDV/Draklive/Initrd.pm
@@ -0,0 +1,280 @@
+package MDV::Draklive::Initrd;
+
+use MDK::Common;
+use common;
+use list_modules;
+use MDV::Draklive::Utils;
+use MDV::Draklive::StorageFS;
+use MDV::Draklive::Loopback;
+
+sub nls_modules {
+ my ($live) = @_;
+ my $fs = $live->{media}->get_media_setting('fs');
+ if_($fs eq 'vfat', 'nls_cp437'), #- default FAT codepage
+ if_($fs !~ /^ext/, map { "nls_$_" } (map { "iso8859_$_" } 1..7, 9, 13..15), 'utf8');
+}
+
+sub create_media_initrd {
+ my ($live) = @_;
+ create_initrd_for_media($live, $live->{media});
+ cp_f($live->get_builddir . $live->{prefix}{build}{boot} . $live->{media}->get_initrd_path,
+ $live->{copy_initrd}) if $live->{copy_initrd};
+}
+
+sub inst_initrd_file {
+ my ($root, $initrd_tree, $file) = @_;
+ if ($file =~ m|/s?bin/|) {
+ inst_initrd_bin($root, $initrd_tree, $file);
+ } else {
+ mkdir_p($initrd_tree . dirname($file));
+ inst_initrd_dso_deps($root, $initrd_tree, $file) if $file =~ m|/lib[^/]*/|;
+ cp_f($root . $file, $initrd_tree . $file) or die "unable to copy $file from system chroot\n";
+ }
+}
+
+sub inst_initrd_dso_deps {
+ my ($root, $initrd_tree, $dso) = @_;
+ foreach my $file (`chroot $root ldd $dso | awk '/\\// {if(\$2 == "=>") {print \$3} else {print \$1}}'`) {
+ chomp $file;
+ $file =~ s!^(/lib[^/]*)/(?:i686|tls)!$1!;
+ my ($lib_prefix, $filename) = $file =~ m|(/lib[^/]*).*/([^/]+)$| or next;
+ my $dest = $initrd_tree . $lib_prefix . '/' . $filename;
+ mkdir_p($initrd_tree . $lib_prefix);
+ -f $dest || cp_f($root . $file, $dest) or die "unable to copy $filename from system chroot\n";
+ }
+}
+sub inst_initrd_bin {
+ my ($root, $initrd_tree, $bin) = @_;
+ cp_f($root . $bin, $initrd_tree . '/bin/');
+ inst_initrd_dso_deps($root, $initrd_tree, $bin);
+}
+
+sub create_initrd_for_media {
+ my ($live, $media) = @_;
+
+ my $lib_prefix = find { glob($live->get_system_root . $_ . '/libc.so.*') } qw(/lib64 /lib);
+ $lib_prefix or die 'unable to find system libraries in /lib or /lib64';
+
+ my $initrd_tree = $live->get_builddir . $live->{prefix}{build}{initrd} . '/' . $media->{storage};
+ rm_rf($initrd_tree) if -e $initrd_tree;
+
+ mkdir_p($initrd_tree . $_) foreach
+ qw(/bin /dev /proc /sys /tmp),
+ map { $live->{prefix}{live}{mnt} . $_ }
+ $live->{prefix}{media}{mnt},
+ $live->{mount}{root},
+ map { $_->{mountpoint} } @{$live->{mount}{dirs} || []};
+
+ #- use nash with label support
+ inst_initrd_bin($live->get_system_root, $initrd_tree, '/sbin/nash');
+ inst_initrd_bin($live->get_system_root, $initrd_tree, '/usr' . $lib_prefix . '/drakx-installer-binaries/probe-modules');
+ inst_initrd_bin($live->get_system_root, $initrd_tree, '/sbin/blockdev')
+ if $media->get_media_setting('rereadpt');
+ inst_initrd_bin($live->get_system_root, $initrd_tree, '/usr/bin/strace')
+ if $live->{debug};
+
+ foreach (chomp_(run_program::rooted_get_stdout($live->get_system_root, "/usr/sbin/splashy_find_files"))) {
+ inst_initrd_file($live->get_system_root, $initrd_tree, $_);
+ }
+
+ #- busybox is required to:
+ #- detect usb-storage process (we need sh/while/ps/grep)
+ #- mount loopbacks read-only with losetup (useful over NFS)
+ my $busybox = '/usr/bin/busybox';
+ inst_initrd_bin($live->get_system_root, $initrd_tree, $busybox);
+ my $busybox_rooted = $live->get_system_root . $busybox;
+ my @l = map { /functions:/ .. /^$/ ? do { s/\s//g; split /,/ } : () } `$busybox_rooted`;
+ shift @l;
+ symlink('busybox', $initrd_tree . "/bin/$_") foreach @l;
+
+ my $fs = $media->get_media_setting('fs');
+ my @used_loop_types = uniq(map { $_->{type} } @{$live->{mount}{dirs}});
+ inst_initrd_bin($live->get_system_root, $initrd_tree, $_) foreach
+ MDV::Draklive::StorageFS::get_files($fs),
+ (map { @{$loop_types{$_} && $loop_types{$_}{files} || []} } @used_loop_types);
+
+ output_p($initrd_tree . '/etc/fstab', '');
+ output_p($initrd_tree . '/etc/mtab', '');
+
+ my $loop_nb = 254;
+ my $rrpt_dev = $media->get_media_setting('rereadpt');
+ require devices;
+ devices::make($initrd_tree . "/dev/$_") foreach
+ if_($rrpt_dev, $rrpt_dev),
+ qw(console initrd null ram systty),
+ (map { "tty$_" } 0..8),
+ (map { "loop$_" } 0 .. $loop_nb);
+ syscall_('mknod', $initrd_tree . "/dev/fb0", c::S_IFCHR(), makedev(29, 0)) or die "mknod failed (dev $_): $!";
+ #- pre-create devfsd compatibility loop devices (since busybox is still built with devfsd support)
+ mkdir_p($initrd_tree . "/dev/loop");
+ cp_af($initrd_tree . "/dev/loop$_", $initrd_tree . "/dev/loop/$_") foreach 0 .. $loop_nb;
+
+ my $kernel = $live->find_kernel;
+ print "using kernel $kernel\n";
+ my $kernel_root = "/lib/modules/" . $kernel;
+ list_modules::load_dependencies($live->get_system_root . $kernel_root . "/modules.dep");
+
+ my ($storage_modules, $skipped) = partition { list_modules::modname2filename($_) }
+ uniq(map { modules::cond_mapping_24_26($_) } category2modules($media->get_media_setting('modules')));
+ my ($extra_modules, $extra_missing) = partition { list_modules::modname2filename($_) }
+ category2modules($media->get_media_setting('media_modules')),
+ nls_modules($live),
+ $media->get_media_fs_module,
+ @{$media->get_media_setting('extra_modules') || []},
+ (map { @{$loop_types{$_}{modules} || []} } uniq(map { $_->{type} } @{$live->{mount}{dirs} || []})),
+ ($live->{mount}{overlay} ? @{$overlay{$live->{mount}{overlay}}{modules} || []} : ());
+
+ my @additional_modules = map { if_(m!([^/]+)\.ko(?:\.gz)?!, list_modules::filename2modname($1)) } @{$live->{system}{additional_modules}};
+ @$extra_modules = difference2($extra_modules, \@additional_modules);
+ if (@{$live->{system}{exclude_modules} || []}) {
+ print STDERR "excluding modules: " . join(' ', @{$live->{system}{exclude_modules}}) . "\n";
+ @$_ = difference2($_, $live->{system}{exclude_modules}) foreach $storage_modules, $extra_modules;
+ }
+
+ my @missing = sort(difference2($extra_missing, \@additional_modules));
+ @missing and die "missing mandatory modules:\n" . join("\n", @missing, '');
+
+ mkdir_p($initrd_tree . $kernel_root . "/kernel");
+ my @modules = (@$storage_modules, @$extra_modules);
+ my @modules_closure = uniq(map { list_modules::dependencies_closure($_) } @modules);
+ foreach my $m (@modules_closure) {
+ my $full = list_modules::modname2path($m);
+ mkdir_p(dirname($initrd_tree . $full));
+ cp_f($live->get_system_root . $full, $initrd_tree . $full);
+ }
+ foreach my $f (@{$live->{system}{additional_modules}}) {
+ my $destdir = $initrd_tree . $kernel_root . "/kernel";
+ if ($f =~ /.gz$/) {
+ cp_f($live->{settings}{config_root} . '/' . $f, $destdir);
+ } else {
+ my $m = basename($f);
+ run_program::run('gzip', '>', "$destdir/$m.gz", '-c', $live->{settings}{config_root} . '/' . $f);
+ }
+ }
+ run_('depmod', '-b', $initrd_tree, $kernel);
+
+ mkdir_p($initrd_tree . "/etc/blkid"); #- for nash and showlabels cache
+ mkdir_p($initrd_tree . "/lib/module-init-tools");
+ cp_f($live->get_system_root . "/lib/module-init-tools/ldetect-lst-modules.alias", $initrd_tree . "/lib/module-init-tools");
+ mkdir_p($initrd_tree . "/usr/share/ldetect-lst");
+ cp_f($live->get_system_root . "/usr/share/pci.ids", $initrd_tree . "/usr/share");
+ cp_f($live->get_system_root . "/usr/share/ldetect-lst/" . $_, $initrd_tree . "/usr/share/ldetect-lst")
+ foreach qw(fallback-modules.alias pcitable.gz usbtable.gz);
+
+ @$skipped and print STDERR "skipped modules: " . join(' ', sort(@$skipped)) . "\n";
+
+ my @extra_modules_closure = map { list_modules::modname2filename($_) }
+ uniq(map { list_modules::dependencies_closure($_) } @$extra_modules);
+ create_initrd_scriptlet($live, $media, @extra_modules_closure, @additional_modules);
+ compress_initrd_tree($live, $media);
+ add_splash($live, $media);
+}
+
+sub create_initrd_scriptlet {
+ my ($live, $media, @modules) = @_;
+ my $target = $live->{prefix}{live}{mnt} . ($live->{mount}{root} || $live->{prefix}{media}{mnt});
+ my $pre = $media->get_media_setting('pre');
+ my $fs = $media->get_media_setting('fs');
+ my $rrpt_dev = $media->get_media_setting('rereadpt');
+ my $debug_shell = "sh -c 'if grep -q initrd_debug /proc/cmdline; then exec sh </dev/console >/dev/console 2>/dev/console; fi'";
+ my ($mount_first, $mount_last) = partition { !$loop_types{$_->{type}}{delay_mount} }
+ grep { exists $loop_types{$_->{type}}{mount} } @{$live->{mount}{dirs} || []};
+
+ output_with_perm($live->get_builddir . $live->{prefix}{build}{initrd} . '/' . $media->{storage} . '/linuxrc', 0755,
+ join("\n",
+ "#!/bin/nash",
+ #- required for labels and ps
+ "nash-mount -t proc /proc /proc",
+ #- required for cdrom labels
+ "nash-mount -t sysfs /sys /sys",
+ "splashy_chvt 8",
+ "splashy boot",
+ (map { join(" ", "probe-modules", list_modules::filename2modname($_), grep { $_ } $live->{system}{module_options}{$_}) } @modules),
+ "probe-modules --$media->{storage}",
+ if_($rrpt_dev,
+ "echo *** Waiting for new partitions on device ${rrpt_dev} ***",
+ "sh -c 'while ! ls /sys/block/${rrpt_dev}/${rrpt_dev}* >/dev/null 2>&1; do sleep 3; blockdev --rereadpt /dev/${rrpt_dev} >/dev/null 2>&1; done'"),
+ $debug_shell,
+ if_($pre, deref_array($pre)),
+ "mkdevices /dev",
+ "showlabels --removable",
+ MDV::Draklive::StorageFS::get_mount($fs)->($live, $media),
+ (map { $loop_types{$_->{type}}{mount}->($live, $_) } @$mount_first, @$mount_last),
+ ($live->{mount}{overlay} ? $overlay{$live->{mount}{overlay}}{mount}->($live) : ()),
+ if_($live->{system}{initrd_pre_pivot}, deref_array($live->{system}{initrd_pre_pivot})),
+ qq(splashy_update "chroot $target"),
+ "echo 0x0100 > /proc/sys/kernel/real-root-dev",
+ "umount /sys",
+ "sh -c 'umount /proc/bus/usb 2>/dev/null'",
+ "umount /proc",
+ "pivot_root $target $target/initrd",
+ q(sh -c 'rmdir /initrd/live/union'),
+ q(sh -c 'if [ -d /initrd/live/modules ]; then cd /initrd/live/modules; for i in `ls -1`; do mkdir -p /live/modules/$i; mount -n --move $i /live/modules/$i; rmdir $i; done; rmdir /initrd/live/modules; fi'),
+ q(sh -c 'cd /initrd/live; for i in `ls -1`; do [ -d $i ] || continue; mkdir -p /live/$i; mount -n --move $i /live/$i; rmdir $i; done'),
+ q(sh -c 'mv /initrd/live/* /live/'),
+ q(rmdir /initrd/live),
+ if_($live->{system}{initrd_post}, deref_array($live->{system}{initrd_post})),
+ ""));
+}
+
+sub compress_initrd_tree {
+ my ($live, $media) = @_;
+
+ my $initrd_tree = $live->get_builddir . $live->{prefix}{build}{initrd} . '/' . $media->{storage};
+ my $size = chomp_(run_program::get_stdout("du -ks $initrd_tree | awk '{print \$1}'"));
+ my $inodes = chomp_(run_program::get_stdout("find $initrd_tree | wc -l")) + 100;
+ my $initrd_size = $size + 350 + int($inodes / 10); #- 10 inodes needs 1K
+ $initrd_size += 600; # splashy
+ my $initrd = $live->get_builddir . $live->{prefix}{build}{boot} . $media->get_initrd_path;
+ $initrd =~ s/.gz$//;
+
+ mkdir_p(dirname($initrd));
+ run_('dd', 'if=/dev/zero', "of=$initrd", 'bs=1k', "count=$initrd_size");
+ run_('mke2fs', '-q', '-m', 0, '-F', '-N', $inodes, '-s', 1, $initrd);
+ mkdir_p($live->{mnt});
+ run_('mount', '-o', 'loop', '-t', 'ext2', $initrd, $live->{mnt});
+ cp_af(glob("$initrd_tree/*"), $live->{mnt});
+ rm_rf($live->{mnt} . "/lost+found");
+ my $left = chomp_(run_program::get_stdout("df -Pk $live->{mnt} | tail -n 1 | awk '{ print \$4 }'"));
+ run_('umount', $live->{mnt});
+ $left < 200 and die "not enough room to create initrd (only ${left}K left)\n";
+ run_('gzip', '-f', '-9', $initrd);
+}
+
+sub add_splash {
+ my ($live, $media) = @_;
+ if ($live->{system}{vga_mode} && $live->{system}{splash} ne 'no') {
+ require bootloader;
+ my $initrd = $live->get_builddir . $live->{prefix}{build}{boot} . $media->get_initrd_path;
+ my $tmp_initrd = '/tmp/initrd.gz';
+ cp_f($initrd, $live->get_system_root . $tmp_initrd);
+ {
+ local $::prefix = $live->get_system_root;
+ bootloader::add_boot_splash($tmp_initrd, $live->{system}{vga_mode});
+ }
+ cp_f($live->get_system_root . $tmp_initrd, $initrd);
+ unlink($live->get_system_root . $tmp_initrd);
+ }
+}
+
+sub create_classical_initrd {
+ my ($live) = @_;
+ my $kernel = $live->find_kernel;
+ #- FIXME: use bootloader-config and allow it not to require a bootloader?
+ print "using kernel $kernel\n";
+ my $initrd_long = '/boot/initrd-'. $kernel . '.img';
+ my $initrd_short = '/boot/initrd.img';
+ my $vmlinuz_long = '/boot/vmlinuz-' . $kernel;
+ my $vmlinuz_short = '/boot/vmlinuz';
+ my $root = $live->get_system_root;
+ run_({ root => $root }, 'mkinitrd', '-v', '-f', $initrd_long, $kernel);
+ symlinkf(basename($initrd_long), $root . $initrd_short);
+ symlinkf(basename($vmlinuz_long), $root . $vmlinuz_short);
+ if ($live->{system}{vga_mode} && $live->{system}{splash} ne 'no') {
+ require bootloader;
+ local $::prefix = $live->get_system_root;
+ bootloader::add_boot_splash($initrd_long, $live->{system}{vga_mode});
+ }
+}
+
+1;