|
|
|
@ -23,7 +23,7 @@
|
|
|
|
|
use strict;
|
|
|
|
|
use warnings;
|
|
|
|
|
|
|
|
|
|
our $VERSION = '1.3.3';
|
|
|
|
|
our $VERSION = '1.3.5';
|
|
|
|
|
|
|
|
|
|
use English;
|
|
|
|
|
use Getopt::Long;
|
|
|
|
@ -304,15 +304,19 @@ sub shellescape {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub test_unshare_userns {
|
|
|
|
|
my $verbose = shift;
|
|
|
|
|
my $unshare_fail = shift;
|
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
|
my $msg = "cannot unshare user namespace when executing as root";
|
|
|
|
|
my $verbose = shift;
|
|
|
|
|
|
|
|
|
|
local *maybe_error = sub {
|
|
|
|
|
my $msg = shift;
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
error $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
|
maybe_error("cannot unshare user namespace when executing as root");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
# arguments to syscalls have to be stored in their own variable or
|
|
|
|
@ -326,12 +330,7 @@ sub test_unshare_userns {
|
|
|
|
|
if ($ret == 0) {
|
|
|
|
|
exit 0;
|
|
|
|
|
} else {
|
|
|
|
|
my $msg = "unshare syscall failed: $!";
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
maybe_error("unshare syscall failed: $!");
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -344,120 +343,140 @@ sub test_unshare_userns {
|
|
|
|
|
system "newuidmap 2>/dev/null";
|
|
|
|
|
if (($? >> 8) != 1) {
|
|
|
|
|
if (($? >> 8) == 127) {
|
|
|
|
|
my $msg = "cannot find newuidmap";
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
if ($unshare_fail) {
|
|
|
|
|
error $msg;
|
|
|
|
|
} else {
|
|
|
|
|
warning $msg;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
maybe_error("cannot find newuidmap");
|
|
|
|
|
} else {
|
|
|
|
|
my $msg = "newuidmap returned unknown exit status: $?";
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
maybe_error("newuidmap returned unknown exit status: $?");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
system "newgidmap 2>/dev/null";
|
|
|
|
|
if (($? >> 8) != 1) {
|
|
|
|
|
if (($? >> 8) == 127) {
|
|
|
|
|
my $msg = "cannot find newgidmap";
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
maybe_error("cannot find newgidmap");
|
|
|
|
|
} else {
|
|
|
|
|
my $msg = "newgidmap returned unknown exit status: $?";
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
maybe_error("newgidmap returned unknown exit status: $?");
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
my @idmap = read_subuid_subgid($verbose);
|
|
|
|
|
if (scalar @idmap == 0) {
|
|
|
|
|
maybe_error("failed to parse /etc/subuid and /etc/subgid");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
# too much can go wrong when doing the dance required to unsharing the user
|
|
|
|
|
# namespace, so instead of adding more complexity to support maybe_error()
|
|
|
|
|
# to a function that is already too complex, we use eval()
|
|
|
|
|
eval {
|
|
|
|
|
$pid = get_unshare_cmd(
|
|
|
|
|
sub {
|
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
|
exit 0;
|
|
|
|
|
} else {
|
|
|
|
|
exit 1;
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
\@idmap
|
|
|
|
|
);
|
|
|
|
|
waitpid $pid, 0;
|
|
|
|
|
if ($? != 0) {
|
|
|
|
|
maybe_error("failed to unshare the user namespace");
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if ($@) {
|
|
|
|
|
maybe_error($@);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub read_subuid_subgid() {
|
|
|
|
|
sub read_subuid_subgid {
|
|
|
|
|
my $verbose = shift;
|
|
|
|
|
my @result = ();
|
|
|
|
|
my $username = getpwuid $REAL_USER_ID;
|
|
|
|
|
my ($subid, $num_subid, $fh, $n);
|
|
|
|
|
my @result = ();
|
|
|
|
|
|
|
|
|
|
local *maybe_warn = sub {
|
|
|
|
|
my $msg = shift;
|
|
|
|
|
if ($verbose) {
|
|
|
|
|
warning $msg;
|
|
|
|
|
} else {
|
|
|
|
|
debug $msg;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
if (!-e "/etc/subuid") {
|
|
|
|
|
warning "/etc/subuid doesn't exist";
|
|
|
|
|
maybe_warn("/etc/subuid doesn't exist");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!-r "/etc/subuid") {
|
|
|
|
|
warning "/etc/subuid is not readable";
|
|
|
|
|
maybe_warn("/etc/subuid is not readable");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
open $fh, "<", "/etc/subuid"
|
|
|
|
|
or error "cannot open /etc/subuid for reading: $!";
|
|
|
|
|
or maybe_warn("cannot open /etc/subuid for reading: $!");
|
|
|
|
|
if (!$fh) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (my $line = <$fh>) {
|
|
|
|
|
($n, $subid, $num_subid) = split(/:/, $line, 3);
|
|
|
|
|
last if ($n eq $username);
|
|
|
|
|
}
|
|
|
|
|
close $fh;
|
|
|
|
|
if (!length $subid) {
|
|
|
|
|
warning "/etc/subuid is empty";
|
|
|
|
|
maybe_warn("/etc/subuid is empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ($n ne $username) {
|
|
|
|
|
warning "no entry in /etc/subuid for $username";
|
|
|
|
|
maybe_warn("no entry in /etc/subuid for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
push @result, ["u", 0, $subid, $num_subid];
|
|
|
|
|
|
|
|
|
|
if (scalar(@result) < 1) {
|
|
|
|
|
warning "/etc/subuid does not contain an entry for $username";
|
|
|
|
|
maybe_warn("/etc/subuid does not contain an entry for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (scalar(@result) > 1) {
|
|
|
|
|
warning "/etc/subuid contains multiple entries for $username";
|
|
|
|
|
maybe_warn("/etc/subuid contains multiple entries for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!-e "/etc/subgid") {
|
|
|
|
|
warning "/etc/subgid doesn't exist";
|
|
|
|
|
maybe_warn("/etc/subgid doesn't exist");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (!-r "/etc/subgid") {
|
|
|
|
|
warning "/etc/subgid is not readable";
|
|
|
|
|
maybe_warn("/etc/subgid is not readable");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
open $fh, "<", "/etc/subgid"
|
|
|
|
|
or error "cannot open /etc/subgid for reading: $!";
|
|
|
|
|
or maybe_warn("cannot open /etc/subgid for reading: $!");
|
|
|
|
|
if (!$fh) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
while (my $line = <$fh>) {
|
|
|
|
|
($n, $subid, $num_subid) = split(/:/, $line, 3);
|
|
|
|
|
last if ($n eq $username);
|
|
|
|
|
}
|
|
|
|
|
close $fh;
|
|
|
|
|
if (!length $subid) {
|
|
|
|
|
warning "/etc/subgid is empty";
|
|
|
|
|
maybe_warn("/etc/subgid is empty");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if ($n ne $username) {
|
|
|
|
|
warning "no entry in /etc/subgid for $username";
|
|
|
|
|
maybe_warn("no entry in /etc/subgid for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
push @result, ["g", 0, $subid, $num_subid];
|
|
|
|
|
|
|
|
|
|
if (scalar(@result) < 2) {
|
|
|
|
|
warning "/etc/subgid does not contain an entry for $username";
|
|
|
|
|
maybe_warn("/etc/subgid does not contain an entry for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (scalar(@result) > 2) {
|
|
|
|
|
warning "/etc/subgid contains multiple entries for $username";
|
|
|
|
|
maybe_warn("/etc/subgid contains multiple entries for $username");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -1594,6 +1613,9 @@ sub run_hooks {
|
|
|
|
|
if (length $ENV{APT_CONFIG}) {
|
|
|
|
|
push @env_opts, "MMDEBSTRAP_APT_CONFIG=$ENV{APT_CONFIG}";
|
|
|
|
|
}
|
|
|
|
|
# I hook script that wants to call mmdebstrap with --hook-helper needs to
|
|
|
|
|
# know how mmdebstrap was executed
|
|
|
|
|
push @env_opts, "MMDEBSTRAP_ARGV0=$PROGRAM_NAME";
|
|
|
|
|
# Storing the mode is important for hook scripts to potentially change
|
|
|
|
|
# their behavior depending on the mode. It's also important for when the
|
|
|
|
|
# hook wants to use the mmdebstrap --hook-helper.
|
|
|
|
@ -1801,6 +1823,25 @@ sub setup {
|
|
|
|
|
|
|
|
|
|
run_hooks('setup', $options);
|
|
|
|
|
|
|
|
|
|
# apt runs dpkg from inside the chroot and directly passes the filename to
|
|
|
|
|
# dpkg. Hence, the included files on the outside must be present under the
|
|
|
|
|
# same path on the inside. If they are not, dpkg cannot find them.
|
|
|
|
|
if (scalar(grep { /^\// } @{ $options->{include} }) > 0) {
|
|
|
|
|
my $ret = 0;
|
|
|
|
|
foreach my $f (grep { /^\// } @{ $options->{include} }) {
|
|
|
|
|
next if -e "$options->{root}/$f";
|
|
|
|
|
warning
|
|
|
|
|
"path given via --include is not present inside the chroot: $f";
|
|
|
|
|
$ret = 1;
|
|
|
|
|
}
|
|
|
|
|
if ($ret != 0) {
|
|
|
|
|
warning("apt runs chrooted dpkg which needs access to the "
|
|
|
|
|
. "package paths given via --include inside the chroot.");
|
|
|
|
|
warning "maybe try running mmdebstrap with "
|
|
|
|
|
. "--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (any { $_ eq 'update' } @{ $options->{skip} }) {
|
|
|
|
|
info "skipping update as requested";
|
|
|
|
|
} else {
|
|
|
|
@ -2246,7 +2287,7 @@ sub run_setup() {
|
|
|
|
|
# we have to make the config file world readable so that a possible
|
|
|
|
|
# /usr/lib/apt/solvers/apt process which is run by the _apt user is also
|
|
|
|
|
# able to read it
|
|
|
|
|
chmod 0666, "$tmpfile" or error "cannot chmod $tmpfile: $!";
|
|
|
|
|
chmod 0644, "$tmpfile" or error "cannot chmod $tmpfile: $!";
|
|
|
|
|
if ($verbosity_level >= 3) {
|
|
|
|
|
0 == system('apt-get', '--version')
|
|
|
|
|
or error "apt-get --version failed: $?";
|
|
|
|
@ -4348,12 +4389,12 @@ sub main() {
|
|
|
|
|
# lxc-usernsexec -- lxc-unshare -s 'MOUNT|PID|UTSNAME|IPC' ...
|
|
|
|
|
# but without needing lxc
|
|
|
|
|
if (scalar @ARGV >= 1 && $ARGV[0] eq "--unshare-helper") {
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1)) {
|
|
|
|
|
exit 1;
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0) {
|
|
|
|
|
test_unshare_userns(1);
|
|
|
|
|
}
|
|
|
|
|
my @idmap = ();
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0) {
|
|
|
|
|
@idmap = read_subuid_subgid;
|
|
|
|
|
@idmap = read_subuid_subgid 1;
|
|
|
|
|
}
|
|
|
|
|
my $pid = get_unshare_cmd(
|
|
|
|
|
sub {
|
|
|
|
@ -4423,10 +4464,8 @@ sub main() {
|
|
|
|
|
my ($opt_name, $opt_value) = @_;
|
|
|
|
|
my $sanitize_path = sub {
|
|
|
|
|
my $pkg = shift;
|
|
|
|
|
$pkg = abs_path($pkg);
|
|
|
|
|
if (!defined $pkg) {
|
|
|
|
|
error "cannot resolve absolute path of $pkg: $!";
|
|
|
|
|
}
|
|
|
|
|
$pkg = abs_path($pkg)
|
|
|
|
|
// error "cannot resolve absolute path of $pkg: $!";
|
|
|
|
|
if ($pkg !~ /^\//) {
|
|
|
|
|
error "absolute path of $pkg doesn't start with a slash";
|
|
|
|
|
}
|
|
|
|
@ -4781,7 +4820,8 @@ sub main() {
|
|
|
|
|
}
|
|
|
|
|
exec 'fakechroot', 'fakeroot', @prefix, $PROGRAM_NAME, @ARGVORIG;
|
|
|
|
|
} else {
|
|
|
|
|
error "unable to pick chroot mode automatically";
|
|
|
|
|
error( "unable to pick chroot mode automatically (use --mode for "
|
|
|
|
|
. "manual selection)");
|
|
|
|
|
}
|
|
|
|
|
info "automatically chosen mode: $options->{mode}";
|
|
|
|
|
} elsif ($options->{mode} eq 'root') {
|
|
|
|
@ -4816,26 +4856,8 @@ sub main() {
|
|
|
|
|
}
|
|
|
|
|
# ...or we are not root and then we need to be able to unshare the user
|
|
|
|
|
# namespace.
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0 && !test_unshare_userns(1, 1)) {
|
|
|
|
|
my $procfile = '/proc/sys/kernel/unprivileged_userns_clone';
|
|
|
|
|
open(my $fh, '<', $procfile)
|
|
|
|
|
or error "failed to open $procfile: $!";
|
|
|
|
|
chomp(
|
|
|
|
|
my $content = do { local $/; <$fh> }
|
|
|
|
|
);
|
|
|
|
|
close($fh);
|
|
|
|
|
if ($content ne "1") {
|
|
|
|
|
info "/proc/sys/kernel/unprivileged_userns_clone is set to"
|
|
|
|
|
. " $content";
|
|
|
|
|
info "Try running:";
|
|
|
|
|
info " sudo sysctl -w kernel.unprivileged_userns_clone=1";
|
|
|
|
|
info "or permanently enable unprivileged usernamespaces by"
|
|
|
|
|
. " putting the setting into /etc/sysctl.d/";
|
|
|
|
|
info "THIS SETTING HAS SECURITY IMPLICATIONS!";
|
|
|
|
|
info "Refer to https://bugs.debian.org/cgi-bin/"
|
|
|
|
|
. "bugreport.cgi?bug=898446";
|
|
|
|
|
}
|
|
|
|
|
exit 1;
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0) {
|
|
|
|
|
test_unshare_userns(1);
|
|
|
|
|
}
|
|
|
|
|
} elsif ($options->{mode} eq 'chrootless') {
|
|
|
|
|
if ($EFFECTIVE_USER_ID == 0) {
|
|
|
|
@ -5171,12 +5193,14 @@ sub main() {
|
|
|
|
|
my $keyring
|
|
|
|
|
= get_keyring_by_suite($options->{suite}, \%suite_by_vendor);
|
|
|
|
|
if (!defined $keyring) {
|
|
|
|
|
debug "get_keyring_by_suite() cannot find keyring";
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# we can only check if we need the signed-by entry if we u
|
|
|
|
|
# automatically chosen keyring exists
|
|
|
|
|
if (!defined $keyring || !-e $keyring) {
|
|
|
|
|
debug "found keyring does not exist";
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -5221,7 +5245,7 @@ sub main() {
|
|
|
|
|
# find all the fingerprints of the keys apt currently
|
|
|
|
|
# knows about
|
|
|
|
|
my @keyrings = ();
|
|
|
|
|
opendir my $dh, "$options->{apttrustedparts}"
|
|
|
|
|
opendir my $dh, $options->{apttrustedparts}
|
|
|
|
|
or error "cannot read $options->{apttrustedparts}";
|
|
|
|
|
while (my $filename = readdir $dh) {
|
|
|
|
|
if ($filename !~ /\.(asc|gpg)$/) {
|
|
|
|
@ -5230,7 +5254,7 @@ sub main() {
|
|
|
|
|
$filename = "$options->{apttrustedparts}/$filename";
|
|
|
|
|
# skip empty keyrings
|
|
|
|
|
-s "$filename" || next;
|
|
|
|
|
push @keyrings, "$filename";
|
|
|
|
|
push @keyrings, $filename;
|
|
|
|
|
}
|
|
|
|
|
closedir $dh;
|
|
|
|
|
if (-s $options->{apttrusted}) {
|
|
|
|
@ -5238,6 +5262,7 @@ sub main() {
|
|
|
|
|
}
|
|
|
|
|
my @aptfingerprints = ();
|
|
|
|
|
if (scalar @keyrings == 0) {
|
|
|
|
|
debug "no keyring is trusted by apt";
|
|
|
|
|
return " [signed-by=\"$keyring\"]";
|
|
|
|
|
}
|
|
|
|
|
info "finding correct signed-by value...";
|
|
|
|
@ -5261,6 +5286,7 @@ sub main() {
|
|
|
|
|
}
|
|
|
|
|
print_progress("done");
|
|
|
|
|
if (scalar @aptfingerprints == 0) {
|
|
|
|
|
debug "no fingerprints found";
|
|
|
|
|
return " [signed-by=\"$keyring\"]";
|
|
|
|
|
}
|
|
|
|
|
# check if all fingerprints from the keyring that we guessed
|
|
|
|
@ -5277,6 +5303,7 @@ sub main() {
|
|
|
|
|
# if this fingerprint is not known by apt, then we need
|
|
|
|
|
#to add the signed-by option
|
|
|
|
|
if (none { $_ eq $1 } @aptfingerprints) {
|
|
|
|
|
debug "fingerprint $1 is not trusted by apt";
|
|
|
|
|
return " [signed-by=\"$keyring\"]";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
@ -5665,7 +5692,7 @@ sub main() {
|
|
|
|
|
# for unshare mode the rootfs directory has to have appropriate
|
|
|
|
|
# permissions
|
|
|
|
|
if ($EFFECTIVE_USER_ID != 0 and $options->{mode} eq 'unshare') {
|
|
|
|
|
@idmap = read_subuid_subgid;
|
|
|
|
|
@idmap = read_subuid_subgid 1;
|
|
|
|
|
# sanity check
|
|
|
|
|
if ( scalar(@idmap) != 2
|
|
|
|
|
|| $idmap[0][0] ne 'u'
|
|
|
|
@ -5712,9 +5739,9 @@ sub main() {
|
|
|
|
|
);
|
|
|
|
|
waitpid $pid, 0;
|
|
|
|
|
if ($? != 0) {
|
|
|
|
|
warning "no read access for some packages for the unshared user";
|
|
|
|
|
warning "maybe try running mmdebstrap with "
|
|
|
|
|
. "--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount";
|
|
|
|
|
warning("apt on the outside is run as the unshared user and "
|
|
|
|
|
. "needs read access to packages outside the chroot given "
|
|
|
|
|
. "via --include");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -6450,8 +6477,9 @@ by this option will be the only ones that get either extracted or installed by
|
|
|
|
|
dpkg, respectively. For all other variants, apt is used to install the
|
|
|
|
|
additional packages. Package names are directly passed to apt and thus, you
|
|
|
|
|
can use apt features like C<pkg/suite>, C<pkg=version>, C<pkg->, use a glob or
|
|
|
|
|
regex for C<pkg>, use apt patterns or pass a path to a .deb package file. See
|
|
|
|
|
apt(8) for the supported syntax.
|
|
|
|
|
regex for C<pkg>, use apt patterns or pass a path to a .deb package file (see
|
|
|
|
|
below for notes concerning passing the path to a .deb package file in
|
|
|
|
|
B<unshare> mode). See apt(8) for the supported syntax.
|
|
|
|
|
|
|
|
|
|
The option can be specified multiple times and the packages are concatenated in
|
|
|
|
|
the order in which they are given on the command line. If later list items are
|
|
|
|
@ -6479,6 +6507,22 @@ apt. To add more packages, use multiple B<--include> options. To disable this
|
|
|
|
|
detection of patterns and paths, start the argument to B<--include> with a
|
|
|
|
|
comma or whitespace.
|
|
|
|
|
|
|
|
|
|
If you pass the path to a .deb package file using B<--include>, B<mmdebstrap>
|
|
|
|
|
will ensure that the path exists. If the path is a relative path, it will
|
|
|
|
|
internally by converted to an absolute path. Since apt (outside the chroot)
|
|
|
|
|
passes paths to dpkg (on the inside) verbatim, you have to make the .deb
|
|
|
|
|
package available under the same path inside the chroot as well or otherwise
|
|
|
|
|
dpkg inside the chroot will be unable to access it. This can be achieved using
|
|
|
|
|
a setup-hook. A hook that automatically makes the contents of C<file://>
|
|
|
|
|
mirrors as well as .deb packages given with B<--include> available inside the
|
|
|
|
|
chroot is provided by B<mmdebstrap> as
|
|
|
|
|
B<--hook-dir=/usr/share/mmdebstrap/hooks/file-mirror-automount>. This hook
|
|
|
|
|
takes care of copying all relevant file to their correct locations and cleans
|
|
|
|
|
up those files at the end. In B<unshare> mode, the .deb package paths have to
|
|
|
|
|
be accessible by the unshared user as well. This means that the package itself
|
|
|
|
|
likely must be made world-readable and all directory components on the path to
|
|
|
|
|
it world-executable.
|
|
|
|
|
|
|
|
|
|
=item B<--components>=I<comp1>[,I<comp2>,...]
|
|
|
|
|
|
|
|
|
|
Comma or whitespace separated list of components like main, contrib, non-free
|
|
|
|
@ -6668,9 +6712,9 @@ decides which way this is achieved.
|
|
|
|
|
|
|
|
|
|
This mode automatically selects a fitting mode. If the effective user id is the
|
|
|
|
|
one of the superuser, then the B<sudo> mode is chosen. Otherwise, the
|
|
|
|
|
B<unshare> mode is picked if the system has the sysctl
|
|
|
|
|
C<kernel.unprivileged_userns_clone> set to C<1>. Should that not be the case
|
|
|
|
|
and if the fakechroot binary exists, the B<fakechroot> mode is chosen.
|
|
|
|
|
B<unshare> mode is picked if F</etc/subuid> and F</etc/subgid> are set up
|
|
|
|
|
correctly. Should that not be the case and if the fakechroot binary exists, the
|
|
|
|
|
B<fakechroot> mode is chosen.
|
|
|
|
|
|
|
|
|
|
=item B<sudo>, B<root>
|
|
|
|
|
|
|
|
|
@ -6935,11 +6979,13 @@ C<MMDEBSTRAP_APT_CONFIG> environment variable. All environment variables set by
|
|
|
|
|
the user are preserved, except for C<TMPDIR> which is cleared. See section
|
|
|
|
|
B<TMPDIR>. Furthermore, C<MMDEBSTRAP_MODE> will store the mode set by
|
|
|
|
|
B<--mode>, C<MMDEBSTRAP_HOOK> stores which hook is currently run (setup,
|
|
|
|
|
extract, essential, customize) and C<MMDEBSTRAP_VERBOSITY> stores the numerical
|
|
|
|
|
verbosity level (0 for no output, 1 for normal, 2 for verbose and 3 for debug
|
|
|
|
|
output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of packages, apt
|
|
|
|
|
patterns or file paths given by the B<--include> option, separated by a comma
|
|
|
|
|
and with commas and percent signs in the option values urlencoded.
|
|
|
|
|
extract, essential, customize), C<MMDEBSTRAP_ARGV0> stores the name of the
|
|
|
|
|
binary with which B<mmdebstrap> was executed and C<MMDEBSTRAP_VERBOSITY> stores
|
|
|
|
|
the numerical verbosity level (0 for no output, 1 for normal, 2 for verbose and
|
|
|
|
|
3 for debug output). The C<MMDEBSTRAP_INCLUDE> variable stores the list of
|
|
|
|
|
packages, apt patterns or file paths given by the B<--include> option,
|
|
|
|
|
separated by a comma and with commas and percent signs in the option values
|
|
|
|
|
urlencoded.
|
|
|
|
|
|
|
|
|
|
In special hooks, the paths inside the chroot are relative to the root
|
|
|
|
|
directory of the chroot. The path on the outside is relative to current
|
|
|
|
|