From ef63609db9ae662fc359006d46ad5923e42e8f83 Mon Sep 17 00:00:00 2001 From: abrown38 Date: Fri, 2 Oct 2026 21:21:59 +0000 Subject: [PATCH] fix permissions subcommand --- CHANGELOG.md | 1 + bin/terractl | 25 +++++++++++++++++++++++++ completions/bash/terractl | 2 +- docs/guide.md | 8 ++++++-- lib/terractl-remote | 2 +- 5 files changed, 34 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3781f65..e2d0254 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Unreleased +- New `fix-perms` command: `sudo terractl fix-perms ` gives every file of an instance back to the `terraria` user and reapplies the usual modes (group can read, others nothing; server binaries executable), e.g. after copying worlds in as root. Symlinks are not followed. Works with `--host` too. - `list` warns about zips in `dist/` that the `terraria` user can't read (e.g. copied in with `scp -p` from a private file), and `info` lists them as `unreadable_zip=`. A server that fails to install because of one now says how to fix it (`sudo chmod 644 `) instead of just "cannot read", and a missing zip is reported as not found. ## 0.0.11 - 2026-09-30 diff --git a/bin/terractl b/bin/terractl index e111c0a..102fb7c 100755 --- a/bin/terractl +++ b/bin/terractl @@ -79,6 +79,8 @@ Admin commands: cmd send a console command (e.g. save, say hi) reinstall [--clean] re-unpack server on next start (--clean also re-downloads tModLoader's .NET) + fix-perms give all of an instance's files back to the + '$SVC_USER' user, with the usual modes (run as root) mods [list] show installed mods and whether they're enabled mods add ... install mods (and ModConfigs) and enable them mods enable|disable ... change which installed mods load @@ -1119,6 +1121,28 @@ cmd_reinstall() { echo "server/ will be re-unpacked on next start: $(hint group restart "$name")" } +# Gives every file of an instance back to the service user, with the modes the +# service creates files with (UMask=0027): the terraria group can read but not +# change them, others get nothing. For files copied in as root, or with odd +# modes (e.g. 'cp -a' or 'scp -p'). Symlinks are left alone, never followed. +cmd_fix_perms() { + local name=$1 dir; shift + [[ $# -eq 0 ]] || die "usage: terractl fix-perms " + [[ $EUID -eq 0 ]] || die "fix-perms must be run as root: sudo terractl fix-perms $name" + dir=$(inst_dir "$name") + [[ -f $dir/instance.conf && ! -L $dir ]] || die "no instance '$name'" + chown -R -h "$SVC_USER:$SVC_USER" "$dir" + # X: directories, and files that were already executable for someone + chmod -R u+rwX,u-s,g=rX,o= "$dir" + # The server binaries must stay executable, whatever happened to them + if [[ -d $dir/server ]]; then + find "$dir/server" -maxdepth 1 -type f \ + \( -name TerrariaServer.bin.x86_64 -o -name TerrariaServer -o -name '*.sh' \) \ + -exec chmod u+x,g+x {} + + fi + echo "'$name': all files owned by $SVC_USER:$SVC_USER, readable by the '$SVC_USER' group, private to everyone else" +} + # key=value facts, one per line, for people and for terractl-remote (copy, move, # tab completion). Without a name: this host. Repeated keys are lists. cmd_info() { @@ -1218,6 +1242,7 @@ case $command in mods) cmd_mods "$@" ;; new) cmd_new "$@" ;; reinstall) cmd_reinstall "$@" ;; + fix-perms) cmd_fix_perms "$@" ;; delete) cmd_delete "$@" ;; rename) cmd_rename "$@" ;; export) cmd_export "$@" ;; diff --git a/completions/bash/terractl b/completions/bash/terractl index 28b7fb0..2080ded 100644 --- a/completions/bash/terractl +++ b/completions/bash/terractl @@ -105,7 +105,7 @@ _terractl() { cword=$COMP_CWORD fi - local commands="new list info start stop restart enable disable attach watch cmd mods reinstall delete rename export import" + local commands="new list info start stop restart enable disable attach watch cmd mods reinstall fix-perms delete rename export import" local console="save say playing kick ban motd password time dawn noon dusk midnight settle seed version maxplayers port clear help" # terractl --host ...: the same as on this host, except diff --git a/docs/guide.md b/docs/guide.md index 9949376..b4bf2af 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -808,6 +808,7 @@ The servers always run as the `terraria` user. Administration is simplest with ` | `cmd` | root, or members of the `terraria` group | Same as `attach`. | | `watch` | root, or members of the `terraria` group | Reads the servers' journal only. | | `reinstall` | root (or `terraria`) | | +| `fix-perms` | root only | Checked by the script. | | `mods ` (list) | root, or members of the `terraria` group | | | `mods add/enable/disable/remove` | root (or `terraria`) | Run as root, it sets ownership of the files it installs to `terraria`. | | `delete`, `rename` | root only | Checked by the script. | @@ -837,9 +838,11 @@ Members of the `terraria` group can read server files (useful for backups) but c The helper commands don't leave root-owned files behind, and `mods add` handles mods and ModConfigs. The remaining risk is **copying or creating other files in an instance directory as root**, such as worlds. The server can't write to root-owned files, so saving fails or tModLoader errors. After copying anything in, run: ```bash -sudo chown -R terraria:terraria /var/lib/terraria/instances/ +sudo terractl fix-perms ``` +This gives every file of the instance back to the `terraria` user and resets the modes to what the service creates: the `terraria` group can read everything but change nothing, and other users get no access. Files that were executable stay executable (and the server binaries are made executable again); setuid bits are removed. Symbolic links are left alone, so nothing outside the instance is changed. It's safe while the server is running. + Alternatively, copy files as the `terraria` user to begin with: ```bash @@ -898,7 +901,7 @@ sudo systemctl start terraria@ ``` **The server can't save, or you see "Permission denied" errors.** -Some files are owned by root. Run `sudo chown -R terraria:terraria /var/lib/terraria/instances/`. +Some files are owned by root, or have the wrong modes. Run `sudo terractl fix-perms `. **Players can't join a tModLoader server with a version-mismatch message.** The player's tModLoader version differs from the server's. See [Versions and upgrades](#versions-and-upgrades). @@ -972,6 +975,7 @@ terractl watch [-n ] [-q] Follow the output, read-only ( terractl cmd Send one console command terractl reinstall [--clean] Re-unpack server/ on next start (--clean also re-downloads .NET) +terractl fix-perms Reset the owner and modes of all its files terractl mods [list] Show installed mods terractl mods add ... Install and enable mods (and ModConfigs) terractl mods enable|disable ... Change which mods load diff --git a/lib/terractl-remote b/lib/terractl-remote index 3f61514..40bb8c0 100755 --- a/lib/terractl-remote +++ b/lib/terractl-remote @@ -325,7 +325,7 @@ def host_addresses(listen_host, port): # --------------------------------------------------------------- daemon ---- EXEC_COMMANDS = {"list", "info", "new", "start", "stop", "restart", "enable", "disable", "cmd", "watch", - "mods", "reinstall", "delete", "rename", "export", "import", + "mods", "reinstall", "fix-perms", "delete", "rename", "export", "import", "-V", "--version", "version", "-h", "--help", "help"}