From 1e0b4cb3b06c113460771f1683b7ce91d5333fe5 Mon Sep 17 00:00:00 2001 From: Johannes 'josch' Schauer Date: Tue, 1 Jan 2019 14:28:56 +0100 Subject: [PATCH] now that fakechroot and proot are fixed, add support for for variants beyond essential and apt --- coverage.sh | 41 +++------- mmdebstrap | 222 +++++++++++++++++++++++++++++++++++----------------- 2 files changed, 164 insertions(+), 99 deletions(-) diff --git a/coverage.sh b/coverage.sh index 7bebab7..af3d935 100755 --- a/coverage.sh +++ b/coverage.sh @@ -496,14 +496,18 @@ END if [ "$variant" = standard ]; then continue fi - # FIXME: cannot test fakechroot or proot in any other variant - # than essential because of - # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=909637 case "$mode" in - fakechroot|proot) - if [ "$variant" != "essential" ]; then - continue - fi + proot) + case "$variant" in + important|debootstrap|-|standard) + # the systemd postint yields: + # chfn: PAM: System error + # adduser: `/usr/bin/chfn -f systemd Time Synchronization systemd-timesync' returned error code 1. Exiting. + # similar error with fakechroot https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=745082#75 + # https://github.com/proot-me/PRoot/issues/156 + continue + ;; + esac ;; esac print_header "mode=$mode,variant=$variant: create tarball" @@ -714,28 +718,9 @@ fi # test foreign architecture with all modes # create directory in sudo mode -# FIXME: once fakechroot and proot are fixed, we have to test more variants -# than just essential -print_header "mode=root,variant=essential: create directory" -cat << END > shared/test.sh -#!/bin/sh -set -eu -export LC_ALL=C.UTF-8 -$CMD --mode=root --variant=essential unstable /tmp/unstable-chroot.tar $mirror -tar -tf /tmp/unstable-chroot.tar | sort > tar1.txt -rm /tmp/unstable-chroot.tar -END -if [ "$HAVE_QEMU" = "yes" ]; then - ./run_qemu.sh -else - ./run_null.sh SUDO -fi -# FIXME: once fakechroot and proot are fixed, we can switch to variant=apt -# FIXME: cannot test fakechroot or proot because of -# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=909637 for mode in root unshare fakechroot proot; do - print_header "mode=$mode,variant=essential: create armhf tarball" + print_header "mode=$mode,variant=apt: create armhf tarball" if [ "$HAVE_BINFMT" != "yes" ]; then echo "HAVE_BINFMT != yes -- Skipping test..." continue @@ -757,7 +742,7 @@ export LC_ALL=C.UTF-8 prefix= [ "\$(id -u)" -eq 0 ] && [ "$mode" != "root" ] && prefix="runuser -u user --" [ "$mode" = "fakechroot" ] && prefix="\$prefix fakechroot fakeroot" -\$prefix $CMD --mode=$mode --variant=essential --architectures=armhf unstable /tmp/unstable-chroot.tar $mirror +\$prefix $CMD --mode=$mode --variant=apt --architectures=armhf unstable /tmp/unstable-chroot.tar $mirror # we ignore differences between architectures by ignoring some files # and renaming others # in fakechroot mode, we use a fake ldconfig, so we have to diff --git a/mmdebstrap b/mmdebstrap index 4f7324e..bc6a8cd 100755 --- a/mmdebstrap +++ b/mmdebstrap @@ -1025,22 +1025,75 @@ sub setup { # nothing to do } elsif (any { $_ eq $options->{variant} } ('custom', 'essential', 'apt', 'standard', 'important', 'required', 'buildd', 'minbase')) { if ($options->{mode} eq 'fakechroot') { - # FIXME: if trouble arises, look into /etc/fakechroot/*.env for - # more interesting variables to set - $ENV{FAKECHROOT_CMD_SUBST} = join ':', ( - '/bin/mount=/bin/true', - '/usr/bin/ldd=/usr/bin/ldd.fakechroot', - '/usr/bin/mkfifo=/bin/true', - '/sbin/ldconfig=/bin/true', - ); + # this borrows from and extends + # /etc/fakechroot/debootstrap.env and /etc/fakechroot/chroot.env + { + my @fakechrootsubst = (); + foreach my $dir ('/usr/sbin', '/usr/bin', '/sbin', '/bin') { + push @fakechrootsubst, "$dir/chroot=/usr/sbin/chroot.fakechroot"; + push @fakechrootsubst, "$dir/mkfifo=/bin/true"; + push @fakechrootsubst, "$dir/ldconfig=/bin/true"; + push @fakechrootsubst, "$dir/ldd=/usr/bin/ldd.fakechroot"; + push @fakechrootsubst, "$dir/ischroot=/bin/true"; + } + if (defined $ENV{FAKECHROOT_CMD_SUBST} + && $ENV{FAKECHROOT_CMD_SUBST} ne "") { + push @fakechrootsubst, split /:/, $ENV{FAKECHROOT_CMD_SUBST}; + } + $ENV{FAKECHROOT_CMD_SUBST} = join ':', @fakechrootsubst; + } + if (defined $ENV{FAKECHROOT_EXCLUDE_PATH} + && $ENV{FAKECHROOT_EXCLUDE_PATH} ne "") { + $ENV{FAKECHROOT_EXCLUDE_PATH} = "$ENV{FAKECHROOT_EXCLUDE_PATH}:/dev:/proc:/sys"; + } else { + $ENV{FAKECHROOT_EXCLUDE_PATH} = '/dev:/proc:/sys'; + } + # workaround for long unix socket path if FAKECHROOT_BASE + # exceeds the limit of 108 bytes + $ENV{FAKECHROOT_AF_UNIX_PATH} = "/tmp"; + { + my @ldsoconf = ('/etc/ld.so.conf'); + opendir(my $dh, '/etc/ld.so.conf.d') or die "Can't opendir(/etc/ld.so.conf.d): $!"; + while (my $entry = readdir $dh) { + # skip the "." and ".." entries + next if $entry eq "."; + next if $entry eq ".."; + next if $entry !~ /\.conf$/; + push @ldsoconf, "/etc/ld.so.conf.d/$entry"; + } + closedir($dh); + my @ldlibpath = (); + if (defined $ENV{LD_LIBRARY_PATH} + && $ENV{LD_LIBRARY_PATH} ne "") { + push @ldlibpath, (split /:/, $ENV{LD_LIBRARY_PATH}); + } + # FIXME: workaround allowing installation of systemd should + # live in fakechroot, see #917920 + push @ldlibpath, "/lib/systemd"; + foreach my $fname (@ldsoconf) { + open my $fh, "<", $fname or die "cannot open $fname for reading: $!"; + while (my $line = <$fh>) { + next if $line !~ /^\//; + push @ldlibpath, $line; + } + close $fh; + } + $ENV{LD_LIBRARY_PATH} = join ':', @ldlibpath; + } } # make sure that APT_CONFIG is not set when executing anything inside the # chroot my @chrootcmd = ('env', '--unset=APT_CONFIG'); if ($options->{mode} eq 'proot') { - # FIXME: proot currently cannot install apt because of https://github.com/proot-me/PRoot/issues/147 - push @chrootcmd, ('proot', '--root-id', '--bind=/dev', "--rootfs=$options->{root}", '--cwd=/'); + push @chrootcmd, ( + 'proot', + '--root-id', + '--bind=/dev', + '--bind=/proc', + '--bind=/sys', + "--rootfs=$options->{root}", + '--cwd=/'); } elsif (any { $_ eq $options->{mode} } ('root', 'unshare', 'fakechroot')) { push @chrootcmd, ('/usr/sbin/chroot', $options->{root}); } else { @@ -1223,38 +1276,45 @@ sub setup { } } - # if more than essential should be installed, make the system look - # more like a real one by creating or bind-mounting the device nodes - foreach my $file (@devfiles) { - my ($fname, $mode, $type, $linkname, $devmajor, $devminor) = @{$file}; - next if $fname eq './dev/'; - if ($type == 0) { # normal file - die "type 0 not implemented"; - } elsif ($type == 1) { # hardlink - die "type 1 not implemented"; - } elsif ($type == 2) { # symlink - if (!$options->{havemknod}) { - if ($options->{mode} eq 'fakechroot' and $linkname =~ /^\/proc/) { - # there is no /proc in fakechroot mode - next; + if (any { $_ eq $options->{mode} } ('root', 'unshare')) { + # if more than essential should be installed, make the system look + # more like a real one by creating or bind-mounting the device nodes + foreach my $file (@devfiles) { + my ($fname, $mode, $type, $linkname, $devmajor, $devminor) = @{$file}; + next if $fname eq './dev/'; + if ($type == 0) { # normal file + die "type 0 not implemented"; + } elsif ($type == 1) { # hardlink + die "type 1 not implemented"; + } elsif ($type == 2) { # symlink + if (!$options->{havemknod}) { + if ($options->{mode} eq 'fakechroot' and $linkname =~ /^\/proc/) { + # there is no /proc in fakechroot mode + next; + } + symlink $linkname, "$options->{root}/$fname" or die "cannot create symlink $fname"; + } + } elsif ($type == 3 or $type == 4) { # character/block special + if (!$options->{havemknod}) { + open my $fh, '>', "$options->{root}/$fname" or die "cannot open $options->{root}/$fname: $!"; + close $fh; + 0 == system('mount', '-o', 'bind', "/$fname", "$options->{root}/$fname") or die "mount failed: $?"; + } + } elsif ($type == 5) { # directory + if (!$options->{havemknod}) { + make_path "$options->{root}/$fname"; + chmod $mode, "$options->{root}/$fname" or die "cannot chmod $fname: $!"; } - symlink $linkname, "$options->{root}/$fname" or die "cannot create symlink $fname"; - } - } elsif ($type == 3 or $type == 4) { # character/block special - if (!$options->{havemknod}) { - open my $fh, '>', "$options->{root}/$fname" or die "cannot open $options->{root}/$fname: $!"; - close $fh; 0 == system('mount', '-o', 'bind', "/$fname", "$options->{root}/$fname") or die "mount failed: $?"; + } else { + die "unsupported type: $type"; } - } elsif ($type == 5) { # directory - if (!$options->{havemknod}) { - make_path "$options->{root}/$fname"; - chmod $mode, "$options->{root}/$fname" or die "cannot chmod $fname: $!"; - } - 0 == system('mount', '-o', 'bind', "/$fname", "$options->{root}/$fname") or die "mount failed: $?"; - } else { - die "unsupported type: $type"; } + } elsif (any { $_ eq $options->{mode} } ('proot', 'fakechroot')) { + # we cannot mount in fakechroot and proot mode + # in proot mode we have /dev bind-mounted already through --bind=/dev + } else { + die "unknown mode: $options->{mode}"; } # We can only mount /proc and /sys after extracting the essential # set because if we mount it before, then base-files will not be able @@ -1266,12 +1326,22 @@ sub setup { # we have to rbind because just using bind results in "wrong fs # type, bad option, bad superblock" error 0 == system('mount', '-o', 'rbind', '/sys', "$options->{root}/sys") or die "mount failed: $?"; - } elsif (any { $_ eq $options->{mode} } ('root', 'fakechroot', 'proot')) { + } elsif ($options->{mode} eq 'root') { 0 == system('mount', '-t', 'sysfs', '-o', 'nosuid,nodev,noexec', 'sys', "$options->{root}/sys") or die "mount failed: $?"; + } elsif (any { $_ eq $options->{mode} } ('proot', 'fakechroot')) { + # we cannot mount in fakechroot and proot mode + # in proot mode we have /proc bind-mounted already through --bind=/proc + } else { + die "unknown mode: $options->{mode}"; + } + if (any { $_ eq $options->{mode} } ('root', 'unshare')) { + 0 == system('mount', '-t', 'proc', 'proc', "$options->{root}/proc") or die "mount failed: $?"; + } elsif (any { $_ eq $options->{mode} } ('proot', 'fakechroot')) { + # we cannot mount in fakechroot and proot mode + # in proot mode we have /sys bind-mounted already through --bind=/sys } else { die "unknown mode: $options->{mode}"; } - 0 == system('mount', '-t', 'proc', 'proc', "$options->{root}/proc") or die "mount failed: $?"; # prevent daemons from starting { @@ -1302,46 +1372,54 @@ sub setup { move("$options->{root}/sbin/start-stop-daemon.REAL", "$options->{root}/sbin/start-stop-daemon") or die "cannot move start-stop-daemon"; unlink "$options->{root}/usr/sbin/policy-rc.d" or die "cannot unlink policy-rc.d"; - foreach my $file (@devfiles) { - my ($fname, undef, $type, $linkname, undef, undef) = @{$file}; - next if $fname eq './dev/'; - if ($type == 0) { # normal file - die "type 0 not implemented"; - } elsif ($type == 1) { # hardlink - die "type 1 not implemented"; - } elsif ($type == 2) { # symlink - if (!$options->{havemknod}) { - if ($options->{mode} eq 'fakechroot' and $linkname =~ /^\/proc/) { - # there is no /proc in fakechroot mode - next; + if (any { $_ eq $options->{mode} } ('root', 'unshare')) { + foreach my $file (@devfiles) { + my ($fname, undef, $type, $linkname, undef, undef) = @{$file}; + next if $fname eq './dev/'; + if ($type == 0) { # normal file + die "type 0 not implemented"; + } elsif ($type == 1) { # hardlink + die "type 1 not implemented"; + } elsif ($type == 2) { # symlink + if (!$options->{havemknod}) { + unlink "$options->{root}/$fname" or die "cannot unlink $fname: $!"; } - unlink "$options->{root}/$fname" or die "cannot unlink $fname: $!"; - } - } elsif ($type == 3 or $type == 4) { # character/block special - if (!$options->{havemknod}) { + } elsif ($type == 3 or $type == 4) { # character/block special + if (!$options->{havemknod}) { + if ($options->{mode} eq 'unshare') { + # FIXME: handle umount by a signal handler in + # case of CTRL+C + 0 == system('umount', '--no-mtab', "$options->{root}/$fname") or die "umount failed: $?"; + } elsif ($options->{mode} eq 'root') { + 0 == system('umount', "$options->{root}/$fname") or die "umount failed: $?"; + } elsif (any { $_ eq $options->{mode} } ('fakechroot', 'proot')) { + die "impossible"; + } else { + die "unknown mode: $options->{mode}"; + } + unlink "$options->{root}/$fname"; + } + } elsif ($type == 5) { # directory if ($options->{mode} eq 'unshare') { 0 == system('umount', '--no-mtab', "$options->{root}/$fname") or die "umount failed: $?"; - } elsif (any { $_ eq $options->{mode} } ('root', 'fakechroot', 'proot')) { + } elsif ($options->{mode} eq 'root') { 0 == system('umount', "$options->{root}/$fname") or die "umount failed: $?"; + } elsif (any { $_ eq $options->{mode} } ('fakechroot', 'proot')) { + die "impossible"; } else { die "unknown mode: $options->{mode}"; } - unlink "$options->{root}/$fname"; - } - } elsif ($type == 5) { # directory - if ($options->{mode} eq 'unshare') { - 0 == system('umount', '--no-mtab', "$options->{root}/$fname") or die "umount failed: $?"; - } elsif (any { $_ eq $options->{mode} } ('root', 'fakechroot', 'proot')) { - 0 == system('umount', "$options->{root}/$fname") or die "umount failed: $?"; + if (!$options->{havemknod}) { + rmdir "$options->{root}/$fname" or die "cannot rmdir $fname: $!"; + } } else { - die "unknown mode: $options->{mode}"; + die "unsupported type: $type"; } - if (!$options->{havemknod}) { - rmdir "$options->{root}/$fname" or die "cannot rmdir $fname: $!"; - } - } else { - die "unsupported type: $type"; } + } elsif (any { $_ eq $options->{mode} } ('proot', 'fakechroot')) { + # nothing was mounted + } else { + die "unknown mode: $options->{mode}"; } # naturally we have to clean up after ourselves in sudo mode where we # do a real mount. But we also need to unmount in unshare mode because @@ -1353,9 +1431,11 @@ sub setup { # unmounting /sys only seems to be successful with --lazy 0 == system('umount', '--no-mtab', '--lazy', "$options->{root}/sys") or die "umount failed: $?"; 0 == system('umount', '--no-mtab', "$options->{root}/proc") or die "umount failed: $?"; - } elsif (any { $_ eq $options->{mode} } ('root', 'fakechroot', 'proot')) { + } elsif ($options->{mode} eq 'root') { 0 == system('umount', "$options->{root}/sys") or die "umount failed: $?"; 0 == system('umount', "$options->{root}/proc") or die "umount failed: $?"; + } elsif (any { $_ eq $options->{mode} } ('proot', 'fakechroot')) { + # nothing was mounted } else { die "unknown mode: $options->{mode}"; }