LibrePortal/start.sh
librelad 536b5b8e10 restore: stop the first-run bulk restore from silently dropping most of the host
An end-to-end run restored 4 of 13 apps and reported
"First-run restore complete — 4 apps restored" as a success.

Two truncations, and fixing the first had hidden the second:

  * the CLI dispatcher calls handlers with no arguments, so "$@"/shift inside
    one operate on an empty list. Fixed earlier with LP_CLI_ARGS.
  * LP_CLI_ARGS was built from start.sh's "$@" — but the root wrapper invokes
    start.sh with exactly nine hardcoded positional slots. So the array could
    never hold more than nine entries, and `${LP_CLI_ARGS[@]:5}` yielded at
    most four app names.

The wrapper now forwards the real argv after those nine slots (they stay
untouched: every dispatcher reads them, and unset ones must keep arriving as
the literal "empty"), and start.sh reads it back as "${@:10}". Verified: a
preflight given six apps checks six, where five was the previous ceiling.
footprint_version 7 -> 8, since the wrapper is root-owned and baked at install.

Two further fixes so a truncation cannot pass as success again:

  * restoreFirstRunBulk with no app list is now a whole-host restore — it
    discovers the host's apps and re-applies the preflight. The installer's
    report runs in its own process, so without this an app the user was told
    would be skipped got restored anyway. init.sh now passes no list, so a
    whole-host restore builds nothing that can be truncated.
  * it counts what actually landed and returns non-zero naming the failures,
    instead of reporting the length of the list it was handed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-27 12:20:59 +01:00

102 lines
4.3 KiB
Bash
Executable File

#!/bin/bash
# Used for mainly CLI
initial_command1="$1"
initial_command2="$2"
initial_command3="$3"
initial_command4="$4"
initial_command5="$5"
initial_command6="$6"
initial_command7="$7"
# The full argument vector, for commands that take an open-ended list (restore
# preflight / first-run bulk take any number of app names). Two separate
# truncations conspired here, and fixing only the first hid the second:
#
# * the CLI dispatcher calls its handlers with NO arguments, so "$@" and
# `shift` inside a handler operate on an empty list
# * the root wrapper invokes this script with exactly nine positional slots,
# so reading "$@" here caps any list at nine — which for `first-run bulk`
# meant four app names. A 13-app restore quietly restored four and then
# reported "First-run restore complete — 4 apps restored" as a success.
#
# So the wrapper now appends the real argv after those nine slots, and this is
# where it is read back. Offsets below are into the true argv, unchanged.
declare -a LP_CLI_ARGS=("${@:10}")
displayLibrePortalLogo()
{
[[ "$LIBREPORTAL_SKIP_LOGO" == "1" ]] && return
local hbar; hbar=$(printf '═%.0s' $(seq 1 50))
printf '\n╔%s╗\n' "$hbar"
printf '║%6s%s%8s║\n' '' '╦ ┬┌┐ ┬─┐┌─┐ ╭─╮ ╔═╗┌─┐┬─┐┌┬┐┌─┐┬' ''
printf '║%6s%s%8s║\n' '' '║ │├┴┐├┬┘├┤ │◉│ ╠═╝│ │├┬┘ │ ├─┤│' ''
printf '║%6s%s%6s║\n' '' '╩═╝┴└─┘┴└─└─┘ ╨─╨ ╩ └─┘┴└─ ┴ ┴ ┴┴─┘' ''
printf '╚%s╝\n\n' "$hbar"
}
showRunHelp()
{
displayLibrePortalLogo;
echo "Available Run Commands:"
echo ""
echo " libreportal run install - Run the automated installer (WebUI flow)"
echo " libreportal run terminal - Open the terminal menu / Setup Wizard"
echo ""
echo "Pick one to continue."
echo ""
}
initLibrePortal()
{
# Load the relocatable path roots up front (sets logs_dir/docker_dir/…) — the
# install-log below needs logs_dir before load_sources runs. cwd is the install
# dir, so the relative path resolves.
[[ -f "scripts/source/paths.sh" ]] && source "scripts/source/paths.sh"
# Internal launcher: the systemd unit starts the task processor through this
# stable entry (`libreportal __task-processor`) so the unit never bakes the
# processor's in-tree path — only this hand-off knows where the script lives.
# paths.sh above resolved install_scripts_dir; export it so the exec'd
# processor inherits the roots and skips its own self-location. Intercept here,
# before the heavy load_sources — we only need to hand off to the daemon.
if [[ "$initial_command1" == "__task-processor" ]]; then
export install_scripts_dir
exec "${install_scripts_dir}task/crontab_task_processor.sh" start_script
fi
# For the full application loading
if [[ "$initial_command1" == "run" ]]; then
if [[ -z "$initial_command2" ]]; then
showRunHelp;
exit 0
fi
init_run_flag="true"
# Capture the install run to a log so credentials/URLs can be recovered
# after we clear the screen at the end.
if [[ "$initial_command2" == "install" ]]; then
install_log_path="${logs_dir:-/libreportal-system/logs/}install-$(date +%Y%m%d-%H%M%S).log"
sudo mkdir -p "${logs_dir:-/libreportal-system/logs/}" 2>/dev/null
sudo touch "$install_log_path" 2>/dev/null
# Own it by whoever runs the install (the manager under Model A) so the
# tee below — which runs as that user, not root — can append. A
# sudo-touched file is root:root 644, leaving the manager unable to
# write it → the empty install-*.log files.
sudo chown "$(id -un):$(id -gn)" "$install_log_path" 2>/dev/null
sudo chmod 644 "$install_log_path" 2>/dev/null
export install_log_path
exec > >(tee -a "$install_log_path") 2>&1
fi
displayLibrePortalLogo;
source "scripts/source/load_sources.sh"
else
# For the CLI loading
init_run_flag="false"
displayLibrePortalLogo;
source "scripts/source/load_sources.sh"
fi
}
initLibrePortal;