Skip to content

Commit a30bff4

Browse files
Merge pull request #601 from ExtremeFiretop/Fix-Race-Condition
Prevent mesh firmware checks from interrupting node updates
2 parents b6ce1c0 + 6135b27 commit a30bff4

1 file changed

Lines changed: 91 additions & 27 deletions

File tree

‎MerlinAU.sh‎

Lines changed: 91 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -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

@@ -5433,9 +5437,9 @@ _DoMeshNodeLogin_()
54335437
return "$?"
54345438
}
54355439

5436-
##----------------------------------------##
5437-
## Modified by Martinski W. [2026-Jan-01] ##
5438-
##----------------------------------------##
5440+
##------------------------------------------##
5441+
## Modified by ExtremeFiretop [2026-Sep-16] ##
5442+
##------------------------------------------##
54395443
# Trigger the node "Check for updates" (no waiting here)
54405444
_MeshNodeTriggerFWCheck_()
54415445
{
@@ -5447,6 +5451,7 @@ _MeshNodeTriggerFWCheck_()
54475451
local safeID="$(_MeshSafeID_ "$nodeIPv4addr")"
54485452
local nodeURL="$(_GetNodeURL_ "$nodeIPv4addr")"
54495453
local cookieFile="/tmp/${runID}.${safeID}.cookie"
5454+
local nodeBusy nodeBusyRC
54505455

54515456
# Check for Login Credentials #
54525457
credsENC="$(Get_Custom_Setting credentials_base64)"
@@ -5467,6 +5472,24 @@ _MeshNodeTriggerFWCheck_()
54675472
return 1
54685473
fi
54695474

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

9762-
##----------------------------------------##
9763-
## Modified by Martinski W. [2026-Jan-01] ##
9764-
##----------------------------------------##
9785+
##------------------------------------------##
9786+
## Modified by ExtremeFiretop [2026-Sep-16] ##
9787+
##------------------------------------------##
97659788
_RunFirmwareUpdateNow_()
97669789
{
9790+
local fwUploadResponseFile="/tmp/upload_response.txt"
9791+
local fwUploadDiagFile="${SETTINGS_DIR}/last_fw_upload_response.txt"
9792+
local curlRC=0 uploadHTTPcode=""
9793+
97679794
# Double-check the directory exists before using it #
97689795
[ ! -d "$FW_LOG_DIR" ] && mkdir -p -m 755 "$FW_LOG_DIR"
97699796

@@ -10223,13 +10250,14 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1022310250
fi
1022410251
fi
1022510252

10226-
#------------------------------------------------------------#
10227-
# Restart the WebGUI to make sure nobody else is logged in
10228-
# so that the F/W Update can start without interruptions.
10229-
#------------------------------------------------------------#
10230-
"$isInteractive" && printf "\nRestarting web server... Please wait.\n"
10231-
/sbin/service restart_httpd >/dev/null 2>&1 &
10232-
sleep 4
10253+
#------------------------------------------------------------------------#
10254+
# A volatile guard before restarting/logging into the WebGUI.
10255+
# Primary routers running MerlinAU can query this nvram value with appGet.cgi
10256+
# and avoid triggering start_webs_update on this router mid-flash.
10257+
# Do not commit this value since a reboot should clear it automatically.
10258+
#------------------------------------------------------------------------#
10259+
nvram set merlinau_fw_update=1
10260+
rm -f "$fwUploadResponseFile" "$fwUploadDiagFile"
1023310261

1023410262
# Send last email notification before F/W flash #
1023510263
_SendEMailNotification_ START_FW_UPDATE_STATUS
@@ -10301,21 +10329,19 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1030110329
# Remove SIGHUP to allow script to continue #
1030210330
trap '' HUP
1030310331

10304-
# Stop Entware services WITHOUT exceptions BEFORE the F/W flash #
10305-
_EntwareServicesHandler_ stop -noskip
10306-
1030710332
##-------------------------------------##
1030810333
## Added by Martinski W. [2024-Sep-15] ##
1030910334
##-------------------------------------##
1031010335
# Remove cron jobs from 3rd-party Add-Ons #
1031110336
_RemoveCronJobsFromAddOns_
1031210337

10338+
# Stop Entware services WITHOUT exceptions BEFORE the F/W flash #
10339+
_EntwareServicesHandler_ stop -noskip
10340+
1031310341
_Do_PostReboot_FWUpdate_Setup_
10314-
echo
10315-
Say "Flashing ${GRNct}${firmware_file}${NOct}...\n${REDct}Please wait for reboot in about 4 minutes or less.${NOct}"
10316-
echo
1031710342

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

1032110347
##-------------------------------------##
@@ -10325,13 +10351,25 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1032510351
#------------------------------------------------------------------#
1032610352
_Unmount_Eject_USB_Drives_
1032710353

10354+
echo
10355+
Say "Flashing ${GRNct}${firmware_file}${NOct}...\n${REDct}Please wait for reboot in about 4 minutes or less.${NOct}"
10356+
echo
10357+
10358+
#------------------------------------------------------------#
10359+
# Restart the WebGUI to make sure nobody else is logged in
10360+
# so that the F/W Update can start without interruptions.
10361+
#------------------------------------------------------------#
10362+
"$isInteractive" && printf "\nRestarting web server... Please wait.\n"
10363+
/sbin/service restart_httpd >/dev/null 2>&1 &
10364+
sleep 3
10365+
1032810366
#----------------------------------------------------------------------------------#
1032910367
# **IMPORTANT NOTE**:
1033010368
# Due to the nature of 'nohup' and the specific behavior of this 'Curl' request,
1033110369
# the following 'Curl' command MUST always be the last step in this block.
1033210370
# Do NOT insert any commands after it! (unless you understand the implications).
1033310371
#----------------------------------------------------------------------------------#
10334-
nohup curl -k "${routerURL}/upgrade.cgi" \
10372+
nohup curl -sS -k "${routerURL}/upgrade.cgi" \
1033510373
--referer "${routerURL}/Advanced_FirmwareUpgrade_Content.asp" \
1033610374
--user-agent 'Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0' \
1033710375
-H 'Accept-Language: en-US,en;q=0.5' \
@@ -10344,7 +10382,9 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1034410382
-F 'preferred_lang=EN' \
1034510383
-F "firmver=${dottedVersion}" \
1034610384
-F "file=@${firmware_file}" \
10347-
--cookie "$cookieFile" > /tmp/upload_response.txt 2>&1 &
10385+
--cookie "$cookieFile" \
10386+
--write-out '\nMERLINAU_HTTP_CODE:%{http_code}\n' \
10387+
> "$fwUploadResponseFile" 2>&1 &
1034810388
curlPID=$!
1034910389

1035010390
#----------------------------------------------------------#
@@ -10360,16 +10400,40 @@ Please manually update to version ${GRNct}${MinSupportedFirmwareVers}${NOct} or
1036010400
sleep 180
1036110401
if [ "$curlPID" -gt 0 ]
1036210402
then
10363-
kill -EXIT $curlPID 2>/dev/null || return
10364-
kill -TERM $curlPID 2>/dev/null
10403+
kill -EXIT "$curlPID" 2>/dev/null || return
10404+
kill -TERM "$curlPID" 2>/dev/null
1036510405
fi
1036610406
) &
10367-
wait $curlPID ; curlPID=0
10407+
10408+
# Preserve Curl's actual result instead of discarding it. #
10409+
wait "$curlPID"
10410+
curlRC=$?
10411+
curlPID=0
10412+
uploadHTTPcode="$(sed -n 's/^MERLINAU_HTTP_CODE://p' "$fwUploadResponseFile" 2>/dev/null | tail -n 1)"
10413+
1036810414
#----------------------------------------------------------#
1036910415
# Let's wait for 3 minutes here. If the router does not
10370-
# reboot by itself after the process returns, do it now.
10416+
# reboot by itself after the process returns,
10417+
# preserve any diagnostics then reboot.
10418+
# A successful flash reboots before this step.
1037110419
#----------------------------------------------------------#
1037210420
sleep 180
10421+
10422+
{
10423+
echo "MerlinAU v$SCRIPT_VERSION firmware upload diagnostics"
10424+
echo "Timestamp: $(date '+%Y-%m-%d %H:%M:%S %Z')"
10425+
echo "Router: $MODEL_ID"
10426+
echo "Firmware image: $firmware_file"
10427+
echo "Curl exit code: $curlRC"
10428+
echo "HTTP status: ${uploadHTTPcode:-UNKNOWN}"
10429+
echo "------------------------------------------------------------"
10430+
[ -s "$fwUploadResponseFile" ] && cat "$fwUploadResponseFile"
10431+
} > "$fwUploadDiagFile" 2>/dev/null
10432+
chmod 600 "$fwUploadDiagFile" 2>/dev/null
10433+
10434+
_MsgToSysLog_ "F/W upload did not cause the router to reboot within 180 seconds. Curl exit code [$curlRC], HTTP status [${uploadHTTPcode:-UNKNOWN}]."
10435+
_MsgToSysLog_ "F/W upload diagnostics saved to [$fwUploadDiagFile]."
10436+
1037310437
_ReleaseLock_
1037410438
/sbin/service reboot
1037510439
else

0 commit comments

Comments
 (0)