summaryrefslogtreecommitdiffstats
path: root/share/build-scripts
diff options
context:
space:
mode:
Diffstat (limited to 'share/build-scripts')
-rwxr-xr-xshare/build-scripts/debconf1318
-rwxr-xr-xshare/build-scripts/debconf.d/0001-preseed-file131
-rw-r--r--share/build-scripts/debconf.d/0001-preseed-file.templates18
-rwxr-xr-xshare/build-scripts/debconf.d/0002-preseed-debconf111
-rwxr-xr-xshare/build-scripts/debconf.d/0003-debconf1371
-rw-r--r--share/build-scripts/debconf.d/0003-debconf.templates276
-rwxr-xr-xshare/build-scripts/debootstrap198
7 files changed, 3423 insertions, 0 deletions
diff --git a/share/build-scripts/debconf b/share/build-scripts/debconf
new file mode 100755
index 0000000..900242d
--- /dev/null
+++ b/share/build-scripts/debconf
@@ -0,0 +1,1318 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2022 Daniel Baumann <daniel.baumann@open-infrastructure.net>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+PROJECT="open-infrastructure"
+SOFTWARE="compute-tools"
+PROGRAM="container"
+VERSION="$(container version)"
+
+SCRIPT="${0}"
+export SCRIPT
+
+CACHE="/var/cache/${PROGRAM}/build-$(basename ${SCRIPT})"
+CONFIG="/etc/${SOFTWARE}/config"
+HOOKS="/etc/${SOFTWARE}/hooks"
+MACHINES="/var/lib/machines"
+
+Parameters ()
+{
+ GETOPT_LONGOPTIONS="bind:,bind-ro:,script:,name:,preseed-file:"
+ GETOPT_OPTIONS="b:,s:,n:,p:"
+
+ PARAMETERS="$(getopt --longoptions ${GETOPT_LONGOPTIONS} --name=${SCRIPT} --options ${GETOPT_OPTIONS} --shell sh -- ${@})"
+
+ if [ "${?}" != "0" ]
+ then
+ echo "'${SCRIPT}': getopt exit" >&2
+ exit 1
+ fi
+
+ eval set -- "${PARAMETERS}"
+
+ while true
+ do
+ case "${1}" in
+ -b|--bind)
+ # ignore
+ shift 2
+ ;;
+
+ --bind-ro)
+ # ignore
+ shift 2
+ ;;
+
+ --cnt.auto)
+ # ignore
+ shift 2
+ ;;
+
+ --cnt.container-server)
+ # ignore
+ shift 2
+ ;;
+
+ -s|--script)
+ # ignore
+ shift 2
+ ;;
+
+ -n|--name)
+ NAME="${2}"
+ shift 2
+ ;;
+
+ --preseed-file)
+ PRESEED_FILE="${2}"
+ shift 2
+ ;;
+
+ --)
+ shift 1
+ break
+ ;;
+
+ *)
+ echo "'${SCRIPT}': getopt error" >&2
+ exit 1
+ ;;
+ esac
+ done
+}
+
+Usage ()
+{
+ echo "Usage: container build -n|--name NAME -s|--script ${SCRIPT} -- [-p|--preseed-file FILE]" >&2
+ exit 1
+}
+
+Parameters "${@}"
+
+if [ -z "${NAME}" ]
+then
+ Usage
+fi
+
+if [ -e "${MACHINES}/${NAME}" ]
+then
+ echo "'${NAME}': container already exists" >&2
+ exit 1
+fi
+
+if [ "$(id -u)" -ne 0 ]
+then
+ echo "'${NAME}': need root privileges" >&2
+ exit 1
+fi
+
+Mount ()
+{
+ # Mounting rw bind mounts
+ if [ -n "${BIND}" ]
+ then
+ BINDS="$(echo ${BIND} | sed -e 's|;| |g')"
+
+ for ENTRY in ${BINDS}
+ do
+ SOURCE="$(echo ${ENTRY} | awk -F: '{ print $1 }')"
+ TARGET="$(echo ${ENTRY} | awk -F: '{ print $2 }')"
+
+ mkdir -p "${SOURCE}"
+ mkdir -p "${MACHINES}/${NAME}/${TARGET}"
+
+ mount -o bind "${SOURCE}" "${MACHINES}/${NAME}/${TARGET}"
+ done
+ fi
+
+ # Mounting ro bind mounts
+ if [ -n "${BIND_RO}" ]
+ then
+ BINDS_RO="$(echo ${BIND_RO} | sed -e 's|;| |g')"
+
+ for ENTRY in ${BINDS_RO}
+ do
+ SOURCE="$(echo ${ENTRY} | awk -F: '{ print $1 }')"
+ TARGET="$(echo ${ENTRY} | awk -F: '{ print $2 }')"
+
+ mkdir -p "${SOURCE}"
+ mkdir -p "${MACHINES}/${NAME}/${TARGET}"
+
+ mount -o rbind "${SOURCE}" "${MACHINES}/${NAME}/${TARGET}"
+ done
+ fi
+
+ # Mounting overlay mounts
+ if [ -n "${CNT_OVERLAY}" ]
+ then
+ CNT_OVERLAYS="$(echo ${CNT_OVERLAY} | sed -e 's|;| |g')"
+
+ COUNT="0"
+ for CNT_OVERLAY in ${CNT_OVERLAYS}
+ do
+ DIRECTORY_LOWER="$(echo ${CNT_OVERLAY} | awk -F: '{ print $1 }')"
+ DIRECTORY_UPPER="$(echo ${CNT_OVERLAY} | awk -F: '{ print $2 }')"
+ DIRECTORY_WORK="$(echo ${CNT_OVERLAY} | awk -F: '{ print $3 }')"
+ DIRECTORY_MERGED="$(echo ${CNT_OVERLAY} | awk -F: '{ print $4 }')"
+
+ COUNT="$((${COUNT} + 1))"
+ CNT_OVERLAY_OPTION="$(echo ${CNT_OVERLAY_OPTIONS} | awk -F ';' "{ print \$${COUNT} }")"
+
+ for DIRECTORY in "${DIRECTORY_LOWER}" "${DIRECTORY_UPPER}" "${DIRECTORY_WORK}" "${DIRECTORY_MERGED}"
+ do
+ mkdir -p "${DIRECTORY}"
+ done
+
+ if ! findmnt -n -o SOURCE "${DIRECTORY_MERGED}" | grep -qs '^overlay-'
+ then
+ if [ -n "${CNT_OVERLAY_OPTION}" ]
+ then
+ CNT_OVERLAY_OPTION="-o ${CNT_OVERLAY_OPTION}"
+ fi
+
+ mount -t overlay overlay-${NAME} ${CNT_OVERLAY_OPTION} -olowerdir="${DIRECTORY_LOWER}",upperdir="${DIRECTORY_UPPER}",workdir="${DIRECTORY_WORK}" "${DIRECTORY_MERGED}"
+ fi
+ done
+ fi
+}
+
+Umount ()
+{
+ # Unmounting overlay mounts
+ if [ -n "${CNT_OVERLAY}" ]
+ then
+ CNT_OVERLAYS="$(echo ${CNT_OVERLAY} | sed -e 's|;| |g')"
+
+ for CNT_OVERLAY in ${CNT_OVERLAYS}
+ do
+ DIRECTORY_LOWER="$(echo ${CNT_OVERLAY} | awk -F: '{ print $1 }')"
+ DIRECTORY_UPPER="$(echo ${CNT_OVERLAY} | awk -F: '{ print $2 }')"
+ DIRECTORY_WORK="$(echo ${CNT_OVERLAY} | awk -F: '{ print $3 }')"
+ DIRECTORY_MERGED="$(echo ${CNT_OVERLAY} | awk -F: '{ print $4 }')"
+
+ umount -f "${DIRECTORY_MERGED}" > /dev/null 2>&1 || true
+
+ for DIRECTORY in "${DIRECTORY_LOWER}" "${DIRECTORY_UPPER}" "${DIRECTORY_WORK}" "${DIRECTORY_MERGED}"
+ do
+ rmdir --ignore-fail-on-non-empty --parents ${DIRECTORY} > /dev/null 2>&1 || true
+ done
+ done
+
+ # empty workdir otherwise there might happen stale file handles
+ if [ -d "${DIRECTORY_WORK}" ]
+ then
+ rm --preserve-root --one-file-system -rf "${DIRECTORY_WORK}"/*
+ fi
+ fi
+
+ # Unmounting ro bind mounts
+ if [ -n "${BIND_RO}" ]
+ then
+ # unmount in reverse order to allow nested bind mounts
+ BINDS_RO="$(echo ${BIND_RO} | sed -e 's|;| |g' | awk '{ for (i=NF; i>=1; i--) printf "%s ", $i; print ""}')"
+
+ for ENTRY in ${BINDS_RO}
+ do
+ TARGET="$(echo ${ENTRY} | awk -F: '{ print $2 }')"
+
+ umount -f "${MACHINES}/${NAME}/${TARGET}" > /dev/null 2>&1 || true
+ done
+ fi
+
+ # Unmounting rw bind mounts
+ if [ -n "${BIND}" ]
+ then
+ # unmount in reverse order to allow nested bind mounts
+ BINDS="$(echo ${BIND} | sed -e 's|;| |g' | awk '{ for (i=NF; i>=1; i--) printf "%s ", $i; print ""}')"
+
+ for ENTRY in ${BINDS}
+ do
+ TARGET="$(echo ${ENTRY} | awk -F: '{ print $2 }')"
+
+ umount -f "${MACHINES}/${NAME}/${TARGET}" > /dev/null 2>&1 || true
+ done
+ fi
+
+ # Unmounting pseudo-filesystems
+ umount -f "${DIRECTORY}/dev/pts" > /dev/null 2>&1 || true
+ umount -f "${DIRECTORY}/proc" > /dev/null 2>&1 || true
+ umount -f "${DIRECTORY}/sys" > /dev/null 2>&1 || true
+}
+
+Chroot ()
+{
+ CHROOT="${1}"
+ shift
+
+ chroot "${CHROOT}" /usr/bin/env -i \
+ LC_ALL="C" PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/games:/usr/games" TERM="${TERM}" \
+ DEBIAN_FRONTEND="${DEBCONF_FRONTEND}" DEBIAN_PRIORITY="${DEBCONF_PRIORITY}" \
+ DEBCONF_NONINTERACTIVE_SEEN="true" DEBCONF_NOWARNINGS="true" \
+ ftp_proxy="${ftp_proxy}" http_proxy="${http_proxy}" \
+ ${@}
+}
+
+Upgrade_system ()
+{
+ DIRECTORY="${1}"
+
+ # Mount pseudo-filesystems
+ mount -o bind /dev/pts "${DIRECTORY}/dev/pts"
+ mount -o bind /proc "${DIRECTORY}/proc"
+ mount -o bind /sys "${DIRECTORY}/sys"
+
+ # Disable dpkg syncing
+
+cat > "${DIRECTORY}/etc/dpkg/dpkg.cfg.d/${SOFTWARE}" << EOF
+force-unsafe-io
+EOF
+
+ # Create policy-rc.d file
+
+cat > "${DIRECTORY}/usr/sbin/policy-rc.d" << EOF
+#!/bin/sh
+echo "All runlevel operations denied by policy" >&2
+exit 101
+EOF
+
+ chmod 0755 "${DIRECTORY}/usr/sbin/policy-rc.d"
+
+ # Upgrade system
+ Chroot "${DIRECTORY}" "apt update"
+ Chroot "${DIRECTORY}" "apt --yes --option Dpkg::Options::=--force-confnew upgrade"
+ Chroot "${DIRECTORY}" "apt --yes --option Dpkg::Options::=--force-confnew dist-upgrade"
+
+ # Install systemd support packages
+ Chroot "${DIRECTORY}" "apt --yes install dbus libpam-systemd systemd-sysv"
+
+ Chroot "${DIRECTORY}" "apt clean"
+}
+
+Cleanup_system ()
+{
+ DIRECTORY="${1}"
+
+ Chroot "${DIRECTORY}" "apt --yes --purge autoremove"
+ Chroot "${DIRECTORY}" "apt clean"
+
+ # Cleanup
+ rm -f "${DIRECTORY}/etc/dpkg/dpkg.cfg.d/${SOFTWARE}"
+ rm -f "${DIRECTORY}/usr/sbin/policy-rc.d"
+
+ # Unmount pseudo-filesystems
+ umount -f "${DIRECTORY}/dev/pts" > /dev/null 2>&1 || true
+ umount -f "${DIRECTORY}/proc" > /dev/null 2>&1 || true
+ umount -f "${DIRECTORY}/sys" > /dev/null 2>&1 || true
+}
+
+Debconf ()
+{
+ # Configure local debconf
+ mkdir -p "/tmp/${SOFTWARE}"
+ DEBCONF_TMPDIR="$(mktemp -d -p "/tmp/${SOFTWARE}" -t $(basename ${0}).XXXX)"
+ export DEBCONF_TMPDIR
+
+ mkdir -p "${DEBCONF_TMPDIR}/debconf"
+
+cat > "${DEBCONF_TMPDIR}/debconf.systemrc" << EOF
+Config: configdb
+Templates: templatedb
+
+Name: config
+Driver: File
+Mode: 644
+Reject-Type: password
+Filename: ${DEBCONF_TMPDIR}/debconf/config.dat
+
+Name: passwords
+Driver: File
+Mode: 600
+Backup: false
+Required: false
+Accept-Type: password
+Filename: ${DEBCONF_TMPDIR}/debconf/passwords.dat
+
+Name: configdb
+Driver: Stack
+Stack: config, passwords
+
+Name: templatedb
+Driver: File
+Mode: 644
+Filename: ${DEBCONF_TMPDIR}/debconf/templates.dat
+EOF
+
+ DEBCONF_SYSTEMRC="${DEBCONF_TMPDIR}/debconf.systemrc"
+ export DEBCONF_SYSTEMRC
+}
+
+Bootstrap ()
+{
+ DIRECTORY="${1}"
+
+ EXCLUDE="ifupdown"
+ INCLUDE="dbus"
+
+ # apt repositories
+ INCLUDE="${INCLUDE},gnupg"
+
+ if ( echo "${MIRROR}" | grep -qs '^https' ) || \
+ ( echo "${PARENT_MIRROR}" | grep -qs '^https' )
+ then
+ INCLUDE="${INCLUDE},apt-transport-https,ca-certificates"
+ fi
+
+ case "${MODE}" in
+ progress-linux)
+ INCLUDE="${INCLUDE},progress-linux,gnupg"
+ ;;
+ esac
+
+ mkdir -p "$(dirname ${DIRECTORY})"
+
+ case "${BOOTSTRAP}" in
+ debootstrap)
+ debootstrap --verbose --arch=${ARCHITECTURE} --components=${PARENT_ARCHIVE_AREAS} \
+ --exclude=${EXCLUDE} --include=${INCLUDE} ${PARENT_DISTRIBUTION} "${DIRECTORY}" ${PARENT_MIRROR}
+ ;;
+
+ mmdebstrap)
+ mmdebstrap --arch=${ARCHITECTURE} --components=${PARENT_ARCHIVE_AREAS} \
+ --format=directory --mode=root --aptopt='APT::Sandbox::User "root"' \
+ --include=${INCLUDE} ${PARENT_DISTRIBUTION} "${DIRECTORY}" ${PARENT_MIRROR}
+ ;;
+
+ *)
+ echo "'${NAME}': ${BOOTSTRAP} - not supported" >&2
+ exit 1
+ ;;
+ esac
+}
+
+Image ()
+{
+ DIRECTORY="${1}"
+
+ FILES="${IMAGE}"
+
+ for NUMBER in $(seq 1 ${IMAGE_NUMBER})
+ do
+ eval FILES="${FILES} $`echo IMAGE${NUMBER}`"
+ done
+
+ for FILE in ${FILES}
+ do
+ case "${FILE}" in
+ *.gz)
+ TAR_OPTIONS="--gzip"
+
+ if [ ! -e /bin/gzip ]
+ then
+ echo -en "\n"
+ echo "'${NAME}': /bin/lzip - no such file." >&2
+ exit 1
+ fi
+ ;;
+
+ *.lz)
+ TAR_OPTIONS="--lzip"
+
+ if [ ! -e /usr/bin/lzip ]
+ then
+ echo -en "\n"
+ echo "'${NAME}': /usr/bin/lzip - no such file." >&2
+ exit 1
+ fi
+ ;;
+
+ *.xz)
+ TAR_OPTIONS="--xz"
+
+ if [ ! -e /usr/bin/xz ]
+ then
+ echo -en "\n"
+ echo "'${NAME}': /usr/bin/xz - no such file." >&2
+ exit 1
+ fi
+ ;;
+
+ *)
+ TAR_OPTIONS=""
+ ;;
+ esac
+
+ mkdir -p "${DIRECTORY}"
+
+ echo "Using ${FILE}"
+
+ if [ -e /usr/bin/pv ]
+ then
+ curl --fail --location --progress-bar --user-agent ${SOFTWARE}/${VERSION} --http2 ${CURL_TIME_COND} \
+ "${FILE}" -o - | \
+ pv --format '%p' --width 77 | \
+ tar -C "${DIRECTORY}" --strip 1 ${TAR_OPTIONS} -xf -
+ #pv --format '%p' --width 77 "${CACHE}/${FILE}" | tar xf - ${TAR_OPTIONS} -C "${DIRECTORY}" --strip 1
+ else
+ curl --fail --location --progress-bar --user-agent ${SOFTWARE}/${VERSION} --http2 ${CURL_TIME_COND} \
+ "${FILE}" -o - | \
+ tar -C "${DIRECTORY}" --strip 1 ${TAR_OPTIONS} -xf -
+ fi
+
+ echo " ok."
+ done
+
+ # Writing resolv.conf
+ rm -f "${DIRECTORY}/etc/resolv.conf"
+ cp /etc/resolv.conf "${DIRECTORY}/etc"
+}
+
+Configure_apt ()
+{
+ DIRECTORY="${1}"
+
+ # Configure apt
+ rm -f "${DIRECTORY}/etc/apt/sources.list"
+
+ PARENT_AREA="$(echo ${PARENT_ARCHIVE_AREAS} | sed -e 's|,| |g')"
+ PARENT_DIST="$(echo ${PARENT_DISTRIBUTION} | sed -e 's|-backports||')"
+
+cat > "${DIRECTORY}/etc/apt/sources.list.d/debian.list" << EOF
+# /etc/apt/sources.list.d/debian.list
+
+deb ${PARENT_MIRROR} ${PARENT_DIST} ${PARENT_AREA}
+EOF
+
+ case "${MODE}" in
+ progress-linux)
+
+cat > "${DIRECTORY}/progress-linux.cfg" << EOF
+progress-linux progress-linux/archives multiselect $(echo ${ARCHIVES} | sed -e 's| |, |g')
+progress-linux progress-linux/archive-areas multiselect $(echo ${ARCHIVE_AREAS} | sed -e 's|,| |g')
+EOF
+
+ Chroot "${DIRECTORY}" "debconf-set-selections progress-linux.cfg"
+ Chroot "${DIRECTORY}" "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=criticial dpkg-reconfigure progress-linux"
+
+ rm -f "${DIRECTORY}/progress-linux.cfg"
+
+ case "${INSTALLER}" in
+ bootstrap)
+ Chroot "${DIRECTORY}" "apt update"
+ ;;
+ esac
+ ;;
+ esac
+}
+
+Deconfigure_system ()
+{
+ DIRECTORY="${1}"
+
+ # Configure fstab
+
+cat > "${DIRECTORY}/etc/fstab" << EOF
+# /etc/fstab: static file system information.
+#
+# Use 'blkid' to print the universally unique identifier for a
+# device; this may be used with UUID= as a more robust way to name devices
+# that works even if disks are added and removed. See fstab(5).
+#
+# <file system> <mount point> <type> <options> <dump> <pass>
+
+EOF
+
+ # Fix /etc/mtab
+ rm -f "${DIRECTORY}/etc/mtab"
+ ln -s /proc/self/mounts "${DIRECTORY}/etc/mtab"
+
+ # Removing machine-id
+ rm -f "${DIRECTORY}/etc/machine-id"
+
+ # Removing resolv.conf
+ rm -f "${DIRECTORY}/etc/resolv.conf"
+ cp /etc/resolv.conf "${DIRECTORY}/etc"
+
+ # Removing hosts/hostname
+ rm -f "${DIRECTORY}"/etc/hosts
+ rm -f "${DIRECTORY}"/etc/hostname
+
+ # Removing openssh-server host keys
+ rm -f "${DIRECTORY}"/etc/ssh/ssh_host_*_key
+ rm -f "${DIRECTORY}"/etc/ssh/ssh_host_*_key.pub
+}
+
+Configure_system ()
+{
+ DIRECTORY="${1}"
+
+ # Overwrite resolv.conf from cache with hosts resolv.conf
+ rm -f "${DIRECTORY}/etc/resolv.conf"
+ cp /etc/resolv.conf "${DIRECTORY}/etc"
+
+ echo "${NAME}" > "${DIRECTORY}/etc/hostname"
+
+ # Configure apt
+ rm -f "${DIRECTORY}/etc/apt/sources.list"
+
+ PARENT_AREA="$(echo ${PARENT_ARCHIVE_AREAS} | sed -e 's|,| |g')"
+ PARENT_DIST="$(echo ${PARENT_DISTRIBUTION} | sed -e 's|-backports||')"
+
+cat > "${DIRECTORY}/etc/apt/sources.list.d/debian.list" << EOF
+# /etc/apt/sources.list.d/debian.list
+
+deb ${PARENT_MIRROR} ${PARENT_DIST} ${PARENT_AREA}
+EOF
+
+ for PARENT_REPO in ${PARENT_ARCHIVES}
+ do
+ case "${PARENT_REPO}" in
+ buster-security)
+ echo "deb ${PARENT_MIRROR_SECURITY} ${PARENT_DIST}/updates ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+
+ ${PARENT_DIST}-security)
+ echo "deb ${PARENT_MIRROR_SECURITY} ${PARENT_DIST}-security ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+
+ ${PARENT_DIST}-updates)
+ echo "deb ${PARENT_MIRROR} ${PARENT_DIST}-updates ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+
+ ${PARENT_DIST}-backports)
+ echo "deb ${PARENT_MIRROR} ${PARENT_DIST}-backports ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+
+ ${PARENT_DIST}-proposed-updates)
+ echo "deb ${PARENT_MIRROR} ${PARENT_DIST}-proposed-updates ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+
+ experimental)
+ echo "deb ${PARENT_MIRROR} experimental ${PARENT_AREA}" >> "${DIRECTORY}/etc/apt/sources.list.d/debian.list"
+ ;;
+ esac
+ done
+
+ case "${MODE}" in
+ progress-linux)
+
+cat > "${DIRECTORY}/progress-linux.cfg" << EOF
+progress-linux progress-linux/archives multiselect $(echo ${ARCHIVES} | sed -e 's| |, |g')
+progress-linux progress-linux/archive-areas multiselect $(echo ${ARCHIVE_AREAS} | sed -e 's|,| |g')
+EOF
+
+ Chroot "${DIRECTORY}" "debconf-set-selections progress-linux.cfg"
+ Chroot "${DIRECTORY}" "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=criticial dpkg-reconfigure progress-linux"
+
+ rm -f "${DIRECTORY}/progress-linux.cfg"
+ ;;
+ esac
+
+ if [ "${APT_RECOMMENDS}" = "false" ]
+ then
+
+cat > "${DIRECTORY}/etc/apt/apt.conf.d/recommends.conf" << EOF
+APT::Install-Recommends "false";
+EOF
+
+ fi
+
+ # Add local archives configured from preseed file
+ if ls "${DEBCONF_TMPDIR}/apt"/*.list > /dev/null 2>&1
+ then
+ cp "${DEBCONF_TMPDIR}/apt"/*.list "${DIRECTORY}/etc/apt/sources.list.d"
+
+ if ls "${DEBCONF_TMPDIR}/apt"/*.key > /dev/null 2>&1
+ then
+ for KEY in "${DEBCONF_TMPDIR}/apt"/*.key
+ do
+ cp "${KEY}" "${DIRECTORY}"
+ Chroot "${DIRECTORY}" "apt-key add $(basename ${KEY})"
+ rm -f "${DIRECTORY}/$(basename ${KEY})"
+ done
+ fi
+
+ if ls "${DEBCONF_TMPDIR}/apt"/*.pref > /dev/null 2>&1
+ then
+ cp "${DEBCONF_TMPDIR}/apt"/*.pref "${DIRECTORY}/etc/apt/preferences.d"
+ fi
+ fi
+
+ Upgrade_system "${DIRECTORY}"
+
+ # Preseed system
+ if [ -n "${PRESEED_FILE}" ]
+ then
+ for FILE in ${PRESEED_FILE}
+ do
+ if [ -e /usr/bin/kdig ]
+ then
+ DIG="/usr/bin/kdig"
+ elif [ -e /usr/bin/dig ]
+ then
+ DIG="/usr/bin/dig"
+ fi
+
+ if [ -n "${DIG}" ]
+ then
+ IPV4_ADDRESS1="$(${DIG} A +short ${NAME} | tail -n1)"
+ IPV4_ADDRESS1_PART1="$(echo ${IPV4_ADDRESS1} | cut -d. -f1)"
+ IPV4_ADDRESS1_PART2="$(echo ${IPV4_ADDRESS1} | cut -d. -f2)"
+ IPV4_ADDRESS1_PART3="$(echo ${IPV4_ADDRESS1} | cut -d. -f3)"
+ IPV4_ADDRESS1_PART4="$(echo ${IPV4_ADDRESS1} | cut -d. -f4)"
+
+ IPV6_ADDRESS1="$(${DIG} AAAA +short ${NAME} | tail -n1)"
+ # FIXME: address parts
+
+ export IPV4_ADDRESS1 IPV4_ADDRESS1_PART1 IPV4_ADDRESS1_PART2 IPV4_ADDRESS1_PART3 IPV4_ADDRESS1_PART4
+ export IPV6_ADDRESS1
+ fi
+
+ sed -e "s|@FILE@|${FILE}|g" \
+ -e "s|@NAME@|${NAME}|g" \
+ -e "s|@IPV4_ADDRESS1@|${IPV4_ADDRESS1}|g" \
+ -e "s|@IPV4_ADDRESS1_PART1@|${IPV4_ADDRESS1_PART1}|g" \
+ -e "s|@IPV4_ADDRESS1_PART2@|${IPV4_ADDRESS1_PART2}|g" \
+ -e "s|@IPV4_ADDRESS1_PART3@|${IPV4_ADDRESS1_PART3}|g" \
+ -e "s|@IPV4_ADDRESS1_PART4@|${IPV4_ADDRESS1_PART4}|g" \
+ -e "s|@IPV6_ADDRESS1@|${IPV6_ADDRESS1}|g" \
+ "${FILE}" >> "${DIRECTORY}/preseed.cfg"
+ done
+
+ Chroot "${DIRECTORY}" "debconf-set-selections preseed.cfg"
+
+ rm -f "${DIRECTORY}/preseed.cfg"
+ fi
+
+ # Manual hack to workaround broken preseeding in locales package
+ if [ -n "${PRESEED_FILE}" ]
+ then
+ for FILE in ${PRESEED_FILE}
+ do
+ if grep -qs locales "${FILE}"
+ then
+ if Chroot "${DIRECTORY}" dpkg --get-selections | awk '{ print $1 }' | grep -qs '^locales$'
+ then
+ rm -f "${DIRECTORY}/etc/default/locale" "${DIRECTORY}/etc/locale.gen"
+ Chroot "${DIRECTORY}" "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=criticial dpkg-reconfigure locales"
+
+ break
+ fi
+ fi
+ done
+ fi
+
+ # Manual hack to create conffiles when using locales-all instead of locales
+ if [ ! -e "${DIRECTORY}/etc/environment" ]
+ then
+ echo "LANG=C.UTF-8" >> "${DIRECTORY}/etc/environment"
+ fi
+
+ if [ ! -e "${DIRECTORY}/etc/default/locale" ]
+ then
+ echo "LANG=C.UTF-8" >> "${DIRECTORY}/etc/default/locale"
+ fi
+
+ # Manual hack to workaround broken preseeding in tzdata package
+ if [ -n "${PRESEED_FILE}" ]
+ then
+ for FILE in ${PRESEED_FILE}
+ do
+ if grep -qs tzdata "${FILE}"
+ then
+ rm -f "${DIRECTORY}/etc/localtime" "${DIRECTORY}/etc/timezone"
+ Chroot "${DIRECTORY}" "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=criticial dpkg-reconfigure tzdata"
+
+ break
+ fi
+ done
+ fi
+
+ if [ -n "${PACKAGES}" ]
+ then
+ Chroot "${DIRECTORY}" "apt --option Dpkg::Options::=--force-confnew --yes install ${PACKAGES}"
+ fi
+
+ # Manual hack to regenerate ssh keys
+ if Chroot "${DIRECTORY}" dpkg --get-selections | awk '{ print $1 }' | grep -qs '^openssh-server$' && \
+ ! ls "${DIRECTORY}"/etc/ssh/ssh_host_*_key > /dev/null 2>&1
+ then
+ Chroot "${DIRECTORY}" "DEBIAN_FRONTEND=noninteractive DEBIAN_PRIORITY=criticial dpkg-reconfigure openssh-server"
+ fi
+
+ # container command
+ if [ -n "${CONTAINER_COMMAND}" ]
+ then
+ echo "${CONTAINER_COMMAND}" > "${DIRECTORY}/.container-command"
+
+ chmod 0755 "${DIRECTORY}/.container-command"
+ Chroot "${DIRECTORY}" "sh /.container-command"
+
+ rm -f "${DIRECTORY}/.container-command"
+ fi
+
+ for NUMBER in $(seq 1 ${CONTAINER_COMMAND_NUMBER})
+ do
+ eval COMMAND="$`echo CONTAINER_COMMAND${NUMBER}`"
+
+ echo "${COMMAND}" > "${DIRECTORY}/.container-command"
+
+ chmod 0755 "${DIRECTORY}/.container-command"
+ Chroot "${DIRECTORY}" "sh /.container-command"
+
+ rm -f "${DIRECTORY}/.container-command"
+ done
+}
+
+Configure_network ()
+{
+ DIRECTORY="${1}"
+
+ # Create /etc/resolv.conf
+ rm -f "${DIRECTORY}/etc/resolv.conf.tmp"
+
+ if [ -n "${NAMESERVER_DOMAIN}" ]
+ then
+ echo "domain ${NAMESERVER_DOMAIN}" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ fi
+
+ if [ -n "${NAMESERVER_SEARCH}" ]
+ then
+ echo "search ${NAMESERVER_SEARCH}" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ fi
+
+ if [ -n "${NAMESERVER_SERVER}" ]
+ then
+ if [ -e "${DIRECTORY}/etc/resolv.conf.tmp" ]
+ then
+ echo "" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ fi
+
+ for NAMESERVER in $(echo ${NAMESERVER_SERVER} | sed -e 's|,| |g')
+ do
+ echo "nameserver ${NAMESERVER}" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ done
+ fi
+
+ if [ -n "${NAMESERVER_OPTIONS}" ]
+ then
+ if [ -e "${DIRECTORY}/etc/resolv.conf.tmp" ]
+ then
+ echo "" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ fi
+
+ echo "options ${NAMESERVER_OPTIONS}" >> "${DIRECTORY}/etc/resolv.conf.tmp"
+ fi
+
+ if [ -e "${DIRECTORY}/etc/resolv.conf.tmp" ]
+ then
+ mv "${DIRECTORY}/etc/resolv.conf.tmp" "${DIRECTORY}/etc/resolv.conf"
+ fi
+
+ # Create /etc/hosts
+ rm -f "${DIRECTORY}/etc/hosts.tmp"
+
+ if [ -n "${NETWORK1_IPV4_ADDRESS}" ]
+ then
+
+cat >> "${DIRECTORY}/etc/hosts.tmp" << EOF
+${NETWORK1_IPV4_ADDRESS} ${NAME}
+EOF
+
+ fi
+
+ if [ -n "${NETWORK1_IPV6_ADDRESS}" ]
+ then
+
+cat >> "${DIRECTORY}/etc/hosts.tmp" << EOF
+${NETWORK1_IPV6_ADDRESS} ${NAME}
+EOF
+
+ fi
+
+ if [ -n "${NETWORK1_IPV4_ADDRESS}" ] || [ -n "${NETWORK1_IPV6_ADDRESS}" ]
+ then
+ echo >> "${DIRECTORY}/etc/hosts.tmp"
+ fi
+
+ if [ -z "${NETWORK1_IPV4_ADDRESS}" ] && [ -z "${NETWORK1_IPV6_ADDRESS}" ]
+ then
+ # localhost only
+
+cat > "${DIRECTORY}/etc/hosts.tmp" << EOF
+127.0.0.1 localhost ${NAME}
+::1 localhost ${NAME}
+EOF
+
+ else
+
+cat > "${DIRECTORY}/etc/hosts.tmp" << EOF
+127.0.0.1 localhost
+::1 localhost
+EOF
+
+ fi
+
+cat >> "${DIRECTORY}/etc/hosts.tmp" << EOF
+
+# The following lines are desirable for IPv6 capable hosts
+::1 ip6-localhost ip6-loopback
+fe00::0 ip6-localnet
+ff00::0 ip6-mcastprefix
+ff02::1 ip6-allnodes
+ff02::2 ip6-allrouters
+EOF
+
+ mv "${DIRECTORY}/etc/hosts.tmp" "${DIRECTORY}/etc/hosts"
+}
+
+Configure_systemd_networkd ()
+{
+ DIRECTORY="${1}"
+
+ # Enable systemd-networkd
+ chroot "${DIRECTORY}" systemctl enable systemd-networkd
+
+ for NUMBER in $(seq 1 ${NETWORK_NUMBER})
+ do
+ eval IPV4_COMMENT="$`echo NETWORK${NUMBER}_IPV4_COMMENT`"
+ eval IPV4_METHOD="$`echo NETWORK${NUMBER}_IPV4_METHOD`"
+ eval IPV4_ADDRESS="$`echo NETWORK${NUMBER}_IPV4_ADDRESS`"
+ eval IPV4_GATEWAY="$`echo NETWORK${NUMBER}_IPV4_GATEWAY`"
+ eval IPV4_NETMASK="$`echo NETWORK${NUMBER}_IPV4_NETMASK`"
+ eval IPV4_POST_UP="$`echo NETWORK${NUMBER}_IPV4_POST_UP`"
+ eval IPV4_POST_DOWN="$`echo NETWORK${NUMBER}_IPV4_POST_DOWN`"
+
+ eval IPV6_COMMENT="$`echo NETWORK${NUMBER}_IPV6_COMMENT`"
+ eval IPV6_METHOD="$`echo NETWORK${NUMBER}_IPV6_METHOD`"
+ eval IPV6_ADDRESS="$`echo NETWORK${NUMBER}_IPV6_ADDRESS`"
+ eval IPV6_GATEWAY="$`echo NETWORK${NUMBER}_IPV6_GATEWAY`"
+ eval IPV6_NETMASK="$`echo NETWORK${NUMBER}_IPV6_NETMASK`"
+ eval IPV6_POST_UP="$`echo NETWORK${NUMBER}_IPV6_POST_UP`"
+ eval IPV6_POST_DOWN="$`echo NETWORK${NUMBER}_IPV6_POST_DOWN`"
+
+ if [ "${IPV4_METHOD}" != "none" ] || [ "${IPV6_METHOD}" != "none" ]
+ then
+
+cat > "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+[Match]
+Name=eno${NUMBER}
+EOF
+
+ fi
+
+ if [ -n "${IPV4_METHOD}" ] && [ "${IPV4_METHOD}" != "none" ]
+ then
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+
+[Network]
+EOF
+
+ if [ -n "${IPV4_COMMENT}" ]
+ then
+ echo "Description=${IPV4_COMMENT}" >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network"
+ fi
+
+ case "${IPV4_METHOD}" in
+ dhcp)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=ipv4
+EOF
+
+ ;;
+
+ static)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=no
+Address=${IPV4_ADDRESS}/${IPV4_NETMASK}
+EOF
+
+ if [ -n "${IPV4_GATEWAY}" ]
+ then
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+Gateway=${IPV4_GATEWAY}
+EOF
+
+ fi
+ ;;
+
+ stub)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=no
+EOF
+
+ ;;
+ esac
+
+ if [ -n "${IPV4_POST_UP}" ]
+ then
+
+cat > "${DIRECTORY}/etc/systemd/system/cnt-ipv4-post-up-eno${NUMBER}.service" << EOF
+[Unit]
+Description=${SOFTWARE} IPV4_POST_UP
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "${IPV4_POST_UP}"
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+ chroot "${DIRECTORY}" systemctl enable cnt-ipv4-post-up-eno${NUMBER}.service
+ fi
+
+ if [ -n "${IPV4_POST_DOWN}" ]
+ then
+
+cat > "${DIRECTORY}/etc/systemd/system/cnt-ipv4-post-down-eno${NUMBER}.service" << EOF
+[Unit]
+Description=${SOFTWARE} IPV4_POST_DOWN
+After=network.target
+Wants=network.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "${IPV4_POST_DOWN}"
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+ chroot "${DIRECTORY}" systemctl enable cnt-ipv4-post-down-eno${NUMBER}.service
+ fi
+ fi
+
+ if [ -n "${IPV6_METHOD}" ] && [ "${IPV6_METHOD}" != "none" ]
+ then
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+
+[Network]
+EOF
+
+ if [ -n "${IPV6_COMMENT}" ]
+ then
+ echo "Description=${IPV6_COMMENT}" >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network"
+ fi
+
+ case "${IPV6_METHOD}" in
+ dhcp)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=ipv6
+EOF
+
+ ;;
+
+ static)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=no
+IPv6AcceptRA=no
+Address=${IPV6_ADDRESS}/${IPV6_NETMASK}
+EOF
+
+ if [ -n "${IPV6_GATEWAY}" ]
+ then
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+Gateway=${IPV6_GATEWAY}
+EOF
+
+ fi
+ ;;
+
+ stub)
+
+cat >> "${DIRECTORY}/etc/systemd/network/eno${NUMBER}.network" << EOF
+DHCP=no
+IPv6AcceptRA=no
+EOF
+
+ ;;
+ esac
+
+ if [ -n "${IPV6_POST_UP}" ]
+ then
+
+cat > "${DIRECTORY}/etc/systemd/system/cnt-ipv6-post-up-eno${NUMBER}.service" << EOF
+[Unit]
+Description=${SOFTWARE} IPV6_POST_UP
+After=network-online.target
+Wants=network-online.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "${IPV6_POST_UP}"
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+ chroot "${DIRECTORY}" systemctl enable cnt-ipv6-post-up-eno${NUMBER}.service
+ fi
+
+ if [ -n "${IPV6_POST_DOWN}" ]
+ then
+
+cat > "${DIRECTORY}/etc/systemd/system/cnt-ipv6-post-down-eno${NUMBER}.service" << EOF
+[Unit]
+Description=${SOFTWARE} IPV6_POST_DOWN
+After=network.target
+Wants=network.target
+
+[Service]
+Type=oneshot
+ExecStart=/bin/sh -c "${IPV6_POST_DOWN}"
+
+[Install]
+WantedBy=multi-user.target
+EOF
+
+ chroot "${DIRECTORY}" systemctl enable cnt-ipv6-post-down-eno${NUMBER}.service
+ fi
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+}
+
+Commands ()
+{
+ DIRECTORY="${1}"
+
+ # maximum of 15 characters, prefix is 'veth-'
+ HOSTNAME_SHORT="$(echo ${NAME} | cut -c-8)"
+ HOST_INTERFACE_NAME="$(echo ${NETWORK1_VETH:-veth-${HOSTNAME_SHORT}-0})"
+
+ sed -i -e "s|^cnt.auto=.*|cnt.auto=${CNT_AUTO}|g" \
+ -e "s|^cnt.container-server=.*|cnt.container-server=${CNT_CONTAINER_SERVER}|g" \
+ -e "s|^cnt.network-bridge=.*|cnt.network-bridge=${HOST_INTERFACE_NAME}:${NETWORK1_BRIDGE:-bridge0}|g" \
+ -e "s|^cnt.overlay=.*|cnt.overlay=${CNT_OVERLAY}|g" \
+ -e "s|^cnt.overlay-options=.*|cnt.overlay-options=${CNT_OVERLAY_OPTIONS}|g" \
+ -e "s|^bind=.*|bind=${BIND}|g" \
+ -e "s|^bind-ro=.*|bind-ro=${BIND_RO}|g" \
+ -e "s|^network-veth-extra=.*|network-veth-extra=${HOST_INTERFACE_NAME}:eno1|g" \
+ "${CONFIG}/${NAME}.conf"
+
+ if [ "${NETWORK_NUMBER}" -ge 2 ]
+ then
+ for NUMBER in $(seq 2 ${NETWORK_NUMBER})
+ do
+ eval IPV4_METHOD="$`echo NETWORK${NUMBER}_IPV4_METHOD`"
+ eval IPV6_METHOD="$`echo NETWORK${NUMBER}_IPV6_METHOD`"
+
+ if [ -z "${IPV4_METHOD}" ] && [ -z "${IPV6_METHOD}" ]
+ then
+ continue
+ fi
+
+ eval HOST_INTERFACE_NAME="$`echo NETWORK${NUMBER}_VETH`"
+
+ HOST_INTERFACE_NAME="$(echo ${HOST_INTERFACE_NAME:-veth-${HOSTNAME_SHORT}-${NUMBER}})"
+ CONTAINER_INTERFACE_NAME="eno${NUMBER}"
+
+ sed -i -e "/^register=.*/ a network-veth-extra=${HOST_INTERFACE_NAME}:${CONTAINER_INTERFACE_NAME}" "${CONFIG}/${NAME}.conf"
+
+ eval BRIDGE="$`echo NETWORK${NUMBER}_BRIDGE`"
+ sed -i -e "/^register=.*/ a cnt.network-bridge=${HOST_INTERFACE_NAME}:${BRIDGE:-bridge${NUMBER}}" "${CONFIG}/${NAME}.conf"
+ done
+ fi
+
+ # Setting root password
+ echo root:${ROOT_PASSWORD} | chroot "${DIRECTORY}" chpasswd
+
+ # Host command
+ if [ -n "${HOST_COMMAND}" ]
+ then
+ echo "${HOST_COMMAND}" > "${DIRECTORY}/.host-command"
+
+ cd "${DIRECTORY}"
+ sh "${DIRECTORY}/.host-command"
+ cd "${OLDPWD}"
+
+ rm -f "${DIRECTORY}/.host-command"
+ fi
+
+ for NUMBER in $(seq 1 ${HOST_COMMAND_NUMBER})
+ do
+ eval COMMAND="$`echo HOST_COMMAND${NUMBER}`"
+
+ echo "${COMMAND}" > "${DIRECTORY}/.host-command"
+
+ cd "${DIRECTORY}"
+ sh "${DIRECTORY}/.host-command"
+ cd "${OLDPWD}"
+
+ rm -f "${DIRECTORY}/.host-command"
+ done
+
+ # Show root password in case its automatically set
+ case "${ROOT_RANDOM_PASSWORD}" in
+ true)
+ echo "${NAME}: root password set to '${ROOT_PASSWORD}'."
+ ;;
+ esac
+}
+
+# Trap function
+trap 'Umount' EXIT HUP INT QUIT TERM
+
+umask 0022
+
+export NAME
+
+Debconf
+
+# Pre hooks
+for FILE in "${HOOKS}/pre-${SCRIPT}".* "${HOOKS}/${NAME}.pre-${SCRIPT}"
+do
+ if [ -x "${FILE}" ]
+ then
+ "${FILE}"
+ fi
+done
+
+# Run debconf parts
+for DEBCONF_SCRIPT in "/usr/share/${SOFTWARE}/build-scripts/debconf.d"/*
+do
+ if [ -x "${DEBCONF_SCRIPT}" ]
+ then
+ "${DEBCONF_SCRIPT}"
+ fi
+done
+
+# Read-in configuration from debconf
+. "${DEBCONF_TMPDIR}/debconf.default"
+
+SYSTEM="${MACHINES}/${NAME}"
+
+if [ -z "${IMAGE}" ] && [ -z "${IMAGE1}" ]
+then
+ INSTALLER="bootstrap"
+else
+ INSTALLER="image"
+fi
+
+case "${INSTALLER}" in
+ bootstrap)
+ ## Dependencies
+ if [ -x /usr/bin/mmdebstrap ]
+ then
+ BOOTSTRAP="mmdebstrap"
+ elif [ -x /usr/sbin/debootstrap ]
+ then
+ BOOTSTRAP="debootstrap"
+ else
+ echo "'${NAME}': /usr/bin/mmdebstrap or /usr/sbin/debootstrap - no such file." >&2
+ exit 1
+ fi
+
+ ## Generic parts
+ if [ ! -e "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}" ]
+ then
+ Bootstrap "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}.tmp"
+ Configure_apt "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}.tmp"
+ Deconfigure_system "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}.tmp"
+
+ mv "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}.tmp" "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}"
+ fi
+
+ Upgrade_system "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}" || echo "W: If upgrading the system failed, try removing the cache for your distribution in /var/cache/${PROGRAM}"
+ Cleanup_system "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}"
+
+ ## Specific parts
+ mkdir -p "${MACHINES}"
+ cp -a "${CACHE}/${DISTRIBUTION}_${ARCHITECTURE}" "${MACHINES}/${NAME}"
+ ;;
+
+ image)
+ ## Dependencies
+ if [ -x /usr/bin/curl ]
+ then
+ GET="curl"
+ elif [ -x /usr/bin/wget ]
+ then
+ GET="wget"
+ else
+ echo "'${NAME}': /usr/bin/curl or /usr/bin/wget - no such file." >&2
+ exit 1
+ fi
+
+ COMPRESSIONS=""
+
+ if [ -x /usr/bin/lzip ]
+ then
+ COMPRESSIONS="${COMPRESSIONS} lz"
+ fi
+
+ if [ -x /usr/bin/xz ]
+ then
+ COMPRESSIONS="${COMPRESSIONS} xz"
+ fi
+
+ if [ -x /bin/gzip ]
+ then
+ COMPRESSIONS="${COMPRESSIONS} gz"
+ fi
+
+ if [ -z "${COMPRESSIONS}" ]
+ then
+ echo "'${NAME}': no supported compressor available (lz, xz, gz)."
+ exit 1
+ fi
+
+ ## Parts
+ mkdir -p "${MACHINES}"
+ Image "${MACHINES}/${NAME}"
+
+ Configure_apt "${MACHINES}/${NAME}"
+ Deconfigure_system "${MACHINES}/${NAME}"
+ ;;
+esac
+
+Mount
+
+Configure_system "${MACHINES}/${NAME}"
+Configure_network "${MACHINES}/${NAME}"
+Configure_systemd_networkd "${MACHINES}/${NAME}"
+Cleanup_system "${MACHINES}/${NAME}"
+
+Commands "${MACHINES}/${NAME}"
+
+# remove debconf temporary files
+rm --preserve-root --one-file-system -rf "${DEBCONF_TMPDIR}"
+rmdir --ignore-fail-on-non-empty "/tmp/${SOFTWARE}" 2>&1 || true
+
+# Post hooks
+for FILE in "${HOOKS}/post-${SCRIPT}".* "${HOOKS}/${NAME}.post-${SCRIPT}"
+do
+ if [ -x "${FILE}" ]
+ then
+ "${FILE}"
+ fi
+done
diff --git a/share/build-scripts/debconf.d/0001-preseed-file b/share/build-scripts/debconf.d/0001-preseed-file
new file mode 100755
index 0000000..aa2c3c7
--- /dev/null
+++ b/share/build-scripts/debconf.d/0001-preseed-file
@@ -0,0 +1,131 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2022 Daniel Baumann <daniel.baumann@open-infrastructure.net>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+PROJECT="open-infrastructure"
+SOFTWARE="compute-tools"
+PROGRAM="container"
+
+CONFIG="/etc/${SOFTWARE}/config"
+DEBCONF="/etc/${SOFTWARE}/debconf"
+
+DEBCONF_NOWARNINGS="true"
+export DEBCONF_NOWARNINGS
+
+. /usr/share/debconf/confmodule
+
+# debconf template hierarchy (first match wins):
+#
+# 1. user specified a preseed file through commandline options
+# 2. /etc/compute-tools/debconf/${NAME}.cfg exists
+# 3. /etc/compute-tools/debconf/links/${NAME}.cfg exists
+# 4. /etc/compute-tools/debconf/*/${NAME}.cfg exists (only one file!)
+# 5. /etc/compute-tools/debconf/default.cfg exists
+# 6. user chooses from list of available (if any) *.cfg files
+# (recursively) found in /etc/compute-tools/debconf,
+# /etc/compute-tools/debconf/links is excluded.
+
+if [ -n "${PRESEED_FILE}" ]
+then
+ # user specified one or more preseed files through commandline option
+ db_set container/preseed-file "${PRESEED_FILE}"
+ db_fset container/preseed-file seen true
+elif [ -e "${DEBCONF}/${NAME}.cfg" ]
+then
+ # user did not specify a pressed file, but there is a matching one
+ # available on the system matching the container name
+ db_set container/preseed-file "${DEBCONF}/${NAME}.cfg"
+ db_fset container/preseed-file seen true
+elif [ -e "${DEBCONF}/links/${NAME}.cfg" ]
+then
+ # user did not specify a pressed file, but there is a matching one
+ # in /etc/${SOFTWARE}/debconf/links directory
+ db_set container/preseed-file "${DEBCONF}/links/${NAME}.cfg"
+ db_fset container/preseed-file seen true
+elif [ "$(ls ${DEBCONF}/*/${NAME}.cfg 2>/dev/null | wc -l)" -eq 1 ]
+then
+ # user did not specify a pressed file, but there is 1 (and only 1)
+ # matching in a sub-directory of /etc/${SOFTWARE}/debconf
+
+ FILE="$(ls ${DEBCONF}/*/${NAME}.cfg)"
+
+ db_set container/preseed-file "${FILE}"
+ db_fset container/preseed-file seen true
+elif [ -e "${DEBCONF}/default.cfg" ]
+then
+ # user did not specify a pressed file, but there is a default one
+ db_set container/preseed-file "${DEBCONF}/default.cfg"
+ db_fset container/preseed-file seen true
+elif ls "${DEBCONF}"/*.cfg > /dev/null 2>&1 || ls "${DEBCONF}"/*/*.cfg > /dev/null 2>&1
+then
+ # user has not specified preseed files through commandline option,
+ # showing debconf selection dialog for global preseed file.
+
+ FILES="$(cd ${DEBCONF} && find . -type f -name '*.cfg' -printf '%P\n' | grep -v '^links\/' | LC_ALL=C sort -V)"
+ PRESEED_FILES="$(for FILE in ${FILES}; do echo -n "$(echo ${FILE} | sed -e 's|.cfg$||'), "; done | sed -e 's|, $||')"
+
+ if [ -n "${PRESEED_FILES}" ]
+ then
+ db_subst container/preseed-files CHOICES "custom, exit, none, , ${PRESEED_FILES}"
+
+ db_settitle container/title
+ db_input high container/preseed-files || true
+ db_go
+
+ db_get container/preseed-files
+ PRESEED_FILE="${RET}" # select
+
+ case "${PRESEED_FILE}" in
+ custom|none)
+ ;;
+
+ exit)
+ rm -f "${CONFIG}/${NAME}.conf"
+ exit 1
+ ;;
+
+ *)
+ # user specified preseed file through debconf select
+ db_set container/preseed-file "${DEBCONF}/${PRESEED_FILE}.cfg"
+ db_fset container/preseed-file seen true
+ ;;
+ esac
+ fi
+fi
+
+case "${PRESEED_FILE}" in
+ none)
+ ;;
+
+ *)
+ # ask user for a preseed file
+ db_settitle container/title
+ db_input high container/preseed-file || true
+ db_go
+
+ db_get container/preseed-file
+ PRESEED_FILE="${RET}" # string (w/ empty)
+
+ echo "PRESEED_FILE=\"${PRESEED_FILE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PRESEED_FILE
+ ;;
+esac
+
+db_stop
diff --git a/share/build-scripts/debconf.d/0001-preseed-file.templates b/share/build-scripts/debconf.d/0001-preseed-file.templates
new file mode 100644
index 0000000..9be825d
--- /dev/null
+++ b/share/build-scripts/debconf.d/0001-preseed-file.templates
@@ -0,0 +1,18 @@
+Template: container/title
+Type: title
+Description: compute-tools
+
+Template: container/preseed-files
+Type: select
+Default: none
+Choices: ${CHOICES}
+Description: Choose a preseed config, enter a custom one, or use no preseed file at all.
+
+Template: container/preseed-file
+Type: string
+Default:
+Description: Enter (optional) preseed file to use:
+ A preseed file can be used to automatically answer questions to this
+ container build script.
+ .
+ If you do not want to use a preseed file, leave this question empty.
diff --git a/share/build-scripts/debconf.d/0002-preseed-debconf b/share/build-scripts/debconf.d/0002-preseed-debconf
new file mode 100755
index 0000000..fcb9006
--- /dev/null
+++ b/share/build-scripts/debconf.d/0002-preseed-debconf
@@ -0,0 +1,111 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2022 Daniel Baumann <daniel.baumann@open-infrastructure.net>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+if [ -e "${DEBCONF_TMPDIR}/debconf.default" ]
+then
+ . "${DEBCONF_TMPDIR}/debconf.default"
+fi
+
+if [ -z "${PRESEED_FILE}" ]
+then
+ # user has not specified or selected any preseed files
+ exit 0
+fi
+
+# user has one or more preseed file specified through commandline option
+# or debconf selection dialog.
+PRESEED_FILES="$(echo ${PRESEED_FILE} | sed -e 's|,| |g')"
+
+DEBCONF_PRESEED_FILES=""
+
+for PRESEED_FILE in ${PRESEED_FILES}
+do
+ if [ ! -e "${PRESEED_FILE}" ]
+ then
+ # preseed file does not exist
+ echo "W: ${PRESEED_FILE}: No such file."
+
+ continue
+ fi
+
+ # add preseed file to debconf
+ DEBCONF_PRESEED_FILES="${DEBCONF_PRESEED_FILES} ${PRESEED_FILE}"
+
+ if ! grep -qs '^ *compute-tools *container/include-preseed-files' "${PRESEED_FILE}"
+ then
+ # preseed file has no includes
+ continue
+ fi
+
+ # preseed file has includes
+ INCLUDE_PRESEED_FILES="$(grep '^ *compute-tools *container/include-preseed-files' ${PRESEED_FILE} | awk '{ $1=$2=$3=""; print $0 }' | sed -e 's|,| |g')"
+
+ # only one include layer is supported, no nested/recursive includes
+ for FILE in ${INCLUDE_PRESEED_FILES}
+ do
+ if [ -e "${FILE}" ]
+ then
+ DEBCONF_PRESEED_FILES="${FILE} ${DEBCONF_PRESEED_FILES}"
+ else
+ # included preseed file does not exist
+ echo "W: ${INCLUDE_PRESEED_FILE}: No such file - included from ${PRESEED_FILE}"
+ fi
+ done
+done
+
+for DEBCONF_PRESEED_FILE in ${DEBCONF_PRESEED_FILES}
+do
+ if [ -e /usr/bin/kdig ]
+ then
+ DIG="/usr/bin/kdig"
+ elif [ -e /usr/bin/dig ]
+ then
+ DIG="/usr/bin/dig"
+ fi
+
+ if [ -n "${DIG}" ]
+ then
+ IPV4_ADDRESS1="$(${DIG} A +short ${NAME} | tail -n1)"
+ IPV4_ADDRESS1_PART1="$(echo ${IPV4_ADDRESS1} | cut -d. -f1)"
+ IPV4_ADDRESS1_PART2="$(echo ${IPV4_ADDRESS1} | cut -d. -f2)"
+ IPV4_ADDRESS1_PART3="$(echo ${IPV4_ADDRESS1} | cut -d. -f3)"
+ IPV4_ADDRESS1_PART4="$(echo ${IPV4_ADDRESS1} | cut -d. -f4)"
+
+ IPV6_ADDRESS1="$(${DIG} AAAA +short ${NAME} | tail -n1)"
+ fi
+
+ sed -e "s|@NAME@|${NAME}|g" \
+ -e "s|@IPV4_ADDRESS1@|${IPV4_ADDRESS1}|g" \
+ -e "s|@IPV4_ADDRESS1_PART1@|${IPV4_ADDRESS1_PART1}|g" \
+ -e "s|@IPV4_ADDRESS1_PART2@|${IPV4_ADDRESS1_PART2}|g" \
+ -e "s|@IPV4_ADDRESS1_PART3@|${IPV4_ADDRESS1_PART3}|g" \
+ -e "s|@IPV4_ADDRESS1_PART4@|${IPV4_ADDRESS1_PART4}|g" \
+ -e "s|@IPV6_ADDRESS1@|${IPV6_ADDRESS1}|g" \
+ "${DEBCONF_PRESEED_FILE}" > "${DIRECTORY}/preseed.cfg"
+
+ # Apply user specified preseed files
+ debconf-set-selections "${DIRECTORY}/preseed.cfg"
+
+ rm -f "${DIRECTORY}/preseed.cfg"
+done
+
+# Write expanded list of debconf preseed files
+echo "PRESEED_FILE=\"${DEBCONF_PRESEED_FILES}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
diff --git a/share/build-scripts/debconf.d/0003-debconf b/share/build-scripts/debconf.d/0003-debconf
new file mode 100755
index 0000000..e12e25e
--- /dev/null
+++ b/share/build-scripts/debconf.d/0003-debconf
@@ -0,0 +1,1371 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2022 Daniel Baumann <daniel.baumann@open-infrastructure.net>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+DEBCONF_NOWARNINGS="true"
+export DEBCONF_NOWARNINGS
+
+. /usr/share/debconf/confmodule
+
+Mode ()
+{
+ db_get container/mode
+ MODE="${RET}" # select
+
+ if [ -z "${MODE}" ]
+ then
+ MODE="$(basename ${SCRIPT})"
+
+ case "${MODE}" in
+ debconf)
+ MODE="debian"
+ ;;
+ esac
+ fi
+
+ echo "MODE=\"${MODE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export MODE
+}
+
+Images ()
+{
+ if db_get container/image && [ "${RET}" ]
+ then
+ db_get container/image
+ IMAGE="${RET}" # string (w/o empty)
+
+ echo "IMAGE=\"${IMAGE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ fi
+
+ NUMBER="1"
+
+ while db_get container/image${NUMBER} && [ "${RET}" ]
+ do
+ if db_get container/image${NUMBER}
+ then
+ eval IMAGE${NUMBER}="\"${RET}\"" # string (w/o empty)
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+
+ IMAGE_NUMBER="$((${NUMBER} - 1))"
+
+ echo "IMAGE_NUMBER=\"${IMAGE_NUMBER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ for NUMBER in $(seq 1 ${IMAGE_NUMBER})
+ do
+ eval IMAGE="$`echo IMAGE${NUMBER}`"
+ echo "IMAGE${NUMBER}=\"${IMAGE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ done
+}
+
+Distribution ()
+{
+ db_get container/distribution
+ DISTRIBUTION="${RET}" # select
+
+ if [ -z "${DISTRIBUTION}" ]
+ then
+ case "${MODE}" in
+ debian)
+ db_subst container/distribution CHOICES "Debian GNU/Linux 10 \"buster\", Debian GNU/Linux 11 \"bullseye\", Debian GNU/Linux 12 \"bookworm\", Debian GNU/Linux testing, Debian GNU/Linux unstable/sid"
+ db_subst container/distribution CHOICES_C "buster, bullseye, bookworm, testing, sid"
+
+ db_set container/distribution bookworm
+ db_fset container/distribution seen false
+ ;;
+
+ progress-linux)
+ db_subst container/distribution CHOICES "Progress Linux 5 (engywuck), Progress Linux 5.99 (engywuck-backports), Progress Linux 6 (fuchur), Progress Linux 6.99 (fuchur-backports), Progress Linux 7 (graograman), Progress Linux 7.99 (graograman-backports)"
+ db_subst container/distribution CHOICES_C "engywuck, engywuck-backports, fuchur, fuchur-backports, graograman, graograman-backports"
+
+ db_set container/distribution graograman-backports
+ db_fset container/distribution seen false
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/distribution || true
+ db_go
+
+ db_get container/distribution
+ DISTRIBUTION="${RET}" # select
+ fi
+
+ echo "DISTRIBUTION=\"${DISTRIBUTION}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export DISTRIBUTION
+}
+
+Parent_distribution ()
+{
+ db_get container/parent-distribution
+ PARENT_DISTRIBUTION="${RET}"
+
+ if [ -z "${PARENT_DISTRIBUTION}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ case "${DISTRIBUTION}" in
+ engywuck*)
+ PARENT_DISTRIBUTION="buster"
+ ;;
+
+ fuchur*)
+ PARENT_DISTRIBUTION="bullseye"
+ ;;
+
+ graograman*)
+ PARENT_DISTRIBUTION="bookworm"
+ ;;
+ esac
+ ;;
+
+ *)
+ PARENT_DISTRIBUTION="${DISTRIBUTION}"
+ ;;
+ esac
+ fi
+
+ echo "PARENT_DISTRIBUTION=\"${PARENT_DISTRIBUTION}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PARENT_DISTRIBUTION
+}
+
+Architecture ()
+{
+ case "$(dpkg --print-architecture)" in
+ amd64)
+ DEFAULT="amd64"
+ CHOICES="Automatic, 32-bit PC (i386), 64-bit PC (amd64)"
+ CHOICES_C="auto, i386, amd64"
+ ;;
+
+ arm64)
+ DEFAULT="arm64"
+ CHOICES="Automatic, RaspberryPi 3 and newer (arm64)"
+ CHOICES_C="auto, arm64"
+ ;;
+
+ i386)
+ case "$(uname -m)" in
+ x86_64)
+ DEFAULT="amd64"
+ CHOICES="Automatic, 32-bit PC (i386), 64-bit PC (amd64)"
+ CHOICES_C="auto, i386, amd64"
+ ;;
+
+ *)
+ DEFAULT="i386"
+ CHOICES=""
+ CHOICES_C=""
+ ;;
+ esac
+ ;;
+
+ *)
+ echo "E: Architecture current not yet supported."
+ exit 1
+ esac
+
+ db_get container/architecture
+ ARCHITECTURE="${RET}" # select
+
+ if [ -z "${ARCHITECTURE}" ] && [ -n "${CHOICES}" ]
+ then
+ db_subst container/architecture CHOICES ${CHOICES}
+ db_subst container/architecture CHOICES_C ${CHOICES_C}
+
+ db_set container/architecture ${DEFAULT}
+ db_fset container/distribution seen false
+
+ db_settitle container/title
+ db_input high container/architecture || true
+ db_go
+
+ db_get container/architecture
+ ARCHITECTURE="${RET}" # select
+ fi
+
+ case "${ARCHITECTURE}" in
+ auto)
+ ARCHITECTURE="${DEFAULT}"
+ ;;
+ esac
+
+ echo "ARCHITECTURE=\"${ARCHITECTURE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export ARCHITECTURE
+}
+
+Archives ()
+{
+ db_get container/archives
+ ARCHIVES="${RET}" # multiselect
+
+ if [ -z "${ARCHIVES}" ]
+ then
+ case "${MODE}" in
+ debian)
+ case "${PARENT_DISTRIBUTION}" in
+ sid)
+ db_subst container/archives CHOICES "sid, experimental"
+
+ db_set container/archives "sid"
+ db_fset container/archives seen false
+ ;;
+
+ *)
+ db_subst container/archives CHOICES "${DISTRIBUTION}, ${DISTRIBUTION}-security, ${DISTRIBUTION}-updates, ${DISTRIBUTION}-backports, ${DISTRIBUTION}-proposed-updates"
+
+ case "${PARENT_DISTRIBUTION}" in
+ sid)
+ db_set container/archives "sid"
+ ;;
+
+ *)
+ db_set container/archives "${DISTRIBUTION}, ${DISTRIBUTION}-security, ${DISTRIBUTION}-updates"
+ ;;
+ esac
+
+ db_fset container/archives seen false
+ ;;
+ esac
+ ;;
+
+ progress-linux)
+ DIST="$(echo ${DISTRIBUTION} | sed -e 's|-backports||')"
+
+ db_subst container/archives CHOICES "${DIST}, ${DIST}-security, ${DIST}-updates, ${DIST}-extras, ${DIST}-backports, ${DIST}-backports-extras"
+
+ db_set container/archives "${DIST}, ${DIST}-security, ${DIST}-updates, ${DIST}-extras, ${DIST}-backports, ${DIST}-backports-extras"
+ db_fset container/archives seen false
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/archives || true
+ db_go
+
+ db_get container/archives
+ ARCHIVES="${RET}" # multiselect
+ fi
+
+ ARCHIVES="$(echo ${ARCHIVES} | sed -e 's|, | |g')"
+
+ echo "ARCHIVES=\"${ARCHIVES}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export ARCHIVES
+}
+
+Parent_archives ()
+{
+ db_get container/parent-archives
+ PARENT_ARCHIVES="${RET}" # multiselect (w/o empty)
+
+ if [ -z "${PARENT_ARCHIVES}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ db_subst container/parent-archives CHOICES "${PARENT_DISTRIBUTION}, ${PARENT_DISTRIBUTION}-security, ${PARENT_DISTRIBUTION}-updates, ${PARENT_DISTRIBUTION}-backports, ${PARENT_DISTRIBUTION}-proposed-updates"
+
+ case "${PARENT_DISTRIBUTION}" in
+ *)
+ db_set container/parent-archives "${PARENT_DISTRIBUTION}, ${PARENT_DISTRIBUTION}-security, ${PARENT_DISTRIBUTION}-updates"
+ ;;
+ esac
+
+ db_fset container/parent-archives seen false
+
+ db_settitle container/title
+ db_input high container/parent-archives || true
+ db_go
+ ;;
+
+ *)
+ db_subst container/parent-archives CHOICES "${DISTRIBUTION}, ${DISTRIBUTION}-security, ${DISTRIBUTION}-updates, ${DISTRIBUTION}-backports, ${DISTRIBUTION}-proposed-updates"
+
+ db_set container/parent-archives "${ARCHIVES}"
+ db_fset container/parent-archives seen true
+ ;;
+ esac
+
+ db_get container/parent-archives
+ PARENT_ARCHIVES="${RET}" # multiselect (w/o empty)
+
+ if [ -z "${PARENT_ARCHIVES}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ case "${PARENT_DISTRIBUTION}" in
+ *)
+ PARENT_ARCHIVES="${PARENT_DISTRIBUTION}, ${PARENT_DISTRIBUTION}-security, ${PARENT_DISTRIBUTION}-updates"
+ ;;
+ esac
+ ;;
+
+ *)
+ PARENT_ARCHIVES="${ARCHIVES}"
+ ;;
+ esac
+ fi
+ fi
+
+ PARENT_ARCHIVES="$(echo ${PARENT_ARCHIVES} | sed -e 's|, | |g')"
+
+ echo "PARENT_ARCHIVES=\"${PARENT_ARCHIVES}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PARENT_ARCHIVES
+}
+
+Mirror ()
+{
+ db_get container/mirror
+ MIRROR="${RET}"
+
+ if [ -z "${MIRROR}" ]
+ then
+ case "${MODE}" in
+ debian)
+ db_set container/mirror https://deb.debian.org/debian
+ db_fset container/mirror seen false
+ ;;
+
+ progress-linux)
+ db_set container/mirror https://deb.progress-linux.org/packages
+ db_fset container/mirror seen false
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/mirror || true
+ db_go
+
+ db_get container/mirror
+ MIRROR="${RET}" # string (w/o empty)
+
+ if [ -z "${MIRROR}" ]
+ then
+ case "${MODE}" in
+ debian)
+ MIRROR="https://deb.debian.org/debian"
+ ;;
+
+ progress-linux)
+ MIRROR="https://deb.progress-linux.org/packages"
+ ;;
+ esac
+ fi
+ fi
+
+ echo "MIRROR=\"${MIRROR}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export MIRROR
+}
+
+Mirror_security ()
+{
+ if ! echo "${ARCHIVES}" | grep -qs "-security"
+ then
+ return 0
+ fi
+
+ db_get container/mirror-security
+ MIRROR_SECURITY="${RET}" # string (w/o empty)
+
+ if [ -z "${MIRROR_SECURITY}" ]
+ then
+ case "${MODE}" in
+ debian)
+ db_set container/mirror-security https://security.debian.org
+ db_fset container/mirror-security seen false
+ ;;
+
+ *)
+ db_set container/mirror-security ${MIRROR}
+ db_fset container/mirror-security seen true
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/mirror-security || true
+ db_go
+
+ db_get container/mirror-security
+ MIRROR_SECURITY="${RET}" # string (w/o empty)
+
+ if [ -z "${MIRROR_SECURITY}" ]
+ then
+ case "${MODE}" in
+ debian)
+ MIRROR_SECURITY="https://security.debian.org"
+ ;;
+
+ *)
+ MIRROR_SECURITY="${MIRROR}"
+ ;;
+ esac
+ fi
+ fi
+
+ echo "MIRROR_SECURITY=\"${MIRROR_SECURITY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export MIRROR_SECURITY
+}
+
+Parent_mirror ()
+{
+ db_get container/parent-mirror
+ PARENT_MIRROR="${RET}" # string (w/o empty)
+
+ if [ -z "${PARENT_MIRROR}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ db_set container/parent-mirror https://deb.debian.org/debian
+ db_fset container/parent-mirror seen false
+
+ db_settitle container/title
+ db_input high container/parent-mirror || true
+ db_go
+ ;;
+
+ *)
+ db_set container/parent-mirror ${MIRROR}
+ db_fset container/parent-mirror seen true
+ ;;
+ esac
+
+ db_get container/parent-mirror
+ PARENT_MIRROR="${RET}" # string (w/o empty)
+
+ if [ -z "${PARENT_MIRROR}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ PARENT_MIRROR="https://deb.debian.org/debian"
+ ;;
+
+ *)
+ PARENT_MIRROR="${MIRROR}"
+ ;;
+ esac
+ fi
+ fi
+
+ echo "PARENT_MIRROR=\"${PARENT_MIRROR}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PARENT_MIRROR
+}
+
+Parent_mirror_security ()
+{
+ if ! echo "${PARENT_ARCHIVES}" | grep -qs "-security"
+ then
+ return 0
+ fi
+
+ db_get container/parent-mirror-security
+ PARENT_MIRROR_SECURITY="${RET}" # string (w/o empty)
+
+ if [ -z "${PARENT_MIRROR_SECURITY}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ db_set container/parent-mirror-security https://security.debian.org
+ db_fset container/parent-mirror-security seen false
+
+ db_settitle container/title
+ db_input high container/parent-mirror-security || true
+ db_go
+ ;;
+
+ *)
+ db_set container/parent-mirror-security ${MIRROR_SECURITY}
+ db_fset container/parent-mirror-security seen true
+ ;;
+ esac
+
+ db_get container/parent-mirror-security
+ PARENT_MIRROR_SECURITY="${RET}" # string (w/o empty)
+
+ if [ -z "${PARENT_MIRROR_SECURITY}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ PARENT_MIRROR_SECURITY="https://security.debian.org"
+ ;;
+
+ *)
+ PARENT_MIRROR_SECURITY="${MIRROR_SECURITY}"
+ ;;
+ esac
+ fi
+ fi
+
+ echo "PARENT_MIRROR_SECURITY=\"${PARENT_MIRROR_SECURITY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PARENT_MIRROR_SECURITY
+}
+
+Archive_areas ()
+{
+ db_get container/archive-areas
+ ARCHIVE_AREAS="${RET}"
+
+ case "${PARENT_DISTRIBUTION}" in
+ bookworm|testing|sid)
+ ARCHIVE_AREAS_ALL="main, contrib, non-free, non-free-firmware"
+ ;;
+
+ *)
+ ARCHIVE_AREAS_ALL="main, contrib, non-free"
+ ;;
+ esac
+
+ if [ -z "${ARCHIVE_AREAS}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ db_subst container/archive-areas CHOICES "${ARCHIVE_AREAS_ALL}"
+
+ db_set container/archive-areas "${ARCHIVE_AREAS_ALL}"
+ db_fset container/archive-areas seen false
+ ;;
+
+ *)
+ db_subst container/archive-areas CHOICES "${ARCHIVE_AREAS_ALL}"
+
+ db_set container/archive-areas "main"
+ db_fset container/archive-areas seen false
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/archive-areas || true
+ db_go
+
+ db_get container/archive-areas
+ ARCHIVE_AREAS="${RET}" # multiselect (w/o empty)
+
+ if [ -z "${ARCHIVE_AREAS}" ]
+ then
+ case "${MODE}" in
+ debian)
+ ARCHIVE_AREAS="main"
+ ;;
+
+ progress-linux)
+ ARCHIVE_AREAS="${ARCHIVE_AREAS_ALL}"
+ ;;
+ esac
+ fi
+ fi
+
+ ARCHIVE_AREAS="$(echo ${ARCHIVE_AREAS} | sed -e 's| ||g')"
+
+ echo "ARCHIVE_AREAS=\"${ARCHIVE_AREAS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export ARCHIVE_AREAS
+}
+
+Parent_archive_areas ()
+{
+ db_get container/parent-archive-areas
+ PARENT_ARCHIVE_AREAS="${RET}" # multiselect (w/o empty)
+
+ case "${PARENT_DISTRIBUTION}" in
+ bookworm|testing|sid)
+ PARENT_ARCHIVE_AREAS_ALL="main, contrib, non-free, non-free-firmware"
+ ;;
+
+ *)
+ PARENT_ARCHIVE_AREAS_ALL="main, contrib, non-free"
+ ;;
+ esac
+
+ if [ -z "${PARENT_ARCHIVE_AREAS}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ db_subst container/parent-archive-areas CHOICES "${PARENT_ARCHIVE_AREAS_ALL}"
+
+ db_set container/parent-archive-areas "${PARENT_ARCHIVE_AREAS_ALL}"
+ db_fset container/parent-archive-areas seen false
+
+ db_settitle container/title
+ db_input high container/parent-archive-areas || true
+ db_go
+ ;;
+
+ *)
+ db_subst container/parent-archive-areas CHOICES "${ARCHIVE_AREAS}"
+
+ db_set container/parent-archive-areas "${ARCHIVE_AREAS}"
+ db_fset container/parent-archive-areas seen true
+ ;;
+ esac
+
+ db_get container/parent-archive-areas
+ PARENT_ARCHIVE_AREAS="${RET}" # multiselect (w/o empty)
+
+ if [ -z "${PARENT_ARCHIVE_AREAS}" ]
+ then
+ case "${MODE}" in
+ progress-linux)
+ PARENT_ARCHIVE_AREAS="${PARENT_ARCHIVE_AREAS_ALL}"
+ ;;
+
+ *)
+ PARENT_ARCHIVE_AREAS="${ARCHIVE_AREAS}"
+ ;;
+ esac
+ fi
+ fi
+
+ PARENT_ARCHIVE_AREAS="$(echo ${PARENT_ARCHIVE_AREAS} | sed -e 's| ||g')"
+
+ echo "PARENT_ARCHIVE_AREAS=\"${PARENT_ARCHIVE_AREAS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PARENT_ARCHIVE_AREAS
+}
+
+Packages ()
+{
+ db_get container/packages
+ PACKAGES="${RET}" # string (w/ empty)
+
+ if [ -z "${PACKAGES}" ]
+ then
+ db_settitle container/title
+ db_input high container/packages || true
+ db_go
+
+ db_get container/packages
+ PACKAGES="${RET}" # string (w/ empty)
+ fi
+
+ echo "PACKAGES=\"${PACKAGES}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ export PACKAGES
+}
+
+Local_archives ()
+{
+ NUMBER="1"
+
+ while db_get container/archive${NUMBER}/repository && [ "${RET}" ]
+ do
+ mkdir -p "${DEBCONF_TMPDIR}/apt"
+
+ REPOSITORY="${RET#deb }"
+
+ LIST="archive${NUMBER}.list"
+ if db_get container/archive${NUMBER}/list
+ then
+ LIST="$(basename ${RET} .list).list"
+ fi
+
+ COMMENT=""
+ if db_get container/archive${NUMBER}/comment
+ then
+ COMMENT="${RET}"
+
+ echo "# ${COMMENT}" > "${DEBCONF_TMPDIR}/apt/${LIST}"
+ fi
+
+ echo "deb ${REPOSITORY}" >> "${DEBCONF_TMPDIR}/apt/${LIST}"
+
+ if db_get container/archive${NUMBER}/source && [ "$RET" = true ]
+ then
+ echo "deb-src ${REPOSITORY}" >> "${DEBCONF_TMPDIR}/apt/${LIST}"
+ fi
+
+ KEY=""
+ if db_get container/archive${NUMBER}/key
+ then
+ KEY="${RET}"
+
+ wget -q "${KEY}" -O "${DEBCONF_TMPDIR}/apt/$(basename ${LIST} .list).key"
+ fi
+
+ PREFERENCES_PACKAGE=""
+ PREFERENCES_PIN=""
+ PREFERENCES_PIN_PRIORITY=""
+ if db_get container/archive${NUMBER}/preferences-package
+ then
+ PREFERENCES_PACKAGE="${RET}"
+
+ if db_get container/archive${NUMBER}/preferences-pin
+ then
+ PREFERENCES_PIN="${RET}"
+ fi
+
+ if db_get container/archive${NUMBER}/preferences-pin-priority
+ then
+ PREFERENCES_PIN_PRIORITY="${RET}"
+ fi
+
+ if [ -n "${PREFERENCES_PACKAGE}" ] || [ -n "${PREFERENCES_PIN}" ] || [ -n "${PREFERENCES_PIN_PRIORITY}" ]
+ then
+
+cat > "${DEBCONF_TMPDIR}/apt/$(basename ${LIST} .list).pref" << EOF
+Package: ${PREFERENCES_PACKAGE}
+Pin: ${PREFERENCES_PIN}
+Pin-Priority: ${PREFERENCES_PIN_PRIORITY}
+EOF
+
+ fi
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+}
+
+Network_defaults ()
+{
+ HOSTNAME_SHORT="$(echo veth-$(echo ${NAME} | cut -c-8)-0)"
+ VETH_NAME="${HOSTNAME_SHORT}"
+
+ NETWORK1_VETH="${NETWORK1_VETH:-$VETH_NAME}"
+ NETWORK1_BRIDGE="${NETWORK1_BRIDGE:-bridge0}"
+
+ NETWORK1_IPV4_METHOD="${NETWORK1_IPV4_METHOD:-dhcp}"
+ NETWORK1_IPV4_ADDRESS="${NETWORK1_IPV4_ADDRESS:-192.168.1.2}"
+ NETWORK1_IPV4_NETMASK="${NETWORK1_IPV4_NETMASK:-24}"
+
+ NETWORK1_IPV6_METHOD="${NETWORK1_IPV6_METHOD:-none}"
+ NETWORK1_IPV6_ADDRESS="${NETWORK1_IPV6_ADDRESS:-fc00::2}"
+ NETWORK1_IPV6_NETMASK="${NETWORK1_IPV6_NETMASK:-7}"
+
+ if [ "${NETWORK1_IPV4_METHOD}" = "static" ] || [ "${NETWORK1_IPV6_METHOD}" = "static" ]
+ then
+ if [ -e /etc/resolv.conf ]
+ then
+ NAMESERVER_SERVER="${NAMESERVER_SERVER:-$(awk '/^nameserver / {$1=""; print $0}' /etc/resolv.conf)}"
+ # Workaround to get rid of newlines since debconf can not handle multiline return value in assignments
+ NAMESERVER_SERVER="$(echo ${NAMESERVER_SERVER})"
+
+ NAMESERVER_DOMAIN="${NAMESERVER_DOMAIN:-$(awk '/^domain / {$1=""; print $0}' /etc/resolv.conf)}"
+ NAMESERVER_SEARCH="${NAMESERVER_SEARCH:-$(awk '/^search / {$1=""; print $0}' /etc/resolv.conf)}"
+ NAMESERVER_OPTIONS="${NAMESERVER_OPTIONS:-$(awk '/^options / {$1=""; print $0}' /etc/resolv.conf)}"
+ fi
+ fi
+}
+
+Network ()
+{
+ db_get container/network1/bridge
+ NETWORK1_BRIDGE="${RET}" # string (w/o empty)
+
+ db_get container/network1/veth
+ NETWORK1_VETH="${RET}" # string (w/o empty)
+
+ db_get container/network1/ipv4-method
+ NETWORK1_IPV4_METHOD="${RET}" # select
+
+ db_get container/network1/ipv4-comment
+ NETWORK1_IPV4_COMMENT="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv4-address
+ NETWORK1_IPV4_ADDRESS="${RET}" # string (w/o empty)
+
+ db_get container/network1/ipv4-gateway
+ NETWORK1_IPV4_GATEWAY="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv4-netmask
+ NETWORK1_IPV4_NETMASK="${RET}" # string (w/o empty)
+
+ db_get container/network1/ipv4-post-up
+ NETWORK1_IPV4_POST_UP="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv4-post-down
+ NETWORK1_IPV4_POST_DOWN="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv6-method
+ NETWORK1_IPV6_METHOD="${RET}" # select
+
+ db_get container/network1/ipv6-comment
+ NETWORK1_IPV6_COMMENT="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv6-address
+ NETWORK1_IPV6_ADDRESS="${RET}" # string (w/o empty)
+
+ db_get container/network1/ipv6-gateway
+ NETWORK1_IPV6_GATEWAY="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv6-netmask
+ NETWORK1_IPV6_NETMASK="${RET}" # string (w/o empty)
+
+ db_get container/network1/ipv6-post-up
+ NETWORK1_IPV6_POST_UP="${RET}" # string (w/ empty)
+
+ db_get container/network1/ipv6-post-down
+ NETWORK1_IPV6_POST_DOWN="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/server
+ NAMESERVER_SERVER="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/domain
+ NAMESERVER_DOMAIN="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/search
+ NAMESERVER_SEARCH="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/options
+ NAMESERVER_OPTIONS="${RET}" # string (w/ empty)
+
+ Network_defaults
+
+ db_set container/network1/bridge "${NETWORK1_BRIDGE}"
+ db_fset container/network1/bridge seen false
+
+ db_set container/network1/veth "${NETWORK1_VETH}"
+ db_fset container/network1/veth seen false
+
+ db_set container/network1/ipv4-method "${NETWORK1_IPV4_METHOD}"
+ db_fset container/network1/ipv4-method seen false
+
+ db_set container/network1/ipv4-comment "${NETWORK1_IPV4_COMMENT}"
+ db_fset container/network1/ipv4-comment seen false
+
+ db_set container/network1/ipv4-address "${NETWORK1_IPV4_ADDRESS}"
+ db_fset container/network1/ipv4-address seen false
+
+ db_set container/network1/ipv4-gateway "${NETWORK1_IPV4_GATEWAY}"
+ db_fset container/network1/ipv4-gateway seen false
+
+ db_set container/network1/ipv4-netmask "${NETWORK1_IPV4_NETMASK}"
+ db_fset container/network1/ipv4-netmask seen false
+
+ db_set container/network1/ipv4-post-up "${NETWORK1_IPV4_POST_UP}"
+ db_fset container/network1/ipv4-post-up seen false
+
+ db_set container/network1/ipv4-post-down "${NETWORK1_IPV4_POST_DOWN}"
+ db_fset container/network1/ipv4-post-down seen false
+
+ db_set container/network1/ipv6-method "${NETWORK1_IPV6_METHOD}"
+ db_fset container/network1/ipv6-method seen false
+
+ db_set container/network1/ipv6-comment "${NETWORK1_IPV6_COMMENT}"
+ db_fset container/network1/ipv6-comment seen false
+
+ db_set container/network1/ipv6-address "${NETWORK1_IPV6_ADDRESS}"
+ db_fset container/network1/ipv6-address seen false
+
+ db_set container/network1/ipv6-gateway "${NETWORK1_IPV6_GATEWAY}"
+ db_fset container/network1/ipv6-gateway seen false
+
+ db_set container/network1/ipv6-netmask "${NETWORK1_IPV6_NETMASK}"
+ db_fset container/network1/ipv6-netmask seen false
+
+ db_set container/network1/ipv6-post-up "${NETWORK1_IPV6_POST_UP}"
+ db_fset container/network1/ipv6-post-up seen false
+
+ db_set container/network1/ipv6-post-down "${NETWORK1_IPV6_POST_DOWN}"
+ db_fset container/network1/ipv6-post-down seen false
+
+ db_set container/nameserver/server "${NAMESERVER_SERVER}"
+ db_fset container/nameserver/server seen false
+
+ db_set container/nameserver/domain "${NAMESERVER_DOMAIN}"
+ db_fset container/nameserver/domain seen false
+
+ db_set container/nameserver/search "${NAMESERVER_SEARCH}"
+ db_fset container/nameserver/search seen false
+
+ db_set container/nameserver/options "${NAMESERVER_OPTIONS}"
+ db_fset container/nameserver/options seen false
+
+ db_get container/network1/bridge
+ NETWORK1_BRIDGE="${RET}" # select
+
+ db_get container/network1/veth
+ NETWORK1_VETH="${RET}" # select
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-method || true
+ db_go
+
+ db_get container/network1/ipv4-method
+ NETWORK1_IPV4_METHOD="${RET}" # select
+
+ case "${NETWORK1_IPV4_METHOD}" in
+ none|dhcp)
+ ;;
+
+ static)
+ db_settitle container/title
+ db_input high container/network1/ipv4-comment || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-address || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-gateway || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-netmask || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-post-up || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-post-down || true
+ db_go
+ ;;
+
+ stub)
+ db_settitle container/title
+ db_input high container/network1/ipv4-comment || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-post-up || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv4-post-down || true
+ db_go
+ ;;
+ esac
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-method || true
+ db_go
+
+ db_get container/network1/ipv6-method
+ NETWORK1_IPV6_METHOD="${RET}" # select
+
+ case "${NETWORK1_IPV6_METHOD}" in
+ none|dhcp)
+ ;;
+
+ static)
+ db_settitle container/title
+ db_input high container/network1/ipv6-comment || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-address || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-gateway || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-netmask || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-post-up || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-post-down || true
+ db_go
+ ;;
+
+ stub)
+ db_settitle container/title
+ db_input high container/network1/ipv6-comment || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-post-up || true
+ db_go
+
+ db_settitle container/title
+ db_input high container/network1/ipv6-post-down || true
+ db_go
+ ;;
+ esac
+
+ if [ "${NETWORK1_IPV4_METHOD}" = "static" ] || [ "${NETWORK1_IPV6_METHOD}" = "static" ]
+ then
+ db_settitle container/title
+ db_input high container/nameserver/server || true
+ db_go
+ fi
+
+ NUMBER="1"
+
+ while ( db_get container/network${NUMBER}/ipv4-method && [ "${RET}" ] ) || ( db_get container/network${NUMBER}/ipv6-method && [ "${RET}" ] )
+ do
+ if db_get container/network${NUMBER}/bridge
+ then
+ eval NETWORK${NUMBER}_BRIDGE="\"${RET}\"" # string (w/o empty)
+ fi
+
+ if db_get container/network${NUMBER}/veth
+ then
+ eval NETWORK${NUMBER}_VETH="\"${RET}\"" # string (w/o empty)
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+
+ NETWORK_NUMBER="$((${NUMBER} - 1))"
+
+ for NUMBER in $(seq 1 ${NETWORK_NUMBER})
+ do
+ if db_get container/network${NUMBER}/ipv4-comment
+ then
+ eval NETWORK${NUMBER}_IPV4_COMMENT="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-method
+ then
+ eval NETWORK${NUMBER}_IPV4_METHOD="\"${RET}\"" # select
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-address
+ then
+ eval NETWORK${NUMBER}_IPV4_ADDRESS="\"${RET}\"" # string (w/o empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-gateway
+ then
+ eval NETWORK${NUMBER}_IPV4_GATEWAY="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-netmask
+ then
+ eval NETWORK${NUMBER}_IPV4_NETMASK="\"${RET}\"" # string (w/o empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-post-up
+ then
+ eval NETWORK${NUMBER}_IPV4_POST_UP="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv4-post-down
+ then
+ eval NETWORK${NUMBER}_IPV4_POST_DOWN="\"${RET}\"" # string (w/ empty)
+ fi
+ done
+
+ for NUMBER in $(seq 1 ${NETWORK_NUMBER})
+ do
+ if db_get container/network${NUMBER}/ipv6-comment
+ then
+ eval NETWORK${NUMBER}_IPV6_COMMENT="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-method
+ then
+ eval NETWORK${NUMBER}_IPV6_METHOD="\"${RET}\"" # select
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-address
+ then
+ eval NETWORK${NUMBER}_IPV6_ADDRESS="\"${RET}\"" # string (w/o empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-gateway
+ then
+ eval NETWORK${NUMBER}_IPV6_GATEWAY="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-netmask
+ then
+ eval NETWORK${NUMBER}_IPV6_NETMASK="\"${RET}\"" # string (w/o empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-post-up
+ then
+ eval NETWORK${NUMBER}_IPV6_POST_UP="\"${RET}\"" # string (w/ empty)
+ fi
+
+ if db_get container/network${NUMBER}/ipv6-post-down
+ then
+ eval NETWORK${NUMBER}_IPV6_POST_DOWN="\"${RET}\"" # string (w/ empty)
+ fi
+ done
+
+ db_get container/nameserver/server
+ NAMESERVER_SERVER="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/domain
+ NAMESERVER_DOMAIN="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/search
+ NAMESERVER_SEARCH="${RET}" # string (w/ empty)
+
+ db_get container/nameserver/options
+ NAMESERVER_OPTIONS="${RET}" # string (w/ empty)
+
+ Network_defaults
+
+ echo "NETWORK_NUMBER=\"${NETWORK_NUMBER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ for NUMBER in $(seq 1 ${NETWORK_NUMBER})
+ do
+ eval BRIDGE="$`echo NETWORK${NUMBER}_BRIDGE`"
+ echo "NETWORK${NUMBER}_BRIDGE=\"${BRIDGE}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval VETH="$`echo NETWORK${NUMBER}_VETH`"
+ echo "NETWORK${NUMBER}_VETH=\"${VETH}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval COMMENT="$`echo NETWORK${NUMBER}_IPV4_COMMENT`"
+ echo "NETWORK${NUMBER}_IPV4_COMMENT=\"${COMMENT}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval METHOD="$`echo NETWORK${NUMBER}_IPV4_METHOD`"
+ echo "NETWORK${NUMBER}_IPV4_METHOD=\"${METHOD}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval ADDRESS="$`echo NETWORK${NUMBER}_IPV4_ADDRESS`"
+ echo "NETWORK${NUMBER}_IPV4_ADDRESS=\"${ADDRESS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval GATEWAY="$`echo NETWORK${NUMBER}_IPV4_GATEWAY`"
+ echo "NETWORK${NUMBER}_IPV4_GATEWAY=\"${GATEWAY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval NETMASK="$`echo NETWORK${NUMBER}_IPV4_NETMASK`"
+ echo "NETWORK${NUMBER}_IPV4_NETMASK=\"${NETMASK}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval POST_UP="$`echo NETWORK${NUMBER}_IPV4_POST_UP`"
+ echo "NETWORK${NUMBER}_IPV4_POST_UP=\"${POST_UP}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval POST_DOWN="$`echo NETWORK${NUMBER}_IPV4_POST_DOWN`"
+ echo "NETWORK${NUMBER}_IPV4_POST_DOWN=\"${POST_DOWN}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval COMMENT="$`echo NETWORK${NUMBER}_IPV6_COMMENT`"
+ echo "NETWORK${NUMBER}_IPV6_COMMENT=\"${COMMENT}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval METHOD="$`echo NETWORK${NUMBER}_IPV6_METHOD`"
+ echo "NETWORK${NUMBER}_IPV6_METHOD=\"${METHOD}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval ADDRESS="$`echo NETWORK${NUMBER}_IPV6_ADDRESS`"
+ echo "NETWORK${NUMBER}_IPV6_ADDRESS=\"${ADDRESS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval GATEWAY="$`echo NETWORK${NUMBER}_IPV6_GATEWAY`"
+ echo "NETWORK${NUMBER}_IPV6_GATEWAY=\"${GATEWAY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval NETMASK="$`echo NETWORK${NUMBER}_IPV6_NETMASK`"
+ echo "NETWORK${NUMBER}_IPV6_NETMASK=\"${NETMASK}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval POST_UP="$`echo NETWORK${NUMBER}_IPV6_POST_UP`"
+ echo "NETWORK${NUMBER}_IPV6_POST_UP=\"${POST_UP}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ eval POST_DOWN="$`echo NETWORK${NUMBER}_IPV6_POST_DOWN`"
+ echo "NETWORK${NUMBER}_IPV6_POST_DOWN=\"${POST_DOWN}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ done
+
+ echo "NAMESERVER_SERVER=\"${NAMESERVER_SERVER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ echo "NAMESERVER_DOMAIN=\"${NAMESERVER_DOMAIN}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ echo "NAMESERVER_SEARCH=\"${NAMESERVER_SEARCH}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ echo "NAMESERVER_OPTIONS=\"${NAMESERVER_OPTIONS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+}
+
+Root_password ()
+{
+ if db_get container/root-password
+ then
+ ROOT_PASSWORD="${RET}" # string (w/o empty)
+ fi
+
+ if [ -z "${ROOT_PASSWORD}" ]
+ then
+ # Create a random password as suggestion for the user
+ RANDOM_PASSWORD="$(dd if=/dev/urandom bs=12 count=1 2> /dev/null | base64)"
+
+ db_set container/root-password ${RANDOM_PASSWORD}
+ db_fset container/root-password seen false
+
+ db_settitle container/title
+ db_input high container/root-password || true
+ db_go
+
+ db_get container/root-password
+ ROOT_PASSWORD="${RET}"
+
+ if [ -z "${ROOT_PASSWORD}" ]
+ then
+ # User did set not set a password, falling back to random password
+ ROOT_PASSWORD="${RANDOM_PASSWORD}"
+ fi
+
+ if [ "${ROOT_PASSWORD}" = "${RANDOM_PASSWORD}" ]
+ then
+ echo "ROOT_RANDOM_PASSWORD=\"true\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ fi
+ fi
+
+ echo "ROOT_PASSWORD=\"${ROOT_PASSWORD}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+}
+
+Internal_options ()
+{
+ if db_get container/apt-recommends
+ then
+ APT_RECOMMENDS="${RET}" # boolean (w/ empty)
+ fi
+
+ echo "APT_RECOMMENDS=\"${APT_RECOMMENDS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/debconf-frontend
+ then
+ DEBCONF_FRONTEND="${RET}" # select
+ fi
+
+ DEBCONF_FRONTEND="${DEBCONF_FRONTEND:-dialog}"
+ echo "DEBCONF_FRONTEND=\"${DEBCONF_FRONTEND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/debconf-priority
+ then
+ DEBCONF_PRIORITY="${RET}" # select
+ fi
+
+ DEBCONF_PRIORITY="${DEBCONF_PRIORITY:-high}"
+ echo "DEBCONF_PRIORITY=\"${DEBCONF_PRIORITY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/container-command
+ then
+ CONTAINER_COMMAND="${RET}" # string (w/ empty)
+ fi
+
+ echo "CONTAINER_COMMAND=\"${CONTAINER_COMMAND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ NUMBER="1"
+
+ while db_get container/container-command${NUMBER} && [ "${RET}" ]
+ do
+ if db_get container/container-command${NUMBER}
+ then
+ eval CONTAINER_COMMAND${NUMBER}="\"${RET}\"" # string (w/o empty)
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+
+ CONTAINER_COMMAND_NUMBER="$((${NUMBER} - 1))"
+
+ echo "CONTAINER_COMMAND_NUMBER=\"${CONTAINER_COMMAND_NUMBER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ for NUMBER in $(seq 1 ${CONTAINER_COMMAND_NUMBER})
+ do
+ eval COMMAND="$`echo CONTAINER_COMMAND${NUMBER}`"
+ echo "CONTAINER_COMMAND${NUMBER}=\"${COMMAND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ done
+
+ if db_get container/host-command
+ then
+ HOST_COMMAND="${RET}" # string (w/ empty)
+ fi
+
+ echo "HOST_COMMAND=\"${HOST_COMMAND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ NUMBER="1"
+
+ while db_get container/host-command${NUMBER} && [ "${RET}" ]
+ do
+ if db_get container/host-command${NUMBER}
+ then
+ eval HOST_COMMAND${NUMBER}="\"${RET}\"" # string (w/o empty)
+ fi
+
+ NUMBER="$((${NUMBER} + 1))"
+ done
+
+ HOST_COMMAND_NUMBER="$((${NUMBER} - 1))"
+
+ echo "HOST_COMMAND_NUMBER=\"${HOST_COMMAND_NUMBER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ for NUMBER in $(seq 1 ${HOST_COMMAND_NUMBER})
+ do
+ eval COMMAND="$`echo HOST_COMMAND${NUMBER}`"
+ echo "HOST_COMMAND${NUMBER}=\"${COMMAND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+ done
+
+ if db_get container/auto
+ then
+ CNT_AUTO="${RET:-last-on}" # string (w/o empty)
+ fi
+
+ CNT_AUTO="${CNT_AUTO:-last-on}"
+ echo "CNT_AUTO=\"${CNT_AUTO}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/container-server
+ then
+ CNT_CONTAINER_SERVER="${RET:-FQDN}" # string (w/o empty)
+ fi
+
+ CNT_CONTAINER_SERVER="${CNT_CONTAINER_SERVER:-FQDN}"
+
+ case "${CNT_CONTAINER_SERVER}" in
+ FQDN)
+ CNT_CONTAINER_SERVER="$(hostname -f 2> /dev/null || hostname)"
+ ;;
+ esac
+
+ echo "CNT_CONTAINER_SERVER=\"${CNT_CONTAINER_SERVER}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/bind
+ then
+ BIND="${RET}" # string (w/ empty)
+ fi
+
+ echo "BIND=\"${BIND}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/bind-ro
+ then
+ BIND_RO="${RET}" # string (w/ empty)
+ fi
+
+ echo "BIND_RO=\"${BIND_RO}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/overlay
+ then
+ CNT_OVERLAY="${RET}" # string (w/ empty)
+ fi
+
+ echo "CNT_OVERLAY=\"${CNT_OVERLAY}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+
+ if db_get container/overlay-options
+ then
+ CNT_OVERLAY_OPTIONS="${RET}" # string (w/ empty)
+ fi
+
+ echo "CNT_OVERLAY_OPTIONS=\"${CNT_OVERLAY_OPTIONS}\"" >> "${DEBCONF_TMPDIR}/debconf.default"
+}
+
+Mode
+Images
+
+Distribution
+Parent_distribution
+
+Architecture
+
+Archives
+Parent_archives
+
+Mirror
+Mirror_security
+
+Parent_mirror
+Parent_mirror_security
+
+Archive_areas
+Parent_archive_areas
+
+Packages
+Local_archives
+
+Network
+Root_password
+
+Internal_options
+
+db_stop
diff --git a/share/build-scripts/debconf.d/0003-debconf.templates b/share/build-scripts/debconf.d/0003-debconf.templates
new file mode 100644
index 0000000..551033a
--- /dev/null
+++ b/share/build-scripts/debconf.d/0003-debconf.templates
@@ -0,0 +1,276 @@
+Template: container/title
+Type: title
+Description: compute-tools
+
+Template: container/mode
+Type: select
+Default:
+Choices-C: ${CHOICES_C}
+Choices: ${CHOICES}
+Description: Mode
+ Mode.
+
+Template: container/image
+Type: string
+Default:
+Description: Image
+ Image.
+
+Template: container/distribution
+Type: select
+Default:
+Choices-C: ${CHOICES_C}
+Choices: ${CHOICES}
+Description: Distribution
+ Distribution.
+
+Template: container/parent-distribution
+Type: select
+Default:
+Choices-C: ${CHOICES_C}
+Choices: ${CHOICES}
+Description: for internal use; can be preseeded
+ Parent Distribution.
+
+Template: container/architecture
+Type: select
+Default:
+Choices-C: ${CHOICES_C}
+Choices: ${CHOICES}
+Description: Architecture
+ Architecture.
+
+Template: container/archives
+Type: multiselect
+Default:
+Choices: ${CHOICES}
+Description: Archives
+ Archives.
+
+Template: container/parent-archives
+Type: multiselect
+Default:
+Choices: ${CHOICES}
+Description: Parent Archives
+ Parent Archives.
+
+Template: container/mirror
+Type: string
+Default:
+Description: Mirror
+ Mirror.
+
+Template: container/mirror-security
+Type: string
+Default:
+Description: Mirror Security
+ Mirror Security.
+
+Template: container/parent-mirror
+Type: string
+Default:
+Description: Parent Mirror
+ Parent Mirror.
+
+Template: container/parent-mirror-security
+Type: string
+Default:
+Description: Parent Mirror Security
+ Parent Mirror Security.
+
+Template: container/archive-areas
+Type: multiselect
+Default:
+Choices: ${CHOICES}
+Description: Archive Areas
+ Archive Areas.
+
+Template: container/parent-archive-areas
+Type: multiselect
+Default:
+Choices: ${CHOICES}
+Description: Parent Archive Areas
+ Parent Archive Areas.
+
+Template: container/packages
+Type: string
+Default:
+Description: Packages
+ Packages.
+
+Template: container/root-password
+Type: string
+Default:
+Description: Root password
+ Root password.
+
+Template: container/network1/bridge
+Type: string
+Default:
+Description: Bridge
+ Bridge.
+
+Template: container/network1/veth
+Type: string
+Default:
+Description: Veth name
+ Veth name.
+
+Template: container/network1/ipv4-method
+Type: select
+Choices: dhcp, static, stub, none
+Default:
+Description: Ethernet Interface Method (IPv4)?
+ What method should be used to configure the ethernet interface?
+ .
+ This defaults to dhcp and will require that you run a dhcp-server in your
+ network.
+
+Template: container/network1/ipv4-comment
+Type: string
+Default:
+Description: Ethernet Interface Comment (IPv4)?
+ What optional comment would you like to give to the ethernet interface?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv4-address
+Type: string
+Default:
+Description: Ethernet IP Address (IPv4)?
+ What should be the IP address of the current system?
+ .
+ This defaults to 192.168.1.2.
+
+Template: container/network1/ipv4-gateway
+Type: string
+Default:
+Description: Ethernet Gateway Address (IPv4)?
+ What should be the gateway address of the current system?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv4-netmask
+Type: string
+Default:
+Description: Ethernet Network Mask (IPv4)?
+ What should be the netmask of the current system?
+ .
+ Note that only the suffix is supported, e.g. '24'
+ for /24 or '16' for /16.
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv4-post-up
+Type: string
+Default:
+Description: Ethernet post-up Command (IPv4)?
+ What should be the post-up command for eno1?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv4-post-down
+Type: string
+Default:
+Description: Ethernet post-down Command (IPv4)?
+ What should be the post-down command for eno1?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv6-method
+Type: select
+Choices: dhcp, static, stub, none
+Default:
+Description: Ethernet Interface Method (IPv6)?
+ What method should be used to configure the ethernet interface?
+ .
+ This defaults to none.
+
+Template: container/network1/ipv6-comment
+Type: string
+Default:
+Description: Ethernet Interface Comment (IPv6)?
+ What optional comment would you like to give to the ethernet interface?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv6-address
+Type: string
+Default:
+Description: Ethernet IP Address (IPv6)?
+ What should be the IP address of the current system?
+ .
+ This defaults to fc00::1 (unique local unicast).
+
+Template: container/network1/ipv6-gateway
+Type: string
+Default:
+Description: Ethernet Gateway Address (IPv6)?
+ What should be the gateway address of the current system?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv6-netmask
+Type: string
+Default:
+Description: Ethernet Network Mask (IPv6)?
+ What should be the netmask of the current system?
+ .
+ Note that only the suffix is supported, e.g. '64'
+ for /64 or '48' for /48.
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv6-post-up
+Type: string
+Default:
+Description: Ethernet post-up Command (IPv6)?
+ What should be the post-up command for eno1?
+ .
+ This defaults to empty.
+
+Template: container/network1/ipv6-post-down
+Type: string
+Default:
+Description: Ethernet post-down Command (IPv6)?
+ What should be the post-down command for eno1?
+ .
+ This defaults to empty.
+
+Template: container/nameserver/server
+Type: string
+Default:
+Description: Nameserver Addresses?
+ What should be the IP addresses of the nameservers of the current system?
+ .
+ This defaults to empty. Multiple nameservers can be separated by whitespace.
+
+Template: container/nameserver/domain
+Type: string
+Default:
+Description: Nameserver Local Domain Name?
+ What should be local domain name used for name resolution?
+ .
+ See resolv.conf(5) for more information about the 'domain' option.
+ .
+ This defaults to empty.
+
+Template: container/nameserver/search
+Type: string
+Default:
+Description: Nameserver Search List?
+ What should be search list for hostname lookups?
+ .
+ See resolv.conf(5) for more information about the 'search' option.
+ .
+ This defaults to empty.
+
+Template: container/nameserver/options
+Type: string
+Default:
+Description: Nameserver Resolver Options?
+ What should be the resolver options?
+ .
+ See resolv.conf(5) for more information about the 'options' option.
+ .
+ This defaults to empty.
diff --git a/share/build-scripts/debootstrap b/share/build-scripts/debootstrap
new file mode 100755
index 0000000..5ab5db2
--- /dev/null
+++ b/share/build-scripts/debootstrap
@@ -0,0 +1,198 @@
+#!/bin/sh
+
+# Copyright (C) 2014-2022 Daniel Baumann <daniel.baumann@open-infrastructure.net>
+#
+# SPDX-License-Identifier: GPL-3.0+
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <https://www.gnu.org/licenses/>.
+
+set -e
+
+PROJECT="open-infrastructure"
+SOFTWARE="compute-tools"
+PROGRAM="container"
+
+SCRIPT="$(basename ${0})"
+
+HOOKS="/etc/${SOFTWARE}/hooks"
+MACHINES="/var/lib/machines"
+
+Parameters ()
+{
+ GETOPT_LONGOPTIONS="bind:,bind-ro:,script:,name:,architecture:,distribution:,mirror:,password:"
+ GETOPT_OPTIONS="b:,s:,n:,a:,d:,m:,p:"
+
+ PARAMETERS="$(getopt --longoptions ${GETOPT_LONGOPTIONS} --name=${SCRIPT} --options ${GETOPT_OPTIONS} --shell sh -- ${@})"
+
+ if [ "${?}" != "0" ]
+ then
+ echo "'${SCRIPT}': getopt exit" >&2
+ exit 1
+ fi
+
+ eval set -- "${PARAMETERS}"
+
+ while true
+ do
+ case "${1}" in
+ -b|--bind)
+ # ignore
+ shift 2
+ ;;
+
+ --bind-ro)
+ # ignore
+ shift 2
+ ;;
+
+ --cnt.auto)
+ # ignore
+ shift 2
+ ;;
+
+ --cnt.container-server)
+ # ignore
+ shift 2
+ ;;
+
+ -s|--script)
+ # ignore
+ shift 2
+ ;;
+
+ -n|--name)
+ NAME="${2}"
+ shift 2
+ ;;
+
+ -a|--architecture)
+ ARCHITECTURE="${2}"
+ shift 2
+ ;;
+
+ -d|--distribution)
+ DISTRIBUTION="${2}"
+ shift 2
+ ;;
+
+ -m|--mirror)
+ MIRROR="${2}"
+ shift 2
+ ;;
+
+ -p|--password)
+ PASSWORD="${2}"
+ shift 2
+ ;;
+
+ --)
+ shift 1
+ break
+ ;;
+
+ *)
+ echo "'${SCRIPT}': getopt error" >&2
+ exit 1
+ ;;
+ esac
+ done
+}
+
+Usage ()
+{
+ echo "Usage: container build -n|--name NAME -s|--script ${SCRIPT} -- [-a|--architecture ARCHITECTURE] [-d|--distribution DISTRIBUTION] [-m|--mirror MIRROR] [-p|--password PASSWORD}" >&2
+ exit 1
+}
+
+Parameters "${@}"
+
+if [ -z "${NAME}" ]
+then
+ Usage
+fi
+
+if [ -e "${MACHINES}/${NAME}" ]
+then
+ echo "'${NAME}': container already exists" >&2
+ exit 1
+fi
+
+case "${SCRIPT}" in
+ debootstrap)
+ BOOTSTRAP="/usr/sbin/debootstrap"
+ BOOTSTRAP_OPTIONS=""
+ ;;
+
+ mmdebstrap)
+ BOOTSTRAP="/usr/bin/mmdebstrap"
+ BOOTSTRAP_OPTIONS="--format=directory --mode=root --aptopt='APT::Sandbox::User \"root\"'"
+ ;;
+esac
+
+if [ ! -x "${BOOTSTRAP}" ]
+then
+ echo "'${NAME}': ${BOOTSTRAP} - no such file." >&2
+ exit 1
+fi
+
+if [ "$(id -u)" -ne 0 ]
+then
+ echo "'${NAME}': need root privileges" >&2
+ exit 1
+fi
+
+ARCHITECTURE="${ARCHITECTURE:-$(dpkg --print-architecture)}"
+DISTRIBUTION="${DISTRIBUTION:-bookworm}"
+MIRROR="${MIRROR:-https://deb.debian.org/debian}"
+PASSWORD="${PASSWORD:-$(dd if=/dev/urandom bs=12 count=1 2> /dev/null | base64)}"
+
+INCLUDE="dbus"
+
+case "${MIRROR}" in
+ https*)
+ INCLUDE="${INCLUDE},apt-transport-https,ca-certificates"
+ ;;
+esac
+
+# Pre hooks
+for FILE in "${HOOKS}/pre-${SCRIPT}".* "${HOOKS}/${NAME}.pre-${SCRIPT}"
+do
+ if [ -x "${FILE}" ]
+ then
+ "${FILE}"
+ fi
+done
+
+# Run
+mkdir -p "${MACHINES}"
+${BOOTSTRAP} ${BOOTSTRAP_OPTIONS} --arch=${ARCHITECTURE} --include=${INCLUDE} ${DISTRIBUTION} ${MACHINES}/${NAME} ${MIRROR}
+
+# Cleaning apt cache
+chroot "${MACHINES}/${NAME}" apt clean
+
+# Setting hostname
+echo "${NAME}" > "${MACHINES}/${NAME}/etc/hostname"
+
+# Setting root password
+echo root:${PASSWORD} | chroot "${MACHINES}/${NAME}" chpasswd
+echo "${NAME}: root password set to '${PASSWORD}'."
+
+# Post hooks
+for FILE in "${HOOKS}/post-${SCRIPT}".* "${HOOKS}/${NAME}.post-${SCRIPT}"
+do
+ if [ -x "${FILE}" ]
+ then
+ "${FILE}"
+ fi
+done