From d8301b27dcda3bb9a66f145e3181c6ea781567fe Mon Sep 17 00:00:00 2001 From: Andrew Cady Date: Wed, 30 Aug 2017 23:11:02 -0400 Subject: selfstrap: internally manage /var/lib/dpkg/status --- multistrap/selfstrap | 116 ++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 25 deletions(-) diff --git a/multistrap/selfstrap b/multistrap/selfstrap index 88dc07e..c693a4e 100755 --- a/multistrap/selfstrap +++ b/multistrap/selfstrap @@ -43,6 +43,8 @@ apt_get() [ "$rootfs" ] || die 'no $rootfs' [ "$APT_CONFIG" ] || die 'no $APT_CONFIG' + visible_args="$*" + set -- -o Apt::Install-Recommends=false "$@" # Set various paths to within the created system. @@ -59,7 +61,7 @@ apt_get() # We must also set dpkg to use the created system. # Dpkg::options requires undocumented apt CLI magic. if [ "$DEBUG_DPKG" ]; then - [ "$DEBUG_DPKG" -gt 0 ] 2>/dev/null || DEBUG_DPKG=013 + [ "$DEBUG_DPKG" -gt 0 ] 2>/dev/null || DEBUG_DPKG=10013 set -- -o DPkg::options::arg0=--debug="${DEBUG_DPKG}" "$@" fi # This is the important one: @@ -75,9 +77,60 @@ apt_get() # Avoid deleting lists on the calling system. set -- -o APT::Get::List-Cleanup=false "$@" + [ "$VERBOSE" ] && printf '+ apt-get %s\n' "$visible_args" >&2 || true + apt-get "$@" } +idem() { if [ ! -e "${!#}" ]; then "$@"; fi; } +idem_mknod() { if [ ! -e "$3" ]; then mknod "$@"; fi; } + +# This function is copied (with modifications) from debootstrap. +install_devices() +{ + local TARGET="$rootfs" + [ "$TARGET" -a -d "$TARGET" ] || die 'no $TARGET' + idem mkdir "$TARGET"/dev + # The list of devices that can be created in a container comes from + # src/core/cgroup.c in the systemd source tree. + idem_mknod -m 666 "$TARGET"/dev/null c 1 3 + idem_mknod -m 666 "$TARGET"/dev/zero c 1 5 + idem_mknod -m 666 "$TARGET"/dev/full c 1 7 + idem_mknod -m 666 "$TARGET"/dev/random c 1 8 + idem_mknod -m 666 "$TARGET"/dev/urandom c 1 9 + idem_mknod -m 666 "$TARGET"/dev/tty c 5 0 + idem mkdir "$TARGET"/dev/pts/ + idem mkdir "$TARGET"/dev/shm/ + # Inside a container, we might not be allowed to create /dev/ptmx. + # If not, do the next best thing. + if ! idem_mknod -m 666 "$TARGET"/dev/ptmx c 5 2; then + idem ln -s pts/ptmx "$TARGET"/dev/ptmx + fi + idem ln -s /proc/self/fd "$TARGET"/dev/fd + idem ln -s /proc/self/fd/0 "$TARGET"/dev/stdin + idem ln -s /proc/self/fd/1 "$TARGET"/dev/stdout + idem ln -s /proc/self/fd/2 "$TARGET"/dev/stderr +} + +mount_virtfs() +{ + local TARGET="$1" + [ "$TARGET" ] || die 'no $TARGET' + [ -d "$TARGET"/proc ] || mkdir "$TARGET"/proc + [ -d "$TARGET"/sys ] || mkdir "$TARGET"/sys + mount -t proc proc "$TARGET"/proc + mount -t sysfs sysfs "$TARGET"/sys +} + +umount_virtfs() +{ + local TARGET="$1" fail= + [ "$TARGET" ] || die 'no $TARGET' + umount "$TARGET"/proc || fail=y + umount "$TARGET"/sys || fail=y + [ ! "$fail" ] +} + write_lines_once() { local output="$1" @@ -100,6 +153,7 @@ populate_rootfs() write_lines_once "$rootfs"/etc/apt/sources.list \ "deb $debian_mirror $release main contrib non-free" \ "deb http://security.debian.org $release/updates main contrib non-free" + install_devices } parse_apt_noact_line() @@ -131,23 +185,33 @@ dpkg_extract_with_info() PKG=${PKG%%_*} PKG=$PKG$multiarch - command=' -[ "$TAR_FILENAME" = ./control ] && exit -f=$TARGET/var/lib/dpkg/info/$PKG.${TAR_FILENAME#./} -cat > "$f" -chmod $TAR_MODE "$f" -' + command=$(cat <<'EOF' +if [ "$TAR_FILENAME" = ./control ]; then + (sed "/^Package:/a Status: install ok installed"; echo) >> "$TARGET"/var/lib/dpkg/status +else + f=$TARGET/var/lib/dpkg/info/$PKG.${TAR_FILENAME#./} + cat > "$f" + chmod $TAR_MODE "$f" +fi +EOF +) (export PKG TARGET; dpkg --ctrl-tarfile "$deb" | tar -x --to-command "$command") dpkg --fsys-tarfile "$deb" | (cd "$TARGET" && tar -xv) | sed 's?^\.??; s?^/$?/.?; s?/$??' > "$TARGET/var/lib/dpkg/info/$PKG.list" - } apt_run_inst() { - apt_get -s -yqq install "$@" | while read line; do + apt_get -s -yqq install "$@" | dpkg_inst_from_apt +} + +dpkg_inst_from_apt() +{ + while read line; do parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line" + export LC_ALL=C + export DEBIAN_FRONTEND=noninteractive export DPKG_MAINTSCRIPT_PACKAGE="$package" DPKG_MAINTSCRIPT_ARCH="$arch" is_multiarch_same "$package" && multiarch=":$arch" || multiarch= case "$action" in @@ -174,7 +238,9 @@ apt_run_inst() apt_extract() { apt_get -d -yqq install "$@" - apt_get -s -yqq install "$@" | while read line; do + actions=$(mktemp) || die 'mktemp failed' + apt_get -s -yqq install "$@" | tee "$actions" | while read line; do + parse_apt_noact_line "$line" || die "unexpected output from apt-get: $line" deb=/var/cache/apt/archives/${package}_${version//:/%3a}_${arch}.deb @@ -194,18 +260,22 @@ apt_extract() dpkg-deb --extract "$deb" "$rootfs" fi ;; - Conf) - ;; + Conf) ;; Remv) ;; *) die "impossible" ;; esac done + if [ "$EXTRACT_DPKG_INFO" ]; then + install_etc_passwd + dpkg_inst_from_apt < "$actions" + fi + rm "$actions" } install_etc_passwd() { - [ -e "$rootfs"/etc/passwd ] || cp "$rootfs"//usr/share/base-passwd/passwd.master "$rootfs"/etc/passwd - [ -e "$rootfs"/etc/group ] || cp "$rootfs"//usr/share/base-passwd/group.master "$rootfs"/etc/group + [ -e "$rootfs"/etc/passwd ] || cp "$rootfs"/usr/share/base-passwd/passwd.master "$rootfs"/etc/passwd + [ -e "$rootfs"/etc/group ] || cp "$rootfs"/usr/share/base-passwd/group.master "$rootfs"/etc/group } main_packages_file() @@ -273,8 +343,6 @@ packages=$(required_packages) && [ "$packages" ] || die 'failed to determine lis extra_packages='apt debian-archive-keyring locales' -# Extract files from downloaded packages. -# # Some files need to be present before 'apt-get install' can install anything. # In particular: # @@ -282,20 +350,18 @@ extra_packages='apt debian-archive-keyring locales' # 2. /etc/passwd and /etc/group so that 'chown' works # Rather than fuss about (1), extract everything from all packages. -apt_extract $packages -# This handles (2). -install_etc_passwd +# Note: apt_extract() runs preinst and postinst scripts itself when +# $EXTRACT_DPKG_INFO is true. +apt_extract $packages -# Finally we are ready to run apt-get install. -export LC_ALL=C -export DEBIAN_FRONTEND=noninteractive if [ "$SKIP_INSTALL" ]; then apt_extract $extra_packages - if [ "$RUN_INST_SCRIPTS" ]; then - apt_run_inst $packages $extra_packages - fi else + export LC_ALL=C + export DEBIAN_FRONTEND=noninteractive + + install_etc_passwd # This handles (2). if [ "$FIX_BROKEN" ]; then dpkg --root="$rootfs" --configure -a fi -- cgit v1.2.3