From b38878bd5fb42423d16c464d9a3e27710e877cf6 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Fri, 25 Sep 2026 10:36:28 +0200 Subject: [PATCH 1/2] Make install prompts visible and answerable under Incus incus exec has no pty, so bash printed no read -p prompt: the question was invisible and its EOF aborted the install under catch_errors. A read shim in the container prints the prompt itself and treats EOF as the default, and prompt_confirm no longer needs /dev/tty to ask. --- core/core.func | 10 +++++---- incus/backend.func | 51 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 16 deletions(-) diff --git a/core/core.func b/core/core.func index 0c93ef7..a3fb241 100644 --- a/core/core.func +++ b/core/core.func @@ -1693,9 +1693,11 @@ prompt_confirm() { fi fi - # Check if running in a TTY - if [[ ! -t 0 ]]; then - # Not a TTY, use default + # Incus has no /dev/tty and forwards stdin as a pipe, so a bare -t 0 gate never asked. + local prompt_src="/dev/stdin" + : 2>/dev/null >"${LOGFILE:-$INCUS_BUILD_LOG}" 2>&1 || { msg_error "Failed to push f _install_script="$(_cs_fetch_text "install/${var_install}.sh")" _run_env="$(_incus_build_install_env)" _run_env+=$'\nsource /dev/stdin <<<"$(cat /tmp/incus-functions)"' + _run_env+=$'\n'"$(_incus_prompt_shim)" - # Deliberately NO pty here. Forcing one with `incus exec -t` looks like the - # fix for install scripts that prompt, but apt saves and restores stdin's - # terminal attributes around every dpkg call: on that pty tcsetattr returned - # EIO ("Setting in Stop via TCSAFLUSH for stdin failed"), killing the shell - # mid-install. It died before silent() could record anything, so the run was - # reported as a success against an empty container. + # No pty on purpose: under `incus exec -t` apt's tcsetattr fails with EIO and kills the shell. set +Eeuo pipefail trap - ERR - # stdin from /dev/null: without a pty `read -p` prints no prompt at all, so a - # script that asks a question waited on input nobody could see or answer. - # The trailing touch is a completion sentinel: all 552 install scripts run to - # cleanup_lxc/customize and none exits early, so the marker appears if and - # only if the script reached its end. + # The trailing touch is a completion sentinel: no install script exits early. incus exec "${CT_NAME}" -- bash -c "${_run_env} ${_install_script} -touch /root/.install-${SESSION_ID}.done" &1 | +touch /root/.install-${SESSION_ID}.done" 2>&1 | tee >(sed -u 's/.*\r//' >>"${LOGFILE:-$INCUS_BUILD_LOG}") # PIPESTATUS, not $?: the line above turns pipefail off, so $? is tee's # status - always 0. Every non-zero exit from the container was discarded @@ -1403,9 +1395,44 @@ export REPO_SOURCE='${REPO_SOURCE:-}' export REPO_SLUG='${REPO_SLUG:-}' export TELEMETRY_PLATFORM='incus' export CS_ANIMATION_OK='$([ -t 1 ] && echo 1 || echo 0)' +export CS_STDIN_OK='$([ -t 0 ] && echo 1 || echo 0)' EOF } +# bash shows a `read -p` prompt only on a terminal, so without a pty the question was invisible. +_incus_prompt_shim() { + cat <<'SHIMEOF' +read() { + local -a _args=() + local _prompt="" _flags + while (($#)); do + if [[ "$1" == -*p && "$1" != --* && $# -ge 2 ]]; then + _flags="${1%p}" + [[ "$_flags" != "-" ]] && _args+=("$_flags") + _prompt="$2" + shift 2 + continue + fi + _args+=("$1") + shift + done + [[ -n "$_prompt" ]] || { + builtin read "${_args[@]}" + return + } + printf '%s' "$_prompt" >&2 + if [[ "${CS_STDIN_OK:-0}" != "1" ]]; then + printf '%s\n' "(no input available - using the default)" >&2 + return 0 + fi + builtin read "${_args[@]}" || { + printf '\n' >&2 + return 0 + } +} +SHIMEOF +} + incus_build_container() { _incus_sync_from_pve_settings _incus_prepare_install_exports From 32a405d7d5eafe8ed878f086452a54b66456efe0 Mon Sep 17 00:00:00 2001 From: MickLesk <47820557+MickLesk@users.noreply.github.com> Date: Fri, 25 Sep 2026 10:41:15 +0200 Subject: [PATCH 2/2] Route the remaining container prompts through one stdin resolver The arm64 confirmation and the apt mirror fallback tested for a tty or opened /dev/tty directly, so under Incus the first aborted every unverified arm64 install with exit 106 and the second could never be offered. --- core/core.func | 23 ++++++++++++++++------- lxc/install.func | 9 ++++----- ui/API.txt | 1 + 3 files changed, 21 insertions(+), 12 deletions(-) diff --git a/core/core.func b/core/core.func index a3fb241..3b5797e 100644 --- a/core/core.func +++ b/core/core.func @@ -718,12 +718,13 @@ arch_check() { echo -e "${TAB}If you try it, please report the outcome - success or failure:" echo -e "${TAB}${BGN}https://github.com/community-scripts/ProxmoxVED/issues${CL}" echo "" - if [[ ! -t 0 ]]; then + local arm64_src + if ! arm64_src="$(_cs_stdin_source)"; then msg_error "Not running interactively - refusing to guess on arm64. Set var_arm64=yes to override." sleep 2 exit 106 fi - read -r -p "${TAB}Continue anyway? (y/N): " arm64_prompt /dev/null /dev/null