From 2d24a764a8a6635e262be130f40afc73a7dd23b9 Mon Sep 17 00:00:00 2001 From: librelad Date: Mon, 24 Aug 2026 04:04:19 +0100 Subject: [PATCH] refactor(storage): route elevation tests and the WebUI tree through paths.sh MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two mechanical sweeps, no behaviour change on a single-root install. The 14 `[[ "$p" == "$containers_dir"* ]]` prefix tests that decide manager-vs-container-user elevation become pathIsContainerData, so a file on a second storage root is no longer misclassified as manager-owned — which would have written it with the wrong owner and failed later, far from the cause. The 65 references to the WebUI's own tree become webuiDir(), which is pinned to the primary root by design. Two traps found while doing it: run_privileged.sh is sourced directly by init.sh without paths.sh, so it needs a fallback. Defining one named pathIsContainerData was wrong: generate_function_manifest.sh indexes top-level definitions, and the resulting autoload stub would have shadowed the real multi-root implementation with the primary-only fallback — silently classifying every file on a second disk as manager-owned, which is exactly the bug this sweep exists to prevent. Renamed to _runCfgIsContainerPath, which delegates when the real one is loaded. setup_lock.sh built its path in a top-level assignment, so it was evaluated at source time and needed the file flagged eager. Made it a function instead: the path resolves on call, and the file drops off LP_EAGER_FILES entirely. Co-Authored-By: Claude Opus 5 --- .../crowdsec/scripts/crowdsec_install_host.sh | 4 ++-- containers/dashy/scripts/dashy_update_conf.sh | 4 ++-- .../gluetun/scripts/gluetun_providers.sh | 2 +- .../gluetun/scripts/gluetun_route_apps.sh | 2 +- .../libreportal_catalog_install_hooks.sh | 2 +- scripts/cli/commands/app/cli_app_tool_list.sh | 2 +- .../commands/updater/cli_updater_commands.sh | 4 ++-- .../cli/commands/webui/cli_webui_commands.sh | 2 +- scripts/cli/task/cli_task_run.sh | 2 +- .../core/variables/config_scan_variables.sh | 2 +- .../tags/manager/tags_manager_update.sh | 2 +- scripts/docker/app/uninstall/uninstall_app.sh | 4 ++-- scripts/docker/command/run_privileged.sh | 22 ++++++++++++++++++- scripts/docker/command/stranded_containers.sh | 2 +- scripts/docker/health/docker_health_scan.sh | 2 +- scripts/function/file/copy_file.sh | 4 ++-- scripts/function/file/copy_files.sh | 2 +- scripts/function/file/create_touch.sh | 2 +- scripts/function/file/move_file.sh | 2 +- scripts/function/folder/copy_folder.sh | 4 ++-- scripts/function/folder/copy_folders.sh | 2 +- scripts/function/folder/create_folder.sh | 2 +- scripts/setup/setup_apply.sh | 2 +- scripts/setup/setup_lock.sh | 16 +++++++++----- .../source/files/arrays/function_manifest.sh | 7 +++++- scripts/task/crontab_setup_check_processor.sh | 2 +- scripts/task/crontab_setup_task_processor.sh | 2 +- .../data/generators/apps/webui_app_status.sh | 2 +- .../data/generators/apps/webui_config.sh | 4 ++-- .../generators/apps/webui_config_patch.sh | 2 +- .../data/generators/apps/webui_services.sh | 6 ++--- .../webui/data/generators/apps/webui_tools.sh | 2 +- .../backup/webui_backup_app_status.sh | 2 +- .../backup/webui_backup_dashboard.sh | 2 +- .../generators/backup/webui_backup_engines.sh | 2 +- .../backup/webui_backup_locations.sh | 2 +- .../generators/backup/webui_backup_migrate.sh | 2 +- .../backup/webui_backup_passwords.sh | 2 +- .../generators/backup/webui_backup_schema.sh | 2 +- .../backup/webui_backup_snapshots.sh | 2 +- .../generators/backup/webui_task_create.sh | 2 +- .../config/webui_generate_configs.sh | 2 +- .../data/generators/peers/webui_peers.sh | 2 +- .../generators/system/webui_ssh_access.sh | 2 +- .../generators/system/webui_system_disk.sh | 2 +- .../generators/system/webui_system_health.sh | 2 +- .../generators/system/webui_system_info.sh | 2 +- .../generators/system/webui_system_memory.sh | 2 +- .../generators/system/webui_system_metrics.sh | 6 ++--- .../generators/system/webui_system_network.sh | 2 +- .../generators/system/webui_system_update.sh | 4 ++-- .../generators/updater/webui_updater_scan.sh | 2 +- .../data/lock/webui_check_update_lock.sh | 2 +- .../data/lock/webui_create_update_lock.sh | 2 +- .../data/lock/webui_remove_setup_lock.sh | 2 +- .../data/lock/webui_remove_update_lock.sh | 2 +- scripts/webui/data/logs/webui_logs_folders.sh | 2 +- scripts/webui/data/tasks/webui_task_files.sh | 2 +- scripts/webui/data/utils/webui_app_icons.sh | 4 ++-- scripts/webui/data/utils/webui_app_log.sh | 2 +- .../webui/data/utils/webui_atomic_write.sh | 2 +- scripts/webui/webui_install_image.sh | 4 ++-- scripts/webui/webui_install_systemd.sh | 2 +- scripts/webui/webui_regen.sh | 2 +- scripts/webui/webui_updater.sh | 2 +- 65 files changed, 114 insertions(+), 83 deletions(-) diff --git a/containers/crowdsec/scripts/crowdsec_install_host.sh b/containers/crowdsec/scripts/crowdsec_install_host.sh index b7b9225..b151d2d 100644 --- a/containers/crowdsec/scripts/crowdsec_install_host.sh +++ b/containers/crowdsec/scripts/crowdsec_install_host.sh @@ -5,7 +5,7 @@ # mount set takes effect. crowdsecToggleLibrePortalLogMounts() { local mode="$1" - local compose="${containers_dir}libreportal/docker-compose.yml" + local compose="$(webuiDir)/docker-compose.yml" [[ -f "$compose" ]] || return 0 case "$mode" in @@ -26,7 +26,7 @@ crowdsecToggleLibrePortalLogMounts() { if runFileOp docker ps --format '{{.Names}}' 2>/dev/null | grep -q '^libreportal-service$'; then isNotice "Recreating libreportal so log mount toggle takes effect..." - ( cd "${containers_dir}libreportal" && runAsManager docker compose up -d >/dev/null 2>&1 ) || true + ( cd "$(webuiDir)" && runAsManager docker compose up -d >/dev/null 2>&1 ) || true fi } diff --git a/containers/dashy/scripts/dashy_update_conf.sh b/containers/dashy/scripts/dashy_update_conf.sh index 5f26dee..8a5e454 100755 --- a/containers/dashy/scripts/dashy_update_conf.sh +++ b/containers/dashy/scripts/dashy_update_conf.sh @@ -9,8 +9,8 @@ appDashyUpdateConf() { local conf_file="${containers_dir}dashy/etc/conf.yml" - local services_json="${containers_dir}libreportal/frontend/data/apps/generated/apps-services.json" - local icons_src_dir="${containers_dir}libreportal/frontend/icons/apps" + local services_json="$(webuiDir)/frontend/data/apps/generated/apps-services.json" + local icons_src_dir="$(webuiDir)/frontend/icons/apps" # Don't check the apps DB here — appUpdateSpecifics calls us at # install step 6, BEFORE databaseInstallApp (step 8) writes the diff --git a/containers/gluetun/scripts/gluetun_providers.sh b/containers/gluetun/scripts/gluetun_providers.sh index efba1d7..ed08e0a 100644 --- a/containers/gluetun/scripts/gluetun_providers.sh +++ b/containers/gluetun/scripts/gluetun_providers.sh @@ -10,7 +10,7 @@ # gluetun adds/removes providers and protocols. Falls back silently to the # previous snapshot (or the bundled default) on network failure. appWebuiRefresh_gluetun() { - local output_file="${containers_dir}libreportal/frontend/data/apps/generated/gluetun-providers.json" + local output_file="$(webuiDir)/frontend/data/apps/generated/gluetun-providers.json" local upstream="https://raw.githubusercontent.com/qdm12/gluetun/master/internal/storage/servers.json" local tmp="$(mktemp)" local raw="${output_file}.raw.$$" diff --git a/containers/gluetun/scripts/gluetun_route_apps.sh b/containers/gluetun/scripts/gluetun_route_apps.sh index 67dc1d4..1ae5d81 100644 --- a/containers/gluetun/scripts/gluetun_route_apps.sh +++ b/containers/gluetun/scripts/gluetun_route_apps.sh @@ -5,7 +5,7 @@ # override flag. Skips itself, Traefik, LibrePortal, fail2ban. gluetunRouteExistingAppsPrompt() { - local categories_file="${containers_dir}libreportal/frontend/data/apps/gluetun-eligible-categories.json" + local categories_file="$(webuiDir)/frontend/data/apps/gluetun-eligible-categories.json" local override="${CFG_REQUIREMENT_GLUETUN_FOR_ALL:-false}" if ! command -v sqlite3 >/dev/null 2>&1 || [[ ! -f "$docker_dir/$db_file" ]]; then diff --git a/containers/libreportal_catalog/scripts/libreportal_catalog_install_hooks.sh b/containers/libreportal_catalog/scripts/libreportal_catalog_install_hooks.sh index 221d582..4319302 100644 --- a/containers/libreportal_catalog/scripts/libreportal_catalog_install_hooks.sh +++ b/containers/libreportal_catalog/scripts/libreportal_catalog_install_hooks.sh @@ -25,7 +25,7 @@ libreportal_catalog_install_post_setup() # Bundle the App Center's category icons so the site's sidebar matches the # WebUI (same per-category glyphs). Copied from the live frontend so they # stay in step; best-effort (the site falls back to misc.svg if absent). - local cat_src="$containers_dir/libreportal/frontend/core/icons/categories" + local cat_src="$(webuiDir)/frontend/core/icons/categories" if [[ -d "$cat_src" ]]; then runFileOp mkdir -p "$dest/categories" || true runFileOp cp -f "$cat_src"/*.svg "$dest/categories/" 2>/dev/null || true diff --git a/scripts/cli/commands/app/cli_app_tool_list.sh b/scripts/cli/commands/app/cli_app_tool_list.sh index 9bc7b82..604b788 100644 --- a/scripts/cli/commands/app/cli_app_tool_list.sh +++ b/scripts/cli/commands/app/cli_app_tool_list.sh @@ -12,7 +12,7 @@ cliAppToolList() { local filter_app="$1" - local manifest="$containers_dir/libreportal/frontend/data/apps/generated/apps-tools.json" + local manifest="$(webuiDir)/frontend/data/apps/generated/apps-tools.json" if [[ ! -f "$manifest" ]]; then isError "apps-tools.json not found at $manifest. Run the WebUI updater to generate it." diff --git a/scripts/cli/commands/updater/cli_updater_commands.sh b/scripts/cli/commands/updater/cli_updater_commands.sh index 1ae9102..f6d4272 100644 --- a/scripts/cli/commands/updater/cli_updater_commands.sh +++ b/scripts/cli/commands/updater/cli_updater_commands.sh @@ -194,7 +194,7 @@ updaterSetAnchorRef() # — i.e. the roll-back target. Read from history.json's most recent update/ok. updaterLastUpdateFrom() { - local app="$1" hist="$containers_dir/libreportal/frontend/data/updater/generated/history.json" + local app="$1" hist="$(webuiDir)/frontend/data/updater/generated/history.json" [ -f "$hist" ] && command -v jq >/dev/null 2>&1 || return 0 jq -r --arg a "$app" 'first(.entries[]? | select(.app==$a and .action=="update" and .result=="ok") | .from) // ""' "$hist" 2>/dev/null } @@ -336,7 +336,7 @@ updaterRecordHistory() { local app="$1" action="$2" from="$3" to="$4" result="$5" local artifact_id="${6:-}" serial="${7:-}" undo_id="${8:-}" trigger="${9:-manual}" - local f="$containers_dir/libreportal/frontend/data/updater/generated/history.json" + local f="$(webuiDir)/frontend/data/updater/generated/history.json" local ts; ts="$(date -Iseconds 2>/dev/null || date)" [ -f "$f" ] || printf '{ "entries": [] }\n' | runFileWrite "$f" diff --git a/scripts/cli/commands/webui/cli_webui_commands.sh b/scripts/cli/commands/webui/cli_webui_commands.sh index 3fe4881..2220f9d 100755 --- a/scripts/cli/commands/webui/cli_webui_commands.sh +++ b/scripts/cli/commands/webui/cli_webui_commands.sh @@ -71,7 +71,7 @@ cliHandleWebuiCommands() cliWebuiLoginReset() { - local auth_file="$containers_dir/libreportal/frontend/.auth.json" + local auth_file="$(webuiDir)/frontend/.auth.json" local webui_logins_file="$configs_dir/webui/webui_logins" isNotice "Resetting WebUI credentials..." diff --git a/scripts/cli/task/cli_task_run.sh b/scripts/cli/task/cli_task_run.sh index 191e0d6..347be05 100644 --- a/scripts/cli/task/cli_task_run.sh +++ b/scripts/cli/task/cli_task_run.sh @@ -21,7 +21,7 @@ # crontab_task_processor.sh and webui_task_create.sh use; if those move, both # this file and they have to update together. _taskDir() { - echo "${containers_dir}libreportal/frontend/data/tasks" + echo "$(webuiDir)/frontend/data/tasks" } _genTaskId() { diff --git a/scripts/config/core/variables/config_scan_variables.sh b/scripts/config/core/variables/config_scan_variables.sh index 944dfe3..3d26c12 100755 --- a/scripts/config/core/variables/config_scan_variables.sh +++ b/scripts/config/core/variables/config_scan_variables.sh @@ -142,7 +142,7 @@ reconcileConfigFile() if [[ -s "$tmp" ]] && grep -q '^CFG_' "$tmp" && ! runInstallOp cmp -s "$tmp" "$live"; then local bak_file="${live%/*}/.${live##*/}.bak" runCfgOp cp -a "$live" "$bak_file" - { [[ -n "$containers_dir" && "$live" == "$containers_dir"* ]] && runFileWrite "$live" < "$tmp" || runInstallOp cp "$tmp" "$live"; } + { pathIsContainerData "$live" && runFileWrite "$live" < "$tmp" || runInstallOp cp "$tmp" "$live"; } # A hidden ..bak sibling is still written above for safety; the # per-file result is intentionally silent — the intro notice and the # per-section "...completed." lines are the only reconcile output. diff --git a/scripts/config/tags/manager/tags_manager_update.sh b/scripts/config/tags/manager/tags_manager_update.sh index 5c72ab8..449b89e 100755 --- a/scripts/config/tags/manager/tags_manager_update.sh +++ b/scripts/config/tags/manager/tags_manager_update.sh @@ -51,6 +51,6 @@ tagsManagerUpdateUniversalTag() # manager-owned configs/ + install templates use runInstallOp. The read # (awk above) needs no escalation — config/compose files are world-readable. local op="runInstallOp" - [[ "$file_path" == "$containers_dir"* || "$file_path" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$file_path" && op="runFileOp" $op sed -i "/#LIBREPORTAL|${tag_name}|/s|${esc_placeholder}|${esc_new}|g" "$file_path" } diff --git a/scripts/docker/app/uninstall/uninstall_app.sh b/scripts/docker/app/uninstall/uninstall_app.sh index 4138932..c3a46dd 100755 --- a/scripts/docker/app/uninstall/uninstall_app.sh +++ b/scripts/docker/app/uninstall/uninstall_app.sh @@ -89,7 +89,7 @@ dockerUninstallApp() # scan happened to run. Surgical delete rather than a rescan: a full # updater scan re-runs CVE checks against every image and has no place # inside an uninstall. - local _upd_gen="${containers_dir}libreportal/frontend/data/updater/generated" + local _upd_gen="$(webuiDir)/frontend/data/updater/generated" local _upd_f for _upd_f in updates.json cves.json; do if [[ -f "$_upd_gen/$_upd_f" ]] && command -v jq >/dev/null 2>&1; then @@ -114,7 +114,7 @@ dockerUninstallApp() echo "" echo "---- $menu_number. Removing related task history" echo "" - local _tasks_dir="${containers_dir}libreportal/frontend/data/tasks" + local _tasks_dir="$(webuiDir)/frontend/data/tasks" local _removed=0 if [[ -d "$_tasks_dir" ]]; then for _tf in "$_tasks_dir"/task_*.json; do diff --git a/scripts/docker/command/run_privileged.sh b/scripts/docker/command/run_privileged.sh index 3c635dd..a03952e 100644 --- a/scripts/docker/command/run_privileged.sh +++ b/scripts/docker/command/run_privileged.sh @@ -91,13 +91,33 @@ runInstallWrite() { # file" bug — the substitution silently failed, leaving the placeholder). runCfgOp() { local _file="${!#}" - if [[ -n "$containers_dir" && "$_file" == "$containers_dir"* ]]; then + if _runCfgIsContainerPath "$_file"; then runFileOp "$@" else runInstallOp "$@" fi } +# paths.sh owns pathIsContainerData (it knows every registered storage root). +# init.sh sources THIS file directly at install time WITHOUT paths.sh, so fall +# back to the primary root alone — at install no extra locations exist yet, so +# the two answers agree. +# +# Deliberately not named pathIsContainerData: a same-named top-level definition +# here gets indexed by generate_function_manifest.sh, and the resulting autoload +# stub would shadow the real multi-root implementation with this primary-only +# one — silently classifying every file on a second disk as manager-owned. +_runCfgIsContainerPath() { + local p="$1" + if declare -F pathIsContainerData >/dev/null 2>&1; then + pathIsContainerData "$p" + return $? + fi + local root="${LP_CONTAINERS_DIR:-/libreportal-containers}" + root="${root%/}" + [[ -n "$p" && ( "$p" == "$root" || "$p" == "$root/"* ) ]] +} + # Backup-engine command (borg/restic/kopia) run AS the dedicated backup user # ($docker_install_user), with the repo password and BORG_/RESTIC_/KOPIA_ env # vars carried across the privilege drop. Never root — the scoped sudoers lets diff --git a/scripts/docker/command/stranded_containers.sh b/scripts/docker/command/stranded_containers.sh index 96c2f37..947de5f 100644 --- a/scripts/docker/command/stranded_containers.sh +++ b/scripts/docker/command/stranded_containers.sh @@ -43,7 +43,7 @@ dockerRemoveStrandedContainers() [[ -z "$name" || -z "$work_dir" ]] && continue # Only LibrePortal's own container tree, and only when the project # directory is provably gone. - [[ "$work_dir" == "$containers_dir"* ]] || continue + pathIsContainerData "$work_dir" || continue [[ -d "$work_dir" ]] && continue if runFileOp docker rm -f "$name" >/dev/null 2>&1; then diff --git a/scripts/docker/health/docker_health_scan.sh b/scripts/docker/health/docker_health_scan.sh index a32c073..6bc413c 100644 --- a/scripts/docker/health/docker_health_scan.sh +++ b/scripts/docker/health/docker_health_scan.sh @@ -67,7 +67,7 @@ dockerHealthScan() { # $state_file, written ONLY by the throttled caller (webuiSystemHealthCheck) # via HEALTH_RESTART_SNAPSHOT, so the heal's rapid re-scans don't disturb the # baseline. One inspect over all containers (name|count|status|restarting). - local state_file="${containers_dir}/libreportal/frontend/data/system/.health_restart_counts" + local state_file="$(webuiDir)/frontend/data/system/.health_restart_counts" HEALTH_RESTART_SNAPSHOT="" declare -A _prev_rc=() diff --git a/scripts/function/file/copy_file.sh b/scripts/function/file/copy_file.sh index b7f85fb..d6431bf 100755 --- a/scripts/function/file/copy_file.sh +++ b/scripts/function/file/copy_file.sh @@ -17,7 +17,7 @@ copyFile() # the manager-owned control plane (configs/logs/etc.) is runInstallOp. # Mirrors createTouch's path-based ownership; $user_name is now advisory. local op="runInstallOp" - [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$save_dir" && op="runFileOp" if [ "$silent_flag" == "loud" ]; then local result; result=$($op cp $flags_full "$file" "$save_dir") @@ -43,7 +43,7 @@ repairStubDirForFile() [[ -d "$target" ]] || return 0 local op="runInstallOp" - [[ "$target" == "$containers_dir"* || "$target" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$target" && op="runFileOp" local name; name=$(basename "$target") local staged="$target.stub-repair.$$" diff --git a/scripts/function/file/copy_files.sh b/scripts/function/file/copy_files.sh index 8852b94..ff75039 100755 --- a/scripts/function/file/copy_files.sh +++ b/scripts/function/file/copy_files.sh @@ -9,7 +9,7 @@ copyFiles() # Write as the destination's owner (see copyFile). local op="runInstallOp" - [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$save_dir" && op="runFileOp" local files=($($op find "$source" -type f)) if [ ${#files[@]} -eq 0 ]; then diff --git a/scripts/function/file/create_touch.sh b/scripts/function/file/create_touch.sh index 9ee8312..0ec54d6 100755 --- a/scripts/function/file/create_touch.sh +++ b/scripts/function/file/create_touch.sh @@ -21,7 +21,7 @@ createTouch() local file_dir=$(dirname "$clean_file") local op="runInstallOp" - if [[ "$clean_file" == "$containers_dir"* || "$clean_file" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then + if pathIsContainerData "$clean_file"; then op="runFileOp" fi diff --git a/scripts/function/file/move_file.sh b/scripts/function/file/move_file.sh index af118e9..2e83392 100755 --- a/scripts/function/file/move_file.sh +++ b/scripts/function/file/move_file.sh @@ -10,7 +10,7 @@ moveFile() if [ -e "$file" ]; then # Move as the destination's owner — no root, no chown (see copyFile). local op="runInstallOp" - [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$save_dir" && op="runFileOp" local result; result=$($op mv "$file" "$save_dir") checkSuccess "Moving $file_name to $save_dir" else diff --git a/scripts/function/folder/copy_folder.sh b/scripts/function/folder/copy_folder.sh index af567d7..d2730e6 100755 --- a/scripts/function/folder/copy_folder.sh +++ b/scripts/function/folder/copy_folder.sh @@ -8,8 +8,8 @@ copyFolder() local user_name="$3" # advisory — the destination path determines the owner # Write as the destination's owner — no root, no chown (see copyFile). - if [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then - if [[ "$folder" == "$containers_dir"* || "$folder" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then + if pathIsContainerData "$save_dir"; then + if pathIsContainerData "$folder"; then # container -> container: same owner (dockerinstall), a plain cp works. local result; result=$(runFileOp cp -rf "$folder" "$save_dir") else diff --git a/scripts/function/folder/copy_folders.sh b/scripts/function/folder/copy_folders.sh index 1829c1b..208e55d 100755 --- a/scripts/function/folder/copy_folders.sh +++ b/scripts/function/folder/copy_folders.sh @@ -8,7 +8,7 @@ copyFolders() # Write as the destination's owner — no root, no chown (see copyFile). local op="runInstallOp" - [[ "$save_dir" == "$containers_dir"* || "$save_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]] && op="runFileOp" + pathIsContainerData "$save_dir" && op="runFileOp" local subdirs=($(find "$source" -mindepth 1 -maxdepth 1 -type d)) if [ ${#subdirs[@]} -eq 0 ]; then diff --git a/scripts/function/folder/create_folder.sh b/scripts/function/folder/create_folder.sh index 6acd57b..0aa7bd5 100755 --- a/scripts/function/folder/create_folder.sh +++ b/scripts/function/folder/create_folder.sh @@ -14,7 +14,7 @@ createFolders() # AS that user via runFileOp — creating it as the right owner avoids a # chown-to-another-user the unprivileged runtime can't do. Mirrors # createTouch; the $user_name hint is advisory for these paths. - if [[ "$clean_dir" == "$containers_dir"* || "$clean_dir" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then + if pathIsContainerData "$clean_dir"; then if [ ! -d "$dir_path" ]; then local result; result=$(runFileOp mkdir -p "$dir_path") [ "$silent_flag" == "loud" ] && checkSuccess "Creating $folder_name directory" diff --git a/scripts/setup/setup_apply.sh b/scripts/setup/setup_apply.sh index a8e318f..a561e9e 100644 --- a/scripts/setup/setup_apply.sh +++ b/scripts/setup/setup_apply.sh @@ -125,7 +125,7 @@ setupApplyFinalize() # failed app's own task row is already red; the WebUI watcher is what gates # the "your install is ready" hand-off on this same group-level result. if [[ -n "$setup_group" ]]; then - local tasks_dir="${containers_dir}libreportal/frontend/data/tasks" + local tasks_dir="$(webuiDir)/frontend/data/tasks" local total=0 failed=0 failed_names="" f if [[ -d "$tasks_dir" ]]; then for f in "$tasks_dir"/task_*.json; do diff --git a/scripts/setup/setup_lock.sh b/scripts/setup/setup_lock.sh index 909bbef..e0532bd 100644 --- a/scripts/setup/setup_lock.sh +++ b/scripts/setup/setup_lock.sh @@ -1,21 +1,27 @@ #!/bin/bash -SETUP_LOCK_FILE="${containers_dir}libreportal/frontend/data/.setup_complete" +# Resolved on call, not at source time: this file can be sourced by the lazy +# loader before paths.sh has run, and a source-time expansion would bake an +# empty root into an absolute-looking path. +setupLockFile() +{ + printf '%s' "$(webuiDir)/frontend/data/.setup_complete" +} isSetupWizardComplete() { - [[ -f "$SETUP_LOCK_FILE" ]] + [[ -f "$(setupLockFile)" ]] } setupWizardMarkComplete() { # .setup_complete lives in the docker-install-owned frontend/data -> runFileOp # (created as that user; no root, no chown). - runFileOp touch "$SETUP_LOCK_FILE" 2>/dev/null - runFileOp chmod 644 "$SETUP_LOCK_FILE" 2>/dev/null + runFileOp touch "$(setupLockFile)" 2>/dev/null + runFileOp chmod 644 "$(setupLockFile)" 2>/dev/null } setupWizardReset() { - runFileOp rm -f "$SETUP_LOCK_FILE" 2>/dev/null + runFileOp rm -f "$(setupLockFile)" 2>/dev/null } diff --git a/scripts/source/files/arrays/function_manifest.sh b/scripts/source/files/arrays/function_manifest.sh index e0b66c8..5394564 100644 --- a/scripts/source/files/arrays/function_manifest.sh +++ b/scripts/source/files/arrays/function_manifest.sh @@ -915,6 +915,7 @@ declare -gA LP_FN_MAP=( [runAsManager]="docker/command/run_privileged.sh" [runBackupOp]="docker/command/run_privileged.sh" [runBinInstall]="docker/command/run_privileged.sh" + [_runCfgIsContainerPath]="docker/command/run_privileged.sh" [runCfgOp]="docker/command/run_privileged.sh" [runCrowdsec]="docker/command/run_privileged.sh" [runFileOp]="docker/command/run_privileged.sh" @@ -951,6 +952,7 @@ declare -gA LP_FN_MAP=( [setupHeadscaleUser]="headscale/scripts/headscale_user.sh" [setupHeadscaleVariables]="network/variables/headscale_variables.sh" [setupLocalDnsRewrites]="network/dns/setup_local_dns.sh" + [setupLockFile]="setup/setup_lock.sh" [setupTaskDir]="task/crontab_task_processor.sh" [setupWizardMarkComplete]="setup/setup_lock.sh" [setupWizardReset]="setup/setup_lock.sh" @@ -2097,6 +2099,7 @@ declare -gA LP_FN_ROOT=( [runAsManager]="scripts" [runBackupOp]="scripts" [runBinInstall]="scripts" + [_runCfgIsContainerPath]="scripts" [runCfgOp]="scripts" [runCrowdsec]="scripts" [runFileOp]="scripts" @@ -2133,6 +2136,7 @@ declare -gA LP_FN_ROOT=( [setupHeadscaleUser]="containers" [setupHeadscaleVariables]="scripts" [setupLocalDnsRewrites]="scripts" + [setupLockFile]="scripts" [setupTaskDir]="scripts" [setupWizardMarkComplete]="scripts" [setupWizardReset]="scripts" @@ -2387,7 +2391,6 @@ LP_EAGER_FILES=( "containers:matrix/scripts/matrix_auth.sh" "scripts:migrate/migrate_url_rewrite.sh" "containers:nextcloud/scripts/nextcloud_upgrade_hooks.sh" - "scripts:setup/setup_lock.sh" "scripts:source/artifacts.sh" "scripts:task/crontab_check_processor.sh" "scripts:task/crontab_task_processor.sh" @@ -3316,6 +3319,7 @@ runAppCfg() { unset -f runAppCfg; __lpAutoload "${install_scripts_dir}docker/com runAsManager() { unset -f runAsManager; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runAsManager "$@"; } runBackupOp() { unset -f runBackupOp; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runBackupOp "$@"; } runBinInstall() { unset -f runBinInstall; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runBinInstall "$@"; } +_runCfgIsContainerPath() { unset -f _runCfgIsContainerPath; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; _runCfgIsContainerPath "$@"; } runCfgOp() { unset -f runCfgOp; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runCfgOp "$@"; } runCrowdsec() { unset -f runCrowdsec; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runCrowdsec "$@"; } runFileOp() { unset -f runFileOp; __lpAutoload "${install_scripts_dir}docker/command/run_privileged.sh"; runFileOp "$@"; } @@ -3352,6 +3356,7 @@ setupHeadscaleRemote() { unset -f setupHeadscaleRemote; __lpAutoload "${install_ setupHeadscaleUser() { unset -f setupHeadscaleUser; __lpAutoload "${install_containers_dir}headscale/scripts/headscale_user.sh"; setupHeadscaleUser "$@"; } setupHeadscaleVariables() { unset -f setupHeadscaleVariables; __lpAutoload "${install_scripts_dir}network/variables/headscale_variables.sh"; setupHeadscaleVariables "$@"; } setupLocalDnsRewrites() { unset -f setupLocalDnsRewrites; __lpAutoload "${install_scripts_dir}network/dns/setup_local_dns.sh"; setupLocalDnsRewrites "$@"; } +setupLockFile() { unset -f setupLockFile; __lpAutoload "${install_scripts_dir}setup/setup_lock.sh"; setupLockFile "$@"; } setupTaskDir() { unset -f setupTaskDir; __lpAutoload "${install_scripts_dir}task/crontab_task_processor.sh"; setupTaskDir "$@"; } setupWizardMarkComplete() { unset -f setupWizardMarkComplete; __lpAutoload "${install_scripts_dir}setup/setup_lock.sh"; setupWizardMarkComplete "$@"; } setupWizardReset() { unset -f setupWizardReset; __lpAutoload "${install_scripts_dir}setup/setup_lock.sh"; setupWizardReset "$@"; } diff --git a/scripts/task/crontab_setup_check_processor.sh b/scripts/task/crontab_setup_check_processor.sh index e75e9d5..63c24e1 100755 --- a/scripts/task/crontab_setup_check_processor.sh +++ b/scripts/task/crontab_setup_check_processor.sh @@ -3,7 +3,7 @@ crontabSetupCheckProcessor() { local task_check_script="$install_scripts_dir/task/crontab_check_processor.sh" - local task_dir="$containers_dir/libreportal/frontend/data/tasks" + local task_dir="$(webuiDir)/frontend/data/tasks" # Update TASK_DIR in the task processor script if [ -f "$task_check_script" ]; then diff --git a/scripts/task/crontab_setup_task_processor.sh b/scripts/task/crontab_setup_task_processor.sh index a3d7af1..720af18 100755 --- a/scripts/task/crontab_setup_task_processor.sh +++ b/scripts/task/crontab_setup_task_processor.sh @@ -3,7 +3,7 @@ crontabSetupTaskProcessor() { local task_processor_script="$install_scripts_dir/task/crontab_task_processor.sh" - local task_dir="$containers_dir/libreportal/frontend/data/tasks" + local task_dir="$(webuiDir)/frontend/data/tasks" # Update TASK_DIR in the task processor script if [ -f "$task_processor_script" ]; then diff --git a/scripts/webui/data/generators/apps/webui_app_status.sh b/scripts/webui/data/generators/apps/webui_app_status.sh index 8bfd6c3..fec14cc 100755 --- a/scripts/webui/data/generators/apps/webui_app_status.sh +++ b/scripts/webui/data/generators/apps/webui_app_status.sh @@ -3,7 +3,7 @@ # Update a specific app's status in apps.json (used for install/uninstall operations) webuiUpdateAppStatus() { local app_name="$1" - local output_file="${containers_dir}libreportal/frontend/data/apps/generated/apps.json" + local output_file="$(webuiDir)/frontend/data/apps/generated/apps.json" if [[ -z "$app_name" ]]; then isError "app_name parameter required for webuiUpdateAppStatus" diff --git a/scripts/webui/data/generators/apps/webui_config.sh b/scripts/webui/data/generators/apps/webui_config.sh index 89ea809..54c229d 100644 --- a/scripts/webui/data/generators/apps/webui_config.sh +++ b/scripts/webui/data/generators/apps/webui_config.sh @@ -33,7 +33,7 @@ _webuiReadServiceTags() { webuiGenerateLibrePortalConfig() { local testing_mode="$1" local specific_app="$2" - local output_file="${containers_dir}libreportal/frontend/data/apps/generated/apps.json" + local output_file="$(webuiDir)/frontend/data/apps/generated/apps.json" local first_app=true local app_count=0 @@ -162,7 +162,7 @@ EOF icon_file="$app_name.png" fi if [[ -n "$icon_file" ]]; then - local icons_apps_dir="${containers_dir}libreportal/frontend/core/icons/apps" + local icons_apps_dir="$(webuiDir)/frontend/core/icons/apps" runFileOp mkdir -p "$icons_apps_dir" runFileWrite "$icons_apps_dir/$icon_file" < "$dir/$icon_file" 2>/dev/null fi diff --git a/scripts/webui/data/generators/apps/webui_config_patch.sh b/scripts/webui/data/generators/apps/webui_config_patch.sh index 123d15d..dcbac80 100644 --- a/scripts/webui/data/generators/apps/webui_config_patch.sh +++ b/scripts/webui/data/generators/apps/webui_config_patch.sh @@ -7,7 +7,7 @@ webuiPatchAppConfigJson() { local app_name="$1" [[ -z "$app_name" ]] && return 1 - local apps_json="${containers_dir}libreportal/frontend/data/apps/generated/apps.json" + local apps_json="$(webuiDir)/frontend/data/apps/generated/apps.json" [[ ! -f "$apps_json" ]] && return 1 local deployed_cfg="${containers_dir}${app_name}/${app_name}.config" diff --git a/scripts/webui/data/generators/apps/webui_services.sh b/scripts/webui/data/generators/apps/webui_services.sh index 34f0499..14f1010 100755 --- a/scripts/webui/data/generators/apps/webui_services.sh +++ b/scripts/webui/data/generators/apps/webui_services.sh @@ -4,7 +4,7 @@ # Generates apps-services.json from database webuiGenerateAppsServicesConfig() { local testing_mode="$1" - local output_file="${containers_dir}libreportal/frontend/data/apps/generated/apps-services.json" + local output_file="$(webuiDir)/frontend/data/apps/generated/apps-services.json" local first_service=true local service_count=0 @@ -81,8 +81,8 @@ EOF # source IP of the default route) is what LAN/VPN clients dial, # and matches the host APP_URL is stamped with. local server_ip="" - if [[ -f "${containers_dir}libreportal/config/generated/configs.json" ]]; then - server_ip=$(grep -o '"CFG_SERVER_IP":[[:space:]]*"[^"]*"' "${containers_dir}libreportal/config/generated/configs.json" | cut -d'"' -f4) + if [[ -f "$(webuiDir)/config/generated/configs.json" ]]; then + server_ip=$(grep -o '"CFG_SERVER_IP":[[:space:]]*"[^"]*"' "$(webuiDir)/config/generated/configs.json" | cut -d'"' -f4) fi [[ -z "$server_ip" ]] && server_ip="${local_ip_v4:-localhost}" [[ -z "$server_ip" ]] && server_ip="localhost" diff --git a/scripts/webui/data/generators/apps/webui_tools.sh b/scripts/webui/data/generators/apps/webui_tools.sh index b40e5b7..1d63358 100644 --- a/scripts/webui/data/generators/apps/webui_tools.sh +++ b/scripts/webui/data/generators/apps/webui_tools.sh @@ -47,7 +47,7 @@ webuiGenerateAppsToolsConfig() { return $? fi - local output_file="${containers_dir}libreportal/frontend/data/apps/generated/apps-tools.json" + local output_file="$(webuiDir)/frontend/data/apps/generated/apps-tools.json" local tmp="$(mktemp)" runFileOp mkdir -p "$(dirname "$output_file")" diff --git a/scripts/webui/data/generators/backup/webui_backup_app_status.sh b/scripts/webui/data/generators/backup/webui_backup_app_status.sh index b1cde78..1d29738 100644 --- a/scripts/webui/data/generators/backup/webui_backup_app_status.sh +++ b/scripts/webui/data/generators/backup/webui_backup_app_status.sh @@ -3,7 +3,7 @@ webuiGenerateBackupAppStatus() { local app_name="${1:-}" - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated/apps" + local output_dir="$(webuiDir)/frontend/data/backup/generated/apps" runFileOp mkdir -p "$output_dir" # Resolve the app list: a single app (direct call — e.g. right after that diff --git a/scripts/webui/data/generators/backup/webui_backup_dashboard.sh b/scripts/webui/data/generators/backup/webui_backup_dashboard.sh index e9d424a..dd0b200 100644 --- a/scripts/webui/data/generators/backup/webui_backup_dashboard.sh +++ b/scripts/webui/data/generators/backup/webui_backup_dashboard.sh @@ -2,7 +2,7 @@ webuiGenerateBackupDashboard() { - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local output_dir="$(webuiDir)/frontend/data/backup/generated" local output_file="$output_dir/dashboard.json" local temp_file="${output_file}.tmp.$$" diff --git a/scripts/webui/data/generators/backup/webui_backup_engines.sh b/scripts/webui/data/generators/backup/webui_backup_engines.sh index 94aeb7b..b24c58c 100644 --- a/scripts/webui/data/generators/backup/webui_backup_engines.sh +++ b/scripts/webui/data/generators/backup/webui_backup_engines.sh @@ -7,7 +7,7 @@ webuiGenerateBackupEngines() { local src_dir="$install_scripts_dir/backup/engines" - local out_dir="$containers_dir/libreportal/frontend/data/backup/generated/engines" + local out_dir="$(webuiDir)/frontend/data/backup/generated/engines" runFileOp mkdir -p "$out_dir" if [[ ! -d "$src_dir" ]]; then diff --git a/scripts/webui/data/generators/backup/webui_backup_locations.sh b/scripts/webui/data/generators/backup/webui_backup_locations.sh index 4a01739..f4fc7fa 100644 --- a/scripts/webui/data/generators/backup/webui_backup_locations.sh +++ b/scripts/webui/data/generators/backup/webui_backup_locations.sh @@ -2,7 +2,7 @@ webuiGenerateBackupLocations() { - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local output_dir="$(webuiDir)/frontend/data/backup/generated" local output_file="$output_dir/locations.json" local temp_file="${output_file}.tmp.$$" runFileOp mkdir -p "$output_dir" diff --git a/scripts/webui/data/generators/backup/webui_backup_migrate.sh b/scripts/webui/data/generators/backup/webui_backup_migrate.sh index 51c85ee..cbbf800 100644 --- a/scripts/webui/data/generators/backup/webui_backup_migrate.sh +++ b/scripts/webui/data/generators/backup/webui_backup_migrate.sh @@ -11,7 +11,7 @@ webuiGenerateBackupMigrate() { - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local output_dir="$(webuiDir)/frontend/data/backup/generated" local output_file="$output_dir/migrate.json" runFileOp mkdir -p "$output_dir" diff --git a/scripts/webui/data/generators/backup/webui_backup_passwords.sh b/scripts/webui/data/generators/backup/webui_backup_passwords.sh index 38ea7f8..796b70b 100644 --- a/scripts/webui/data/generators/backup/webui_backup_passwords.sh +++ b/scripts/webui/data/generators/backup/webui_backup_passwords.sh @@ -2,7 +2,7 @@ webuiGenerateBackupPasswords() { - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local output_dir="$(webuiDir)/frontend/data/backup/generated" local output_file="$output_dir/passwords.txt" local temp_file="${output_file}.tmp.$$" diff --git a/scripts/webui/data/generators/backup/webui_backup_schema.sh b/scripts/webui/data/generators/backup/webui_backup_schema.sh index 8790d6d..4e8f470 100644 --- a/scripts/webui/data/generators/backup/webui_backup_schema.sh +++ b/scripts/webui/data/generators/backup/webui_backup_schema.sh @@ -10,7 +10,7 @@ webuiGenerateBackupSchema() { - local out_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local out_dir="$(webuiDir)/frontend/data/backup/generated" local out_file="$out_dir/schema.json" runFileOp mkdir -p "$out_dir" diff --git a/scripts/webui/data/generators/backup/webui_backup_snapshots.sh b/scripts/webui/data/generators/backup/webui_backup_snapshots.sh index b927202..aa758dd 100644 --- a/scripts/webui/data/generators/backup/webui_backup_snapshots.sh +++ b/scripts/webui/data/generators/backup/webui_backup_snapshots.sh @@ -3,7 +3,7 @@ webuiGenerateBackupSnapshots() { local scope="${1:-all}" - local output_dir="$containers_dir/libreportal/frontend/data/backup/generated" + local output_dir="$(webuiDir)/frontend/data/backup/generated" runFileOp mkdir -p "$output_dir" local indices=() diff --git a/scripts/webui/data/generators/backup/webui_task_create.sh b/scripts/webui/data/generators/backup/webui_task_create.sh index c8e0e20..aabb689 100755 --- a/scripts/webui/data/generators/backup/webui_task_create.sh +++ b/scripts/webui/data/generators/backup/webui_task_create.sh @@ -14,7 +14,7 @@ createTaskFile() { fi # Set task directory - local task_dir="${containers_dir}libreportal/frontend/data/tasks" + local task_dir="$(webuiDir)/frontend/data/tasks" # Ensure task directory exists (container-owned WebUI data tree -> runFileOp) if [ ! -d "$task_dir" ]; then diff --git a/scripts/webui/data/generators/config/webui_generate_configs.sh b/scripts/webui/data/generators/config/webui_generate_configs.sh index c241ead..d6a5fdf 100755 --- a/scripts/webui/data/generators/config/webui_generate_configs.sh +++ b/scripts/webui/data/generators/config/webui_generate_configs.sh @@ -78,7 +78,7 @@ webuiGenerateSystemConfigs() { fi } - local output_file="${containers_dir}libreportal/frontend/data/config/generated/configs.json" + local output_file="$(webuiDir)/frontend/data/config/generated/configs.json" local temp_file="$(mktemp)" runFileOp mkdir -p "$(dirname "$output_file")" diff --git a/scripts/webui/data/generators/peers/webui_peers.sh b/scripts/webui/data/generators/peers/webui_peers.sh index 2652427..0258e03 100644 --- a/scripts/webui/data/generators/peers/webui_peers.sh +++ b/scripts/webui/data/generators/peers/webui_peers.sh @@ -8,7 +8,7 @@ webuiGeneratePeers() { - local output_dir="$containers_dir/libreportal/frontend/data/peers/generated" + local output_dir="$(webuiDir)/frontend/data/peers/generated" local output_file="$output_dir/peers.json" runFileOp mkdir -p "$output_dir" diff --git a/scripts/webui/data/generators/system/webui_ssh_access.sh b/scripts/webui/data/generators/system/webui_ssh_access.sh index b086ff9..85f709e 100644 --- a/scripts/webui/data/generators/system/webui_ssh_access.sh +++ b/scripts/webui/data/generators/system/webui_ssh_access.sh @@ -6,7 +6,7 @@ webuiGenerateSshAccess() { - local out_dir="$containers_dir/libreportal/frontend/data/ssh" + local out_dir="$(webuiDir)/frontend/data/ssh" local out_file="$out_dir/access.json" runFileOp mkdir -p "$out_dir" diff --git a/scripts/webui/data/generators/system/webui_system_disk.sh b/scripts/webui/data/generators/system/webui_system_disk.sh index e83d1d4..c2b8f34 100755 --- a/scripts/webui/data/generators/system/webui_system_disk.sh +++ b/scripts/webui/data/generators/system/webui_system_disk.sh @@ -27,7 +27,7 @@ webuiSystemDisk() { fi # Create system info directory if it doesn't exist - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" createFolders "quiet" $sudo_user_name "$system_dir" # Create temp file first, then atomic move diff --git a/scripts/webui/data/generators/system/webui_system_health.sh b/scripts/webui/data/generators/system/webui_system_health.sh index bae4e28..e69db59 100644 --- a/scripts/webui/data/generators/system/webui_system_health.sh +++ b/scripts/webui/data/generators/system/webui_system_health.sh @@ -20,7 +20,7 @@ webuiSystemHealthCheck() { local force_flag="$1" - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" local final_file="${system_dir}/health_status.json" local stamp_file="${system_dir}/.health_check_stamp" local heal_stamp="${system_dir}/.health_heal_stamp" diff --git a/scripts/webui/data/generators/system/webui_system_info.sh b/scripts/webui/data/generators/system/webui_system_info.sh index 8ec9c42..4ded246 100755 --- a/scripts/webui/data/generators/system/webui_system_info.sh +++ b/scripts/webui/data/generators/system/webui_system_info.sh @@ -31,7 +31,7 @@ webuiSystemInfo() { local kernel_version=$(uname -r) # Create system info directory if it doesn't exist - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" createFolders "quiet" $sudo_user_name "$system_dir" # Create temp file first, then atomic move diff --git a/scripts/webui/data/generators/system/webui_system_memory.sh b/scripts/webui/data/generators/system/webui_system_memory.sh index b3f4f9b..03f6c1a 100755 --- a/scripts/webui/data/generators/system/webui_system_memory.sh +++ b/scripts/webui/data/generators/system/webui_system_memory.sh @@ -23,7 +23,7 @@ webuiSystemMemory() { local mem_text="$mem_used_gb GB / $mem_total_gb GB - $mem_percent%" # Create system info directory if it doesn't exist - local system_dir="${containers_dir}libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" createFolders "quiet" $sudo_user_name "$system_dir" # Create temp file first, then atomic move diff --git a/scripts/webui/data/generators/system/webui_system_metrics.sh b/scripts/webui/data/generators/system/webui_system_metrics.sh index 598de5e..c6ea7cc 100644 --- a/scripts/webui/data/generators/system/webui_system_metrics.sh +++ b/scripts/webui/data/generators/system/webui_system_metrics.sh @@ -27,7 +27,7 @@ _metricsReadCpu() { } webuiSystemMetrics() { - local system_dir="${containers_dir}libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" createFolders "quiet" "$sudo_user_name" "$system_dir" local now_epoch; now_epoch=$(date +%s) @@ -209,7 +209,7 @@ EOF # run per CFG_APP_STORAGE_INTERVAL (default 10 min) via the .stamp idiom used by # the update/verify checks above. Pass "force" to bypass it. webuiSystemAppStorage() { - local system_dir="${containers_dir}libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" createFolders "quiet" "$sudo_user_name" "$system_dir" local final_file="$system_dir/app_storage.json" @@ -304,7 +304,7 @@ webuiSystemAppStorage() { # compose project label fall back to their container name so nothing is lost. webuiSystemApps() { local now_epoch="$1" now_iso="$2" system_dir="$3" - [[ -z "$system_dir" ]] && system_dir="${containers_dir}libreportal/frontend/data/system" + [[ -z "$system_dir" ]] && system_dir="$(webuiDir)/frontend/data/system" command -v docker &>/dev/null || return 0 # name|project|state|status for every container (running or not) diff --git a/scripts/webui/data/generators/system/webui_system_network.sh b/scripts/webui/data/generators/system/webui_system_network.sh index 056a7f5..b675df5 100644 --- a/scripts/webui/data/generators/system/webui_system_network.sh +++ b/scripts/webui/data/generators/system/webui_system_network.sh @@ -16,7 +16,7 @@ webuiSystemNetworkCheck() { local force_flag="$1" - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" local final_file="${system_dir}/network_status.json" local stamp_file="${system_dir}/.network_check_stamp" local interval="${CFG_NETWORK_CHECK_INTERVAL:-300}" diff --git a/scripts/webui/data/generators/system/webui_system_update.sh b/scripts/webui/data/generators/system/webui_system_update.sh index 5ab2705..c73f733 100755 --- a/scripts/webui/data/generators/system/webui_system_update.sh +++ b/scripts/webui/data/generators/system/webui_system_update.sh @@ -52,7 +52,7 @@ webuiSystemUpdateCheck() { local force_flag="$1" local repo_dir="${script_dir}" - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" local final_file="${system_dir}/update_status.json" local stamp_file="${system_dir}/.update_check_stamp" # How long (seconds) a fetch result stays "fresh" before we hit the network @@ -267,7 +267,7 @@ EOF webuiSystemVerify() { local force_flag="$1" - local system_dir="$containers_dir/libreportal/frontend/data/system" + local system_dir="$(webuiDir)/frontend/data/system" local final_file="${system_dir}/verify_status.json" local stamp_file="${system_dir}/.verify_check_stamp" local interval="${CFG_VERIFY_CHECK_INTERVAL:-86400}" diff --git a/scripts/webui/data/generators/updater/webui_updater_scan.sh b/scripts/webui/data/generators/updater/webui_updater_scan.sh index 3b760e1..a189b1a 100644 --- a/scripts/webui/data/generators/updater/webui_updater_scan.sh +++ b/scripts/webui/data/generators/updater/webui_updater_scan.sh @@ -355,7 +355,7 @@ updaterDisplayVersion() { } webuiUpdaterScan() { - local out_dir="$containers_dir/libreportal/frontend/data/updater/generated" + local out_dir="$(webuiDir)/frontend/data/updater/generated" runFileOp mkdir -p "$out_dir" 2>/dev/null || mkdir -p "$out_dir" 2>/dev/null local now; now="$(date -Iseconds 2>/dev/null || date)" diff --git a/scripts/webui/data/lock/webui_check_update_lock.sh b/scripts/webui/data/lock/webui_check_update_lock.sh index 9ffb4f2..e7360eb 100755 --- a/scripts/webui/data/lock/webui_check_update_lock.sh +++ b/scripts/webui/data/lock/webui_check_update_lock.sh @@ -15,7 +15,7 @@ # the leftover lock would otherwise wedge EVERY future refresh. No single refresh # runs anywhere near this long, so a lock older than the threshold is a leftover. webuiCheckUpdateLock() { - local lock_file="$containers_dir/libreportal/frontend/data/updater.lock" + local lock_file="$(webuiDir)/frontend/data/updater.lock" local stale_after=900 # seconds (15 min); far longer than any real refresh if [ ! -f "$lock_file" ]; then diff --git a/scripts/webui/data/lock/webui_create_update_lock.sh b/scripts/webui/data/lock/webui_create_update_lock.sh index 2fa536b..2f892c5 100755 --- a/scripts/webui/data/lock/webui_create_update_lock.sh +++ b/scripts/webui/data/lock/webui_create_update_lock.sh @@ -4,7 +4,7 @@ # Creates update lock file to prevent concurrent updates webuiCreateUpdateLock() { - local lock_file="$containers_dir/libreportal/frontend/data/updater.lock" + local lock_file="$(webuiDir)/frontend/data/updater.lock" # Create lock file with timestamp and process ID. The lock lives in the # dockerinstall-owned WebUI data dir, so write it as the path owner. diff --git a/scripts/webui/data/lock/webui_remove_setup_lock.sh b/scripts/webui/data/lock/webui_remove_setup_lock.sh index 983cf88..b961380 100755 --- a/scripts/webui/data/lock/webui_remove_setup_lock.sh +++ b/scripts/webui/data/lock/webui_remove_setup_lock.sh @@ -4,7 +4,7 @@ # Removes setup lock file after update completion webuiRemoveSetupLock() { - local lock_file="$containers_dir/libreportal/frontend/data/setup.lock" + local lock_file="$(webuiDir)/frontend/data/setup.lock" if [ -f "$lock_file" ]; then runFileOp rm -f "$lock_file" diff --git a/scripts/webui/data/lock/webui_remove_update_lock.sh b/scripts/webui/data/lock/webui_remove_update_lock.sh index 8e1b1a9..579487d 100755 --- a/scripts/webui/data/lock/webui_remove_update_lock.sh +++ b/scripts/webui/data/lock/webui_remove_update_lock.sh @@ -4,7 +4,7 @@ # Removes update lock file after update completion webuiRemoveUpdateLock() { - local lock_file="$containers_dir/libreportal/frontend/data/updater.lock" + local lock_file="$(webuiDir)/frontend/data/updater.lock" if [ -f "$lock_file" ]; then runFileOp rm -f "$lock_file" diff --git a/scripts/webui/data/logs/webui_logs_folders.sh b/scripts/webui/data/logs/webui_logs_folders.sh index 8cda4c1..dff4983 100755 --- a/scripts/webui/data/logs/webui_logs_folders.sh +++ b/scripts/webui/data/logs/webui_logs_folders.sh @@ -4,7 +4,7 @@ webuiCreateLogsFolders() { - local log_dir="${containers_dir}libreportal/frontend/logs" + local log_dir="$(webuiDir)/frontend/logs" local apps_dir="${log_dir}/apps" if [ ! -d "$apps_dir" ]; then local result; result=$(createFolders "loud" $sudo_user_name $log_dir $apps_dir) diff --git a/scripts/webui/data/tasks/webui_task_files.sh b/scripts/webui/data/tasks/webui_task_files.sh index bf3f7c1..33bc6ed 100755 --- a/scripts/webui/data/tasks/webui_task_files.sh +++ b/scripts/webui/data/tasks/webui_task_files.sh @@ -4,7 +4,7 @@ # Ensures essential task system files exist for LibrePortal task management webuiEnsureTaskFiles() { - local task_dir="${containers_dir}libreportal/frontend/data/tasks" + local task_dir="$(webuiDir)/frontend/data/tasks" # Create tasks directory if it doesn't exist if [ ! -d "$task_dir" ]; then diff --git a/scripts/webui/data/utils/webui_app_icons.sh b/scripts/webui/data/utils/webui_app_icons.sh index b64ebc9..33e8914 100755 --- a/scripts/webui/data/utils/webui_app_icons.sh +++ b/scripts/webui/data/utils/webui_app_icons.sh @@ -13,7 +13,7 @@ webuiSyncAppIcon() { local app_name="$1" [[ -z "$app_name" ]] && return 1 - local icons_dir="${containers_dir}libreportal/frontend/core/icons/apps" + local icons_dir="$(webuiDir)/frontend/core/icons/apps" runFileOp mkdir -p "$icons_dir" # Icons live in the install template dir — copy_build_context.sh @@ -65,7 +65,7 @@ webuiSyncAppIcons() { # Only ever removes icons it can match to a missing template, never anything # else in the directory. webuiPruneAppIcons() { - local icons_dir="${containers_dir}libreportal/frontend/core/icons/apps" + local icons_dir="$(webuiDir)/frontend/core/icons/apps" [[ -d "$icons_dir" ]] || return 0 [[ -d "$install_containers_dir" ]] || return 0 diff --git a/scripts/webui/data/utils/webui_app_log.sh b/scripts/webui/data/utils/webui_app_log.sh index c1cc8e7..5efcdf6 100755 --- a/scripts/webui/data/utils/webui_app_log.sh +++ b/scripts/webui/data/utils/webui_app_log.sh @@ -6,7 +6,7 @@ webuiUpdateAppLog() local type=$2 # install or uninstall # Create logs directory if it doesn't exist - local log_dir="${containers_dir}libreportal/frontend/logs" + local log_dir="$(webuiDir)/frontend/logs" local apps_dir="${log_dir}/apps" if [ ! -d "$apps_dir" ]; then local result; result=$(createFolders "loud" $sudo_user_name $log_dir $apps_dir) diff --git a/scripts/webui/data/utils/webui_atomic_write.sh b/scripts/webui/data/utils/webui_atomic_write.sh index a070a56..0b1b3ca 100755 --- a/scripts/webui/data/utils/webui_atomic_write.sh +++ b/scripts/webui/data/utils/webui_atomic_write.sh @@ -13,7 +13,7 @@ atomicWriteWebUI() { # can write the dockerinstall-owned WebUI/app files. Temp + rename share the # target's directory, so the mv stays atomic (same filesystem, same owner). local op="runInstallOp" wop="runInstallWrite" - if [[ "$target_file" == "$containers_dir"* || "$target_file" == "${LP_CONTAINERS_DIR:-/libreportal-containers}"/* ]]; then + if pathIsContainerData "$target_file"; then op="runFileOp"; wop="runFileWrite" fi diff --git a/scripts/webui/webui_install_image.sh b/scripts/webui/webui_install_image.sh index eef741d..5f1aacb 100755 --- a/scripts/webui/webui_install_image.sh +++ b/scripts/webui/webui_install_image.sh @@ -17,7 +17,7 @@ installLibrePortalImageWebUI() # libreportal.config as a Docker-created directory. The tar copy below can't # extract a file over a directory ("Cannot open: File exists") and aborts the # whole source copy, so clear the stub first. - repairStubDirForFile "$containers_dir/libreportal/libreportal.config" "loud" + repairStubDirForFile "$(webuiDir)/libreportal.config" "loud" local result; result=$(copyFolder "$install_containers_dir/libreportal" "$containers_dir" "$sudo_user_name") checkSuccess "Copy the LibrePortal to the containers folder" @@ -40,6 +40,6 @@ installLibrePortalImageWebUI() fi isNotice "Building libreportal-service image, this may take a while..." - local result; result=$(runFileOp docker build -t libreportal-service -f $containers_dir/libreportal/Dockerfile $containers_dir/libreportal >/dev/null 2>&1) + local result; result=$(runFileOp docker build -t libreportal-service -f $(webuiDir)/Dockerfile $(webuiDir) >/dev/null 2>&1) checkSuccess "Built LibrePortal WebUI Docker image" } \ No newline at end of file diff --git a/scripts/webui/webui_install_systemd.sh b/scripts/webui/webui_install_systemd.sh index e213359..f21b380 100755 --- a/scripts/webui/webui_install_systemd.sh +++ b/scripts/webui/webui_install_systemd.sh @@ -14,7 +14,7 @@ installLibrePortalWebUITaskService() [[ "$CFG_REQUIREMENT_WEBUI_SERVICE" == "true" ]] || return 0 local task_processor_script="$install_scripts_dir/task/crontab_task_processor.sh" - local task_dir="$containers_dir/libreportal/frontend/data/tasks" + local task_dir="$(webuiDir)/frontend/data/tasks" # Point the processor at the task dir (idempotent). This edits the # manager-owned install tree, so no privilege is needed. diff --git a/scripts/webui/webui_regen.sh b/scripts/webui/webui_regen.sh index 4ba3851..ea78539 100644 --- a/scripts/webui/webui_regen.sh +++ b/scripts/webui/webui_regen.sh @@ -49,7 +49,7 @@ _lpRegenOrphanedApp() { lpRegenWebui() { local force="$1" - local gen="${containers_dir}libreportal/frontend/data/apps/generated" + local gen="$(webuiDir)/frontend/data/apps/generated" local apps_json="$gen/apps.json" local tools_json="$gen/apps-tools.json" diff --git a/scripts/webui/webui_updater.sh b/scripts/webui/webui_updater.sh index 4c5626a..b8bb830 100755 --- a/scripts/webui/webui_updater.sh +++ b/scripts/webui/webui_updater.sh @@ -59,7 +59,7 @@ webuiLibrePortalUpdate() { checkSuccess "Generated system configurations..." # Generate categories - local result; result=$(webuiCreateCategories $containers_dir/libreportal/frontend/data) + local result; result=$(webuiCreateCategories $(webuiDir)/frontend/data) checkSuccess "Generated app and config categories..." # Generate LibrePortal app configuration