From 58279fa96c7845fa006c6a2b789ebba2f48db49e Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 08:55:35 -0400 Subject: [PATCH 1/7] Bug Fixes for Fresh Installs Bug Fixes for Fresh Installs --- MerlinAU.sh | 69 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 697cc167..253df58f 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -4,12 +4,12 @@ # # Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. # Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Mar-30 +# Last Modified: 2025-Apr-07 ################################################################### set -u ## Set version for each Production Release ## -readonly SCRIPT_VERSION=1.4.0 +readonly SCRIPT_VERSION=1.4.1 readonly SCRIPT_NAME="MerlinAU" ## Set to "master" for Production Releases ## SCRIPT_BRANCH="dev" @@ -2151,14 +2151,39 @@ _Mount_WebUI_() return 0 } -##-------------------------------------## -## Added by Martinski W. [2025-Feb-12] ## -##-------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2025-Apr-07] ## +##------------------------------------------## _CheckFor_WebGUI_Page_() { - if "$mountWebGUI_OK" && \ - [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] - then _Mount_WebUI_ ; fi + if "$mountWebGUI_OK" && \ + [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] + then + updatedWebUIPage=false + # Only try to download if the local .asp file does NOT exist: + if [ ! -f "$SCRIPT_WEB_ASP_FILE" ] + then + if _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" + then + chmod 664 "$SCRIPT_WEB_ASP_PATH" + if "$updatedWebUIPage" + then + theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" + if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] + then + sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" + rm -f "${SHARED_WEB_DIR}/$theWebPage" + rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" + fi + _Mount_WebUI_ + fi + else + Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME." + fi + else + _Mount_WebUI_ + fi + fi } ##----------------------------------------## @@ -9587,13 +9612,12 @@ then _ReleaseLock_ ; exit 0 fi -##---------------------------------------## -## Added by ExtremeFiretop [2025-Feb-08] ## -##---------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2025-Apr-07] ## +##------------------------------------------## _CheckAndSetBackupOption_() { - local currentBackupOption - currentBackupOption="$(Get_Custom_Setting "FW_Auto_Backupmon")" + local currentBackupOption="$(Get_Custom_Setting "FW_Auto_Backupmon")" if [ -f "/jffs/scripts/backupmon.sh" ] then # If setting is empty, add it to the configuration file # @@ -9661,15 +9685,16 @@ _EnableFWAutoUpdateChecks_() fi } -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-12] ## -##----------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2025-Apr-07] ## +##------------------------------------------## _ConfirmCronJobForFWAutoUpdates_() { if [ $# -gt 0 ] && [ -n "$1" ] && \ echo "$1" | grep -qE "^(install|startup)$" then return 1 ; fi + FW_UpdateCronJobSchedule="$(Get_Custom_Setting FW_New_Update_Cron_Job_Schedule)" # Check if the PREVIOUS Cron Job ID already exists # if eval $cronListCmd | grep -qE "$CRON_JOB_RUN #${CRON_JOB_TAG_OLD}#$" then #If it exists, delete the OLD one & create a NEW one# @@ -10683,9 +10708,9 @@ _MainMenu_() done } -##-------------------------------------## -## Added by Martinski W. [2025-Jan-15] ## -##-------------------------------------## +##------------------------------------------## +## Modified by ExtremeFiretop [2025-Apr-07] ## +##------------------------------------------## _DoInitializationStartup_() { if ! _CheckForMinimumRequirements_ @@ -10694,6 +10719,9 @@ _DoInitializationStartup_() _DoExit_ 1 fi + _CheckAndSetBackupOption_ + _SetDefaultBuildType_ + if [ $# -gt 0 ] && [ -n "$1" ] && \ echo "$1" | grep -qE "^(install|startup)$" then return 1 ; fi @@ -10709,9 +10737,6 @@ _DoInitializationStartup_() _AutoStartupHook_ create 2>/dev/null _AutoServiceEvent_ create 2>/dev/null fi - - _CheckAndSetBackupOption_ - _SetDefaultBuildType_ } FW_InstalledVersion="$(_GetCurrentFWInstalledLongVersion_)" From 75c44160b32dbd2a4527b7d385d433ce9522835c Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 09:11:49 -0400 Subject: [PATCH 2/7] Update MerlinAU.asp --- MerlinAU.asp | 13321 +++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 10639 insertions(+), 2682 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index 3e21edf1..0127599b 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -1,2947 +1,10904 @@ - - - - - - - - - - - - -MerlinAU add-on for ASUSWRT-Merlin Firmware - - - - - - - - - - - - - - - -
- - - -
- - - - - - - -" /> -" /> - -" /> - -" /> -" /> -" /> -" /> -" /> -" /> - - - - - - - - -
  - - - - - - - -
- - - -
-
 
-
MerlinAU
-
-
This is the MerlinAU add-on integrated into the router WebUI -[ - Wiki ] - -
-
 
- - - - - - - - -
- - - - - - - - - - - -
Firmware Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: - <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> -
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
- - - - - - - - - - - -
Settings Status (click to expand/collapse)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
- -
 
- - - - - - -
Actions (click to expand/collapse)
-
- -- - - - - - - -
- -
- -
-
- -
- -
-
- -
- -
-
- -
 
