diff --git a/scripts/on-device-install/README.md b/scripts/on-device-install/README.md index cc760de..eaed5c9 100644 --- a/scripts/on-device-install/README.md +++ b/scripts/on-device-install/README.md @@ -16,10 +16,21 @@ If your device doesn't expose the port, you can still use the on-device installe ### Space Limitation -The storage space on the SoundTouch devices is very limited. At the moment only one AfterTouch installation barely fits on them with enough room for the data it needs to maintain. When installing, make sure that you have removed any binaries and folders of previous installation attempts. +The storage space on the SoundTouch devices is very limited — stock rootfs typically has only a few MB free (e.g. ~4 MB on the ST20, see issue #268), well below the AfterTouch binary's ~12 MB. To work around this, the installer puts everything on `/mnt/nv/aftertouch` by default (the persistent partition, typically ~30 MB free) and points `/opt/aftertouch` at it via a symlink so the init script and runtime paths stay unchanged. Override the install target with `INSTALL_DIR=/some/path` if you've got room elsewhere. The space limitation also means we are currently unsure on how to update the system, because two binaries are already too large. We are currently working on this - both by checking how we can make the binaries smaller, but also on how we can extend the storage space (e.g. by running AfterTouch from a USB drive). +### Logs + +The daemon writes to BusyBox syslog (tagged `aftertouch`) rather than to a file. Disk usage stays bounded — the syslog ring buffer is in memory — and the same `logread` recipe used elsewhere in this project works: + +```sh +logread | grep aftertouch | tail -20 # recent entries +logread -f | grep aftertouch # live tail +``` + +If the install command reports "running but :8000 not responding" or `aftertouch status` reports the listener is down, the syslog tail is the first place to look. + ## Installation Enable SSH on your SoundTouch device using the usual "Stick with remote_services" method. Connect with the following command. diff --git a/scripts/on-device-install/aftertouch b/scripts/on-device-install/aftertouch index fced2f3..42a72ed 100644 --- a/scripts/on-device-install/aftertouch +++ b/scripts/on-device-install/aftertouch @@ -17,6 +17,7 @@ PIDFILE="/var/run/$NAME.pid" DATADIR="/opt/aftertouch/data" SCRIPTNAME="/etc/init.d/$NAME" USER="root" +LOG_TAG="aftertouch" # Export PATH @@ -41,6 +42,17 @@ case "$1" in mkdir -p "$DATADIR" + # Pipe stdout + stderr through `logger -t $LOG_TAG` so the + # daemon's output lands in busybox syslog (bounded ring buffer, + # never grows on disk). Users diagnose with: + # + # logread | grep aftertouch | tail -20 + # logread -f | grep aftertouch # live tail + # + # `exec` on the daemon replaces /bin/sh so --make-pidfile records + # the daemon's own PID (not the shell wrapper). The `logger` + # process sits on the read end of the pipe and exits cleanly + # when the daemon dies and closes its end. start-stop-daemon --start \ --quiet \ --pidfile "$PIDFILE" \ @@ -48,7 +60,7 @@ case "$1" in --make-pidfile \ --chuid "$USER" \ --startas "/bin/sh" \ - -- -c "\"$DAEMON\" --data-dir '$DATADIR' --record-interactions=false --discovery-interval=60m" + -- -c "exec \"$DAEMON\" --data-dir '$DATADIR' --record-interactions=false --discovery-interval=60m 2>&1 | logger -t $LOG_TAG" tries=0 max_tries=60 @@ -60,6 +72,9 @@ case "$1" in tries=$((tries + 1)) done + echo "ERROR: daemon started but http://localhost:8000 never responded within $((max_tries * 2))s." >&2 + echo " Inspect the daemon's syslog output:" >&2 + echo " logread | grep $LOG_TAG | tail -20" >&2 exit 1 ;; @@ -86,12 +101,27 @@ case "$1" in if [ -f "$PIDFILE" ]; then PID=$(cat "$PIDFILE") if kill -0 "$PID" 2>/dev/null; then - echo "$NAME is running." + # PID is alive — does it actually serve HTTP? A live process + # with a dead listener is the symptom behind issue #250 + # (Gustour's ST30: status said running, curl said + # connection-refused). Distinguish the two states here so + # status isn't a false-positive. + if curl -fsS --max-time 3 http://localhost:8000 >/dev/null 2>&1; then + echo "$NAME is running (PID $PID, http://localhost:8000 responding)." + exit 0 + else + echo "$NAME PID $PID is alive but http://localhost:8000 is not responding." >&2 + echo "Recent log:" >&2 + logread 2>/dev/null | grep "$LOG_TAG" | tail -10 >&2 + exit 3 + fi else - echo "$NAME is not running (PID file exists but process is dead)." + echo "$NAME is not running (PID file exists but process is dead)." >&2 + exit 1 fi else echo "$NAME is not running." + exit 3 fi ;; @@ -102,4 +132,4 @@ case "$1" in esac -exit 0 \ No newline at end of file +exit 0 diff --git a/scripts/on-device-install/install.sh b/scripts/on-device-install/install.sh index 6f8913c..a805a22 100644 --- a/scripts/on-device-install/install.sh +++ b/scripts/on-device-install/install.sh @@ -5,22 +5,47 @@ VERSION=${VERSION:-0.79.0} GH_REPO=${GH_REPO:-gesellix/Bose-SoundTouch} BINARY_URL=${BINARY_URL:-https://github.com/$GH_REPO/releases/download/v$VERSION/soundtouch-service-v$VERSION-linux-armv7} INIT_SCRIPT_URL=${INIT_SCRIPT_URL:-https://raw.githubusercontent.com/$GH_REPO/v$VERSION/scripts/on-device-install/aftertouch} -UPDATE_TMP_DIR=${UPDATE_TMP_DIR:-/media/aftertouch} +# Default install location is /mnt/nv/aftertouch (the persistent +# partition), not /opt/aftertouch on rootfs. Stock SoundTouch rootfs +# has ~4 MB free on devices like the ST20 (issue #268); the +# AfterTouch binary is ~12 MB. /mnt/nv typically has tens of MB +# free and persists across reboots the same way /opt would. +# +# /opt/aftertouch becomes a symlink into the install target so the +# init script's hardcoded DAEMON path keeps working unchanged. +# +# Power users can override with INSTALL_DIR=/some/other/path. +INSTALL_DIR=${INSTALL_DIR:-/mnt/nv/aftertouch} + +# Scratch directory for the download. /media is tmpfs on most +# SoundTouch firmware, fine for transient files but unrelated to +# the persistent install target. +UPDATE_TMP_DIR=${UPDATE_TMP_DIR:-/media/aftertouch} rm -rf "$UPDATE_TMP_DIR" || true mkdir -p "$UPDATE_TMP_DIR" -echo "Installing Aftertouch $VERSION ..." -mkdir -p /opt/aftertouch +echo "Installing AfterTouch $VERSION to $INSTALL_DIR ..." +mkdir -p "$INSTALL_DIR" + +# Wire /opt/aftertouch -> $INSTALL_DIR so the init script +# (DAEMON=/opt/aftertouch/aftertouch-service) finds the binary +# regardless of which target we picked. Replace any prior +# /opt/aftertouch (directory or stale symlink) before re-creating. +if [ "$INSTALL_DIR" != "/opt/aftertouch" ]; then + rm -rf /opt/aftertouch + ln -sf "$INSTALL_DIR" /opt/aftertouch +fi + curl \ -sSL \ -o "$UPDATE_TMP_DIR/binary" \ --fail \ "$BINARY_URL" -mv "$UPDATE_TMP_DIR/binary" /opt/aftertouch/aftertouch-service -chmod +x /opt/aftertouch/aftertouch-service +mv "$UPDATE_TMP_DIR/binary" "$INSTALL_DIR/aftertouch-service" +chmod +x "$INSTALL_DIR/aftertouch-service" echo "Creating init script..." curl \ @@ -33,12 +58,33 @@ mv "$UPDATE_TMP_DIR/init-script" /etc/init.d/aftertouch chmod +x /etc/init.d/aftertouch update-rc.d aftertouch defaults -echo "Installation complete. Running initial startup to accelerate future startups..." +echo "Installation complete. Running initial startup..." /etc/init.d/aftertouch start /etc/init.d/aftertouch status -echo "Installation complete. Aftertouch $VERSION is now running on your device." -echo "You can try to connect to at http://:8000 ." -echo "If the connection fails, reconnect ssh with port forwarding like:" -echo "ssh -L 8000:localhost:8000 root@" +# Post-install verification: the init script's own poll loop only +# checks that the daemon registered a PID file; that's not enough +# evidence the listener is actually serving HTTP. Issue #250 shipped +# with a "running but unreachable" state where status was green and +# `curl :8000` got connection-refused. Re-check directly here and +# surface the recent syslog if it fails — the init script pipes the +# daemon's stdout/stderr through `logger -t aftertouch`, so panics +# land in busybox syslog and `logread` reads them out. +if curl -fsS --max-time 10 http://localhost:8000 >/dev/null 2>&1; then + echo "Installation complete. AfterTouch $VERSION is now running on your device." + echo "Connect to http://:8000 from another machine on the LAN." + echo "If the device doesn't expose :8000 directly, port-forward via SSH:" + echo " ssh -L 8000:localhost:8000 root@" +else + echo "WARNING: the init script reports AfterTouch as running, but" >&2 + echo " http://localhost:8000 isn't responding. The daemon may have" >&2 + echo " panicked shortly after start. Recent aftertouch syslog:" >&2 + echo "" >&2 + logread 2>/dev/null | grep aftertouch | tail -20 >&2 || \ + echo " (logread returned nothing for tag 'aftertouch'; the daemon" >&2 + echo "" >&2 + echo " For a live view of the daemon's output, run:" >&2 + echo " logread -f | grep aftertouch" >&2 + exit 1 +fi diff --git a/scripts/on-device-install/uninstall.sh b/scripts/on-device-install/uninstall.sh index 57ae404..342e92e 100644 --- a/scripts/on-device-install/uninstall.sh +++ b/scripts/on-device-install/uninstall.sh @@ -1,4 +1,22 @@ -/etc/init.d/aftertouch stop -rm -rf /etc/init.d/aftertouch +#!/bin/sh +# Uninstall AfterTouch on-device. Handles both the historical +# layout (/opt/aftertouch as a directory) and the post-#268 layout +# (/opt/aftertouch as a symlink into /mnt/nv/aftertouch). +set -eu + +/etc/init.d/aftertouch stop || true +rm -f /etc/init.d/aftertouch update-rc.d -f aftertouch remove -rm -rf /opt/aftertouch \ No newline at end of file + +# If /opt/aftertouch is a symlink, resolve it and remove the target +# before unlinking, so we don't leave ~12 MB of orphan binary on +# /mnt/nv. Tolerate either layout — readlink -f returns the same +# path for a real directory, and rm -rf on a missing path with +# set -eu would abort. +target="$(readlink -f /opt/aftertouch 2>/dev/null || echo /opt/aftertouch)" +if [ -e "$target" ]; then + rm -rf "$target" +fi +if [ -L /opt/aftertouch ] || [ -e /opt/aftertouch ]; then + rm -rf /opt/aftertouch +fi