Skip to content

Commit ee06d2a

Browse files
Prevent mesh firmware checks from interrupting node updates
Fix a new bug identified and introduced by commit: bae3640 And PR: #539 This bug appears to be a concurrent firmware management collision, essentially a race while flashing a node while checking it for updates from the primary at the same time. I accidently ran into this, the seems to be that the node had prepared for the update, authenticated to its own WebUI, and was just about to hand the beta1 image to /upgrade.cgi When at that exact time, I started an upgrade from the primary, which logged into the node to check for updates, triggered start_webs_update, and resulted in putting the node’s ASUS firmware update system into a competing update/check state and ultimately MerlinAU rebooted the node without flashing any firmware. This may also be related to a report from JimbobJay here: https://www.snbforums.com/threads/merlinau-v1-6-8-the-ultimate-firmware-auto-updater.96306/post-999444
1 parent d208706 commit ee06d2a

1 file changed

Lines changed: 86 additions & 17 deletions

File tree

‎MerlinAU.sh‎

Lines changed: 86 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@
1919
set -u
2020

2121
## Set version for each Production Release ##
22-
readonly SCRIPT_VERSION=1.6.8
23-
readonly SCRIPT_VERSTAG="26090718"
22+
readonly SCRIPT_VERSION=1.6.9
23+
readonly SCRIPT_VERSTAG="26091601"
2424
readonly SCRIPT_NAME="MerlinAU"
2525
## Set to "master" for Production Releases ##
26-
SCRIPT_BRANCH="master"
26+
SCRIPT_BRANCH="dev"
2727

2828
##----------------------------------------##
2929
## Modified by Martinski W. [2024-Jul-03] ##
@@ -4335,7 +4335,7 @@ _ReEnableAsusTrendMicroProcesses_()
43354335
}
43364336

