#!/bin/sh # Parahub Mesh — OTA Auto-Update # Checks manifest.json for new firmware, downloads and verifies, runs sysupgrade. # Runs nightly via cron. Lock file prevents concurrent runs. LOCK="/tmp/parahub-autoupdate.lock" MANIFEST_YGG="http://[200:abb9:5810:37d3:8a4c:98a6:b82b:969a]/firmware/manifest.json" MANIFEST_PUBLIC="https://parahub.io/firmware/manifest.json" FIRMWARE_YGG="http://[200:abb9:5810:37d3:8a4c:98a6:b82b:969a]/firmware" FIRMWARE_PUBLIC="https://parahub.io/firmware" # Lock — exit if already running if [ -f "$LOCK" ]; then LOCK_PID=$(cat "$LOCK" 2>/dev/null) if kill -0 "$LOCK_PID" 2>/dev/null; then logger -t parahub-update "Already running (pid $LOCK_PID), exiting" exit 0 fi rm -f "$LOCK" fi echo $$ > "$LOCK" trap 'rm -f "$LOCK"' EXIT # Read current version and device profile CURRENT_VERSION=$(cat /etc/parahub/version 2>/dev/null) DEVICE_PROFILE=$(cat /etc/parahub/profile 2>/dev/null) ROLE=$(cat /etc/parahub/role 2>/dev/null || echo "unknown") if [ -z "$CURRENT_VERSION" ] || [ -z "$DEVICE_PROFILE" ]; then logger -t parahub-update "Missing /etc/parahub/version or /etc/parahub/profile, skipping" exit 1 fi # Fetch manifest (Yggdrasil first for bumblebee, public for bee) MANIFEST="" if [ "$ROLE" != "bee" ] && ping6 -c 1 -W 3 200:abb9:5810:37d3:8a4c:98a6:b82b:969a >/dev/null 2>&1; then MANIFEST=$(curl -s -m 30 "$MANIFEST_YGG" 2>/dev/null) BASE_URL="$FIRMWARE_YGG" fi if [ -z "$MANIFEST" ]; then MANIFEST=$(curl -s -m 30 "$MANIFEST_PUBLIC" 2>/dev/null) BASE_URL="$FIRMWARE_PUBLIC" fi if [ -z "$MANIFEST" ]; then logger -t parahub-update "Failed to fetch manifest" exit 1 fi # Parse manifest with jsonfilter NEW_VERSION=$(echo "$MANIFEST" | jsonfilter -e '$.version' 2>/dev/null) SYSUPGRADE_FILE=$(echo "$MANIFEST" | jsonfilter -e "$.devices.${DEVICE_PROFILE}.sysupgrade" 2>/dev/null) EXPECTED_SHA256=$(echo "$MANIFEST" | jsonfilter -e "$.devices.${DEVICE_PROFILE}.sha256" 2>/dev/null) if [ -z "$NEW_VERSION" ]; then logger -t parahub-update "Could not parse version from manifest" exit 1 fi if [ -z "$SYSUPGRADE_FILE" ] || [ -z "$EXPECTED_SHA256" ]; then logger -t parahub-update "Device ${DEVICE_PROFILE} not found in manifest" exit 0 fi # Compare versions if [ "$CURRENT_VERSION" = "$NEW_VERSION" ]; then logger -t parahub-update "Already up to date: ${CURRENT_VERSION}" exit 0 fi logger -t parahub-update "Update available: ${CURRENT_VERSION} → ${NEW_VERSION}" # Download firmware FIRMWARE_PATH="/tmp/firmware.bin" rm -f "$FIRMWARE_PATH" curl -s -m 600 -o "$FIRMWARE_PATH" "${BASE_URL}/${SYSUPGRADE_FILE}" 2>/dev/null if [ ! -f "$FIRMWARE_PATH" ]; then logger -t parahub-update "Download failed: ${SYSUPGRADE_FILE}" exit 1 fi # Verify SHA256 ACTUAL_SHA256=$(sha256sum "$FIRMWARE_PATH" | cut -d' ' -f1) if [ "$ACTUAL_SHA256" != "$EXPECTED_SHA256" ]; then logger -t parahub-update "SHA256 mismatch! Expected: ${EXPECTED_SHA256}, Got: ${ACTUAL_SHA256}" rm -f "$FIRMWARE_PATH" exit 1 fi logger -t parahub-update "SHA256 verified, starting sysupgrade to ${NEW_VERSION}..." # Run sysupgrade (preserves /etc/config/ by default + /etc/sysupgrade.conf entries) sysupgrade "$FIRMWARE_PATH"