# Copyright (C) 2005 Mandriva # Olivier Blin # Copyright (C) 2017-2018 Mageia # Martin Whitaker # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software Foundation, # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA. # SYNOPSIS # -------- # This package defines a set of alternative methods for creating the images # that will be mounted as loopback filesystems when booting a Live system. # 'squashfs' is the only method that has been tested with drakiso. The other # methods were inherited from the original draklive and are most likely no # longer needed. package MGA::DrakISO::Loopback; use strict; use MDK::Common; use File::Temp; use MGA::DrakISO::Mounts; use MGA::DrakISO::Utils; use Exporter; our @ISA = qw(Exporter); our @EXPORT = qw(%loop_types); my $loop_number = 0; our %loop_types; %loop_types = ( squashfs => { read_only => 1, is_loopback => 1, modules => sub { "loop", best_squashfs4_compression($_[0]) ? "squashfs" : "squashfs_lzma" }, extension => '-lzma.sqfs', build => sub { my ($build, $dir) = @_; my $dest = $build->get_build_dir('loopbacks') . $dir->{path} . $loop_types{squashfs}{extension}; mkdir_p(dirname($dest)); my $root = $dir->{root} || $build->get_live_root; my $src = $root . $dir->{build_from}; my $total = directory_usage($src); print "Have to process " . int($total/1000000) . " MB\n" if $::verbose; my $exclude_file = tmpnam(); output_p($exclude_file, map { $root . "$_\n" } grep { run_as_root('test', '-e', $root . $_) } @{$dir->{exclude} || []}); my $sort = $build->{settings}{config_root} . '/' . $dir->{sort}; my $squashfs4_comp = best_squashfs4_compression($build); run_as_root(join(' ', $squashfs4_comp ? 'mksquashfs' : 'mksquashfs3', $src, $dest, $squashfs4_comp ? ('-comp', $squashfs4_comp) : '-lzma', '-noappend', '-b', '1048576', #'-processors', 1, '-ef', $exclude_file, if_(-f $sort, '-sort', $sort), if_($::verbose > 2, '-info', '-progress'), if_($::verbose < 2, '-no-progress'), # 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 { my ($dir) = @_; $dir->{loop} = "/dev/loop" . $loop_number++; my $extension = $dir->{path} . $loop_types{squashfs}{extension}; my $mountpoint = $dir->{mountpoint}; ( "/bin/losetup $dir->{loop} /live/media/loopbacks$extension", "nash-mount -o ro -t squashfs $dir->{loop} /live$mountpoint", ); }, }, modules => { read_only => 1, delay_mount => 1, mount => sub { my ($dir) = @_; my $path = $dir->{path}; my $mountpoint = $dir->{mountpoint}; "sh -c 'modules=;" . "for m in /live/media/loopbacks$path/*; do" . "n=\$(basename \$m);" . "n=\${n%.sqfs};" . "d=/live$mountpoint/\$n;" . "mkdir -p \$d;" . "mount -n -o loop,ro -t squashfs \$m \$d && modules=\$modules\$d=ro:;" . "done;" . "echo \$modules | sed -e s/:\$// > /live/$dir->{list}'"; }, pivot_clean => sub { my ($dir, $initrdroot) = @_; my $list = $dir->{list}; my $mountpoint = $dir->{mountpoint}; ( "sh -c 'cd $initrdroot/live$mountpoint;" . "for i in `ls -1`; do" . "mkdir -p /live$mountpoint/\$i;" . "mount -n --move \$i /live$mountpoint/\$i;" . "rmdir \$i;" . "done;" . "rmdir $initrdroot/live$mountpoint'", "sh -c 'mv $initrdroot/live/$list /live/'", ); }, }, loopfs => { is_loopback => 1, modules => [], extension => '.loop', build => sub { my ($build, $dir) = @_; my $dest = $build->get_build_dir('loopbacks') . $dir->{path} . $loop_types{loopfs}{extension}; mkdir_p(dirname($dest)); MGA::DrakISO::Utils::device_allocate_file($dest, $dir->{pre_allocate}); MGA::DrakISO::Utils::device_mkfs($dest, $dir->{fs}) if !defined $dir->{min_size}; }, mount => sub { my ($dir) = @_; $dir->{loop} = "/dev/loop" . $loop_number++; my $sqfs = $MGA::DrakISO::Mounts::dir_distrib_sqfs->{mountpoint}; my $fsck = "chroot {loop}"; my $extension = $dir->{path} . $loop_types{loopfs}{extension}; my $mountpoint = $dir->{mountpoint}; ( "losetup $dir->{loop} /live/media/loopbacks$extension", qq(sh -c "$fsck -a || $fsck -y"), "nash-mount -t $dir->{fs} $dir->{loop} /live$mountpoint", ); }, }, plain => { skip_mkdir => 1, mount => sub { my ($dir) = @_; my $mountpoint = $dir->{mountpoint}; qq(sh -c "mkdir -p /live$mountpoint"); }, }, partition => { files => [ '/sbin/fsck', '/sbin/blkid' ], mount => sub { my ($dir) = @_; my $fsck = "/bin/fsck"; my $path = $dir->{path}; my $mountpoint = $dir->{mountpoint}; ( qq(sh -c 'dev=`blkid -l -t $path -o device`; [ -z "\$dev" ] || $fsck -a \$dev || $fsck -y \$dev'), "nash-mount -t $dir->{fs} $path /live$mountpoint", ); }, }, tmpfs => { mount => sub { my ($dir) = @_; my $mnt = '/live' . $dir->{mountpoint}; my $mount_opts = $dir->{mount_opts} ? "-o $dir->{mount_opts}" : ""; my $cmd = "mount -t tmpfs $mount_opts $mnt $mnt"; $dir->{fallback} ? qq(sh -c 'if ! grep -q " $mnt " /proc/mounts; then $cmd; fi') : $cmd; }, }, ); sub has_squashfs4_with { my ($build, $comp) = @_; my $ucomp = uc($comp); cat_($build->get_live_root . "/boot/config-" . $build->find_kernel->{version}) =~ /^CONFIG_SQUASHFS_$ucomp=y$/m; } sub mksquashfs4_compressors() { map { /^Compressors available/ .. /^$/ ? if_(/^\t(\w+)/, chomp_($1)) : () } `mksquashfs 2>&1`; } sub best_squashfs4_compression { my ($build) = @_; find { has_squashfs4_with($build, $_) } intersection([ mksquashfs4_compressors() ], [ qw(xz lzma) ]); } 1;