Skip to content

Commit d91b906

Browse files
MarcvsTvllivsclaude
andcommitted
fix(build.func): stop a modified conffile from aborting the whole update
update_script() runs with no tty. If an update pulls a package whose conffile the operator edited, and the new version also ships a changed copy, dpkg raises its "modified since installation" prompt, finds nothing to read it, and exits with "end of file on stdin at conffile prompt". The package is then left half configured (iU) and apt returns 100, which aborts every other pending package on that container, not just the one being updated. The error surfaced is "APT: Package manager error (broken packages / dependency problems)", which does not mention conffiles. The dpkg --configure -a recovery paths run without --force-conf* and hit the same prompt, so they cannot clear it either. 87 of 583 ct scripts run an apt upgrade inside update_script() and none pass Dpkg::Options, so this hooks the single dispatch in start() that all of them already funnel through, beside the existing check_container_os_guard. The guard is scoped to the update run and removed afterwards, so an operator's own later apt calls are unaffected. It also reports any newly appearing .dpkg-dist / .dpkg-new files, so keeping the local version stays visible instead of silently diverging from upstream. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1 parent ba2f9f8 commit d91b906

1 file changed

Lines changed: 65 additions & 0 deletions

File tree

misc/build.func

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4109,6 +4109,65 @@ check_container_os_guard() {
41094109
# - Otherwise: shows update/setting menu and runs update_script with cleanup
41104110
# ------------------------------------------------------------------------------
41114111

4112+
# ------------------------------------------------------------------------------
4113+
# apt_conffile_guard_begin()
4114+
#
4115+
# - Makes the upgrade inside update_script non-interactive for dpkg conffiles
4116+
# - Without this, a conffile the operator edited raises dpkg's "modified since
4117+
# installation" prompt. update_script has no tty, so dpkg exits with
4118+
# "end of file on stdin at conffile prompt", the package is left half
4119+
# configured (iU), and apt returns 100 - which aborts every other pending
4120+
# package on the container, not just the one being updated
4121+
# - DEBIAN_FRONTEND does not cover this: the prompt comes from dpkg, not debconf
4122+
# - Scoped to the update run only. apt_conffile_guard_end() removes the drop-in
4123+
# again, so an operator's own later apt calls are unaffected
4124+
# ------------------------------------------------------------------------------
4125+
CS_APT_CONF_DROPIN="/etc/apt/apt.conf.d/99-community-scripts-conffile"
4126+
4127+
apt_conffile_guard_begin() {
4128+
command -v apt-get >/dev/null 2>&1 || return 0
4129+
[[ -d /etc/apt/apt.conf.d ]] || return 0
4130+
4131+
rm -f "$CS_APT_CONF_DROPIN"
4132+
cat >"$CS_APT_CONF_DROPIN" <<'EOF'
4133+
// Added by community-scripts for the duration of an update run.
4134+
// Keeps locally modified configuration files instead of prompting, because
4135+
// update_script runs without a tty and dpkg would otherwise abort the upgrade.
4136+
Dpkg::Options {
4137+
"--force-confdef";
4138+
"--force-confold";
4139+
};
4140+
EOF
4141+
4142+
CS_CONFFILE_BEFORE="$(_cs_list_pending_conffiles)"
4143+
}
4144+
4145+
# ------------------------------------------------------------------------------
4146+
# apt_conffile_guard_end()
4147+
#
4148+
# - Removes the drop-in written by apt_conffile_guard_begin()
4149+
# - Reports any conffile where upstream shipped a change that was not applied,
4150+
# so keeping the local file stays visible instead of silently diverging
4151+
# ------------------------------------------------------------------------------
4152+
apt_conffile_guard_end() {
4153+
command -v apt-get >/dev/null 2>&1 || return 0
4154+
rm -f "$CS_APT_CONF_DROPIN"
4155+
4156+
local after new
4157+
after="$(_cs_list_pending_conffiles)"
4158+
new="$(comm -13 <(printf '%s\n' "$CS_CONFFILE_BEFORE") <(printf '%s\n' "$after") 2>/dev/null)"
4159+
[[ -z "$new" ]] && return 0
4160+
4161+
msg_warn "Kept your version of these config files; upstream shipped changes alongside them:"
4162+
while IFS= read -r f; do
4163+
[[ -n "$f" ]] && msg_warn " ${f%.dpkg-*} (new upstream version: $f)"
4164+
done <<<"$new"
4165+
}
4166+
4167+
_cs_list_pending_conffiles() {
4168+
find /etc \( -name '*.dpkg-dist' -o -name '*.dpkg-new' \) -type f 2>/dev/null | sort
4169+
}
4170+
41124171
start() {
41134172
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
41144173
if command -v pveversion >/dev/null 2>&1; then
@@ -4122,7 +4181,9 @@ start() {
41224181
get_lxc_ip
41234182
runtime_script_status_guard update || return 0
41244183
check_container_os_guard || return 0
4184+
apt_conffile_guard_begin
41254185
update_script
4186+
apt_conffile_guard_end
41264187
run_addon_updates
41274188
update_motd_ip
41284189
cleanup_lxc
@@ -4134,7 +4195,9 @@ start() {
41344195
get_lxc_ip
41354196
runtime_script_status_guard update || return 0
41364197
check_container_os_guard || return 0
4198+
apt_conffile_guard_begin
41374199
update_script
4200+
apt_conffile_guard_end
41384201
run_addon_updates
41394202
update_motd_ip
41404203
cleanup_lxc
@@ -4165,7 +4228,9 @@ start() {
41654228
get_lxc_ip
41664229
runtime_script_status_guard update || return 0
41674230
check_container_os_guard || return 0
4231+
apt_conffile_guard_begin
41684232
update_script
4233+
apt_conffile_guard_end
41694234
run_addon_updates
41704235
update_motd_ip
41714236
cleanup_lxc

0 commit comments

Comments
 (0)