From dc6f3011e888e9046b69e05db30e79b38bb2c81b Mon Sep 17 00:00:00 2001 From: Ben Hoff Date: Fri, 21 Nov 2025 14:22:27 -0500 Subject: [PATCH 1/3] Add configurable cache bind for chroot --- lib/functions/general/chroot-helpers.sh | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/functions/general/chroot-helpers.sh b/lib/functions/general/chroot-helpers.sh index a28feee25bf9..34fa6c110055 100644 --- a/lib/functions/general/chroot-helpers.sh +++ b/lib/functions/general/chroot-helpers.sh @@ -13,7 +13,7 @@ function mount_chroot() { display_alert "mount_chroot called outside of logging section..." "mount_chroot '$1'\n$(stack_color="${magenta_color:-}" show_caller_full)" "warn" fi - local target + local target cache_src target="$(realpath "$1")" # normalize, remove last slash if dir display_alert "mount_chroot" "$target" "debug" mkdir -p "${target}/run/user/0" @@ -26,6 +26,19 @@ function mount_chroot() { mount -t sysfs chsys "${target}"/sys mount --bind /dev "${target}"/dev mount -t devpts chpts "${target}"/dev/pts || mount --bind /dev/pts "${target}"/dev/pts + + # Bind host cache into chroot if present (configurable via ARMBIAN_CACHE_DIR) + cache_src="${ARMBIAN_CACHE_DIR:-/armbian/cache}" + if [[ -d "${cache_src}" ]]; then + mkdir -p "${target}/armbian/cache" + if ! mountpoint -q "${target}/armbian/cache" && mount --bind "${cache_src}" "${target}/armbian/cache"; then + : + else + display_alert "cache bind failed or already bound" "${cache_src} -> ${target}/armbian/cache" "warn" + fi + else + display_alert "Host cache not found — skipping cache mount" "${cache_src}" "warn" + fi } # umount_chroot @@ -33,9 +46,15 @@ function umount_chroot() { if [[ "x${LOG_SECTION}x" == "xx" ]]; then display_alert "umount_chroot called outside of logging section..." "umount_chroot '$1'\n$(stack_color="${magenta_color:-}" show_caller_full)" "warn" fi - local target + local target cache_src target="$(realpath "$1")" # normalize, remove last slash if dir display_alert "Unmounting" "$target" "info" + + cache_src="${ARMBIAN_CACHE_DIR:-/armbian/cache}" + if mountpoint -q "${target}/armbian/cache"; then + umount "${target}/armbian/cache" || true + fi + while grep -Eq "${target}\/(dev|proc|sys|tmp|var\/tmp|run\/user\/0)" /proc/mounts; do display_alert "Unmounting..." "target: ${target}" "debug" umount "${target}"/dev/pts || true From a51e9fdf2abd305963956f535ec0c15292fdfb57 Mon Sep 17 00:00:00 2001 From: Ben Hoff Date: Sat, 22 Nov 2025 20:36:16 -0500 Subject: [PATCH 2/3] Improve chroot mounts and document cache dir --- config/README.md | 5 +++ lib/functions/general/chroot-helpers.sh | 54 ++++++++++++++++++------- 2 files changed, 45 insertions(+), 14 deletions(-) create mode 100644 config/README.md diff --git a/config/README.md b/config/README.md new file mode 100644 index 000000000000..af41ae608994 --- /dev/null +++ b/config/README.md @@ -0,0 +1,5 @@ +# Configuration Directory + +This directory contains the build-time configuration files, templates, and data consumed by the Armbian build framework. + +- `ARMBIAN_CACHE_DIR` (default `/armbian/cache`): Host path that, when present, is bind-mounted into the chroot at `/armbian/cache` to share downloaded artifacts (keyrings, packages, etc.) between builds. Override this if your cache lives elsewhere or needs to be relocated for containerized builds. diff --git a/lib/functions/general/chroot-helpers.sh b/lib/functions/general/chroot-helpers.sh index 34fa6c110055..9eec2301812d 100644 --- a/lib/functions/general/chroot-helpers.sh +++ b/lib/functions/general/chroot-helpers.sh @@ -16,25 +16,52 @@ function mount_chroot() { local target cache_src target="$(realpath "$1")" # normalize, remove last slash if dir display_alert "mount_chroot" "$target" "debug" - mkdir -p "${target}/run/user/0" + if ! mkdir -p "${target}/run/user/0"; then + display_alert "Failed to prepare chroot runtime directory" "${target}/run/user/0" "err" + return 1 + fi # tmpfs size=50% is the Linux default, but we need more. - mount -t tmpfs -o "size=99%" tmpfs "${target}/tmp" - mount -t tmpfs -o "size=99%" tmpfs "${target}/var/tmp" - mount -t tmpfs -o "size=99%" tmpfs "${target}/run/user/0" - mount -t proc chproc "${target}"/proc - mount -t sysfs chsys "${target}"/sys - mount --bind /dev "${target}"/dev - mount -t devpts chpts "${target}"/dev/pts || mount --bind /dev/pts "${target}"/dev/pts + if ! mountpoint -q "${target}/tmp" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/tmp"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/tmp" "err" + return 1 + fi + if ! mountpoint -q "${target}/var/tmp" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/var/tmp"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/var/tmp" "err" + return 1 + fi + if ! mountpoint -q "${target}/run/user/0" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/run/user/0"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/run/user/0" "err" + return 1 + fi + if ! mountpoint -q "${target}/proc" && ! mount -t proc chproc "${target}/proc"; then + display_alert "Failed to mount proc inside chroot" "${target}/proc" "err" + return 1 + fi + if ! mountpoint -q "${target}/sys" && ! mount -t sysfs chsys "${target}/sys"; then + display_alert "Failed to mount sysfs inside chroot" "${target}/sys" "err" + return 1 + fi + if ! mountpoint -q "${target}/dev" && ! mount --bind /dev "${target}/dev"; then + display_alert "Failed to bind /dev into chroot" "${target}/dev" "err" + return 1 + fi + if ! mountpoint -q "${target}/dev/pts" && ! mount -t devpts chpts "${target}/dev/pts" && ! mount --bind /dev/pts "${target}/dev/pts"; then + display_alert "Failed to mount devpts inside chroot" "${target}/dev/pts" "err" + return 1 + fi # Bind host cache into chroot if present (configurable via ARMBIAN_CACHE_DIR) cache_src="${ARMBIAN_CACHE_DIR:-/armbian/cache}" if [[ -d "${cache_src}" ]]; then - mkdir -p "${target}/armbian/cache" - if ! mountpoint -q "${target}/armbian/cache" && mount --bind "${cache_src}" "${target}/armbian/cache"; then - : + if ! mkdir -p "${target}/armbian/cache"; then + display_alert "Failed to create cache mountpoint" "${target}/armbian/cache" "warn" + elif mountpoint -q "${target}/armbian/cache"; then + display_alert "Cache already mounted — skipping cache bind" "${target}/armbian/cache" "debug" else - display_alert "cache bind failed or already bound" "${cache_src} -> ${target}/armbian/cache" "warn" + if ! mount --bind "${cache_src}" "${target}/armbian/cache"; then + display_alert "Cache bind failed" "${cache_src} -> ${target}/armbian/cache" "warn" + fi fi else display_alert "Host cache not found — skipping cache mount" "${cache_src}" "warn" @@ -46,11 +73,10 @@ function umount_chroot() { if [[ "x${LOG_SECTION}x" == "xx" ]]; then display_alert "umount_chroot called outside of logging section..." "umount_chroot '$1'\n$(stack_color="${magenta_color:-}" show_caller_full)" "warn" fi - local target cache_src + local target target="$(realpath "$1")" # normalize, remove last slash if dir display_alert "Unmounting" "$target" "info" - cache_src="${ARMBIAN_CACHE_DIR:-/armbian/cache}" if mountpoint -q "${target}/armbian/cache"; then umount "${target}/armbian/cache" || true fi From 87db834771f0b79f45a1d9205ace241ca3e27ed2 Mon Sep 17 00:00:00 2001 From: Ben Hoff Date: Wed, 10 Dec 2025 20:19:33 -0500 Subject: [PATCH 3/3] Clean up chroot mounts on failure --- lib/functions/general/chroot-helpers.sh | 78 ++++++++++++++++++------- 1 file changed, 57 insertions(+), 21 deletions(-) diff --git a/lib/functions/general/chroot-helpers.sh b/lib/functions/general/chroot-helpers.sh index 9eec2301812d..665f31ce07d2 100644 --- a/lib/functions/general/chroot-helpers.sh +++ b/lib/functions/general/chroot-helpers.sh @@ -16,39 +16,75 @@ function mount_chroot() { local target cache_src target="$(realpath "$1")" # normalize, remove last slash if dir display_alert "mount_chroot" "$target" "debug" + # Track mounts we create so we can unwind on failure. + local -a mounted_points=() + cleanup_mounted_points() { + local -i i + for (( i=${#mounted_points[@]}-1; i>=0; i-- )); do + umount --recursive "${mounted_points[i]}" &> /dev/null || true + done + } if ! mkdir -p "${target}/run/user/0"; then display_alert "Failed to prepare chroot runtime directory" "${target}/run/user/0" "err" return 1 fi # tmpfs size=50% is the Linux default, but we need more. - if ! mountpoint -q "${target}/tmp" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/tmp"; then - display_alert "Failed to mount tmpfs inside chroot" "${target}/tmp" "err" - return 1 + if ! mountpoint -q "${target}/tmp"; then + if ! mount -t tmpfs -o "size=99%" tmpfs "${target}/tmp"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/tmp" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/tmp") fi - if ! mountpoint -q "${target}/var/tmp" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/var/tmp"; then - display_alert "Failed to mount tmpfs inside chroot" "${target}/var/tmp" "err" - return 1 + if ! mountpoint -q "${target}/var/tmp"; then + if ! mount -t tmpfs -o "size=99%" tmpfs "${target}/var/tmp"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/var/tmp" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/var/tmp") fi - if ! mountpoint -q "${target}/run/user/0" && ! mount -t tmpfs -o "size=99%" tmpfs "${target}/run/user/0"; then - display_alert "Failed to mount tmpfs inside chroot" "${target}/run/user/0" "err" - return 1 + if ! mountpoint -q "${target}/run/user/0"; then + if ! mount -t tmpfs -o "size=99%" tmpfs "${target}/run/user/0"; then + display_alert "Failed to mount tmpfs inside chroot" "${target}/run/user/0" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/run/user/0") fi - if ! mountpoint -q "${target}/proc" && ! mount -t proc chproc "${target}/proc"; then - display_alert "Failed to mount proc inside chroot" "${target}/proc" "err" - return 1 + if ! mountpoint -q "${target}/proc"; then + if ! mount -t proc chproc "${target}/proc"; then + display_alert "Failed to mount proc inside chroot" "${target}/proc" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/proc") fi - if ! mountpoint -q "${target}/sys" && ! mount -t sysfs chsys "${target}/sys"; then - display_alert "Failed to mount sysfs inside chroot" "${target}/sys" "err" - return 1 + if ! mountpoint -q "${target}/sys"; then + if ! mount -t sysfs chsys "${target}/sys"; then + display_alert "Failed to mount sysfs inside chroot" "${target}/sys" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/sys") fi - if ! mountpoint -q "${target}/dev" && ! mount --bind /dev "${target}/dev"; then - display_alert "Failed to bind /dev into chroot" "${target}/dev" "err" - return 1 + if ! mountpoint -q "${target}/dev"; then + if ! mount --bind /dev "${target}/dev"; then + display_alert "Failed to bind /dev into chroot" "${target}/dev" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/dev") fi - if ! mountpoint -q "${target}/dev/pts" && ! mount -t devpts chpts "${target}/dev/pts" && ! mount --bind /dev/pts "${target}/dev/pts"; then - display_alert "Failed to mount devpts inside chroot" "${target}/dev/pts" "err" - return 1 + if ! mountpoint -q "${target}/dev/pts"; then + if ! mount -t devpts chpts "${target}/dev/pts" && ! mount --bind /dev/pts "${target}/dev/pts"; then + display_alert "Failed to mount devpts inside chroot" "${target}/dev/pts" "err" + cleanup_mounted_points + return 1 + fi + mounted_points+=("${target}/dev/pts") fi # Bind host cache into chroot if present (configurable via ARMBIAN_CACHE_DIR)