Skip to content

Commit 192d61d

Browse files
committed
Fix Incus host misdetection in update paths
Make Incus platform detection resilient when `incus` is installed outside PATH (e.g., /snap/bin) and when `incus info` is unavailable to non-root users. The change adds Incus binary/path resolution, ensures PATH is corrected early in build flow, prioritizes container markers before host checks, and uses filesystem/socket signals for host detection. It also hardens the menu update branch to explicitly refuse running container update logic on detected PVE/Incus hosts and provides recovery guidance.
1 parent 927c936 commit 192d61d

3 files changed

Lines changed: 68 additions & 7 deletions

File tree

core/build.func

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,12 @@ _cs_prefetch_engine || true
309309

310310
_cs_source_func "lxc/platform.func"
311311

312+
# Before anything asks which platform this is: the client has to be resolvable,
313+
# or an Incus host detects as a plain container and the ct script below runs its
314+
# update path against the host.
315+
declare -f ensure_incus_on_path >/dev/null 2>&1 && ensure_incus_on_path
316+
true
317+
312318
# Inside a container the OS is a fact, not a choice. A dual-OS script branches
313319
# on var_os near the top of the file and only offers the menu on a host, so an
314320
# update took the Debian arm and told an Alpine container it needed 6 GB and

lxc/platform.func

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,66 @@
1616
[[ -n "${_LXC_PLATFORM_FUNC_LOADED:-}" ]] && return
1717
_LXC_PLATFORM_FUNC_LOADED=1
1818

19+
# The client is not always on PATH: a non-login shell misses /snap/bin, and
20+
# sudo's secure_path can drop it too. `command -v incus` then failed, detection
21+
# answered "container", and the ct script updated the host instead of building.
22+
_lxc_incus_bin() {
23+
if command -v incus &>/dev/null; then
24+
command -v incus
25+
return 0
26+
fi
27+
local p
28+
for p in /usr/bin/incus /usr/local/bin/incus /snap/bin/incus /opt/incus/bin/incus; do
29+
[[ -x "$p" ]] && {
30+
printf '%s\n' "$p"
31+
return 0
32+
}
33+
done
34+
return 1
35+
}
36+
37+
# Detection finding the client is not enough - every later `incus` call in the
38+
# engine has to resolve too. Idempotent, and a no-op when it is already there.
39+
ensure_incus_on_path() {
40+
command -v incus &>/dev/null && return 0
41+
local bin dir
42+
bin="$(_lxc_incus_bin)" || return 1
43+
dir="$(dirname "$bin")"
44+
case ":${PATH}:" in
45+
*":${dir}:"*) ;;
46+
*)
47+
PATH="${dir}:${PATH}"
48+
export PATH
49+
;;
50+
esac
51+
}
52+
1953
detect_lxc_platform() {
2054
if [[ -n "${LXC_PLATFORM:-}" ]]; then
2155
echo "$LXC_PLATFORM"
2256
return
2357
fi
2458

25-
if command -v pveversion &>/dev/null; then
26-
echo "pve"
59+
# Container markers come first now: the host test below no longer needs a
60+
# reachable daemon, so a container carrying the client could match it.
61+
if [[ -S /dev/incus/sock ]] || [[ -f /etc/profile.d/incus-motd.sh ]]; then
62+
echo "incus-container"
2763
return
2864
fi
2965

30-
if command -v incus &>/dev/null && incus info &>/dev/null 2>&1; then
31-
echo "incus"
66+
if command -v pveversion &>/dev/null; then
67+
echo "pve"
3268
return
3369
fi
3470

35-
if [[ -S /dev/incus/sock ]] || [[ -f /etc/profile.d/incus-motd.sh ]]; then
36-
echo "incus-container"
37-
return
71+
# `incus info` needs a running daemon AND group membership, neither of which
72+
# a non-root operator is guaranteed. On-disk state settles it either way.
73+
local bin
74+
if bin="$(_lxc_incus_bin)"; then
75+
if "$bin" info &>/dev/null 2>&1 || [[ -d /var/lib/incus ]] || [[ -S /var/run/incus/unix.socket ]]; then
76+
echo "incus"
77+
return
78+
fi
3879
fi
3980

4081
echo "container"

ui/menu.func

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,10 +1096,24 @@ start() {
10961096
# five parts were six network requests between the header and the menu,
10971097
# every run, whatever else had already been fetched.
10981098
_cs_source_func "lib/tools.func"
1099+
1100+
# Every branch after the first updates the system it is running on. Missing
1101+
# pveversion used to be taken as proof of being inside a container, but an
1102+
# Incus host has none either, so a create run fell through and ran apt-get
1103+
# against the host. Only refuse on a positively identified host, so an
1104+
# environment we cannot classify still updates as before.
1105+
local _cs_platform=""
1106+
declare -f detect_lxc_platform >/dev/null 2>&1 && _cs_platform="$(detect_lxc_platform)"
1107+
10991108
if command -v pveversion >/dev/null 2>&1; then
11001109
runtime_script_status_guard install || return 0
11011110
install_script || return 0
11021111
return 0
1112+
elif [[ "$_cs_platform" == "pve" || "$_cs_platform" == "incus" ]]; then
1113+
msg_error "This is a ${_cs_platform} host, not a container - refusing to update it"
1114+
msg_custom "ℹ️" "${YW}" "The engine could not load the ${_cs_platform} backend, so ${APP:-this script} never got to the create path"
1115+
msg_custom "ℹ️" "${YW}" "Retry with: LXC_PLATFORM=${_cs_platform} bash -c \"\$(curl -fsSL <script-url>)\""
1116+
exit 1
11031117
elif [ ! -z ${PHS_SILENT+x} ] && [[ "${PHS_SILENT}" == "1" ]]; then
11041118
VERBOSE="no"
11051119
set_std_mode

0 commit comments

Comments
 (0)