Compare commits

..

No commits in common. "7d7d757f00ece2ee5fbab4d4b43824b6071bbf82" and "3fcb125e3cc6c86c2a407f8d64d67c92d0ef260d" have entirely different histories.

13 changed files with 180 additions and 223 deletions

View file

@ -88,14 +88,12 @@ def main():
) )
parser.add_argument("--mode", metavar="mode", help="only run tests with this mode") parser.add_argument("--mode", metavar="mode", help="only run tests with this mode")
parser.add_argument("--dist", metavar="dist", help="only run tests with this dist") parser.add_argument("--dist", metavar="dist", help="only run tests with this dist")
parser.add_argument(
"--variant", metavar="variant", help="only run tests with this variant"
)
args = parser.parse_args() args = parser.parse_args()
# copy over files from git or as distributed # copy over files from git or as distributed
for (git, dist, target) in [ for (git, dist, target) in [
("./mmdebstrap", "/usr/bin/mmdebstrap", "mmdebstrap"), ("./mmdebstrap", "/usr/bin/mmdebstrap", "mmdebstrap"),
("./taridshift", "/usr/bin/mmtaridshift", "taridshift"),
("./tarfilter", "/usr/bin/mmtarfilter", "tarfilter"), ("./tarfilter", "/usr/bin/mmtarfilter", "tarfilter"),
( (
"./proxysolver", "./proxysolver",
@ -225,7 +223,7 @@ def main():
) )
print("time left: %s" % timeleft, file=sys.stderr) print("time left: %s" % timeleft, file=sys.stderr)
if failed: if failed:
print("failed: %d" % len(failed), file=sys.stderr) print("failed: %d" % len(failed))
num_finished += 1 num_finished += 1
with open("tests/" + name) as fin, open("shared/test.sh", "w") as fout: with open("tests/" + name) as fin, open("shared/test.sh", "w") as fout:
for line in fin: for line in fin:
@ -259,9 +257,6 @@ def main():
if args.mode and args.mode != mode: if args.mode and args.mode != mode:
print(f"skipping because of --mode={args.mode}", file=sys.stderr) print(f"skipping because of --mode={args.mode}", file=sys.stderr)
continue continue
if args.variant and args.variant != variant:
print(f"skipping because of --variant={args.variant}", file=sys.stderr)
continue
proc = subprocess.Popen(argv) proc = subprocess.Popen(argv)
try: try:
proc.wait() proc.wait()

View file

@ -52,7 +52,7 @@ Skip-If:
fmt == "squashfs" and dist == "oldstable" # squashfs-tools-ng is not available fmt == "squashfs" and dist == "oldstable" # squashfs-tools-ng is not available
fmt == "ext2" and dist == "oldstable" # genext2fs does not support SOURCE_DATE_EPOCH fmt == "ext2" and dist == "oldstable" # genext2fs does not support SOURCE_DATE_EPOCH
Test: tarfilter-idshift Test: taridshift-utility
Needs-QEMU: true Needs-QEMU: true
Skip-If: dist == "oldstable" # python3 tarfile module does not preserve xattrs Skip-If: dist == "oldstable" # python3 tarfile module does not preserve xattrs
@ -286,10 +286,11 @@ Test: install-doc-debian
Modes: chrootless Modes: chrootless
Variants: custom Variants: custom
Test: chrootless-essential Test: install-known-good-from-essential-yes
Variants: custom Variants: custom
Modes: chrootless Modes: chrootless
Skip-If: Skip-If:
True # #1006692
dist in ["oldstable", "stable"] dist in ["oldstable", "stable"]
Test: install-doc-debian-and-output-tarball Test: install-doc-debian-and-output-tarball
@ -321,7 +322,3 @@ Modes: fakechroot
Test: dev-ptmx Test: dev-ptmx
Modes: root unshare Modes: root unshare
Needs-QEMU: true Needs-QEMU: true
Test: error-if-stdout-is-tty
Test: variant-custom-timeout

View file

@ -37,8 +37,7 @@ use Cwd qw(abs_path getcwd);
require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes) require "syscall.ph"; ## no critic (Modules::RequireBarewordIncludes)
use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD); use Fcntl qw(S_IFCHR S_IFBLK FD_CLOEXEC F_GETFD F_SETFD);
use List::Util qw(any none); use List::Util qw(any none);
use POSIX use POSIX qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime);
qw(SIGINT SIGHUP SIGPIPE SIGTERM SIG_BLOCK SIG_UNBLOCK strftime isatty);
use Carp; use Carp;
use Term::ANSIColor; use Term::ANSIColor;
use Socket; use Socket;
@ -979,24 +978,19 @@ sub run_apt_download_progress {
my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!"; my $flags = fcntl($wfh, F_GETFD, 0) or error "fcntl F_GETFD: $!";
fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC) or error "fcntl F_SETFD: $!"; fcntl($wfh, F_SETFD, $flags & ~FD_CLOEXEC) or error "fcntl F_SETFD: $!";
my $fd = fileno $wfh; my $fd = fileno $wfh;
# run_apt_progress() can raise an exception which would leave this function
# without cleaning up the other thread we started, making mmdebstrap hang
# in case run_apt_progress() fails -- so wrap this in eval() instead
eval {
# 2022-05-02, #debian-apt on OFTC, times in UTC+2 # 2022-05-02, #debian-apt on OFTC, times in UTC+2
# 16:57 < josch> DonKult: how is -oDebug::pkgDpkgPm=1 # 16:57 < josch> DonKult: how is -oDebug::pkgDpkgPm=1 -oDir::Log=/dev/null
# -oDir::Log=/dev/null a "fancy no-op"? # a "fancy no-op"?
# 11:52 < DonKult> josch: "fancy no-op" in sofar as it does nothing to # 11:52 < DonKult> josch: "fancy no-op" in sofar as it does nothing to the
# the system even through its not in a special mode # system even through its not in a special mode ala
# ala simulation or download-only. It does all the # simulation or download-only. It does all the things it
# things it normally does, except that it just prints # normally does, except that it just prints the dpkg calls
# the dpkg calls instead of execv() them which in # instead of execv() them which in practice amounts means
# practice amounts means it does nothing (the Dir::Log # it does nothing (the Dir::Log just prevents libapt from
# just prevents libapt from creating the /var/log/apt # creating the /var/log/apt directories. As the code
# directories. As the code creates them even if no # creates them even if no logs will be placed there…). As
# logs will be placed there…). As said, midterm an apt # said, midterm an apt --print-install-packages or
# --print-install-packages or something would be nice # something would be nice to avoid running everything.
# to avoid running everything.
run_apt_progress({ run_apt_progress({
ARGV => [ ARGV => [
'apt-get', 'apt-get',
@ -1017,21 +1011,13 @@ sub run_apt_download_progress {
@{ $options->{APT_ARGV} }, @{ $options->{APT_ARGV} },
], ],
}); });
};
my $err = '';
if ($@) {
$err = "apt download failed: $@";
}
# signal the child process that we are done # signal the child process that we are done
close $wfh; close $wfh;
# and then read from it what it got # and then read from it what it got
my @listofdebs = <$fh>; my @listofdebs = <$fh>;
close $fh; close $fh;
if ($? != 0) { if ($? != 0) {
$err = "status child failed"; error "status child failed";
}
if ($err) {
error $err;
} }
# remove trailing newlines # remove trailing newlines
chomp @listofdebs; chomp @listofdebs;
@ -4163,7 +4149,7 @@ sub main() {
# this is like: # this is like:
# lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC' ... # lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC' ...
# but without needing lxc # but without needing lxc
if (scalar @ARGV >= 1 && $ARGV[0] eq "--unshare-helper") { if ($ARGV[0] eq "--unshare-helper") {
if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1)) { if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1)) {
exit 1; exit 1;
} }
@ -4465,7 +4451,7 @@ sub main() {
); );
close $fh; close $fh;
if ( $? == 0 if ( $? == 0
and $content =~ /^apt (\d+\.\d+\.\d+)\w* \(\S+\)$/am) { and $content =~ /^apt ([0-9]+\.[0-9]+\.[0-9]+)[a-z0-9]* \([a-z0-9-]+\)$/m) {
$aptversion = version->new($1); $aptversion = version->new($1);
} }
if ($aptversion < "2.3.14") { if ($aptversion < "2.3.14") {
@ -5140,11 +5126,7 @@ sub main() {
$options->{sourceslists} = $sourceslists; $options->{sourceslists} = $sourceslists;
} }
if ($options->{target} eq '-') { if ($options->{target} ne '-') {
if (POSIX::isatty STDOUT) {
error "stdout is a an interactive tty";
}
} else {
my $abs_path = abs_path($options->{target}); my $abs_path = abs_path($options->{target});
if (!defined $abs_path) { if (!defined $abs_path) {
error "unable to get absolute path of target directory" error "unable to get absolute path of target directory"

View file

@ -43,53 +43,17 @@ class PaxFilterAction(argparse.Action):
setattr(namespace, "paxfilter", items) setattr(namespace, "paxfilter", items)
class TransformAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
items = getattr(namespace, "trans", [])
# This function mimics what src/transform.c from tar does
if not values.startswith("s"):
raise ValueError("regex must start with an 's'")
if len(values) <= 4:
# minimum regex: s/x//
raise ValueError("invalid regex (too short)")
d = values[1]
if values.startswith(f"s{d}{d}"):
raise ValueError("empty regex")
values = values.removeprefix(f"s{d}")
flags = 0
if values.endswith(f"{d}i"):
# trailing flags
flags = re.IGNORECASE
values = values.removesuffix(f"{d}i")
# This regex only finds non-empty tokens.
# Finding empty tokens would require a variable length look-behind
# or \K in order to find escaped delimiters which is not supported by
# the python re module.
tokens = re.findall(rf"(?:\\[\\{d}]|[^{d}])+", values)
match len(tokens):
case 0:
raise ValueError("invalid regex: not enough terms")
case 1:
repl = ""
case 2:
repl = tokens[1]
case _:
raise ValueError("invalid regex: too many terms: %s" % tokens)
items.append((re.compile(tokens[0], flags), repl))
setattr(namespace, "trans", items)
def main(): def main():
parser = argparse.ArgumentParser( parser = argparse.ArgumentParser(
formatter_class=argparse.RawDescriptionHelpFormatter,
description="""\ description="""\
Filters a tarball on standard input by the same rules as the dpkg --path-exclude Filters a tarball on standard input by the same rules as the dpkg --path-exclude
and --path-include options and writes resulting tarball to standard output. See and --path-include options and writes resulting tarball to standard output. See
dpkg(1) for information on how these two options work in detail. To reuse the dpkg(1) for information on how these two options work in detail. Since this is
exact same semantics as used by dpkg, paths must be given as /path and not as meant for filtering tarballs storing a rootfs, notice that paths must be given
./path even though they might be stored as such in the tarball. as /path and not as ./path even though they might be stored as such in the
tarball.
Secondly, filter out unwanted pax extended headers. This is useful in cases Similarly, filter out unwanted pax extended headers. This is useful in cases
where a tool only accepts certain xattr prefixes. For example tar2sqfs only where a tool only accepts certain xattr prefixes. For example tar2sqfs only
supports SCHILY.xattr.user.*, SCHILY.xattr.trusted.* and supports SCHILY.xattr.user.*, SCHILY.xattr.trusted.* and
SCHILY.xattr.security.* but not SCHILY.xattr.system.posix_acl_default.*. SCHILY.xattr.security.* but not SCHILY.xattr.system.posix_acl_default.*.
@ -101,65 +65,41 @@ Both types of options use Unix shell-style wildcards:
[seq] matches any character in seq [seq] matches any character in seq
[!seq] matches any character not in seq [!seq] matches any character not in seq
Thirdly, transform the path of tar members using a sed expression just as with Thirdly, strip leading directory components off of tar members. Just as with
GNU tar --transform.
Fourthly, strip leading directory components off of tar members. Just as with
GNU tar --strip-components, tar members that have less or equal components in GNU tar --strip-components, tar members that have less or equal components in
their path are not passed through. their path are not passed through.
"""
Lastly, shift user id and group id of each entry by the value given by the
--idshift argument. The resulting uid or gid must not be negative.
""",
) )
parser.add_argument( parser.add_argument(
"--path-exclude", "--path-exclude",
metavar="pattern", metavar="pattern",
action=PathFilterAction, action=PathFilterAction,
help="Exclude path matching the given shell pattern. " help="Exclude path matching the given shell pattern.",
"This option can be specified multiple times.",
) )
parser.add_argument( parser.add_argument(
"--path-include", "--path-include",
metavar="pattern", metavar="pattern",
action=PathFilterAction, action=PathFilterAction,
help="Re-include a pattern after a previous exclusion. " help="Re-include a pattern after a previous exclusion.",
"This option can be specified multiple times.",
) )
parser.add_argument( parser.add_argument(
"--pax-exclude", "--pax-exclude",
metavar="pattern", metavar="pattern",
action=PaxFilterAction, action=PaxFilterAction,
help="Exclude pax header matching the given globbing pattern. " help="Exclude pax header matching the given globbing pattern.",
"This option can be specified multiple times.",
) )
parser.add_argument( parser.add_argument(
"--pax-include", "--pax-include",
metavar="pattern", metavar="pattern",
action=PaxFilterAction, action=PaxFilterAction,
help="Re-include a pax header after a previous exclusion. " help="Re-include a pax header after a previous exclusion.",
"This option can be specified multiple times.",
)
parser.add_argument(
"--transform",
"--xform",
metavar="EXPRESSION",
action=TransformAction,
help="Use sed replace EXPRESSION to transform file names. "
"This option can be specified multiple times.",
) )
parser.add_argument( parser.add_argument(
"--strip-components", "--strip-components",
metavar="NUMBER", metavar="number",
type=int, type=int,
help="Strip NUMBER leading components from file names", help="Strip NUMBER leading components from file names",
) )
parser.add_argument(
"--idshift",
metavar="NUM",
type=int,
help="Integer value by which to shift the uid and gid of each entry",
)
args = parser.parse_args() args = parser.parse_args()
if ( if (
not hasattr(args, "pathfilter") not hasattr(args, "pathfilter")
@ -217,8 +157,6 @@ Lastly, shift user id and group id of each entry by the value given by the
continue continue
if args.strip_components: if args.strip_components:
comps = member.name.split("/") comps = member.name.split("/")
# just as with GNU tar, archive members with less or equal
# number of components are not passed through at all
if len(comps) <= args.strip_components: if len(comps) <= args.strip_components:
continue continue
member.name = "/".join(comps[args.strip_components :]) member.name = "/".join(comps[args.strip_components :])
@ -227,18 +165,6 @@ Lastly, shift user id and group id of each entry by the value given by the
for k, v in member.pax_headers.items() for k, v in member.pax_headers.items()
if not pax_filter_should_skip(k) if not pax_filter_should_skip(k)
} }
if args.idshift:
if args.idshift < 0 and -args.idshift > member.uid:
print("uid cannot be negative", file=sys.stderr)
exit(1)
if args.idshift < 0 and -args.idshift > member.gid:
print("gid cannot be negative", file=sys.stderr)
exit(1)
member.uid += args.idshift
member.gid += args.idshift
if hasattr(args, "trans"):
for r, s in args.trans:
member.name = r.sub(s, member.name)
if member.isfile(): if member.isfile():
with in_tar.extractfile(member) as file: with in_tar.extractfile(member) as file:
out_tar.addfile(member, file) out_tar.addfile(member, file)

67
taridshift Executable file
View file

@ -0,0 +1,67 @@
#!/usr/bin/env python3
#
# This script is in the public domain
#
# Author: Johannes Schauer Marin Rodrigues <josch@mister-muffin.de>
#
# This script accepts a tarball on standard input and prints a tarball on
# standard output with the same contents but all uid and gid ownership
# information shifted by the value given as first command line argument.
#
# A tool like this should be written in C but libarchive has issues:
# https://github.com/libarchive/libarchive/issues/587
# https://github.com/libarchive/libarchive/pull/1288/ (needs 3.4.1)
# Should these issues get fixed, then a good template is tarfilter.c in the
# examples directory of libarchive.
#
# We are not using Perl either, because Archive::Tar slurps the whole tarball
# into memory.
#
# We could also use Go but meh...
# https://stackoverflow.com/a/59542307/784669
import tarfile
import sys
import argparse
def main():
parser = argparse.ArgumentParser(
description="""\
Accepts a tarball on standard input and prints a tarball on standard output
with the same contents but all uid and gid ownership information shifted by the
value given as first command line argument.
"""
)
parser.add_argument(
"idshift",
metavar="NUM",
type=int,
help="Integer value by which to shift the uid and gid of each entry",
)
args = parser.parse_args()
# starting with Python 3.8, the default format became PAX_FORMAT, so this
# is only for compatibility with older versions of Python 3
with tarfile.open(fileobj=sys.stdin.buffer, mode="r|*") as in_tar, tarfile.open(
fileobj=sys.stdout.buffer, mode="w|", format=tarfile.PAX_FORMAT
) as out_tar:
for member in in_tar:
if args.idshift < 0 and -args.idshift > member.uid:
print("uid cannot be negative", file=sys.stderr)
exit(1)
if args.idshift < 0 and -args.idshift > member.gid:
print("gid cannot be negative", file=sys.stderr)
exit(1)
member.uid += args.idshift
member.gid += args.idshift
if member.isfile():
with in_tar.extractfile(member) as file:
out_tar.addfile(member, file)
else:
out_tar.addfile(member)
if __name__ == "__main__":
main()

View file

@ -16,7 +16,7 @@ echo "SOURCE_DATE_EPOCH=$SOURCE_DATE_EPOCH"
# mmdebstrap, resulting in different gid values # mmdebstrap, resulting in different gid values
{{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \ {{ CMD }} --variant={{ VARIANT }} --mode={{ MODE }} \
--essential-hook='if [ {{ VARIANT }} = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd; fi' \ --essential-hook='if [ {{ VARIANT }} = - ]; then echo _apt:*:100:65534::/nonexistent:/usr/sbin/nologin >> "$1"/etc/passwd; fi' \
--essential-hook='if [ {{ VARIANT }} = - ] && [ {{ DIST }} = unstable -o {{ DIST }} = testing ]; then printf "systemd-journal:x:999:\nsystemd-network:x:998:\ncrontab:x:101:" >> "$1"/etc/group; fi' \ --essential-hook='if [ {{ VARIANT }} = - ] && [ {{ DIST }} = unstable -o {{ DIST }} = testing ]; then printf "systemd-journal:x:101:\nsystemd-network:x:102:\nsystemd-resolve:x:103:\ncrontab:x:104:" >> "$1"/etc/group; fi' \
$(case {{ DIST }} in oldstable|stable) : ;; *) echo --hook-dir=./hooks/merged-usr ;; esac) \ $(case {{ DIST }} in oldstable|stable) : ;; *) echo --hook-dir=./hooks/merged-usr ;; esac) \
{{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }} {{ DIST }} /tmp/debian-{{ DIST }}-mm.tar {{ MIRROR }}
@ -32,7 +32,7 @@ tar --xattrs --xattrs-include='*' -C /tmp/debian-{{ DIST }}-debootstrap -xf "cac
tar -C /tmp/debian-{{ DIST }}-debootstrap -cf dev1.tar ./dev tar -C /tmp/debian-{{ DIST }}-debootstrap -cf dev1.tar ./dev
tar -C /tmp/debian-{{ DIST }}-mm -cf dev2.tar ./dev tar -C /tmp/debian-{{ DIST }}-mm -cf dev2.tar ./dev
ret=0 ret=0
cmp dev1.tar dev2.tar >&2 || ret=$? cmp dev1.tar dev2.tar || ret=$?
if [ "$ret" -ne 0 ]; then if [ "$ret" -ne 0 ]; then
if type diffoscope >/dev/null; then if type diffoscope >/dev/null; then
diffoscope dev1.tar dev2.tar diffoscope dev1.tar dev2.tar
@ -144,7 +144,7 @@ for f in "/var/lib/dpkg/triggers/File" "/etc/shells"; do
continue continue
fi fi
# the file must be different # the file must be different
if cmp "$f1" "$f2" >&2; then if cmp "$f1" "$f2"; then
continue continue
fi fi
# then sort both # then sort both
@ -162,27 +162,15 @@ for f in shadow shadow-; do
done done
# same as above but for cron and systemd groups # same as above but for cron and systemd groups
for f in gshadow gshadow-; do for f in gshadow gshadow-; do
for group in systemd-journal systemd-network crontab; do for group in systemd-journal systemd-network systemd-resolve crontab; do
for password in "!" "!\\*"; do if grep -q '^'"$group"':!:' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then
if grep -q '^'"$group"':'"$password"':' /tmp/debian-{{ DIST }}-debootstrap/etc/$f; then sed -i 's/^'"$group"':x::/'"$group"':!::/' /tmp/debian-{{ DIST }}-mm/etc/$f
sed -i 's/^'"$group"':x::/'"$group"':'"$password"'::/' /tmp/debian-{{ DIST }}-mm/etc/$f
fi fi
done done
done done
done
for log in faillog lastlog; do
if ! cmp /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log >&2;then
# if the files differ, make sure they are all zeroes
cmp -n $(stat -c %s /tmp/debian-{{ DIST }}-debootstrap/var/log/$log) /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /dev/zero >&2
cmp -n $(stat -c %s /tmp/debian-{{ DIST }}-mm/var/log/$log) /tmp/debian-{{ DIST }}-mm/var/log/$log /dev/zero >&2
# then delete them
rm /tmp/debian-{{ DIST }}-debootstrap/var/log/$log /tmp/debian-{{ DIST }}-mm/var/log/$log
fi
done
# workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773 # workaround for https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=917773
if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow /tmp/debian-{{ DIST }}-mm/etc/shadow >&2; then if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow /tmp/debian-{{ DIST }}-mm/etc/shadow; then
echo patching /etc/shadow on {{ DIST }} {{ VARIANT }} >&2 echo patching /etc/shadow on {{ DIST }} {{ VARIANT }} >&2
awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow > /tmp/debian-{{ DIST }}-mm/etc/shadow.bak awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow > /tmp/debian-{{ DIST }}-mm/etc/shadow.bak
cat /tmp/debian-{{ DIST }}-mm/etc/shadow.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow cat /tmp/debian-{{ DIST }}-mm/etc/shadow.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow
@ -190,7 +178,7 @@ if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow /tmp/debian-{{ DIST }}-mm
else else
echo no difference for /etc/shadow on {{ DIST }} {{ VARIANT }} >&2 echo no difference for /etc/shadow on {{ DIST }} {{ VARIANT }} >&2
fi fi
if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow- /tmp/debian-{{ DIST }}-mm/etc/shadow- >&2; then if ! cmp /tmp/debian-{{ DIST }}-debootstrap/etc/shadow- /tmp/debian-{{ DIST }}-mm/etc/shadow-; then
echo patching /etc/shadow- on {{ DIST }} {{ VARIANT }} >&2 echo patching /etc/shadow- on {{ DIST }} {{ VARIANT }} >&2
awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow- > /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak awk -v FS=: -v OFS=: -v SDE={{ SOURCE_DATE_EPOCH }} '{ print $1,$2,int(SDE/60/60/24),$4,$5,$6,$7,$8,$9 }' < /tmp/debian-{{ DIST }}-mm/etc/shadow- > /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak
cat /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow- cat /tmp/debian-{{ DIST }}-mm/etc/shadow-.bak > /tmp/debian-{{ DIST }}-mm/etc/shadow-

View file

@ -1,13 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
adduser --gecos user --disabled-password user
fi
prefix=
[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --"
$prefix fakechroot fakeroot {{ CMD }} --mode=chrootless --variant=essential {{ DIST }} /dev/null {{ MIRROR }}

View file

@ -13,10 +13,6 @@ homedir=$(runuser -u user -- sh -c 'cd && pwd')
# apt:test/integration/test-apt-key # apt:test/integration/test-apt-key
TMPDIR_ADD="This is fü\$\$ing cràzy, \$(apt -v)\$!" TMPDIR_ADD="This is fü\$\$ing cràzy, \$(apt -v)\$!"
runuser -u user -- mkdir "$homedir/$TMPDIR_ADD" runuser -u user -- mkdir "$homedir/$TMPDIR_ADD"
# make sure the unshared user can traverse into the TMPDIR
chmod 711 "$homedir"
# set permissions and sticky bit like the real /tmp
chmod 1777 "$homedir/$TMPDIR_ADD"
runuser -u user -- env TMPDIR="$homedir/$TMPDIR_ADD" {{ CMD }} --mode=unshare --variant=apt \ runuser -u user -- env TMPDIR="$homedir/$TMPDIR_ADD" {{ CMD }} --mode=unshare --variant=apt \
--setup-hook='case "$1" in '"$(quote "$homedir/$TMPDIR_ADD/mmdebstrap.")"'??????????) exit 0;; *) echo "$1"; exit 1;; esac' \ --setup-hook='case "$1" in '"$(quote "$homedir/$TMPDIR_ADD/mmdebstrap.")"'??????????) exit 0;; *) echo "$1"; exit 1;; esac' \
{{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }} {{ DIST }} /tmp/debian-chroot.tar {{ MIRROR }}

View file

@ -132,7 +132,6 @@ script -qfc "$prefix {{ CMD }} --mode={{ MODE }} --variant=apt \
{{ DIST }} /dev/null {{ MIRROR }}" /dev/null {{ DIST }} /dev/null {{ MIRROR }}" /dev/null
fail=0 fail=0
[ -r /tmp/log ] || fail=1
grep '^E:' /tmp/log && fail=1 grep '^E:' /tmp/log && fail=1
grep 'Can not write log' /tmp/log && fail=1 grep 'Can not write log' /tmp/log && fail=1
grep 'posix_openpt' /tmp/log && fail=1 grep 'posix_openpt' /tmp/log && fail=1

View file

@ -1,12 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
ret=0
script -qfec "{{ CMD }} --mode={{ MODE }} --variant=apt {{ DIST }} - {{ MIRROR }}" /dev/null || ret=$?
if [ "$ret" = 0 ]; then
echo expected failure but got exit $ret >&2
exit 1
fi

View file

@ -0,0 +1,43 @@
#!/bin/sh
#
# regularly check whether more packages work with chrootless:
# for p in $(grep-aptavail -F Essential yes -s Package -n | sort -u); do ./mmdebstrap -- mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg, findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed, sysvinit-utils,tar,$p unstable /dev/null; done
#
# see https://bugs.debian.org/cgi-bin/pkgreport.cgi?users=debian-dpkg@lists.debian.org;tag=dpkg- root-support
#
# base-files: #824594
# base-passwd: debconf
# bash: depends base-files
# bsdutils: ok
# coreutils: ok
# dash: debconf
# debianutils: ok
# diffutils: ok
# dpkg: ok
# findutils: ok
# grep: ok
# gzip: ok
# hostname: ok
# init-system-helpers: ok
# libc-bin: #983412
# login: debconf
# ncurses-base: ok
# ncurses-bin: ok
# perl-base: ok
# sed: ok
# sysvinit-utils: ok
# tar: ok
# util-linux: debconf
set -eu
export LC_ALL=C.UTF-8
if [ "$(id -u)" -eq 0 ] && ! id -u user > /dev/null 2>&1; then
if [ ! -e /mmdebstrap-testenv ]; then
echo "this test modifies the system and should only be run inside a container" >&2
exit 1
fi
adduser --gecos user --disabled-password user
fi
prefix=
[ "$(id -u)" -eq 0 ] && prefix="runuser -u user --"
$prefix {{ CMD }} --mode=chrootless --variant=custom --include=bsdutils,coreutils,debianutils,diffutils,dpkg,findutils,grep,gzip,hostname,init-system-helpers,ncurses-base,ncurses-bin,perl-base,sed,sysvinit-utils,tar {{ DIST }} /dev/null {{ MIRROR }}

View file

@ -10,12 +10,12 @@ adduser --gecos user --disabled-password user
echo user:100000:65536 | cmp /etc/subuid - echo user:100000:65536 | cmp /etc/subuid -
echo user:100000:65536 | cmp /etc/subgid - echo user:100000:65536 | cmp /etc/subgid -
sysctl -w kernel.unprivileged_userns_clone=1 sysctl -w kernel.unprivileged_userns_clone=1
# include iputils-ping so that we can verify that tarfilter does not remove # include iputils-ping so that we can verify that taridshift does not remove
# extended attributes # extended attributes
# run through tarshift no-op to create a tarball that should be bit-by-bit # run through tarshift no-op to create a tarball that should be bit-by-bit
# identical to a round trip through "tarfilter --idshift X" and "tarfilter --idshift -X" # identical to a round trip through "taridshift X" and "taridshift -X"
runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=iputils-ping {{ DIST }} - {{ MIRROR }} \ runuser -u user -- {{ CMD }} --mode=unshare --variant=apt --include=iputils-ping {{ DIST }} - {{ MIRROR }} \
| ./tarfilter --idshift 0 > /tmp/debian-chroot.tar | ./taridshift 0 > /tmp/debian-chroot.tar
# make sure that xattrs are set in the original tarball # make sure that xattrs are set in the original tarball
mkdir /tmp/debian-chroot mkdir /tmp/debian-chroot
tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./bin/ping tar --xattrs --xattrs-include='*' --directory /tmp/debian-chroot -xf /tmp/debian-chroot.tar ./bin/ping
@ -25,9 +25,9 @@ rm /tmp/debian-chroot/bin/ping
rmdir /tmp/debian-chroot/bin rmdir /tmp/debian-chroot/bin
rmdir /tmp/debian-chroot rmdir /tmp/debian-chroot
# shift the uid/gid forward by 100000 and backward by 100000 # shift the uid/gid forward by 100000 and backward by 100000
./tarfilter --idshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar ./taridshift 100000 < /tmp/debian-chroot.tar > /tmp/debian-chroot-shifted.tar
./tarfilter --idshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar ./taridshift -100000 < /tmp/debian-chroot-shifted.tar > /tmp/debian-chroot-shiftedback.tar
# the tarball before and after the roundtrip through tarfilter should be bit # the tarball before and after the roundtrip through taridshift should be bit
# by bit identical # by bit identical
cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar cmp /tmp/debian-chroot.tar /tmp/debian-chroot-shiftedback.tar
# manually adjust uid/gid and compare "tar -t" output # manually adjust uid/gid and compare "tar -t" output

View file

@ -1,11 +0,0 @@
#!/bin/sh
set -eu
export LC_ALL=C.UTF-8
# mmdebstrap used to hang forever if apt in custom mode failed to resolve
# dependencies because a process died without cleaning up its children.
# https://bugs.debian.org/1017795
ret=0
{{ CMD }} --mode={{ MODE }} --variant=custom \
--include=this-package-does-not-exist {{ DIST }} /dev/null {{ MIRROR }} || ret=1
[ $ret -eq 1 ]