From 3d3b270748b43362d0ec51a1e52f300e6770b469 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 May 2025 14:07:57 +0200 Subject: [PATCH 01/24] README: give a hint on builtin certificate store I guess this should become the default any time in future... --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 2a8b2cef..bc098408 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,14 @@ including demonstation recorded live at [MUM Europe ### The long way in detail The update script does server certificate verification, so first step is to -download the certificates. If you intend to download the scripts from a +download the certificates. + +> 💡️ **Hint**: RouterOS 7.19 comes with a builtin certificate store. You +> can skip the steps regarding certificate download and import if you set +> the trust for these builtin trust anchors: +> `/certificate/settings/set builtin-trust-anchors=trusted;` + +If you intend to download the scripts from a different location (for example from github.com) install the corresponding certificate chain. From d59c4aee26788f3c5088c32a3bd54f0562b4d2b4 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 May 2025 14:16:57 +0200 Subject: [PATCH 02/24] README: add a paragraph and link to jump --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bc098408..243e1fc5 100644 --- a/README.md +++ b/README.md @@ -75,8 +75,9 @@ The update script does server certificate verification, so first step is to download the certificates. > 💡️ **Hint**: RouterOS 7.19 comes with a builtin certificate store. You -> can skip the steps regarding certificate download and import if you set -> the trust for these builtin trust anchors: +> can skip the steps regarding certificate download and import and jump +> to [installation of scripts](#installation-of-scripts) if you set the +> trust for these builtin trust anchors: > `/certificate/settings/set builtin-trust-anchors=trusted;` If you intend to download the scripts from a @@ -113,6 +114,8 @@ is shown. Always make sure there are no certificates installed you do not know or want! +#### Installation of scripts + All following commands will verify the server certificate. For validity the certificate's lifetime is checked with local time, so make sure the device's date and time is set correctly! From bf684a7197f9ad07e23415de5779a366af7dd71b Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 May 2025 15:08:26 +0200 Subject: [PATCH 03/24] global-functions: $CertificateAvailable: try to use builtin certificates The builtin certificates were introduced with RouterOS 7.19, so requires this hacky :parse workaround. --- global-functions.rsc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 55dbdee9..759b2744 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -119,6 +119,11 @@ :return false; } + :if (([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \ + [[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CommonName . "\" ] ]") ]] > 0) do={ + :return true; + } + :if ([ :len [ /certificate/find where common-name=$CommonName ] ] = 0) do={ $LogPrint info $0 ("Certificate with CommonName '" . $CommonName . "' not available."); :if ([ $CertificateDownload $CommonName ] = false) do={ From d69b39957278a9393762ec1653895eeb69483e9e Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Wed, 28 May 2025 16:38:50 +0200 Subject: [PATCH 04/24] INITIAL-COMMANDS: use builtin certificates if possible --- INITIAL-COMMANDS.md | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/INITIAL-COMMANDS.md b/INITIAL-COMMANDS.md index 79773bd9..40f609b9 100644 --- a/INITIAL-COMMANDS.md +++ b/INITIAL-COMMANDS.md @@ -18,17 +18,21 @@ Run the complete base installation: { :local BaseUrl "https://git.eworm.de/cgit/routeros-scripts/plain/"; + :local CertCommonName "ISRG Root X2"; :local CertFileName "ISRG-Root-X2.pem"; :local CertFingerprint "69729b8e15a86efc177a57afb7171dfc64add28c2fca8cf1507e34453ccb1470"; - :put "Importing certificate..."; - /tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value; - :delay 1s; - /certificate/import file-name=$CertFileName passphrase=""; - :if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] != 1) do={ - :error "Something is wrong with your certificates!"; + :if (!(([ /certificate/settings/get ]->"builtin-trust-anchors") = "trusted" && \ + [[ :parse (":return [ :len [ /certificate/builtin/find where common-name=\"" . $CertCommonName . "\" ] ]") ]] > 0)) do={ + :put "Importing certificate..."; + /tool/fetch ($BaseUrl . "certs/" . $CertFileName) dst-path=$CertFileName as-value; + :delay 1s; + /certificate/import file-name=$CertFileName passphrase=""; + :if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] != 1) do={ + :error "Something is wrong with your certificates!"; + }; + :delay 1s; }; - :delay 1s; :put "Renaming global-config-overlay, if exists..."; /system/script/set name=("global-config-overlay-" . [ /system/clock/get date ] . "-" . [ /system/clock/get time ]) [ find where name="global-config-overlay" ]; :foreach Script in={ "global-config"; "global-config-overlay"; "global-functions" } do={ @@ -41,9 +45,11 @@ Run the complete base installation: :put "Scheduling to load configuration and functions..."; /system/scheduler/remove [ find where name="global-scripts" ]; /system/scheduler/add name="global-scripts" start-time=startup on-event="/system/script { run global-config; run global-functions; }"; - :put "Renaming certificate by its common-name..."; - :global CertificateNameByCN; - $CertificateNameByCN $CertFingerprint; + :if ([ :len [ /certificate/find where fingerprint=$CertFingerprint ] ] > 0) do={ + :put "Renaming certificate by its common-name..."; + :global CertificateNameByCN; + $CertificateNameByCN $CertFingerprint; + }; }; Then continue setup with From b70e6e79843f7c1bbc0031dd74cdf8005d3da4ff Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 21:53:23 +0200 Subject: [PATCH 05/24] global-functions: introduce $FileGet --- global-functions.rsc | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index 759b2744..3a2d20a5 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -38,6 +38,7 @@ :global ExitError; :global FetchHuge; :global FetchUserAgentStr; +:global FileGet; :global FormatLine; :global FormatMultiLines; :global GetMacVendor; @@ -529,6 +530,18 @@ $Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)"); } +# get file properties in array, or false on error +:set FileGet do={ + :local FileName [ :tostr $1 ]; + + :local FileVal false; + :do { + :set FileVal [ /file/get $FileName ]; + } on-error={ } + + :return $FileVal; +} + # format a line for output :set FormatLine do={ :local Key [ :tostr $1 ]; From 1e4f168735663cc09395980b5fa24a25f6403347 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:42:25 +0200 Subject: [PATCH 06/24] global-functions: $MkDir: use $FileGet ... ... to work around restrictions in new file handling. --- global-functions.rsc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3a2d20a5..3b2ab95d 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -893,6 +893,7 @@ :local Path [ :tostr $1 ]; :global CleanFilePath; + :global FileGet; :global LogPrint; :global RmDir; :global WaitForFile; @@ -930,7 +931,8 @@ $LogPrint debug $0 ("Making directory: " . $Path); - :if ([ :len [ /file/find where name=$Path type="directory" ] ] = 1) do={ + :local PathVal [ $FileGet $Path ]; + :if ($PathVal->"type" = "directory") do={ $LogPrint debug $0 ("... which already exists."); :return true; } From d993495e44563f841f7fed19fcf3162a6cb7b971 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 21:38:26 +0200 Subject: [PATCH 07/24] global-functions: $RmDir: use $FileGet ... ... to work around restrictions in new file handling. --- global-functions.rsc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3b2ab95d..2d0cd391 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1057,25 +1057,26 @@ :set RmDir do={ :local DirName [ :tostr $1 ]; + :global FileGet; :global LogPrint; $LogPrint debug $0 ("Removing directory: ". $DirName); - :if ([ :len [ /file/find where name=$DirName type!=directory ] ] > 0) do={ - $LogPrint error $0 ("Directory '" . $DirName . "' is not a directory."); - :return false; - } - - :local Dir [ /file/find where name=$DirName type=directory ]; - :if ([ :len $Dir ] = 0) do={ + :local DirVal [ $FileGet $DirName ]; + :if ($DirVal = false) do={ $LogPrint debug $0 ("... which does not exist."); :return true; } + :if ($DirVal->"type" != "directory") do={ + $LogPrint error $0 ("Directory '" . $DirName . "' is not a directory."); + :return false; + } + :onerror Err { - /file/remove $Dir; + /file/remove $DirName; } do={ - $LogPrint error $0 ("Removing directory '" . $DirName . "' (" . $Dir . ") failed: " . $Err); + $LogPrint error $0 ("Removing directory '" . $DirName . "' failed: " . $Err); :return false; } :return true; From fb8e616846ab8decb10a8b792b5307a01195110d Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 21:41:34 +0200 Subject: [PATCH 08/24] global-functions: $RmFile: use $FileGet ... ... to work around restrictions in new file handling. --- global-functions.rsc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 2d0cd391..985deba4 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1086,25 +1086,26 @@ :set RmFile do={ :local FileName [ :tostr $1 ]; + :global FileGet; :global LogPrint; $LogPrint debug $0 ("Removing file: ". $FileName); - :if ([ :len [ /file/find where name=$FileName (type=directory or type=disk) ] ] > 0) do={ - $LogPrint error $0 ("File '" . $FileName . "' is not a file."); - :return false; - } - - :local File [ /file/find where name=$FileName !(type=directory or type=disk) ]; - :if ([ :len $File ] = 0) do={ + :local FileVal [ $FileGet $FileName ]; + :if ($FileVal = false) do={ $LogPrint debug $0 ("... which does not exist."); :return true; } + :if ($FileVal->"type" = "directory" || $FileVal->"type" = "disk") do={ + $LogPrint error $0 ("File '" . $FileName . "' is not a file."); + :return false; + } + :onerror Err { - /file/remove $File; + /file/remove $FileName; } do={ - $LogPrint error $0 ("Removing file '" . $FileName . "' (" . $File . ") failed: " . $Err); + $LogPrint error $0 ("Removing file '" . $FileName . "' failed: " . $Err); :return false; } :return true; From e08bb2192dfd22b25652553f28304818a3602331 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:48:05 +0200 Subject: [PATCH 09/24] global-functions: $WaitForFile: drop the workaround This was fixed in RouterOS 7.18rc1, so should be ok to remove now. --- global-functions.rsc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 985deba4..3a621697 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1757,15 +1757,6 @@ :set I ($I + 1); } - :while ([ :len [ /file/find where name=$FileName ] ] > 0) do={ - :do { - /file/get $FileName; - :return true; - } on-error={ } - :delay $Delay; - :set Delay ($Delay * 3 / 2); - } - :return false; } From 0e00a228d67d77fadc80eee2df04c2cec25b8db8 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 21:25:20 +0200 Subject: [PATCH 10/24] global-functions: $WaitForFile: use :retry for simplification, ... ... and to work around restrictions in new file handling. --- global-functions.rsc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index 3a621697..fa5d2be9 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -1746,16 +1746,14 @@ :global MAX; :set FileName [ $CleanFilePath $FileName ]; - :local I 1; :local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10); - :while ([ :len [ /file/find where name=$FileName ] ] = 0) do={ - :if ($I >= 10) do={ - :return false; - } - :delay $Delay; - :set I ($I + 1); - } + :do { + :retry { + /file/get $FileName; + :return true; + } delay=$Delay max=10; + } on-error={ } :return false; } From cb984a5e527a12aaa2336cfd66f180302755f066 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:34:07 +0200 Subject: [PATCH 11/24] global-functions: introduce $FileExists --- global-functions.rsc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/global-functions.rsc b/global-functions.rsc index fa5d2be9..ddddc409 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -38,6 +38,7 @@ :global ExitError; :global FetchHuge; :global FetchUserAgentStr; +:global FileExists; :global FileGet; :global FormatLine; :global FormatMultiLines; @@ -530,6 +531,29 @@ $Resource->"architecture-name" . " " . $Caller . "/Fetch (https://rsc.eworm.de/)"); } +# check for existence of file, optionally with type +:set FileExists do={ + :local FileName [ :tostr $1 ]; + :local Type [ :tostr $2 ]; + + :global FileGet; + + :local FileVal [ $FileGet $FileName ]; + :if ($FileVal = false) do={ + :return false; + } + + :if ([ :len ($FileVal->"size") ] = 0) do={ + :return false; + } + + :if ([ :len $Type ] = 0 || $FileVal->"type" = $Type) do={ + :return true; + } + + :return false; +} + # get file properties in array, or false on error :set FileGet do={ :local FileName [ :tostr $1 ]; From 8353a8547f45a18e167b8ffd3779d8bd469dd1c7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 20:44:49 +0200 Subject: [PATCH 12/24] global-functions: $DownloadPackage: use $FileExists ... ... to work around restrictions in new file handling. --- global-functions.rsc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/global-functions.rsc b/global-functions.rsc index ddddc409..50426b69 100644 --- a/global-functions.rsc +++ b/global-functions.rsc @@ -365,6 +365,7 @@ :global CertificateAvailable; :global CleanFilePath; + :global FileExists; :global LogPrint; :global MkDir; :global RmFile; @@ -385,7 +386,7 @@ :return false; } - :if ([ :len [ /file/find where name=$PkgDest type="package" ] ] > 0) do={ + :if ([ $FileExists $PkgDest "package" ] = true) do={ $LogPrint info $0 ("Package file " . $PkgName . " already exists."); :return true; } @@ -407,7 +408,7 @@ :return false; } - :if ([ /file/get [ find where name=$PkgDest ] type ] != "package") do={ + :if ([ $FileExists $PkgDest "package" ] = false) do={ $LogPrint warning $0 ("Downloaded file is not a package, removing."); $RmFile $PkgDest; :return false; From a2f837be591e4e64f2634e1d2e57352989326e98 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:39:18 +0200 Subject: [PATCH 13/24] backup-email: use :retry and $FileExists ... ... to work around restrictions in new file handling. --- backup-email.rsc | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/backup-email.rsc b/backup-email.rsc index 632d2e60..cff6fd83 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -27,6 +27,7 @@ :global CleanName; :global DeviceInfo; + :global FileExists; :global FormatLine; :global LogPrint; :global MkDir; @@ -124,16 +125,16 @@ attach=$Attach; remove-attach=true }); # wait for the mail to be sent - :local I 0; - :while ([ :len [ /file/find where name ~ ($FilePath . "\\.(backup|rsc)\$") ] ] > 0) do={ - :if ($I >= 120) do={ - $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); - :set PackagesUpdateBackupFailure true; - :set ExitOK true; - :error false; - } - :delay 1s; - :set I ($I + 1); + :do { + :retry { + :if ([ $FileExists ($FilePath . ".backup") "backup" ] = true || \ + [ $FileExists ($FilePath . ".rsc") "script" ] = true) do={ + :error "Files are still available."; + } + } delay=1s max=120; + } on-error={ + $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); + :set PackagesUpdateBackupFailure true; } } do={ :global ExitError; $ExitError $ExitOK [ :jobname ] $Err; From 43bac7c33c50e164ff7ac56029519d510bc08973 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 23:52:29 +0200 Subject: [PATCH 14/24] backup-email: check for .conf file --- backup-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backup-email.rsc b/backup-email.rsc index cff6fd83..cc621055 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -127,7 +127,8 @@ # wait for the mail to be sent :do { :retry { - :if ([ $FileExists ($FilePath . ".backup") "backup" ] = true || \ + :if ([ $FileExists ($FilePath . ".conf") ".conf file" ] = true || \ + [ $FileExists ($FilePath . ".backup") "backup" ] = true || \ [ $FileExists ($FilePath . ".rsc") "script" ] = true) do={ :error "Files are still available."; } From daee05dbd7c03aa7ce977ba7856234026185c4a1 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 23:49:50 +0200 Subject: [PATCH 15/24] backup-email: add a comment why files are not removed --- backup-email.rsc | 1 + 1 file changed, 1 insertion(+) diff --git a/backup-email.rsc b/backup-email.rsc index cc621055..8015beaa 100644 --- a/backup-email.rsc +++ b/backup-email.rsc @@ -137,6 +137,7 @@ $LogPrint warning $ScriptName ("Files are still available, sending e-mail failed."); :set PackagesUpdateBackupFailure true; } + # do not remove the files here, as the mail is still queued! } do={ :global ExitError; $ExitError $ExitOK [ :jobname ] $Err; } From e3284ca77081642d2105d6a6773fa6767188dbec Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:46:03 +0200 Subject: [PATCH 16/24] mod/notification-email: use $FileExists ... ... to work around restrictions in new file handling. --- mod/notification-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 52937668..75e11b9d 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -40,6 +40,7 @@ :global EitherOr; :global EMailGenerateFrom; + :global FileExists; :global IsDNSResolving; :global IsTimeSync; :global LogPrint; @@ -93,7 +94,7 @@ :onerror Err { :local Attach ({}); :foreach File in=[ :toarray [ $EitherOr ($Message->"attach") "" ] ] do={ - :if ([ :len [ /file/find where name=$File ] ] = 1) do={ + :if ([ $FileExists $File ] = true) do={ :set Attach ($Attach, $File); } else={ $LogPrint warning $0 ("File '" . $File . "' does not exist, can not attach."); From 2d81984aed8894200e4f8c6c72596b8b05bdbb93 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:46:16 +0200 Subject: [PATCH 17/24] mod/notification-email: use $RmFile --- mod/notification-email.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mod/notification-email.rsc b/mod/notification-email.rsc index 75e11b9d..ad9762a3 100644 --- a/mod/notification-email.rsc +++ b/mod/notification-email.rsc @@ -44,6 +44,7 @@ :global IsDNSResolving; :global IsTimeSync; :global LogPrint; + :global RmFile; :local AllDone true; :local QueueLen [ :len $EmailQueue ]; @@ -111,7 +112,7 @@ :set Wait false; :if (($Message->"remove-attach") = true) do={ :foreach File in=$Attach do={ - /file/remove $File; + $RmFile $File; } } } From 80aed200fd7400e4a4958ba314912488780be635 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:48:57 +0200 Subject: [PATCH 18/24] mod/ssh-keys-import: use $FileExists ... ... to work around restrictions in new file handling. --- mod/ssh-keys-import.rsc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mod/ssh-keys-import.rsc b/mod/ssh-keys-import.rsc index 94675255..7bdc95da 100644 --- a/mod/ssh-keys-import.rsc +++ b/mod/ssh-keys-import.rsc @@ -75,6 +75,7 @@ :local User [ :tostr $2 ]; :global EitherOr; + :global FileExists; :global LogPrint; :global ParseKeyValueStore; :global SSHKeysImport; @@ -84,8 +85,7 @@ :return false; } - :local File [ /file/find where name=$FileName ]; - :if ([ :len $File ] = 0) do={ + :if ([ $FileExists $FileName ] = true) do={ $LogPrint warning $0 ("File '" . $FileName . "' does not exist."); :return false; } From 30b80e903dbf80510fbb05f21c598ecf6c1834d7 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 22:41:03 +0200 Subject: [PATCH 19/24] telegram-chat: use $FileExists ... ... to work around restrictions in new file handling. --- telegram-chat.rsc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/telegram-chat.rsc b/telegram-chat.rsc index fdd08838..7f7b7a79 100644 --- a/telegram-chat.rsc +++ b/telegram-chat.rsc @@ -30,6 +30,7 @@ :global CertificateAvailable; :global EitherOr; :global EscapeForRegEx; + :global FileExists; :global GetRandom20CharAlNum; :global IfThenElse; :global LogPrint; @@ -154,7 +155,7 @@ :if ([ $WaitForFile ($File . ".done") [ $EitherOr $TelegramChatRunTime 20s ] ] = false) do={ :set State ([ $SymbolForNotification "warning-sign" ] . "The command did not finish, still running in background.\n\n"); } - :if ([ :len [ /file/find where name=($File . ".failed") ] ] > 0) do={ + :if ([ $FileExists ($File . ".failed") ] = true) do={ :set State ([ $SymbolForNotification "cross-mark" ] . "The command failed with an error!\n\n"); } :local Content ([ /file/read chunk-size=32768 file=$File as-value ]->"data"); From 5b15c82bb11f9da1b6858504dc1e0de401e91c8f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 22:16:43 +0200 Subject: [PATCH 20/24] capsman-download-packages: use $FileGet ... ... to work around restrictions in new file handling. --- capsman-download-packages.capsman.rsc | 3 ++- capsman-download-packages.template.rsc | 3 ++- capsman-download-packages.wifi.rsc | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index cab1e4c3..e296e159 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -20,6 +20,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -42,7 +43,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index ea411201..4040d4d0 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -21,6 +21,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -44,7 +45,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index a8103569..809fe8e7 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -20,6 +20,7 @@ :global CleanFilePath; :global DownloadPackage; + :global FileGet; :global LogPrint; :global MkDir; :global RmFile; @@ -42,7 +43,7 @@ :error false; } - :if ([ :len [ /file/find where name=$PackagePath type="directory" ] ] = 0) do={ + :if ([ $FileGet $PackagePath ] = false) do={ :if ([ $MkDir $PackagePath ] = false) do={ $LogPrint warning $ScriptName ("Creating directory at CAPsMAN package path (" . \ $PackagePath . ") failed!"); From 15fd522d3db507cc7c22af9cd59ff85d41a5be6f Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Fri, 30 May 2025 23:22:59 +0200 Subject: [PATCH 21/24] capsman-download-packages: adopt new functionality from file menu --- capsman-download-packages.capsman.rsc | 8 ++++---- capsman-download-packages.template.rsc | 8 ++++---- capsman-download-packages.wifi.rsc | 8 ++++---- doc/capsman-download-packages.md | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/capsman-download-packages.capsman.rsc b/capsman-download-packages.capsman.rsc index e296e159..aaebf5c0 100644 --- a/capsman-download-packages.capsman.rsc +++ b/capsman-download-packages.capsman.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "mipsbe" } do={ :foreach Package in={ "routeros"; "wireless" } do={ diff --git a/capsman-download-packages.template.rsc b/capsman-download-packages.template.rsc index 4040d4d0..ebbba709 100644 --- a/capsman-download-packages.template.rsc +++ b/capsman-download-packages.template.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -56,8 +56,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -69,7 +69,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); # NOT /interface/wifi/ # :foreach Arch in={ "arm"; "mipsbe" } do={ diff --git a/capsman-download-packages.wifi.rsc b/capsman-download-packages.wifi.rsc index 809fe8e7..7de0431f 100644 --- a/capsman-download-packages.wifi.rsc +++ b/capsman-download-packages.wifi.rsc @@ -4,7 +4,7 @@ # Michael Gisbers # https://rsc.eworm.de/COPYING.md # -# requires RouterOS, version=7.15 +# requires RouterOS, version=7.18 # # download and cleanup packages for CAP installation from CAPsMAN # https://rsc.eworm.de/doc/capsman-download-packages.md @@ -54,8 +54,8 @@ "). Please place your packages!"); } - :foreach Package in=[ /file/find where type=package \ - package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={ + :foreach Package in=[ /file/find recursive where path=$PackagePath \ + type="package" package-version!=$InstalledVersion ] do={ :local File [ /file/get $Package ]; :if ($File->"package-architecture" = "mips") do={ :set ($File->"package-architecture") "mipsbe"; @@ -67,7 +67,7 @@ } } - :if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={ + :if ([ :len [ /file/find recursive where path=$PackagePath type="package" ] ] = 0) do={ $LogPrint info $ScriptName ("No packages available, downloading default set."); :foreach Arch in={ "arm"; "arm64" } do={ :local Packages { "arm"={ "routeros"; "wifi-qcom"; "wifi-qcom-ac" }; diff --git a/doc/capsman-download-packages.md b/doc/capsman-download-packages.md index 57222272..4daad494 100644 --- a/doc/capsman-download-packages.md +++ b/doc/capsman-download-packages.md @@ -4,7 +4,7 @@ Download packages for CAP upgrade from CAPsMAN [![GitHub stars](https://img.shields.io/github/stars/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=red)](https://github.com/eworm-de/routeros-scripts/stargazers) [![GitHub forks](https://img.shields.io/github/forks/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=green)](https://github.com/eworm-de/routeros-scripts/network) [![GitHub watchers](https://img.shields.io/github/watchers/eworm-de/routeros-scripts?logo=GitHub&style=flat&color=blue)](https://github.com/eworm-de/routeros-scripts/watchers) -[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.15-yellow?style=flat)](https://mikrotik.com/download/changelogs/) +[![required RouterOS version](https://img.shields.io/badge/RouterOS-7.18-yellow?style=flat)](https://mikrotik.com/download/changelogs/) [![Telegram group @routeros_scripts](https://img.shields.io/badge/Telegram-%40routeros__scripts-%2326A5E4?logo=telegram&style=flat)](https://t.me/routeros_scripts) [![donate with PayPal](https://img.shields.io/badge/Like_it%3F-Donate!-orange?logo=githubsponsors&logoColor=orange&style=flat)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J) From c3d3d61f92d4d3e219373045dbd3b982af18a824 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 15:58:00 +0200 Subject: [PATCH 22/24] packages-update: support deferred reboot with longer interval --- doc/packages-update.md | 4 ++-- packages-update.rsc | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/doc/packages-update.md b/doc/packages-update.md index 75225fe2..a0a17956 100644 --- a/doc/packages-update.md +++ b/doc/packages-update.md @@ -46,8 +46,8 @@ Configuration The configuration goes to `global-config-overlay`, this is the only parameter: -* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM - and 5 AM) +* `PackagesUpdateDeferReboot`: defer the reboot for night (between 3 AM and + 5 AM), use a numerical value in days suffixed with a `d` to defer further By modifying the scheduler's `start-time` you can force the reboot at different time. diff --git a/packages-update.rsc b/packages-update.rsc index 4fde131b..43f67494 100644 --- a/packages-update.rsc +++ b/packages-update.rsc @@ -31,19 +31,24 @@ :local Schedule do={ :local ScriptName [ :tostr $1 ]; + :global PackagesUpdateDeferReboot; + :global GetRandomNumber; + :global IfThenElse; :global LogPrint; :global RebootForUpdate do={ /system/reboot; } + :local Interval [ $IfThenElse ($PackagesUpdateDeferReboot >= 1d) $PackagesUpdateDeferReboot 1d ]; :local StartTime [ :tostr [ :totime (10800 + [ $GetRandomNumber 7200 ]) ] ]; - /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=1d \ + /system/scheduler/add name="_RebootForUpdate" start-time=$StartTime interval=$Interval \ on-event=("/system/scheduler/remove \"_RebootForUpdate\"; " . \ ":global RebootForUpdate; \$RebootForUpdate;"); $LogPrint info $ScriptName ("Scheduled reboot for update at " . $StartTime . \ - " local time (" . [ /system/clock/get time-zone-name ] . ")."); + " local time (" . [ /system/clock/get time-zone-name ] . ")" . \ + [ $IfThenElse ($Interval > 1d) (" deferred by " . $Interval) ] . "."); :return true; } @@ -153,7 +158,7 @@ :error true; } } else={ - :if ($PackagesUpdateDeferReboot = true) do={ + :if ($PackagesUpdateDeferReboot = true || $PackagesUpdateDeferReboot >= 1d) do={ $Schedule $ScriptName; :set ExitOK true; :error true; From 1f4bf9ee63c57a711652954d6d408b221a6503e5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 16:12:28 +0200 Subject: [PATCH 23/24] check-routeros-update: remove a stale scheduler --- check-routeros-update.rsc | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/check-routeros-update.rsc b/check-routeros-update.rsc index e28a0190..8b80ddeb 100644 --- a/check-routeros-update.rsc +++ b/check-routeros-update.rsc @@ -28,6 +28,7 @@ :global EscapeForRegEx; :global FetchUserAgentStr; :global LogPrint; + :global RebootForUpdate; :global ScriptFromTerminal; :global ScriptLock; :global SendNotification2; @@ -62,9 +63,14 @@ $WaitFullyConnected; :if ([ :len [ /system/scheduler/find where name="_RebootForUpdate" ] ] > 0) do={ - $LogPrint info $ScriptName ("A reboot for update is already scheduled."); - :set ExitOK true; - :error false; + :if ([ :typeof $RebootForUpdate ] = "nothing") do={ + $LogPrint info $ScriptName ("Found a stale scheduler for reboot, removing."); + /system/scheduler/remove "_RebootForUpdate"; + } else={ + $LogPrint info $ScriptName ("A reboot for update is already scheduled."); + :set ExitOK true; + :error false; + } } $LogPrint debug $ScriptName ("Checking for updates..."); From 0de6d006ae1773b38bef60845c6c343bc20f5da6 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Mon, 2 Jun 2025 21:37:59 +0200 Subject: [PATCH 24/24] update list of contributors --- CONTRIBUTIONS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CONTRIBUTIONS.md b/CONTRIBUTIONS.md index 5bf5d089..00861c18 100644 --- a/CONTRIBUTIONS.md +++ b/CONTRIBUTIONS.md @@ -35,6 +35,7 @@ Add yourself to the list, [donate with PayPal ↗️](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=A4ZXBD6YS2W8J)! * Abdul Mannan Abbasi +* Alex Maier * Andrea Ruffini Perico * Andrew Cox * Christoph Boss (@Kampfwurst)