- - - - - - - - - - -
Configuration (click to expand/collapse)
- - -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- -
-
-
- -
-
-
-
- -
-
- - -
- - - -
- - - -
- - -
- Days: - - - - -
- - - - - - - -
-
-
- Hour: - -
-
- Minutes: - -
-
- - - -
- - - -
- -
- -
- -
- - - - -
- - - - -
- - - - -
- -
- -
-
- -
-
-
MerlinAU
-
- - - +FW_InstalledVersion="$(_GetCurrentFWInstalledLongVersion_)" +FW_InstalledVerStr="${GRNct}${FW_InstalledVersion}${NOct}" +FW_NewUpdateVerInit=TBD + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-12] ## +##----------------------------------------## +if [ $# -eq 0 ] || [ -z "$1" ] || \ + { [ $# -gt 1 ] && [ "$1" = "reload" ] ; } +then + if ! _AcquireLock_ cliMenuLock + then Say "Exiting..." ; exit 1 ; fi + + inMenuMode=true + _DoInitializationStartup_ + if _AcquireLock_ cliFileLock + then + _CheckForNewScriptUpdates_ + _ReleaseLock_ cliFileLock + fi + if [ "$ScriptAutoUpdateSetting" = "ENABLED" ] + then _AddScriptAutoUpdateCronJob_ ; fi + _ConfirmCronJobForFWAutoUpdates_ + _CheckFor_WebGUI_Page_ + + _MainMenu_ "$@" + _DoExit_ 0 +fi + +##----------------------------------------## +## Modified by Martinski W. [2025-Feb-15] ## +##----------------------------------------## +if [ $# -gt 0 ] +then + if ! _AcquireLock_ cliOptsLock + then Say "Exiting..." ; exit 1 ; fi + + inMenuMode=false + _DoInitializationStartup_ "$1" + _ConfirmCronJobForFWAutoUpdates_ "$1" + + case "$1" in + run_now) + if _AcquireLock_ cliFileLock + then + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi + ;; + processNodes) _ProcessMeshNodes_ 0 + ;; + addCronJob) _AddFWAutoUpdateCronJob_ + ;; + scriptAUCronJob) _AddScriptAutoUpdateCronJob_ + ;; + postRebootRun) _PostRebootRunNow_ + ;; + postUpdateEmail) _PostUpdateEmailNotification_ + ;; + about) _ShowAbout_ + ;; + help) _ShowHelp_ + ;; + checkupdates) + if _AcquireLock_ cliFileLock + then + _CheckForNewScriptUpdates_ + _ReleaseLock_ cliFileLock + fi + ;; + forceupdate) + if _AcquireLock_ cliFileLock + then + _SCRIPT_UPDATE_ force + _ReleaseLock_ cliFileLock + fi + ;; + develop) _ChangeToDev_ + ;; + stable) _ChangeToStable_ + ;; + startup) _DoStartupInit_ + ;; + install) _DoInstallation_ + ;; + uninstall) _DoUnInstallation_ + ;; + service_event) + if [ "$2" = "start" ] + then + case "$3" in + "${SCRIPT_NAME}uninstall" | \ + "${SCRIPT_NAME}uninstall_keepConfig") + if [ "$3" = "${SCRIPT_NAME}uninstall_keepConfig" ] + then keepConfigFile=true + else keepConfigFile=false + fi + _DoUnInstallation_ + sleep 1 + ;; + "${SCRIPT_NAME}downloadchangelog") + if "$isGNUtonFW" + then + _ManageChangelogGnuton_ "webuidownload" + else + _ManageChangelogMerlin_ "webuidownload" + fi + ;; + "${SCRIPT_NAME}approvechangelog") + currApprovalStatus="$(Get_Custom_Setting "FW_New_Update_Changelog_Approval")" + if [ "$currApprovalStatus" = "BLOCKED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "APPROVED" + elif [ "$currApprovalStatus" = "APPROVED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "BLOCKED" + fi + ;; + "${SCRIPT_NAME}blockchangelog") + currApprovalStatus="$(Get_Custom_Setting "FW_New_Update_Changelog_Approval")" + if [ "$currApprovalStatus" = "APPROVED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "BLOCKED" + elif [ "$currApprovalStatus" = "BLOCKED" ] + then + Update_Custom_Settings "FW_New_Update_Changelog_Approval" "APPROVED" + fi + ;; + "${SCRIPT_NAME}checkupdate" | \ + "${SCRIPT_NAME}checkupdate_bypassDays") + if _AcquireLock_ cliFileLock + then + if [ "$3" = "${SCRIPT_NAME}checkupdate_bypassDays" ] + then bypassPostponedDays=true + else bypassPostponedDays=false + fi + _RunFirmwareUpdateNow_ + _ReleaseLock_ cliFileLock + fi + ;; + "${SCRIPT_NAME}config" | \ + "${SCRIPT_NAME}config_runLoginTest") + if _AcquireLock_ cliFileLock + then + if [ "$3" = "${SCRIPT_NAME}config_runLoginTest" ] + then runLoginCredentialsTest=true + else runLoginCredentialsTest=false + fi + _UpdateConfigFromWebUISettings_ + _ConfirmCronJobForFWAutoUpdates_ + _ReleaseLock_ cliFileLock + fi + ;; + *) + printf "${REDct}INVALID Parameters [$*].${NOct}\n" + ;; + esac + fi + ;; + *) printf "${REDct}INVALID Parameter [$*].${NOct}\n" + ;; + esac + _DoExit_ 0 +fi + +#EOF# From 13257303961f992e8bac4317336e8a78a43b93e8 Mon Sep 17 00:00:00 2001 From: ExtremeFiretop Date: Mon, 7 Apr 2025 09:13:48 -0400 Subject: [PATCH 3/7] Revert "Update MerlinAU.asp" This reverts commit 75c44160b32dbd2a4527b7d385d433ce9522835c. --- MerlinAU.asp | 13325 ++++++++++--------------------------------------- 1 file changed, 2684 insertions(+), 10641 deletions(-) diff --git a/MerlinAU.asp b/MerlinAU.asp index 0127599b..3e21edf1 100644 --- a/MerlinAU.asp +++ b/MerlinAU.asp @@ -1,10904 +1,2947 @@ -#!/bin/sh -################################################################### -# MerlinAU.sh (MerlinAutoUpdate) -# -# Original Creation Date: 2023-Oct-01 by @ExtremeFiretop. -# Official Co-Author: @Martinski W. - Date: 2023-Nov-01 -# Last Modified: 2025-Apr-07 -################################################################### -set -u - -## Set version for each Production Release ## -readonly SCRIPT_VERSION=1.4.1 -readonly SCRIPT_NAME="MerlinAU" -## Set to "master" for Production Releases ## -SCRIPT_BRANCH="dev" - -##----------------------------------------## -## Modified by Martinski W. [2024-Jul-03] ## -##----------------------------------------## -# Script URL Info # -readonly SCRIPT_URL_BASE="https://raw.githubusercontent.com/ExtremeFiretop/MerlinAutoUpdate-Router" -SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH" - -# Firmware URL Info # -readonly FW_SFURL_BASE="https://sourceforge.net/projects/asuswrt-merlin/files" -readonly FW_SFURL_RELEASE_SUFFIX="Release" -readonly FW_GITURL_RELEASE="https://api.github.com/repos/gnuton/asuswrt-merlin.ng/releases/latest" - -##----------------------------------------## -## Modified by Martinski W. [2024-May-31] ## -##----------------------------------------## -# Changelog Info # -readonly CL_URL_NG="${FW_SFURL_BASE}/Documentation/Changelog-NG.txt/download" -readonly CL_URL_386="${FW_SFURL_BASE}/Documentation/Changelog-386.txt/download" -readonly CL_URL_3006="${FW_SFURL_BASE}/Documentation/Changelog-3006.txt/download" - -readonly high_risk_terms="factory default reset|features are disabled|break backward compatibility|must be manually|strongly recommended" - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-24] ## -##----------------------------------------## -# For new script version updates from source repository # -DLRepoVersion="" -DLRepoVersionNum="" -DLRepoBuildNum=0 -ScriptBuildNum=0 -ScriptVersionNum="" -scriptUpdateNotify=0 - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Oct-02] ## -##------------------------------------------## -# For minimum supported firmware version check # -MinFirmwareVerCheckFailed=false -MinSupportedFirmwareVers="3004.386.12.6" - -# For router model check # -routerModelCheckFailed=false -offlineUpdateTrigger=false - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-18] ## -##----------------------------------------## -readonly NOct="\e[0m" -readonly BOLDct="\e[1m" -readonly BLKct="\e[1;30m" -readonly REDct="\e[1;31m" -readonly GRNct="\e[1;32m" -readonly YLWct="\e[1;33m" -readonly BLUEct="\e[1;34m" -readonly MGNTct="\e[1;35m" #Magenta# -readonly CYANct="\e[1;36m" -readonly WHITEct="\e[1;37m" -readonly CRITct="\e[1;41m" -readonly InvREDct="\e[41m" -readonly InvGRNct="\e[42m" -readonly InvMGNct="\e[45m" -readonly InvBREDct="\e[30;101m" -readonly InvBGRNct="\e[30;102m" -readonly InvBYLWct="\e[30;103m" -readonly InvBMGNct="\e[30;105m" - -readonly ScriptFileName="${0##*/}" -readonly ScriptFNameTag="${ScriptFileName%%.*}" -readonly ScriptDirNameD="${ScriptFNameTag}.d" - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-15] ## -##----------------------------------------## -readonly ADDONS_PATH="/jffs/addons" -readonly SCRIPTS_PATH="/jffs/scripts" -readonly SETTINGS_DIR="${ADDONS_PATH}/$ScriptDirNameD" -readonly CONFIG_FILE="${SETTINGS_DIR}/custom_settings.txt" -readonly SCRIPT_VERPATH="${SETTINGS_DIR}/version.txt" -readonly HELPER_JSFILE="${SETTINGS_DIR}/CheckHelper.js" -readonly PSWD_CHECK_JS="${SETTINGS_DIR}/PswdCheckStatus.js" -readonly CHANGELOG_PATH="${SETTINGS_DIR}/changelog.txt" -readonly SHARED_SETTINGS_FILE="${ADDONS_PATH}/custom_settings.txt" -readonly SHARED_WEB_DIR="$(readlink -f /www/user)" -readonly SCRIPT_WEB_DIR="${SHARED_WEB_DIR}/$SCRIPT_NAME" -readonly SCRIPT_WEB_ASP_FILE="${SCRIPT_NAME}.asp" -readonly SCRIPT_WEB_ASP_PATH="$SETTINGS_DIR/$SCRIPT_WEB_ASP_FILE" -readonly TEMP_MENU_TREE="/tmp/menuTree.js" -readonly ORIG_MENU_TREE="/www/require/modules/menuTree.js" -readonly WEBUI_LOCKFD=386 -readonly WEBUI_LOCKFILE="/tmp/addonwebui.lock" -readonly TEMPFILE="/tmp/MerlinAU_settings_$$.txt" -readonly webPageFileRegExp="user([1-9]|[1-2][0-9])[.]asp" -readonly webPageLineTabExp="\{url: \"$webPageFileRegExp\", tabName: " -readonly webPageLineRegExp="${webPageLineTabExp}\"$SCRIPT_NAME\"\}," - -# Give FIRST priority to built-in binaries over any other # -export PATH="/bin:/usr/bin:/sbin:/usr/sbin:$PATH" - -##-------------------------------------## -## Added by Martinski W. [2024-Sep-15] ## -##-------------------------------------## -# For handling 3rd-party add-on cron jobs # -readonly USB_OPT_DIRPATH1="/opt" -readonly USB_OPT_DIRPATH2="/tmp/opt" -readonly USB_MNT_DIRPATH1="/mnt" -readonly USB_MNT_DIRPATH2="/tmp/mnt" - -readonly cronJobsRegEx1="[[:blank:]]+${ADDONS_PATH}/.* " -readonly cronJobsRegEx2="[[:blank:]]+${SCRIPTS_PATH}/.* " -readonly cronJobsRegEx3="[[:blank:]]+${USB_OPT_DIRPATH1}/.* " -readonly cronJobsRegEx4="[[:blank:]]+${USB_OPT_DIRPATH2}/.* " -readonly cronJobsRegEx5="[[:blank:]]+${USB_MNT_DIRPATH1}/.* " -readonly cronJobsRegEx6="[[:blank:]]+${USB_MNT_DIRPATH2}/.* " -readonly addonCronJobList="/home/root/addonCronJobList_$$.txt" - -##----------------------------------------## -## Modified by Martinski W. [2024-Jun-05] ## -##----------------------------------------## -ScriptsDirPath="$SCRIPTS_PATH" -ScriptFilePath="${SCRIPTS_PATH}/${SCRIPT_NAME}.sh" - -if [ ! -f "$ScriptFilePath" ] -then - ScriptsDirPath="$(pwd)" - ScriptFilePath="$(pwd)/$ScriptFileName" -fi - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Dec-21] ## -##------------------------------------------## -#-------------------------------------------------------# -# We'll use the built-in AMTM email configuration file -# to send email notifications *IF* enabled by the user. -#-------------------------------------------------------# -readonly FW_UpdateEMailFormatTypeDefault=HTML -readonly FW_UpdateEMailNotificationDefault=DISABLED -readonly amtmMailDirPath="/jffs/addons/amtm/mail" -readonly amtmMailConfFile="${amtmMailDirPath}/email.conf" -readonly amtmMailPswdFile="${amtmMailDirPath}/emailpw.enc" -readonly tempEMailContent="/tmp/var/tmp/tempEMailContent.$$.TXT" -readonly tempNodeEMailList="/tmp/var/tmp/tempNodeEMailList.$$.TXT" -readonly tempEMailBodyMsg="/tmp/var/tmp/tempEMailBodyMsg.$$.TXT" -readonly saveEMailInfoMsg="${SETTINGS_DIR}/savedEMailInfoMsg.SAVE.TXT" -readonly theEMailDateTimeFormat="%Y-%b-%d %a %I:%M:%S %p %Z" - -if [ -z "$(which crontab)" ] -then cronListCmd="cru l" -else cronListCmd="crontab -l" -fi - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-22] ## -##----------------------------------------## -inMenuMode=true -isInteractive=false -FlashStarted=false -MerlinChangeLogURL="" -GnutonChangeLogURL="" -keepConfigFile=false -bypassPostponedDays=false -runLoginCredentialsTest=false - -# Main LAN Network Info # -readonly myLAN_HostName="$(nvram get lan_hostname)" -readonly mainLAN_IFname="$(nvram get lan_ifname)" -readonly mainLAN_IPaddr="$(nvram get lan_ipaddr)" -readonly mainNET_IPaddr="$(ip route show | grep -E "[[:blank:]]+dev[[:blank:]]+${mainLAN_IFname}[[:blank:]]+proto[[:blank:]]+" | awk -F ' ' '{print $1}')" - -# RegExp for IPv4 address # -readonly IPv4octet_RegEx="([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" -readonly IPv4addrs_RegEx="(${IPv4octet_RegEx}\.){3}${IPv4octet_RegEx}" -readonly IPv4privt_RegEx="(^10\.|^172\.1[6-9]\.|^172\.2[0-9]\.|^172\.3[0-1]\.|^192\.168\.)" - -##----------------------------------------## -## Modified by Martinski W. [2024-Oct-03] ## -##----------------------------------------## -readonly fwInstalledBaseVers="$(nvram get firmver | sed 's/\.//g')" -readonly fwInstalledBuildVers="$(nvram get buildno)" -readonly fwInstalledExtendNum="$(nvram get extendno)" -readonly fwInstalledInnerVers="$(nvram get innerver)" -readonly fwInstalledBranchVer="${fwInstalledBaseVers}.$(echo "$fwInstalledBuildVers" | awk -F'.' '{print $1}')" - -##-------------------------------------## -## Added by Martinski W. [2024-Oct-03] ## -##-------------------------------------## -readonly MinSupportedFW_3004_386_Ver="3004.386.12.6" -readonly MinSupportedFW_3004_388_Ver="3004.388.6.2" -readonly MinSupportedFW_3006_102_Ver="3004.388.8.0" - -case "$fwInstalledBranchVer" in - "3004.386") MinSupportedFirmwareVers="$MinSupportedFW_3004_386_Ver" ;; - "3004.388") MinSupportedFirmwareVers="$MinSupportedFW_3004_388_Ver" ;; - "3006.102") MinSupportedFirmwareVers="$MinSupportedFW_3006_102_Ver" ;; -esac - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-19] ## -##----------------------------------------## -aiMeshNodes_OK=false -mountWebGUI_OK=false -inMainRouterMode=false -inAccessPointMode=false - -readonly nvramSWmode="$(nvram get sw_mode)" -if [ "$nvramSWmode" = "1" ] -then - mountWebGUI_OK=true - aiMeshNodes_OK=true - inMainRouterMode=true -else - if [ "$nvramSWmode" = "3" ] && \ - [ "$(nvram get wlc_psta)" = "0" ] - then - mountWebGUI_OK=true - aiMeshNodes_OK=false - inAccessPointMode=true - fi -fi - -readonly mainMenuReturnPromptStr="Press to return to the Main Menu..." -readonly advnMenuReturnPromptStr="Press to return to the Advanced Options Menu..." -readonly logsMenuReturnPromptStr="Press to return to the Log Options Menu..." -theMenuReturnPromptMsg="$mainMenuReturnPromptStr" -readonly SEPstr="----------------------------------------------------------" - -##-------------------------------------## -## Added by Martinski W. [2024-Nov-24] ## -##-------------------------------------## -# menu setup variables # -readonly padStr=" " -readonly theExitStr="${GRNct}e${NOct}=Exit to Main Menu" -readonly theMUExitStr="${GRNct}e${NOct}=Exit" -readonly theADExitStr="${GRNct}e${NOct}=Exit to Advanced Options Menu" -readonly theLGExitStr="${GRNct}e${NOct}=Exit to Log Options Menu" -readonly menuCancelAndExitStr="${GRNct}e${NOct}=Exit Menu" -readonly menuSavedThenExitStr="${GRNct}s${NOct}=Save&Exit" -readonly menuReturnToBeginStr="${GRNct}b${NOct}=Back to Top" - -##-------------------------------------## -## Added by Martinski W. [2024-Aug-15] ## -##-------------------------------------## -routerLoginFailureMsg="Please try the following: -1. Confirm that you are *not* already logged into the router webGUI using a web browser. -2. Check that the \"Enable Access Restrictions\" option from the webGUI is *not* set up - to restrict access to the router webGUI from the router's IP address [${GRNct}${mainLAN_IPaddr}${NOct}]. -3. Confirm your password via the \"Set Router Login Password\" option from the Main Menu." - -[ -t 0 ] && ! tty | grep -qwi "NOT" && isInteractive=true - -##----------------------------------------## -## Modified by Martinski W. [2023-Dec-23] ## -##----------------------------------------## -userLOGFile="" -userTraceFile="${SETTINGS_DIR}/${ScriptFNameTag}_Trace.LOG" -userDebugFile="${SETTINGS_DIR}/${ScriptFNameTag}_Debug.LOG" -LOGdateFormat="%Y-%m-%d %H:%M:%S" -_LogMsgNoTime_() { _UserLogMsg_ "_NOTIME_" "$@" ; } - -_UserTraceLog_() -{ - local logTime="$(date +"$LOGdateFormat")" - if [ $# -eq 0 ] || [ -z "$1" ] - then - echo >> "$userTraceFile" - elif [ $# -eq 1 ] - then - echo "$logTime" "$1" >> "$userTraceFile" - elif [ "$1" = "_NOTIME_" ] - then - echo "$2" >> "$userTraceFile" - else - echo "$logTime" "${1}: $2" >> "$userTraceFile" - fi -} - -_UserLogMsg_() -{ - if [ -z "$userLOGFile" ] || [ ! -f "$userLOGFile" ] - then return 1 ; fi - - local logTime="$(date +"$LOGdateFormat")" - if [ $# -eq 0 ] || [ -z "$1" ] - then - echo >> "$userLOGFile" - elif [ $# -eq 1 ] - then - echo "$logTime" "$1" >> "$userLOGFile" - elif [ "$1" = "_NOTIME_" ] - then - echo "$2" >> "$userLOGFile" - else - echo "$logTime" "${1}: $2" >> "$userLOGFile" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-15] ## -##----------------------------------------## -Say() -{ - local logMsg - "$isInteractive" && printf "${1}\n" - # Remove all "color escape sequences" from the system log file entries # - logMsg="$(echo "$1" | sed 's/\\\e\[[0-1]m//g ; s/\\\e\[[0-1];[3-4][0-9]m//g')" - _UserLogMsg_ "$logMsg" - printf "$logMsg" | logger -t "[${SCRIPT_NAME}] $$" -} - -##----------------------------------------------## -## Added/Modified by Martinski W. [2023-Nov-20] ## -##----------------------------------------------## -_WaitForEnterKey_() -{ - ! "$isInteractive" && return 0 - local promptStr - - if [ $# -gt 0 ] && [ -n "$1" ] - then promptStr="$1" - else promptStr="Press to continue..." - fi - - printf "\n$promptStr" - read -rs EnterKEY ; echo -} - -##-------------------------------------## -## Modified Martinski W. [2025-Feb-18] ## -##-------------------------------------## -_WaitForYESorNO_() -{ - local defltCode=0 defltAnswer=NO promptStr - - if [ $# -eq 0 ] - then defltCode=0 ; defltAnswer=NO - elif [ "$1" = "NO" ] - then defltCode=1 ; defltAnswer=NO - elif [ "$1" = "YES" ] - then defltCode=0 ; defltAnswer=YES - fi - - ! "$isInteractive" && return "$defltCode" - - if [ $# -eq 0 ] || [ -z "$1" ] || \ - echo "$1" | grep -qE "^(YES|NO)$" - then promptStr=" [yY|nN]? " - else promptStr="$1 [yY|nN]? " - fi - - printf "$promptStr" ; read -r YESorNO - [ -z "$YESorNO" ] && YESorNO="$defltAnswer" - if echo "$YESorNO" | grep -qE "^([Yy](es)?|YES)$" - then echo "OK" ; return 0 - else echo "NO" ; return 1 - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-11] ## -##----------------------------------------## -readonly LockFilePath="/tmp/var/${ScriptFNameTag}.LOCK" -readonly LockTypeRegEx="(cliMenuLock|cliOptsLock|cliFileLock)" - -_FindLockFileTypes_() -{ grep -woE "$LockTypeRegEx" "$LockFilePath" | tr '\n' ' ' | sed 's/[ ]*$//' ; } - -_ReleaseLock_() -{ - local lockType - if [ $# -eq 0 ] || [ -z "$1" ] - then lockType="" - else lockType="$1" - fi - if [ -s "$LockFilePath" ] && \ - [ "$(wc -l < "$LockFilePath")" -gt 1 ] - then - if [ -z "$lockType" ] - then sed -i "/^$$|/d" "$LockFilePath" - else sed -i "/.*|${1}$/d" "$LockFilePath" - fi - [ -s "$LockFilePath" ] && return 0 - fi - rm -f "$LockFilePath" -} - -## Defaults ## -LockMaxTimeoutSecs=120 -LockFileMaxAgeSecs=600 #10-minutes# - -if [ $# -eq 0 ] || [ -z "$1" ] -then - #Interactive Mode# - LockMaxTimeoutSecs=3 - LockFileMaxAgeSecs=1200 -else - case "$1" in - run_now|resetLockFile) - LockMaxTimeoutSecs=3 - LockFileMaxAgeSecs=1200 - ;; - startup|addCronJob) - LockMaxTimeoutSecs=600 - LockFileMaxAgeSecs=900 - ;; - esac -fi - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-15] ## -##----------------------------------------## -_AcquireLock_() -{ - local retCode waitTimeoutSecs - local lockFileSecs ageOfLockSecs oldPID - local lockTypeReq lockTypeFound - - if [ $# -gt 0 ] && [ -n "$1" ] - then lockTypeReq="$1" - else lockTypeReq="cliAnyLock" - fi - - _CreateLockFile_() - { echo "$$|$lockTypeReq" > "$LockFilePath" ; } - - if [ ! -f "$LockFilePath" ] - then _CreateLockFile_ ; return 0 - fi - - retCode=1 - lockTypeFound="" - waitTimeoutSecs=0 - - while true - do - if [ -s "$LockFilePath" ] - then - oldPID="$(head -n1 "$LockFilePath" | awk -F '|' '{print $1}')" - if [ -n "$oldPID" ] && ! pidof "$ScriptFileName" | grep -qow "$oldPID" - then sed -i "/^${oldPID}|/d" "$LockFilePath" - fi - lockFileSecs="$(date +%s -r "$LockFilePath")" - lockTypeFound="$(_FindLockFileTypes_)" - if [ "$lockTypeReq" != "cliAnyLock" ] && \ - ! echo "$lockTypeFound" | grep -qw "$lockTypeReq" - then # Specific "Lock Type" NOT found # - echo "$$|$lockTypeReq" >> "$LockFilePath" - retCode=0 ; break - fi - [ -z "$lockTypeFound" ] && lockTypeFound="noTypeLock" - else - _CreateLockFile_ - retCode=0 ; break - fi - - ageOfLockSecs="$(($(date +%s) - lockFileSecs))" - if [ "$ageOfLockSecs" -gt "$LockFileMaxAgeSecs" ] - then - Say "Stale Lock Found (older than $LockFileMaxAgeSecs secs). Resetting lock file..." - if [ -n "$oldPID" ] && \ - pidof "$ScriptFileName" | grep -qow "$oldPID" && \ - kill -EXIT "$oldPID" 2>/dev/null - then - kill -TERM "$oldPID" ; wait "$oldPID" - fi - _CreateLockFile_ - retCode=0 ; break - elif [ "$waitTimeoutSecs" -le "$LockMaxTimeoutSecs" ] - then - if [ "$((waitTimeoutSecs % 10))" -eq 0 ] - then - Say "Lock Found [$lockTypeFound: $ageOfLockSecs secs]. Waiting for script [PID=$oldPID] to exit [Timer: $waitTimeoutSecs secs]" - fi - sleep 5 - waitTimeoutSecs="$((waitTimeoutSecs + 5))" - else - Say "${REDct}**ERROR**${NOct}: The shell script ${ScriptFileName} [PID=$oldPID] is already running [$lockTypeFound: $ageOfLockSecs secs]" - retCode=1 ; break - fi - done - return "$retCode" -} - -##-------------------------------------## -## Added by Martinski W. [2023-Dec-26] ## -##-------------------------------------## -_DoExit_() -{ - local exitCode=0 - [ $# -gt 0 ] && [ -n "$1" ] && exitCode="$1" - _ReleaseLock_ ; exit "$exitCode" -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-May-21] ## -##------------------------------------------## -_ShowLogo_() -{ - echo -e "${YLWct}" - echo -e " __ __ _ _ _ _ " - echo -e " | \/ | | (_) /\ | | | |" - echo -e " | \ / | ___ _ __| |_ _ __ / \ | | | |" - echo -e " | |\/| |/ _ | '__| | | '_ \ / /\ \| | | |" - echo -e " | | | | __| | | | | | | |/ ____ | |__| |" - echo -e " |_| |_|\___|_| |_|_|_| |_/_/ \_\____/ ${GRNct}v${SCRIPT_VERSION}" - echo -e "${NOct}" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-19] ## -##----------------------------------------## -_ShowAbout_() -{ - local webUI_Page webUI_URL="[Not Available]" - if "$mountWebGUI_OK" - then - webUI_Page="$(_Check_WebGUI_Page_Exists_)" - if [ "$webUI_Page" != "NONE" ] - then webUI_URL="$(_GetRouterURL_)/$webUI_Page" - fi - fi - - clear - _ShowLogo_ - cat < /dev/null 2>&1 - sleep "$blinkRateSecs" - done - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-31] ## -##----------------------------------------## -_Reset_LEDs_() -{ - local doTrace=false - [ $# -gt 0 ] && [ "$1" -eq 1 ] && doTrace=false - if "$doTrace" - then - Say "START _Reset_LEDs_" - _UserTraceLog_ "START _Reset_LEDs_" - fi - - # Check if the process with that PID is still running # - if [ -n "$Toggle_LEDs_PID" ] && \ - kill -EXIT "$Toggle_LEDs_PID" 2>/dev/null - then - kill -TERM "$Toggle_LEDs_PID" - wait "$Toggle_LEDs_PID" - # Set LEDs to their "initial state" # - nvram set ${nvramLEDsVar}="$LEDsInitState" - /sbin/service restart_leds >/dev/null 2>&1 - sleep 2 - fi - Toggle_LEDs_PID="" - - if "$doTrace" - then - Say "EXIT _Reset_LEDs_" - _UserTraceLog_ "EXIT _Reset_LEDs_" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Apr-06] ## -##----------------------------------------## -_GetRouterURL_() -{ - local urlProto urlDomain urlPort - - if [ "$(nvram get http_enable)" = "1" ] - then urlProto="https" - else urlProto="http" - fi - - urlDomain="$(nvram get lan_domain)" - if [ -z "$urlDomain" ] - then urlDomain="$mainLAN_IPaddr" - else urlDomain="${myLAN_HostName}.$urlDomain" - fi - - urlPort="$(nvram get "${urlProto}_lanport")" - if [ "$urlPort" -eq 80 ] || [ "$urlPort" -eq 443 ] - then urlPort="" - else urlPort=":$urlPort" - fi - - echo "${urlProto}://${urlDomain}${urlPort}" -} - -##----------------------------------------------## -## Added/Modified by Martinski W. [2023-Nov-20] ## -##----------------------------------------------## -_GetRouterModelID_() -{ - local retCode=1 routerModelID="" - local nvramModelKeys="odmpid wps_modelnum model build_name" - for nvramKey in $nvramModelKeys - do - routerModelID="$(nvram get "$nvramKey")" - [ -n "$routerModelID" ] && retCode=0 && break - done - echo "$routerModelID" ; return "$retCode" -} - -##----------------------------------------------## -## Added/Modified by Martinski W. [2023-Nov-20] ## -##----------------------------------------------## -_GetRouterProductID_() -{ - local retCode=1 routerProductID="" - local nvramProductKeys="productid build_name odmpid" - for nvramKey in $nvramProductKeys - do - routerProductID="$(nvram get "$nvramKey")" - [ -n "$routerProductID" ] && retCode=0 && break - done - echo "$routerProductID" ; return "$retCode" -} - -##-------------------------------------## -## Added by Martinski W. [2023-Nov-28] ## -##-------------------------------------## -_ScriptVersionStrToNum_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then echo 0 ; return 1 ; fi - local verNum verStr - - verStr="$(echo "$1" | awk -F '_' '{print $1}')" - verNum="$(echo "$verStr" | awk -F '.' '{printf ("%d%03d%03d\n", $1,$2,$3);}')" - verNum="$(echo "$verNum" | sed 's/^0*//')" - echo "$verNum" ; return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Aug-11] ## -##----------------------------------------## -_GetFirmwareVariantFromRouter_() -{ - local hasGNUtonFW=false - - ##FOR TESTING/DEBUG ONLY## - if false # Change to true for forcing GNUton flag # - then hasGNUtonFW=true ; return 0 ; fi - ##FOR TESTING/DEBUG ONLY## - - # Check if installed F/W NVRAM vars contain "gnuton" # - if echo "$fwInstalledInnerVers" | grep -iq "gnuton" || \ - echo "$fwInstalledExtendNum" | grep -iq "gnuton" - then hasGNUtonFW=true ; fi - - echo "$hasGNUtonFW" ; return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-31] ## -##----------------------------------------## -_FWVersionStrToNum_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then echo ; return 1 ; fi - - USE_BETA_WEIGHT="$(Get_Custom_Setting FW_Allow_Beta_Production_Up)" - - local verNum verStr="$1" nonProductionVersionWeight=0 - local fwBasecodeVers="" numOfFields - - #-------------------------------------------------------------- - # Handle any 'alpha/beta' in the version string to be sure - # that we always get good numerical values for comparison. - #-------------------------------------------------------------- - if echo "$verStr" | grep -qiE '(alpha|beta)' - then - # Adjust weight value if "Beta-to-Production" update is enabled # - [ "$USE_BETA_WEIGHT" = "ENABLED" ] && nonProductionVersionWeight=-100 - - # Replace '.alpha|.beta' and anything following it with ".0" # - verStr="$(echo "$verStr" | sed 's/[.][Aa]lpha.*/.0/ ; s/[.][Bb]eta.*/.0/')" - # Remove 'alpha|beta' and anything following it # - verStr="$(echo "$verStr" | sed 's/[_-]\?[Aa]lpha.*// ; s/[_-]\?[Bb]eta.*//')" - fi - - numOfFields="$(echo "$verStr" | awk -F '.' '{print NF}')" - - if [ "$numOfFields" -lt "$2" ] - then fwBasecodeVers="$fwInstalledBaseVers" ; fi - - #----------------------------------------------------------- - # Temporarily remove Basecode version to avoid issues with - # integers greater than the maximum 32-bit signed integer - # when doing arithmetic computations with shell cmds. - #----------------------------------------------------------- - if [ "$numOfFields" -gt 3 ] - then - fwBasecodeVers="$(echo "$verStr" | cut -d'.' -f1)" - verStr="$(echo "$verStr" | cut -d'.' -f2-)" - fi - verNum="$(echo "$verStr" | awk -F '.' '{printf ("%d%02d%02d\n", $1,$2,$3);}')" - - # Subtract non-production weight from the version number # - verNum="$((verNum + nonProductionVersionWeight))" - - # Now prepend the F/W Basecode version # - [ -n "$fwBasecodeVers" ] && verNum="${fwBasecodeVers}$verNum" - - echo "$verNum" ; return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-19] ## -##----------------------------------------## -if "$inMainRouterMode" -then - readonly FW_Update_CRON_DefaultSchedule="0 0 * * *" -else - ## Set 20 minutes AFTER for APs and AiMesh Nodes ## - readonly FW_Update_CRON_DefaultSchedule="20 0 * * *" -fi - -## Recommended 15 minutes BEFORE the F/W Update ## -readonly ScriptAU_CRON_DefaultSchedule="45 23 * * *" - -## For Automatic Script Updates Cron Schedule ## -readonly SW_Update_CRON_DefaultSchedDays="* x *" - -readonly CRON_MINS_RegEx="([0-9]|[1-5][0-9])" -readonly CRON_HOUR_RegEx="([0-9]|1[0-9]|2[0-3])" - -readonly CRON_DAYofMONTH_rexp1="([1-9]|[1-2][0-9]|3[0-1])" -readonly CRON_DAYofMONTH_rexp2="${CRON_DAYofMONTH_rexp1}[-]${CRON_DAYofMONTH_rexp1}" -readonly CRON_DAYofMONTH_rexp3="${CRON_DAYofMONTH_rexp2}[/][2-9]" -readonly CRON_DAYofMONTH_rexp4="${CRON_DAYofMONTH_rexp1}([,]${CRON_DAYofMONTH_rexp1})+" -readonly CRON_DAYofMONTH_RegEx="($CRON_DAYofMONTH_rexp1|$CRON_DAYofMONTH_rexp2|$CRON_DAYofMONTH_rexp3|$CRON_DAYofMONTH_rexp4)" - -readonly CRON_DAYofWEEK_Names="([S|s]un|[M|m]on|[T|t]ue|[W|w]ed|[T|t]hu|[F|f]ri|[S|s]at)" -readonly CRON_DAYofWEEK_rexp1="[0-6][-][0-6][/][2-3]" -readonly CRON_DAYofWEEK_rexp2="${CRON_DAYofWEEK_Names}|[0-6]" -readonly CRON_DAYofWEEK_rexp3="${CRON_DAYofWEEK_Names}[-]${CRON_DAYofWEEK_Names}|[0-6][-][0-6]" -readonly CRON_DAYofWEEK_rexp4="${CRON_DAYofWEEK_Names}([,]${CRON_DAYofWEEK_Names})+|[0-6]([,][0-6])+" -readonly CRON_DAYofWEEK_RegEx="($CRON_DAYofWEEK_rexp1|$CRON_DAYofWEEK_rexp2|$CRON_DAYofWEEK_rexp3|$CRON_DAYofWEEK_rexp4)" - -readonly CRON_MONTH_NAMES="(Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)" -readonly CRON_MONTH_RegEx="$CRON_MONTH_NAMES([\/,-]$CRON_MONTH_NAMES)*|([*1-9]|1[0-2])([\/,-]([1-9]|1[0-2]))*" - -readonly CRON_UNKNOWN_DATE="**ERROR**: UNKNOWN Date Found" - -##------------------------------------------## -## Modified by Martinski W. [2024-Aug-06] ## -##------------------------------------------## -# To postpone a firmware update for a few days # -readonly FW_UpdateMinimumPostponementDays=0 -readonly FW_UpdateDefaultPostponementDays=15 -readonly FW_UpdateMaximumPostponementDays=199 -readonly FW_UpdateNotificationDateFormat="%Y-%m-%d_%H:%M:00" - -readonly MODEL_ID="$(_GetRouterModelID_)" -readonly PRODUCT_ID="$(_GetRouterProductID_)" - -##FOR TESTING/DEBUG ONLY## -##readonly PRODUCT_ID="TUF-AX3000_V2" -##readonly MODEL_ID="$PRODUCT_ID" -##FOR TESTING/DEBUG ONLY## - -readonly FW_FileName="${PRODUCT_ID}_firmware" -readonly FW_SFURL_RELEASE="${FW_SFURL_BASE}/${PRODUCT_ID}/${FW_SFURL_RELEASE_SUFFIX}/" -readonly isGNUtonFW="$(_GetFirmwareVariantFromRouter_)" - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-05] ## -##----------------------------------------## -readonly FW_RouterProductID="${GRNct}${PRODUCT_ID}${NOct}" -# Some Model IDs have a lower case suffix of the same Product ID # -if [ "$PRODUCT_ID" = "$(echo "$MODEL_ID" | tr 'a-z' 'A-Z')" ] -then - readonly FW_RouterModelID="$PRODUCT_ID" - readonly FW_RouterModelIDstr="$FW_RouterProductID" -else - readonly FW_RouterModelID="${PRODUCT_ID}/$MODEL_ID" - readonly FW_RouterModelIDstr="${FW_RouterProductID}/${GRNct}${MODEL_ID}${NOct}" -fi - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-05] ## -##----------------------------------------## -_ChangeToDev_() -{ - if ! _AcquireLock_ cliFileLock - then return 1 - fi - SCRIPT_BRANCH="dev" - SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH" - _SCRIPT_UPDATE_ force - _DoExit_ 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-05] ## -##----------------------------------------## -_ChangeToStable_() -{ - if ! _AcquireLock_ cliFileLock - then return 1 - fi - SCRIPT_BRANCH="master" - SCRIPT_URL_REPO="${SCRIPT_URL_BASE}/$SCRIPT_BRANCH" - _SCRIPT_UPDATE_ force - _DoExit_ 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Nov-15] ## -##----------------------------------------## -#-------------------------------------------------------------# -# Since a list of current mount points can have a different -# order after each reboot, or when USB drives are unmounted -# (unplugged) & then mounted (plugged in) manually by users, -# to validate a given mount point path selection we have to -# go through the current list & check for the specific path. -# We also make a special case for Entware "/opt/" paths. -#-------------------------------------------------------------# -_ValidateUSBMountPoint_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - - local mounPointPaths expectedPath mountPointList - local symblPath realPath1 realPath2 foundPathOK - local mountPointRegExp="^/dev/sd.* /tmp/mnt/.*" - - mounPointPaths="$(grep "$mountPointRegExp" /proc/mounts | awk -F ' ' '{print $2}')" - [ -z "$mounPointPaths" ] && return 1 - - expectedPath="$1" - if echo "$1" | grep -qE "^(/opt/|/tmp/opt/)" && [ -d /tmp/opt ] - then - realPath1="$(readlink -f /tmp/opt)" - realPath2="$(ls -l /tmp/opt | awk -F ' ' '{print $11}')" - symblPath="$(ls -l /tmp/opt | awk -F ' ' '{print $9}')" - [ -L "$symblPath" ] && [ -n "$realPath1" ] && \ - [ -n "$realPath2" ] && [ "$realPath1" = "$realPath2" ] && \ - expectedPath="$(/usr/bin/dirname "$realPath1")" - fi - - mountPointList="" - foundPathOK=false - - for thePATH in $mounPointPaths - do - if echo "${expectedPath}/" | grep -qE "^${thePATH}/" - then foundPathOK=true ; break ; fi - mountPointList="$mountPointList $thePATH" - done - "$foundPathOK" && return 0 - - ## Report found Mount Points on failure ## - if [ $# -gt 1 ] && [ "$2" -eq 1 ] && [ -n "$mountPointList" ] - then Say "Mount points found:\n$mountPointList" ; fi - return 1 -} - -##----------------------------------------## -## Modified by Martinski W. [2023-Nov-24] ## -##----------------------------------------## -if USBMountPoint="$(_GetDefaultUSBMountPoint_)" -then - USBConnected="${GRNct}True${NOct}" - readonly FW_Update_ZIP_DefaultSetupDIR="$USBMountPoint" - readonly FW_Update_LOG_BASE_DefaultDIR="$USBMountPoint" -else - USBConnected="${REDct}False${NOct}" - readonly FW_Update_ZIP_DefaultSetupDIR="/home/root" - readonly FW_Update_LOG_BASE_DefaultDIR="$ADDONS_PATH" -fi - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-15] ## -##-------------------------------------## -_SetUp_FW_UpdateZIP_DirectoryPaths_() -{ - local theDirPath="" - if [ $# -eq 1 ] && [ -n "$1" ] && [ -d "$1" ] - then - theDirPath="$1" - else - theDirPath="$(Get_Custom_Setting FW_New_Update_ZIP_Directory_Path)" - fi - FW_ZIP_BASE_DIR="$theDirPath" - FW_ZIP_DIR="${FW_ZIP_BASE_DIR}/$FW_ZIP_SUBDIR" - FW_ZIP_FPATH="${FW_ZIP_DIR}/${FW_FileName}.zip" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-15] ## -##-------------------------------------## -_SetUp_FW_UpdateLOG_DirectoryPaths_() -{ - local theDirPath="" - if [ $# -eq 1 ] && [ -n "$1" ] && [ -d "$1" ] - then - theDirPath="$1" - else - theDirPath="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" - fi - FW_LOG_BASE_DIR="$theDirPath" - FW_LOG_DIR="${FW_LOG_BASE_DIR}/$FW_LOG_SUBDIR" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Mar-07] ## -##-------------------------------------## -_WriteVarDefToPswdCheckJSFile_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then return 1; fi - - local varValue fixedVal - if [ $# -eq 3 ] && [ "$3" = "true" ] - then varValue="$2" - else varValue="'${2}'" - fi - - if [ ! -s "$PSWD_CHECK_JS" ] - then - echo "var $1 = ${varValue};" > "$PSWD_CHECK_JS" - elif ! grep -q "^var $1 =.*" "$PSWD_CHECK_JS" - then - echo "var $1 = ${varValue};" >> "$PSWD_CHECK_JS" - elif ! grep -q "^var $1 = ${varValue};" "$PSWD_CHECK_JS" - then - fixedVal="$(echo "$varValue" | sed 's/[\/&]/\\&/g')" - sed -i "s/^var $1 =.*/var $1 = ${fixedVal};/" "$PSWD_CHECK_JS" - fi -} - -##-------------------------------------## -## Added by Martinski W. [2025-Mar-07] ## -##-------------------------------------## -_GetLoginPswdCheckStatusJS_() -{ - if [ ! -s "$PSWD_CHECK_JS" ] ; then echo "0" ; return 0 ; fi - local checkCode - checkCode="$(grep "^var loginPswdCheckStatus =" "$PSWD_CHECK_JS" | awk -F '[ ;]' '{print $4}')" - if [ -z "$checkCode" ] - then echo "0" - else echo "$checkCode" - fi - return 0 -} - -##-------------------------------------## -## Added by Martinski W. [2025-Mar-07] ## -##-------------------------------------## -_UpdateLoginPswdCheckHelper_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - local checkCode checkMsge prevChkCode - - case "$1" in - InitPWD) - checkCode=0 - checkMsge="Password is EMPTY." - ;; - NoACCESS) - checkCode=1 - checkMsge="Login access is RESTRICTED." - ;; - OldPSWD) - prevChkCode="$(_GetLoginPswdCheckStatusJS_)" - if [ -n "$prevChkCode" ] && [ "$prevChkCode" -gt 1 ] - then - return 0 - else - checkCode=2 - checkMsge="Password is unchanged." - fi - ;; - NewPSWD) - checkCode=3 - checkMsge="Password is NOT verified." - ;; - SUCCESS) - checkCode=4 - checkMsge="Password is verified." - ;; - FAILURE) - checkCode=5 - checkMsge="Password is INVALID." - ;; - UNKNOWN) - prevChkCode="$(_GetLoginPswdCheckStatusJS_)" - if [ -n "$prevChkCode" ] && [ "$prevChkCode" -gt 1 ] - then - return 0 - else - checkCode=6 - checkMsge="UNKNOWN" - fi - ;; - *) ##IGNORE## - return 1 ;; - esac - - _WriteVarDefToPswdCheckJSFile_ "loginPswdCheckStatus" "$checkCode" true - _WriteVarDefToPswdCheckJSFile_ "loginPswdCheckMsgStr" "$checkMsge" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-07] ## -##----------------------------------------## -_InitCustomSettingsConfig_() -{ - [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - - if [ ! -f "$CONFIG_FILE" ] - then - { - echo "FW_New_Update_Notification_Date TBD" - echo "FW_New_Update_Notification_Vers TBD" - echo "FW_New_Update_Postponement_Days=$FW_UpdateDefaultPostponementDays" - echo "FW_New_Update_EMail_Notification $FW_UpdateEMailNotificationDefault" - echo "FW_New_Update_EMail_FormatType=\"${FW_UpdateEMailFormatTypeDefault}\"" - echo "FW_New_Update_Cron_Job_Schedule=\"${FW_Update_CRON_DefaultSchedule}\"" - echo "FW_New_Update_ZIP_Directory_Path=\"${FW_Update_ZIP_DefaultSetupDIR}\"" - echo "FW_New_Update_LOG_Directory_Path=\"${FW_Update_LOG_BASE_DefaultDIR}\"" - echo "FW_New_Update_LOG_Preferred_Path=\"${FW_Update_LOG_BASE_DefaultDIR}\"" - echo "FW_New_Update_EMail_CC_Name=TBD" - echo "FW_New_Update_EMail_CC_Address=TBD" - echo "credentials_base64 TBD" - echo "CheckChangeLog ENABLED" - echo "FW_Update_Check TBD" - echo "Allow_Updates_OverVPN DISABLED" - echo "FW_Allow_Beta_Production_Up ENABLED" - echo "Allow_Script_Auto_Update DISABLED" - echo "Script_Update_Cron_Job_SchedDays=\"${SW_Update_CRON_DefaultSchedDays}\"" - } > "$CONFIG_FILE" - chmod 664 "$CONFIG_FILE" - _UpdateLoginPswdCheckHelper_ InitPWD - return 1 - fi - local retCode=0 preferredPath - - # TEMPORARY Migration Function # - _Migrate_Settings_ - - if ! grep -q "^FW_New_Update_Notification_Date " "$CONFIG_FILE" - then - sed -i "1 i FW_New_Update_Notification_Date TBD" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_Notification_Vers " "$CONFIG_FILE" - then - sed -i "2 i FW_New_Update_Notification_Vers TBD" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_Postponement_Days=" "$CONFIG_FILE" - then - sed -i "3 i FW_New_Update_Postponement_Days=$FW_UpdateDefaultPostponementDays" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_EMail_Notification " "$CONFIG_FILE" - then - sed -i "4 i FW_New_Update_EMail_Notification $FW_UpdateEMailNotificationDefault" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_EMail_FormatType=" "$CONFIG_FILE" - then - sed -i "5 i FW_New_Update_EMail_FormatType=\"${FW_UpdateEMailFormatTypeDefault}\"" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_Cron_Job_Schedule=" "$CONFIG_FILE" - then - sed -i "6 i FW_New_Update_Cron_Job_Schedule=\"${FW_Update_CRON_DefaultSchedule}\"" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_ZIP_Directory_Path=" "$CONFIG_FILE" - then - sed -i "7 i FW_New_Update_ZIP_Directory_Path=\"${FW_Update_ZIP_DefaultSetupDIR}\"" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_LOG_Directory_Path=" "$CONFIG_FILE" - then - sed -i "8 i FW_New_Update_LOG_Directory_Path=\"${FW_Update_LOG_BASE_DefaultDIR}\"" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_New_Update_LOG_Preferred_Path=" "$CONFIG_FILE" - then - preferredPath="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" - sed -i "9 i FW_New_Update_LOG_Preferred_Path=\"${preferredPath}\"" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^credentials_base64 " "$CONFIG_FILE" - then - sed -i "10 i credentials_base64 TBD" "$CONFIG_FILE" - _UpdateLoginPswdCheckHelper_ InitPWD - retCode=1 - else - _UpdateLoginPswdCheckHelper_ UNKNOWN - fi - if ! grep -q "^CheckChangeLog " "$CONFIG_FILE" - then - sed -i "11 i CheckChangeLog ENABLED" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_Update_Check " "$CONFIG_FILE" - then - sed -i "12 i FW_Update_Check TBD" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^Allow_Updates_OverVPN " "$CONFIG_FILE" - then - sed -i "13 i Allow_Updates_OverVPN DISABLED" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^FW_Allow_Beta_Production_Up " "$CONFIG_FILE" - then - sed -i "14 i FW_Allow_Beta_Production_Up ENABLED" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^Allow_Script_Auto_Update " "$CONFIG_FILE" - then - sed -i "15 i Allow_Script_Auto_Update DISABLED" "$CONFIG_FILE" - retCode=1 - fi - if ! grep -q "^Script_Update_Cron_Job_SchedDays=" "$CONFIG_FILE" - then - sed -i "16 i Script_Update_Cron_Job_SchedDays=\"${SW_Update_CRON_DefaultSchedDays}\"" "$CONFIG_FILE" - retCode=1 - fi - dos2unix "$CONFIG_FILE" - chmod 664 "$CONFIG_FILE" - - return "$retCode" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-05] ## -##----------------------------------------## -Get_Custom_Setting() -{ - if [ $# -eq 0 ] || [ -z "$1" ]; then echo "**ERROR**"; return 1; fi - [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - - local setting_value="" setting_type="$1" default_value="TBD" - [ $# -gt 1 ] && default_value="$2" - - if [ -f "$CONFIG_FILE" ] - then - case "$setting_type" in - "ROGBuild" | "TUFBuild" | \ - "credentials_base64" | \ - "CheckChangeLog" | \ - "FW_Update_Check" | \ - "Allow_Updates_OverVPN" | \ - "FW_Allow_Beta_Production_Up" | \ - "FW_Auto_Backupmon" | \ - "Allow_Script_Auto_Update" | \ - "FW_New_Update_EMail_Notification" | \ - "FW_New_Update_Notification_Date" | \ - "FW_New_Update_Notification_Vers") - setting_value="$(grep "^${setting_type} " "$CONFIG_FILE" | awk -F ' ' '{print $2}')" - ;; - "FW_New_Update_Postponement_Days" | \ - "FW_New_Update_Changelog_Approval" | \ - "FW_New_Update_Expected_Run_Date" | \ - "FW_New_Update_Cron_Job_Schedule" | \ - "Script_Update_Cron_Job_SchedDays" | \ - "FW_New_Update_ZIP_Directory_Path" | \ - "FW_New_Update_LOG_Directory_Path" | \ - "FW_New_Update_LOG_Preferred_Path" | \ - "FW_New_Update_EMail_FormatType" | \ - "FW_New_Update_EMail_CC_Name" | \ - "FW_New_Update_EMail_CC_Address") - grep -q "^${setting_type}=" "$CONFIG_FILE" && \ - setting_value="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" - ;; - *) - setting_value="**ERROR**" - ;; - esac - if [ -z "$setting_value" ] - then echo "$default_value" - else echo "$setting_value" - fi - else - echo "$default_value" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-20] ## -##----------------------------------------## -Update_Custom_Settings() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] ; then return 1 ; fi - - local fixedVal oldVal="" - local setting_type="$1" setting_value="$2" - - # Check if the directory exists, and if not, create it # - [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - - case "$setting_type" in - "ROGBuild" | "TUFBuild" | \ - "credentials_base64" | \ - "CheckChangeLog" | \ - "FW_Update_Check" | \ - "Allow_Updates_OverVPN" | \ - "FW_Allow_Beta_Production_Up" | \ - "FW_Auto_Backupmon" | \ - "Allow_Script_Auto_Update" | \ - "FW_New_Update_EMail_Notification" | \ - "FW_New_Update_Notification_Date" | \ - "FW_New_Update_Notification_Vers") - if [ -f "$CONFIG_FILE" ] - then - if [ "$(grep -c "^$setting_type" "$CONFIG_FILE")" -gt 0 ] - then - if [ "$setting_value" != "$(grep "^$setting_type" "$CONFIG_FILE" | cut -f2 -d' ')" ] - then - sed -i "s/^$setting_type.*/$setting_type $setting_value/" "$CONFIG_FILE" - fi - else - echo "$setting_type $setting_value" >> "$CONFIG_FILE" - fi - else - echo "$setting_type $setting_value" > "$CONFIG_FILE" - fi - ;; - "FW_New_Update_Postponement_Days" | \ - "FW_New_Update_Changelog_Approval" | \ - "FW_New_Update_Expected_Run_Date" | \ - "FW_New_Update_Cron_Job_Schedule" | \ - "Script_Update_Cron_Job_SchedDays" | \ - "FW_New_Update_ZIP_Directory_Path" | \ - "FW_New_Update_LOG_Directory_Path" | \ - "FW_New_Update_LOG_Preferred_Path" | \ - "FW_New_Update_EMail_FormatType" | \ - "FW_New_Update_EMail_CC_Name" | \ - "FW_New_Update_EMail_CC_Address") - if [ -f "$CONFIG_FILE" ] - then - if grep -q "^${setting_type}=" "$CONFIG_FILE" - then - oldVal="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" - if [ -z "$oldVal" ] || [ "$oldVal" != "$setting_value" ] - then - fixedVal="$(echo "$setting_value" | sed 's/[\/.,*-]/\\&/g')" - sed -i "s/${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$CONFIG_FILE" - fi - else - echo "$setting_type=\"${setting_value}\"" >> "$CONFIG_FILE" - fi - else - echo "$setting_type=\"${setting_value}\"" > "$CONFIG_FILE" - fi - if [ "$setting_type" = "FW_New_Update_Postponement_Days" ] - then - FW_UpdatePostponementDays="$setting_value" - # - elif [ "$setting_type" = "FW_New_Update_Expected_Run_Date" ] - then - FW_UpdateExpectedRunDate="$setting_value" - # - elif [ "$setting_type" = "FW_New_Update_EMail_FormatType" ] - then - sendEMailFormaType="$setting_value" - [ "$sendEMailFormaType" = "HTML" ] && \ - isEMailFormatHTML=true || isEMailFormatHTML=false - # - elif [ "$setting_type" = "FW_New_Update_EMail_CC_Name" ] - then - sendEMail_CC_Name="$setting_value" - # - elif [ "$setting_type" = "FW_New_Update_EMail_CC_Address" ] - then - sendEMail_CC_Address="$setting_value" - # - elif [ "$setting_type" = "FW_New_Update_Cron_Job_Schedule" ] - then - FW_UpdateCronJobSchedule="$setting_value" - _WebUI_AutoScriptUpdateCronSchedule_ - _WebUI_AutoFWUpdateCheckCronSchedule_ - # - elif [ "$setting_type" = "Script_Update_Cron_Job_SchedDays" ] - then - ScriptUpdateCronSchedDays="$setting_value" - _WebUI_AutoScriptUpdateCronSchedule_ - # - elif [ "$setting_type" = "FW_New_Update_ZIP_Directory_Path" ] - then - _SetUp_FW_UpdateZIP_DirectoryPaths_ "$setting_value" - # - elif [ "$setting_type" = "FW_New_Update_LOG_Directory_Path" ] - then - _SetUp_FW_UpdateLOG_DirectoryPaths_ "$setting_value" - fi - ;; - *) - # Generic handling for arbitrary settings # - if grep -q "^${setting_type}=" "$CONFIG_FILE" - then - oldVal="$(grep "^${setting_type}=" "$CONFIG_FILE" | awk -F '=' '{print $2}' | sed "s/['\"]//g")" - if [ -z "$oldVal" ] || [ "$oldVal" != "$setting_value" ] - then - fixedVal="$(echo "$setting_value" | sed 's/[\/&]/\\&/g')" - sed -i "s/^${setting_type}=.*/${setting_type}=\"${fixedVal}\"/" "$CONFIG_FILE" - fi - else - echo "${setting_type}=\"${setting_value}\"" >> "$CONFIG_FILE" - fi - ;; - esac - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Jun-04] ## -##----------------------------------------## -Delete_Custom_Settings() -{ - if [ $# -lt 1 ] || [ -z "$1" ] || [ ! -f "$CONFIG_FILE" ] - then return 1 ; fi - - local setting_type="$1" - sed -i "/^${setting_type}[ =]/d" "$CONFIG_FILE" - return $? -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Dec-21] ## -##------------------------------------------## -_GetAllNodeSettings_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then echo "**ERROR**" ; return 1; fi - - ## Node Setting KEY="Node_{MACaddress}_{keySuffix}" ## - local fullKeyName="Node_${1}_${2}" - local setting_value="TBD" matched_lines - - # Ensure the settings directory exists # - [ ! -d "$SETTINGS_DIR" ] && mkdir -m 755 -p "$SETTINGS_DIR" - - if [ -f "$CONFIG_FILE" ] - then - matched_lines="$(grep -E "^${fullKeyName}=.*" "$CONFIG_FILE")" - if [ -n "$matched_lines" ] - then - # Extract the value from the first matched line # - setting_value="$(echo "$matched_lines" | head -n 1 | awk -F '=' '{print $2}' | tr -d '"')" - fi - fi - echo "$setting_value" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Feb-23] ## -##-------------------------------------## -extCheckRETvarID=0x00 -extCheckZIPdirID=0x01 -extCheckLOGdirID=0x02 -extCheckALLvarID=0x0F -extCheckZIPdirOK=true -extCheckLOGdirOK=true -extCheckRETvarOK=true -extCheckZIPdirMG="OK" -extCheckLOGdirMG="OK" -extCheckRETvarMG="OK" - -##-------------------------------------## -## Added by Martinski W. [2025-Feb-25] ## -##-------------------------------------## -_WebUI_FW_UpdateZIPDirPathDefault_() -{ - local defltDirPath="/home/root" - if [ -n "$USBMountPoint" ] && \ - _ValidateUSBMountPoint_ "$FW_ZIP_BASE_DIR" - then defltDirPath="$FW_ZIP_BASE_DIR" ; fi - _WriteVarDefToHelperJSFile_ "defaultFWUpdateZIPdirPath" "$defltDirPath" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-25] ## -##----------------------------------------## -_InitHelperJSFile_() -{ - ! "$mountWebGUI_OK" && return 0 - - [ ! -s "$HELPER_JSFILE" ] && \ - { - echo "var externalCheckID = 0x00;" - echo "var externalCheckOK = true;" - echo "var externalCheckMsg = '';" - } > "$HELPER_JSFILE" - - _WebUI_FW_UpdateZIPDirPathDefault_ - _WebUI_SetEmailConfigFileFromAMTM_ - _WebUI_AutoScriptUpdateCronSchedule_ - _WebUI_AutoFWUpdateCheckCronSchedule_ -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-25] ## -##----------------------------------------## -_UpdateHelperJSFile_() -{ - if [ $# -lt 2 ] || \ - [ -z "$1" ] || [ -z "$2" ] || \ - ! "$mountWebGUI_OK" - then return 1; fi - - local extCheckMsg="" - if [ $# -gt 2 ] && [ -n "$3" ] - then extCheckMsg="$3" ; fi - - if [ "$(($1 & extCheckZIPdirID))" -gt 0 ] - then - extCheckZIPdirOK="$2" - extCheckZIPdirMG="$extCheckMsg" - fi - if [ "$(($1 & extCheckLOGdirID))" -gt 0 ] - then - extCheckLOGdirOK="$2" - extCheckLOGdirMG="$extCheckMsg" - fi - - if [ "$1" = "$extCheckALLvarID" ] || \ - [ "$extCheckZIPdirOK" = "$extCheckLOGdirOK" ] - then - extCheckRETvarOK="$extCheckZIPdirOK" - extCheckRETvarID="$((extCheckZIPdirID | extCheckLOGdirID))" - if "$extCheckZIPdirOK" - then - extCheckRETvarMG="$extCheckZIPdirMG" - else - extCheckRETvarMG="${extCheckZIPdirMG}\n\n${extCheckLOGdirMG}" - fi - elif ! "$extCheckZIPdirOK" - then - extCheckRETvarOK="$extCheckZIPdirOK" - extCheckRETvarID="$extCheckZIPdirID" - extCheckRETvarMG="$extCheckZIPdirMG" - elif ! "$extCheckLOGdirOK" - then - extCheckRETvarOK="$extCheckLOGdirOK" - extCheckRETvarID="$extCheckLOGdirID" - extCheckRETvarMG="$extCheckLOGdirMG" - fi - - { - echo "var externalCheckID = ${extCheckRETvarID};" - echo "var externalCheckOK = ${extCheckRETvarOK};" - echo "var externalCheckMsg = '${extCheckRETvarMG}';" - } > "$HELPER_JSFILE" - - _WebUI_FW_UpdateZIPDirPathDefault_ - _WebUI_SetEmailConfigFileFromAMTM_ - _WebUI_AutoScriptUpdateCronSchedule_ - _WebUI_AutoFWUpdateCheckCronSchedule_ -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-23] ## -##----------------------------------------## -_Validate_FW_UpdateLOG_DirectoryPath_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - - local updateHelperJS=false - if [ $# -eq 2 ] && [ "$2" = "true" ] - then updateHelperJS=true ; fi - - if [ ! -d "$1" ] - then - if "$updateHelperJS" - then - checkErrorMsg="The directory path for F/W update log files is NOT found:\n[$1]" - _UpdateHelperJSFile_ "$extCheckLOGdirID" "false" "$checkErrorMsg" - fi - Say "${REDct}**ERROR**${NOct}: Directory path [${REDct}${1}${NOct}] for F/W update log files is NOT found." - _WaitForEnterKey_ - return 1 - fi - - if [ "$1" = "$FW_LOG_DIR" ] || [ "$1" = "$FW_LOG_BASE_DIR" ] - then - _UpdateHelperJSFile_ "$extCheckLOGdirID" "true" - return 0 - fi - - local newFullDirPath="" newBaseDirPath="$1" - - if echo "$newBaseDirPath" | grep -qE "/${FW_LOG_SUBDIR}$" - then newFullDirPath="$newBaseDirPath" - else newFullDirPath="${newBaseDirPath}/$FW_LOG_SUBDIR" - fi - mkdir -p -m 755 "$newFullDirPath" 2>/dev/null - if [ ! -d "$newFullDirPath" ] - then - if "$updateHelperJS" - then - checkErrorMsg="The directory path for F/W update log files cannot be created:\n[$newFullDirPath]" - _UpdateHelperJSFile_ "$extCheckLOGdirID" "false" "$checkErrorMsg" - fi - Say "${REDct}**ERROR**${NOct}: Could NOT create directory path [${REDct}${newFullDirPath}${NOct}] for F/W update log files." - _WaitForEnterKey_ - return 1 - fi - # Move any existing log files to new directory # - mv -f "${FW_LOG_DIR}"/*.log "$newFullDirPath" 2>/dev/null - # Remove now the obsolete directory path # - rm -fr "${FW_LOG_DIR:?}" - # Update the log directory paths after validation # - Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$newBaseDirPath" - Update_Custom_Settings FW_New_Update_LOG_Preferred_Path "$newBaseDirPath" - _UpdateHelperJSFile_ "$extCheckLOGdirID" "true" - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-23] ## -##----------------------------------------## -_Set_FW_UpdateLOG_DirectoryPath_() -{ - local newLOG_BaseDirPath="$FW_LOG_BASE_DIR" - - while true - do - printf "\nEnter the directory path where the subdirectory [${GRNct}${FW_LOG_SUBDIR}${NOct}] will be located.\n" - printf "[${theLGExitStr}]\n" - printf "[Current Base Path: ${GRNct}${FW_LOG_BASE_DIR}${NOct}]: " - read -r userInput - - if [ -z "$userInput" ] ; then break ; fi - if echo "$userInput" | grep -qE "^(e|exit|Exit)$" ; then return 1 ; fi - - if echo "$userInput" | grep -q '/$' - then userInput="${userInput%/*}" ; fi - - if echo "$userInput" | grep -q '//' || \ - echo "$userInput" | grep -q '/$' || \ - ! echo "$userInput" | grep -q '^/' || \ - [ "${#userInput}" -lt 4 ] || \ - [ "$(echo "$userInput" | awk -F '/' '{print NF-1}')" -lt 2 ] - then - printf "\n${REDct}INVALID input.${NOct}\n" - _WaitForEnterKey_ - clear - continue - fi - - if [ -d "$userInput" ] - then newLOG_BaseDirPath="$userInput" ; break ; fi - - rootDir="${userInput%/*}" - if [ ! -d "$rootDir" ] - then - printf "\n${REDct}**ERROR**${NOct}: Root directory path [${REDct}${rootDir}${NOct}] does NOT exist.\n\n" - printf "\n${REDct}INVALID input.${NOct}\n" - _WaitForEnterKey_ - clear - continue - fi - - printf "The directory path '${REDct}${userInput}${NOct}' does NOT exist.\n\n" - if ! _WaitForYESorNO_ "Do you want to create it now" - then - printf "Directory was ${REDct}NOT${NOct} created.\n\n" - else - mkdir -m 755 "$userInput" 2>/dev/null - if [ -d "$userInput" ] - then newLOG_BaseDirPath="$userInput" ; break - else printf "\n${REDct}**ERROR**${NOct}: Could NOT create directory [${REDct}${userInput}${NOct}].\n\n" - fi - fi - done - - if [ -d "$newLOG_BaseDirPath" ] - then - if ! _Validate_FW_UpdateLOG_DirectoryPath_ "$newLOG_BaseDirPath" - then return 1 - fi - echo "The directory path for the log files was updated successfully." - _WaitForEnterKey_ "$logsMenuReturnPromptStr" - fi - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-23] ## -##----------------------------------------## -_Validate_FW_UpdateZIP_DirectoryPath_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - - local updateHelperJS=false - if [ $# -eq 2 ] && [ "$2" = "true" ] - then updateHelperJS=true ; fi - - if [ ! -d "$1" ] - then - if "$updateHelperJS" - then - checkErrorMsg="The directory path for F/W update files is NOT found:\n[$1]" - _UpdateHelperJSFile_ "$extCheckZIPdirID" "false" "$checkErrorMsg" - fi - Say "${REDct}**ERROR**${NOct}: Directory path [${REDct}${1}${NOct}] for F/W update files is NOT found." - _WaitForEnterKey_ - return 1 - fi - - if [ "$1" = "$FW_ZIP_DIR" ] || [ "$1" = "$FW_ZIP_BASE_DIR" ] - then - _UpdateHelperJSFile_ "$extCheckZIPdirID" "true" - return 0 - fi - - local newFullDirPath="" newBaseDirPath="$1" - - if echo "$newBaseDirPath" | grep -qE "/${FW_ZIP_SUBDIR}$" - then newFullDirPath="$newBaseDirPath" - else newFullDirPath="${newBaseDirPath}/$FW_ZIP_SUBDIR" - fi - mkdir -p -m 755 "$newFullDirPath" 2>/dev/null - if [ ! -d "$newFullDirPath" ] - then - if "$updateHelperJS" - then - checkErrorMsg="The directory path for F/W update files cannot be created:\n[$newFullDirPath]" - _UpdateHelperJSFile_ "$extCheckZIPdirID" "false" "$checkErrorMsg" - fi - Say "${REDct}**ERROR**${NOct}: Could NOT create directory path [${REDct}${newFullDirPath}${NOct}] for F/W update files." - _WaitForEnterKey_ - return 1 - fi - # Remove now the obsolete directory path # - rm -fr "${FW_ZIP_DIR:?}" - rm -f "${newFullDirPath}"/*.zip "${newFullDirPath}"/*.sha256 - Update_Custom_Settings FW_New_Update_ZIP_Directory_Path "$newBaseDirPath" - _UpdateHelperJSFile_ "$extCheckZIPdirID" "true" - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-23] ## -##----------------------------------------## -_Set_FW_UpdateZIP_DirectoryPath_() -{ - local newZIP_BaseDirPath="$FW_ZIP_BASE_DIR" - - while true - do - printf "\nEnter the directory path where the update subdirectory [${GRNct}${FW_ZIP_SUBDIR}${NOct}] will be located.\n" - if [ -n "$USBMountPoint" ] && _ValidateUSBMountPoint_ "$FW_ZIP_BASE_DIR" - then - printf "Default directory for USB-attached drive: [${GRNct}${FW_ZIP_BASE_DIR}${NOct}]\n" - else - printf "Default directory for 'Local' storage is: [${GRNct}/home/root${NOct}]\n" - fi - printf "\n[${theADExitStr}]\n" - printf "[Current Base Path: ${GRNct}${FW_ZIP_BASE_DIR}${NOct}]: " - read -r userInput - - if [ -z "$userInput" ] ; then break ; fi - if echo "$userInput" | grep -qE "^(e|E|exit|Exit)$" ; then return 1 ; fi - - if echo "$userInput" | grep -q '/$' - then userInput="${userInput%/*}" ; fi - - if echo "$userInput" | grep -q '//' || \ - echo "$userInput" | grep -q '/$' || \ - ! echo "$userInput" | grep -q '^/' || \ - [ "${#userInput}" -lt 4 ] || \ - [ "$(echo "$userInput" | awk -F '/' '{print NF-1}')" -lt 2 ] - then - printf "\n${REDct}INVALID input.${NOct}\n" - _WaitForEnterKey_ - clear - continue - fi - - if [ -d "$userInput" ] - then newZIP_BaseDirPath="$userInput" ; break ; fi - - rootDir="${userInput%/*}" - if [ ! -d "$rootDir" ] - then - printf "\n${REDct}**ERROR**${NOct}: Root directory path [${REDct}${rootDir}${NOct}] does NOT exist.\n\n" - printf "\n${REDct}INVALID input.${NOct}\n" - _WaitForEnterKey_ - clear - continue - fi - - printf "The directory path '${REDct}${userInput}${NOct}' does NOT exist.\n\n" - if ! _WaitForYESorNO_ "Do you want to create it now" - then - printf "Directory was ${REDct}NOT${NOct} created.\n\n" - else - mkdir -m 755 "$userInput" 2>/dev/null - if [ -d "$userInput" ] - then newZIP_BaseDirPath="$userInput" ; break - else printf "\n${REDct}**ERROR**${NOct}: Could NOT create directory [${REDct}${userInput}${NOct}].\n\n" - fi - fi - done - - if [ -d "$newZIP_BaseDirPath" ] - then - if ! _Validate_FW_UpdateZIP_DirectoryPath_ "$newZIP_BaseDirPath" - then return 1 - fi - if "$isGNUtonFW" - then - echo "The directory path for the F/W update file was updated successfully." - else - echo "The directory path for the F/W ZIP file was updated successfully." - fi - keepWfile=0 - _WaitForEnterKey_ "$advnMenuReturnPromptStr" - fi - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-15] ## -##----------------------------------------## -## Function to migrate specific settings from old values to new standardized values. -## This function is meant to be only TEMPORARY. -## We should be safe to remove it after 3 months, or 5 version releases, -## whichever comes first. Similar to the migration function removed in v1.0.9 -##-----------------------------------------------------------------------------------## -_Migrate_Settings_() -{ - [ ! -s "$CONFIG_FILE" ] && return 1 - - ## Migrate Setting from [y|Y|n|N] to [ENABLED|DISABLED] ## - ROGBuild_Value="$(Get_Custom_Setting ROGBuild)" - if [ "$ROGBuild_Value" != "TBD" ] - then - case "$ROGBuild_Value" in - y|Y) New_ROGBuild_Value="ENABLED" ;; - n|N) New_ROGBuild_Value="DISABLED" ;; - *) - New_ROGBuild_Value="" - ! echo "$ROGBuild_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ - Say "ROGBuild has a unknown value: '$ROGBuild_Value'. Skipping migration for this setting." - ;; - esac - if [ -n "$New_ROGBuild_Value" ] - then - if Update_Custom_Settings ROGBuild "$New_ROGBuild_Value" - then - Say "ROGBuild setting was successfully migrated to '$New_ROGBuild_Value'." - else - Say "Error occurred while migrating ROGBuild setting to '$New_ROGBuild_Value'." - fi - fi - fi - - ## Migrate Setting from [y|Y|n|N] to [ENABLED|DISABLED] ## - TUFBuild_Value="$(Get_Custom_Setting TUFBuild)" - if [ "$TUFBuild_Value" != "TBD" ] - then - case "$TUFBuild_Value" in - y|Y) New_TUFBuild_Value="ENABLED" ;; - n|N) New_TUFBuild_Value="DISABLED" ;; - *) - New_TUFBuild_Value="" - ! echo "$TUFBuild_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ - Say "TUFBuild has a unknown value: '$TUFBuild_Value'. Skipping migration for this setting." - ;; - esac - if [ -n "$New_TUFBuild_Value" ] - then - if Update_Custom_Settings TUFBuild "$New_TUFBuild_Value" - then - Say "TUFBuild setting was successfully migrated to '$New_TUFBuild_Value'." - else - Say "Error occurred while migrating TUFBuild setting to '$New_TUFBuild_Value'." - fi - fi - fi - - ## Migrate Setting from [true|false] to [ENABLED|DISABLED] ## - EMailNotif_Value="$(grep '^FW_New_Update_EMail_Notification=' "$CONFIG_FILE" | cut -d'=' -f2 | tr -d '"')" - if [ -n "$EMailNotif_Value" ] && [ "$EMailNotif_Value" != "TBD" ] - then - case "$EMailNotif_Value" in - true|TRUE|True) New_EMailNotif_Value="ENABLED" ;; - false|FALSE|False) New_EMailNotif_Value="DISABLED" ;; - *) - New_EMailNotif_Value="" - ! echo "$EMailNotif_Value" | grep -qE "^(ENABLED|DISABLED)$" && \ - Say "FW_New_Update_EMail_Notification has a unknown value: '$EMailNotif_Value'. Skipping migration for this setting." - ;; - esac - if [ -n "$New_EMailNotif_Value" ] - then - sed -i '/^FW_New_Update_EMail_Notification .*/d' "$CONFIG_FILE" - sed -i "s/^FW_New_Update_EMail_Notification=.*/FW_New_Update_EMail_Notification $New_EMailNotif_Value/" "$CONFIG_FILE" - if [ $? -eq 0 ] - then - sendEMailNotificationsFlag="$New_EMailNotif_Value" - Say "EMail_Notification setting was successfully migrated to $New_EMailNotif_Value." - else - Say "Error occurred while migrating EMail_Notification setting to $New_EMailNotif_Value." - fi - fi - fi -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Jan-27] ## -##------------------------------------------## -# NOTE: -# Depending on available RAM & storage capacity of the -# target router, it may be required to have USB-attached -# storage for the ZIP file so that it can be downloaded -# in a separate directory from the firmware bin file. -#----------------------------------------------------------- -readonly FW_LOG_SUBDIR="${ScriptDirNameD}/logs" -readonly FW_BIN_SUBDIR="${ScriptDirNameD}/$FW_FileName" -readonly FW_ZIP_SUBDIR="${ScriptDirNameD}/$FW_FileName" - -FW_BIN_BASE_DIR="/home/root" -FW_BIN_DIR="${FW_BIN_BASE_DIR}/$FW_BIN_SUBDIR" - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-15] ## -##----------------------------------------## -_SetUp_FW_UpdateZIP_DirectoryPaths_ -_SetUp_FW_UpdateLOG_DirectoryPaths_ - -##----------------------------------------## -## Modified by Martinski W. [2023-Nov-24] ## -##----------------------------------------## -# The built-in F/W hook script file to be used for -# setting up persistent jobs to run after a reboot. -readonly hookScriptFName="services-start" -readonly hookScriptFPath="${SCRIPTS_PATH}/$hookScriptFName" -readonly hookScriptTagStr="#Added by $ScriptFNameTag#" - -# Postponement Days for F/W Update Check # -FW_UpdatePostponementDays="$(Get_Custom_Setting FW_New_Update_Postponement_Days)" -FW_UpdateExpectedRunDate="$(Get_Custom_Setting FW_New_Update_Expected_Run_Date)" - -##----------------------------------------## -## Modified by Martinski W. [2024-Feb-18] ## -##----------------------------------------## -# F/W Update Email Notifications # -isEMailFormatHTML=true -isEMailConfigEnabledInAMTM=false -sendEMailFormaType="$(Get_Custom_Setting FW_New_Update_EMail_FormatType)" -sendEMailNotificationsFlag="$(Get_Custom_Setting FW_New_Update_EMail_Notification)" -sendEMail_CC_Name="$(Get_Custom_Setting FW_New_Update_EMail_CC_Name)" -sendEMail_CC_Address="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" -if [ "$sendEMailFormaType" = "HTML" ] -then isEMailFormatHTML=true -else isEMailFormatHTML=false -fi - -##----------------------------------------## -## Modified by Martinski W. [2024-Nov-27] ## -##----------------------------------------## -# Define the CRON job command to execute # -# Define the hook script file to be used # -ScriptAutoUpdateSetting="$(Get_Custom_Setting Allow_Script_Auto_Update)" -ScriptUpdateCronSchedDays="$(Get_Custom_Setting Script_Update_Cron_Job_SchedDays)" - -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" - -# Define the CRON job command to execute # -FW_UpdateCronJobSchedule="$(Get_Custom_Setting FW_New_Update_Cron_Job_Schedule)" -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" - -# 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" - -# 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" - -if [ -d "$FW_LOG_DIR" ] -then - # Log rotation - delete logs older than 30 days # - /usr/bin/find -L "$FW_LOG_DIR" -name '*.log' -mtime +30 -exec rm {} \; -fi - -##----------------------------------------## -## Modified by Martinski W. [2024-Jan-27] ## -##----------------------------------------## -#------------------------------------------------------------------------------------------- -# This code is in case the user-selected USB mount point isn't available anymore. -# If the USB drive is selected as the log location but it goes offline for some reason, -# any call to the "Say" function creates a new '/tmp/mnt/XXXX' directory. -# In such a case where the USB drive is unmounted, we need to change the log directory -# back to a local directory. First if-statement executes first and updates to local 'jffs' -# directory if no USB drives are found. If ANY DefaultUSBMountPoint found, then move the -# log files from their local jffs location to the default mount location. -# We don't know the user selected yet because it's local at this time and was changed -# by the else statement. Remove the old log directory location from jffs, and update the -# settings file again to the new default again. This creates a semi-permanent switch which -# can reset back to default if the user-selected mount points aren't valid anymore. -#------------------------------------------------------------------------------------------- -UserSelectedLogPath="$(Get_Custom_Setting FW_New_Update_LOG_Directory_Path)" -if [ ! -d "$UserSelectedLogPath" ] || [ ! -r "$UserSelectedLogPath" ]; then - Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$ADDONS_PATH" -fi - -UserPreferredLogPath="$(Get_Custom_Setting FW_New_Update_LOG_Preferred_Path)" -if echo "$UserPreferredLogPath" | grep -qE "^(/tmp/mnt/|/tmp/opt/|/opt/)" && \ - _ValidateUSBMountPoint_ "$UserPreferredLogPath" && \ - [ "$UserPreferredLogPath" != "$FW_LOG_BASE_DIR" ] -then - mv -f "${FW_LOG_DIR}"/*.log "${UserPreferredLogPath}/$FW_LOG_SUBDIR" 2>/dev/null - rm -fr "${FW_LOG_DIR:?}" - Update_Custom_Settings FW_New_Update_LOG_Directory_Path "$UserPreferredLogPath" -fi - -##-------------------------------------## -## Added by Martinski W. [2025-Feb-12] ## -##-------------------------------------## -_Check_WebGUI_Page_Exists_() -{ - local webPageStr webPageFile theWebPage - - if [ ! -f "$TEMP_MENU_TREE" ] - then echo "NONE" ; return 1 ; fi - - theWebPage="NONE" - webPageStr="$(grep -E -m1 "^$webPageLineRegExp" "$TEMP_MENU_TREE")" - if [ -n "$webPageStr" ] - then - webPageFile="$(echo "$webPageStr" | grep -owE "$webPageFileRegExp" | head -n1)" - if [ -n "$webPageFile" ] && [ -s "${SHARED_WEB_DIR}/$webPageFile" ] - then theWebPage="$webPageFile" ; fi - fi - echo "$theWebPage" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-12] ## -##----------------------------------------## -_GetWebUIPage_() -{ - local webPageFile webPagePath webPageTemp - - webPageFile="$(_Check_WebGUI_Page_Exists_)" - - for index in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 - do - webPageTemp="user${index}.asp" - webPagePath="${SHARED_WEB_DIR}/$webPageTemp" - - if [ -s "$webPagePath" ] && \ - [ "$(md5sum < "$1")" = "$(md5sum < "$webPagePath")" ] - then - webPageFile="$webPageTemp" - break - elif [ "$webPageFile" = "NONE" ] && [ ! -s "$webPagePath" ] - then - webPageFile="$webPageTemp" - fi - done - echo "$webPageFile" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-11] ## -##----------------------------------------## -_Mount_WebUI_() -{ - if [ ! -f "$SCRIPT_WEB_ASP_PATH" ] - then - Say "${CRITct}**ERROR**${NOct}: The WebUI page file for $SCRIPT_NAME is NOT found." - return 1 - fi - local webPageFile - - Say "Mounting WebUI page for ${SCRIPT_NAME}..." - - eval exec "$WEBUI_LOCKFD>$WEBUI_LOCKFILE" - flock -x "$WEBUI_LOCKFD" - - webPageFile="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" - if [ -z "$webPageFile" ] || [ "$webPageFile" = "NONE" ] - then - Say "${CRITct}**ERROR**${NOct}: Unable to mount the $SCRIPT_NAME WebUI page." - flock -u "$WEBUI_LOCKFD" - return 1 - fi - - cp -fp "$SCRIPT_WEB_ASP_PATH" "${SHARED_WEB_DIR}/$webPageFile" - echo "$SCRIPT_NAME" > "${SHARED_WEB_DIR}/$(echo "$webPageFile" | cut -f1 -d'.').title" - - if [ ! -f "$TEMP_MENU_TREE" ] - then cp -fp "$ORIG_MENU_TREE" "$TEMP_MENU_TREE" - fi - sed -i "/url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" - - # Insert new page tab in the 'Administration' menu # - sed -i "/url: \"Advanced_FirmwareUpgrade_Content.asp\", tabName:/a {url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"}," "$TEMP_MENU_TREE" - - umount "$ORIG_MENU_TREE" 2>/dev/null - mount -o bind "$TEMP_MENU_TREE" "$ORIG_MENU_TREE" - flock -u "$WEBUI_LOCKFD" - - Say "${GRNct}$SCRIPT_NAME WebUI page was mounted as $webPageFile successfully." - return 0 -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2025-Apr-07] ## -##------------------------------------------## -_CheckFor_WebGUI_Page_() -{ - if "$mountWebGUI_OK" && \ - [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] - then - updatedWebUIPage=false - # Only try to download if the local .asp file does NOT exist: - if [ ! -f "$SCRIPT_WEB_ASP_FILE" ] - then - if _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" - then - chmod 664 "$SCRIPT_WEB_ASP_PATH" - theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" - if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] - then - sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" - rm -f "${SHARED_WEB_DIR}/$theWebPage" - rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" - fi - _Mount_WebUI_ - else - Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME." - fi - else - _Mount_WebUI_ - fi - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-11] ## -##----------------------------------------## -_Unmount_WebUI_() -{ - if [ ! -f "$SCRIPT_WEB_ASP_PATH" ] - then - Say "${CRITct}**ERROR**${NOct}: The WebUI page file for $SCRIPT_NAME is NOT found." - return 1 - fi - local webPageFile - - Say "Unmounting WebUI page for $SCRIPT_NAME" - - eval exec "$WEBUI_LOCKFD>$WEBUI_LOCKFILE" - flock -x "$WEBUI_LOCKFD" - - webPageFile="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" - if [ -z "$webPageFile" ] || [ "$webPageFile" = "NONE" ] - then - Say "WebUI page file for $SCRIPT_NAME is NOT found to uninstall." - flock -u "$WEBUI_LOCKFD" - return 1 - fi - - if [ -f "$TEMP_MENU_TREE" ] - then - sed -i "/url: \"$webPageFile\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" - fi - rm -f "${SHARED_WEB_DIR}/$webPageFile" - rm -f "${SHARED_WEB_DIR}/$(echo "$webPageFile" | cut -f1 -d'.').title" - - umount "$ORIG_MENU_TREE" 2>/dev/null - mount -o bind "$TEMP_MENU_TREE" "$ORIG_MENU_TREE" - flock -u "$WEBUI_LOCKFD" - - Say "${GRNct}$SCRIPT_NAME WebUI page unmounted successfully." - /sbin/service restart_httpd >/dev/null 2>&1 & - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-12] ## -##----------------------------------------## -_AutoStartupHook_() -{ - local theScriptNameTag="#${SCRIPT_NAME}#" - local theHookScriptFile="${SCRIPTS_PATH}/services-start" - local theScriptFilePath="${SCRIPTS_PATH}/${SCRIPT_NAME}.sh" - - case "$1" in - create) - if [ -f "$theHookScriptFile" ] - then - theLineCount="$(grep -c "$theScriptNameTag" "$theHookScriptFile")" - theLineCountEx="$(grep -cx '\[ -x '"$theScriptFilePath"' \] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" "$theHookScriptFile")" - - if [ "$theLineCount" -gt 1 ] || { [ "$theLineCountEx" -eq 0 ] && [ "$theLineCount" -gt 0 ] ; } - then - sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" - fi - if [ "$theLineCountEx" -eq 0 ] - then - { - echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" - } >> "$theHookScriptFile" - fi - else - { - echo "#!/bin/sh" ; echo - echo '[ -x '"$theScriptFilePath"' ] && '"$theScriptFilePath"' startup "$@" & '"$theScriptNameTag" - echo - } > "$theHookScriptFile" - fi - chmod 755 "$theHookScriptFile" - ;; - delete) - if [ -f "$theHookScriptFile" ] && \ - { grep -q "$theScriptNameTag" "$theHookScriptFile" || \ - grep -q "$theScriptFilePath" "$theHookScriptFile" ; } - then - theFixedPath="$(echo "$theScriptFilePath" | sed 's/[\/.]/\\&/g')" - sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" - sed -i "/$theFixedPath startup/d" "$theHookScriptFile" - fi - ;; - esac -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-12] ## -##----------------------------------------## -_AutoServiceEvent_() -{ - local theScriptNameTag="#${SCRIPT_NAME}#" - local theHookScriptFile="${SCRIPTS_PATH}/service-event" - local theScriptFilePath="${SCRIPTS_PATH}/${SCRIPT_NAME}.sh" - - case "$1" in - create) - if [ -f "$theHookScriptFile" ] - then - theLineCount="$(grep -c "$theScriptNameTag" "$theHookScriptFile")" - theLineCountEx="$(grep -cx 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" "$theHookScriptFile")" - - if [ "$theLineCount" -gt 1 ] || { [ "$theLineCountEx" -eq 0 ] && [ "$theLineCount" -gt 0 ]; } - then - sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" - fi - if [ "$theLineCountEx" -eq 0 ] - then - { - echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" - } >> "$theHookScriptFile" - fi - else - { - echo "#!/bin/sh" ; echo - echo 'if echo "$2" | /bin/grep -q "'"$SCRIPT_NAME"'" ; then { '"$theScriptFilePath"' service_event "$@" & }; fi '"$theScriptNameTag" - echo - } > "$theHookScriptFile" - fi - chmod 755 "$theHookScriptFile" - ;; - delete) - if [ -f "$theHookScriptFile" ] && \ - { grep -q "$theScriptNameTag" "$theHookScriptFile" || \ - grep -q "$theScriptFilePath" "$theHookScriptFile" ; } - then - theFixedPath="$(echo "$theScriptFilePath" | sed 's/[\/.]/\\&/g')" - sed -i "/${theScriptNameTag}/d" "$theHookScriptFile" - sed -i "/$theFixedPath service_event/d" "$theHookScriptFile" - fi - ;; - esac -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-05] ## -##----------------------------------------## -_SetVersionSharedSettings_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] || \ - ! echo "$1" | grep -qE "^(local|server|delete)$" - then return 1; fi - - if [ "$1" = "delete" ] - then - if [ -f "$SHARED_SETTINGS_FILE" ] - then - if grep -q "^MerlinAU_version_" "$SHARED_SETTINGS_FILE" - then - sed -i "/^MerlinAU_version_local/d" "$SHARED_SETTINGS_FILE" - sed -i "/^MerlinAU_version_server/d" "$SHARED_SETTINGS_FILE" - fi - fi - return 0 - fi - if [ $# -lt 2 ] || [ -z "$2" ] ; then return 1; fi - - local versionTypeStr="" - [ "$1" = "local" ] && versionTypeStr="MerlinAU_version_local" - [ "$1" = "server" ] && versionTypeStr="MerlinAU_version_server" - - if [ -f "$SHARED_SETTINGS_FILE" ] - then - if grep -q "^${versionTypeStr}.*" "$SHARED_SETTINGS_FILE" - then - if [ "$2" != "$(grep "^$versionTypeStr" "$SHARED_SETTINGS_FILE" | cut -f2 -d' ')" ] - then - sed -i "s/^${versionTypeStr}.*/$versionTypeStr $2/" "$SHARED_SETTINGS_FILE" - fi - else - echo "$versionTypeStr $2" >> "$SHARED_SETTINGS_FILE" - fi - else - echo "$versionTypeStr $2" > "$SHARED_SETTINGS_FILE" - fi - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-20] ## -##----------------------------------------## -_CreateDirPaths_() -{ - if [ ! -d "$SETTINGS_DIR" ] - then - mkdir -p "$SETTINGS_DIR" - chmod 755 "$SETTINGS_DIR" - fi - ! "$mountWebGUI_OK" && return 0 - - if [ ! -d "$SCRIPT_WEB_DIR" ] - then - mkdir -p "$SCRIPT_WEB_DIR" - chmod 775 "$SCRIPT_WEB_DIR" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-07] ## -##----------------------------------------## -_CreateSymLinks_() -{ - if [ -d "$SCRIPT_WEB_DIR" ] - then - rm -rf "${SCRIPT_WEB_DIR:?}/"* 2>/dev/null - fi - ! "$mountWebGUI_OK" && return 0 - - ln -sf "$CONFIG_FILE" "${SCRIPT_WEB_DIR}/config.htm" 2>/dev/null - ln -sf "$HELPER_JSFILE" "${SCRIPT_WEB_DIR}/checkHelper.js" 2>/dev/null - ln -sf "$PSWD_CHECK_JS" "${SCRIPT_WEB_DIR}/pswdCheckStatus.js" 2>/dev/null - ln -sf "$CHANGELOG_PATH" "${SCRIPT_WEB_DIR}/changelog.htm" 2>/dev/null -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-07] ## -##----------------------------------------## -_WriteVarDefToHelperJSFile_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then return 1; fi - - local varValue fixedVal - if [ $# -eq 3 ] && [ "$3" = "true" ] - then varValue="$2" - else varValue="'${2}'" - fi - - if [ ! -s "$HELPER_JSFILE" ] - then - echo "var $1 = ${varValue};" > "$HELPER_JSFILE" - elif ! grep -q "^var $1 =.*" "$HELPER_JSFILE" - then - echo "var $1 = ${varValue};" >> "$HELPER_JSFILE" - elif ! grep -q "^var $1 = ${varValue};" "$HELPER_JSFILE" - then - fixedVal="$(echo "$varValue" | sed 's/[\/&]/\\&/g')" - sed -i "s/^var $1 =.*/var $1 = ${fixedVal};/" "$HELPER_JSFILE" - fi -} - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-20] ## -##-------------------------------------## -_WebUI_AutoFWUpdateCheckCronSchedule_() -{ - ! "$mountWebGUI_OK" && return 0 - local fwUpdtCronScheduleRaw fwUpdtCronScheduleStr - fwUpdtCronScheduleRaw="$(Get_Custom_Setting FW_New_Update_Cron_Job_Schedule)" - fwUpdtCronScheduleStr="$(_TranslateCronSchedHR_ "$fwUpdtCronScheduleRaw")" - _WriteVarDefToHelperJSFile_ "fwAutoUpdateCheckCronSchedHR" "$fwUpdtCronScheduleStr" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-20] ## -##-------------------------------------## -_WebUI_AutoScriptUpdateCronSchedule_() -{ - ! "$mountWebGUI_OK" && return 0 - local scriptUpdtCronSchedRaw scriptUpdtCronSchedStr - scriptUpdtCronSchedRaw="$(_GetScriptAutoUpdateCronSchedule_)" - scriptUpdtCronSchedStr="$(_TranslateCronSchedHR_ "$scriptUpdtCronSchedRaw")" - _WriteVarDefToHelperJSFile_ "scriptAutoUpdateCronSchedHR" "$scriptUpdtCronSchedStr" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-27] ## -##-------------------------------------## -_WebUI_SetEmailConfigFileFromAMTM_() -{ - ! "$mountWebGUI_OK" && return 0 - _CheckEMailConfigFileFromAMTM_ 0 - _WriteVarDefToHelperJSFile_ "isEMailConfigEnabledInAMTM" "$isEMailConfigEnabledInAMTM" true -} - -##-------------------------------------## -## Added by Martinski W. [2025-Jan-15] ## -##-------------------------------------## -_ActionsAfterNewConfigSettings_() -{ - if [ ! -s "${CONFIG_FILE}.bak" ] || \ - diff -q "$CONFIG_FILE" "${CONFIG_FILE}.bak" >/dev/null 2>&1 - then return 1 ; fi - - _ConfigOptionChanged_() - { - if diff "$CONFIG_FILE" "${CONFIG_FILE}.bak" | grep -q "$1" - then return 0 - else return 1 - fi - } - local ccNewEmailAddr ccNewEmailName newScriptAUpdateVal - - if _ConfigOptionChanged_ "FW_New_Update_EMail_CC_Address=" - then - ccNewEmailAddr="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" - ccNewEmailName="${ccNewEmailAddr%%@*}" - Update_Custom_Settings FW_New_Update_EMail_CC_Name "$ccNewEmailName" - fi - if _ConfigOptionChanged_ "FW_New_Update_Postponement_Days=" - then - _Calculate_NextRunTime_ - fi - if _ConfigOptionChanged_ "Allow_Script_Auto_Update" - then - ScriptAutoUpdateSetting="$(Get_Custom_Setting Allow_Script_Auto_Update)" - if [ "$ScriptAutoUpdateSetting" = "DISABLED" ] - then - _DelScriptAutoUpdateHook_ - _DelScriptAutoUpdateCronJob_ - elif [ "$ScriptAutoUpdateSetting" = "ENABLED" ] - then - scriptUpdateCronSched="$(_GetScriptAutoUpdateCronSchedule_)" - if _ValidateCronJobSchedule_ "$scriptUpdateCronSched" - then - _AddScriptAutoUpdateCronJob_ && _AddScriptAutoUpdateHook_ - fi - fi - fi - if _ConfigOptionChanged_ "CheckChangeLog" - then - currentChangelogValue="$(Get_Custom_Setting CheckChangeLog)" - if [ "$currentChangelogValue" = "DISABLED" ] - then - Delete_Custom_Settings "FW_New_Update_Changelog_Approval" - elif [ "$currentChangelogValue" = "ENABLED" ] - then - Update_Custom_Settings FW_New_Update_Changelog_Approval TBD - fi - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-07] ## -##----------------------------------------## -_UpdateConfigFromWebUISettings_() -{ - [ ! -f "$SHARED_SETTINGS_FILE" ] && return 1 - - local settingsMergeOK=true logMsgTag="with errors." - local oldLoginCredsENC doRouterLoginTest=false - - # Check for 'MerlinAU_' entries excluding 'version' # - if [ "$(grep "^MerlinAU_" "$SHARED_SETTINGS_FILE" | grep -vc "_version")" -gt 0 ] - then - Say "Updated settings from WebUI found, merging into $CONFIG_FILE" - cp -a "$CONFIG_FILE" "${CONFIG_FILE}.bak" - - # Extract 'MerlinAU_' entries excluding 'version' # - grep "^MerlinAU_" "$SHARED_SETTINGS_FILE" | grep -v "_version" > "$TEMPFILE" - sed -i 's/^MerlinAU_//g;s/ /=/g' "$TEMPFILE" - - while IFS='' read -r line || [ -n "$line" ] - do - keySettingName="$(echo "$line" | cut -f1 -d'=')" - keySettingValue="$(echo "$line" | cut -f2- -d'=')" - - if [ "$keySettingName" = "FW_New_Update_ZIP_Directory_Path" ] - then - if _Validate_FW_UpdateZIP_DirectoryPath_ "$keySettingValue" true - then - Say "Directory path [$keySettingValue] was updated successfully." - else - settingsMergeOK=false - Say "**ERROR**: Could NOT update directory path [$keySettingValue]" - fi - continue - elif [ "$keySettingName" = "FW_New_Update_LOG_Directory_Path" ] - then - if _Validate_FW_UpdateLOG_DirectoryPath_ "$keySettingValue" true - then - Say "Directory path [$keySettingValue] was updated successfully." - else - settingsMergeOK=false - Say "**ERROR**: Could NOT update directory path [$keySettingValue]" - fi - continue - fi - if [ "$keySettingName" = "FW_New_Update_Cron_Job_Schedule" ] - then # Replace delimiter char placed by the WebGUI # - keySettingValue="$(echo "$keySettingValue" | sed 's/|/ /g')" - fi - if [ "$keySettingName" = "credentials_base64" ] - then - oldLoginCredsENC="$(Get_Custom_Setting credentials_base64)" - if [ "$oldLoginCredsENC" = "$keySettingValue" ] - then _UpdateLoginPswdCheckHelper_ OldPSWD - else _UpdateLoginPswdCheckHelper_ NewPSWD - fi - doRouterLoginTest="$runLoginCredentialsTest" - fi - Update_Custom_Settings "$keySettingName" "$keySettingValue" - done < "$TEMPFILE" - - # Extract 'MerlinAU_version_*' separately (if found) # - grep '^MerlinAU_version_.*' "$SHARED_SETTINGS_FILE" > "$TEMPFILE" - # Now remove all 'MerlinAU_*' entries # - sed -i "/^MerlinAU_.*/d" "$SHARED_SETTINGS_FILE" - - # Reconstruct the shared settings file # - mv -f "$SHARED_SETTINGS_FILE" "${SHARED_SETTINGS_FILE}.bak" - cat "${SHARED_SETTINGS_FILE}.bak" "$TEMPFILE" > "$SHARED_SETTINGS_FILE" - rm -f "$TEMPFILE" "${SHARED_SETTINGS_FILE}.bak" - - _ActionsAfterNewConfigSettings_ - - "$settingsMergeOK" && logMsgTag="successfully." - Say "Merge of updated settings from WebUI was completed ${logMsgTag}" - - if ! "$settingsMergeOK" - then ## Reset for Next Check ## - { sleep 15 ; _UpdateHelperJSFile_ "$extCheckALLvarID" "true" ; } & - fi - - ## Do this ONLY IF requested by user ## - "$doRouterLoginTest" && _TestLoginCredentials_ - else - Say "No updated settings from WebUI found. No merge into $CONFIG_FILE necessary." - fi - return 0 -} - -##-------------------------------------## -## Added by Martinski W. [2024-Dec-31] ## -##-------------------------------------## -newGUIversionNum="$(_ScriptVersionStrToNum_ '1.4.0')" -# Temporary code used to migrate to future new script version # -_CheckForNewGUIVersionUpdate_() -{ - local retCode theScriptVerNum urlScriptVerNum - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then - theScriptVerNum="$ScriptVersionNum" - urlScriptVerNum="$DLRepoVersionNum" - else - theScriptVerNum="$(_ScriptVersionStrToNum_ "$1")" - urlScriptVerNum="$(_ScriptVersionStrToNum_ "$2")" - fi - if [ "$theScriptVerNum" -lt "$newGUIversionNum" ] && \ - [ "$urlScriptVerNum" -ge "$newGUIversionNum" ] - then retCode=0 - else retCode=1 - fi - return "$retCode" -} - -##-------------------------------------## -## Added by Martinski W. [2025-Mar-24] ## -##-------------------------------------## -_GetDLScriptVersion_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] || [ ! -s "$1" ] - then echo ; return 1 ; fi - - local DLversBuildNum=0 - if [ "$(wc -l < "$1")" -eq 2 ] - then - DLversBuildNum="$(tail -n1 "$1")" - [ -z "$DLversBuildNum" ] && DLversBuildNum=0 - fi - echo "$(head -n1 "$1")|$DLversBuildNum" - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Feb-15] ## -##----------------------------------------## -_CurlFileDownload_() -{ - if [ $# -lt 2 ] || [ -z "$1" ] || [ -z "$2" ] - then return 1 ; fi - local retCode=1 - local tempFilePathDL="${2}.DL.TMP" - local srceFilePathDL="${SCRIPT_URL_REPO}/$1" - - curl -LSs --retry 4 --retry-delay 5 --retry-connrefused \ - "$srceFilePathDL" -o "$tempFilePathDL" - if [ $? -ne 0 ] || [ ! -s "$tempFilePathDL" ] || \ - grep -iq "^404: Not Found" "$tempFilePathDL" - then - rm -f "$tempFilePathDL" - retCode=1 - else - if [ "$1" = "$SCRIPT_WEB_ASP_FILE" ] && \ - [ -f "$2" ] && [ -f "$TEMP_MENU_TREE" ] && \ - ! diff -q "$tempFilePathDL" "$2" >/dev/null 2>&1 - then updatedWebUIPage=true - else updatedWebUIPage=false - fi - mv -f "$tempFilePathDL" "$2" - retCode=0 - fi - - return "$retCode" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-27] ## -##----------------------------------------## -_DownloadScriptFiles_() -{ - local retCode isUpdateAction updatedWebUIPage theWebPage - - if [ $# -gt 0 ] && [ "$1" = "update" ] - then isUpdateAction=true - else isUpdateAction=false - fi - updatedWebUIPage=false - - if _CurlFileDownload_ "version.txt" "$SCRIPT_VERPATH" - then - retCode=0 ; chmod 664 "$SCRIPT_VERPATH" - else - retCode=1 - Say "${REDct}**ERROR**${NOct}: Unable to download latest version file for $SCRIPT_NAME." - fi - if "$mountWebGUI_OK" && \ - _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" - then - chmod 664 "$SCRIPT_WEB_ASP_PATH" - if "$updatedWebUIPage" - then - theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" - if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] - then - sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" - rm -f "${SHARED_WEB_DIR}/$theWebPage" - rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" - fi - "$isUpdateAction" && _Mount_WebUI_ - fi - retCode=0 - elif "$mountWebGUI_OK" - then - retCode=1 - Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME." - fi - if _CurlFileDownload_ "${SCRIPT_NAME}.sh" "$ScriptFilePath" - then - retCode=0 ; chmod 755 "$ScriptFilePath" - else - retCode=1 - Say "${REDct}**ERROR**${NOct}: Unable to download latest script file for $SCRIPT_NAME." - fi - return "$retCode" -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-24] ## -##----------------------------------------## -_SCRIPT_UPDATE_() -{ - local extraParam="" - - if [ $# -gt 0 ] && [ "$1" = "force" ] - then - printf "\n${CYANct}Force downloading latest script version...${NOct}\n" - _CheckForNewScriptUpdates_ -quietcheck - if _CheckForNewGUIVersionUpdate_ "$SCRIPT_VERSION" "$DLRepoVersion" - then extraParam="install" - fi - printf "${CYANct}Downloading latest version [$DLRepoVersion] of ${SCRIPT_NAME}${NOct}\n" - - if _DownloadScriptFiles_ update - then - printf "${CYANct}$SCRIPT_NAME files were successfully updated.${NOct}\n\n" - if "$mountWebGUI_OK" - then - _SetVersionSharedSettings_ local "$DLRepoVersion" - _SetVersionSharedSettings_ server "$DLRepoVersion" - fi - sleep 1 - _ReleaseLock_ - exec "$ScriptFilePath" $extraParam - exit 0 - fi - return 0 - fi - - ! _CheckForNewScriptUpdates_ && return 1 - - clear - _ShowLogo_ - - printf "\n${YLWct}Script Update Utility${NOct}\n\n" - printf "${CYANct}Version Currently Installed: ${YLWct}${SCRIPT_VERSION}${NOct}\n" - printf "${CYANct}Update Version Available Now: ${YLWct}${DLRepoVersion}${NOct}\n\n" - - if "$mountWebGUI_OK" - then _SetVersionSharedSettings_ server "$DLRepoVersion" ; fi - - if [ "$SCRIPT_VERSION" = "$DLRepoVersion" ] - then - echo -e "${CYANct}You are on the latest version! Would you like to download anyways?${NOct}" - echo -e "${CYANct}This will overwrite your currently installed version.${NOct}" - if _WaitForYESorNO_ - then - printf "\n\n${CYANct}Downloading $SCRIPT_NAME $DLRepoVersion version.${NOct}\n" - - if _DownloadScriptFiles_ update - then - if "$mountWebGUI_OK" - then _SetVersionSharedSettings_ local "$DLRepoVersion" - fi - printf "\n${CYANct}Download successful!${NOct}\n" - printf "$(date) - Successfully downloaded $SCRIPT_NAME v${DLRepoVersion}\n" - fi - _WaitForEnterKey_ - return - else - printf "\n\n${GRNct}Exiting Script Update Utility...${NOct}\n" - sleep 1 - return - fi - elif [ "$scriptUpdateNotify" != "0" ] - then - echo -e "${CYANct}Bingo! New version available! Would you like to update now?${NOct}" - if _WaitForYESorNO_ - then - printf "\n\n${CYANct}Downloading $SCRIPT_NAME $DLRepoVersion version.${NOct}\n" - - if _DownloadScriptFiles_ update - then - if "$mountWebGUI_OK" - then _SetVersionSharedSettings_ local "$DLRepoVersion" - fi - printf "\n$(date) - Successfully downloaded $SCRIPT_NAME v${DLRepoVersion}\n" - printf "${CYANct}Update successful! Restarting script...${NOct}\n" - sleep 1 - _CheckForNewGUIVersionUpdate_ && extraParam="install" - _ReleaseLock_ - exec "$ScriptFilePath" $extraParam - exit 0 - else - _WaitForEnterKey_ - return - fi - else - printf "\n\n${GRNct}Exiting Script Update Utility...${NOct}\n" - sleep 1 - return - fi - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Mar-24] ## -##----------------------------------------## -_CheckForNewScriptUpdates_() -{ - local verStr DLScriptVerPath="${SCRIPT_VERPATH}.DL.tmp" - echo - DLRepoVersion="$SCRIPT_VERSION" - if [ -s "$SCRIPT_VERPATH" ] - then - if verStr="$(_GetDLScriptVersion_ "$SCRIPT_VERPATH")" - then - DLRepoVersion="$(echo "$verStr" | awk -F '|' '{print $1}')" - DLRepoBuildNum="$(echo "$verStr" | awk -F '|' '{print $2}')" - ScriptBuildNum="$DLRepoBuildNum" - fi - fi - - if ! _CurlFileDownload_ "version.txt" "$DLScriptVerPath" - then - Say "${REDct}**ERROR**${NOct}: Unable to download latest version file for $SCRIPT_NAME." - scriptUpdateNotify=0 - return 1 - fi - - if verStr="$(_GetDLScriptVersion_ "$DLScriptVerPath")" - then - DLRepoVersion="$(echo "$verStr" | awk -F '|' '{print $1}')" - DLRepoBuildNum="$(echo "$verStr" | awk -F '|' '{print $2}')" - fi - rm -f "$DLScriptVerPath" - - if [ -z "$DLRepoVersion" ] - then - Say "${REDct}**ERROR**${NOct}: Variable for downloaded version is empty." - scriptUpdateNotify=0 - return 1 - fi - - DLRepoVersionNum="$(_ScriptVersionStrToNum_ "$DLRepoVersion")" - ScriptVersionNum="$(_ScriptVersionStrToNum_ "$SCRIPT_VERSION")" - - if [ "$DLRepoVersionNum" -gt "$ScriptVersionNum" ] || \ - { - [ "$DLRepoBuildNum" -gt "$ScriptBuildNum" ] && \ - [ "$DLRepoVersionNum" -eq "$ScriptVersionNum" ] - } - then - scriptUpdateNotify="New script update available. -${REDct}v${SCRIPT_VERSION}${NOct} --> ${GRNct}v${DLRepoVersion}${NOct}" - - if [ $# -gt 0 ] && [ "$1" = "-quietcheck" ] - then return 0 - fi - Say "$myLAN_HostName - A new script version update (v$DLRepoVersion) is available to download." - if [ "$ScriptAutoUpdateSetting" = "ENABLED" ] - then - _SCRIPT_UPDATE_ force - fi - else - scriptUpdateNotify=0 - fi - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2023-Nov-22] ## -##----------------------------------------## -_GetLatestFWUpdateVersionFromRouter_() -{ - local retCode=0 webState newVersionStr - - webState="$(nvram get webs_state_flag)" - if [ -z "$webState" ] || [ "$webState" -eq 0 ] - then retCode=1 ; fi - - newVersionStr="$(nvram get webs_state_info | sed 's/_/./g')" - if [ $# -eq 0 ] || [ -z "$1" ] - then - newVersionStr="$(echo "$newVersionStr" | awk -F '-' '{print $1}')" - fi - - [ -z "$newVersionStr" ] && retCode=1 - echo "$newVersionStr" ; return "$retCode" -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Dec-28] ## -##------------------------------------------## -_CreateEMailContent_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - local fwInstalledVersion fwNewUpdateVersion - local savedInstalledVersion savedNewUpdateVersion - local subjectStr emailBodyTitle="" release_version - - rm -f "$tempEMailContent" "$tempEMailBodyMsg" - - if [ -s "$tempNodeEMailList" ] - then subjectStr="F/W Update Status for $node_lan_hostname" - else subjectStr="F/W Update Status for $MODEL_ID" - fi - fwInstalledVersion="$(_GetCurrentFWInstalledLongVersion_)" - if ! "$offlineUpdateTrigger" - then - fwNewUpdateVersion="$(_GetLatestFWUpdateVersionFromRouter_)" - else - fwNewUpdateVersion="$(Get_Custom_Setting "FW_New_Update_Notification_Vers")" - fi - - # Remove "_rog" or "_tuf" or -gHASHVALUES or -Gnuton* suffix to avoid version comparison failure, can't remove all for proper beta and alpha comparison # - fwInstalledVersion="$(echo "$fwInstalledVersion" | sed -E 's/(_(rog|tuf)|-g[0-9a-f]{10}|-gnuton[0-9]+)$//')" - - case "$1" in - FW_UPDATE_TEST_EMAIL) - emailBodyTitle="Testing Email Notification" - { - echo "This is a TEST of the F/W Update email notification from the ${MODEL_ID} router." - printf "\nThe F/W version that is currently installed:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - NEW_FW_UPDATE_STATUS) - emailBodyTitle="New Firmware Update for ASUS Router" - { - echo "A new F/W Update version ${fwNewUpdateVersion} is available for the ${MODEL_ID} router." - printf "\nThe F/W version that is currently installed:\n${fwInstalledVersion}\n" - printf "\nNumber of days to postpone flashing the new F/W Update version: ${FW_UpdatePostponementDays}\n" - printf "\nPlease click here to review the changelog:\n" - if "$isGNUtonFW" - then - printf "${GnutonChangeLogURL}\n" - else - printf "${MerlinChangeLogURL}\n" - fi - [ "$FW_UpdateExpectedRunDate" != "TBD" ] && \ - printf "\nThe firmware update is expected to occur on: ${FW_UpdateExpectedRunDate}\n" - } > "$tempEMailBodyMsg" - ;; - AGGREGATED_UPDATE_NOTIFICATION) - if "$aiMeshNodes_OK" && [ -n "$node_list" ]; then - nodefwNewUpdateVersion="$(_GetLatestFWUpdateVersionFromNode_ 1)" - fi - if [ -z "$nodefwNewUpdateVersion" ] - then - Say "${REDct}**ERROR**${NOct}: Unable to send node email notification [No saved info]." - return 1 - fi - emailBodyTitle="New Firmware Update(s) for AiMesh Node(s)" - NODE_UPDATE_CONTENT="$(cat "$tempNodeEMailList")" - { - echo "The following AiMesh Node(s) have a new F/W Update version available:" - echo "$NODE_UPDATE_CONTENT" - } > "$tempEMailBodyMsg" - ;; - START_FW_UPDATE_STATUS) - emailBodyTitle="New Firmware Flash Started" - { - echo "Started flashing the new F/W Update version ${fwNewUpdateVersion} on the ${MODEL_ID} router." - printf "\nThe F/W version that is currently installed:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - STOP_FW_UPDATE_APPROVAL) - emailBodyTitle="WARNING" - if "$isEMailFormatHTML" - then - # Highlight high-risk terms using HTML with a yellow background # - highlighted_changelog_contents="$(echo "$changelog_contents" | sed -E "s/($high_risk_terms)/\1<\/span>/gi")" - else - # Step 1: Enclose matched terms with unique markers that don't conflict with '>' and '<' - highlighted_changelog_contents="$(echo "$changelog_contents" | sed -E "s/($high_risk_terms)/\[\[UPPER\]\]\1\[\[ENDUPPER\]\]/gi")" - - # Step 2: Modify the awk script with correct marker lengths - highlighted_changelog_contents="$(echo "$highlighted_changelog_contents" | awk ' - BEGIN { - upper_marker = "[[UPPER]]" - endupper_marker = "[[ENDUPPER]]" - upper_marker_length = length(upper_marker) - endupper_marker_length = length(endupper_marker) - } - { - while (match($0, /\[\[UPPER\]\][^\[]*\[\[ENDUPPER\]\]/)) { - prefix = substr($0, 1, RSTART - 1) - match_text_start = RSTART + upper_marker_length - match_text_length = RLENGTH - upper_marker_length - endupper_marker_length - match_text = substr($0, match_text_start, match_text_length) - suffix = substr($0, RSTART + RLENGTH) - match_text_upper = toupper(match_text) - $0 = prefix ">" match_text_upper "<" suffix - } - print - } - ')" - fi - { - echo "Found high-risk phrases in the changelog file while Auto-Updating to version ${fwNewUpdateVersion} on the ${MODEL_ID} router." - echo "Changelog contents include the following changes:" - echo "$highlighted_changelog_contents" - printf "\nPlease run script interactively to approve this F/W Update from current version:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - NEW_BM_BACKUP_FAILED) - emailBodyTitle="WARNING" - { - echo "Backup failed during the F/W Update process to version ${fwNewUpdateVersion} on the ${MODEL_ID} router." - echo "Flashing the F/W Update on the ${MODEL_ID} router is now cancelled." - printf "\nPlease check backupmon.sh configuration and retry F/W Update from current version:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - FAILED_FW_UNZIP_STATUS) - emailBodyTitle="**ERROR**" - { - echo "Unable to decompress the F/W Update ZIP file for version ${fwNewUpdateVersion} on the ${MODEL_ID} router." - echo "Flashing the F/W Update on the ${MODEL_ID} router is now cancelled due to decompress error." - printf "\nPlease retry F/W Update from current version:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - FAILED_FW_CHECKSUM_STATUS) - emailBodyTitle="**ERROR**" - { - echo "Checksum verification failed during the F/W Update process to version ${fwNewUpdateVersion} on the ${MODEL_ID} router." - echo "Flashing the F/W Update on the ${MODEL_ID} router is now cancelled due to checksum mismatch." - printf "\nPlease retry F/W Update from current version:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - FAILED_FW_UPDATE_STATUS) - emailBodyTitle="**ERROR**" - { - echo "Flashing of new F/W Update version ${fwNewUpdateVersion} for the ${MODEL_ID} router failed." - printf "\nThe F/W version that is currently installed:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - ;; - POST_REBOOT_FW_UPDATE_SETUP) - { - echo "FW_InstalledVersion=$fwInstalledVersion" - echo "FW_NewUpdateVersion=$fwNewUpdateVersion" - } > "$saveEMailInfoMsg" - _AddPostUpdateEmailNotifyScriptHook_ - return 0 - ;; - POST_REBOOT_FW_UPDATE_STATUS) - if [ ! -f "$saveEMailInfoMsg" ] - then - Say "${REDct}**ERROR**${NOct}: Unable to send post-update email notification [No saved info file]." - return 1 - fi - savedInstalledVersion="$(grep "^FW_InstalledVersion=" "$saveEMailInfoMsg" | awk -F '=' '{print $2}')" - savedNewUpdateVersion="$(grep "^FW_NewUpdateVersion=" "$saveEMailInfoMsg" | awk -F '=' '{print $2}')" - if [ -z "$savedInstalledVersion" ] || [ -z "$savedNewUpdateVersion" ] - then - Say "${REDct}**ERROR**${NOct}: Unable to send post-update email notification [Saved info is empty]." - return 1 - fi - if [ "$savedNewUpdateVersion" = "$fwInstalledVersion" ] - then - emailBodyTitle="Successful Firmware Update" - { - echo "Flashing of new F/W Update version ${fwInstalledVersion} for the ${MODEL_ID} router was successful." - printf "\nThe F/W version that was previously installed:\n${savedInstalledVersion}\n" - } > "$tempEMailBodyMsg" - else - emailBodyTitle="**ERROR**" - { - echo "Flashing of new F/W Update version ${savedNewUpdateVersion} for the ${MODEL_ID} router failed." - printf "\nThe F/W version that is currently installed:\n${fwInstalledVersion}\n" - } > "$tempEMailBodyMsg" - fi - rm -f "$saveEMailInfoMsg" - ;; - *) return 1 - ;; - esac - - ! "$isEMailFormatHTML" && sed -i 's/[<]b[>]//g ; s/[<]\/b[>]//g' "$tempEMailBodyMsg" - - if [ -n "$CC_NAME" ] && [ -n "$CC_ADDRESS" ] - then - CC_ADDRESS_ARG="--mail-rcpt $CC_ADDRESS" - CC_ADDRESS_STR="\"${CC_NAME}\" <$CC_ADDRESS>" - fi - - ## Header-1 ## - cat < "$tempEMailContent" -From: "$FROM_NAME" <$FROM_ADDRESS> -To: "$TO_NAME" <$TO_ADDRESS> -EOF - - [ -n "$CC_ADDRESS_STR" ] && \ - printf "Cc: %s\n" "$CC_ADDRESS_STR" >> "$tempEMailContent" - - ## Header-2 ## - cat <> "$tempEMailContent" -Subject: $subjectStr -Date: $(date -R) -EOF - - if "$isEMailFormatHTML" - then - cat <> "$tempEMailContent" -MIME-Version: 1.0 -Content-Type: text/html; charset="UTF-8" -Content-Disposition: inline - - - -

