v0.7.3: work out the user bus instead of asking for it by hand

A shell entered via `su` keeps the ORIGINAL user's XDG_RUNTIME_DIR, so
`systemctl --user` hunts for the bus in someone else's directory and finds
nothing — even when this user's manager is running perfectly. v0.7.2 detected
that and told the operator to export the right path. Typing /run/user/100
instead of /run/user/1000 cost a whole run.

The runtime dir is /run/user/<uid> by definition. The script now derives it,
retries the bus check with it, and installs the units — then tells the operator
to export it for the REST of their shell, because a child process cannot fix
its parent's environment.

The failure message also stopped guessing. It now distinguishes the two real
cases: /run/user/<uid> missing (no logind session — enable-linger, and no fresh
login is needed, contrary to what v0.7.1 said) versus present but unanswered
(the manager itself is the problem — go look at user@<uid>.service).

Four branches fired in a sandbox with three stub systemctls: bus answers
directly; bus answers only with the corrected dir; runtime dir absent; runtime
dir present but manager silent. All exit 0, and the middle one installs units
that the previous version would have skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-13 02:45:04 +08:00
co-authored by Claude Opus 5
parent b928ac54df
commit 9dfee100d2
+31 -3
View File
@@ -79,8 +79,31 @@ say "systemd user units"
# "Failed to connect to user scope bus". Ask the real question — can we talk to # "Failed to connect to user scope bus". Ask the real question — can we talk to
# the user manager — instead of asking whether the binary exists. # the user manager — instead of asking whether the binary exists.
USER_BUS="" USER_BUS=""
if command -v systemctl >/dev/null 2>&1 && systemctl --user show-environment >/dev/null 2>&1; then BUS_FIXED_UP=""
if command -v systemctl >/dev/null 2>&1; then
if systemctl --user show-environment >/dev/null 2>&1; then
USER_BUS="yes" USER_BUS="yes"
else
# A shell entered via `su` keeps the ORIGINAL user's XDG_RUNTIME_DIR, so
# `systemctl --user` looks for the bus in someone else's directory and finds
# nothing — even when this user's manager is running perfectly well. The
# runtime dir is /run/user/<uid> by definition, so work it out instead of
# asking someone to export it by hand and get the digits right.
_own_runtime="/run/user/$(id -u)"
if [[ -d "$_own_runtime" && "${XDG_RUNTIME_DIR:-}" != "$_own_runtime" ]]; then
export XDG_RUNTIME_DIR="$_own_runtime"
if systemctl --user show-environment >/dev/null 2>&1; then
USER_BUS="yes"
BUS_FIXED_UP="yes"
fi
fi
fi
fi
if [[ -n "$BUS_FIXED_UP" ]]; then
ok "user bus found at $XDG_RUNTIME_DIR (the inherited XDG_RUNTIME_DIR pointed elsewhere)"
warn "this shell still has the old value. For later commands in THIS shell:"
warn " export XDG_RUNTIME_DIR=$XDG_RUNTIME_DIR"
fi fi
if [[ -z "$USER_BUS" ]]; then if [[ -z "$USER_BUS" ]]; then
@@ -89,8 +112,13 @@ if [[ -z "$USER_BUS" ]]; then
warn "reason: systemctl is not on PATH." warn "reason: systemctl is not on PATH."
else else
warn "reason: systemctl --user cannot reach a user manager (XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-unset})." warn "reason: systemctl --user cannot reach a user manager (XDG_RUNTIME_DIR=${XDG_RUNTIME_DIR:-unset})."
warn "common causes: an LXC without logind, a shell entered via su, or no lingering." if [[ ! -d "/run/user/$(id -u)" ]]; then
warn " sudo loginctl enable-linger $USER # then log in fresh and re-run" warn "/run/user/$(id -u) does not exist — $USER has no logind session at all."
warn " sudo loginctl enable-linger $USER # then re-run; no fresh login needed"
else
warn "/run/user/$(id -u) exists but the manager there did not answer."
warn " systemctl status user@$(id -u).service # start here"
fi
fi fi
warn "until then, run the three by hand from $REPO:" warn "until then, run the three by hand from $REPO:"
warn " $VENV/bin/socialmag-openbridge &" warn " $VENV/bin/socialmag-openbridge &"