diff --git a/.claude/settings.local.json b/.claude/settings.local.json index aa3fff8e..77289ce1 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -122,7 +122,24 @@ "Bash(gh run:*)", "Bash(dig:*)", "Bash(nslookup:*)", - "Bash(host:*)" + "Bash(host:*)", + "Bash(git fetch:*)", + "Bash(/home/reepost/CyberMindStudio/secubox-openwrt/secubox-tools/deploy-remote.sh:*)", + "Bash(for i in 1 2 3 4 5)", + "Bash(do echo \"Attempt $i...\")", + "Bash(if ssh -o ConnectTimeout=10 root@192.168.255.1 'echo \"\"Connected\"\"; df -h /')", + "Bash(then break)", + "Bash(fi)", + "Bash(done)", + "Bash(for i in 1 2 3 4 5 6)", + "Bash(do echo \"Checking... \\($i\\)\")", + "Bash(if ssh -o ConnectTimeout=10 root@192.168.255.1 'df -h / /overlay 2>/dev/null')", + "Bash(./secubox-tools/deploy-remote.sh:*)", + "Bash(do)", + "Bash(if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.255.1 \"echo ''Router is back!''\")", + "Bash(then)", + "Bash(exit 0)", + "Bash(if ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no root@192.168.255.1 \"echo ''Router online!''\")" ] } } diff --git a/package/secubox/secubox-core/files/etc/init.d/secubox-extroot b/package/secubox/secubox-core/files/etc/init.d/secubox-extroot new file mode 100755 index 00000000..1af5c972 --- /dev/null +++ b/package/secubox/secubox-core/files/etc/init.d/secubox-extroot @@ -0,0 +1,235 @@ +#!/bin/sh /etc/rc.common +# SecuBox Extroot Auto-Setup +# Automatically configures overlay on mmcblk0p3 after fresh install/upgrade +# Copyright (C) 2025 CyberMind.fr + +START=10 +STOP=90 + +EXTRA_COMMANDS="status setup" +EXTRA_HELP=" status Show extroot status + setup Configure extroot on mmcblk0p3" + +OVERLAY_DEV="/dev/mmcblk0p3" +OVERLAY_LABEL="rootfs_data" +LOG_TAG="secubox-extroot" + +log() { logger -t "$LOG_TAG" "$*"; echo "$*"; } + +# Check if extroot is already active +is_extroot_active() { + mount | grep -q "on /overlay type" && [ -d /overlay/upper ] +} + +# Check if overlay partition exists +has_overlay_partition() { + [ -b "$OVERLAY_DEV" ] || return 1 + blkid "$OVERLAY_DEV" >/dev/null 2>&1 +} + +# Get filesystem type of overlay partition +get_overlay_fstype() { + blkid "$OVERLAY_DEV" -s TYPE -o value 2>/dev/null +} + +# Get UUID of overlay partition +get_overlay_uuid() { + blkid "$OVERLAY_DEV" -s UUID -o value 2>/dev/null +} + +# Install required filesystem support +install_fs_support() { + local fstype="$1" + + case "$fstype" in + f2fs) + if ! opkg list-installed 2>/dev/null | grep -q "^kmod-fs-f2fs"; then + log "Installing f2fs support..." + opkg update >/dev/null 2>&1 + opkg install kmod-fs-f2fs f2fs-tools 2>/dev/null || true + fi + ;; + ext4) + if ! opkg list-installed 2>/dev/null | grep -q "^kmod-fs-ext4"; then + log "Installing ext4 support..." + opkg update >/dev/null 2>&1 + opkg install kmod-fs-ext4 e2fsprogs 2>/dev/null || true + fi + ;; + esac + + # Always ensure block-mount is available + if ! opkg list-installed 2>/dev/null | grep -q "^block-mount"; then + log "Installing block-mount..." + opkg install block-mount 2>/dev/null || true + fi +} + +# Prepare overlay partition structure +prepare_overlay() { + local fstype="$1" + local mount_point="/tmp/extroot_setup" + + mkdir -p "$mount_point" + + # Mount the partition + if ! mount -t "$fstype" "$OVERLAY_DEV" "$mount_point" 2>/dev/null; then + log "Failed to mount $OVERLAY_DEV" + return 1 + fi + + # Create overlay directories + mkdir -p "$mount_point/upper" + mkdir -p "$mount_point/work" + + # Copy existing data if overlay was previously active + if [ -d /overlay/upper ] && [ "$(ls -A /overlay/upper 2>/dev/null)" ]; then + log "Migrating existing overlay data..." + cp -a /overlay/upper/* "$mount_point/upper/" 2>/dev/null || true + fi + + sync + umount "$mount_point" + rmdir "$mount_point" + + return 0 +} + +# Configure fstab for extroot +configure_fstab() { + local uuid="$1" + local fstype="$2" + + # Check if already configured + if uci -q get fstab.extroot >/dev/null 2>&1; then + local current_uuid=$(uci -q get fstab.extroot.uuid) + if [ "$current_uuid" = "$uuid" ]; then + log "Extroot already configured" + return 0 + fi + fi + + log "Configuring fstab for extroot..." + + # Remove old extroot config if exists + uci -q delete fstab.extroot 2>/dev/null || true + + # Add new extroot configuration + uci set fstab.extroot=mount + uci set fstab.extroot.target="/overlay" + uci set fstab.extroot.uuid="$uuid" + uci set fstab.extroot.enabled="1" + + if [ "$fstype" = "f2fs" ]; then + uci set fstab.extroot.fstype="f2fs" + uci set fstab.extroot.options="rw,noatime" + fi + + uci commit fstab + + log "Fstab configured - reboot required to activate" + return 0 +} + +# Main setup function +setup_extroot() { + log "SecuBox Extroot Setup starting..." + + # Check if already active + if is_extroot_active; then + log "Extroot already active on /overlay" + df -h /overlay | tail -1 + return 0 + fi + + # Check for overlay partition + if ! has_overlay_partition; then + log "No overlay partition found at $OVERLAY_DEV" + return 1 + fi + + # Get filesystem info + local fstype=$(get_overlay_fstype) + local uuid=$(get_overlay_uuid) + + if [ -z "$fstype" ] || [ -z "$uuid" ]; then + log "Cannot determine filesystem type or UUID" + return 1 + fi + + log "Found overlay partition: $OVERLAY_DEV ($fstype, UUID=$uuid)" + + # Install filesystem support + install_fs_support "$fstype" + + # Prepare the partition + if ! prepare_overlay "$fstype"; then + log "Failed to prepare overlay partition" + return 1 + fi + + # Configure fstab + if ! configure_fstab "$uuid" "$fstype"; then + log "Failed to configure fstab" + return 1 + fi + + log "Extroot setup complete - REBOOT REQUIRED" + + # Create flag file to indicate reboot needed + touch /tmp/extroot-reboot-required + + return 0 +} + +start() { + # Only run setup if not already configured or after upgrade + if is_extroot_active; then + log "Extroot active" + return 0 + fi + + if has_overlay_partition; then + setup_extroot + fi +} + +stop() { + return 0 +} + +boot() { + start +} + +# Manual commands +status() { + echo "=== SecuBox Extroot Status ===" + echo "" + + if is_extroot_active; then + echo "Status: ACTIVE" + echo "" + echo "Overlay mount:" + mount | grep overlay + echo "" + echo "Storage:" + df -h /overlay + else + echo "Status: NOT ACTIVE" + echo "" + if has_overlay_partition; then + echo "Overlay partition available: $OVERLAY_DEV" + echo "Filesystem: $(get_overlay_fstype)" + echo "UUID: $(get_overlay_uuid)" + echo "" + echo "Run '/etc/init.d/secubox-extroot setup' to configure" + else + echo "No overlay partition found" + fi + fi +} + +setup() { + setup_extroot +} diff --git a/secubox-tools/deploy-extroot-init.sh b/secubox-tools/deploy-extroot-init.sh new file mode 100755 index 00000000..cbefef54 --- /dev/null +++ b/secubox-tools/deploy-extroot-init.sh @@ -0,0 +1,23 @@ +#!/bin/bash +# Deploy SecuBox Extroot init.d script to router +# Usage: ./deploy-extroot-init.sh [ROUTER_IP] + +ROUTER_IP="${1:-192.168.255.1}" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +echo "Deploying secubox-extroot to $ROUTER_IP..." + +# Deploy the init script +cat "$SCRIPT_DIR/../package/secubox/secubox-core/files/etc/init.d/secubox-extroot" | \ +ssh root@$ROUTER_IP 'cat > /etc/init.d/secubox-extroot && chmod 755 /etc/init.d/secubox-extroot' + +# Enable and run setup +ssh root@$ROUTER_IP ' +/etc/init.d/secubox-extroot enable +/etc/init.d/secubox-extroot setup +/etc/init.d/secubox-extroot status +' + +echo "" +echo "Done! If setup was successful, reboot to activate extroot:" +echo " ssh root@$ROUTER_IP reboot" diff --git a/secubox-tools/deploy-remote.sh b/secubox-tools/deploy-remote.sh new file mode 100755 index 00000000..f011f492 --- /dev/null +++ b/secubox-tools/deploy-remote.sh @@ -0,0 +1,226 @@ +#!/bin/bash +# SecuBox Remote Deployment Script +# Deploys all SecuBox packages to a remote OpenWrt router + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" +BUILD_DIR="$SCRIPT_DIR/sdk/bin/packages/aarch64_cortex-a72/secubox" +ROUTER_IP="${1:-192.168.255.1}" +ROUTER_USER="${2:-root}" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +info() { echo -e "${BLUE}ℹ️ $*${NC}"; } +success() { echo -e "${GREEN}✅ $*${NC}"; } +warn() { echo -e "${YELLOW}⚠️ $*${NC}"; } +error() { echo -e "${RED}❌ $*${NC}"; exit 1; } + +# Check SSH connectivity +check_ssh() { + info "Checking SSH connectivity to $ROUTER_IP..." + if ! ssh -o ConnectTimeout=10 "$ROUTER_USER@$ROUTER_IP" "echo ok" 2>/dev/null; then + error "Cannot connect to $ROUTER_IP via SSH" + fi + success "SSH connection OK" +} + +# Setup local feed on router +setup_feed() { + info "Setting up local package feed on router..." + + ssh "$ROUTER_USER@$ROUTER_IP" 'mkdir -p /www/secubox-feed /tmp/secubox-install' + + # Copy packages + info "Copying packages to router (this may take a while)..." + scp -q "$BUILD_DIR"/*.ipk "$ROUTER_USER@$ROUTER_IP:/www/secubox-feed/" 2>/dev/null || true + + # Generate Packages index + info "Generating package index..." + ssh "$ROUTER_USER@$ROUTER_IP" 'cd /www/secubox-feed && { + rm -f Packages Packages.gz + for ipk in *.ipk; do + [ -f "$ipk" ] || continue + tar -xOzf "$ipk" ./control.tar.gz 2>/dev/null | tar -xOz ./control 2>/dev/null >> Packages + echo "Filename: $ipk" >> Packages + echo "" >> Packages + done + gzip -k Packages + }' + + # Configure opkg + ssh "$ROUTER_USER@$ROUTER_IP" 'grep -q "secubox-feed" /etc/opkg/customfeeds.conf 2>/dev/null || { + echo "src/gz secubox file:///www/secubox-feed" >> /etc/opkg/customfeeds.conf + }' + + success "Local feed configured" +} + +# Install core packages first +install_core() { + info "Installing core SecuBox packages..." + + ssh "$ROUTER_USER@$ROUTER_IP" 'opkg update 2>/dev/null + + # Core packages (order matters) + for pkg in secubox-core; do + if [ -f "/www/secubox-feed/${pkg}_"*.ipk ]; then + echo "Installing $pkg..." + opkg install --force-reinstall /www/secubox-feed/${pkg}_*.ipk 2>&1 || true + fi + done' + + success "Core packages installed" +} + +# Install LuCI apps +install_luci_apps() { + info "Installing LuCI applications..." + + ssh "$ROUTER_USER@$ROUTER_IP" ' + cd /www/secubox-feed + + # Skip large bonus package and packages with missing deps + SKIP="secubox-bonus|auth-guardian|ksm-manager|vhost-manager|zigbee" + + for ipk in luci-app-*.ipk; do + [ -f "$ipk" ] || continue + + # Skip excluded packages + if echo "$ipk" | grep -qE "$SKIP"; then + echo "Skipping: $ipk (excluded)" + continue + fi + + pkg_name=$(echo "$ipk" | sed "s/_[0-9].*//") + echo "Installing: $pkg_name" + opkg install --force-reinstall "/www/secubox-feed/$ipk" 2>&1 | grep -v "^Collected" || true + done' + + success "LuCI apps installed" +} + +# Install service packages +install_services() { + info "Installing service packages..." + + ssh "$ROUTER_USER@$ROUTER_IP" ' + cd /www/secubox-feed + + for ipk in secubox-app-*.ipk; do + [ -f "$ipk" ] || continue + + pkg_name=$(echo "$ipk" | sed "s/_[0-9].*//") + echo "Installing: $pkg_name" + opkg install --force-reinstall "/www/secubox-feed/$ipk" 2>&1 | grep -v "^Collected" || true + done' + + success "Service packages installed" +} + +# Fix permissions and restart services +finalize() { + info "Finalizing installation..." + + ssh "$ROUTER_USER@$ROUTER_IP" ' + # Fix RPCD script permissions + chmod 755 /usr/libexec/rpcd/luci.* 2>/dev/null || true + + # Restart rpcd + /etc/init.d/rpcd restart + + # Clear LuCI cache + rm -rf /tmp/luci-modulecache /tmp/luci-indexcache 2>/dev/null + + # Show installed packages + echo "" + echo "=== Installed SecuBox packages ===" + opkg list-installed | grep -E "^(luci-app-|secubox-)" | wc -l + echo "packages installed" + ' + + success "Installation complete!" +} + +# Generate apps-local.json for store UI +generate_apps_json() { + info "Generating apps manifest..." + + ssh "$ROUTER_USER@$ROUTER_IP" 'cd /www/secubox-feed && { + cat > apps-local.json << "HEADER" +{ + "feed_url": "/secubox-feed", + "generated": "TIMESTAMP", + "packages": [ +HEADER + sed -i "s/TIMESTAMP/$(date -Iseconds)/" apps-local.json + + first=true + for pkg in *.ipk; do + [ -f "$pkg" ] || continue + filename="$pkg" + name=$(echo "$filename" | sed "s/_[0-9].*$//") + version=$(echo "$filename" | sed "s/^[^_]*_//; s/_[^_]*$//") + size=$(stat -c%s "$pkg" 2>/dev/null || ls -l "$pkg" | awk "{print \$5}") + + # Category based on name + category="utility" + case "$name" in + *crowdsec*|*mitmproxy*|*tor*) category="security";; + *bandwidth*|*traffic*|*network*|*wireguard*) category="network";; + *hexojs*|*gitea*|*streamlit*) category="apps";; + *secubox*) category="system";; + esac + + [ "$first" = "true" ] || echo "," >> apps-local.json + first=false + + cat >> apps-local.json << ENTRY + { + "name": "$name", + "version": "$version", + "filename": "$filename", + "size": $size, + "category": "$category" + } +ENTRY + done + + echo " ]" >> apps-local.json + echo "}" >> apps-local.json + }' + + success "Apps manifest generated" +} + +# Main +main() { + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo " SecuBox Remote Deployment" + echo " Target: $ROUTER_USER@$ROUTER_IP" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + echo "" + + check_ssh + setup_feed + install_core + install_services + install_luci_apps + generate_apps_json + finalize + + echo "" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + success "Deployment complete!" + echo " Access LuCI at: http://$ROUTER_IP" + echo " Local feed at: http://$ROUTER_IP/secubox-feed/" + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +} + +main "$@" diff --git a/secubox-tools/fix-extroot.sh b/secubox-tools/fix-extroot.sh new file mode 100755 index 00000000..04978f34 --- /dev/null +++ b/secubox-tools/fix-extroot.sh @@ -0,0 +1,85 @@ +#!/bin/sh +# Fix extroot by formatting mmcblk0p3 fresh +# Run this from console or SSH after failsafe boot + +OVERLAY_DEV="/dev/mmcblk0p3" + +echo "=== SecuBox Extroot Fix ===" +echo "" + +# Stop services using overlay +echo "Stopping services..." +for svc in /etc/init.d/*; do + [ -x "$svc" ] && "$svc" stop 2>/dev/null & +done +sleep 3 + +# Kill processes using overlay +echo "Killing processes using overlay..." +fuser -km /overlay 2>/dev/null || true +sleep 2 + +# Unmount everything +echo "Unmounting filesystems..." +umount -l /overlay 2>/dev/null || true +umount -l /mnt/extroot 2>/dev/null || true +umount -l "$OVERLAY_DEV" 2>/dev/null || true +sync +sleep 2 + +# Verify unmounted +if mount | grep -q "$OVERLAY_DEV"; then + echo "ERROR: Cannot unmount $OVERLAY_DEV" + echo "Try: reboot into failsafe mode and run this script" + exit 1 +fi + +echo "" +echo "Formatting $OVERLAY_DEV as f2fs..." +mkfs.f2fs -f -l rootfs_data "$OVERLAY_DEV" || { + echo "Format failed! Try: mkfs.ext4 -L rootfs_data $OVERLAY_DEV" + exit 1 +} + +echo "" +echo "Preparing overlay structure..." +mkdir -p /mnt/extroot +mount -t f2fs "$OVERLAY_DEV" /mnt/extroot +mkdir -p /mnt/extroot/upper /mnt/extroot/work +sync +umount /mnt/extroot + +echo "" +echo "Configuring fstab..." +UUID=$(blkid "$OVERLAY_DEV" -s UUID -o value) +echo "UUID: $UUID" + +# Write fstab config +cat > /etc/config/fstab << EOF +config global + option anon_swap '0' + option anon_mount '0' + option auto_swap '0' + option auto_mount '1' + option delay_root '5' + option check_fs '1' + +config mount 'extroot' + option target '/overlay' + option uuid '$UUID' + option enabled '1' + option fstype 'f2fs' + option options 'rw,noatime' + +config mount 'srv' + option target '/srv' + option uuid '443e8304-4d3b-4fd0-9f26-74c50ba64113' + option enabled '1' +EOF + +echo "" +echo "=== Setup complete ===" +echo "" +cat /etc/config/fstab +echo "" +echo "Now reboot: reboot" diff --git a/secubox-tools/setup-extroot.sh b/secubox-tools/setup-extroot.sh new file mode 100755 index 00000000..b59a5b95 --- /dev/null +++ b/secubox-tools/setup-extroot.sh @@ -0,0 +1,176 @@ +#!/bin/bash +# SecuBox Extroot Setup Script +# Configures overlay on mmcblk0p3 for expanded storage +# Run after fresh install or upgrade + +ROUTER_IP="${1:-192.168.255.1}" +ROUTER_USER="${2:-root}" + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' + +info() { echo -e "${BLUE}ℹ️ $*${NC}"; } +success() { echo -e "${GREEN}✅ $*${NC}"; } +warn() { echo -e "${YELLOW}⚠️ $*${NC}"; } +error() { echo -e "${RED}❌ $*${NC}"; } + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo " SecuBox Extroot Setup" +echo " Target: $ROUTER_USER@$ROUTER_IP" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +info "Connecting to router..." + +ssh "$ROUTER_USER@$ROUTER_IP" ' +#!/bin/sh +# Extroot setup script - runs on router + +set -e + +OVERLAY_DEV="/dev/mmcblk0p3" +OVERLAY_MOUNT="/mnt/extroot" + +echo "=== Checking current setup ===" +echo "Root filesystem:" +df -h / +echo "" + +# Check if overlay already mounted +if mount | grep -q "overlay on / "; then + echo "Overlay already active!" + df -h /overlay + exit 0 +fi + +# Check if partition exists +if [ ! -b "$OVERLAY_DEV" ]; then + echo "ERROR: Partition $OVERLAY_DEV not found" + exit 1 +fi + +# Get partition info +FSTYPE=$(blkid "$OVERLAY_DEV" -s TYPE -o value 2>/dev/null || echo "unknown") +echo "Partition: $OVERLAY_DEV" +echo "Filesystem: $FSTYPE" +echo "" + +# Install required packages if not present +echo "=== Checking required packages ===" +opkg update 2>/dev/null || true + +if [ "$FSTYPE" = "f2fs" ]; then + if ! opkg list-installed | grep -q "^kmod-fs-f2fs"; then + echo "Installing f2fs support..." + opkg install kmod-fs-f2fs f2fs-tools 2>/dev/null || true + fi +elif [ "$FSTYPE" = "ext4" ]; then + if ! opkg list-installed | grep -q "^kmod-fs-ext4"; then + echo "Installing ext4 support..." + opkg install kmod-fs-ext4 e2fsprogs 2>/dev/null || true + fi +fi + +# Ensure block-mount is installed +if ! opkg list-installed | grep -q "^block-mount"; then + echo "Installing block-mount..." + opkg install block-mount 2>/dev/null || true +fi + +echo "" +echo "=== Preparing overlay partition ===" + +# Mount partition temporarily +mkdir -p "$OVERLAY_MOUNT" +mount -t "$FSTYPE" "$OVERLAY_DEV" "$OVERLAY_MOUNT" || { + echo "ERROR: Cannot mount $OVERLAY_DEV" + exit 1 +} + +# Create overlay directories +mkdir -p "$OVERLAY_MOUNT/upper" +mkdir -p "$OVERLAY_MOUNT/work" + +# Copy existing overlay data if any +if [ -d /overlay/upper ]; then + echo "Copying existing overlay data..." + cp -a /overlay/upper/* "$OVERLAY_MOUNT/upper/" 2>/dev/null || true +fi + +# Sync +sync + +# Unmount +umount "$OVERLAY_MOUNT" + +echo "" +echo "=== Configuring fstab ===" + +# Get block info +eval $(block info "$OVERLAY_DEV" | grep -o "UUID=\S*") +echo "UUID: $UUID" + +# Configure fstab using UCI +uci -q delete fstab.extroot 2>/dev/null || true +uci set fstab.extroot=mount +uci set fstab.extroot.target="/overlay" +uci set fstab.extroot.uuid="$UUID" +uci set fstab.extroot.enabled="1" +if [ "$FSTYPE" = "f2fs" ]; then + uci set fstab.extroot.fstype="f2fs" + uci set fstab.extroot.options="rw,noatime" +fi +uci commit fstab + +echo "" +echo "=== Updated fstab ===" +cat /etc/config/fstab + +echo "" +echo "=== Setup complete! ===" +echo "" +echo "IMPORTANT: Reboot to activate the overlay" +echo "After reboot, /overlay will be mounted on the 14GB partition" +echo "" +echo "Run: reboot" +' + +if [ $? -eq 0 ]; then + success "Extroot configuration complete!" + echo "" + warn "REBOOT REQUIRED to activate overlay" + echo "" + read -p "Reboot router now? [y/N] " -n 1 -r + echo + if [[ $REPLY =~ ^[Yy]$ ]]; then + info "Rebooting router..." + ssh "$ROUTER_USER@$ROUTER_IP" "reboot" 2>/dev/null || true + echo "" + info "Waiting for router to come back online..." + sleep 60 + + # Wait for router to come back + for i in {1..30}; do + if ssh -o ConnectTimeout=5 "$ROUTER_USER@$ROUTER_IP" "echo ok" 2>/dev/null; then + success "Router is back online!" + echo "" + ssh "$ROUTER_USER@$ROUTER_IP" ' + echo "=== Overlay status ===" + mount | grep overlay || echo "No overlay (yet)" + echo "" + echo "=== Disk usage ===" + df -h / /overlay 2>/dev/null + ' + break + fi + echo "Waiting... ($i/30)" + sleep 5 + done + fi +else + error "Setup failed" +fi