The three roots reach running code three ways — the CLI wrapper exports them,
the task-processor unit carries them as Environment=, and anything those start
inherits them. An @reboot crontab entry is started by none of the three: it runs
a script by absolute path, so paths.sh fell through to
: "${LP_CONTAINERS_DIR:=/libreportal-containers}"
That entry is crontab_boot_app_reconcile.sh, which brings every installed app up
at boot. On a relocated install it therefore reconciled against the DEFAULT
root, and that does not fail — docker creates the bind-mount directories it does
not find, so every app comes back empty while the real data sits untouched on
the other disk. Nothing logs an error; the only symptom is opening an app and
finding it blank (storage-locations §10.1 calls this the top data-integrity
risk).
Verified on a case-2 install (apps on /mnt/lptest2): a bare environment resolved
containers_dir to /libreportal-containers/ where the real root was
/mnt/lptest2/libreportal-containers.
Recover them from the systemd unit, which is the authoritative baked record —
init.sh already reads it back the same way, libreportal-relocate rewrites it,
and it is root-owned, so this is not the manager reading a config it can edit.
An explicit environment still wins; with no unit the defaults are unchanged.
scripts/dev/lp-paths-roots-test pins all four cases; verified it fails when the
recovery is removed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
3.1 KiB
Bash
Executable File
67 lines
3.1 KiB
Bash
Executable File
#!/bin/bash
|
|
# Where do the three roots come from when nothing exported them?
|
|
#
|
|
# scripts/dev/lp-paths-roots-test
|
|
#
|
|
# The roots reach running code three ways: the CLI wrapper exports them, the
|
|
# task-processor unit carries them as Environment=, and anything those start
|
|
# inherits them. An @reboot crontab entry is started by none of the three — it
|
|
# runs a script by absolute path — so paths.sh fell through to the
|
|
# /libreportal-* defaults.
|
|
#
|
|
# That job is crontab_boot_app_reconcile.sh, which brings every installed app up
|
|
# at boot. Pointed at the wrong root it does not fail: docker creates the
|
|
# bind-mount directories it does not find, so every app comes back EMPTY while
|
|
# the real data sits untouched on the other disk. Nothing reports an error, and
|
|
# the damage is only visible by opening an app (storage-locations §10.1).
|
|
#
|
|
# So the case that matters is the second one: no environment, relocated install.
|
|
|
|
REPO="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
BASE="$(mktemp -d "${TMPDIR:-/tmp}/lp-paths-test-XXXXXX")"
|
|
trap 'rm -rf "$BASE"' EXIT
|
|
|
|
fail=0
|
|
chk(){ if [[ "$2" == "$3" ]]; then echo " ok $1"; else echo " FAIL $1: got '$2' want '$3'"; fail=1; fi; }
|
|
|
|
# A stand-in for the baked task-processor unit.
|
|
cat > "$BASE/unit" <<EOF
|
|
[Service]
|
|
Environment=LP_SYSTEM_DIR=/mnt/d1/libreportal-system
|
|
Environment=LP_CONTAINERS_DIR=/mnt/d2/libreportal-containers
|
|
Environment=LP_BACKUPS_DIR=/mnt/d2/libreportal-backups
|
|
EOF
|
|
|
|
# Each case runs in its own bash so no root leaks between them.
|
|
ask() { # ask <var> [env assignments...]
|
|
local var="$1"; shift
|
|
env -i PATH=/usr/bin:/bin "$@" bash -c \
|
|
'source "$0" >/dev/null 2>&1; eval echo "\$$1"' "$REPO/scripts/source/paths.sh" "$var"
|
|
}
|
|
|
|
echo "--- no environment, unit present (the @reboot cron case) ---"
|
|
chk "system" "$(ask LP_SYSTEM_DIR LP_UNIT_FILE="$BASE/unit")" "/mnt/d1/libreportal-system"
|
|
chk "containers" "$(ask LP_CONTAINERS_DIR LP_UNIT_FILE="$BASE/unit")" "/mnt/d2/libreportal-containers"
|
|
chk "backups" "$(ask LP_BACKUPS_DIR LP_UNIT_FILE="$BASE/unit")" "/mnt/d2/libreportal-backups"
|
|
chk "derived containers_dir" \
|
|
"$(ask containers_dir LP_UNIT_FILE="$BASE/unit")" "/mnt/d2/libreportal-containers/"
|
|
chk "derived configs_dir" \
|
|
"$(ask configs_dir LP_UNIT_FILE="$BASE/unit")" "/mnt/d1/libreportal-system/configs/"
|
|
|
|
echo "--- an explicit environment still wins over the unit ---"
|
|
chk "containers" \
|
|
"$(ask LP_CONTAINERS_DIR LP_UNIT_FILE="$BASE/unit" LP_CONTAINERS_DIR=/explicit)" "/explicit"
|
|
|
|
echo "--- no unit: unchanged default behaviour ---"
|
|
chk "system" "$(ask LP_SYSTEM_DIR LP_UNIT_FILE=/nonexistent)" "/libreportal-system"
|
|
chk "containers" "$(ask LP_CONTAINERS_DIR LP_UNIT_FILE=/nonexistent)" "/libreportal-containers"
|
|
|
|
echo "--- a unit that names only the system root ---"
|
|
printf '[Service]\nEnvironment=LP_SYSTEM_DIR=/mnt/d1/libreportal-system\n' > "$BASE/partial"
|
|
chk "system" "$(ask LP_SYSTEM_DIR LP_UNIT_FILE="$BASE/partial")" "/mnt/d1/libreportal-system"
|
|
chk "containers -> default" "$(ask LP_CONTAINERS_DIR LP_UNIT_FILE="$BASE/partial")" "/libreportal-containers"
|
|
|
|
echo ""
|
|
if (( fail )); then echo "FAILED"; exit 1; fi
|
|
echo "All root-resolution checks passed."
|