#!/bin/bash set -e # Includes . $(miniade) || { echo "${0##*/}: ERROR: miniade failed (hint: run 'miniade' to see error)" >&2; exit 1; } # Based on /usr/share/lxc/templates/lxc-debian, which is the work of: # # Daniel Lezcano # Greg Olsen # Tanya # Configurable stuff TTY_COUNT=4 MIRROR=http://deb.debian.org/debian # Other globals main() { local MY_ARGS local PROGNAME # Defaults for options RELEASE= CONTAINER_ROOTDIR= CONTAINER_NAME= CONTAINER_LXC_PATH= FLUSH_CACHE_FLAG=false # Process options special_opts_handler() { case $1 in # Lxc-create-specified options --name=*) CONTAINER_NAME=${1#*=} ;; --path=*) CONTAINER_LXC_PATH=${2#*=} ;; --rootfs=*) CONTAINER_ROOTDIR=${1#*=} ;; # Template-specific options --release=*) RELEASE=${1#*=} ;; --mirror=*) MIRROR=${1#*=} ;; --stderr=*) eval "exec 2>&${1#*=}" ;; # urgent # lxc-create does not have --flush-cache/-F but the official template (and so also this template) # does. To use template options lxc-create needs to be called as: # # lxc-create -- # --flush-cache|-F) FLUSH_CACHE_FLAG=true ;; *) return 1 ;; esac } miniade_process_options --special-opts-handler=special_opts_handler MY_ARGS "$@" && set -- "${MY_ARGS[@]}" # Process arguments [ $# = 0 ] || usage # Sanity checks and derivations miniade_get_progname PROGNAME CACHE_ROOTDIR=/var/cache/$PROGNAME for VAR in CONTAINER_ROOTDIR CONTAINER_NAME RELEASE; do eval "[ \"X\$$VAR\" != X ]" || usage done [ $(uname -m) = x86_64 ] || miniade_error "this template only supports x86_64 on the host" ARCH=amd64 [ "$(id -u)" = 0 ] || miniade_error "this script must be run as root" for CMD in debootstrap; do type -p $CMD > /dev/null || miniade_error "$CMD: not found (hint: install it)" done [[ $RELEASE =~ ^(bullseye|bookworm|trixie)$ ]] || miniade_error "$RELEASE: release not supported (hint: ...)" [[ $CONTAINER_ROOTDIR =~ ^/.* ]] || miniade_error "$CONTAINER_ROOTDIR: not absolute (hint: ...)" [ -d "$CONTAINER_ROOTDIR" ] || miniade_error "$CONTAINER_ROOTDIR: not found (hint: this script will not create it for you)" LSA_OUTPUT=$(ls -A $CONTAINER_ROOTDIR 2>&1 | egrep -vx '(lost\+found)') || true [ "X$LSA_OUTPUT" = X ] || miniade_error "$CONTAINER_ROOTDIR: not empty or error examining contents (hint: 'ls -A $CONTAINER_ROOTDIR' reported '$LSA_OUTPUT')" # Guts flush_cache_if_requested download_debian_to_cache_if_necessary copy_debian_from_cache containerise_installation install_packages } usage() { local RC PROGNAME miniade_get_progname PROGNAME echo "Usage: $PROGNAME [ ... ] --name= [ --path= ] --rootfs= --release={bullseye|bookworm|trixie} [ --mirror= ] [ --stderr= ] [ --clean ]" exit 0 } copy_debian_from_cache() { miniade_info "copying debian out of cache ..." miniade_evaler "rsync -SHaAX \"$CACHE_ROOTDIR/$RELEASE-$ARCH/\" \"$CONTAINER_ROOTDIR/\"" } containerise_installation() { containerise_installation_$RELEASE "$@" } containerise_installation_bullseye() { local TTY_ID TTY_SERVICES I PROGNAME miniade_get_progname PROGNAME miniade_info "applying multiple small fixes ..." miniade_debug 10 "containerise_installation_bullseye: mknod'ing ttys in container ..." for TTY_ID in $(seq 1 $TTY_COUNT); do [ -e $CONTAINER_ROOTDIR/dev/tty$TTY_ID ] || miniade_evaler "mknod \"$CONTAINER_ROOTDIR/dev/tty$TTY_ID\" c 4 $TTY_ID" done miniade_debug 10 "containerise_installation_bullseye: writing /etc/inittab in container ..." { echo "id:3:initdefault:" echo "si::sysinit:/etc/init.d/rcS" for I in {0..6}; do echo "l$I:$I:wait:/etc/init.d/rc $I" done echo "z6:6:respawn:/sbin/sulogin" echo "1:2345:respawn:/sbin/getty 38400 console" for TTY_ID in $(seq 1 $TTY_COUNT); do echo "c$TTY_ID:12345:respawn:/sbin/getty 38400 tty$TTY_ID linux" done echo "p6::ctrlaltdel:/sbin/init 6" echo "p0::powerfail:/sbin/init 0" } > /tmp/$PROGNAME.$$.inittab miniade_evaler "cat /tmp/$PROGNAME.$$.inittab > $CONTAINER_ROOTDIR/etc/inittab" rm -f /tmp/$PROGNAME.$$.inittab # Symlink mtab miniade_debug 10 "containerise_installation_bullseye: fixing /etc/mtab in container ..." [ ! -h "$CONTAINER_ROOTDIR/etc/mtab" -a ! -e "$CONTAINER_ROOTDIR/etc/mtab" ] || miniade_evaler "rm \"$CONTAINER_ROOTDIR/etc/mtab\"" miniade_evaler "ln -s /proc/self/mounts \"$CONTAINER_ROOTDIR/etc/mtab\"" # Disable SELinux miniade_debug 10 "containerise_installation_bullseye: disabling SELinux in container ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/selinux\"" miniade_evaler "echo 0 > \"$CONTAINER_ROOTDIR/selinux/enforce\"" miniade_debug 10 "containerise_installation_bullseye: writing network interface config file in container ..." # Configure the network using the dhcp { echo "auto lo" echo "iface lo inet loopback" echo echo "auto eth0" echo "iface eth0 inet dhcp" } > /tmp/$PROGNAME.$$.interfaces miniade_evaler "cat /tmp/$PROGNAME.$$.interfaces > \"$CONTAINER_ROOTDIR/etc/network/interfaces\"" # Set the hostname miniade_debug 10 "containerise_installation_bullseye: setting hostname in container ..." miniade_evaler "echo \"$CONTAINER_NAME\" > \"$CONTAINER_ROOTDIR/etc/hostname\"" # Set up minimal /etc/hosts miniade_debug 10 "containerise_installation_bullseye: setting up minimal /etc/hosts in container ..." { echo "127.0.0.1 localhost" echo "127.0.1.1 $CONTAINER_NAME" echo echo "::1 localhost ip6-localhost ip6-loopback" echo "ff02::1 ip6-allnodes" echo "ff02::2 ip6-allrouters" } > /tmp/$PROGNAME.$$.hosts miniade_evaler "cat /tmp/$PROGNAME.$$.hosts > \"$CONTAINER_ROOTDIR/etc/hosts\"" rm -f /tmp/$PROGNAME.$$.hosts # Before reconfiguring some services, ensure that locale # is set else reconfiguring services gets noisy. If LANG # not set or set to C or C.* then use en_US.UTF-8. # but first reconfigure locales - so we get no noisy perl-warnings miniade_debug 10 "containerise_installation_bullseye: fixing locale in container ..." if [[ $LANG =~ ^(|C|C\..*)$ ]]; then miniade_evaler "echo \"en_US.UTF-8 UTF-8\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"en_US.UTF-8\" \"UTF-8\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=en_US.UTF-8\"" else ENCODING=$(locale charmap) [ "X$ENCODING" != X ] || ENCODING="UTF-8" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" sed -e \"s/^# \($LANG $ENCODING\)/\\1/\" -i /etc/locale.gen 2> /dev/null" miniade_evaler "echo \"$LANG $ENCODING\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"$LANG\" \"$ENCODING\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=$LANG\"" fi # Remove pointless services miniade_debug 10 "containerise_installation_bullseye: removing pointless services ..." #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f checkroot.sh disable" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f umountfs disable" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclock.sh disable 2>/dev/null" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclockfirst.sh disable" # Set up getty miniade_debug 10 "containerise_installation_bullseye: setting up getty ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/lib/systemd/system\"" miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants\"" # Fix getty-static-service as debootstrap does not install dbus if [ -e "$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service" ]; then miniade_debug 10 "containerise_installation_bullseye: fixing getty-static-service ..." TTY_SERVICES=$(for I in $(seq 2 $TTY_COUNT); do echo -n "getty@tty$I.service "; done) miniade_evaler "sed \"s/ getty@tty.*/ $TTY_SERVICES /g\" \"$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service\" | sed \"s/\\\\(tty2-tty\\\\)[5-9]/\\\\1$TTY_COUNT/g\" > \"$CONTAINER_ROOTDIR/etc/systemd/system/getty-static.service\"" fi # Setup getty service on the ttys we are going to allow in the # default config. Number should match lxc.tty.max for I in $(seq 1 $TTY_COUNT); do miniade_evaler "ln -sf ../getty@.service \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/getty@tty$I.service\"" done # Since we use static-getty.target; we need to mask container-getty@.service generated by # container-getty-generator, so we don't get multiple instances of agetty running. # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484 for I in $(seq 0 $TTY_COUNT); do miniade_evaler "ln -sf /dev/null \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/container-getty@$I.service\"" done # This function has been copied and adapted from lxc-fedora miniade_debug 10 "containerise_installation_bullseye: fixing udev-related services ..." miniade_evaler "rm -f \"$CONTAINER_ROOTDIR/etc/systemd/system/default.target\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/udev.service" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/systemd-udevd.service" # Set default runlevel miniade_debug 10 "containerise_installation_bullseye: making multi-user target the default target ..." miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target" # Avoid possible warning 'stdin not a tty'. Preserve single-commandedness of the thing # that gets substituted. miniade_evaler "[ ! -f \"$CONTAINER_ROOTDIR/root/.profile\" ] || sed -i -e \"s/^mesg n/{ [ ! -t 0 ] || mesg n; }/g\" \"$CONTAINER_ROOTDIR/root/.profile\"" # Disable more services not supported on containers. These don't crash # the container, but they do leave uply fail messages in startup. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-debug.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-tracing.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-config.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask systemd-journald-audit.socket" } containerise_installation_bookworm() { local TTY_ID TTY_SERVICES I PROGNAME miniade_get_progname PROGNAME miniade_info "applying multiple small fixes ..." miniade_debug 10 "containerise_installation_bookworm: mknod'ing ttys in container ..." for TTY_ID in $(seq 1 $TTY_COUNT); do [ -e $CONTAINER_ROOTDIR/dev/tty$TTY_ID ] || miniade_evaler "mknod \"$CONTAINER_ROOTDIR/dev/tty$TTY_ID\" c 4 $TTY_ID" done miniade_debug 10 "containerise_installation_bookworm: writing /etc/inittab in container ..." { echo "id:3:initdefault:" echo "si::sysinit:/etc/init.d/rcS" for I in {0..6}; do echo "l$I:$I:wait:/etc/init.d/rc $I" done echo "z6:6:respawn:/sbin/sulogin" echo "1:2345:respawn:/sbin/getty 38400 console" for TTY_ID in $(seq 1 $TTY_COUNT); do echo "c$TTY_ID:12345:respawn:/sbin/getty 38400 tty$TTY_ID linux" done echo "p6::ctrlaltdel:/sbin/init 6" echo "p0::powerfail:/sbin/init 0" } > /tmp/$PROGNAME.$$.inittab miniade_evaler "cat /tmp/$PROGNAME.$$.inittab > $CONTAINER_ROOTDIR/etc/inittab" rm -f /tmp/$PROGNAME.$$.inittab # Symlink mtab miniade_debug 10 "containerise_installation_bookworm: fixing /etc/mtab in container ..." [ ! -h "$CONTAINER_ROOTDIR/etc/mtab" -a ! -e "$CONTAINER_ROOTDIR/etc/mtab" ] || miniade_evaler "rm \"$CONTAINER_ROOTDIR/etc/mtab\"" miniade_evaler "ln -s /proc/self/mounts \"$CONTAINER_ROOTDIR/etc/mtab\"" # Disable SELinux miniade_debug 10 "containerise_installation_bookworm: disabling SELinux in container ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/selinux\"" miniade_evaler "echo 0 > \"$CONTAINER_ROOTDIR/selinux/enforce\"" miniade_debug 10 "containerise_installation_bookworm: writing network interface config file in container ..." # Configure the network using the dhcp { echo "auto lo" echo "iface lo inet loopback" echo echo "auto eth0" echo "iface eth0 inet dhcp" } > /tmp/$PROGNAME.$$.interfaces miniade_evaler "cat /tmp/$PROGNAME.$$.interfaces > \"$CONTAINER_ROOTDIR/etc/network/interfaces\"" # Set the hostname miniade_debug 10 "containerise_installation_bookworm: setting hostname in container ..." miniade_evaler "echo \"$CONTAINER_NAME\" > \"$CONTAINER_ROOTDIR/etc/hostname\"" # Set up minimal /etc/hosts miniade_debug 10 "containerise_installation_bookworm: setting up minimal /etc/hosts in container ..." { echo "127.0.0.1 localhost" echo "127.0.1.1 $CONTAINER_NAME" echo echo "::1 localhost ip6-localhost ip6-loopback" echo "ff02::1 ip6-allnodes" echo "ff02::2 ip6-allrouters" } > /tmp/$PROGNAME.$$.hosts miniade_evaler "cat /tmp/$PROGNAME.$$.hosts > \"$CONTAINER_ROOTDIR/etc/hosts\"" rm -f /tmp/$PROGNAME.$$.hosts # Before reconfiguring some services, ensure that locale # is set else reconfiguring services gets noisy. If LANG # not set or set to C or C.* then use en_US.UTF-8. # but first reconfigure locales - so we get no noisy perl-warnings miniade_debug 10 "containerise_installation_bookworm: fixing locale in container ..." if [[ $LANG =~ ^(|C|C\..*)$ ]]; then miniade_evaler "echo \"en_US.UTF-8 UTF-8\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"en_US.UTF-8\" \"UTF-8\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=en_US.UTF-8\"" else ENCODING=$(locale charmap) [ "X$ENCODING" != X ] || ENCODING="UTF-8" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" sed -e \"s/^# \($LANG $ENCODING\)/\\1/\" -i /etc/locale.gen 2> /dev/null" miniade_evaler "echo \"$LANG $ENCODING\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"$LANG\" \"$ENCODING\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=$LANG\"" fi # Remove pointless services miniade_debug 10 "containerise_installation_bookworm: removing pointless services ..." #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f checkroot.sh disable" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f umountfs disable" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclock.sh disable 2>/dev/null" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclockfirst.sh disable" # Set up getty miniade_debug 10 "containerise_installation_bookworm: setting up getty ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/lib/systemd/system\"" miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants\"" # Fix getty-static-service as debootstrap does not install dbus if [ -e "$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service" ]; then miniade_debug 10 "containerise_installation_bookworm: fixing getty-static-service ..." TTY_SERVICES=$(for I in $(seq 2 $TTY_COUNT); do echo -n "getty@tty$I.service "; done) miniade_evaler "sed \"s/ getty@tty.*/ $TTY_SERVICES /g\" \"$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service\" | sed \"s/\\\\(tty2-tty\\\\)[5-9]/\\\\1$TTY_COUNT/g\" > \"$CONTAINER_ROOTDIR/etc/systemd/system/getty-static.service\"" fi # Setup getty service on the ttys we are going to allow in the # default config. Number should match lxc.tty.max for I in $(seq 1 $TTY_COUNT); do miniade_evaler "ln -sf ../getty@.service \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/getty@tty$I.service\"" done # Since we use static-getty.target; we need to mask container-getty@.service generated by # container-getty-generator, so we don't get multiple instances of agetty running. # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484 for I in $(seq 0 $TTY_COUNT); do miniade_evaler "ln -sf /dev/null \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/container-getty@$I.service\"" done # This function has been copied and adapted from lxc-fedora miniade_debug 10 "containerise_installation_bookworm: fixing udev-related services ..." miniade_evaler "rm -f \"$CONTAINER_ROOTDIR/etc/systemd/system/default.target\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/udev.service" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/systemd-udevd.service" # Set default runlevel miniade_debug 10 "containerise_installation_bookworm: making multi-user target the default target ..." miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target" # Avoid possible warning 'stdin not a tty'. Preserve single-commandedness of the thing # that gets substituted. miniade_evaler "[ ! -f \"$CONTAINER_ROOTDIR/root/.profile\" ] || sed -i -e \"s/^mesg n/{ [ ! -t 0 ] || mesg n; }/g\" \"$CONTAINER_ROOTDIR/root/.profile\"" # Disable more services not supported on containers. These don't crash # the container, but they do leave uply fail messages in startup. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-debug.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-tracing.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-config.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask systemd-journald-audit.socket" } containerise_installation_trixie() { local TTY_ID TTY_SERVICES I PROGNAME miniade_get_progname PROGNAME miniade_info "applying multiple small fixes ..." # Almost all of this function is cloned from the official template, with style changes. miniade_debug 10 "containerise_installation_trixie: mknod'ing ttys in container ..." for TTY_ID in $(seq 1 $TTY_COUNT); do [ -e $CONTAINER_ROOTDIR/dev/tty$TTY_ID ] || miniade_evaler "mknod \"$CONTAINER_ROOTDIR/dev/tty$TTY_ID\" c 4 $TTY_ID" done miniade_debug 10 "containerise_installation_trixie: writing /etc/inittab in container ..." { echo "id:3:initdefault:" echo "si::sysinit:/etc/init.d/rcS" for I in {0..6}; do echo "l$I:$I:wait:/etc/init.d/rc $I" done echo "z6:6:respawn:/sbin/sulogin" echo "1:2345:respawn:/sbin/getty 38400 console" for TTY_ID in $(seq 1 $TTY_COUNT); do echo "c$TTY_ID:12345:respawn:/sbin/getty 38400 tty$TTY_ID linux" done echo "p6::ctrlaltdel:/sbin/init 6" echo "p0::powerfail:/sbin/init 0" } > /tmp/$PROGNAME.$$.inittab miniade_evaler "cat /tmp/$PROGNAME.$$.inittab > $CONTAINER_ROOTDIR/etc/inittab" rm -f /tmp/$PROGNAME.$$.inittab # Symlink mtab miniade_debug 10 "containerise_installation_trixie: fixing /etc/mtab in container ..." [ ! -h "$CONTAINER_ROOTDIR/etc/mtab" -a ! -e "$CONTAINER_ROOTDIR/etc/mtab" ] || miniade_evaler "rm \"$CONTAINER_ROOTDIR/etc/mtab\"" miniade_evaler "ln -s /proc/self/mounts \"$CONTAINER_ROOTDIR/etc/mtab\"" # Disable SELinux miniade_debug 10 "containerise_installation_trixie: disabling SELinux in container ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/selinux\"" miniade_evaler "echo 0 > \"$CONTAINER_ROOTDIR/selinux/enforce\"" miniade_debug 10 "containerise_installation_trixie: writing network interface config file in container ..." # Configure the network using the dhcp { echo "auto lo" echo "iface lo inet loopback" echo echo "auto eth0" echo "iface eth0 inet dhcp" } > /tmp/$PROGNAME.$$.interfaces miniade_evaler "cat /tmp/$PROGNAME.$$.interfaces > \"$CONTAINER_ROOTDIR/etc/network/interfaces\"" # Set the hostname miniade_debug 10 "containerise_installation_trixie: setting hostname in container ..." miniade_evaler "echo \"$CONTAINER_NAME\" > \"$CONTAINER_ROOTDIR/etc/hostname\"" # Set up minimal /etc/hosts miniade_debug 10 "containerise_installation_trixie: setting up minimal /etc/hosts in container ..." { echo "127.0.0.1 localhost" echo "127.0.1.1 $CONTAINER_NAME" echo echo "::1 localhost ip6-localhost ip6-loopback" echo "ff02::1 ip6-allnodes" echo "ff02::2 ip6-allrouters" } > /tmp/$PROGNAME.$$.hosts miniade_evaler "cat /tmp/$PROGNAME.$$.hosts > \"$CONTAINER_ROOTDIR/etc/hosts\"" rm -f /tmp/$PROGNAME.$$.hosts # Before reconfiguring some services, ensure that locale # is set else reconfiguring services gets noisy. If LANG # not set or set to C or C.* then use en_US.UTF-8. # but first reconfigure locales - so we get no noisy perl-warnings miniade_debug 10 "containerise_installation_trixie: fixing locale in container ..." if [[ $LANG =~ ^(|C|C\..*)$ ]]; then miniade_evaler "echo \"en_US.UTF-8 UTF-8\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"en_US.UTF-8\" \"UTF-8\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=en_US.UTF-8\"" else ENCODING=$(locale charmap) [ "X$ENCODING" != X ] || ENCODING="UTF-8" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" sed -e \"s/^# \($LANG $ENCODING\)/\\1/\" -i /etc/locale.gen 2> /dev/null" miniade_evaler "echo \"$LANG $ENCODING\" >> \"$CONTAINER_ROOTDIR/etc/locale.gen\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" locale-gen \"$LANG\" \"$ENCODING\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" update-locale \"LANG=$LANG\"" fi # Remove pointless services miniade_debug 10 "containerise_installation_trixie: removing pointless services ..." #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f checkroot.sh disable" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f umountfs disable" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclock.sh disable 2>/dev/null" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" /usr/sbin/update-rc.d -f hwclockfirst.sh disable" # Set up getty miniade_debug 10 "containerise_installation_trixie: setting up getty ..." miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/lib/systemd/system\"" miniade_evaler "mkdir -p \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants\"" # Fix getty-static-service as debootstrap does not install dbus if [ -e "$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service" ]; then miniade_debug 10 "containerise_installation_trixie: fixing getty-static-service ..." TTY_SERVICES=$(for I in $(seq 2 $TTY_COUNT); do echo -n "getty@tty$I.service "; done) miniade_evaler "sed \"s/ getty@tty.*/ $TTY_SERVICES /g\" \"$CONTAINER_ROOTDIR/lib/systemd/system/getty-static.service\" | sed \"s/\\\\(tty2-tty\\\\)[5-9]/\\\\1$TTY_COUNT/g\" > \"$CONTAINER_ROOTDIR/etc/systemd/system/getty-static.service\"" fi # Setup getty service on the ttys we are going to allow in the # default config. Number should match lxc.tty.max for I in $(seq 1 $TTY_COUNT); do miniade_debug 10 "containerise_installation_trixie: enabling getty#$I ..." miniade_evaler "ln -sf ../getty@.service \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/getty@tty$I.service\"" done # Since we use static-getty.target; we need to mask container-getty@.service generated by # container-getty-generator, so we don't get multiple instances of agetty running. # See https://github.com/lxc/lxc/issues/520 and https://github.com/lxc/lxc/issues/484 for I in $(seq 0 $TTY_COUNT); do miniade_debug 10 "containerise_installation_trixie: masking container-getty#$I ..." miniade_evaler "ln -sf /dev/null \"$CONTAINER_ROOTDIR/etc/systemd/system/getty.target.wants/container-getty@$I.service\"" done # This function has been copied and adapted from lxc-fedora miniade_debug 10 "containerise_installation_trixie: fixing udev-related services ..." miniade_evaler "rm -f \"$CONTAINER_ROOTDIR/etc/systemd/system/default.target\"" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/udev.service" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /dev/null /etc/systemd/system/systemd-udevd.service" # Set default runlevel miniade_debug 10 "containerise_installation_trixie: making multi-user target the default target ..." miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" ln -s /lib/systemd/system/multi-user.target /etc/systemd/system/default.target" # Avoid possible warning 'stdin not a tty'. Preserve single-commandedness of the thing # that gets substituted. miniade_debug 10 "containerise_installation_trixie: fixing up ~root/.profile ..." miniade_evaler "[ ! -f \"$CONTAINER_ROOTDIR/root/.profile\" ] || sed -i -e \"s/^mesg n/{ [ ! -t 0 ] || mesg n; }/g\" \"$CONTAINER_ROOTDIR/root/.profile\"" # Disable more services not supported on containers. These don't crash # the container, but they do leave uply fail messages in startup. miniade_debug 10 "containerise_installation_trixie: masking container-unsupported services ..." miniade_evaler "mount devpts -t devpts $CONTAINER_ROOTDIR/dev/pts" miniade_evaler "mount proc -t proc $CONTAINER_ROOTDIR/proc" miniade_evaler "mount sysfs -t sysfs $CONTAINER_ROOTDIR/sys" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-debug.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-tracing.mount" miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask sys-kernel-config.mount" #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" systemctl --quiet mask systemd-journald-audit.socket" miniade_evaler "umount $CONTAINER_ROOTDIR/sys" miniade_evaler "umount $CONTAINER_ROOTDIR/proc" miniade_evaler "umount $CONTAINER_ROOTDIR/dev/pts" miniade_debug 2 "containerise_installation_trixie: if openssh-server is installed *already* then the host keys should be regenerated to avoid inheriting the template's (see official template for how)" dpkg -l openssh-server || true miniade_debug 2 "containerise_installation_trixie: see above" } install_packages() { # Particularly when installing packages for testing/unstable releases, # the existing package cache may be out of date. Hence we *always* # update the package cache. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get update" || true install_packages_$RELEASE "$@" } install_packages_bullseye() { # Disable service startup as we install packages. miniade_evaler "echo -e \"#!/bin/bash\\nexit 101\" > \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_evaler "chmod +x \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_info "installing packages ..." # Install (sensible) things that a PM/VM gets that a container doesn't. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --no-install-recommends install vim-tiny cron whiptail cron-daemon-common logrotate debconf-i18n less nano shared-mime-info xdg-user-dirs procps iputils-ping openssh-server" || true # Remove things that a PM/VM doesn't get. dialog was needed above # but no longer. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --purge remove dialog" || true # Clean up. miniade_evaler "rm \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" } install_packages_bookworm() { # Disable service startup as we install packages. miniade_evaler "echo -e \"#!/bin/bash\\nexit 101\" > \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_evaler "chmod +x \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_evaler "mount devpts -t devpts $CONTAINER_ROOTDIR/dev/pts" miniade_info "installing packages ..." # Install (sensible) things that a PM/VM gets that a container doesn't. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --no-install-recommends install vim-tiny cron whiptail cron-daemon-common logrotate debconf-i18n less nano shared-mime-info xdg-user-dirs procps iputils-ping openssh-server" || true # Remove things that a PM/VM doesn't get. dialog was needed above # but no longer. miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --purge remove dialog" || true # Clean up. miniade_evaler "umount $CONTAINER_ROOTDIR/dev/pts" miniade_evaler "rm \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" } install_packages_trixie() { miniade_info "installing packages to better align containers with KVM-VMs ..." miniade_debug 2 "install_packages_trixie: this function disabled, pending confirmation of what is needed to be done" return 0 miniade_debug 10 "install_packages_trixie: disabling install-time service startup ..." miniade_evaler "echo -e \"#!/bin/bash\\nexit 101\" > \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_evaler "chmod +x \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" miniade_debug 10 "install_packages_trixie: mounting install-time required mounts ..." miniade_evaler "mount devpts -t devpts $CONTAINER_ROOTDIR/dev/pts" miniade_evaler "mount proc -t proc $CONTAINER_ROOTDIR/proc" miniade_evaler "mount sysfs -t sysfs $CONTAINER_ROOTDIR/sys" miniade_debug 10 "install_packages_trixie: installing packages using chroot+apt-get ..." # Install (sensible) things that a PM/VM gets that a container doesn't. #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --no-install-recommends install vim-tiny cron whiptail cron-daemon-common logrotate debconf-i18n less nano shared-mime-info xdg-user-dirs procps iputils-ping openssh-server" || true # Remove things that a PM/VM doesn't get. dialog was needed above # but no longer. #miniade_evaler "chroot \"$CONTAINER_ROOTDIR\" apt-get -y --purge remove dialog" || true # Clean up. miniade_debug 10 "install_packages_trixie: unmounting install-time required mounts ..." miniade_evaler "umount $CONTAINER_ROOTDIR/sys" miniade_evaler "umount $CONTAINER_ROOTDIR/proc" miniade_evaler "umount $CONTAINER_ROOTDIR/dev/pts" miniade_debug 10 "install_packages_trixie: re-enabling install-time service startup ..." miniade_evaler "rm \"$CONTAINER_ROOTDIR/usr/sbin/policy-rc.d\"" } flush_cache_if_requested() { $FLUSH_CACHE_FLAG || return 0 miniade_evaler "rm -fr \"$CACHE_ROOTDIR/$RELEASE-$ARCH\"" } download_debian_to_cache_if_necessary() { download_debian_to_cache_if_necessary_$RELEASE "$@" } download_debian_to_cache_if_necessary_bullseye() { local PACKAGES FOUND KEYRING # This is the same as the OS-provided lxc-debian's preferred package list # except that it does not include openssh-server, apt-transport-https # net-tools or ca-certificates. None of these packages gets installed on # a "task-less" pristine PM/VM. apt-utils was added as, even with dialog # installed, there are still complaints from debconf. PACKAGES=init,ifupdown,locales,isc-dhcp-client,netbase,iproute2,dialog,apt-utils [ ! -d "$CACHE_ROOTDIR/$RELEASE-$ARCH" ] || return 0 miniade_evaler "rm -fr \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "mkdir -p \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" # That directory will become / in the container, so it is important that # (1) it itself has the right permissions and (2) it does not have any # permissions that will be propogated from directory to subdirectory # automatically. On Debian 11 and 12, /var/local is setgid! It's typically # owned by root:staff too, so there's quite some fixing to do! miniade_evaler "chmod g-s,u-s \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chown root:root \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chmod 755 \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "[ \"X\$(stat -c %u:%g:%a \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\")\" = X0:0:755 ]" || internal "chmod/chown failed" FOUND=false for KEYRING in /usr/share/keyrings/debian-archive-keyring.gpg /etc/apt/trusted.gpg.d/debian-archive-$RELEASE-stable.gpg; do [ ! -f $KEYRING ] || { FOUND=true; break; } done $FOUND || miniade_error "keyring not found" miniade_info "calling debootstrap to download debian to cache ..." miniade_evaler "debootstrap --verbose --variant=minbase --arch=$ARCH --include=$PACKAGES --keyring=$KEYRING $RELEASE \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" $MIRROR" || miniade_error "debootstrap failed" miniade_evaler "mv \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" \"$CACHE_ROOTDIR/$RELEASE-$ARCH\"" } download_debian_to_cache_if_necessary_bookworm() { local PACKAGES FOUND KEYRING # This is the same as the OS-provided lxc-debian's preferred package list # except that it does not include openssh-server, apt-transport-https # net-tools or ca-certificates. None of these packages gets installed on # a "task-less" pristine PM/VM. apt-utils was added as, even with dialog # installed, there are still complaints from debconf. PACKAGES=init,ifupdown,locales,isc-dhcp-client,netbase,iproute2,dialog,apt-utils [ ! -d "$CACHE_ROOTDIR/$RELEASE-$ARCH" ] || return 0 miniade_evaler "rm -fr \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "mkdir -p \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" # That directory will become / in the container, so it is important that # (1) it itself has the right permissions and (2) it does not have any # permissions that will be propogated from directory to subdirectory # automatically. On Debian 11 and 12, /var/local is setgid! It's typically # owned by root:staff too, so there's quite some fixing to do! miniade_evaler "chmod g-s,u-s \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chown root:root \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chmod 755 \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "[ \"X\$(stat -c %u:%g:%a \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\")\" = X0:0:755 ]" || internal "chmod/chown failed" FOUND=false for KEYRING in /usr/share/keyrings/debian-archive-keyring.gpg /etc/apt/trusted.gpg.d/debian-archive-$RELEASE-stable.gpg; do [ ! -f $KEYRING ] || { FOUND=true; break; } done $FOUND || miniade_error "keyring not found" miniade_info "calling debootstrap to download debian to cache ..." miniade_evaler "debootstrap --verbose --variant=minbase --arch=$ARCH --include=$PACKAGES --keyring=$KEYRING $RELEASE \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" $MIRROR" || miniade_error "debootstrap failed" miniade_evaler "mv \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" \"$CACHE_ROOTDIR/$RELEASE-$ARCH\"" } download_debian_to_cache_if_necessary_trixie() { local PACKAGES FOUND KEYRING # For earlier releases, I told debootstrap to install a slightly # modified list of packages. But I've since decided that that that # is not this function's job. This function should call debootstrap # in as similar way as possible to what the OS-provided template # does. So this package list is *identical* to the list in the # OS-provided template. (However, it may be necessary to add # apt-utils to this list to avoid complains from debconf.) PACKAGES=init,ifupdown,locales,ca-certificates,dialog,isc-dhcp-client,netbase,net-tools,iproute2,openssh-server,apt-transport-https # We download into $CACHE_ROOTDIR/$RELEASE-$ARCH.partial and then rename # that to $CACHE_ROOTDIR/$RELEASE-$ARCH, which means if $CACHE_ROOTDIR/$RELEASE-$ARCH # exists already then the cache has already been populated. [ ! -d "$CACHE_ROOTDIR/$RELEASE-$ARCH" ] || return 0 miniade_debug 10 "download_debian_to_cache_if_necessary_trixie: creating download directory ..." miniade_evaler "rm -fr \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "mkdir -p \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" # That directory will become / in the container, so it is important that # (1) it itself has the right permissions and (2) it does not have any # permissions that will be propogated from directory to subdirectory # automatically. On Debian 11 and 12, /var/local is setgid! It's typically # owned by root:staff too, so there's quite some fixing to do! miniade_evaler "chmod g-s,u-s \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chown root:root \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "chmod 755 \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\"" miniade_evaler "[ \"X\$(stat -c %u:%g:%a \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\")\" = X0:0:755 ]" || internal "chmod/chown failed" miniade_debug 10 "download_debian_to_cache_if_necessary_trixie: locating keyring that will allow debootstrap to successfully install things within the container using apt-get ..." FOUND=false for KEYRING in /usr/share/keyrings/debian-archive-keyring.gpg /etc/apt/trusted.gpg.d/debian-archive-$RELEASE-stable.gpg; do [ ! -f $KEYRING ] || { FOUND=true; break; } done $FOUND || miniade_error "keyring not found" miniade_info "calling debootstrap to download debian to cache ..." miniade_debug 10 "download_debian_to_cache_if_necessary_trixie: calling [debootstrap --verbose --variant=minbase --arch=$ARCH --include=$PACKAGES --keyring=$KEYRING $RELEASE \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" $MIRROR] ..." miniade_evaler "debootstrap --verbose --variant=minbase --arch=$ARCH --include=$PACKAGES --keyring=$KEYRING $RELEASE \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" $MIRROR" || miniade_error "debootstrap failed" # As mentioned above we now slide the .partial directory into place. miniade_evaler "mv \"$CACHE_ROOTDIR/$RELEASE-$ARCH.partial\" \"$CACHE_ROOTDIR/$RELEASE-$ARCH\"" } main "$@"