#!/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"