@ -2707,16 +2707,9 @@ sub main() {
# figure out whether a tarball has to be created in the end
# figure out whether a tarball has to be created in the end
$options->{maketar} = 0;
$options->{maketar} = 0;
$options->{makesqfs} = 0;
if (defined $tar_compressor or $options->{target} =~ /\.tar$/ or $options->{target} eq '-') {
if (defined $tar_compressor or $options->{target} =~ /\.tar$/ or $options->{target} eq '-') {
$options->{maketar} = 1;
$options->{maketar} = 1;
if (any { $_ eq $options->{variant} } ('extract', 'custom') and any { $_ eq $options->{mode} } ('fakechroot', 'proot')) {
info "creating a tarball in fakechroot mode or proot mode might fail in extract and custom variants because there might be no tar inside the chroot";
}
# try to fail early if target tarball cannot be opened for writing
if ($options->{target} ne '-') {
open my $fh, '>', $options->{target} or error "cannot open $options->{target} for writing: $!";
close $fh;
}
# check if the compressor is installed
# check if the compressor is installed
if (defined $tar_compressor) {
if (defined $tar_compressor) {
my $pid = fork() // error "fork() failed: $!";
my $pid = fork() // error "fork() failed: $!";
@ -2730,9 +2723,31 @@ sub main() {
error ("failed to start " . (join " ", @{$tar_compressor}));
error ("failed to start " . (join " ", @{$tar_compressor}));
}
}
}
}
} elsif ($options->{target} =~ /\.(squashfs|sqfs)$/) {
$options->{makesqfs} = 1;
# check if tar2sqfs is installed
my $pid = fork() // error "fork() failed: $!";
if ($pid == 0) {
open(STDOUT, '>', '/dev/null') or error "cannot open /dev/null for writing: $!";
open(STDIN, '<', '/dev/null') or error "cannot open /dev/null for reading: $!";
exec ('tar2sqfs', '--version') or error ("cannot exec tar2sqfs --version: $!");
}
waitpid $pid, 0;
if ($? != 0) {
error ("failed to start tar2sqfs --version");
}
}
}
if ($options->{maketar}) {
if ($options->{maketar} or $options->{makesqfs}) {
if (any { $_ eq $options->{variant} } ('extract', 'custom') and any { $_ eq $options->{mode} } ('fakechroot', 'proot')) {
info "creating a tarball or squashfs image in fakechroot mode or proot mode might fail in extract and custom variants because there might be no tar inside the chroot";
}
# try to fail early if target tarball or squashfs image cannot be
# opened for writing
if ($options->{target} ne '-') {
open my $fh, '>', $options->{target} or error "cannot open $options->{target} for writing: $!";
close $fh;
}
# since the output is a tarball, we create the rootfs in a temporary
# since the output is a tarball, we create the rootfs in a temporary
# directory
# directory
$options->{root} = tempdir(
$options->{root} = tempdir(
@ -2837,7 +2852,7 @@ sub main() {
my $devtar = '';
my $devtar = '';
# We always craft the /dev entries ourselves if a tarball is to be created
# We always craft the /dev entries ourselves if a tarball is to be created
if ($options->{maketar}) {
if ($options->{maketar} or $options->{makesqfs} ) {
foreach my $file (@devfiles) {
foreach my $file (@devfiles) {
my ($fname, $mode, $type, $linkname, $devmajor, $devminor) = @{$file};
my ($fname, $mode, $type, $linkname, $devmajor, $devminor) = @{$file};
my $entry = pack('a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
my $entry = pack('a100 a8 a8 a8 a12 a12 A8 a1 a100 a8 a32 a32 a8 a8 a155 x12',
@ -2901,7 +2916,7 @@ sub main() {
close $childsock;
close $childsock;
if ($options->{maketar}) {
if ($options->{maketar} or $options->{makesqfs} ) {
info "creating tarball...";
info "creating tarball...";
# redirect tar output to the writing end of the pipe so that the
# redirect tar output to the writing end of the pipe so that the
@ -2943,7 +2958,7 @@ sub main() {
close $childsock;
close $childsock;
if ($options->{maketar}) {
if ($options->{maketar} or $options->{makesqfs} ) {
info "creating tarball...";
info "creating tarball...";
# redirect tar output to the writing end of the pipe so that the
# redirect tar output to the writing end of the pipe so that the
@ -3306,7 +3321,7 @@ sub main() {
close $parentsock;
close $parentsock;
if ($options->{maketar}) {
if ($options->{maketar} or $options->{makesqfs} ) {
# we use eval() so that error() doesn't take this process down and
# we use eval() so that error() doesn't take this process down and
# thus leaves the setup() process without a parent
# thus leaves the setup() process without a parent
eval {
eval {
@ -3315,7 +3330,17 @@ sub main() {
error "cannot copy to standard output: $!";
error "cannot copy to standard output: $!";
}
}
} else {
} else {
if (defined $tar_compressor) {
if ($options->{makesqfs} or defined $tar_compressor) {
my @argv = ();
if ($options->{makesqfs}) {
push @argv, 'tar2sqfs',
'--quiet', '--no-skip', '--force', '--exportable',
'--compressor', 'xz',
'--block-size', '1048576',
$options->{target};
} else {
push @argv, @{$tar_compressor};
}
POSIX::sigprocmask(SIG_BLOCK, $sigset) or error "Can't block signals: $!";
POSIX::sigprocmask(SIG_BLOCK, $sigset) or error "Can't block signals: $!";
my $cpid = fork() // error "fork() failed: $!";
my $cpid = fork() // error "fork() failed: $!";
if ($cpid == 0) {
if ($cpid == 0) {
@ -3327,14 +3352,19 @@ sub main() {
# unblock all delayed signals (and possibly handle them)
# unblock all delayed signals (and possibly handle them)
POSIX::sigprocmask(SIG_UNBLOCK, $sigset) or error "Can't unblock signals: $!";
POSIX::sigprocmask(SIG_UNBLOCK, $sigset) or error "Can't unblock signals: $!";
if ($options->{makesqfs}) {
open(STDOUT, '>', '/dev/null') or error "cannot open /dev/null for writing: $!";
} else {
open(STDOUT, '>', $options->{target}) or error "cannot open $options->{target} for writing: $!";
open(STDOUT, '>', $options->{target}) or error "cannot open $options->{target} for writing: $!";
}
open(STDIN, '<&', $rfh) or error "cannot open file handle for reading: $!";
open(STDIN, '<&', $rfh) or error "cannot open file handle for reading: $!";
exec { $tar_compressor->[0] } @{$tar_compressor} or error ("cannot exec " . (join " ", @{$tar_compressor}) . ": $!");
exec { $argv[0] } @argv or error ("cannot exec " . (join " ", @argv ) . ": $!");
}
}
POSIX::sigprocmask(SIG_UNBLOCK, $sigset) or error "Can't unblock signals: $!";
POSIX::sigprocmask(SIG_UNBLOCK, $sigset) or error "Can't unblock signals: $!";
waitpid $cpid, 0;
waitpid $cpid, 0;
if ($? != 0) {
if ($? != 0) {
error ("failed to start " . (join " ", @{$tar_compressor} ));
error ("failed to start " . (join " ", @argv ));
}
}
} else {
} else {
if(!copy($rfh, $options->{target})) {
if(!copy($rfh, $options->{target})) {
@ -3359,7 +3389,7 @@ sub main() {
# change signal handler message
# change signal handler message
$waiting_for = "cleanup";
$waiting_for = "cleanup";
if ($options->{maketar} and -e $options->{root}) {
if (( $options->{maketar} or $options->{makesqfs}) and -e $options->{root}) {
info "removing tempdir $options->{root}...";
info "removing tempdir $options->{root}...";
if ($options->{mode} eq 'unshare') {
if ($options->{mode} eq 'unshare') {
# We don't have permissions to remove the directory outside
# We don't have permissions to remove the directory outside
@ -3447,25 +3477,29 @@ installed inside the chroot. If any mirror contains a tor+xxx URI, then the
apt-transport-tor package will be installed inside the chroot.
apt-transport-tor package will be installed inside the chroot.
The optional I<TARGET> argument can either be the path to a directory, the
The optional I<TARGET> argument can either be the path to a directory, the
path to a tarball filename or C<->. If I<TARGET> ends with C<.tar>, or with
path to a tarball filename, the path to a squashfs image or C<->. If I<TARGET>
any of the filename extensions listed in the section B<COMPRESSION>, then
ends with C<.tar>, or with any of the filename extensions listed in the
I<TARGET> will be interpreted as a path to a tarball filename. If I<TARGET> is
section B<COMPRESSION>, then I<TARGET> will be interpreted as a path to a
the path to a tarball filename or if I<TARGET> is C<-> or if no I<TARGET> was
tarball filename. If I<TARGET> ends with C<.squashfs> or C<.sqfs>, then
specified, B<mmdebstrap> will create a temporary chroot directory in
I<TARGET> will be interpreted as a path to a squashfs image. If I<TARGET> is
C<$TMPDIR> or F</tmp>. If I<TARGET> is the path to a tarball filename,
the path to a tarball filename or a squashfs image or if I<TARGET> is C<-> or
B<mmdebstrap> will create a tarball of that directory and store it as
if no I<TARGET> was specified, B<mmdebstrap> will create a temporary chroot
I<TARGET>, optionally applying a compression algorithm as indicated by its
directory in C<$TMPDIR> or F</tmp>. If I<TARGET> is the path to a tarball
filename, B<mmdebstrap> will create a tarball of that directory and store it
as I<TARGET>, optionally applying a compression algorithm as indicated by its
filename extension. If I<TARGET> is C<-> or if no I<TARGET> was specified,
filename extension. If I<TARGET> is C<-> or if no I<TARGET> was specified,
then an uncompressed tarball of that directory will be sent to standard
then an uncompressed tarball of that directory will be sent to standard
output. When B<mmdebstrap> creates a tarball it also stores extended
output. When B<mmdebstrap> creates a tarball it also stores extended
attributes. To preserve the extended attributes, you have to pass B<--xattrs
attributes. To preserve the extended attributes, you have to pass B<--xattrs
--xattrs-include='*'> to tar when extracting the tarball. If I<TARGET> does
--xattrs-include='*'> to tar when extracting the tarball. If I<TARGET> is the
not end in C<.tar> or with any of the filename extensions listed in the
path to a squashfs image, B<mmdebstrap> will create an xz compressed image
section B<COMPRESSION>, then I<TARGET> will be interpreted as the path to a
with a blocksize of 1048576 bytes. If I<TARGET> does neither end with C<.tar>
directory. If the directory already exists, it must either be empty or only
nor with any of the filename extensions listed in the section B<COMPRESSION>,
contain an empty C<lost+found> directory. If a directory is chosen as output
nor with C<.squashfs> or C<.sqfs>, then I<TARGET> will be interpreted as the
in any other mode than B<sudo>, then its contents will have wrong ownership
path to a directory. If the directory already exists, it must either be empty
information and special device files will be missing.
or only contain an empty C<lost+found> directory. If a directory is chosen as
output in any other mode than B<sudo>, then its contents will have wrong
ownership information and special device files will be missing.
The I<SUITE> may be a valid release code name (eg, sid, stretch, jessie) or a
The I<SUITE> may be a valid release code name (eg, sid, stretch, jessie) or a
symbolic name (eg, unstable, testing, stable, oldstable). Any suite name that
symbolic name (eg, unstable, testing, stable, oldstable). Any suite name that
@ -3938,6 +3972,10 @@ create device nodes:
$ mmdebstrap unstable | tar --delete ./dev > unstable-chroot.tar
$ mmdebstrap unstable | tar --delete ./dev > unstable-chroot.tar
Instead of a tarball, a squashfs image can be created:
$ mmdebstrap unstable unstable-chroot.squashfs
By default, debootstrapping a stable distribution will add mirrors for security
By default, debootstrapping a stable distribution will add mirrors for security
and updates to the sources.list.
and updates to the sources.list.