fix(rootless): own the WebUI dir as the container user on fresh install

A fresh rootless install left /docker/containers/libreportal/frontend owned
by the manager (webui_install_image chowned -R to $sudo_user_name) while the
WebUI container and the host-side runFileOp generators run as dockerinstall.
So every generator touch under frontend/data and frontend/logs failed with
'Permission denied' (~27 in the install log). reconcileDockerOwnership chowns
the WebUI dir to the mode's container owner, but only runs on a mode switch,
not on a fresh install.

Extract that WebUI-dir chown into reconcileWebuiDirOwnership (rooted ->
manager, rootless -> the config-authoritative docker install user; runs as
root so it can chown either way) and call it from both reconcileDockerOwnership
and the fresh-install WebUI setup. A fresh install now lands the same
ownership a switch does, so the dockerinstall generators can write.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Signed-off-by: librelad <librelad@digitalangels.vip>
This commit is contained in:
librelad 2026-05-24 13:37:42 +01:00
parent 69d89c9e63
commit d310249ce1
2 changed files with 36 additions and 13 deletions

View File

@ -60,21 +60,45 @@ reconcileDockerOwnership()
# LibrePortal's OWN WebUI container dir is regenerable, so flip it to the
# mode's container owner so the WebUI survives a switch (safe to recurse —
# one UID, no per-app uid to clobber). Third-party app data is left untouched.
# rooted -> the manager (owns everything under /docker in rooted)
# rootless -> the docker install user (owns /docker/containers/**)
local webui_dir="${cdir}libreportal"
if [[ -d "$webui_dir" ]]; then
local app_owner="$owner"
[[ "$mode" == "rootless" ]] && app_owner="$appusr"
runSystem chown -R "$app_owner:$app_owner" "$webui_dir"
isSuccessful "Reconciled WebUI dir ($webui_dir) -> $app_owner"
else
isNotice "reconcileDockerOwnership: WebUI dir '$webui_dir' not found — skipped"
fi
reconcileWebuiDirOwnership "$mode"
isSuccessful "Reconciled ownership for $mode"
}
# Chown LibrePortal's own (regenerable) WebUI container dir to the mode's
# CONTAINER owner, so both the WebUI container and the host-side runFileOp
# generators — which run as that user — can write it:
# rooted -> the manager ($sudo_user_name)
# rootless -> the docker install user, read authoritatively from config (the
# $docker_install_user global is the manager in rooted and so goes
# stale across a switch).
# Recurses (one regenerable UID, no per-app uid to clobber). Must run as root
# (runSystem stays root in both modes). Shared by the switch reconcile and the
# fresh-install WebUI setup so a fresh install gets the same ownership a switch
# does — otherwise rootless generators hit "Permission denied" on a
# manager-owned frontend/data tree.
reconcileWebuiDirOwnership()
{
local mode="${1:-$CFG_DOCKER_INSTALL_TYPE}"
local cdir="${containers_dir:-${docker_dir:-/docker}/containers/}"
local cfgdir="${configs_dir:-${docker_dir:-/docker}/configs/}"
local webui_dir="${cdir}libreportal"
if [[ ! -d "$webui_dir" ]]; then
isNotice "reconcileWebuiDirOwnership: WebUI dir '$webui_dir' not found — skipped"
return 0
fi
local app_owner="${sudo_user_name:-libreportal}"
if [[ "$mode" == "rootless" ]]; then
local appusr
appusr=$(grep -h '^CFG_DOCKER_INSTALL_USER=' "$cfgdir/general/general_docker_install" 2>/dev/null | head -1 | cut -d= -f2 | awk '{print $1}')
app_owner="${appusr:-${CFG_DOCKER_INSTALL_USER:-dockerinstall}}"
fi
runSystem chown -R "$app_owner:$app_owner" "$webui_dir"
isSuccessful "Reconciled WebUI dir ($webui_dir) -> $app_owner"
}
fixFolderPermissions()
{
local silent_flag="$1"

View File

@ -9,8 +9,7 @@ installLibrePortalImageWebUI()
local result=$(copyFolder "$install_containers_dir/libreportal" "$containers_dir" "$sudo_user_name")
checkSuccess "Copy the LibrePortal to the containers folder"
local result=$(sudo chown -R $sudo_user_name:$sudo_user_name $containers_dir/libreportal)
checkSuccess "Setting folder permissions for LibrePortal folders"
reconcileWebuiDirOwnership
isNotice "Building libreportal-service image, this may take a while..."
local result=$(sudo docker build -t libreportal-service -f $containers_dir/libreportal/Dockerfile $containers_dir/libreportal >/dev/null 2>&1)