check the terraria user can run terractl before switching to it

upgrade (before stopping anything) and prepare/run started as root now
refuse with an explanation when terractl is somewhere the terraria user
can't open, such as a copy under /root, instead of failing with
"env: Permission denied". upgrade also says when it started the server
again after a failure.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
adamandClaude Opus 5.5 committed 2026-10-02 22:03:43 +00:00
1 parent 7adf5c2999
commit 8a509f1398
2 files changed
+14 -3

No files matched your search

+13 -3
View File
@@ -1074,6 +1074,15 @@ svc_can_read() {
else (( 8#$mode & 0004 )); fi
}
# Check that the service user can run this script, which prepare/run (as root)
# and upgrade switch to. Not so for a copy in a private folder, such as a
# development copy under /root.
need_svc_can_run_self() {
command -v runuser >/dev/null || die "runuser not found; run as '$SVC_USER' instead"
runuser -u "$SVC_USER" -- test -x "$SELF" 2>/dev/null ||
die "$1 runs $SELF as the '$SVC_USER' user, who can't open it (it's in a folder only root can open, e.g. /root). Use the installed terractl, or a copy somewhere '$SVC_USER' can read."
}
# Zips in dist/ the servers can't unpack, e.g. copied in with 'scp -p' from a
# private file. Instances fail on their first start with such a zip.
unreadable_zips() {
@@ -1373,6 +1382,7 @@ cmd_upgrade() {
fi
command -v unzip >/dev/null || die "unzip is not installed"
need_svc_can_run_self "upgrade"
listing=$(unzip -Z1 "$f" 2>/dev/null) || die "$f isn't a readable zip (damaged, or not fully downloaded?)"
case $TYPE in
vanilla) grep -q '/Linux/TerrariaServer\.bin\.x86_64$' <<< "$listing" ||
@@ -1402,7 +1412,7 @@ cmd_upgrade() {
backup_file+=.tar.gz
# In a subshell, so a failure comes back here instead of exiting
if ! ( trap cleanup EXIT; cmd_export "$name" "$backup_file" ) >/dev/null; then
if [[ $was_running -eq 1 ]]; then systemctl start "$unit"; fi
if [[ $was_running -eq 1 ]]; then systemctl start "$unit"; echo "$unit started again"; fi
die "backing up '$name' failed, so its version wasn't changed"
fi
echo "backup of worlds and configs: $backup_file"
@@ -1414,7 +1424,7 @@ cmd_upgrade() {
# new server/ is complete, the old one is left in place.
if ! runuser -u "$SVC_USER" -- env HOME="$dir" "$SELF" prepare "$name"; then
set_zip_pin "$name" "$old_pin"
if [[ $was_running -eq 1 ]]; then systemctl start "$unit"; fi
if [[ $was_running -eq 1 ]]; then systemctl start "$unit"; echo "$unit started again"; fi
die "unpacking $zip failed (see above); '$name' still runs ${installed:-its old version}"
fi
@@ -1529,7 +1539,7 @@ valid_name "$1"
# debugging), switch to the service user so nothing ends up owned by root.
if [[ $command == prepare || $command == run ]]; then
if [[ $EUID -eq 0 ]]; then
command -v runuser >/dev/null || die "runuser not found; run as '$SVC_USER' instead"
need_svc_can_run_self "'$command'"
exec runuser -u "$SVC_USER" -- env HOME="$(inst_dir "$1")" \
"$SELF" "$command" "$@"
elif [[ $(id -un) != "$SVC_USER" ]]; then