From 4c94b98292ce0208388dcd03a270e3321f2e7612 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 2 Dec 2025 03:01:14 +0000 Subject: [PATCH 1/9] Bump softprops/action-gh-release in the all-actions group Bumps the all-actions group with 1 update: [softprops/action-gh-release](https://github.com/softprops/action-gh-release). Updates `softprops/action-gh-release` from 2.4.2 to 2.5.0 - [Release notes](https://github.com/softprops/action-gh-release/releases) - [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md) - [Commits](https://github.com/softprops/action-gh-release/compare/v2.4.2...v2.5.0) --- updated-dependencies: - dependency-name: softprops/action-gh-release dependency-version: 2.5.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index 0cd286d9..05693af2 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -85,7 +85,7 @@ jobs: git push origin ${{ steps.nextver.outputs.tag }} - name: Create Release with Automated Release Notes - uses: softprops/action-gh-release@v2.4.2 + uses: softprops/action-gh-release@v2.5.0 with: token: ${{ secrets.GITHUB_TOKEN }} tag_name: ${{ steps.nextver.outputs.tag }} From c029dd96a24695fb185be41df1ebf2b4b158c2c7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 8 Dec 2025 23:11:01 +0000 Subject: [PATCH 2/9] Bump actions/checkout from 6.0.0 to 6.0.1 in the all-actions group Bumps the all-actions group with 1 update: [actions/checkout](https://github.com/actions/checkout). Updates `actions/checkout` from 6.0.0 to 6.0.1 - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v6.0.0...v6.0.1) --- updated-dependencies: - dependency-name: actions/checkout dependency-version: 6.0.1 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: all-actions ... Signed-off-by: dependabot[bot] --- .github/workflows/Create-NewReleases.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/Create-NewReleases.yml b/.github/workflows/Create-NewReleases.yml index 05693af2..fdfd46e7 100644 --- a/.github/workflows/Create-NewReleases.yml +++ b/.github/workflows/Create-NewReleases.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout source code - uses: actions/checkout@v6.0.0 + uses: actions/checkout@v6.0.1 with: fetch-depth: 0 ref: 'main' # Ensure we're tagging the main branch after the merge From bae364025176113bcedff624fc665087954a7f8a Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Tue, 30 Dec 2025 11:38:16 -0500 Subject: [PATCH 3/9] Trigger Webs_update on Nodes 1. Bump Minimum Supported Versions 2. Forcefully Trigger Webs_update on the Nodes 3. Minor Cleanup/Tuning --- MerlinAU.sh | 43 ++++++++++++++++++++++++++++++++++++++----- README.md | 4 ++-- version.txt | 2 +- 3 files changed, 41 insertions(+), 8 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 420f09ad..7af179b7 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -9,8 +9,8 @@ set -u ## Set version for each Production Release ## -readonly SCRIPT_VERSION=1.5.7 -readonly SCRIPT_VERSTAG="25111620" +readonly SCRIPT_VERSION=1.5.8 +readonly SCRIPT_VERSTAG="25123011" readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## SCRIPT_BRANCH="master" @@ -203,8 +203,8 @@ readonly fwInstalledBranchVer="${fwInstalledBaseVers}.$(echo "$fwInstalledBuildV # For minimum supported firmware version check # MinFirmwareVerCheckFailed=false readonly MinSupportedFW_3004_386_Ver="3004.386.13.2" -readonly MinSupportedFW_3004_388_Ver="3004.388.8.4" -readonly MinSupportedFW_3006_102_Ver="3004.388.8.2" +readonly MinSupportedFW_3004_388_Ver="3004.388.10.0" +readonly MinSupportedFW_3006_102_Ver="3006.102.4.0" ##----------------------------------------## ## Modified by Martinski W. [2025-Apr-09] ## @@ -4797,6 +4797,40 @@ _GetNodeInfo_() return 1 fi + ##################################################################### + # Trigger AiMesh node "Check for updates" (mimics UI start_apply.htm) # + ##################################################################### + + curl -s -k "${NodeURLstr}/start_apply.htm" \ + --referer "${NodeURLstr}/Advanced_FirmwareUpgrade_Content.asp" \ + --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H "Origin: ${NodeURLstr}" \ + -H 'Connection: keep-alive' \ + --data "current_page=Advanced_FirmwareUpgrade_Content.asp" \ + --data "next_page=Advanced_FirmwareUpgrade_Content.asp" \ + --data "flag=liveUpdate" \ + --data "action_mode=apply" \ + --data "action_script=start_webs_update" \ + --data "action_wait=webs_update_trigger" \ + --cookie '/tmp/nodecookies.txt' \ + --max-time 3 > /tmp/node_fwcheck_trigger.txt 2>&1 + + # UI waits ~10s before querying status; give node a moment to update nvram/status + waitSeconds=8 + waitMsg="Please wait while we query the node for update status" + printf "\n" + idx=0 + while [ "$idx" -lt "$waitSeconds" ] + do + printf "\r%s (%ds)" "$waitMsg" "$((waitSeconds - idx))" + sleep 1 + idx=$((idx + 1)) + done + printf "\r%s Done. \n" + # Retrieve the HTML content # htmlContent="$(curl -s -k "${NodeURLstr}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(asus_device_list)%3bnvram_get(cfg_device_list)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(odmpid)%3bnvram_get(wps_modelnum)%3bnvram_get(model)%3bnvram_get(build_name)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ @@ -9091,7 +9125,6 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or Say "Please fix the BACKUPMON configuration, or consider uninstalling it to proceed flash.\n" Say "Resolving the BACKUPMON configuration is HIGHLY recommended for safety of the upgrade.\n" "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" - _Reset_LEDs_ return 1 fi diff --git a/README.md b/README.md index 5236d0e9..af54b608 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # MerlinAU - AsusWRT-Merlin Firmware Auto Updater -## v1.5.7 -## 2025-Nov-25 +## v1.5.8 +## 2025-Dec-30 ## WebUI: ![image](https://github.com/user-attachments/assets/9c1dff99-9c13-491b-a7fa-aff924d5f02e) diff --git a/version.txt b/version.txt index f01291b8..1cc9c180 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -1.5.7 +1.5.8 From 5e125e251144b8c71801668fec456f549c98541d Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Tue, 30 Dec 2025 20:58:48 -0500 Subject: [PATCH 4/9] Parallel Node Processing Parallel Node Processing. This should speed up the checking of nodes to a single 8 second wait. --- MerlinAU.sh | 283 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 214 insertions(+), 69 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 7af179b7..76a0effe 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4,7 +4,7 @@ # # Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. # Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Nov-16 +# Last Modified: 2025-Dec-30 ################################################################### set -u @@ -198,7 +198,7 @@ readonly fwInstalledInnerVers="$(nvram get innerver)" readonly fwInstalledBranchVer="${fwInstalledBaseVers}.$(echo "$fwInstalledBuildVers" | awk -F'.' '{print $1}')" ##------------------------------------------## -## Modified by ExtremeFiretop [2025-Apr-09] ## +## Modified by ExtremeFiretop [2025-Dec-30] ## ##------------------------------------------## # For minimum supported firmware version check # MinFirmwareVerCheckFailed=false @@ -4719,6 +4719,14 @@ _Populate_Node_Settings_() Update_Custom_Settings "${nodeKeyPrefix}New_Notification_Vers" "$update_vers" } +##---------------------------------------## +## Added by ExtremeFiretop [2025-Dec-30] ## +##---------------------------------------## +# Make an IP safe for filenames +_MeshSafeID_() { + printf "%s" "$1" | tr '.:' '__' +} + ##---------------------------------------## ## Added by ExtremeFiretop [2024-Mar-26] ## ##---------------------------------------## @@ -4743,13 +4751,95 @@ _GetNodeURL_() echo "${urlProto}://${NodeIP_Address}${urlPort}" } +##---------------------------------------## +## Added by ExtremeFiretop [2025-Dec-30] ## +##---------------------------------------## +# Trigger the node "Check for updates" (no waiting here) +_MeshNodeTriggerFWCheck_() { + local NodeIP_Address="$1" + local runid="$2" + local safe_id="$(_MeshSafeID_ "$NodeIP_Address")" + local NodeURLstr="$(_GetNodeURL_ "$NodeIP_Address")" + local cookieFile="/tmp/${runid}.${safe_id}.cookie" + + ## Check for Login Credentials ## + credsBase64="$(Get_Custom_Setting credentials_base64)" + if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] + then + _UpdateLoginPswdCheckHelper_ InitPWD + Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." + "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" + return 1 + fi + + # Perform login request # + curl -s -k "${NodeURLstr}/login.cgi" \ + --referer "${NodeURLstr}/Main_Login.asp" \ + --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H "Origin: ${NodeURLstr}" \ + -H 'Connection: keep-alive' \ + --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ + --cookie-jar "$cookieFile" \ + --max-time 2 >/dev/null 2>&1 || return 1 + + # Trigger firmware check (mimic WebUI "Check" button) + curl -s -k "${NodeURLstr}/start_apply.htm" \ + --referer "${NodeURLstr}/Advanced_FirmwareUpgrade_Content.asp" \ + --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H "Origin: ${NodeURLstr}" \ + -H 'Connection: keep-alive' \ + --data "current_page=Advanced_FirmwareUpgrade_Content.asp" \ + --data "next_page=Advanced_FirmwareUpgrade_Content.asp" \ + --data "flag=liveUpdate" \ + --data "action_mode=apply" \ + --data "action_script=start_webs_update" \ + --data "action_wait=webs_update_trigger" \ + --cookie "$cookieFile" \ + --max-time 3 >/dev/null 2>&1 || return 1 + + # Perform logout request # + curl -s -k "${NodeURLstr}/Logout.asp" \ + -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Accept-Encoding: gzip, deflate' \ + -H 'Connection: keep-alive' \ + -H "Referer: ${NodeURLstr}/Main_Login.asp" \ + -H 'Upgrade-Insecure-Requests: 0' \ + --cookie "$cookieFile" \ + --max-time 2 >/dev/null 2>&1 + + if [ $? -ne 0 ]; then + return 1 + fi + + rm -f "$cookieFile" + + return 0 +} + ##------------------------------------------## -## Modified by ExtremeFiretop [2025-Jun-08] ## +## Modified by ExtremeFiretop [2025-Dec-30] ## ##------------------------------------------## _GetNodeInfo_() { local NodeIP_Address="$1" + local runid="$2" + local safe_id="$(_MeshSafeID_ "$NodeIP_Address")" local NodeURLstr="$(_GetNodeURL_ "$NodeIP_Address")" + local cookieFile="/tmp/${runid}.${safe_id}.cookie" + local varsFile="/tmp/${runid}.${safe_id}.vars" + + # Shell-safe single-quote wrapper for writing vars files + _sh_quote_() { + # prints a single-quoted literal that can be safely `.` sourced + printf "'%s'" "$(printf "%s" "$1" | sed "s/'/'\\\\''/g")" + } ## Default values for specific variables node_productid="Unreachable" @@ -4774,6 +4864,7 @@ _GetNodeInfo_() if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] then _UpdateLoginPswdCheckHelper_ InitPWD + rm -f "$varsFile" Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" return 1 @@ -4788,49 +4879,16 @@ _GetNodeInfo_() -H "Origin: ${NodeURLstr}" \ -H 'Connection: keep-alive' \ --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ - --cookie-jar '/tmp/nodecookies.txt' \ - --max-time 2 > /tmp/login_response.txt 2>&1 + --cookie-jar "$cookieFile" \ + --max-time 2 >/dev/null 2>&1 if [ $? -ne 0 ] then printf "\n${REDct}Login failed for AiMesh Node [$NodeIP_Address].${NOct}\n" + rm -f "$varsFile" "$cookieFile" return 1 fi - ##################################################################### - # Trigger AiMesh node "Check for updates" (mimics UI start_apply.htm) # - ##################################################################### - - curl -s -k "${NodeURLstr}/start_apply.htm" \ - --referer "${NodeURLstr}/Advanced_FirmwareUpgrade_Content.asp" \ - --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${NodeURLstr}" \ - -H 'Connection: keep-alive' \ - --data "current_page=Advanced_FirmwareUpgrade_Content.asp" \ - --data "next_page=Advanced_FirmwareUpgrade_Content.asp" \ - --data "flag=liveUpdate" \ - --data "action_mode=apply" \ - --data "action_script=start_webs_update" \ - --data "action_wait=webs_update_trigger" \ - --cookie '/tmp/nodecookies.txt' \ - --max-time 3 > /tmp/node_fwcheck_trigger.txt 2>&1 - - # UI waits ~10s before querying status; give node a moment to update nvram/status - waitSeconds=8 - waitMsg="Please wait while we query the node for update status" - printf "\n" - idx=0 - while [ "$idx" -lt "$waitSeconds" ] - do - printf "\r%s (%ds)" "$waitMsg" "$((waitSeconds - idx))" - sleep 1 - idx=$((idx + 1)) - done - printf "\r%s Done. \n" - # Retrieve the HTML content # htmlContent="$(curl -s -k "${NodeURLstr}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(asus_device_list)%3bnvram_get(cfg_device_list)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(odmpid)%3bnvram_get(wps_modelnum)%3bnvram_get(model)%3bnvram_get(build_name)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ @@ -4840,11 +4898,15 @@ _GetNodeInfo_() -H 'Connection: keep-alive' \ -H "Referer: ${NodeURLstr}/index.asp" \ -H 'Upgrade-Insecure-Requests: 0' \ - --cookie '/tmp/nodecookies.txt' \ + --cookie "$cookieFile" \ --max-time 2 2>&1)" if [ $? -ne 0 ] || [ -z "$htmlContent" ] then + rm -f "$varsFile" + rm -f "$cookieFile" + # Logout best-effort + curl -s -k "${NodeURLstr}/Logout.asp" --cookie "$cookieFile" --max-time 2 >/dev/null 2>&1 printf "\n${REDct}Failed to get information for AiMesh Node [$NodeIP_Address].${NOct}\n" return 1 fi @@ -4880,41 +4942,66 @@ _GetNodeInfo_() -H 'Connection: keep-alive' \ -H "Referer: ${NodeURLstr}/Main_Login.asp" \ -H 'Upgrade-Insecure-Requests: 0' \ - --cookie '/tmp/nodecookies.txt' \ - --max-time 2 > /tmp/logout_response.txt 2>&1 + --cookie "$cookieFile" \ + --max-time 2 >/dev/null 2>&1 if [ $? -ne 0 ]; then return 1 fi + + rm -f "$cookieFile" + + # Write a vars file the parent shell can source safely + { + printf "node_productid=%s\n" "$(_sh_quote_ "$node_productid")" + printf "node_asus_device_list=%s\n" "$(_sh_quote_ "$node_asus_device_list")" + printf "node_cfg_device_list=%s\n" "$(_sh_quote_ "$node_cfg_device_list")" + printf "node_firmver=%s\n" "$(_sh_quote_ "$node_firmver")" + printf "node_buildno=%s\n" "$(_sh_quote_ "$node_buildno")" + printf "node_extendno=%s\n" "$(_sh_quote_ "$node_extendno")" + printf "node_webs_state_flag=%s\n" "$(_sh_quote_ "$node_webs_state_flag")" + printf "node_webs_state_info=%s\n" "$(_sh_quote_ "$node_webs_state_info")" + printf "node_odmpid=%s\n" "$(_sh_quote_ "$node_odmpid")" + printf "node_wps_modelnum=%s\n" "$(_sh_quote_ "$node_wps_modelnum")" + printf "node_model=%s\n" "$(_sh_quote_ "$node_model")" + printf "node_build_name=%s\n" "$(_sh_quote_ "$node_build_name")" + printf "node_lan_hostname=%s\n" "$(_sh_quote_ "$node_lan_hostname")" + printf "node_label_mac=%s\n" "$(_sh_quote_ "$node_label_mac")" + printf "Node_combinedVer=%s\n" "$(_sh_quote_ "$Node_combinedVer")" + printf "NodeGNUtonFW=%s\n" "$NodeGNUtonFW" + } >"$varsFile" + + return 0 } -##----------------------------------------## -## Modified by Martinski W. [2024-Apr-06] ## -##----------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2025-Dec-30] ## +##------------------------------------------## _GetLatestFWUpdateVersionFromNode_() { local retCode=0 webState newVersionStr - if [ -z "${node_webs_state_flag:+xSETx}" ] - then webState="" - else webState="$node_webs_state_flag" - fi - if [ -z "$webState" ] || [ "$webState" -eq 0 ] - then retCode=1 ; fi + webState="${node_webs_state_flag:-}" - if [ -z "${node_webs_state_info:+xSETx}" ] - then - newVersionStr="" - else - newVersionStr="$(echo "$node_webs_state_info" | sed 's/_/./g')" - if [ $# -eq 0 ] || [ -z "$1" ] - then - newVersionStr="$(echo "$newVersionStr" | awk -F '-' '{print $1}')" - fi - fi + # Treat missing/non-numeric/zero as "no update info" + case "$webState" in + ""|*[!0-9]*|0) retCode=1 ;; + esac - [ -z "$newVersionStr" ] && retCode=1 - echo "$newVersionStr" ; return "$retCode" + if [ -n "${node_webs_state_info:-}" ] + then + newVersionStr="$(printf "%s" "$node_webs_state_info" | sed 's/_/./g')" + if [ -z "$1" ] + then + newVersionStr="$(printf "%s" "$newVersionStr" | awk -F '-' '{print $1}')" + fi + else + newVersionStr="" + fi + + [ -z "$newVersionStr" ] && retCode=1 + printf "%s\n" "$newVersionStr" + return "$retCode" } ##----------------------------------------## @@ -10121,7 +10208,7 @@ _ValidatePrivateIPv4Address_() } ##------------------------------------------## -## Modified by ExtremeFiretop [2024-Apr-30] ## +## Modified by ExtremeFiretop [2025-Dec-30] ## ##------------------------------------------## _ProcessMeshNodes_() { @@ -10137,11 +10224,66 @@ _ProcessMeshNodes_() if [ -n "$node_list" ] then - # Iterate over the list of nodes and print information for each node + # Unique run id for temp files + local runid="mesh_$$.$(date +%s)" + + # ---- trigger FW check on all nodes in parallel ---- + for nodeIPv4addr in $node_list + do + _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue + ( + _MeshNodeTriggerFWCheck_ "$nodeIPv4addr" "$runid" + ) >/dev/null 2>&1 & + done + wait + + # ---- Single wait ---- + local waitSeconds="${MESH_UPDATE_WAIT_SECONDS:-8}" + if [ "$includeExtraLogic" -eq 1 ] + then + local waitMsg="Please wait while we query the node(s) for status..." + printf "\n" + local idx=0 + while [ "$idx" -lt "$waitSeconds" ] + do + printf "\r%s (%ds)" "$waitMsg" "$((waitSeconds - idx))" + sleep 1 + idx=$((idx + 1)) + done + printf "\r%s Done. " "$waitMsg" + else + sleep "$waitSeconds" + fi + + # ---- fetch node info on all nodes in parallel ---- for nodeIPv4addr in $node_list do - ! _ValidatePrivateIPv4Address_ "$nodeIPv4addr" && continue - _GetNodeInfo_ "$nodeIPv4addr" + _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue + ( + _GetNodeInfo_ "$nodeIPv4addr" "$runid" + ) >/dev/null 2>&1 & + done + wait + + # ---- read each node's vars ---- + for nodeIPv4addr in $node_list + do + _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue + + local safe_id="$(_MeshSafeID_ "$nodeIPv4addr")" + local varsFile="/tmp/${runid}.${safe_id}.vars" + + # Load per-node globals (node_*, Node_combinedVer, NodeGNUtonFW) + if [ -s "$varsFile" ]; then + . "$varsFile" + else + # keep defaults consistent + node_productid="Unreachable" + Node_combinedVer="Unreachable" + node_extendno="Unreachable" + NodeGNUtonFW=false + fi + if ! Node_FW_NewUpdateVersion="$(_GetLatestFWUpdateVersionFromNode_ 1)" then Node_FW_NewUpdateVersion="NONE FOUND" @@ -10149,8 +10291,8 @@ _ProcessMeshNodes_() _CheckNodeFWUpdateNotification_ "$Node_combinedVer" "$Node_FW_NewUpdateVersion" fi - # Apply extra logic if flag is '1' - if [ "$includeExtraLogic" -eq 1 ]; then + if [ "$includeExtraLogic" -eq 1 ] + then _PrintNodeInfo "$nodeIPv4addr" "$node_online_status" "$Node_FW_NewUpdateVersion" "$uid" uid="$((uid + 1))" fi @@ -10158,6 +10300,9 @@ _ProcessMeshNodes_() if [ -s "$tempNodeEMailList" ]; then _SendEMailNotification_ AGGREGATED_UPDATE_NOTIFICATION fi + + rm -f "/tmp/${runid}."*.vars 2>/dev/null + else if [ "$includeExtraLogic" -eq 1 ]; then printf "\n${padStr}${padStr}${padStr}${REDct}No AiMesh Node(s)${NOct}" From 0120d623740b3b8f27ce84c697dc11aa504aafdd Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Tue, 30 Dec 2025 20:59:21 -0500 Subject: [PATCH 5/9] Update Dev Tag Update Dev Tag --- MerlinAU.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 76a0effe..6ded3a69 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -10,7 +10,7 @@ set -u ## Set version for each Production Release ## readonly SCRIPT_VERSION=1.5.8 -readonly SCRIPT_VERSTAG="25123011" +readonly SCRIPT_VERSTAG="251230119" readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## SCRIPT_BRANCH="master" From ece930e332517e5964d75024e2ec8fb13593286a Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Wed, 31 Dec 2025 10:59:52 -0500 Subject: [PATCH 6/9] Additional Cleanup / No Logout 1. Additional Cleanup of Unused code 2. Don't logout until the final phase. --- MerlinAU.sh | 85 ++++++++++++++++------------------------------------- 1 file changed, 25 insertions(+), 60 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 6ded3a69..ab2b732a 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4802,24 +4802,10 @@ _MeshNodeTriggerFWCheck_() { --cookie "$cookieFile" \ --max-time 3 >/dev/null 2>&1 || return 1 - # Perform logout request # - curl -s -k "${NodeURLstr}/Logout.asp" \ - -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Accept-Encoding: gzip, deflate' \ - -H 'Connection: keep-alive' \ - -H "Referer: ${NodeURLstr}/Main_Login.asp" \ - -H 'Upgrade-Insecure-Requests: 0' \ - --cookie "$cookieFile" \ - --max-time 2 >/dev/null 2>&1 - if [ $? -ne 0 ]; then return 1 fi - rm -f "$cookieFile" - return 0 } @@ -4844,17 +4830,11 @@ _GetNodeInfo_() ## Default values for specific variables node_productid="Unreachable" Node_combinedVer="Unreachable" - node_asus_device_list="" - node_cfg_device_list="" node_firmver="Unreachable" node_buildno="Unreachable" node_extendno="Unreachable" node_webs_state_flag="" node_webs_state_info="" - node_odmpid="Unreachable" - node_wps_modelnum="Unreachable" - node_model="Unreachable" - node_build_name="Unreachable" node_lan_hostname="Unreachable" node_label_mac="Unreachable" NodeGNUtonFW=false @@ -4864,33 +4844,32 @@ _GetNodeInfo_() if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] then _UpdateLoginPswdCheckHelper_ InitPWD - rm -f "$varsFile" Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" return 1 fi - # Perform login request # - curl -s -k "${NodeURLstr}/login.cgi" \ - --referer "${NodeURLstr}/Main_Login.asp" \ - --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${NodeURLstr}" \ - -H 'Connection: keep-alive' \ - --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ - --cookie-jar "$cookieFile" \ - --max-time 2 >/dev/null 2>&1 - - if [ $? -ne 0 ] + # If Phase 1 already created a cookie, reuse it (skip login) else perform login request # + if [ ! -s "$cookieFile" ] then - printf "\n${REDct}Login failed for AiMesh Node [$NodeIP_Address].${NOct}\n" - rm -f "$varsFile" "$cookieFile" - return 1 + curl -s -k "${NodeURLstr}/login.cgi" \ + --referer "${NodeURLstr}/Main_Login.asp" \ + --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H "Origin: ${NodeURLstr}" \ + -H 'Connection: keep-alive' \ + --data-raw \ + "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ + --cookie-jar "$cookieFile" \ + --max-time 2 >/dev/null 2>&1 || { + printf "\n${REDct}Login failed for AiMesh Node [$NodeIP_Address].${NOct}\n" + return 1 + } fi # Retrieve the HTML content # - htmlContent="$(curl -s -k "${NodeURLstr}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(asus_device_list)%3bnvram_get(cfg_device_list)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(odmpid)%3bnvram_get(wps_modelnum)%3bnvram_get(model)%3bnvram_get(build_name)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ + htmlContent="$(curl -s -k "${NodeURLstr}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ -H 'Accept-Language: en-US,en;q=0.5' \ @@ -4899,11 +4878,10 @@ _GetNodeInfo_() -H "Referer: ${NodeURLstr}/index.asp" \ -H 'Upgrade-Insecure-Requests: 0' \ --cookie "$cookieFile" \ - --max-time 2 2>&1)" + --max-time 2 2>/dev/null)" if [ $? -ne 0 ] || [ -z "$htmlContent" ] then - rm -f "$varsFile" rm -f "$cookieFile" # Logout best-effort curl -s -k "${NodeURLstr}/Logout.asp" --cookie "$cookieFile" --max-time 2 >/dev/null 2>&1 @@ -4913,17 +4891,11 @@ _GetNodeInfo_() # Extract values using regular expressions # node_productid="$(echo "$htmlContent" | grep -o '"productid":"[^"]*' | sed 's/"productid":"//')" - node_asus_device_list="$(echo "$htmlContent" | grep -o '"asus_device_list":"[^"]*' | sed 's/"asus_device_list":"//')" - node_cfg_device_list="$(echo "$htmlContent" | grep -o '"cfg_device_list":"[^"]*' | sed 's/"cfg_device_list":"//')" node_firmver="$(echo "$htmlContent" | grep -o '"firmver":"[^"]*' | sed 's/"firmver":"//' | tr -d '.')" node_buildno="$(echo "$htmlContent" | grep -o '"buildno":"[^"]*' | sed 's/"buildno":"//')" node_extendno="$(echo "$htmlContent" | grep -o '"extendno":"[^"]*' | sed 's/"extendno":"//')" node_webs_state_flag="$(echo "$htmlContent" | grep -o '"webs_state_flag":"[^"]*' | sed 's/"webs_state_flag":"//')" node_webs_state_info="$(echo "$htmlContent" | grep -o '"webs_state_info":"[^"]*' | sed 's/"webs_state_info":"//')" - node_odmpid="$(echo "$htmlContent" | grep -o '"odmpid":"[^"]*' | sed 's/"odmpid":"//')" - node_wps_modelnum="$(echo "$htmlContent" | grep -o '"wps_modelnum":"[^"]*' | sed 's/"wps_modelnum":"//')" - node_model="$(echo "$htmlContent" | grep -o '"model":"[^"]*' | sed 's/"model":"//')" - node_build_name="$(echo "$htmlContent" | grep -o '"build_name":"[^"]*' | sed 's/"build_name":"//')" node_lan_hostname="$(echo "$htmlContent" | grep -o '"lan_hostname":"[^"]*' | sed 's/"lan_hostname":"//')" node_label_mac="$(echo "$htmlContent" | grep -o '"label_mac":"[^"]*' | sed 's/"label_mac":"//')" @@ -4949,22 +4921,16 @@ _GetNodeInfo_() return 1 fi - rm -f "$cookieFile" + rm -f "$cookieFile" >/dev/null 2>&1 # Write a vars file the parent shell can source safely { printf "node_productid=%s\n" "$(_sh_quote_ "$node_productid")" - printf "node_asus_device_list=%s\n" "$(_sh_quote_ "$node_asus_device_list")" - printf "node_cfg_device_list=%s\n" "$(_sh_quote_ "$node_cfg_device_list")" printf "node_firmver=%s\n" "$(_sh_quote_ "$node_firmver")" printf "node_buildno=%s\n" "$(_sh_quote_ "$node_buildno")" printf "node_extendno=%s\n" "$(_sh_quote_ "$node_extendno")" printf "node_webs_state_flag=%s\n" "$(_sh_quote_ "$node_webs_state_flag")" printf "node_webs_state_info=%s\n" "$(_sh_quote_ "$node_webs_state_info")" - printf "node_odmpid=%s\n" "$(_sh_quote_ "$node_odmpid")" - printf "node_wps_modelnum=%s\n" "$(_sh_quote_ "$node_wps_modelnum")" - printf "node_model=%s\n" "$(_sh_quote_ "$node_model")" - printf "node_build_name=%s\n" "$(_sh_quote_ "$node_build_name")" printf "node_lan_hostname=%s\n" "$(_sh_quote_ "$node_lan_hostname")" printf "node_label_mac=%s\n" "$(_sh_quote_ "$node_label_mac")" printf "Node_combinedVer=%s\n" "$(_sh_quote_ "$Node_combinedVer")" @@ -10231,9 +10197,7 @@ _ProcessMeshNodes_() for nodeIPv4addr in $node_list do _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue - ( - _MeshNodeTriggerFWCheck_ "$nodeIPv4addr" "$runid" - ) >/dev/null 2>&1 & + _MeshNodeTriggerFWCheck_ "$nodeIPv4addr" "$runid" >/dev/null 2>&1 & done wait @@ -10259,9 +10223,7 @@ _ProcessMeshNodes_() for nodeIPv4addr in $node_list do _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue - ( - _GetNodeInfo_ "$nodeIPv4addr" "$runid" - ) >/dev/null 2>&1 & + _GetNodeInfo_ "$nodeIPv4addr" "$runid" >/dev/null 2>&1 & done wait @@ -10274,13 +10236,16 @@ _ProcessMeshNodes_() local varsFile="/tmp/${runid}.${safe_id}.vars" # Load per-node globals (node_*, Node_combinedVer, NodeGNUtonFW) - if [ -s "$varsFile" ]; then + if [ -s "$varsFile" ] + then . "$varsFile" else # keep defaults consistent node_productid="Unreachable" Node_combinedVer="Unreachable" node_extendno="Unreachable" + node_webs_state_flag="" + node_webs_state_info="" NodeGNUtonFW=false fi From 0f1dd8340b13fdbf331ecdff3c37caad4e88a4e7 Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Wed, 31 Dec 2025 11:01:57 -0500 Subject: [PATCH 7/9] Update Dev Tag Update Dev Tag --- MerlinAU.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index ab2b732a..de40d80a 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4,13 +4,13 @@ # # Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. # Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Dec-30 +# Last Modified: 2025-Dec-31 ################################################################### set -u ## Set version for each Production Release ## readonly SCRIPT_VERSION=1.5.8 -readonly SCRIPT_VERSTAG="251230119" +readonly SCRIPT_VERSTAG="2512311" readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## SCRIPT_BRANCH="master" From 3e9fef2508248a43f9c554c35a05f098be1d7308 Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Wed, 31 Dec 2025 11:10:20 -0500 Subject: [PATCH 8/9] Add Back Missing Comment Add Back Missing Comment --- MerlinAU.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/MerlinAU.sh b/MerlinAU.sh index de40d80a..a132daae 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -10256,6 +10256,7 @@ _ProcessMeshNodes_() _CheckNodeFWUpdateNotification_ "$Node_combinedVer" "$Node_FW_NewUpdateVersion" fi + # Apply extra logic if flag is '1' if [ "$includeExtraLogic" -eq 1 ] then _PrintNodeInfo "$nodeIPv4addr" "$node_online_status" "$Node_FW_NewUpdateVersion" "$uid" From 9515ac67ac1f1c0221875b39faf1893d0e0ab4b9 Mon Sep 17 00:00:00 2001 From: Martinski4GitHub <119833648+Martinski4GitHub@users.noreply.github.com> Date: Fri, 2 Jan 2026 13:46:11 -0800 Subject: [PATCH 9/9] Code Improvements Miscellaneous code improvements and fine-tuning. --- MerlinAU.sh | 415 ++++++++++++++++++++++++++++------------------------ README.md | 2 +- 2 files changed, 226 insertions(+), 191 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index a132daae..8ecbf110 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4,16 +4,16 @@ # # Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. # Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Dec-31 +# Last Modified: 2026-Jan-02 ################################################################### set -u ## Set version for each Production Release ## readonly SCRIPT_VERSION=1.5.8 -readonly SCRIPT_VERSTAG="2512311" +readonly SCRIPT_VERSTAG="26010210" readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## -SCRIPT_BRANCH="master" +SCRIPT_BRANCH="dev" ##----------------------------------------## ## Modified by Martinski W. [2024-Jul-03] ## @@ -927,6 +927,7 @@ else ## Set 20 minutes AFTER for APs and AiMesh Nodes ## readonly FW_Update_CRON_DefaultSchedule="20 0 * * *" fi +readonly meshUpdate_WaitSecs=8 ## Recommended 15 minutes BEFORE the F/W Update ## readonly ScriptAU_CRON_DefaultSchedule="45 23 * * *" @@ -2087,23 +2088,23 @@ isEMailConfigEnabledInAMTM=false # Define the CRON job command to execute # readonly SCRIPT_UP_CRON_JOB_RUN="sh $ScriptFilePath checkupdates" readonly SCRIPT_UP_CRON_JOB_TAG="${ScriptFNameTag}_ScriptUpdate" -readonly DAILY_SCRIPT_UPDATE_CHECK_JOB="sh $ScriptFilePath scriptAUCronJob & $hookScriptTagStr" -readonly DAILY_SCRIPT_UPDATE_CHECK_HOOK="[ -f $ScriptFilePath ] && $DAILY_SCRIPT_UPDATE_CHECK_JOB" +readonly DAILY_SCRIPT_UPDATE_CHECK_JOB="$ScriptFilePath scriptAUCronJob &" +readonly DAILY_SCRIPT_UPDATE_CHECK_HOOK="[ -x $ScriptFilePath ] && $DAILY_SCRIPT_UPDATE_CHECK_JOB $hookScriptTagStr" # Define the CRON job command to execute # readonly CRON_JOB_RUN="sh $ScriptFilePath run_now" readonly CRON_JOB_TAG_OLD="$ScriptFNameTag" readonly CRON_JOB_TAG="${ScriptFNameTag}_FWUpdate" -readonly CRON_SCRIPT_JOB="sh $ScriptFilePath addCronJob & $hookScriptTagStr" -readonly CRON_SCRIPT_HOOK="[ -f $ScriptFilePath ] && $CRON_SCRIPT_JOB" +readonly CRON_SCRIPT_JOB="$ScriptFilePath addCronJob &" +readonly CRON_SCRIPT_HOOK="[ -x $ScriptFilePath ] && $CRON_SCRIPT_JOB $hookScriptTagStr" # Define post-reboot run job command to execute # -readonly POST_REBOOT_SCRIPT_JOB="sh $ScriptFilePath postRebootRun & $hookScriptTagStr" -readonly POST_REBOOT_SCRIPT_HOOK="[ -f $ScriptFilePath ] && $POST_REBOOT_SCRIPT_JOB" +readonly POST_REBOOT_SCRIPT_JOB="$ScriptFilePath postRebootRun &" +readonly POST_REBOOT_SCRIPT_HOOK="[ -x $ScriptFilePath ] && $POST_REBOOT_SCRIPT_JOB $hookScriptTagStr" # Define post-update email notification job command to execute # -readonly POST_UPDATE_EMAIL_SCRIPT_JOB="sh $ScriptFilePath postUpdateEmail & $hookScriptTagStr" -readonly POST_UPDATE_EMAIL_SCRIPT_HOOK="[ -f $ScriptFilePath ] && $POST_UPDATE_EMAIL_SCRIPT_JOB" +readonly POST_UPDATE_EMAIL_SCRIPT_JOB="$ScriptFilePath postUpdateEmail &" +readonly POST_UPDATE_EMAIL_SCRIPT_HOOK="[ -x $ScriptFilePath ] && $POST_UPDATE_EMAIL_SCRIPT_JOB $hookScriptTagStr" if [ -d "$FW_LOG_DIR" ] then @@ -3433,7 +3434,7 @@ _DelPostUpdateEmailNotifyScriptHook_() if grep -qE "$POST_UPDATE_EMAIL_SCRIPT_JOB" "$hookScriptFile" then - sed -i -e '/\/'"$ScriptFileName"' postUpdateEmail & '"$hookScriptTagStr"'/d' "$hookScriptFile" + sed -i -e '/\/'"$ScriptFileName"' postUpdateEmail & /d' "$hookScriptFile" if [ $? -eq 0 ] then Say "Post-update email notification hook was deleted successfully from '$hookScriptFile' script." @@ -3486,7 +3487,7 @@ _DelPostRebootRunScriptHook_() if grep -qE "$POST_REBOOT_SCRIPT_JOB" "$hookScriptFile" then - sed -i -e '/\/'"$ScriptFileName"' postRebootRun & '"$hookScriptTagStr"'/d' "$hookScriptFile" + sed -i -e '/\/'"$ScriptFileName"' postRebootRun & /d' "$hookScriptFile" if [ $? -eq 0 ] then Say "Post-reboot run hook was deleted successfully from '$hookScriptFile' script." @@ -4046,53 +4047,75 @@ _CheckForMinimumModelSupport_() "$routerModelCheckFailed" && return 1 || return 0 } +##-------------------------------------## +## Added by Martinski W. [2026-Jan-01] ## +##-------------------------------------## +_DoMainRouterLogin_() +{ + if [ $# -lt 3 ] || [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] + then + echo ; return 1 + fi + local routerURL="$1" + local credsENC="$2" + local cookieFile="$3" + local curlCode curlResponse + + curlResponse="$(curl -k "${routerURL}/login.cgi" \ + --referer "${routerURL}/Main_Login.asp" \ + --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ + -H 'Accept-Language: en-US,en;q=0.5' \ + -H 'Content-Type: application/x-www-form-urlencoded' \ + -H "Origin: ${routerURL}/" \ + -H 'Connection: keep-alive' \ + --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsENC" \ + --cookie-jar "$cookieFile")" + curlCode="$?" + + echo "$curlResponse" + return "$curlCode" +} + ##----------------------------------------## -## Modified by Martinski W. [2025-Mar-07] ## +## Modified by Martinski W. [2026-Jan-01] ## ##----------------------------------------## _TestLoginCredentials_() { - local credsENC curlResponse routerURLstr + local credsENC routerURL cookieFile curlResponse retCode if [ $# -gt 0 ] && [ -n "$1" ] then credsENC="$1" else credsENC="$(Get_Custom_Setting credentials_base64)" fi - # Define routerURLstr # - routerURLstr="$(_GetRouterURL_)" + routerURL="$(_GetRouterURL_)" + cookieFile="/tmp/MerlinAU_LoginCookie.txt" printf "\nRestarting web server... Please wait.\n" - /sbin/service restart_httpd >/dev/null 2>&1 & - sleep 5 + /sbin/service restart_httpd >/dev/null 2>&1 + sleep 4 - curlResponse="$(curl -k "${routerURLstr}/login.cgi" \ - --referer "${routerURLstr}/Main_Login.asp" \ - --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${routerURLstr}/" \ - -H 'Connection: keep-alive' \ - --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=${credsENC}" \ - --cookie-jar /tmp/cookie.txt)" - - # Determine login success or failure. This is a basic check # - if echo "$curlResponse" | grep -Eq 'url=index\.asp|url=GameDashboard\.asp' + if curlResponse="$(_DoMainRouterLogin_ "$routerURL" "$credsENC" "$cookieFile")" && \ + echo "$curlResponse" | grep -Eq 'url=index\.asp|url=GameDashboard\.asp' then _UpdateLoginPswdCheckHelper_ SUCCESS printf "\n${GRNct}Router Login test passed.${NOct}" printf "\nRestarting web server... Please wait.\n" /sbin/service restart_httpd >/dev/null 2>&1 & sleep 2 - return 0 + retCode=0 else _UpdateLoginPswdCheckHelper_ FAILURE printf "\n${REDct}**ERROR**${NOct}: Router Login test failed.\n" printf "\n${routerLoginFailureMsg}\n\n" if _WaitForYESorNO_ "Would you like to try again?" - then return 1 # Indicates failure but with intent to retry # - else return 0 # User opted not to retry so just return # + then retCode=1 # Indicates failure but with intent to retry # + else retCode=0 # User chose not to retry so just return # fi fi + + rm -f "$cookieFile" + return "$retCode" } ##----------------------------------------## @@ -4619,13 +4642,14 @@ _GetLoginCredentials_() then _UpdateLoginPswdCheckHelper_ NewPSWD savedMsgStr="${GRNct}New credentials saved.${NOct}" + oldPWSDstring="$thePWSDstring" else _UpdateLoginPswdCheckHelper_ OldPSWD savedMsgStr="${GRNct}Credentials remain unchanged.${NOct}" fi printf "\n${savedMsgStr}\n" printf "Encoded Credentials:\n" - printf "${GRNct}$loginCredsENC${NOct}\n" + printf "${GRNct}${loginCredsENC}${NOct}\n" if _WaitForYESorNO_ "\nWould you like to test the current login credentials?" then @@ -4722,18 +4746,17 @@ _Populate_Node_Settings_() ##---------------------------------------## ## Added by ExtremeFiretop [2025-Dec-30] ## ##---------------------------------------## -# Make an IP safe for filenames -_MeshSafeID_() { - printf "%s" "$1" | tr '.:' '__' -} +# Make an ID safe for filenames # +_MeshSafeID_() +{ printf "%s" "$1" | tr '.:' '__' ; } ##---------------------------------------## ## Added by ExtremeFiretop [2024-Mar-26] ## ##---------------------------------------## _GetNodeURL_() { - local NodeIP_Address="$1" - local urlProto urlDomain urlPort + local nodeIPv4addr="$1" + local urlProto urlDomain urlPort if [ "$(nvram get http_enable)" = "1" ]; then urlProto="https" @@ -4748,50 +4771,78 @@ _GetNodeURL_() urlPort=":$urlPort" fi - echo "${urlProto}://${NodeIP_Address}${urlPort}" + echo "${urlProto}://${nodeIPv4addr}${urlPort}" } -##---------------------------------------## -## Added by ExtremeFiretop [2025-Dec-30] ## -##---------------------------------------## -# Trigger the node "Check for updates" (no waiting here) -_MeshNodeTriggerFWCheck_() { - local NodeIP_Address="$1" - local runid="$2" - local safe_id="$(_MeshSafeID_ "$NodeIP_Address")" - local NodeURLstr="$(_GetNodeURL_ "$NodeIP_Address")" - local cookieFile="/tmp/${runid}.${safe_id}.cookie" - - ## Check for Login Credentials ## - credsBase64="$(Get_Custom_Setting credentials_base64)" - if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] +##-------------------------------------## +## Added by Martinski W. [2026-Jan-01] ## +##-------------------------------------## +_DoMeshNodeLogin_() +{ + if [ $# -lt 3 ] || [ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] then - _UpdateLoginPswdCheckHelper_ InitPWD - Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." - "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" return 1 fi + local nodeURL="$1" + local credsENC="$2" + local cookieFile="$3" - # Perform login request # - curl -s -k "${NodeURLstr}/login.cgi" \ - --referer "${NodeURLstr}/Main_Login.asp" \ + curl -s -k "${nodeURL}/login.cgi" \ + --referer "${nodeURL}/Main_Login.asp" \ --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept-Language: en-US,en;q=0.5' \ -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${NodeURLstr}" \ + -H "Origin: ${nodeURL}" \ -H 'Connection: keep-alive' \ - --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ + --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsENC" \ --cookie-jar "$cookieFile" \ - --max-time 2 >/dev/null 2>&1 || return 1 + --max-time 3 >/dev/null 2>&1 + + return "$?" +} + +##----------------------------------------## +## Modified by Martinski W. [2026-Jan-01] ## +##----------------------------------------## +# Trigger the node "Check for updates" (no waiting here) +_MeshNodeTriggerFWCheck_() +{ + if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] + then echo "**ERROR** **NO_PARAMS**" ; return 1 + fi + + local nodeIPv4addr="$1" runID="$2" + local safeID="$(_MeshSafeID_ "$nodeIPv4addr")" + local nodeURL="$(_GetNodeURL_ "$nodeIPv4addr")" + local cookieFile="/tmp/${runID}.${safeID}.cookie" + + # Check for Login Credentials # + credsENC="$(Get_Custom_Setting credentials_base64)" + if [ -z "$credsENC" ] || [ "$credsENC" = "TBD" ] + then + _UpdateLoginPswdCheckHelper_ InitPWD + Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." + "$inMenuMode" && _WaitForEnterKey_ "$mainMenuReturnPromptStr" + return 1 + fi + + if _DoMeshNodeLogin_ "$nodeURL" "$credsENC" "$cookieFile" + then + Say "${GRNct}Successful Login for AiMesh Node [$nodeIPv4addr].${NOct}" + else + rm -f "$cookieFile" + Say "${REDct}Failed Login for AiMesh Node [$nodeIPv4addr].${NOct}" + return 1 + fi - # Trigger firmware check (mimic WebUI "Check" button) - curl -s -k "${NodeURLstr}/start_apply.htm" \ - --referer "${NodeURLstr}/Advanced_FirmwareUpgrade_Content.asp" \ + # Trigger firmware check (mimic WebUI "Check" button) # + curl -s -k "${nodeURL}/start_apply.htm" \ + --referer "${nodeURL}/Advanced_FirmwareUpgrade_Content.asp" \ --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8' \ -H 'Accept-Language: en-US,en;q=0.5' \ -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${NodeURLstr}" \ + -H "Origin: ${nodeURL}" \ -H 'Connection: keep-alive' \ --data "current_page=Advanced_FirmwareUpgrade_Content.asp" \ --data "next_page=Advanced_FirmwareUpgrade_Content.asp" \ @@ -4800,34 +4851,34 @@ _MeshNodeTriggerFWCheck_() { --data "action_script=start_webs_update" \ --data "action_wait=webs_update_trigger" \ --cookie "$cookieFile" \ - --max-time 3 >/dev/null 2>&1 || return 1 + --max-time 3 >/dev/null 2>&1 - if [ $? -ne 0 ]; then - return 1 - fi - - return 0 + return "$?" } -##------------------------------------------## -## Modified by ExtremeFiretop [2025-Dec-30] ## -##------------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2026-Jan-01] ## +##----------------------------------------## _GetNodeInfo_() { - local NodeIP_Address="$1" - local runid="$2" - local safe_id="$(_MeshSafeID_ "$NodeIP_Address")" - local NodeURLstr="$(_GetNodeURL_ "$NodeIP_Address")" - local cookieFile="/tmp/${runid}.${safe_id}.cookie" - local varsFile="/tmp/${runid}.${safe_id}.vars" + if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] + then echo "**ERROR** **NO_PARAMS**" ; return 1 + fi - # Shell-safe single-quote wrapper for writing vars files - _sh_quote_() { - # prints a single-quoted literal that can be safely `.` sourced + local curlCode htmlContent + local nodeIPv4addr="$1" runID="$2" + local safeID="$(_MeshSafeID_ "$nodeIPv4addr")" + local nodeURL="$(_GetNodeURL_ "$nodeIPv4addr")" + local cookieFile="/tmp/${runID}.${safeID}.cookie" + local varsFile="/tmp/${runID}.${safeID}.vars" + + # Shell-safe single-quote wrapper for writing vars files # + _sh_quote_() + { # prints a single-quoted literal that can be safely "sourced" # printf "'%s'" "$(printf "%s" "$1" | sed "s/'/'\\\\''/g")" } - ## Default values for specific variables + # Default values for specific variables # node_productid="Unreachable" Node_combinedVer="Unreachable" node_firmver="Unreachable" @@ -4839,9 +4890,9 @@ _GetNodeInfo_() node_label_mac="Unreachable" NodeGNUtonFW=false - ## Check for Login Credentials ## - credsBase64="$(Get_Custom_Setting credentials_base64)" - if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] + # Check for Login Credentials # + credsENC="$(Get_Custom_Setting credentials_base64)" + if [ -z "$credsENC" ] || [ "$credsENC" = "TBD" ] then _UpdateLoginPswdCheckHelper_ InitPWD Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." @@ -4849,47 +4900,38 @@ _GetNodeInfo_() return 1 fi - # If Phase 1 already created a cookie, reuse it (skip login) else perform login request # - if [ ! -s "$cookieFile" ] + # If already created a cookie, reuse it (skip login), else perform login request # + if [ ! -s "$cookieFile" ] && \ + ! _DoMeshNodeLogin_ "$nodeURL" "$credsENC" "$cookieFile" then - curl -s -k "${NodeURLstr}/login.cgi" \ - --referer "${NodeURLstr}/Main_Login.asp" \ - --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${NodeURLstr}" \ - -H 'Connection: keep-alive' \ - --data-raw \ - "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=$credsBase64" \ - --cookie-jar "$cookieFile" \ - --max-time 2 >/dev/null 2>&1 || { - printf "\n${REDct}Login failed for AiMesh Node [$NodeIP_Address].${NOct}\n" - return 1 - } + rm -f "$cookieFile" + Say "${REDct}Failed Login for AiMesh Node [$nodeIPv4addr].${NOct}" + return 1 fi - # Retrieve the HTML content # - htmlContent="$(curl -s -k "${NodeURLstr}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ + # Retrieve Info # + htmlContent="$(curl -s -k "${nodeURL}/appGet.cgi?hook=nvram_get(productid)%3bnvram_get(firmver)%3bnvram_get(buildno)%3bnvram_get(extendno)%3bnvram_get(webs_state_flag)%3bnvram_get(lan_hostname)%3bnvram_get(webs_state_info)%3bnvram_get(label_mac)" \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ -H 'Accept-Language: en-US,en;q=0.5' \ -H 'Accept-Encoding: gzip, deflate' \ -H 'Connection: keep-alive' \ - -H "Referer: ${NodeURLstr}/index.asp" \ + -H "Referer: ${nodeURL}/index.asp" \ -H 'Upgrade-Insecure-Requests: 0' \ --cookie "$cookieFile" \ --max-time 2 2>/dev/null)" + curlCode="$?" - if [ $? -ne 0 ] || [ -z "$htmlContent" ] + if [ "$curlCode" -ne 0 ] || [ -z "$htmlContent" ] then + # Logout best-effort # + curl -s -k "${nodeURL}/Logout.asp" --cookie "$cookieFile" --max-time 2 >/dev/null 2>&1 + printf "\n${REDct}Failed to get information for AiMesh Node [$nodeIPv4addr].${NOct}\n" rm -f "$cookieFile" - # Logout best-effort - curl -s -k "${NodeURLstr}/Logout.asp" --cookie "$cookieFile" --max-time 2 >/dev/null 2>&1 - printf "\n${REDct}Failed to get information for AiMesh Node [$NodeIP_Address].${NOct}\n" return 1 fi - # Extract values using regular expressions # + # Extract values # node_productid="$(echo "$htmlContent" | grep -o '"productid":"[^"]*' | sed 's/"productid":"//')" node_firmver="$(echo "$htmlContent" | grep -o '"firmver":"[^"]*' | sed 's/"firmver":"//' | tr -d '.')" node_buildno="$(echo "$htmlContent" | grep -o '"buildno":"[^"]*' | sed 's/"buildno":"//')" @@ -4905,25 +4947,20 @@ _GetNodeInfo_() # Combine extracted information into one string # Node_combinedVer="${node_firmver}.${node_buildno}.$node_extendno" - # Perform logout request # - curl -s -k "${NodeURLstr}/Logout.asp" \ + # Logout request # + curl -s -k "${nodeURL}/Logout.asp" \ -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8' \ -H 'Accept-Language: en-US,en;q=0.5' \ -H 'Accept-Encoding: gzip, deflate' \ -H 'Connection: keep-alive' \ - -H "Referer: ${NodeURLstr}/Main_Login.asp" \ + -H "Referer: ${nodeURL}/Main_Login.asp" \ -H 'Upgrade-Insecure-Requests: 0' \ --cookie "$cookieFile" \ --max-time 2 >/dev/null 2>&1 + curlCode="$?" - if [ $? -ne 0 ]; then - return 1 - fi - - rm -f "$cookieFile" >/dev/null 2>&1 - - # Write a vars file the parent shell can source safely + # Write a vars file the parent shell can source safely # { printf "node_productid=%s\n" "$(_sh_quote_ "$node_productid")" printf "node_firmver=%s\n" "$(_sh_quote_ "$node_firmver")" @@ -4935,9 +4972,10 @@ _GetNodeInfo_() printf "node_label_mac=%s\n" "$(_sh_quote_ "$node_label_mac")" printf "Node_combinedVer=%s\n" "$(_sh_quote_ "$Node_combinedVer")" printf "NodeGNUtonFW=%s\n" "$NodeGNUtonFW" - } >"$varsFile" + } > "$varsFile" - return 0 + rm -f "$cookieFile" + return "$curlCode" } ##------------------------------------------## @@ -4945,7 +4983,7 @@ _GetNodeInfo_() ##------------------------------------------## _GetLatestFWUpdateVersionFromNode_() { - local retCode=0 webState newVersionStr + local retCode=0 webState newVersionStr webState="${node_webs_state_flag:-}" @@ -4966,7 +5004,7 @@ _GetLatestFWUpdateVersionFromNode_() fi [ -z "$newVersionStr" ] && retCode=1 - printf "%s\n" "$newVersionStr" + echo "$newVersionStr" return "$retCode" } @@ -8547,7 +8585,7 @@ _SelectOfflineUpdateFile_() return 1 fi - # Confirm the selection + # Confirm selection # if _WaitForYESorNO_ "\nDo you want to continue with the selected file?" then printf "\n---------------------------------------------------\n" @@ -8944,7 +8982,7 @@ _Unmount_Eject_USB_Drives_() } ##----------------------------------------## -## Modified by Martinski W. [2025-Nov-09] ## +## Modified by Martinski W. [2026-Jan-01] ## ##----------------------------------------## _RunFirmwareUpdateNow_() { @@ -9019,10 +9057,10 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or if ! node_online_status="$(_NodeActiveStatus_)" then node_online_status="" - else _ProcessMeshNodes_ 0 + else _ProcessMeshNodes_ false fi - local retCode credsBase64="" + local retCode credsENC="" local currentVersionNum="" releaseVersionNum="" local current_version="" @@ -9129,8 +9167,8 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or dottedVersion="$(echo "$fwUpdateBaseNum" | sed 's/./&./g' | sed 's/.$//')" ## Check for Login Credentials ## - credsBase64="$(Get_Custom_Setting credentials_base64)" - if [ -z "$credsBase64" ] || [ "$credsBase64" = "TBD" ] + credsENC="$(Get_Custom_Setting credentials_base64)" + if [ -z "$credsENC" ] || [ "$credsENC" = "TBD" ] then _UpdateLoginPswdCheckHelper_ InitPWD Say "${REDct}**ERROR**${NOct}: No login credentials have been saved. Use the Main Menu to save login credentials." @@ -9390,8 +9428,9 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or Say "Required RAM: ${requiredRAM_kb} KB - RAM Free: ${freeRAM_kb} KB - RAM Available: ${availableRAM_kb} KB" check_memory_and_prompt_reboot "$requiredRAM_kb" "$availableRAM_kb" - routerURLstr="$(_GetRouterURL_)" - Say "Router Web URL is: ${routerURLstr}" + routerURL="$(_GetRouterURL_)" + Say "Router Web URL is: ${routerURL}" + cookieFile="/tmp/FW_UpgradeCookie.txt" if "$isInteractive" then @@ -9412,7 +9451,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or #------------------------------------------------------------# "$isInteractive" && printf "\nRestarting web server... Please wait.\n" /sbin/service restart_httpd >/dev/null 2>&1 & - sleep 5 + sleep 4 # Send last email notification before F/W flash # _SendEMailNotification_ START_FW_UPDATE_STATUS @@ -9447,20 +9486,11 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or requiredDIVER_version="$(_ScriptVersionStrToNum_ "5.2.0")" fi - ##------------------------------------------## - ## Modified by ExtremeFiretop [2024-Sep-07] ## - ##------------------------------------------## - curl_response="$(curl -k "${routerURLstr}/login.cgi" \ - --referer "${routerURLstr}/Main_Login.asp" \ - --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ - -H 'Accept-Language: en-US,en;q=0.5' \ - -H 'Content-Type: application/x-www-form-urlencoded' \ - -H "Origin: ${routerURLstr}/" \ - -H 'Connection: keep-alive' \ - --data-raw "group_id=&action_mode=&action_script=&action_wait=5¤t_page=Main_Login.asp&next_page=index.asp&login_authorization=${credsBase64}" \ - --cookie-jar /tmp/cookie.txt)" - - if echo "$curl_response" | grep -Eq 'url=index\.asp|url=GameDashboard\.asp' + ##----------------------------------------## + ## Modified by Martinski W. [2026-Jan-01] ## + ##----------------------------------------## + if curlResponse="$(_DoMainRouterLogin_ "$routerURL" "$credsENC" "$cookieFile")" && \ + echo "$curlResponse" | grep -Eq 'url=index\.asp|url=GameDashboard\.asp' then _UpdateLoginPswdCheckHelper_ SUCCESS @@ -9523,11 +9553,11 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or # the following 'curl' command MUST always be the last step in this block. # Do NOT insert any commands after it! (unless you understand the implications). #----------------------------------------------------------------------------------# - nohup curl -k "${routerURLstr}/upgrade.cgi" \ - --referer "${routerURLstr}/Advanced_FirmwareUpgrade_Content.asp" \ + nohup curl -k "${routerURL}/upgrade.cgi" \ + --referer "${routerURL}/Advanced_FirmwareUpgrade_Content.asp" \ --user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \ -H 'Accept-Language: en-US,en;q=0.5' \ - -H "Origin: ${routerURLstr}/" \ + -H "Origin: ${routerURL}/" \ -F 'current_page=Advanced_FirmwareUpgrade_Content.asp' \ -F 'next_page=' \ -F 'action_mode=' \ @@ -9536,7 +9566,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or -F 'preferred_lang=EN' \ -F "firmver=${dottedVersion}" \ -F "file=@${firmware_file}" \ - --cookie /tmp/cookie.txt > /tmp/upload_response.txt 2>&1 & + --cookie "$cookieFile" > /tmp/upload_response.txt 2>&1 & curlPID=$! #----------------------------------------------------------# @@ -9572,6 +9602,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or printf "\n${routerLoginFailureMsg}\n\n" _WaitForEnterKey_ fi + rm -f "$cookieFile" _SendEMailNotification_ FAILED_FW_UPDATE_STATUS _DoCleanUp_ 1 "$keepZIPfile" "$keepWfile" _EntwareServicesHandler_ start @@ -9703,7 +9734,7 @@ _DelFWAutoUpdateHook_() if grep -qE "$CRON_SCRIPT_JOB" "$hookScriptFile" then - sed -i -e '/\/'"$ScriptFileName"' addCronJob & '"$hookScriptTagStr"'/d' "$hookScriptFile" + sed -i -e '/\/'"$ScriptFileName"' addCronJob & /d' "$hookScriptFile" if [ $? -eq 0 ] then Say "F/W Update cron job hook was deleted successfully from '$hookScriptFile' script." @@ -9787,7 +9818,7 @@ _DelScriptAutoUpdateHook_() if grep -qE "$DAILY_SCRIPT_UPDATE_CHECK_JOB" "$hookScriptFile" then - sed -i -e '/\/'"$ScriptFileName"' scriptAUCronJob & '"$hookScriptTagStr"'/d' "$hookScriptFile" + sed -i -e '/\/'"$ScriptFileName"' scriptAUCronJob & /d' "$hookScriptFile" if [ $? -eq 0 ] then Say "ScriptAU cron job hook was deleted successfully from '$hookScriptFile' script." @@ -10173,14 +10204,17 @@ _ValidatePrivateIPv4Address_() fi } -##------------------------------------------## -## Modified by ExtremeFiretop [2025-Dec-30] ## -##------------------------------------------## +##----------------------------------------## +## Modified by Martinski W. [2026-Jan-01] ## +##----------------------------------------## _ProcessMeshNodes_() { - includeExtraLogic="$1" # Use '1' to include extra logic, '0' to exclude if [ $# -eq 0 ] || [ -z "$1" ] - then echo "**ERROR** **NO_PARAMS**" ; return 1 ; fi + then echo "**ERROR** **NO_PARAMS**" ; return 1 + fi + # 'true' to include extra logic, 'false' to exclude # + local includeExtraLogic="$1" + local runID if "$aiMeshNodes_OK" then @@ -10190,57 +10224,57 @@ _ProcessMeshNodes_() if [ -n "$node_list" ] then - # Unique run id for temp files - local runid="mesh_$$.$(date +%s)" + # Unique run ID for temp files # + runID="mesh_$$.$(date +%s)" - # ---- trigger FW check on all nodes in parallel ---- + # ---- Trigger F/W check on all nodes in parallel ---- # for nodeIPv4addr in $node_list do _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue - _MeshNodeTriggerFWCheck_ "$nodeIPv4addr" "$runid" >/dev/null 2>&1 & + _MeshNodeTriggerFWCheck_ "$nodeIPv4addr" "$runID" >/dev/null 2>&1 & done wait - # ---- Single wait ---- - local waitSeconds="${MESH_UPDATE_WAIT_SECONDS:-8}" - if [ "$includeExtraLogic" -eq 1 ] + # ---- Single wait ---- # + local waitSeconds="${meshUpdate_WaitSecs:-8}" + if "$includeExtraLogic" then local waitMsg="Please wait while we query the node(s) for status..." - printf "\n" + echo local idx=0 while [ "$idx" -lt "$waitSeconds" ] do printf "\r%s (%ds)" "$waitMsg" "$((waitSeconds - idx))" sleep 1 - idx=$((idx + 1)) + idx="$((idx + 1))" done printf "\r%s Done. " "$waitMsg" else sleep "$waitSeconds" fi - # ---- fetch node info on all nodes in parallel ---- + # ---- Fetch info from all nodes in parallel ---- # for nodeIPv4addr in $node_list do _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue - _GetNodeInfo_ "$nodeIPv4addr" "$runid" >/dev/null 2>&1 & + _GetNodeInfo_ "$nodeIPv4addr" "$runID" >/dev/null 2>&1 & done wait - # ---- read each node's vars ---- + # ---- Read each node's vars ---- # for nodeIPv4addr in $node_list do _ValidatePrivateIPv4Address_ "$nodeIPv4addr" || continue - local safe_id="$(_MeshSafeID_ "$nodeIPv4addr")" - local varsFile="/tmp/${runid}.${safe_id}.vars" + local safeID="$(_MeshSafeID_ "$nodeIPv4addr")" + local varsFile="/tmp/${runID}.${safeID}.vars" - # Load per-node globals (node_*, Node_combinedVer, NodeGNUtonFW) + # Load per-node globals (node_*, Node_combinedVer, NodeGNUtonFW) # if [ -s "$varsFile" ] then . "$varsFile" else - # keep defaults consistent + # keep defaults consistent # node_productid="Unreachable" Node_combinedVer="Unreachable" node_extendno="Unreachable" @@ -10256,21 +10290,22 @@ _ProcessMeshNodes_() _CheckNodeFWUpdateNotification_ "$Node_combinedVer" "$Node_FW_NewUpdateVersion" fi - # Apply extra logic if flag is '1' - if [ "$includeExtraLogic" -eq 1 ] + if "$includeExtraLogic" then _PrintNodeInfo "$nodeIPv4addr" "$node_online_status" "$Node_FW_NewUpdateVersion" "$uid" uid="$((uid + 1))" fi done - if [ -s "$tempNodeEMailList" ]; then + + if [ -s "$tempNodeEMailList" ] + then _SendEMailNotification_ AGGREGATED_UPDATE_NOTIFICATION fi - rm -f "/tmp/${runid}."*.vars 2>/dev/null - + rm -f "/tmp/${runID}."*.vars 2>/dev/null else - if [ "$includeExtraLogic" -eq 1 ]; then + if "$includeExtraLogic" + then printf "\n${padStr}${padStr}${padStr}${REDct}No AiMesh Node(s)${NOct}" fi fi @@ -11115,7 +11150,8 @@ _ShowNodesMenu_() printf "${SEPstr}\n" if ! node_online_status="$(_NodeActiveStatus_)" - then node_online_status="" ; fi + then node_online_status="" + fi # Count the number of IP addresses local numIPs="$(echo "$node_list" | wc -w)" @@ -11123,9 +11159,8 @@ _ShowNodesMenu_() # Print the result printf "\n${padStr}${padStr}${padStr}${GRNct} AiMesh Node(s): ${numIPs}${NOct}" - _ProcessMeshNodes_ 1 - - echo "" + _ProcessMeshNodes_ true + echo printf "\n ${GRNct}e${NOct}. Return to Main Menu\n" printf "${SEPstr}" @@ -11549,7 +11584,7 @@ then _ReleaseLock_ cliFileLock fi ;; - processNodes) _ProcessMeshNodes_ 0 + processNodes) _ProcessMeshNodes_ false ;; addCronJob) _AddFWAutoUpdateCronJob_ ;; diff --git a/README.md b/README.md index af54b608..a2f11ee1 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # MerlinAU - AsusWRT-Merlin Firmware Auto Updater ## v1.5.8 -## 2025-Dec-30 +## 2026-Jan-02 ## WebUI: ![image](https://github.com/user-attachments/assets/9c1dff99-9c13-491b-a7fa-aff924d5f02e)