#!/bin/bash # Mode-aware privileged operations. # # The privilege a file operation needs depends on the Docker mode: # rooted — app/container files under /docker are root-owned, so ops run via # sudo. This is byte-for-byte the historical behaviour. # rootless — those files are owned by the unprivileged Docker install user, so # ops run AS that user (via `sudo -u`, no root over the data plane). # Centralising the branch here means each call site is written once and is # correct in both modes, and rooted installs (incl. live boxes) are unchanged. # Run a /docker data-plane command — mkdir/chown/rm/cp/mv/find/sqlite3/etc. on # app or container files. # rooted -> sudo # rootless -> run as the Docker install user (no sudo) # Note: for stdin-fed writes (e.g. `… | sudo tee file`) use runFileWrite below; # this helper is for self-contained commands. runFileOp() { if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then dockerCommandRunInstallUser --argv "$@" else sudo "$@" fi } # Write stdin to a path with the right privilege (replaces `… | sudo tee path`). # rooted -> sudo tee # rootless -> tee as the Docker install user # Pass -a/--append as the first arg to append instead of truncate (replaces # `… | sudo tee -a path`, e.g. the /docker/logs log-append idiom). # Usage: some_command | runFileWrite [-a] /path/to/file runFileWrite() { local append="" if [[ "$1" == "-a" || "$1" == "--append" ]]; then append=" -a" shift fi local dest="$1" if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then dockerCommandRunInstallUser "tee$append '$dest' >/dev/null" else sudo tee$append "$dest" >/dev/null fi } # Genuine system-administration command (ufw/systemctl/apt/sysctl/useradd, /etc # edits). Needs real root in both modes; kept as sudo and funnelled through one # place so it can later be confined to a scoped sudoers allowlist. runSystem() { sudo "$@" } # Op on a MANAGER-owned path — the LibrePortal clone + shipped templates AND the # /docker management layer the runtime owns (apps DB, configs/, logs/, scripts). # In rootless these are owned by the manager user; ops on them need no privilege. # rooted -> sudo (root-owned; byte-identical) # rootless -> (runs as the current user: root at install-time, # the manager user at runtime — both can access) # Container-owned data under /docker/containers// is NOT this — use runFileOp. # For copies that read manager files and write container-owned ones, read here # and pipe into runFileWrite so each side runs as the correct owner. runInstallOp() { if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then "$@" else sudo "$@" fi } # Write stdin to a MANAGER-owned path (apps DB sidecars, configs/, logs/ — e.g. # the /docker/logs log-append idiom). Mirror of runFileWrite for the manager # owner. Pass -a/--append as the first arg to append. # rooted -> sudo tee # rootless -> tee as the current (manager) user runInstallWrite() { local append="" if [[ "$1" == "-a" || "$1" == "--append" ]]; then append=" -a" shift fi local dest="$1" if [[ "$CFG_DOCKER_INSTALL_TYPE" == "rootless" ]]; then tee$append "$dest" >/dev/null else sudo tee$append "$dest" >/dev/null fi }