summaryrefslogtreecommitdiffstats
path: root/lib/MGA
diff options
context:
space:
mode:
Diffstat (limited to 'lib/MGA')
-rw-r--r--lib/MGA/DrakISO/BuildBoot.pm27
-rw-r--r--lib/MGA/DrakISO/BuildLoop.pm14
-rw-r--r--lib/MGA/DrakISO/BuildMedia.pm4
-rw-r--r--lib/MGA/DrakISO/BuildRoot.pm683
-rw-r--r--lib/MGA/DrakISO/Config.pm3
-rw-r--r--lib/MGA/DrakISO/ISOBuild.pm2
-rw-r--r--lib/MGA/DrakISO/LiveBuild.pm5
-rw-r--r--lib/MGA/DrakISO/Loopback.pm11
-rw-r--r--lib/MGA/DrakISO/Utils.pm60
9 files changed, 597 insertions, 212 deletions
diff --git a/lib/MGA/DrakISO/BuildBoot.pm b/lib/MGA/DrakISO/BuildBoot.pm
index ed3347c..276217b 100644
--- a/lib/MGA/DrakISO/BuildBoot.pm
+++ b/lib/MGA/DrakISO/BuildBoot.pm
@@ -51,6 +51,8 @@ our @EXPORT = qw(prepare_live_system_boot prepare_iso_bootloader);
sub prepare_live_system_boot {
my ($build) = @_;
+ my $root = $build->get_system_root;
+
# Create a build directory. This will contain all the files we need to
# exist in /boot on the ISO.
my $boot_dir = $build->get_builddir('boot');
@@ -61,21 +63,24 @@ sub prepare_live_system_boot {
print "Using kernel $kernel->{version}\n";
# Copy the kernel into the build directory.
- my $vmlinuz = $build->get_system_root . '/boot/vmlinuz-' . $kernel->{version};
- -e $vmlinuz or die "ERROR: cannot find kernel $kernel->{version} in root system\n";
- cp_f($vmlinuz, $boot_dir . '/vmlinuz');
+ my $vmlinuz = '/boot/vmlinuz-' . $kernel->{version};
+ -e $root . $vmlinuz or die "ERROR: cannot find kernel $kernel->{version} in root system\n";
+ cp_f($root . $vmlinuz, $boot_dir . '/vmlinuz');
# Build an initrd suitable for Live boot.
- my $initrd = $build->get_system_root . '/boot/' . $build->get_initrd_name;
- unlink($initrd);
- {
- my $bootloader = {};
- local $::prefix = $build->get_system_root;
- bootloader::add_kernel($bootloader, $kernel, { label => 'linux', vga => $build->{system}{vga_mode} }, '', $build->{system}{no_initrd});
- }
+ my $initrd = '/boot/' . $build->get_initrd_name;
+ run_in_root($root, undef, 'mkinitrd', '-f', if_($::verbose < 3, '-q'), $initrd, $kernel->{version})
+ or die "ERROR: cannot create initrd\n";
+ run_as_root('chmod', '644', $root . $initrd)
+ or die "ERROR: cannot chmod initrd\n";
# Move the initrd into the build directory.
- mv($initrd, $boot_dir . '/initrd.gz') or die "ERROR: cannot move initrd: $!\n";
+ run_as_root('mv', $root . $initrd, $boot_dir . '/initrd.gz')
+ or die "ERROR: cannot move initrd\n";
+
+ # Remove anything written to /dev/null. We haven't mounted the /dev
+ # filesystem, so this will just be an ordinary file.
+ run_as_root('rm', $root . '/dev/null') if -f $root . '/dev/null';
}
###############################################################################
diff --git a/lib/MGA/DrakISO/BuildLoop.pm b/lib/MGA/DrakISO/BuildLoop.pm
index a16ecd8..01aefca 100644
--- a/lib/MGA/DrakISO/BuildLoop.pm
+++ b/lib/MGA/DrakISO/BuildLoop.pm
@@ -45,7 +45,7 @@ our @EXPORT = qw(build_live_loopback_files list_loopback_modules);
sub build_live_loopback_files {
my ($build) = @_;
# make sure no external filesystems are mounted before creating the loopback
- umount_all_in_chroot($build);
+ umount_all_in_root($build->get_system_root);
my @excluded_files = expand_file_list($build, @{$build->{loopbacks}{exclude}{files} || []});
my @modules_files = expand_file_list($build, @{$build->{loopbacks}{modules} || []});
@@ -57,11 +57,11 @@ sub build_live_loopback_files {
foreach my $module (list_loopback_modules($build)) {
my $copy_tree = $build->get_system_root . "/tmp/draklive/loop/$module->{name}";
- eval { rm_rf($copy_tree) };
+ run_as_root('rm', '-rf', $copy_tree);
hardlink_filtered($build->get_system_root, $copy_tree, $module->{files});
my $loop = $loop_types{$module->{type}};
$loop->{build}->($build, { path => "/modules/$module->{name}", root => $copy_tree, exclude => \@excluded_files });
- eval { rm_rf($copy_tree) };
+ run_as_root('rm', '-rf', $copy_tree);
}
if (@excluded_files) {
@@ -71,17 +71,17 @@ sub build_live_loopback_files {
foreach my $module (list_loopback_modules($build)) {
my $copy_tree = $build->get_system_root . "/tmp/draklive/excluded/$module->{name}";
- eval { rm_rf($copy_tree) };
+ run_as_root('rm', '-rf', $copy_tree);
hardlink_filtered($excluded_tree, $copy_tree, $module->{files});
my $loop = $loop_types{$module->{type}};
$loop->{build}->($build, { path => "/modules/excluded-$module->{name}", root => $copy_tree });
- eval { rm_rf($copy_tree) };
+ run_as_root('rm', '-rf', $copy_tree);
}
my $loop = $loop_types{$build->{loopbacks}{exclude}{type}};
$loop->{build}->($build, { path => "/excluded", root => $excluded_tree, exclude => \@modules_files });
- eval { rm_rf($excluded_tree) };
+ run_as_root('rm', '-rf', $excluded_tree);
}
}
@@ -101,7 +101,7 @@ sub hardlink_filtered {
my $list_file = tmpnam();
output_p($list_file, map { "$_\n" } grep { -e $src . $_ } @$files);
#- cpio -pldm won't copy recursively, use rsync -r instead
- system('rsync', '-ar', '--files-from=' . $list_file, '--link-dest=' . $src, $src, $dest);
+ run_as_root('rsync', '-ar', '--files-from=' . $list_file, '--link-dest=' . $src, $src, $dest);
unlink $list_file;
}
diff --git a/lib/MGA/DrakISO/BuildMedia.pm b/lib/MGA/DrakISO/BuildMedia.pm
index 8fe59bd..5e75c1c 100644
--- a/lib/MGA/DrakISO/BuildMedia.pm
+++ b/lib/MGA/DrakISO/BuildMedia.pm
@@ -175,7 +175,7 @@ sub get_available_packages {
$urpm = urpm->new;
- urpm::set_files($urpm, $build->get_system_root);
+ urpm::set_files($urpm, $build->get_chroot_dir);
urpm::get_global_options($urpm);
$urpm->{info} = sub { };
@@ -600,7 +600,7 @@ sub create_index {
sub run_urpm {
my ($build, $cmd, $parameters, $o_not_fatal) = @_;
- my $urpmi_root = '--urpmi-root ' . $build->get_system_root;
+ my $urpmi_root = '--urpmi-root ' . $build->get_chroot_dir;
my $error = system("LC_ALL=C sudo $cmd $urpmi_root $parameters");
$error == 0 || $o_not_fatal or die "ERROR: $cmd command failed\n";
diff --git a/lib/MGA/DrakISO/BuildRoot.pm b/lib/MGA/DrakISO/BuildRoot.pm
index 616e3a6..af06769 100644
--- a/lib/MGA/DrakISO/BuildRoot.pm
+++ b/lib/MGA/DrakISO/BuildRoot.pm
@@ -27,8 +27,11 @@ package MGA::DrakISO::BuildRoot;
use strict;
use MDK::Common;
+use Try::Tiny;
use common;
+use File::Temp qw(tmpnam);
+
use MGA::DrakISO::LiveBuild;
use MGA::DrakISO::Loopback;
use MGA::DrakISO::Utils;
@@ -37,163 +40,479 @@ use Exporter;
our @ISA = qw(Exporter);
our @EXPORT = qw(install_live_system customise_live_system);
+###############################################################################
+# System Installation
+###############################################################################
+
# This is the top-level function called to create the basic root filesystem. It
# uses stage2 of the Mageia installer to do the actual work. It is independent
# of any other preparatory step.
#
+# This function is largely derived from drakx_in_chroot.
+#
sub install_live_system {
my ($build) = @_;
- my $repository = $build->{settings}{repository} . '/' . $build->{settings}{arch};
+ print "Installing Live system\n" if $::verbose;
- my $drakx_in_chroot = $repository . '/misc/drakx-in-chroot';
- my $remote_repository = $repository =~ m!^(ftp|http)://! && $1;
- if ($remote_repository) {
- my $local_drakx_in_chroot = $build->get_builddir('scripts') . '/drakx-in-chroot';
- mkdir_p(dirname($local_drakx_in_chroot));
- run_('curl', '--silent', '-o', $local_drakx_in_chroot, $drakx_in_chroot)
- or die "unable to get drakx-in-chroot from remote repository\n";
- $drakx_in_chroot = $local_drakx_in_chroot;
- }
+ my $arch = $build->{settings}{arch};
- local %ENV = (
- %ENV,
- (map { "DRAKLIVE_" . uc($_->[0]) => $_->[1] } group_by2(%{$build->{settings}})),
- %{$build->{system}{install_env}},
- );
- $ENV{DRAKLIVE_LANGS} = join(':', $build->get_langs);
- run_({ targetarch => $build->{settings}{arch} },
- 'perl', $drakx_in_chroot,
- $repository,
- $build->get_system_root,
- if_($build->{system}{auto_install}, '--auto_install', $build->{settings}{config_root} . '/' . $build->{system}{auto_install}),
- if_($build->{system}{patch_install}, '--defcfg', $build->{settings}{config_root} . '/' . $build->{system}{patch_install}),
- if_($build->{system}{rpmsrate}, '--rpmsrate', $build->{settings}{config_root} . '/' . $build->{system}{rpmsrate}),
- ($build->{system}{stage2_updates} ? (map { ('--stage2-update', $build->{settings}{config_root} . '/' . $_->[0], $_->[1]) } @{$build->{system}{stage2_updates}}) : ()),
- ) or die "unable to install system chroot\n";
-}
+ my $base_repository = $build->{settings}{repository};
+ my $arch_repository = $base_repository . '/' . $arch;
+ my $remote_method = $arch_repository =~ m!^(ftp|http)://! && $1;
-# This is the top-level function called to customise the root filesystem. It
-# allows a standard Mageia installation to be fine-tuned for use as a Live
-# system. The basic root filesystem must have been prepared before calling
-# this function.
-#
-sub customise_live_system {
- my ($build) = @_;
+ my $chroot = $build->get_chroot_dir;
- my $previous_umask = umask;
- #- workaround buggy installation of directories that are not owned by any packages
- umask 022;
+ my $rooted_stage2 = '/tmp/stage2';
+ my $chroot_stage2 = $chroot . $rooted_stage2;
+
+ my $live_root = $build->get_system_root;
+ if (-e $live_root) {
+ # We want a clean start...
+ umount_all_in_root($live_root);
+ run_as_root('rm', '-rf', $live_root);
+ }
+ mkdir_p($live_root);
+
+ my $Xserver_pid;
+ my $error_message;
+ try {
+ # Mount the directory where we want to install the Live system.
+ mount($chroot . '/mnt', $live_root, '-o bind');
+
+ # Mount the standard system pseudo-filesystems, so that the installer
+ # has a proper environment to run in.
+ mount_system_fs($chroot);
+ mount($chroot . '/sys/kernel/debug', 'none', '-t debugfs');
+
+ # Mount the stage2 installer filesystem.
+ if ($remote_method) {
+ my $local_mdkinst = $chroot . '/tmp/mdkinst.sqfs';
+ system("curl --silent -o $local_mdkinst $arch_repository/install/stage2/mdkinst.sqfs")
+ or die "ERROR: failed to download mdkinst.sqfs from remote repository\n";
+ mount($chroot_stage2, $local_mdkinst, '-t squashfs -o loop,ro');
+
+ } elsif (-d $arch_repository . '/install/stage2/live') {
+ mount($chroot_stage2, $arch_repository . '/install/stage2/live', '-o bind,ro');
+
+ } elsif (-f $arch_repository . '/install/stage2/mdkinst.sqfs') {
+ mount($chroot_stage2, $arch_repository . '/install/stage2/mdkinst.sqfs', '-t squashfs -o loop,ro');
+
+ } else {
+ die "ERROR: failed to find installer stage2\n";
+ }
+
+ # The stage2 installer expects to find the full repository in this
+ # location...
+ mount($chroot . '/tmp/media', $base_repository, '-o bind,ro') if !$remote_method;
+ # and the arch-specific repository in this location.
+ symlinkf('media/' . $arch, $chroot . '/tmp/image');
+ # Because the installer uses the above symlink, relative paths in
+ # the urpmi configuration don't work unless we add this extra link.
+ symlinkf('media/i586', $chroot . '/tmp/i586') if $arch eq 'x86_64';
+
+ # If the user has provided an auto-install configuration file, use it,
+ # otherwise construct one.
+ my $rooted_auto_inst = '/tmp/auto_inst.cfg.pl';
+ my $system_auto_inst = $build->get_absolute_path($build->{system}{auto_install});
+ my $interactive;
+ if (defined $system_auto_inst) {
+ -f $system_auto_inst or die "ERROR: can't find the auto-install configuration file $system_auto_inst\n";
+ cp_f($system_auto_inst, $chroot . $rooted_auto_inst);
+ } else {
+ write_auto_inst_cfg($build, $chroot . $rooted_auto_inst, \$interactive);
+ }
+
+ # Add a few more things to complete the installer's working environment.
+
+ my $etc = $chroot . '/etc';
+ mkdir_p($etc);
+ output($etc . '/hosts', "127.0.0.1 localhost\n");
+
+ my $var = $chroot . '/var';
+ mkdir_p($var);
+
+ create_initial_symlinks($chroot, $rooted_stage2);
+
+ chomp(my $kernel_version = `uname -r`);
+ my $modules_dir = '/modules/' . $kernel_version;
+ output_p($chroot . $modules_dir . $_, "\n")
+ foreach "/lib/$modules_dir/modules.dep", "/lib/$modules_dir/modules.alias";
+
+ # If some of the installer steps will be interactive, we need to start a
+ # nested X server to display the GUI.
+ my $DISPLAY = '';
+ if ($interactive) {
+ my $Xserver = whereis_binary('Xephyr') || whereis_binary('Xnest')
+ or die "ERROR: Xephyr or Xnest not found - cannot run installer GUI\n";
+ my $screen_size = $Xserver =~ /Xephyr/ ? '-screen' : '-geometry';
+ $DISPLAY = ':8';
+ if ($Xserver_pid = fork()) {
+ } else {
+ close(STDOUT); open(STDOUT, '>', '/dev/null');
+ close(STDERR); open(STDERR, '>', '/dev/null');
+ exec($Xserver, $DISPLAY, '-ac', $screen_size, '1024x768');
+ }
+ }
+
+ # Run the installer. The chroot command sets up a new environment,
+ # so we need to set the variables we want after we've entered the
+ # chroot.
+ my $env = join(' ',
+ "PATH=/usr/sbin:/mnt/usr/sbin:/usr/bin:/mnt/usr/bin",
+ "LD_LIBRARY_PATH=/usr/lib:/mnt/usr/lib:/usr/lib64:/mnt/usr/lib64",
+ if_($remote_method, "URLPREFIX=$arch_repository"),
+ "DISPLAY=$DISPLAY",
+ "TERM=linux",
+ "HOME=/",
+ );
+ my $cmd = "/usr/bin/runinstall2 --local_install --auto_install $rooted_auto_inst";
+ $cmd .= "--method $remote_method" if $remote_method;
+ run_in_root($chroot, $arch, 'sh', '-c', "$env $cmd")
+ or die "ERROR: failed to install base system\n";
+ } catch {
+ $error_message = $_;
+ } finally {
+ # During package installation, a dbus daemon may get automatically
+ # launched in the Live system root. We need to kill it before we
+ # can unmount the root filesystem.
+ run_as_root('fuser', '-s', '-k', "$chroot/mnt");
+ # Allow a bit of time for the processes to die.
+ sleep(1);
+ # Now we can unmount everything. The order is important.
+ umount_all_in_root($live_root);
+ umount_all_in_root($chroot);
+ # And finally kill off our nested X server.
+ kill(15, $Xserver_pid) if $Xserver_pid;
+ };
+ defined $error_message && die $error_message;
+}
- mount_system_fs($build);
+sub write_auto_inst_cfg {
+ my ($build, $file, $interactive) = @_;
+
+ my $region = $build->{settings}{region};
+ my $enabled_media = $build->{system}{enabled_media};
+ my $rpmsrate_flags = $build->{system}{rpmsrate_flags};
+ my $rpmsrate_level = $build->{system}{rpmsrate_level} || 5;
+ my $include_packages = $build->{system}{include_packages};
+ my $exclude_packages = $build->{system}{exclude_packages};
+ my $preferred_packages = $build->{system}{preferred_packages};
+ my @desktops = split(/\|/, $build->{settings}{desktop});
+ my $default_user = $build->{settings}{default_user};
+ my $post_install_nr = $build->{system}{post_install_nr};
+ my $post_install = $build->{system}{post_install};
+
+ $$interactive = !$region || !$enabled_media || !$rpmsrate_flags || !$default_user;
+
+ my @text;
+ push @text, (
+ "\$o = {",
+ " security => 1,",
+ " authentication => {",
+ " shadow => 1,",
+ " local => 1,",
+ " blowfish => 1,",
+ " },",
+ );
+ push @text, (
+ " interactiveSteps => [",
+ if_(!$region,
+ " 'selectLanguage',",
+ " 'selectKeyboard',",
+ ),
+ if_(!$enabled_media,
+ " 'chooseMedia',",
+ ),
+ if_(!$rpmsrate_flags,
+ " 'choosePackages',",
+ ),
+ if_(!$default_user,
+ " 'addUser',",
+ ),
+ " ],",
+ ) if $$interactive;
+ push @text, (
+ " media => [",
+ " {",
+ " type => 'media_cfg',",
+ " url => 'drakx://media',",
+ " selected_names => '" . join(', ', @$enabled_media) . "',",
+ " },",
+ " ],",
+ " # temporary (?) fix for mga#12299",
+ " enabled_media => [ " . join(', ', map { "'$_'" } @$enabled_media) . " ],",
+ ) if $enabled_media;
+ push @text, (
+ " rpmsrate_flags_chosen => {",
+ (map { " $_ => 1," } @$rpmsrate_flags),
+ " },",
+ " compssListLevel => $rpmsrate_level,",
+ ) if $rpmsrate_flags;
+ push @text, (
+ " default_packages => [",
+ (map { " '$_'," } @$include_packages),
+ " ],",
+ ) if $include_packages;
+ push @text, (
+ " skipped_packages => [",
+ (map { " '$_'," } @$exclude_packages),
+ " ],",
+ ) if $exclude_packages;
+ push @text, (
+ " preferred_packages => '" . join(', ', @$preferred_packages) . "',",
+ ) if $preferred_packages;
+ push @text, (
+ " meta_class => 'desktop',",
+ " desktop => '$desktops[0]',",
+ ) if @desktops;
+ push @text, (
+ " autologin => '$default_user',",
+ " users => [",
+ " {",
+ " realname => '',",
+ " name => '$default_user',",
+ " shell => '/bin/bash',",
+ " icon => 'default',",
+ " groups => [],",
+ " gid => '',",
+ " uid => '',",
+ " },",
+ " ],",
+ " superuser => {",
+ " pw => '',",
+ " realname => 'root',",
+ " shell => '/bin/bash',",
+ " home => '/root',",
+ " gid => '0',",
+ " uid => '0',",
+ " },",
+ ) if $default_user;
+ push @text, (
+ " locale => {",
+ " lang => 'en_US',",
+ " country => 'US',",
+ " IM => undef,",
+ if_($region ne 'all',
+ " langs => { " . join(', ', map { "$_ => 1" } $build->get_langs) . " },",
+ ),
+ if_($region eq 'all',
+ " langs => { all => 1 },",
+ ),
+ " utf8 => 1,",
+ " },",
+ " keyboard => {",
+ " KEYBOARD => 'us',",
+ " KEYTABLE => 'us',",
+ " KBCHARSET => 'C',",
+ " GRP_TOGGLE => '',",
+ " },",
+ " timezone => {",
+ " ntp => undef,",
+ " timezone => 'America/New_York',",
+ " UTC => 1,",
+ " },",
+ ) if $region;
+ push @text, (
+ " postInstallNonRooted => \"$post_install_nr\","
+ ) if $post_install_nr;
+ push @text, (
+ " postInstall => \"$post_install\","
+ ) if $post_install;
+ push @text, (
+ " X => { disabled => 1 },",
+ " keep_unrequested_dependencies => 0,",
+ " match_all_hardware => 1,",
+ " autoExitInstall => 1,",
+ "};",
+ );
+ output($file, map { "$_\n" } @text);
+}
- #- copy resolv.conf for name resolution to work when adding media
- cp_f("/etc/resolv.conf", $build->get_system_root . "/etc/");
+sub create_initial_symlinks {
+ my ($chroot, $rooted_stage2) = @_;
- #- remove previous draklive leftovers if needed
- run_({ root => $build->get_system_root }, 'urpmi.removemedia', '-a');
+ my $chroot_stage2 = $chroot . $rooted_stage2;
- foreach (@{$build->{system}{additional_media}}) {
- run_({ root => $build->get_system_root }, 'urpmi.addmedia', if_($_->{distrib}, '--distrib'), $_->{name}, $_->{path})
- or die "unable to add media from $_->{path}\n";
- @{$_->{packages} || []} or next;
- run_({ root => $build->get_system_root, targetarch => $build->{settings}{arch} },
- 'urpmi', '--auto', '--no-verify-rpm', if_(!$_->{distrib}, '--searchmedia', $_->{name}), @{$_->{packages}})
- or die "unable to install packages from $_->{path}\n";
+ foreach my $line (cat_or_die($chroot_stage2 . '/usr/share/symlinks')) {
+ my ($from, $to_) = split(' ', $line);
+ my $to = $chroot . ($to_ || $from);
+ $from = $rooted_stage2 . $from if !$to_;
+ symlinkf($from, $to) or die "ERROR: symlinking $to failed\n";
}
- #- additional rpms may have dependencies in additional media
- if (@{$build->{system}{rpms} || []}) {
- my $rpm_tmp_dir = '/tmp/draklive_rpms';
- mkdir_p($build->get_system_root . $rpm_tmp_dir);
- cp_f((map { $build->{settings}{config_root} . '/' . $_ } @{$build->{system}{rpms}}), $build->get_system_root . $rpm_tmp_dir);
- run_({ root => $build->get_system_root, targetarch => $build->{settings}{arch} },
- 'urpmi', '--auto', '--no-verify-rpm',
- map { $rpm_tmp_dir . '/' . basename($_) } @{$build->{system}{rpms}})
- or die "unable to install additional system rpms\n";
- rm_rf($build->get_system_root . $rpm_tmp_dir);
- }
+ my $from = $rooted_stage2 . '/usr';
+ my $to = $chroot . '/usr';
+ symlinkf $from, $to or die "ERROR: symlinking $to failed\n";
- #- remove urpmi media added by drakx-in-chroot and additional media, they're unusable
- run_({ root => $build->get_system_root }, 'urpmi.removemedia', '-a');
-
- my $erase = join(' ', @{$build->{system}{erase_rpms} || []});
- run_({ root => $build->get_system_root, targetarch => $build->{settings}{arch} },
- 'sh', '-c', "rpm -qa $erase | xargs rpm -e ") if $erase;
-
- run_({ root => $build->get_system_root }, 'systemctl', if_($::verbose < 2, '-q'), 'disable', $_ . '.service')
- foreach @{$build->{system}{disable_services}};
- run_({ root => $build->get_system_root }, 'systemctl', if_($::verbose < 2, '-q'), 'disable', $_ . '.timer')
- foreach @{$build->{system}{disable_timers}};
-
- #- make sure harddrake is run:
- #- if previous HW config file is empty, we assumes DrakX has just completed the installation
- #- (do it in chroot, or else Storable from the build box may write an incompatible config file)
- run_({ root => $build->get_system_root },
- 'perl', '-MStorable', '-e', qq(Storable::store({ UNKNOWN => {} }, '/etc/sysconfig/harddrake2/previous_hw')));
-
- #- remove some build-machine specific configuration
- clean_system_conf_file($build, $_)
- foreach qw(/etc/mtab /etc/iftab /etc/shorewall/interfaces /etc/mdadm.conf),
- if_(!$build->{system}{skip_fstab}, '/etc/fstab');
- unlink($_) foreach map { glob($build->get_system_root . $_) } @{$build->{system}{remove_files} || []};
-
- if ($build->{system}{modules_conf}) {
- local $::prefix = $build->get_system_root;
- local *modules::write_preload_conf = sub {}; #- FIXME, make this an option
- my $modules_conf = modules::any_conf->vnew;
- put_in_hash($modules_conf, $build->{system}{modules_conf});
- $modules_conf->write;
+ foreach my $dir ('/bin', '/sbin', '/lib', '/lib64') {
+ $from = 'usr' . $dir;
+ $to = $chroot . $dir;
+ symlinkf($from, $to) or die "ERROR: symlinking $to failed\n";
}
+}
- my $mount_options = $build->get_media_setting('mount_options') || "defaults";
- output_with_perm($build->get_system_root . '/etc/fstab', 0644,
- $build->{mount}{overlay}
- ? "none / $build->{mount}{overlay} $mount_options 0 0\n"
- : $build->get_media_setting('source') . " / " . $build->get_media_setting('fs') . " $mount_options 1 1\n"
- ) unless $build->{system}{skip_fstab};
+###############################################################################
+# System Customisation
+###############################################################################
- #- interactive mode can lead to race in initscripts
- #- (don't use addVarsInSh from MDK::Common, it breaks shell escapes)
- substInFile { s/^PROMPT=.*/PROMPT=no/ } $build->get_system_root . '/etc/sysconfig/init';
+# This is the top-level function called to customise the root filesystem. It
+# allows the standard Mageia installation to be fine-tuned for use as a Live
+# system. The basic root filesystem must have been prepared before calling
+# this function.
+#
+sub customise_live_system {
+ my ($build) = @_;
- configure_draklive_resize($build);
+ print "Customising Live system\n" if $::verbose;
- if ($build->{system}{preselect_kdm_user}) {
- #- preselect specified user in kdm
- my $kdm_cfg = $build->get_system_root . '/etc/kde/kdm/kdmrc';
- update_gnomekderc($kdm_cfg, 'X-:0-Greeter' => (PreselectUser => 'Default', DefaultUser => $build->{system}{preselect_kdm_user})) if -f $kdm_cfg;
- }
+ my $arch = $build->{settings}{arch};
+ my $root = $build->get_system_root;
- #- apply patches and install files after the configuration is cleaned
- #- to allow special configuration files (especially modprobe.preload)
- foreach (@{$build->{system}{patches}}) {
- my $patch = $build->{settings}{config_root} . '/' . $_;
- my @args = ('-p0', '-d', $build->get_system_root, '-i', $patch);
- run_program::run('patch', '>', '/dev/null', '--dry-run', '-f', '-R', @args) || run_('patch', @args)
- or die "unable to apply patch " . $patch . "\n";
- }
+ # Workaround buggy installation of directories that are not owned by any
+ # packages.
+ my $previous_umask = umask;
+ umask 022;
- copy_files_to($build, $build->{system}{files}, $build->get_system_root);
- my @no_install_files = map { $_->[1] } grep { $_->[2] && $_->[2]{no_install} } @{$build->{system}{files}};
- output_p($build->get_system_root . '/etc/draklive-install.d/remove.d/draklive', map { "$_\n" } @no_install_files);
+ my $error_message;
+ try {
+ mount_system_fs($root);
+
+ # Copy resolv.conf for name resolution to work when adding media.
+ copy_to_root($root, '/etc/', undef, '/etc/resolv.conf');
- eval { rm_rf($build->get_builddir('files')) };
- mkdir_p($build->get_builddir('files'));
- if ($build->{media}{files}) {
- copy_files_to($build, $build->{media}{files}, $build->get_builddir('files'));
- }
- remove_files_from($build->{media}{remove_files}, $build->get_builddir('files'));
+ # Remove urpmi media added by drakx-in-chroot, they're unusable.
+ run_in_root($root, undef, 'urpmi.removemedia', if_($::verbose < 3, '-q'), '-a');
+
+ print "..adding additional media\n" if $::verbose > 1;
- run_({ targetarch => $build->{settings}{arch} },
- "chroot", $build->get_system_root, "bash", "-c", $build->{system}{final_fixes}) if $build->{system}{final_fixes};
+ # Add additional media for installing RPMs not in the main repository.
+ foreach (@{$build->{system}{additional_media}}) {
+ run_in_root($root, undef, 'urpmi.addmedia', if_($::verbose < 2, '-q'),
+ if_($_->{distrib}, '--distrib'), $_->{name}, $_->{path})
+ or die "ERROR: unable to add media from $_->{path}\n";
- clean_system_conf_file($build, "/etc/resolv.conf");
- write_dist_lists($build);
+ @{$_->{packages} || []} or next;
+
+ run_in_root($root, $arch, 'urpmi', if_($::verbose < 3, '-q'), '--auto', '--no-verify-rpm',
+ if_(!$_->{distrib}, '--searchmedia', $_->{name}), @{$_->{packages}})
+ or die "ERROR: unable to install packages from $_->{path}\n";
+ }
- umount_all_in_chroot($build);
+ print "..installing additional packages\n" if $::verbose > 1;
+
+ # Additional rpms may have dependencies in additional media.
+ if (@{$build->{system}{rpms} || []}) {
+ my $rpm_tmp_dir = '/tmp/draklive_rpms/';
+ mkdir_in_root($root, $rpm_tmp_dir);
- umask $previous_umask;
+ my @rpm_files = map { $build->get_absolute_path($_) } @{$build->{system}{rpms}};
+ copy_to_root($root, $rpm_tmp_dir, undef, @rpm_files);
+
+ @rpm_files = map { $rpm_tmp_dir . basename($_) } @{$build->{system}{rpms}};
+ run_in_root($root, $arch, 'urpmi', if_($::verbose < 3, '-q'), '--auto', '--no-verify-rpm', @rpm_files)
+ or die "ERROR: unable to install additional system rpms\n";
+
+ rm_in_root($root, $rpm_tmp_dir);
+ }
+
+ # Remove any additional media.
+ if (@{$build->{system}{additional_media}}) {
+ run_in_root($root, undef, 'urpmi.removemedia', if_($::verbose < 3, '-q'),'-a');
+ }
+
+ print "..removing unwanted packages\n" if $::verbose > 1;
+
+ # Remove any packages as requested by the user.
+ my @erase = @{$build->{system}{erase_rpms} || []};
+ run_in_root($root, $arch, 'rpm -e', @erase) if @erase;
+
+ print "..disabling unwanted services\n" if $::verbose > 1;
+
+ # Disable services as requested by the user.
+ foreach (@{$build->{system}{disable_services}}) {
+ run_in_root($root, undef, 'systemctl', if_($::verbose < 3, '-q'), 'disable', "$_.service");
+ }
+ foreach (@{$build->{system}{disable_timers}}) {
+ run_in_root($root, undef, 'systemctl', if_($::verbose < 3, '-q'), 'disable', "$_.timer");
+ }
+
+ print "..adjusting system files\n" if $::verbose > 1;
+
+ # Make sure harddrake is run:
+ # if previous HW config file is empty, we assume DrakX has just completed the installation
+ # (do it in chroot, or else Storable from the build system may write an incompatible config file)
+ run_in_root($root, undef, 'perl', '-MStorable', '-e', qq(Storable::store({ UNKNOWN => {} }, '/etc/sysconfig/harddrake2/previous_hw')));
+
+ # Remove some build-machine specific configuration.
+ foreach (qw(/etc/shorewall/interfaces /etc/mdadm.conf)) {
+ clean_system_conf_file($root . $_);
+ }
+
+ # Create fstab.
+ my $mount_options = $build->get_media_setting('mount_options') || 'defaults';
+ my $fstab_entry;
+ if ($build->{mount}{overlay}) {
+ $fstab_entry = "none / $build->{mount}{overlay} $mount_options 0 0";
+ } else {
+ $fstab_entry = $build->get_media_setting('source') . " / " . $build->get_media_setting('fs') . " $mount_options 1 1";
+ }
+ output_to_root($root, '/etc/fstab', 0644, $fstab_entry);
+
+ # Interactive mode can lead to race in initscripts.
+ run_as_root('sed', '-i', 's/^PROMPT=.*/PROMPT=no/', $root . '/etc/sysconfig/init');
+
+ configure_draklive_resize($build);
+
+ print "..copying additional files\n" if $::verbose > 1;
+
+ # Copy extra files as requested by the user.
+ foreach (@{$build->{system}{files}}) {
+ my ($source, $dest, $o_opts) = @$_;
+ mkdir_in_root($root, $dest =~ m|/$| ? $dest : dirname($dest));
+ my @sources = glob__($build->get_absolute_path($source));
+ my $mode = $o_opts && $o_opts->{mode};
+ copy_to_root($root, $dest, $mode, @sources);
+ }
+ my @no_install_files = map { $_->[1] } grep { $_->[2] && $_->[2]{no_install} } @{$build->{system}{files}};
+ my $installer_file = '/etc/draklive-install.d/remove.d/draklive';
+ mkdir_in_root($root, dirname($installer_file));
+ output_to_root($root, $installer_file, undef, @no_install_files);
+
+ print "..removing unwanted files\n" if $::verbose > 1;
+
+ # Remove any files as requested by the user.
+ my @remove = @{$build->{system}{remove_files} || []};
+ rm_in_root($root, @remove) if @remove;
+
+ print "..applying patches\n" if $::verbose > 1;
+
+ # Apply patches as requested by the user.
+ foreach (@{$build->{system}{patches}}) {
+ my $patch_file = $build->get_absolute_path($_);
+ my @patch_cmd = ( 'patch', '-p0', '-d', $root, '-i', $patch_file, if_($::verbose < 3, '-s') );
+ run_as_root(join(' ', @patch_cmd, '--dry-run -f -R > /dev/null')) || run_as_root(@patch_cmd)
+ or die "ERROR: unable to apply patch $patch_file\n";
+ }
+
+ print "..performing final fixes\n" if $::verbose > 1;
+
+ # Perform any final fixes as requested by the user.
+ if ($build->{system}{final_fixes}) {
+ run_in_root($root, $arch, 'bash', '-c', $build->{system}{final_fixes});
+ }
+
+ # Final cleanup.
+ clean_system_conf_file($root . '/etc/resolv.conf');
+
+ write_dist_lists($build);
+ } catch {
+ $error_message = $_;
+ } finally {
+ umount_all_in_root($root);
+ umask $previous_umask;
+ };
+ defined $error_message && die $error_message;
}
sub configure_draklive_resize {
@@ -202,46 +521,23 @@ sub configure_draklive_resize {
my $resizable_loopback = find { $_->{min_size} } @{$build->{mount}{dirs} || []};
if ($resizable_loopback) {
my $ext = $loop_types{$resizable_loopback->{type}}{extension};
- output($build->get_system_root . '/etc/sysconfig/draklive-resize', <<EOF);
-DRAKLIVE_RESIZE=yes
-LOOPBACK=/live/media/loopbacks$resizable_loopback->{path}$ext
-TYPE=$resizable_loopback->{fs}
-MIN_SIZE=$resizable_loopback->{min_size}
-MOUNT=/live$resizable_loopback->{mountpoint}_resized
-OLD_MOUNT=/live$resizable_loopback->{mountpoint}
-UNION=/
-EOF
+ my @text = (
+ "DRAKLIVE_RESIZE=yes",
+ "LOOPBACK=/live/media/loopbacks$resizable_loopback->{path}$ext",
+ "TYPE=$resizable_loopback->{fs}",
+ "MIN_SIZE=$resizable_loopback->{min_size}",
+ "MOUNT=/live$resizable_loopback->{mountpoint}_resized",
+ "OLD_MOUNT=/live$resizable_loopback->{mountpoint}",
+ "UNION=/",
+ );
+ output_to_root($build->get_system_root, '/etc/sysconfig/draklive-resize', undef, @text);
}
}
-sub copy_files_to {
- my ($build, $files, $root) = @_;
- foreach (@$files) {
- my ($source, $dest, $o_opts) = @$_;
- $dest = $root . '/' . $dest;
- mkdir_p($dest =~ m|/$| ? $dest : dirname($dest));
- my @sources = MGA::DrakISO::Utils::glob__($build->{settings}{config_root} . '/' . $source);
- print "copying @sources to $dest\n" if $::verbose > 1;
- cp_af(@sources, $dest);
- my $o_perm = $o_opts && $o_opts->{mode};
- chmod $o_perm, $dest if $o_perm;
- }
-}
-
-sub remove_files_from {
- my ($files, $root) = @_;
- run_('find', $root, '(', join_lists('-o', map { [ '-name', $_ ] } @$files), ')', '-exec', 'rm', '-r', '{}', ';')
- if $files && @$files;
-}
-
-sub join_lists {
- my ($separator, $head, @lists) = @_;
- @{$head || []}, map { $separator, @$_ } @lists;
-}
-
sub clean_system_conf_file {
- my ($build, $file) = @_;
- substInFile { undef $_ if /^[^#]/ } $build->get_system_root . $file;
+ my ($file) = @_;
+
+ run_as_root('sed', '-i', '/^[^#]/d', $file) if -f $file;
}
sub write_dist_lists {
@@ -250,19 +546,19 @@ sub write_dist_lists {
my $lists_dir = $build->get_builddir('dist');
mkdir_p($lists_dir);
- run_("chroot " . $build->get_system_root . " rpm -qa | sort > " .
- $lists_dir . '/' . $build->get_name . '.lst');
+ my $root = $build->get_system_root;
- run_("chroot " . $build->get_system_root . " rpm -qa --qf '%{name}\n' | sort > " .
- $lists_dir . '/' . $build->get_name . '.lst.names');
+ run_in_root($root, undef, "rpm -qa | sort > " .
+ $lists_dir . '/' . $build->get_name . '.lst');
- run_("chroot " . $build->get_system_root .
- qq( sh -c "rpm -qa --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) .
- $lists_dir . '/' . $build->get_name . '.lst.full');
+ run_in_root($root, undef, "rpm -qa --qf '%{name}\n' | sort > " .
+ $lists_dir . '/' . $build->get_name . '.lst.names');
- run_("chroot " . $build->get_system_root .
- qq( sh -c "urpmi_rpm-find-leaves | xargs rpm -q --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) .
- $lists_dir . '/' . $build->get_name . '.lst.leaves');
+ run_in_root($root, undef, qq( sh -c "rpm -qa --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) .
+ $lists_dir . '/' . $build->get_name . '.lst.full');
+
+ run_in_root($root, undef, qq( sh -c "urpmi_rpm-find-leaves | xargs rpm -q --qf '[%{NAME} %{FILESIZES} %{FILESTATES}\n]' | awk '{if(\\\$3==0) {s[\\\$1]+=\\\$2}} END{for (p in s){print s[p],p}}' | sort -n" > ) .
+ $lists_dir . '/' . $build->get_name . '.lst.leaves');
require lang;
my @live_langs = $build->get_langs;
@@ -271,4 +567,45 @@ sub write_dist_lists {
output_p($langs_file, map { lang::l2name($_) . " (" . $_ . ")\n" } sort(@langs));
}
+###############################################################################
+# Helper Functions
+###############################################################################
+
+sub mkdir_in_root {
+ my ($root, $dir) = @_;
+
+ run_as_root('mkdir', '-p', $root . $dir)
+ or die "ERROR: failed to make directory $dir in Live system root\n";
+}
+
+sub copy_to_root {
+ my ($root, $dest, $mode, @files) = @_;
+
+ run_as_root('cp', '-af', @files, $root . $dest)
+ or die "ERROR: failed to copy file to $dest in Live system root\n";
+
+ return if !defined $mode;
+
+ run_as_root('chmod', sprintf("%o", $mode), $root . $dest)
+ or die "ERROR: failed to change mode of $dest in Live system root\n";
+}
+
+sub output_to_root {
+ my ($root, $file, $mode, @text) = @_;
+
+ my $temp_file = tmpnam();
+ output($temp_file, map { "$_\n" } @text);
+ chmod($mode, $temp_file) if $mode;
+
+ run_as_root('mv', $temp_file, $root . $file)
+ or die "ERROR: failed to write $file in Live system root\n";
+}
+
+sub rm_in_root {
+ my ($root, @targets) = @_;
+
+ run_as_root('rm', '-rf', map { $root . $_ } @targets)
+ or die "ERROR: failed to remove files in Live system root\n";
+}
+
1;
diff --git a/lib/MGA/DrakISO/Config.pm b/lib/MGA/DrakISO/Config.pm
index d88df90..a3d0511 100644
--- a/lib/MGA/DrakISO/Config.pm
+++ b/lib/MGA/DrakISO/Config.pm
@@ -74,8 +74,7 @@ sub complete_config {
$build->{settings}{arch} ||= chomp_(`rpm --eval '%{_target_cpu}'`);
mkdir_p($build->get_builddir);
- mkdir_p($build->get_system_root);
- $build->{mnt} ||= $build->get_builddir('/mnt');
+ mkdir_p($build->get_chroot_dir);
}
sub dump_config {
diff --git a/lib/MGA/DrakISO/ISOBuild.pm b/lib/MGA/DrakISO/ISOBuild.pm
index edc91c1..e6c2aef 100644
--- a/lib/MGA/DrakISO/ISOBuild.pm
+++ b/lib/MGA/DrakISO/ISOBuild.pm
@@ -54,7 +54,7 @@ sub get_builddir {
$build->{settings}{workdir} . '/build/' . $build->get_name . $build->get_set_suffix . if_($o_subdir, '/' . $o_subdir);
}
-sub get_system_root {
+sub get_chroot_dir {
my ($build) = @_;
$build->{settings}{workdir} . '/chroot/' . $build->get_name . $build->get_set_suffix;
}
diff --git a/lib/MGA/DrakISO/LiveBuild.pm b/lib/MGA/DrakISO/LiveBuild.pm
index 8b61601..c41618b 100644
--- a/lib/MGA/DrakISO/LiveBuild.pm
+++ b/lib/MGA/DrakISO/LiveBuild.pm
@@ -55,6 +55,11 @@ sub get_langs {
);
}
+sub get_system_root {
+ my ($build) = @_;
+ $build->get_builddir('root');
+}
+
sub find_kernel {
my ($build) = @_;
require bootloader;
diff --git a/lib/MGA/DrakISO/Loopback.pm b/lib/MGA/DrakISO/Loopback.pm
index e06d2a4..219b9b8 100644
--- a/lib/MGA/DrakISO/Loopback.pm
+++ b/lib/MGA/DrakISO/Loopback.pm
@@ -55,14 +55,13 @@ our %loop_types;
my $root = $dir->{root} || $build->get_system_root;
my $src = $root . $dir->{build_from};
my $total = directory_usage($src);
- print "have to process " . int($total/1000000) . " MB\n";
+ print "Have to process " . int($total/1000000) . " MB\n" if $::verbose;
my $exclude_file = tmpnam();
output_p($exclude_file, map { $root . "$_\n" } grep { -e $root . $_ } @{$dir->{exclude} || []});
my $sort = $build->{settings}{config_root} . '/' . $dir->{sort};
my $squashfs4_comp = best_squashfs4_compression($build);
- run_($squashfs4_comp ? 'mksquashfs' : 'mksquashfs3',
- # unless/until we get a quiet option
- if_($::verbose < 2, '>', '/dev/null'),
+ run_as_root(join(' ',
+ $squashfs4_comp ? 'mksquashfs' : 'mksquashfs3',
$src, $dest,
$squashfs4_comp ? ('-comp', $squashfs4_comp) : '-lzma',
'-noappend', '-b', '1048576',
@@ -71,7 +70,9 @@ our %loop_types;
if_(-f $sort, '-sort', $sort),
if_($::verbose > 2, '-info', '-progress'),
if_($::verbose < 2, '-no-progress'),
- ) or die "unable to run mksquashfs\n";
+ # due to lack of a -quiet option
+ if_($::verbose < 2, '> /dev/null'),
+ )) or die "ERROR: unable to run mksquashfs\n";
unlink $exclude_file;
},
mount => sub {
diff --git a/lib/MGA/DrakISO/Utils.pm b/lib/MGA/DrakISO/Utils.pm
index 85a9892..4e85207 100644
--- a/lib/MGA/DrakISO/Utils.pm
+++ b/lib/MGA/DrakISO/Utils.pm
@@ -34,12 +34,14 @@ use IO::Select;
use Exporter;
our @ISA = qw(Exporter);
-our @EXPORT = qw(directory_usage run_ copy_or_link mount_system_fs umount_all_in_chroot);
+our @EXPORT = qw($sudo directory_usage glob__ run_ run_as_root run_in_root copy_or_link mount mount_system_fs umount_all_in_root);
+
+our $sudo = $> ? 'sudo' : '';
sub directory_usage {
my ($dir, $o_apparent) = @_;
my $apparent = $o_apparent && "--apparent-size";
- first(split /\s/, `du -s -B 1 $apparent $dir`);
+ first(split /\s/, `$sudo du -s -B 1 $apparent $dir`);
}
#- expand only if the pattern contains '*'
@@ -61,6 +63,34 @@ sub run_ {
run_program::raw($options, @cmd);
}
+sub run_as_root {
+ my (@cmd) = @_;
+
+ if (@cmd > 1) {
+ unshift @cmd, $sudo if $sudo;
+ } else {
+ @cmd[0] = join(' ', $sudo, @cmd[0]);
+ }
+ print "@cmd\n" if $::verbose > 2;
+ system(@cmd) == 0;
+}
+
+sub run_in_root {
+ my ($root, $arch, @cmd) = @_;
+
+ if (@cmd > 1) {
+ unshift @cmd, ( 'chroot', $root );
+ unshift @cmd, ( 'setarch', $arch ) if $arch;
+ unshift @cmd, $sudo if $sudo;
+ } else {
+ @cmd[0] = join(' ', $sudo, if_($arch, 'setarch', $arch), 'chroot', $root, @cmd[0]);
+ }
+ print "@cmd\n" if $::verbose > 2;
+ local %ENV = %ENV;
+ $ENV{LC_ALL} = 'C';
+ system(@cmd) == 0;
+}
+
sub device_allocate_file {
my ($device, $size) = @_;
run_('dd', "of=$device", 'count=0', 'bs=1', "seek=" . removeXiBSuffix($size));
@@ -93,20 +123,28 @@ sub copy_or_link {
or die "ERROR: couldn't link $src_file to $dst_file\n";
}
+sub mount {
+ my ($dst, $src, $o_options) = @_;
+ mkdir_p($dst);
+ system(join(' ', 'sudo mount', $o_options, $src, $dst)) == 0
+ or die "ERROR: failed to mount $src on $dst\n";
+}
+
sub mount_system_fs {
- my ($build) = @_;
- run_('mount', '-t', 'devtmpfs', '/dev', $build->get_system_root . '/dev');
- run_('mount', '-t', 'proc', '/proc', $build->get_system_root . '/proc');
- run_('mount', '-t', 'sysfs', '/sys', $build->get_system_root . '/sys');
+ my ($root) = @_;
+ mount($root . '/dev', '/dev', '--bind -o ro');
+ mount($root . '/proc', 'none', '-t proc');
+ mount($root . '/sys', 'none', '-t sysfs');
+ mount($root . '/run', 'none', '-t tmpfs');
}
-sub umount_all_in_chroot {
- my ($build) = @_;
- my $system_root = Cwd::abs_path($build->get_system_root);
- my @mounts = grep { $_ =~ $system_root } split("\n", cat_('/proc/mounts'));
+sub umount_all_in_root {
+ my ($root) = @_;
+ $root = Cwd::abs_path($root);
+ my @mounts = grep { $_ =~ $root } split("\n", cat_('/proc/mounts'));
foreach (reverse(@mounts)) {
my @field = split(' ' , $_);
- fs::mount::umount($field[1]);
+ system(join(' ', 'sudo umount', $field[1]));
}
}