package MDV::Draklive::Loopback; use MDK::Common; use File::Temp; use MDV::Draklive::Progress; use MDV::Draklive::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 ($live, $dir) = @_; my $dest = $live->get_builddir . $live->{prefix}{build}{loopbacks} . $dir->{path} . $loop_types{squashfs}{extension}; mkdir_p(dirname($dest)); my $root = $dir->{root} || $live->get_system_root; my $src = $root . $dir->{build_from}; my $total = directory_usage($src); print "have to process " . int($total/1000000) . " MB\n"; my $progress = MDV::Draklive::Progress->new($total, time(), 6); my $exclude_file = tmpnam(); output_p($exclude_file, map { $root . "$_\n" } grep { -e $root . $_ } @{$dir->{exclude} || []}); my $sort = $live->{settings}{config_root} . '/' . $dir->{sort}; my $squashfs4_comp = best_squashfs4_compression($live); run_foreach(sub { if (/^mksquashfs: file .*, uncompressed size (\d+) bytes\s*(?:DUPLICATE|LINK)?$/) { $progress->{current} += $1; $progress->show(time()); } }, $squashfs4_comp ? 'mksquashfs' : 'mksquashfs3', $src, $dest, $squashfs4_comp ? ('-comp', $squashfs4_comp) : '-lzma', '-noappend', '-no-progress', '-info', '-b', '1048576', #'-processors', 1, '-ef', $exclude_file, if_(-f $sort, '-sort', $sort), ) or die "unable to run mksquashfs\n"; $progress->end; unlink $exclude_file; }, mount => sub { my ($live, $dir) = @_; $dir->{loop} = "/dev/loop" . $loop_number++; my $media_loopbacks = $live->get_media_prefix('loopbacks'); ( "/bin/losetup $dir->{loop} $live->{prefix}{live}{mnt}$live->{prefix}{media}{mnt}${media_loopbacks}$dir->{path}$loop_types{squashfs}{extension}", "nash-mount -o ro -t squashfs $dir->{loop} $live->{prefix}{live}{mnt}$dir->{mountpoint}", ); }, }, modules => { read_only => 1, delay_mount => 1, mount => sub { my ($live, $dir) = @_; my $media_loopbacks = $live->get_media_prefix('loopbacks'); "sh -c 'modules=; for m in $live->{prefix}{live}{mnt}$live->{prefix}{media}{mnt}${media_loopbacks}$dir->{path}/*; do n=\$(basename \$m); n=\${n%.sqfs}; d=$live->{prefix}{live}{mnt}$dir->{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->{prefix}{live}{mnt}/$dir->{list}'"; }, pivot_clean => sub { my ($live, $dir, $initrdroot) = @_; ( "sh -c 'cd $initrdroot$live->{prefix}{live}{mnt}$dir->{mountpoint}; for i in `ls -1`; do mkdir -p $live->{prefix}{live}{mnt}$dir->{mountpoint}/\$i; mount -n --move \$i $live->{prefix}{live}{mnt}$dir->{mountpoint}/\$i; rmdir \$i; done; rmdir $initrdroot$live->{prefix}{live}{mnt}$dir->{mountpoint}'", "sh -c 'mv $initrdroot$live->{prefix}{live}{mnt}/$dir->{list} $live->{prefix}{live}{mnt}/'", ); }, }, loopfs => { is_loopback => 1, modules => [], extension => '.loop', build => sub { my ($live, $dir) = @_; my $dest = $live->get_builddir . $live->{prefix}{build}{loopbacks} . $dir->{path} . $loop_types{loopfs}{extension}; mkdir_p(dirname($dest)); MDV::Draklive::Utils::device_allocate_file($dest, $dir->{pre_allocate}); MDV::Draklive::Utils::device_mkfs($dest, $dir->{fs}) if !defined $dir->{min_size}; }, mount => sub { my ($live, $dir) = @_; $dir->{loop} = "/dev/loop" . $loop_number++; my $fsck = "chroot {prefix}{live}{mnt}$dir_distrib_sqfs->{mountpoint} /sbin/fsck $dir->{loop}"; my $media_loopbacks = $live->get_media_prefix('loopbacks'); ( "losetup $dir->{loop} $live->{prefix}{live}{mnt}$live->{prefix}{media}{mnt}${media_loopbacks}$dir->{path}$loop_types{loopfs}{extension}", qq(sh -c "$fsck -a || $fsck -y"), "nash-mount -t $dir->{fs} $dir->{loop} $live->{prefix}{live}{mnt}$dir->{mountpoint}", ); }, }, plain => { skip_mkdir => 1, mount => sub { my ($live, $dir) = @_; qq(sh -c "mkdir -p $live->{prefix}{live}{mnt}$dir->{mountpoint}"); }, }, partition => { files => [ '/sbin/fsck', '/sbin/blkid' ], mount => sub { my ($live, $dir) = @_; my $fsck = "/bin/fsck"; ( qq(sh -c 'dev=`blkid -l -t $dir->{path} -o device`; [ -z "\$dev" ] || $fsck -a \$dev || $fsck -y \$dev'), "nash-mount -t $dir->{fs} $dir->{path} $live->{prefix}{live}{mnt}$dir->{mountpoint}", ); }, }, tmpfs => { mount => sub { my ($live, $dir) = @_; my $mnt = $live->{prefix}{live}{mnt} . $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 get_loop_modules { my ($live, $type) = @_; my $modules = $loop_types{$_}{modules}; my $type = ref $modules; return $type eq 'CODE' ? $modules->($live) : $type eq 'ARRAY' ? @$modules : (); } sub has_squashfs4_with { my ($live, $comp) = @_; my $ucomp = uc($comp); cat_($live->get_system_root . "/boot/config-" . $live->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 ($live) = @_; find { has_squashfs4_with($live, $_) } intersection([ mksquashfs4_compressors() ], [ qw(xz lzma) ]); } 1;