backup: create a location's config as the manager, not the container user

backupLocationEnsureDir and the config write both went through runFileOp /
runFileWrite, which run as the container user. Backup location configs live
under the system tree, which is owned by the manager — so the mkdir was denied,
the write then failed with "No such file or directory", and locationAdd still
printed "Location N added".

The result was a location that existed in name only: every later command that
sourced its config found nothing. It surfaced in the first-run restore path,
where the installer adds the location it is about to read from and then fails
with "Backup location 2 has no config".

Use runInstallOp/runInstallWrite, which run as the manager and can write there.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-27 12:15:15 +01:00
parent 1381b052ae
commit f8c9e87643
2 changed files with 21 additions and 8 deletions

View File

@ -56,9 +56,11 @@ locationAdd()
echo "CFG_BACKUP_LOC_${idx}_KEEP_WEEKLY="
echo "CFG_BACKUP_LOC_${idx}_KEEP_MONTHLY="
echo "CFG_BACKUP_LOC_${idx}_KEEP_YEARLY="
} | runFileWrite "$cfg_file" >/dev/null
runFileOp chown "$owner":"$owner" "$cfg_file"
runFileOp chmod 0640 "$cfg_file"
# runInstallWrite/runInstallOp: configs/ is manager-owned, and the container
# user these used to run as cannot write there — the write failed while the
# success message printed anyway.
} | runInstallWrite "$cfg_file" >/dev/null
runInstallOp chmod 0644 "$cfg_file"
if declare -f replacePlainPasswords >/dev/null 2>&1; then
replacePlainPasswords "$cfg_file"

View File

@ -49,16 +49,27 @@ backupLocationOwner()
echo "${docker_install_user:-${sudo_user_name:-libreportal}}"
}
# NOTE: runInstallOp, not runFileOp.
#
# These directories live under configs/, which is MANAGER-owned — runFileOp runs
# as the container user, which cannot even mkdir there. The mkdir failed
# silently, the config write then failed with "No such file or directory", and
# locationAdd still printed "Location N added". So `backup location add` could
# not create a location at all, while reporting that it had.
#
# 0750 rather than 0700: the backup engine runs as the container user via
# runBackupOp and has to traverse in to read location.config. World-readable is
# what location 1 ended up with historically; tightening the config file itself
# needs a root helper action, since the manager cannot chgrp to the container
# user's group (verified: "Operation not permitted"). Tracked in
# docs/roadmap/first-run-restore.md §4.1.
backupLocationEnsureDir()
{
local idx="$1"
local dir
dir=$(backupLocationDir "$idx")
local owner
owner=$(backupLocationOwner)
runFileOp mkdir -p "$dir"
runFileOp chown "$owner":"$owner" "$dir"
runFileOp chmod 0700 "$dir"
runInstallOp mkdir -p "$dir"
runInstallOp chmod 0755 "$dir"
}
backupLocationResolvedPath()