diff --git a/hooks/busybox/extract00.sh b/hooks/busybox/extract00.sh new file mode 100755 index 0000000..d7c0e03 --- /dev/null +++ b/hooks/busybox/extract00.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +set -exu + +rootdir="$1" + +chroot "$rootdir" busybox --install -s diff --git a/hooks/busybox/setup00.sh b/hooks/busybox/setup00.sh new file mode 100755 index 0000000..a891c8a --- /dev/null +++ b/hooks/busybox/setup00.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +set -exu + +rootdir="$1" + +mkdir -p "$rootdir/bin" +echo root:x:0:0:root:/root:/bin/sh > "$rootdir/etc/passwd" +cat << END > "$rootdir/etc/group" +root:x:0: +mail:x:8: +utmp:x:43: +END diff --git a/hooks/eatmydata/customize.sh b/hooks/eatmydata/customize.sh new file mode 100755 index 0000000..589b007 --- /dev/null +++ b/hooks/eatmydata/customize.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -exu + +rootdir="$1" + +rm "$rootdir/usr/bin/eatmydata" +mv "$rootdir/usr/bin/dpkg.orig" "$rootdir/usr/bin/dpkg" + +sync diff --git a/hooks/eatmydata/extract.sh b/hooks/eatmydata/extract.sh new file mode 100755 index 0000000..a6f5929 --- /dev/null +++ b/hooks/eatmydata/extract.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +set -exu + +rootdir="$1" + +libdir="/usr/lib/$(dpkg-architecture -q DEB_HOST_MULTIARCH)" +mkdir -p "$rootdir$libdir" +cp -a $libdir/libeatmydata* "$rootdir$libdir" +cp -a /usr/bin/eatmydata "$rootdir/usr/bin" +mv "$rootdir/usr/bin/dpkg" "$rootdir/usr/bin/dpkg.orig" +cat << END > "$rootdir/usr/bin/dpkg" +#!/bin/sh +exec /usr/bin/eatmydata /usr/bin/dpkg.orig "\$@" +END +chmod +x "$rootdir/usr/bin/dpkg" diff --git a/hooks/setup00-merged-usr.sh b/hooks/setup00-merged-usr.sh new file mode 100755 index 0000000..4ed9246 --- /dev/null +++ b/hooks/setup00-merged-usr.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +set -exu + +rootdir="$1" + +for d in bin sbin lib; do + ln -s usr/$d "$rootdir/$d" + mkdir -p "$rootdir/usr/$d" +done diff --git a/mmdebstrap b/mmdebstrap index fda9887..1ed695c 100755 --- a/mmdebstrap +++ b/mmdebstrap @@ -3474,11 +3474,45 @@ sub main() { sub { push @{ $options->{noop} }, 'no-merged-usr'; }, 'force-check-gpg' => sub { push @{ $options->{noop} }, 'force-check-gpg'; }, - # hook options are hidden until I'm happy with them 'setup-hook=s@' => \$options->{setup_hook}, 'extract-hook=s@' => \$options->{extract_hook}, 'essential-hook=s@' => \$options->{essential_hook}, 'customize-hook=s@' => \$options->{customize_hook}, + 'hook-directory=s' => sub { + my ($opt_name, $opt_value) = @_; + if (!-e $opt_value) { + error "hook directory \"$opt_value\" does not exist"; + } + my $abs_path = abs_path($opt_value); + if (!defined $abs_path) { + error( "unable to get absolute path of " + . "--hook-directory: $opt_value"); + } + # since abs_path resolved all symlinks for us, we can now test + # what the actual target actually is + if (!-d $opt_value) { + error "hook directory \"$opt_value\" is not a directory"; + } + # gather all files starting with special prefixes into the + # respective keys of a hash + my %scripts; + opendir(my $dh, $opt_value) + or error "Can't opendir($opt_value): $!"; + while (my $entry = readdir $dh) { + foreach + my $hook ('setup', 'extract', 'essential', 'customize') { + if ($entry =~ m/^\Q$hook\E/ and -x "$opt_value/$entry") { + push @{$scripts{$hook}}, "$opt_value/$entry"; + } + } + } + closedir($dh); + # add the sorted list associated with each key to the respective + # list of hooks + foreach my $hook (keys %scripts) { + push @{ $options->{"${hook}_hook"} }, (sort @{$scripts{$hook}}); + } + }, # Sometimes --simulate fails even though non-simulate succeeds because # in simulate mode, apt cannot rely on dpkg to figure out tricky # dependency situations and will give up instead when it cannot find @@ -5291,6 +5325,35 @@ Example: Preparing a chroot for use with autopkgtest --customize-hook='echo "127.0.0.1 localhost host" > "$1/etc/hosts"' --customize-hook=/usr/share/autopkgtest/setup-commands/setup-testbed +=item B<--hook-directory>=I + +Execute scripts in I with filenames starting with C, +C, C or C, at the respective stages during an +mmdebstrap run. The files must be marked executable. Their extension is +ignored. Subdirectories are not traversed. This option is a short-hand for +specifying the remaining four hook options individually for each file in the +directory. If there are more than one script for a stage, then they are added +alphabetically. This is useful in cases, where a user wants to run the same +hooks frequently. For example, given a directory C<./hooks> with two scripts +C and C, this call: + + mmdebstrap --customize=./scriptA --hook-dir=./hooks --setup=./scriptB + +is equivalent to this call: + + mmdebstrap --customize=./scriptA --setup=./hooks/setup01-foo.sh \ + --setup=./hooks/setup02-bar.sh --setup=./scriptB + +The option can be specified multiple times and scripts are added to the +respective hooks in the order the options are given on the command line. Thus, +if the scripts in two directories depend upon each other, the scripts must be +placed into a common directory and be named such that they get added in the +correct order. + +Example: Run mmdebstrap with eatmydata + + --hook-dir=/usr/share/mmdebstrap/hooks/eatmydata + =item B<--skip>=I[,I,...] B tries hard to implement sensible defaults and will try to stop