${emailBodyTitle}

-
-EOF
-    else
-        cat <> "$tempEMailContent"
-Content-Type: text/plain; charset="UTF-8"
-Content-Transfer-Encoding: quoted-printable
-Content-Disposition: inline
-
-EOF
-       [ -n "$emailBodyTitle" ] && \
-       printf "%s\n\n" "$emailBodyTitle" >> "$tempEMailContent"
-   fi
-
-   ## Body ##
-   cat "$tempEMailBodyMsg" >> "$tempEMailContent"
-
-   ## Footer ##
-   if "$isEMailFormatHTML"
-   then
-       cat <> "$tempEMailContent"
-
-Sent by the "${ScriptFNameTag}" utility.
-From the "${FRIENDLY_ROUTER_NAME}" router.
-
-$(date +"$theEMailDateTimeFormat")
-
-EOF - else - cat <> "$tempEMailContent" - -Sent by the "${ScriptFNameTag}" utility. -From the "${FRIENDLY_ROUTER_NAME}" router. - -$(date +"$theEMailDateTimeFormat") -EOF - fi - - rm -f "$tempEMailBodyMsg" - rm -f "$tempNodeEMailList" - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2025-Jan-10] ## -##----------------------------------------## -_CheckEMailConfigFileFromAMTM_() -{ - local doLogMsgs - - if [ $# -gt 0 ] && [ "$1" -eq 1 ] - then doLogMsgs=true - else doLogMsgs=false - fi - - isEMailConfigEnabledInAMTM=false - - if [ ! -f "$amtmMailConfFile" ] || [ ! -f "$amtmMailPswdFile" ] - then - "$doLogMsgs" && \ - Say "${REDct}**ERROR**${NOct}: Unable to send email notification [No config file]." - return 1 - fi - - FROM_NAME="" TO_NAME="" FROM_ADDRESS="" TO_ADDRESS="" - USERNAME="" SMTP="" PORT="" PROTOCOL="" - PASSWORD="" emailPwEnc="" - - # Custom Options ## - CC_NAME="" CC_ADDRESS="" - - . "$amtmMailConfFile" - - if [ -z "$TO_NAME" ] || [ -z "$USERNAME" ] || \ - [ -z "$FROM_ADDRESS" ] || [ -z "$TO_ADDRESS" ] || \ - [ -z "$SMTP" ] || [ -z "$PORT" ] || [ -z "$PROTOCOL" ] || \ - [ -z "$emailPwEnc" ] || [ "$PASSWORD" = "PUT YOUR PASSWORD HERE" ] - then - "$doLogMsgs" && \ - Say "${REDct}**ERROR**${NOct}: Unable to send email notification [Empty variables]." - return 1 - fi - - sendEMail_CC_Name="$(Get_Custom_Setting FW_New_Update_EMail_CC_Name)" - sendEMail_CC_Address="$(Get_Custom_Setting FW_New_Update_EMail_CC_Address)" - sendEMailNotificationsFlag="$(Get_Custom_Setting FW_New_Update_EMail_Notification)" - sendEMailFormaType="$(Get_Custom_Setting FW_New_Update_EMail_FormatType)" - if [ "$sendEMailFormaType" = "HTML" ] - then isEMailFormatHTML=true - else isEMailFormatHTML=false - fi - - if [ -n "$sendEMail_CC_Name" ] && [ "$sendEMail_CC_Name" != "TBD" ] && \ - [ -n "$sendEMail_CC_Address" ] && [ "$sendEMail_CC_Address" != "TBD" ] - then - [ -z "$CC_NAME" ] && CC_NAME="$sendEMail_CC_Name" - [ -z "$CC_ADDRESS" ] && CC_ADDRESS="$sendEMail_CC_Address" - fi - - isEMailConfigEnabledInAMTM=true - return 0 -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Dec-21] ## -##------------------------------------------## -_SendEMailNotification_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] || \ - [ "$sendEMailNotificationsFlag" != "ENABLED" ] || \ - ! _CheckEMailConfigFileFromAMTM_ 1 - then return 1 ; fi - - local CC_ADDRESS_STR="" CC_ADDRESS_ARG="" - - [ -z "$FROM_NAME" ] && FROM_NAME="$ScriptFNameTag" - [ -z "$FRIENDLY_ROUTER_NAME" ] && FRIENDLY_ROUTER_NAME="$MODEL_ID" - - ! _CreateEMailContent_ "$1" && return 1 - - [ "$1" = "POST_REBOOT_FW_UPDATE_SETUP" ] && return 0 - - if "$isInteractive" - then - printf "\nSending email notification [$1]." - printf "\nPlease wait...\n" - fi - - _UserTraceLog_ "SENDING email notification..." - - curl -Lv --retry 4 --retry-delay 5 --url "${PROTOCOL}://${SMTP}:${PORT}" \ - --mail-from "$FROM_ADDRESS" --mail-rcpt "$TO_ADDRESS" $CC_ADDRESS_ARG \ - --user "${USERNAME}:$(/usr/sbin/openssl aes-256-cbc "$emailPwEnc" -d -in "$amtmMailPswdFile" -pass pass:ditbabot,isoi)" \ - --upload-file "$tempEMailContent" \ - $SSL_FLAG --ssl-reqd --crlf >> "$userTraceFile" 2>&1 - curlCode="$?" - - if [ "$curlCode" -eq 0 ] - then - sleep 2 - rm -f "$userTraceFile" - Say "The email notification was sent successfully [$1]." - else - Say "${REDct}**ERROR**${NOct}: Failure to send email notification [Code: $curlCode][$1]." - fi - rm -f "$tempEMailContent" - - return "$curlCode" -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Jul-31] ## -##----------------------------------------## -# Directory for downloading & extracting firmware # -_CreateDirectory_() -{ - if [ $# -eq 0 ] || [ -z "$1" ] ; then return 1 ; fi - - mkdir -p "$1" - if [ ! -d "$1" ] - then - Say "${REDct}**ERROR**${NOct}: Unable to create directory [$1] to download firmware." - "$inMenuMode" && _WaitForEnterKey_ "$theMenuReturnPromptMsg" - return 1 - fi - if ! "$offlineUpdateTrigger" - then - # Clear directory in case any previous files still exist # - rm -f "${1}"/* - fi - return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-17] ## -##----------------------------------------## -_DelPostUpdateEmailNotifyScriptHook_() -{ - local hookScriptFile - - hookScriptFile="$hookScriptFPath" - if [ ! -f "$hookScriptFile" ] ; then return 1 ; fi - - if grep -qE "$POST_UPDATE_EMAIL_SCRIPT_JOB" "$hookScriptFile" - then - sed -i -e '/\/'"$ScriptFileName"' postUpdateEmail & '"$hookScriptTagStr"'/d' "$hookScriptFile" - if [ $? -eq 0 ] - then - Say "Post-update email notification hook was deleted successfully from '$hookScriptFile' script." - fi - else - Say "${GRNct}Post-update email notification hook is not found in '$hookScriptFile' script.${NOct}" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-17] ## -##----------------------------------------## -_AddPostUpdateEmailNotifyScriptHook_() -{ - local hookScriptFile jobHookAdded=false - - hookScriptFile="$hookScriptFPath" - if [ ! -f "$hookScriptFile" ] - then - jobHookAdded=true - { - echo "#!/bin/sh" - echo "# $hookScriptFName" - echo "#" - echo "$POST_UPDATE_EMAIL_SCRIPT_HOOK" - } > "$hookScriptFile" - # - elif ! grep -qE "$POST_UPDATE_EMAIL_SCRIPT_JOB" "$hookScriptFile" - then - jobHookAdded=true - echo "$POST_UPDATE_EMAIL_SCRIPT_HOOK" >> "$hookScriptFile" - fi - chmod 0755 "$hookScriptFile" - - if "$jobHookAdded" - then Say "Post-update email notification hook was added successfully to '$hookScriptFile' script." - else Say "Post-update email notification hook already exists in '$hookScriptFile' script." - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-17] ## -##----------------------------------------## -_DelPostRebootRunScriptHook_() -{ - local hookScriptFile - - hookScriptFile="$hookScriptFPath" - if [ ! -f "$hookScriptFile" ] ; then return 1 ; fi - - if grep -qE "$POST_REBOOT_SCRIPT_JOB" "$hookScriptFile" - then - sed -i -e '/\/'"$ScriptFileName"' postRebootRun & '"$hookScriptTagStr"'/d' "$hookScriptFile" - if [ $? -eq 0 ] - then - Say "Post-reboot run hook was deleted successfully from '$hookScriptFile' script." - fi - else - Say "${GRNct}Post-reboot run hook is not found in '$hookScriptFile' script.${NOct}" - fi -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-17] ## -##----------------------------------------## -_AddPostRebootRunScriptHook_() -{ - local hookScriptFile jobHookAdded=false - - hookScriptFile="$hookScriptFPath" - if [ ! -f "$hookScriptFile" ] - then - jobHookAdded=true - { - echo "#!/bin/sh" - echo "# $hookScriptFName" - echo "#" - echo "$POST_REBOOT_SCRIPT_HOOK" - } > "$hookScriptFile" - # - elif ! grep -qE "$POST_REBOOT_SCRIPT_JOB" "$hookScriptFile" - then - jobHookAdded=true - echo "$POST_REBOOT_SCRIPT_HOOK" >> "$hookScriptFile" - fi - chmod 0755 "$hookScriptFile" - - if "$jobHookAdded" - then Say "Post-reboot run hook was added successfully to '$hookScriptFile' script." - else Say "Post-reboot run hook already exists in '$hookScriptFile' script." - fi - _WaitForEnterKey_ -} - -##----------------------------------------## -## Modified by Martinski W. [2024-May-31] ## -##----------------------------------------## -_GetCurrentFWInstalledLongVersion_() -{ - -##FOR TESTING/DEBUG ONLY## -if false ; then echo "3004.388.6.2" ; return 0 ; fi -##FOR TESTING/DEBUG ONLY## - - local theVersionStr extVersNum - - extVersNum="$fwInstalledExtendNum" - echo "$extVersNum" | grep -qiE "^(alpha|beta)" && extVersNum="0_$extVersNum" - [ -z "$extVersNum" ] && extVersNum=0 - - theVersionStr="${fwInstalledBuildVers}.$extVersNum" - [ -n "$fwInstalledBaseVers" ] && \ - theVersionStr="${fwInstalledBaseVers}.${theVersionStr}" - - echo "$theVersionStr" -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Mar-31] ## -##----------------------------------------## -_HasRouterMoreThan256MBtotalRAM_() -{ - local totalRAM_KB - totalRAM_KB="$(awk -F ' ' '/^MemTotal:/{print $2}' /proc/meminfo)" - [ -n "$totalRAM_KB" ] && [ "$totalRAM_KB" -gt 262144 ] && return 0 - return 1 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Apr-01] ## -##----------------------------------------## -#---------------------------------------------------------------------# -# The actual amount of RAM that is available for any new process -# (*without* using the swap file) can be roughly estimated from -# "Free Memory" & "Page Cache" (e.g. Inactive memory pages). -# This estimate must take into account that the overall system -# (kernel + native services + tmpfs) needs a minimum amount of RAM -# to continue to work, and that not all reclaimable Page Cache can -# be reclaimed because some may actually be in used at the time. -# NOTE: [Martinski] -# Since reported "Available RAM" estimates tend to be extremely -# conservative in many cases, we decided to take another approach -# and calculate it based on the reported "Free RAM" plus ~66% of -# reported "Memory Cached" and then take the largest of the two -# values: Reported "Available RAM" vs Calculated "Available RAM" -# While still somewhat conservative, this would provide a better -# estimate, especially at the time when the router is about to -# shut down and terminate all non-critical services/processes -# before the actual F/W flash is performed. -#---------------------------------------------------------------------# -_GetAvailableRAM_KB_() -{ - local theMemAvailable_KB theMemAvail_KB theMemCache_KB - local theMemFree1_KB theMemFree2_KB inactivePgs_KB - - _MaxNumber_() { echo "$(($1 < $2 ? $2 : $1))" ; } - - theMemCache_KB="$(awk -F ' ' '/^Cached:/{print $2}' /proc/meminfo)" - theMemFree1_KB="$(awk -F ' ' '/^MemFree:/{print $2}' /proc/meminfo)" - theMemAvail_KB="$(awk -F ' ' '/^MemAvailable:/{print $2}' /proc/meminfo)" - # Assumes that only ~66% of Page Cache can be reclaimed # - theMemFree2_KB="$((theMemFree1_KB + ((theMemCache_KB * 2) / 3)))" - - if [ -z "$theMemAvail_KB" ] - then - inactivePgs_KB="$(awk -F ' ' '/^Inactive:/{print $2}' /proc/meminfo)" - theMemAvail_KB="$((theMemFree1_KB + inactivePgs_KB))" - fi - theMemAvailable_KB="$(_MaxNumber_ "$theMemAvail_KB" "$theMemFree2_KB")" - echo "$theMemAvailable_KB" ; return 0 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Mar-31] ## -##----------------------------------------## -_GetFreeRAM_KB_() -{ - awk -F ' ' '/^MemFree:/{print $2}' /proc/meminfo - ##FOR DEBUG ONLY## echo 1000 -} - -##----------------------------------------## -## Modified by Martinski W. [2024-Jun-05] ## -##----------------------------------------## -_GetRequiredRAM_KB_() -{ - local theURL="$1" - local zip_file_size_bytes zip_file_size_kb overhead_kb - local total_required_kb overhead_percentage=50 - - # Size of the ZIP file in bytes # - zip_file_size_bytes="$(curl -LsI --retry 4 --retry-delay 5 "$theURL" | grep -i Content-Length | tail -1 | awk '{print $2}')" - # Bytes to KBytes # - zip_file_size_kb="$((zip_file_size_bytes / 1024))" - - # Calculate overhead based on the percentage # - overhead_kb="$((zip_file_size_kb * overhead_percentage / 100))" - - total_required_kb="$((zip_file_size_kb + overhead_kb))" - echo "$total_required_kb" -} - -##----------------------------------------## -## Modified by Martinski W. [2023-Mar-24] ## -##----------------------------------------## -_ShutDownNonCriticalServices_() -{ - for procName in nt_center nt_monitor nt_actMail - do - procNum="$(ps w | grep -w "$procName" | grep -cv "grep -w")" - if [ "$procNum" -gt 0 ] - then - printf "$procName: [$procNum]\n" - killall -9 "$procName" && sleep 1 - fi - done - - for service_name in conn_diag samba nasapps - do - procNum="$(ps w | grep -w "$service_name" | grep -cv "grep -w")" - if [ "$procNum" -gt 0 ] - then - printf "$service_name: [$procNum]\n" - service "stop_$service_name" && sleep 1 - fi - done -} - -##------------------------------------------## -## Modified by ExtremeFiretop [2024-Jan-26] ## -##------------------------------------------## -_DoCleanUp_() -{ - local delBINfiles=false keepZIPfile=false keepWfile=false - - local doTrace=false - [ $# -gt 0 ] && [ "$1" -eq 0 ] && doTrace=false - if "$doTrace" - then - Say "START _DoCleanUp_" - _UserTraceLog_ "START _DoCleanUp_" - fi - - [ $# -gt 0 ] && [ "$1" -eq 1 ] && delBINfiles=true - [ $# -gt 1 ] && [ "$2" -eq 1 ] && keepZIPfile=true - [ $# -gt 2 ] && [ "$3" -eq 1 ] && keepWfile=true - - # Stop the LEDs blinking # - _Reset_LEDs_ 1 - - # Check existence of files and preserve based on flags # - local moveZIPback=false moveWback=false - - # Move file temporarily to save it from deletion # - "$keepZIPfile" && [ -f "$FW_ZIP_FPATH" ] && \ - mv -f "$FW_ZIP_FPATH" "${FW_ZIP_BASE_DIR}/$ScriptDirNameD" && moveZIPback=true - - if "$keepWfile" && [ -f "$FW_DL_FPATH" ]; then - mv -f "$FW_DL_FPATH" "${FW_ZIP_BASE_DIR}/$ScriptDirNameD" && moveWback=true - fi - - rm -f "${FW_ZIP_DIR:?}"/* - "$delBINfiles" && rm -f "${FW_BIN_DIR:?}"/* - - # Move files back to their original location if needed # - "$moveZIPback" && \ - mv -f "${FW_ZIP_BASE_DIR}/${ScriptDirNameD}/${FW_FileName}.zip" "$FW_ZIP_FPATH" - - "$moveWback" && \ - mv -f "${FW_ZIP_BASE_DIR}/${ScriptDirNameD}/${FW_FileName}.${extension}" "$FW_DL_FPATH" - - if "$doTrace" - then - Say "EXIT _DoCleanUp_" - _UserTraceLog_ "EXIT _DoCleanUp_" - fi + + + + + + + + + + + + +MerlinAU add-on for ASUSWRT-Merlin Firmware + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + +" /> +" /> + +" /> + +" /> +" /> +" /> +" /> +" /> +" /> + + + + + + + + +
  + + + + + + + +
