Hi,
Not sure if that's useful to someone else
but I spent all day making this script
I tested it against my tplink archer c7 and netgear wax202 and both worked
Here it is updating my archer c7
And here is the script itself
RED="\033[1;31m"; GREEN="\033[1;32m"; YELLOW="\033[1;33m"; BLUE="\033[1;34m"; NC="\033[0m"
abort() { echo -e "${RED}ERROR:${NC} $1"; echo -e "${RED}Aborting safely.${NC}"; return 1; }
get_latest_version() { LATEST_VERSION=$(wget -qO- https://downloads.openwrt.org/releases/ | grep -oE 'href="[0-9]+\.[0-9]+\.[0-9]+/' | cut -d'"' -f2 | tr -d '/' | sort -Vu | tail -n1); [ -n "$LATEST_VERSION" ] || abort "Failed to fetch latest OpenWrt version" || return; echo -e "${BLUE}Latest OpenWrt:${NC} $LATEST_VERSION"; }
get_previous_version() { PREV_VERSION=$(wget -qO- https://downloads.openwrt.org/releases/ | grep -oE 'href="[0-9]+\.[0-9]+\.[0-9]+/' | cut -d'"' -f2 | tr -d '/' | sort -Vu | awk -v cur="$LATEST_VERSION" '$0==cur{print prev; exit}{prev=$0}'); }
step_back_version() { get_previous_version >/dev/null || return; [ -n "$PREV_VERSION" ] || { echo -e "${RED}No older versions available${NC}"; return 1; }; LATEST_VERSION="$PREV_VERSION"; echo -e "${YELLOW}Stepped back to:${NC} $LATEST_VERSION"; }
get_board_pattern() { B="$1"; FULL=$(echo "$B"|tr , _); SHORT=$(echo "$B"|cut -d, -f2); BOARD_PATTERN="$FULL|${SHORT}"; }
parse_board_json() { TARGET_RAW=$(echo "$1"|grep '"target"'|cut -d'"' -f4); BOARD_RAW=$(echo "$1"|grep '"board_name"'|cut -d'"' -f4); }
get_board_info() { BOARD_JSON=$(ubus call system board 2>/dev/null) || return 1; parse_board_json "$BOARD_JSON"; if [ -n "$DEVICE_OVERRIDE" ]; then TARGET=$(echo "$DEVICE_OVERRIDE"|cut -d/ -f1-2); BOARD=$(echo "$DEVICE_OVERRIDE"|cut -d/ -f3); echo -e "${YELLOW}Using DEVICE override:${NC} $DEVICE_OVERRIDE"; else TARGET="$TARGET_RAW"; BOARD="$BOARD_RAW"; fi; get_board_pattern "$BOARD"; echo -e "${BLUE}Detected board:${NC} $BOARD"; }
get_router_ip() { ROUTER_IP=$(uci get network.lan.ipaddr 2>/dev/null); echo "${ROUTER_IP:-192.168.1.1}"; }
check_board() { DEVICE_MISMATCH=0; [ -z "$DEVICE_OVERRIDE" ] && return 0; ACTUAL="${TARGET_RAW}/${BOARD_RAW}"; echo "$ACTUAL" | grep -q "$DEVICE_OVERRIDE" || { DEVICE_MISMATCH=1; echo -e "${RED}WARNING:${NC} Device mismatch: expected '$DEVICE_OVERRIDE' but running on '$ACTUAL'"; }; }
check_memory() { FREE_MEM=$(awk '/MemAvailable/ {print int($2/1024)}' /proc/meminfo); REQ=${MIN_RAM_MB:-24}; echo -e "${BLUE}Available memory:${NC} ${FREE_MEM} MB (required: ${REQ} MB)"; [ "$FREE_MEM" -ge "$REQ" ] || abort "Not enough RAM (need ~${REQ}MB)" || return; }
build_base_url() { BASE_URL="https://downloads.openwrt.org/releases/$LATEST_VERSION/targets/$TARGET"; }
build_firmware_url() { build_base_url; FIRMWARE_NAME=$(grep -E "\*openwrt-.*-(${BOARD_PATTERN})-.*sysupgrade\.bin$" /tmp/sha256sums | head -n1 | sed 's/^.*\*//'); [ -n "$FIRMWARE_NAME" ] || { echo -e "${RED}No matching firmware found${NC}"; return 1; }; FIRMWARE_URL="$BASE_URL/$FIRMWARE_NAME"; FIRMWARE_FILE="/tmp/$FIRMWARE_NAME"; echo -e "${BLUE}Firmware URL:${NC} $FIRMWARE_URL"; echo -e "${BLUE}Firmware file:${NC} $FIRMWARE_FILE"; }
fetch_sha256sums() { [ -n "$LATEST_VERSION" ] && [ -n "$TARGET" ] || { echo -e "${RED}Missing TARGET or VERSION${NC}"; return 1; }; build_base_url; SHA_FILE="/tmp/sha256sums"; echo -e "${BLUE}Fetching sha256sums...${NC}"; wget -qO "$SHA_FILE" "$BASE_URL/sha256sums" || { echo -e "${RED}Failed to download sha256sums${NC}"; return 1; }; [ -s "$SHA_FILE" ] || { echo -e "${RED}sha256sums is empty${NC}"; return 1; }; }
prepare_override() { LATEST_VERSION="$VERSION_OVERRIDE"; echo -e "${BLUE}Using version override:${NC} $LATEST_VERSION"; fetch_sha256sums && build_firmware_url; }
prepare_firmware() { if [ -n "$VERSION_OVERRIDE" ]; then prepare_override || abort "Firmware not found for override version" || return; return 0; fi; get_latest_version || return; while :; do fetch_sha256sums || return; build_firmware_url && return 0; echo -e "${YELLOW}Not found for $LATEST_VERSION, trying previous...${NC}"; step_back_version || abort "No compatible firmware found" || return; done; }
download_files() { for i in 1 2 3; do echo -e "${BLUE}Downloading $FIRMWARE_NAME (attempt $i)...${NC}"; wget -O "$FIRMWARE_FILE" "$FIRMWARE_URL" && return 0; [ "$i" -lt 3 ] && { echo -e "${YELLOW}Retrying in 5s...${NC}"; sleep 5; }; done; abort "Download failed: $FIRMWARE_URL" || return; }
verify_checksum() { [ -f /tmp/sha256sums ] || abort "Missing sha256sums file" || return; EXPECTED=$(grep "\*$FIRMWARE_NAME\$" /tmp/sha256sums | cut -d' ' -f1); [ -n "$EXPECTED" ] || abort "Checksum entry not found" || return; ACTUAL=$(sha256sum "$FIRMWARE_FILE" | cut -d' ' -f1); [ "$EXPECTED" = "$ACTUAL" ] || abort "Checksum failed" || return; echo -e "${GREEN}Checksum OK ✔${NC}"; }
backup_config() { [ "$DO_BACKUP" = "0" ] && { echo -e "${YELLOW}Skipping backup${NC}"; return 0; }; sysupgrade -b /tmp/backup.tar.gz || abort "Backup failed" || return; ROUTER_IP=$(get_router_ip); echo -e "${GREEN}Backup saved:${NC} /tmp/backup.tar.gz"; echo -e "${GREEN}scp root@${ROUTER_IP}:/tmp/backup.tar.gz .${NC}"; printf "Press ENTER to continue... "; read _; }
print_backup_info() { [ -n "$ROUTER_IP" ] || ROUTER_IP=$(get_router_ip); echo -e "${BLUE}Backup file:${NC} /tmp/backup.tar.gz\n${YELLOW}IMPORTANT:${NC} This file will be LOST after reboot.\nDownload it now if you want to keep it:\n${GREEN}scp root@${ROUTER_IP}:/tmp/backup.tar.gz .${NC}"; }
print_confirmation() { [ "$DO_BACKUP" = "0" ] && BS="no" || BS="yes"; echo -e "${YELLOW}==== CONFIRMATION ====${NC}"; [ "${DEVICE_MISMATCH:-0}" -eq 1 ] && echo -e "${RED}WARNING:${NC} DEVICE OVERRIDE does NOT match this hardware!"; echo -e "Version: ${GREEN}$LATEST_VERSION${NC}\nFirmware: $FIRMWARE_URL\nWipe settings: ${WIPE_SETTINGS:-0}\nBackup: $BS\nDry run: ${DRY_RUN:-0}"; [ "$DO_BACKUP" != "0" ] && print_backup_info; }
confirm_interactive() { print_confirmation; [ "$INTERACTIVE" = "0" ] && return 0; echo -e "${YELLOW}Type 'proceed' to continue:${NC}"; read ans || return 1; [ "$ans" = "proceed" ] || { echo -e "${RED}Aborted by user${NC}"; return 1; }; }
run_upgrade() { [ "$WIPE_SETTINGS" = "1" ] && FLAG="-n" || FLAG=""; echo -e "${BLUE}Upgrade mode:${NC} WIPE=${WIPE_SETTINGS:-0} DRY_RUN=${DRY_RUN:-0}"; confirm_interactive || return; [ "$DRY_RUN" = "1" ] && { echo -e "${YELLOW}DRY RUN: skipping sysupgrade${NC}"; return 0; }; sleep 2; sysupgrade $FLAG -v "$FIRMWARE_FILE"; }
run() { get_board_info || abort "Failed to get board info" || return; check_board || return; prepare_firmware || return; check_memory || return; echo -e "${BLUE}Firmware file:${NC} $FIRMWARE_FILE"; download_files || return; verify_checksum || return; backup_config || return; run_upgrade; }
# overrides
# DEVICE_OVERRIDE="ar71xx/tiny/tplink,tl-wa901nd-v2"
# DEVICE_OVERRIDE="ath79/generic/tplink,archer-c7-v2"
# DEVICE_OVERRIDE="ath79/generic/tplink,archer-c7-v4"
# VERSION_OVERRIDE="18.06.9"
# Setting toggles
# MIN_RAM_MB=24 # optional: abort if less than specified ram amount, default 24
# EXPECTED_BOARD="netgear,wax202" # optional: limit upgrade to specified board otherwise abort
# WIPE_SETTINGS=1 # optional: wipe config
# DO_BACKUP=0 # optional: skip backup
# INTERACTIVE=0 # optional: disable prompts and update fully automatically
# DRY_RUN=1
run
Alternate url for script