Skip to content

Commit 19fefdc

Browse files
authored
Stop a modified conffile from aborting the whole update (#47)
* Stop a modified conffile from aborting the whole update dpkg's conffile prompt has no tty during an update. It aborts the run, leaves the package half-configured, and stops every other pending package on the container behind an error that never mentions conffiles. 79 of 608 ct scripts run an unguarded apt upgrade in update_script. apt_conffile_guard points APT_CONFIG at a throwaway file carrying --force-confdef --force-confold. apt reads it after apt.conf.d, and it dies with the process, so an early exit cannot leave a drop-in behind. apt_conffile_report names what upstream shipped alongside the file that was kept. It runs from on_exit, not after update_script: 575 of 604 update_script bodies exit before returning, so anything placed there is unreachable. The three identical update branches in start() are now one function, which is what made a single guard call site possible. Supersedes community-scripts/ProxmoxVE#16438, which targeted the retired misc/build.func and paired begin/end calls that never ran. * smaller comments * Regenerate ui/API.txt
1 parent 662ce24 commit 19fefdc

4 files changed

Lines changed: 74 additions & 72 deletions

File tree

‎core/core.func‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2409,6 +2409,49 @@ apt_update_safe() {
24092409
return 0
24102410
}
24112411

2412+
# dpkg's conffile prompt has no tty during an update and takes the whole run
2413+
# with it. APT_CONFIG is read after apt.conf.d and dies with the process, so an
2414+
# early exit cannot leave a drop-in behind.
2415+
_cs_conffile_list() {
2416+
find "${_CS_CONFFILE_ROOT:-/etc}" -maxdepth 6 \( -name '*.dpkg-dist' -o -name '*.dpkg-new' \) 2>/dev/null | sort
2417+
}
2418+
2419+
apt_conffile_guard() {
2420+
command -v apt-get >/dev/null 2>&1 || return 0
2421+
[[ -n "${_CS_CONFFILE_GUARD:-}" ]] && return 0
2422+
2423+
local conf
2424+
conf="$(mktemp 2>/dev/null)" || return 0
2425+
printf 'Dpkg::Options { "--force-confdef"; "--force-confold"; };\n' >"$conf" 2>/dev/null || {
2426+
rm -f "$conf"
2427+
return 0
2428+
}
2429+
2430+
export APT_CONFIG="$conf"
2431+
_CS_CONFFILE_GUARD="$conf"
2432+
_CS_CONFFILE_BASELINE="$(_cs_conffile_list)"
2433+
return 0
2434+
}
2435+
2436+
apt_conffile_report() {
2437+
[[ -n "${_CS_CONFFILE_GUARD:-}" ]] || return 0
2438+
2439+
local added
2440+
added="$(comm -13 <(printf '%s\n' "${_CS_CONFFILE_BASELINE:-}") <(_cs_conffile_list) 2>/dev/null)"
2441+
rm -f "$_CS_CONFFILE_GUARD"
2442+
_CS_CONFFILE_GUARD=""
2443+
unset APT_CONFIG
2444+
[[ -n "${added//[[:space:]]/}" ]] || return 0
2445+
2446+
msg_warn "Kept your version of these config files - upstream shipped changes to them too:"
2447+
local f
2448+
while IFS= read -r f; do
2449+
[[ -n "$f" ]] || continue
2450+
echo -e "${TAB}${YW}${f%.dpkg-*}${CL} - new upstream version at ${YW}${f}${CL}"
2451+
done <<<"$added"
2452+
return 0
2453+
}
2454+
24122455
# ------------------------------------------------------------------------------
24132456
# ensure_whiptail()
24142457
#

‎core/error_handler.func‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,9 @@ on_exit() {
712712
# Before anything else: the timings are only useful if they survive a failure.
713713
declare -f dev_mode_timing_summary >/dev/null 2>&1 && dev_mode_timing_summary
714714

715+
# Here, because most ct scripts exit inside update_script.
716+
declare -f apt_conffile_report >/dev/null 2>&1 && apt_conffile_report
717+
715718
if _is_container_context; then
716719
if [[ $exit_code -ne 0 ]]; then
717720
_container_write_failure "$exit_code" "${FAILED_COMMAND:-}" "${FAILED_LINE:-}"

‎ui/API.txt‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@ _build_current_app_vars_tmp
22
_build_vars_diff
33
_container_write_failure
44
_cs_clear
5+
_cs_conffile_list
56
_cs_engine_ref_line
67
_cs_host_version_line
78
_cs_live_base
89
_cs_os_family
910
_cs_ref_line
1011
_cs_run_os_section
12+
_cs_run_update
1113
_cs_runtime_cache_dir
1214
_cs_scripts_ref_line
1315
_dev_step_end
@@ -50,6 +52,8 @@ _tm_pick_logfile
5052
_tm_send
5153
_write_storage_to_vars
5254
advanced_settings
55+
apt_conffile_guard
56+
apt_conffile_report
5357
apt_update_safe
5458
arch_check
5559
arch_resolve

‎ui/menu.func‎

Lines changed: 24 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1111,6 +1111,27 @@ check_breaking_change_guard() {
11111111
fi
11121112
return 1
11131113
}
1114+
1115+
# The update path, shared by the three branches of start() that reach it.
1116+
# exit, not return: returning continues into the ct script's host-only tail.
1117+
# Most ct scripts exit inside update_script, so the three calls after it are
1118+
# unreachable for them.
1119+
_cs_run_update() {
1120+
ensure_profile_loaded
1121+
ensure_recorded_toolchains
1122+
get_lxc_ip
1123+
migrate_update_entrypoint
1124+
runtime_script_status_guard update || exit 0
1125+
check_container_os_guard || exit 0
1126+
check_breaking_change_guard || exit 0
1127+
apt_conffile_guard
1128+
update_script
1129+
run_addon_updates
1130+
update_motd_ip
1131+
cleanup_lxc
1132+
exit 0
1133+
}
1134+
11141135
start() {
11151136
# Through the resolver, not a bare curl: this way a local checkout and the
11161137
# prefetched copy are used. Hardcoding the URL here meant tools.func and its
@@ -1138,58 +1159,12 @@ start() {
11381159
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
11391160
VERBOSE="no"
11401161
set_std_mode
1141-
ensure_profile_loaded
1142-
ensure_recorded_toolchains
1143-
get_lxc_ip
1144-
# Move legacy containers onto the helper-based /usr/bin/update the next time
1145-
# they update. No-op once migrated; preserves the container's original source.
1146-
migrate_update_entrypoint
1147-
# exit, not return, for the same reason as below: returning falls through
1148-
# into the ct script's host-only tail.
1149-
runtime_script_status_guard update || exit 0
1150-
check_container_os_guard || exit 0
1151-
check_breaking_change_guard || exit 0
1152-
update_script
1153-
run_addon_updates
1154-
update_motd_ip
1155-
cleanup_lxc
1156-
# An update run ends here. Returning would continue in the ct script, whose
1157-
# next lines are build_container and description -- host code, which inside a
1158-
# container fails as "You need to set 'CTID' variable", "MAC: unbound
1159-
# variable", or on Alpine "dpkg: command not found".
1160-
#
1161-
# Every ct script papers over this with an exit at the end of its own
1162-
# update_script, which is why the three calls above have been unreachable.
1163-
# Those scripts exit before getting here, so this changes nothing for them.
1164-
exit 0
1162+
_cs_run_update
11651163
elif ! command -v whiptail &>/dev/null || ! [ -t 0 ] || [[ "$TERM" == "dumb" ]]; then
11661164
msg_info "No interactive terminal detected – defaulting to silent update mode"
11671165
VERBOSE="no"
11681166
set_std_mode
1169-
ensure_profile_loaded
1170-
ensure_recorded_toolchains
1171-
get_lxc_ip
1172-
# Move legacy containers onto the helper-based /usr/bin/update the next time
1173-
# they update. No-op once migrated; preserves the container's original source.
1174-
migrate_update_entrypoint
1175-
# exit, not return, for the same reason as below: returning falls through
1176-
# into the ct script's host-only tail.
1177-
runtime_script_status_guard update || exit 0
1178-
check_container_os_guard || exit 0
1179-
check_breaking_change_guard || exit 0
1180-
update_script
1181-
run_addon_updates
1182-
update_motd_ip
1183-
cleanup_lxc
1184-
# An update run ends here. Returning would continue in the ct script, whose
1185-
# next lines are build_container and description -- host code, which inside a
1186-
# container fails as "You need to set 'CTID' variable", "MAC: unbound
1187-
# variable", or on Alpine "dpkg: command not found".
1188-
#
1189-
# Every ct script papers over this with an exit at the end of its own
1190-
# update_script, which is why the three calls above have been unreachable.
1191-
# Those scripts exit before getting here, so this changes nothing for them.
1192-
exit 0
1167+
_cs_run_update
11931168
else
11941169
CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "${APP} LXC Update/Setting" --menu \
11951170
"Support/Update functions for ${APP} LXC. Choose an option:" \
@@ -1213,29 +1188,6 @@ start() {
12131188
exit
12141189
;;
12151190
esac
1216-
ensure_profile_loaded
1217-
ensure_recorded_toolchains
1218-
get_lxc_ip
1219-
# Move legacy containers onto the helper-based /usr/bin/update the next time
1220-
# they update. No-op once migrated; preserves the container's original source.
1221-
migrate_update_entrypoint
1222-
# exit, not return, for the same reason as below: returning falls through
1223-
# into the ct script's host-only tail.
1224-
runtime_script_status_guard update || exit 0
1225-
check_container_os_guard || exit 0
1226-
check_breaking_change_guard || exit 0
1227-
update_script
1228-
run_addon_updates
1229-
update_motd_ip
1230-
cleanup_lxc
1231-
# An update run ends here. Returning would continue in the ct script, whose
1232-
# next lines are build_container and description -- host code, which inside a
1233-
# container fails as "You need to set 'CTID' variable", "MAC: unbound
1234-
# variable", or on Alpine "dpkg: command not found".
1235-
#
1236-
# Every ct script papers over this with an exit at the end of its own
1237-
# update_script, which is why the three calls above have been unreachable.
1238-
# Those scripts exit before getting here, so this changes nothing for them.
1239-
exit 0
1191+
_cs_run_update
12401192
fi
12411193
}

0 commit comments

Comments
 (0)