43374337
##------------------------------------------##
4338-
## Modified by ExtremeFiretop [2024-Jan-26] ##
4338+
## Modified by ExtremeFiretop [2025-Sep-16] ##
43394339
##------------------------------------------##
43404340
_DoCleanUp_()
43414341
{
@@ -4353,6 +4353,10 @@ _DoCleanUp_()
43534353
[ $# -gt 1 ] && [ "$2" -eq 1 ] && keepZIPfile=true
43544354
[ $# -gt 2 ] && [ "$3" -eq 1 ] && keepWfile=true
43554355

4356+
# Clear the volatile F/W-update guard used by AiMesh primaries. #
4357+
# This value is intentionally never committed to NVRAM. #
4358+
nvram unset merlinau_fw_update 2>/dev/null
4359+
43564360
# Stop the LEDs blinking #
43574361
_Reset_LEDs_ 1
43584362

@@ -5429,9 +5433,9 @@ _DoMeshNodeLogin_()
54295433
return "$?"
54305434
}
54315435

5432-
##----------------------------------------##
5433-
## Modified by Martinski W. [2026-Jan-01] ##
5434-
##----------------------------------------##
5436+
##------------------------------------------##
5437+
## Modified by ExtremeFiretop [2026-Sep-16] ##
5438+
##------------------------------------------##
54355439
# Trigger the node "Check for updates" (no waiting here)
54365440
_MeshNodeTriggerFWCheck_()
54375441
{
@@ -5443,6 +5447,7 @@ _MeshNodeTriggerFWCheck_()
54435447
local safeID="$(_MeshSafeID_ "$nodeIPv4addr")"
54445448
local nodeURL="$(_GetNodeURL_ "$nodeIPv4addr")"
54455449
local cookieFile="/tmp/${runID}.${safeID}.cookie"
5450+
local nodeBusy nodeBusyRC
54465451

54475452
# Check for Login Credentials #
54485453
credsENC="$(Get_Custom_Setting credentials_base64)"
@@ -5463,6 +5468,30 @@ _MeshNodeTriggerFWCheck_()
54635468
return 1
54645469
fi
54655470

5471+
# Check if the AiMesh node is already performing a MerlinAU F/W update
5472+
# before triggering the built-in firmware update check.
5473+
nodeBusy="$(curl -s -k "${nodeURL}/appGet.cgi?hook=nvram_get(merlinau_fw_update)" \
5474+
-H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \
5475+
-H 'Accept: application/json,text/plain,*/*' \
5476+
-H 'Accept-Language: en-US,en;q=0.5' \
5477+
-H 'Connection: keep-alive' \
5478+
-H "Referer: ${nodeURL}/index.asp" \
5479+
--cookie "$cookieFile" \
5480+
--max-time 2 2>/dev/null)"
5481+
nodeBusyRC="$?"
5482+
5483+
if [ "$nodeBusyRC" -eq 0 ] && echo "$nodeBusy" | grep -Eq '"merlinau_fw_update"[[:space:]]*:[[:space:]]*"1"'
5484+
then
5485+
Say "AiMesh Node [$nodeIPv4addr] entered an active MerlinAU F/W update before start_webs_update. Skipping firmware check."
5486+
5487+
# Best-effort logout of this primary-router session, then remove its cookie.
5488+
curl -s -k "${nodeURL}/Logout.asp" \
5489+
--cookie "$cookieFile" \
5490+
--max-time 2 >/dev/null 2>&1
5491+
rm -f "$cookieFile"
5492+
return 0
5493+
fi
5494+
54665495
# Trigger firmware check (mimic WebUI "Check" button) #
54675496
curl -s -k "${nodeURL}/start_apply.htm" \
54685497
--referer "${nodeURL}/Advanced_FirmwareUpgrade_Content.asp" \
@@ -9755,11 +9784,15 @@ _Unmount_Eject_USB_Drives_()
97559784
"$ejectUSB_OK" && return 0 || return 1
97569785
}
97579786

9758-
##----------------------------------------##
9759-
## Modified by Martinski W. [2026-Jan-01] ##
9760-
##----------------------------------------##
9787+
##------------------------------------------##
9788+
## Modified by ExtremeFiretop [2026-Sep-16] ##
9789+
##------------------------------------------##
97619790
_RunFirmwareUpdateNow_()
97629791
{
9792+
local fwUploadResponseFile="/tmp/upload_response.txt"
9793+
local fwUploadDiagFile="${SETTINGS_DIR}/last_fw_upload_response.txt"
9794+
local curlRC=0 uploadHTTPcode=""
9795+
97639796
# Double-check the directory exists before using it #
97649797
[ ! -d "$FW_LOG_DIR" ] && mkdir -p -m 755 "$FW_LOG_DIR"
97659798

@@ -10219,6 +10252,15 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1021910252
fi
1022010253
fi
1022110254

10255+
#------------------------------------------------------------------------#
10256+
# A volatile guard before restarting/logging into the WebGUI.
10257+
# Primary routers running MerlinAU can query this nvram value with appGet.cgi
10258+
# and avoid triggering start_webs_update on this router mid-flash.
10259+
# Do not commit this value since a reboot should clear it automatically.
10260+
#------------------------------------------------------------------------#
10261+
nvram set merlinau_fw_update=1
10262+
rm -f "$fwUploadResponseFile" "$fwUploadDiagFile"
10263+
1022210264
#------------------------------------------------------------#
1022310265
# Restart the WebGUI to make sure nobody else is logged in
1022410266
# so that the F/W Update can start without interruptions.
@@ -10311,7 +10353,8 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1031110353
Say "Flashing ${GRNct}${firmware_file}${NOct}...\n${REDct}Please wait for reboot in about 4 minutes or less.${NOct}"
1031210354
echo
1031310355

10314-
# *WARNING*: NO MORE logging at this point & beyond #
10356+
# Avoid persistent logging from this point during the normal flash path. #
10357+
# Failure diagnostics are written only if the router does not reboot. #
1031510358
sync ; sleep 2 ; echo 3 > /proc/sys/vm/drop_caches ; sleep 3
1031610359

1031710360
##-------------------------------------##
@@ -10327,7 +10370,7 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1032710370
# the following 'Curl' command MUST always be the last step in this block.
1032810371
# Do NOT insert any commands after it! (unless you understand the implications).
1032910372
#----------------------------------------------------------------------------------#
10330-
nohup curl -k "${routerURL}/upgrade.cgi" \
10373+
nohup curl -sS -k "${routerURL}/upgrade.cgi" \
1033110374
--referer "${routerURL}/Advanced_FirmwareUpgrade_Content.asp" \
1033210375
--user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \
1033310376
-H 'Accept-Language: en-US,en;q=0.5' \
@@ -10340,7 +10383,9 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1034010383
-F 'preferred_lang=EN' \
1034110384
-F "firmver=${dottedVersion}" \
1034210385
-F "file=@${firmware_file}" \
10343-
--cookie "$cookieFile" > /tmp/upload_response.txt 2>&1 &
10386+
--cookie "$cookieFile" \
10387+
--write-out '\nMERLINAU_HTTP_CODE:%{http_code}\n' \
10388+
> "$fwUploadResponseFile" 2>&1 &
1034410389
curlPID=$!
1034510390

1034610391
#----------------------------------------------------------#
@@ -10356,16 +10401,40 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1035610401
sleep 180
1035710402
if [ "$curlPID" -gt 0 ]
1035810403
then
10359-
kill -EXIT $curlPID 2>/dev/null || return
10360-
kill -TERM $curlPID 2>/dev/null
10404+
kill -EXIT "$curlPID" 2>/dev/null || return
10405+
kill -TERM "$curlPID" 2>/dev/null
1036110406
fi
1036210407
) &
10363-
wait $curlPID ; curlPID=0
10408+
10409+
# Preserve Curl's actual result instead of discarding it. #
10410+
wait "$curlPID"
10411+
curlRC=$?
10412+
curlPID=0
10413+
uploadHTTPcode="$(sed -n 's/^MERLINAU_HTTP_CODE://p' "$fwUploadResponseFile" 2>/dev/null | tail -n 1)"
10414+
1036410415
#----------------------------------------------------------#
1036510416
# Let's wait for 3 minutes here. If the router does not
10366-
# reboot by itself after the process returns, do it now.
10417+
# reboot by itself after the process returns,
10418+
# preserve any diagnostics then reboot.
10419+
# A successful flash reboots before this step.
1036710420
#----------------------------------------------------------#
1036810421
sleep 180
10422+
10423+
{
10424+
echo "MerlinAU v$SCRIPT_VERSION firmware upload diagnostics"
10425+
echo "Timestamp: $(date '+%Y-%m-%d %H:%M:%S %Z')"
10426+
echo "Router: $MODEL_ID"
10427+
echo "Firmware image: $firmware_file"
10428+
echo "Curl exit code: $curlRC"
10429+
echo "HTTP status: ${uploadHTTPcode:-UNKNOWN}"
10430+
echo "------------------------------------------------------------"
10431+
[ -s "$fwUploadResponseFile" ] && cat "$fwUploadResponseFile"
10432+
} > "$fwUploadDiagFile" 2>/dev/null
10433+
chmod 600 "$fwUploadDiagFile" 2>/dev/null
10434+
10435+
_MsgToSysLog_ "F/W upload did not cause the router to reboot within 180 seconds. Curl exit code [$curlRC], HTTP status [${uploadHTTPcode:-UNKNOWN}]."
10436+
_MsgToSysLog_ "F/W upload diagnostics saved to [$fwUploadDiagFile]."
10437+
1036910438
_ReleaseLock_
1037010439
/sbin/service reboot
1037110440
else

0 commit comments

Comments
 (0)