44#
55# Original Creation Date: 2023-Oct-01 by @ExtremeFiretop.
66# Official Co-Author: @Martinski W. - Date: 2023-Nov-01
7- # Last Modified: 2026-May-21
7+ # Last Modified: 2026-Jun-11
88# ##################################################################
99set -u
1010
1111# # Set version for each Production Release ##
12- readonly SCRIPT_VERSION=1.6.3
13- readonly SCRIPT_VERSTAG=" 26052123 "
12+ readonly SCRIPT_VERSION=1.6.4
13+ readonly SCRIPT_VERSTAG=" 26061118 "
1414readonly SCRIPT_NAME=" MerlinAU"
1515# # Set to "master" for Production Releases ##
16- SCRIPT_BRANCH=" master "
16+ SCRIPT_BRANCH=" dev "
1717
1818# #----------------------------------------##
1919# # Modified by Martinski W. [2024-Jul-03] ##
@@ -434,7 +434,7 @@ _ReleaseLock_()
434434 fi
435435 [ -s " $LockFilePath " ] && return 0
436436 fi
437- rm -f " $LockFilePath "
437+ printf ' ' > " $LockFilePath "
438438}
439439
440440# # Defaults ##
@@ -445,7 +445,7 @@ LockFileMaxAgeSecs=600 #10-minutes#
445445if [ $# -eq 0 ] || [ -z " $1 " ]
446446then
447447 # Interactive Mode#
448- LockMaxTimeoutSecs=3
448+ LockMaxTimeoutSecs=5
449449 LockFileMaxAgeSecs=1200
450450else
451451 case " $1 " in
@@ -478,7 +478,7 @@ _AcquireLock_()
478478 _CreateLockFile_ ()
479479 { echo " $$ |$lockTypeReq " > " $LockFilePath " ; }
480480
481- if [ ! -f " $LockFilePath " ]
481+ if [ ! -s " $LockFilePath " ]
482482 then _CreateLockFile_ ; return 0
483483 fi
484484
@@ -539,6 +539,33 @@ _AcquireLock_()
539539 return " $retCode "
540540}
541541
542+ # #-------------------------------------##
543+ # # Added for initialization operations ##
544+ # #-------------------------------------##
545+ initMutexFLock_FD=577
546+ initMutexFLock_FN=" /tmp/var/${ScriptFNameTag} _Initialization.FLock"
547+
548+ # --------------------------------------------------------------#
549+ # This is a mutually exclusive, blocking FLOCK mechanism used
550+ # to protect initialization routines when concurrent MerlinAU
551+ # executions are running (e.g. called from services-start).
552+ # --------------------------------------------------------------#
553+ _AcquireInitMutexFLock_ ()
554+ {
555+ eval exec " ${initMutexFLock_FD} >$initMutexFLock_FN "
556+ if flock -x " $initMutexFLock_FD " 2> /dev/null
557+ then return 0
558+ fi
559+ eval exec " ${initMutexFLock_FD} >&-"
560+ return 1
561+ }
562+
563+ _ReleaseInitMutexFLock_ ()
564+ {
565+ flock -u " $initMutexFLock_FD " 2> /dev/null
566+ eval exec " ${initMutexFLock_FD} >&-"
567+ }
568+
542569# #-------------------------------------##
543570# # Added by Martinski W. [2026-Mar-18] ##
544571# #-------------------------------------##
@@ -773,7 +800,8 @@ Toggle_LEDs_PID=""
773800
774801# To enable/disable the built-in "F/W Update Check" #
775802FW_UpdateCheckState=" $( nvram get firmware_check_enable) "
776- FW_UpdateCheckScript=" /usr/sbin/webs_update.sh"
803+ readonly FW_WebsUpdateFile=" webs_update.sh"
804+ readonly FW_UpdateCheckScript=" /usr/sbin/$FW_WebsUpdateFile "
777805
778806# #-------------------------------------##
779807# # Added by Martinski W. [2023-Nov-24] ##
@@ -2217,31 +2245,46 @@ readonly POST_REBOOT_SCRIPT_HOOK="[ -x $ScriptFilePath ] && $POST_REBOOT_SCRIPT_
22172245readonly POST_UPDATE_EMAIL_SCRIPT_JOB=" $ScriptFilePath postUpdateEmail &"
22182246readonly POST_UPDATE_EMAIL_SCRIPT_HOOK=" [ -x $ScriptFilePath ] && $POST_UPDATE_EMAIL_SCRIPT_JOB $hookScriptTagStr "
22192247
2220- # #-------------------------------------##
2221- # # Added by Martinski W. [2026-Feb-07 ] ##
2222- # #-------------------------------------##
2248+ # #------------------------------------------ ##
2249+ # # Modified by ExtremeFiretop [2026-Jun-10 ] ##
2250+ # #------------------------------------------ ##
22232251_CleanUpOldLogFiles_ ()
22242252{
22252253 [ ! -d " $FW_LOG_DIR " ] && return 1
2226- local numLogFiles topLogFile
2254+ local numLogFiles topLogFile savedTopLogFile= " "
22272255
22282256 numLogFiles=" $( ls -1lt " $FW_LOG_DIR " /* .log 2> /dev/null | wc -l) "
22292257 # Leave one log file (if any available) #
22302258 [ " $numLogFiles " -lt 2 ] && return 0
22312259
22322260 # Save the most recent log file #
2233- topFile=" $( ls -1t " $FW_LOG_DIR " /* .log 2> /dev/null | head -n1) "
2234- [ -n " $topFile " ] && mv -f " $topFile " " ${topFile} .SAVED.TEMP.LOG"
2261+ topLogFile=" $( ls -1t " $FW_LOG_DIR " /* .log 2> /dev/null | head -n1) "
2262+
2263+ if [ -n " $topLogFile " ] && [ -s " $topLogFile " ]
2264+ then
2265+ savedTopLogFile=" ${topLogFile} .SAVED.$$ .TEMP.LOG"
2266+ if ! mv -f " $topLogFile " " $savedTopLogFile " 2> /dev/null
2267+ then
2268+ return 1
2269+ fi
2270+ fi
22352271
22362272 # Delete logs older than 30 days #
22372273 /usr/bin/find -L " $FW_LOG_DIR " -name ' *.log' -mtime +30 -exec rm {} \;
22382274
22392275 # Restore the most recent log file #
2240- [ -n " $topFile " ] && mv -f " ${topFile} .SAVED.TEMP.LOG" " $topFile "
2276+ if [ -n " $topLogFile " ] && \
2277+ [ -n " $savedTopLogFile " ] && \
2278+ [ -s " $savedTopLogFile " ]
2279+ then
2280+ if ! mv -f " $savedTopLogFile " " $topLogFile " 2> /dev/null
2281+ then
2282+ return 1
2283+ fi
2284+ fi
2285+ return 0
22412286}
22422287
2243- _CleanUpOldLogFiles_
2244-
22452288# #----------------------------------------##
22462289# # Modified by Martinski W. [2024-Jan-27] ##
22472290# #----------------------------------------##
@@ -2860,7 +2903,7 @@ _CurlFileDownload_()
28602903 then return 1
28612904 fi
28622905 local retCode=1
2863- local tempFilePathDL=" ${2} .DL.TMP"
2906+ local tempFilePathDL=" ${2} .DL.$$ . TMP"
28642907 local srceFilePathDL=" ${SCRIPT_URL_REPO} /$1 "
28652908
28662909 curl -LSs --retry 4 --retry-delay 5 --retry-connrefused \
@@ -2877,7 +2920,11 @@ _CurlFileDownload_()
28772920 then updatedWebUIPage=true
28782921 else updatedWebUIPage=false
28792922 fi
2880- mv -f " $tempFilePathDL " " $2 "
2923+ if ! mv -f " $tempFilePathDL " " $2 "
2924+ then
2925+ rm -f " $tempFilePathDL "
2926+ return 1
2927+ fi
28812928 retCode=0
28822929 fi
28832930
@@ -12033,7 +12080,7 @@ _DoInitializationStartup_()
1203312080}
1203412081
1203512082# #----------------------------------------##
12036- # # Modified by Martinski W. [2025-Jul-29 ] ##
12083+ # # Modified by Martinski W. [2026-Jun-11 ] ##
1203712084# #----------------------------------------##
1203812085# ######################################################################
1203912086# TEMPORARY hack to check if the Gnuton F/W built-in 'webs_update.sh'
@@ -12052,10 +12099,9 @@ _Gnuton_Check_Webs_Update_Script_()
1205212099 return 0
1205312100 fi
1205412101
12055- local theWebsUpdateFile=" webs_update.sh"
12056- local fixedGnutonWebsUpdateFilePath=" ${SETTINGS_DIR} /$theWebsUpdateFile "
12057- local dwnldGnutonWebsUpdateFilePath=" ${SETTINGS_DIR} /${theWebsUpdateFile} .GNUTON"
12058- local localVersTag remoteVersTag
12102+ local fixedGnutonWebsUpdateFilePath=" ${SETTINGS_DIR} /$FW_WebsUpdateFile "
12103+ local dwnldGnutonWebsUpdateFilePath=" ${SETTINGS_DIR} /${FW_WebsUpdateFile} .GNUTON.$$ "
12104+ local localVersTag remoteVersTag diffRC mountPoint
1205912105
1206012106 # Get local VERSTAG (if any) #
1206112107 localVersTag=" $( _Get_GnutonWebUpdate_ScriptVersTag_ " $FW_UpdateCheckScript " ) "
@@ -12064,39 +12110,119 @@ _Gnuton_Check_Webs_Update_Script_()
1206412110 # Get the fixed version of the script targeted for Gnuton F/W #
1206512111 if _CurlFileDownload_ " gnuton_webs_update.sh" " $dwnldGnutonWebsUpdateFilePath "
1206612112 then
12067- chmod 755 " $dwnldGnutonWebsUpdateFilePath "
12113+ if ! chmod 755 " $dwnldGnutonWebsUpdateFilePath " 2> /dev/null
12114+ then
12115+ Say " ${REDct} **ERROR**${NOct} : Unable to set permissions on the downloaded GNUton \" ${FW_WebsUpdateFile} \" file."
12116+ rm -f " $dwnldGnutonWebsUpdateFilePath "
12117+ return 1
12118+ fi
1206812119 remoteVersTag=" $( _Get_GnutonWebUpdate_ScriptVersTag_ " $dwnldGnutonWebsUpdateFilePath " ) "
1206912120 [ -z " $remoteVersTag " ] && remoteVersTag=0
1207012121 else
12071- return 1 # NOT available so do nothing#
12122+ rm -f " $dwnldGnutonWebsUpdateFilePath "
12123+ return 1
12124+ fi
12125+
12126+ # Distinguish files that differ from an actual comparison error #
12127+ diff -q " $FW_UpdateCheckScript " " $dwnldGnutonWebsUpdateFilePath " > /dev/null 2>&1
12128+ diffRC=" $? "
12129+
12130+ if [ " $diffRC " -gt 1 ]
12131+ then
12132+ Say " ${REDct} **ERROR**${NOct} : Unable to compare the GNUton \" ${FW_WebsUpdateFile} \" files."
12133+ rm -f " $dwnldGnutonWebsUpdateFilePath "
12134+ return 1
1207212135 fi
1207312136
1207412137 # (Re)bind/mount only if remote is newer version OR files differ #
1207512138 if [ " $remoteVersTag " -gt " $localVersTag " ] || \
12076- ! diff -q " $FW_UpdateCheckScript " " $dwnldGnutonWebsUpdateFilePath " > /dev/null 2>&1
12139+ { [ " $remoteVersTag " -eq " $localVersTag " ] && [ " $diffRC " -ne 0 ] ; }
1207712140 then
12078- umount " $FW_UpdateCheckScript " 2> /dev/null
12079- mv -f " $dwnldGnutonWebsUpdateFilePath " " $fixedGnutonWebsUpdateFilePath "
12080- mount -o bind " $fixedGnutonWebsUpdateFilePath " " $FW_UpdateCheckScript "
12081- Say " ${YLWct} Set up a fixed version of the \" ${theWebsUpdateFile} \" script file.${NOct} "
12141+ for mountPoint in $( grep " $FW_UpdateCheckScript " /proc/mounts | awk -F' ' ' {print $2}' )
12142+ do umount " $FW_UpdateCheckScript " 2> /dev/null
12143+ done
12144+
12145+ if grep -q " $FW_UpdateCheckScript " /proc/mounts
12146+ then
12147+ Say " ${REDct} **ERROR**${NOct} : Unable to unmount \" $FW_UpdateCheckScript \" ."
12148+ rm -f " $dwnldGnutonWebsUpdateFilePath "
12149+ return 1
12150+ fi
12151+
12152+ if ! mv -f " $dwnldGnutonWebsUpdateFilePath " " $fixedGnutonWebsUpdateFilePath " 2> /dev/null
12153+ then
12154+ Say " ${REDct} **ERROR**${NOct} : Unable to install the fixed GNUton \" ${FW_WebsUpdateFile} \" file."
12155+ rm -f " $dwnldGnutonWebsUpdateFilePath "
12156+ return 1
12157+ fi
12158+
12159+ if [ ! -s " $fixedGnutonWebsUpdateFilePath " ]
12160+ then
12161+ Say " ${REDct} **ERROR**${NOct} : GNUton \" ${FW_WebsUpdateFile} \" source file is missing before bind mount."
12162+ return 1
12163+ fi
12164+
12165+ if [ ! -s " $FW_UpdateCheckScript " ]
12166+ then
12167+ Say " ${REDct} **ERROR**${NOct} : Bind-mount target \" $FW_UpdateCheckScript \" does not exist."
12168+ return 1
12169+ fi
12170+
12171+ if ! mount -o bind " $fixedGnutonWebsUpdateFilePath " " $FW_UpdateCheckScript "
12172+ then
12173+ Say " ${REDct} **ERROR**${NOct} : Unable to bind-mount the fixed GNUton \" ${FW_WebsUpdateFile} \" file."
12174+ return 1
12175+ fi
12176+ Say " ${YLWct} Set up a fixed version of the \" ${FW_WebsUpdateFile} \" script file.${NOct} "
1208212177 else
1208312178 rm -f " $dwnldGnutonWebsUpdateFilePath "
1208412179 fi
12180+ return 0
12181+ }
12182+
12183+ # #----------------------------------------##
12184+ # # Modified by Martinski W. [2026-Jun-11] ##
12185+ # #----------------------------------------##
12186+ # Startup/Initialization operations done by possible concurrent processes #
12187+ _RunLockedInitializationChecks_ ()
12188+ {
12189+ local retCode=0
12190+
12191+ if ! _CleanUpOldLogFiles_
12192+ then
12193+ Say " ${YLWct} WARNING:${NOct} Unable to clean up old firmware-update log files."
12194+ retCode=1
12195+ fi
12196+
12197+ # Set variable to 'false' to stop the check #
12198+ checkWebsUpdateScriptForGnuton=" $isGNUtonFW "
12199+ if ! _Gnuton_Check_Webs_Update_Script_
12200+ then
12201+ Say " ${YLWct} WARNING:${NOct} Unable to check or install the GNUton \" ${FW_WebsUpdateFile} \" patch."
12202+ retCode=1
12203+ fi
12204+
12205+ return " $retCode "
1208512206}
1208612207
1208712208if [ " $SCRIPT_BRANCH " = " master" ]
1208812209then SCRIPT_VERS_INFO=" "
1208912210else SCRIPT_VERS_INFO=" [$versionDev_TAG ]"
1209012211fi
1209112212
12092- # # Set variable to 'false' to stop the check ##
12093- checkWebsUpdateScriptForGnuton=" $isGNUtonFW "
12094- _Gnuton_Check_Webs_Update_Script_
12095-
1209612213FW_InstalledVersion=" $( _GetCurrentFWInstalledLongVersion_) "
1209712214FW_InstalledVerStr=" ${GRNct}${FW_InstalledVersion}${NOct} "
1209812215FW_NewUpdateVerInit=TBD
1209912216
12217+ if _AcquireInitMutexFLock_
12218+ then
12219+ _RunLockedInitializationChecks_
12220+ _ReleaseInitMutexFLock_
12221+ else
12222+ Say " ${REDct} **ERROR**${NOct} : Unable to acquire the initialization lock. Exiting..."
12223+ exit 1
12224+ fi
12225+
1210012226# #----------------------------------------##
1210112227# # Modified by Martinski W. [2025-Apr-07] ##
1210212228# #----------------------------------------##
@@ -12132,7 +12258,8 @@ fi
1213212258if [ $# -gt 0 ]
1213312259then
1213412260 if ! _AcquireLock_ cliOptsLock
12135- then Say " Exiting..." ; exit 1 ; fi
12261+ then Say " Exiting..." ; exit 1
12262+ fi
1213612263
1213712264 [ " $1 " = " amtmupdate" ] && isVerbose=false
1213812265
0 commit comments