mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 14:25:08 +00:00
Updates that move HEAD now install changed systemd units through a root-owned helper (/usr/local/sbin/ledmatrix-refresh-units, two literal sudo lines), with a backup restored on rollback; a refresh that fails part-way puts the old units back. Devices without the new sudo rule keep updating and are told to re-run the installer once. The one-shot installer now checks out the newest vX.Y.Z release (LEDMATRIX_CHANNEL=beta keeps main) and never moves an existing checkout backwards. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
229 lines
9.3 KiB
Bash
Executable File
229 lines
9.3 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# Exit on error
|
|
set -e
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: sudo ./scripts/install/install_service.sh [-h|--help]
|
|
|
|
Installs (or reinstalls) the LEDMatrix systemd units from the templates in
|
|
systemd/, then enables and starts them:
|
|
- ledmatrix.service main display (runs as root)
|
|
- ledmatrix-web.service web interface (runs as the invoking user)
|
|
- ledmatrix-update-verify.service automatic-update health check
|
|
- ledmatrix-update-verify.path
|
|
|
|
Existing unit files in /etc/systemd/system are overwritten. The script takes
|
|
no other options; run it with no arguments to install.
|
|
|
|
Options:
|
|
-h, --help Show this help and exit without changing anything.
|
|
USAGE
|
|
}
|
|
|
|
# Parse arguments before touching anything: this script rewrites and restarts
|
|
# services, so an unrecognised option must not fall through to a full install.
|
|
for arg in "$@"; do
|
|
case "$arg" in
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "ERROR: unknown option: $arg" >&2
|
|
usage >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
done
|
|
|
|
# Get the actual user who invoked sudo
|
|
if [ -n "$SUDO_USER" ]; then
|
|
ACTUAL_USER="$SUDO_USER"
|
|
else
|
|
ACTUAL_USER=$(whoami)
|
|
fi
|
|
|
|
# Get the home directory of the actual user
|
|
USER_HOME=$(eval echo ~$ACTUAL_USER)
|
|
|
|
# Determine the Project Root Directory (parent of scripts/install/)
|
|
PROJECT_ROOT_DIR=$(cd "$(dirname "$0")/../.." && pwd)
|
|
|
|
# shellcheck source=scripts/install/lib_systemd_render.sh
|
|
source "$PROJECT_ROOT_DIR/scripts/install/lib_systemd_render.sh"
|
|
|
|
echo "Installing LED Matrix Display Service for user: $ACTUAL_USER"
|
|
echo "Using home directory: $USER_HOME"
|
|
echo "Project root directory: $PROJECT_ROOT_DIR"
|
|
|
|
# Render the main display unit from its template. The display service runs as
|
|
# root (it needs GPIO), so __USER__ is always root here -- unlike the web unit
|
|
# below, which runs as whoever installed it.
|
|
#
|
|
# A missing template or a failed render is fatal: falling through would leave
|
|
# whatever unit already sits at /etc/systemd/system/ledmatrix.service (from a
|
|
# previous install) untouched, and the enable/start step below would then
|
|
# silently reuse that stale unit instead of the one this run was asked to
|
|
# install.
|
|
if [ -f "$PROJECT_ROOT_DIR/systemd/ledmatrix.service" ]; then
|
|
ESCAPED_PROJECT_ROOT_DIR=$(sed_escape_replacement "$PROJECT_ROOT_DIR")
|
|
MAIN_UNIT_TMP=$(mktemp)
|
|
trap 'rm -f "$MAIN_UNIT_TMP"' EXIT
|
|
if ! sed "s|__PROJECT_ROOT_DIR__|$ESCAPED_PROJECT_ROOT_DIR|g; s|__USER__|root|g" \
|
|
"$PROJECT_ROOT_DIR/systemd/ledmatrix.service" > "$MAIN_UNIT_TMP"; then
|
|
echo "ERROR: failed to render ledmatrix.service from its template." >&2
|
|
exit 1
|
|
fi
|
|
# Copy the service file to the systemd directory
|
|
sudo cp "$MAIN_UNIT_TMP" /etc/systemd/system/ledmatrix.service
|
|
# Clean up
|
|
rm -f "$MAIN_UNIT_TMP"
|
|
trap - EXIT
|
|
else
|
|
echo "ERROR: ledmatrix.service template not found at $PROJECT_ROOT_DIR/systemd/ledmatrix.service." >&2
|
|
exit 1
|
|
fi
|
|
|
|
|
|
# Reload systemd to recognize the new service (or modified service)
|
|
sudo systemctl daemon-reload
|
|
|
|
if [ -f "/etc/systemd/system/ledmatrix.service" ]; then
|
|
echo "Enabling ledmatrix.service (main display) to start on boot..."
|
|
sudo systemctl enable ledmatrix.service
|
|
echo "Starting ledmatrix.service (main display)..."
|
|
sudo systemctl start ledmatrix.service
|
|
else
|
|
echo "Skipping enable/start for ledmatrix.service as it was not configured."
|
|
fi
|
|
|
|
# === LEDMatrix Web Interface service (ledmatrix-web.service) ===
|
|
echo "Installing LEDMatrix Web Interface service (ledmatrix-web.service)..."
|
|
|
|
# Rendered from systemd/ledmatrix-web.service, the same template
|
|
# install_web_service.sh uses. This was an inline heredoc until it drifted from
|
|
# the template: it had lost Wants=network-online.target, RestartSec,
|
|
# SyslogIdentifier and Environment=USE_THREADING. Because
|
|
# src/startup_validator.py compares the installed unit against the template,
|
|
# every boot warned "re-run install_service.sh" -- and doing so reinstalled the
|
|
# same stale copy, so the warning could never clear.
|
|
#
|
|
# As with the main unit above, a missing template or a failed render is
|
|
# fatal -- otherwise the enable/start check below would fall back to
|
|
# whatever unit (possibly stale) already exists at the destination path.
|
|
if [ -f "$PROJECT_ROOT_DIR/systemd/ledmatrix-web.service" ]; then
|
|
ESCAPED_ACTUAL_USER=$(sed_escape_replacement "$ACTUAL_USER")
|
|
WEB_UNIT_TMP=$(mktemp)
|
|
trap 'rm -f "$WEB_UNIT_TMP"' EXIT
|
|
if ! sed "s|__PROJECT_ROOT_DIR__|$ESCAPED_PROJECT_ROOT_DIR|g; s|__USER__|$ESCAPED_ACTUAL_USER|g" \
|
|
"$PROJECT_ROOT_DIR/systemd/ledmatrix-web.service" > "$WEB_UNIT_TMP"; then
|
|
echo "ERROR: failed to render ledmatrix-web.service from its template." >&2
|
|
exit 1
|
|
fi
|
|
sudo cp "$WEB_UNIT_TMP" /etc/systemd/system/ledmatrix-web.service
|
|
rm -f "$WEB_UNIT_TMP"
|
|
trap - EXIT
|
|
else
|
|
echo "ERROR: ledmatrix-web.service template not found at $PROJECT_ROOT_DIR/systemd/ledmatrix-web.service." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Health check / rollback units for automatic updates; see install_web_service.sh.
|
|
for VERIFY_UNIT in ledmatrix-update-verify.service ledmatrix-update-verify.path; do
|
|
if [ -f "$PROJECT_ROOT_DIR/systemd/$VERIFY_UNIT" ]; then
|
|
VERIFY_UNIT_TMP=$(mktemp)
|
|
if sed "s|__PROJECT_ROOT_DIR__|$ESCAPED_PROJECT_ROOT_DIR|g; s|__USER__|$ESCAPED_ACTUAL_USER|g" "$PROJECT_ROOT_DIR/systemd/$VERIFY_UNIT" > "$VERIFY_UNIT_TMP"; then
|
|
sudo cp "$VERIFY_UNIT_TMP" "/etc/systemd/system/$VERIFY_UNIT"
|
|
else
|
|
echo "WARNING: failed to render $VERIFY_UNIT; automatic code updates will stay paused." >&2
|
|
fi
|
|
rm -f "$VERIFY_UNIT_TMP"
|
|
fi
|
|
done
|
|
|
|
# The helper updates run (through sudo, see lib_sudoers.sh) to install these
|
|
# same units when a new version changes their templates, and to put the old
|
|
# ones back if the automatic update rolls back. Root-owned and outside the
|
|
# checkout, so the web user who owns the checkout cannot change what sudo runs.
|
|
# Not fatal: without it, updates leave the units for the next reinstall.
|
|
REFRESH_UNITS_SRC="$PROJECT_ROOT_DIR/scripts/install/ledmatrix_refresh_units.py"
|
|
REFRESH_UNITS_DEST=/usr/local/sbin/ledmatrix-refresh-units
|
|
if [ -f "$REFRESH_UNITS_SRC" ]; then
|
|
if sudo install -D -o root -g root -m 0755 "$REFRESH_UNITS_SRC" "$REFRESH_UNITS_DEST"; then
|
|
echo "Installed $REFRESH_UNITS_DEST (lets updates refresh these units)"
|
|
else
|
|
echo "WARNING: could not install $REFRESH_UNITS_DEST; updates will not refresh the systemd units" >&2
|
|
fi
|
|
fi
|
|
# The units above are copied from mktemp files, which are 0600. 0644 is what
|
|
# first_time_install.sh (Step 8.1) sets, and lets the web interface compare
|
|
# them with the templates after an update without root.
|
|
for INSTALLED_UNIT in ledmatrix.service ledmatrix-web.service \
|
|
ledmatrix-update-verify.service ledmatrix-update-verify.path; do
|
|
if [ -f "/etc/systemd/system/$INSTALLED_UNIT" ]; then
|
|
sudo chmod 644 "/etc/systemd/system/$INSTALLED_UNIT" || true
|
|
fi
|
|
done
|
|
|
|
echo "Reloading systemd daemon for web service..."
|
|
sudo systemctl daemon-reload
|
|
|
|
if [ -f "/etc/systemd/system/ledmatrix-web.service" ]; then
|
|
echo "Enabling ledmatrix-web.service to start on boot..."
|
|
sudo systemctl enable ledmatrix-web.service
|
|
|
|
if [ -f /etc/systemd/system/ledmatrix-update-verify.path ]; then
|
|
echo "Enabling ledmatrix-update-verify.path (automatic update health check)..."
|
|
sudo systemctl enable --now ledmatrix-update-verify.path || echo "WARNING: could not enable ledmatrix-update-verify.path; automatic code updates will stay paused" >&2
|
|
fi
|
|
|
|
echo "Starting ledmatrix-web.service..."
|
|
sudo systemctl start ledmatrix-web.service
|
|
|
|
echo "LEDMatrix Web Interface service (ledmatrix-web.service) installation complete."
|
|
echo "It will start based on the 'web_display_autostart' setting in config/config.json."
|
|
else
|
|
echo "Skipping enable/start for ledmatrix-web.service as it was not configured."
|
|
fi
|
|
# === End of LEDMatrix Web Interface service ===
|
|
|
|
|
|
# Check the status
|
|
echo "Service status for main display (ledmatrix.service):"
|
|
sudo systemctl status ledmatrix.service || echo "ledmatrix.service not found or failed to get status."
|
|
echo "Service status for web interface (ledmatrix-web.service):"
|
|
sudo systemctl status ledmatrix-web.service || echo "ledmatrix-web.service not found or failed to get status."
|
|
|
|
echo ""
|
|
echo "LED Matrix Services have been processed."
|
|
echo ""
|
|
echo "To stop the main display when you SSH in:"
|
|
echo " sudo systemctl stop ledmatrix.service"
|
|
echo "To stop the web interface:"
|
|
echo " sudo systemctl stop ledmatrix-web.service"
|
|
|
|
echo ""
|
|
echo "To check if the main display service is running:"
|
|
echo " sudo systemctl status ledmatrix.service"
|
|
echo "To check if the web interface service is running:"
|
|
echo " sudo systemctl status ledmatrix-web.service"
|
|
|
|
echo ""
|
|
echo "To restart the main display service:"
|
|
echo " sudo systemctl restart ledmatrix.service"
|
|
echo "To restart the web interface service:"
|
|
echo " sudo systemctl restart ledmatrix-web.service"
|
|
|
|
echo ""
|
|
echo "To view logs for the main display:"
|
|
echo " journalctl -u ledmatrix.service"
|
|
echo "To view logs for the web interface:"
|
|
echo " journalctl -u ledmatrix-web.service"
|
|
|
|
echo ""
|
|
echo "To disable autostart for the main display:"
|
|
echo " sudo systemctl disable ledmatrix.service"
|
|
echo "To disable autostart for the web interface:"
|
|
echo " sudo systemctl disable ledmatrix-web.service" |