+ + + +
+
 
+
MerlinAU
+
+
This is the MerlinAU add-on integrated into the router WebUI +[ + Wiki ] + +
+
 
+ + + + + + + + +
+ + + + + + + + + + + +
Firmware Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Product/Model ID:
F/W Variant Detected:Unknown
F/W Version Installed: + <% nvram_get("firmver"); %>.<% nvram_get("buildno"); %>.<% nvram_get("extendno"); %> +
F/W Update Available:NONE FOUND
Estimated Update Time:TBD
Last Notification Date:TBD
Changelog Approval:Disabled
+ + + + + + + + + + + +
Settings Status (click to expand/collapse)
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
F/W Update Check:Disabled
Changelog Check:Disabled
Beta-to-Release Updates:Disabled
Tailscale VPN Access:Disabled
Automatic Backups:Disabled
Auto-Updates for MerlinAU:Disabled
Email Notifications:Disabled
+ +
 
+ + + + + + +
Actions (click to expand/collapse)
+
+ ++ + + + + + + +
+ +
+ +
+
+ +
+ +
+
+ +
+ +
+
+ +
 
+ + + + + + + + + + +
Configuration (click to expand/collapse)
+ + ++ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ +
+
+
+ +
+
+
+
+ +
+
+ + +
+ + + +
+ + + +
+ + +
+ Days: + + + + +
+ + + + + + + +
+
+
+ Hour: + +
+
+ Minutes: + +
+
+ + + +
+ + + +
+ +
+ +
+ +
+ + + + +
+ + + + +
+ + + + +
+ +
+ +
+
+ +
+
+
MerlinAU
+
+ + + From c94c253f9caf764ecdfeec50de412904d58e951c Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 09:14:09 -0400 Subject: [PATCH 4/7] Update MerlinAU.sh --- MerlinAU.sh | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 253df58f..0127599b 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -2159,27 +2159,24 @@ _CheckFor_WebGUI_Page_() if "$mountWebGUI_OK" && \ [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] then - updatedWebUIPage=false - # Only try to download if the local .asp file does NOT exist: - if [ ! -f "$SCRIPT_WEB_ASP_FILE" ] - then - if _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" - then - chmod 664 "$SCRIPT_WEB_ASP_PATH" - if "$updatedWebUIPage" - then - theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" - if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] - then - sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" - rm -f "${SHARED_WEB_DIR}/$theWebPage" - rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" - fi - _Mount_WebUI_ + updatedWebUIPage=false + # Only try to download if the local .asp file does NOT exist: + if [ ! -f "$SCRIPT_WEB_ASP_FILE" ] + then + if _CurlFileDownload_ "$SCRIPT_WEB_ASP_FILE" "$SCRIPT_WEB_ASP_PATH" + then + chmod 664 "$SCRIPT_WEB_ASP_PATH" + theWebPage="$(_GetWebUIPage_ "$SCRIPT_WEB_ASP_PATH")" + if [ -n "$theWebPage" ] && [ "$theWebPage" != "NONE" ] + then + sed -i "/url: \"$theWebPage\", tabName: \"$SCRIPT_NAME\"/d" "$TEMP_MENU_TREE" + rm -f "${SHARED_WEB_DIR}/$theWebPage" + rm -f "${SHARED_WEB_DIR}/$(echo "$theWebPage" | cut -f1 -d'.').title" fi + _Mount_WebUI_ else Say "${REDct}**ERROR**${NOct}: Unable to download latest WebUI ASP file for $SCRIPT_NAME." - fi + fi else _Mount_WebUI_ fi From d4c12c953fa7def959fa913883f2bc8e044024eb Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 09:16:24 -0400 Subject: [PATCH 5/7] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f300d7d0..e23e13b1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # MerlinAU - AsusWRT-Merlin Firmware Auto Updater -## v1.4.0 -## 2025-Apr-06 +## v1.4.1 +## 2025-Apr-07 ## WebUI: ![image](https://github.com/user-attachments/assets/92701007-a902-4724-9bae-b255856a686a) From a0b7907696c083f0b8158cd52f94841240a6ed1b Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 09:16:58 -0400 Subject: [PATCH 6/7] Update version.txt --- version.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.txt b/version.txt index 9c0eb14b..93ff4355 100644 --- a/version.txt +++ b/version.txt @@ -1,2 +1,2 @@ -1.4.0 -25040600 +1.4.1 +25040709 From 0e3e28dbebfc521c802d8ff8ebf8ed3e27a77d9a Mon Sep 17 00:00:00 2001 From: Joel Samson Date: Mon, 7 Apr 2025 09:19:16 -0400 Subject: [PATCH 7/7] Update MerlinAU.sh --- MerlinAU.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MerlinAU.sh b/MerlinAU.sh index 0127599b..eea31ffb 100644 --- a/MerlinAU.sh +++ b/MerlinAU.sh @@ -2158,8 +2158,7 @@ _CheckFor_WebGUI_Page_() { if "$mountWebGUI_OK" && \ [ "$(_Check_WebGUI_Page_Exists_)" = "NONE" ] - then - updatedWebUIPage=false + then # Only try to download if the local .asp file does NOT exist: if [ ! -f "$SCRIPT_WEB_ASP_FILE" ] then