diff --git a/core/core.func b/core/core.func index 0c93ef7..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 >"${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 diff --git a/lxc/install.func b/lxc/install.func index 16c9a4d..b3846d6 100644 --- a/lxc/install.func +++ b/lxc/install.func @@ -589,12 +589,11 @@ pkg_update() { else msg_warn "Find Debian mirrors at: https://www.debian.org/mirror/list" fi - # Only ask when there is someone to answer. Headless, /dev/tty does not - # exist, the read fails instantly, custom_mirror stays empty and the - # `continue` below spins the loop forever instead of prompting. Falling - # through leaves apt_ok=false, which the caller reports properly. + # Only ask when there is someone to answer: otherwise the loop spins forever. + local mirror_src while ! is_unattended; do - read -rp " Enter a mirror hostname (or 'skip' to abort): " custom_mirror