Compare commits

...

39 commits

Author SHA1 Message Date
Christian Hesse
89175e511f accesslist-duplicates: print without paging 2025-07-07 18:38:21 +02:00
Christian Hesse
b068f86995 netwatch-dns: fix indention 2025-06-25 10:47:12 +02:00
Christian Hesse
d46574b4fe netwatch-dns: retry doh server...
... for more resilience on bad connectivity or saturated link.
2025-06-25 10:30:26 +02:00
Christian Hesse
c3010af4ed Merge branch 'file' into next 2025-06-23 08:52:58 +02:00
Christian Hesse
1307b8587e global-functions: $FileGet: mitigate race with file properties
RouterOS is suffering a race condition, where a file exists, but its
properties are not (yet) available. This is handled in $WaitForFile.

This passes an interval of zero to $WaitForFile, as does not wait for
the file to exist, but wants to avoid the race only.
2025-06-23 08:52:58 +02:00
Christian Hesse
6415849850 global-functions: $WaitForFile: (mostly) revert changes
This (mostly) reverts commits 0e00a228d6
and e08bb2192d.

This is required for RouterOS 7.20beta4. That fixed recursive find for
files, and (again, or still?) suffers timing (and thus racing) issues
getting file properties.

This breaks RouterOS 7.20beta2 again, so that specific version is not
supported. Just update...
2025-06-23 08:52:51 +02:00
Christian Hesse
95f8af6234 packages-update: convert to time before comparing...
... to avoid:

    packages-update: Script 'packages-update' exited with error: Script Error: cannot compare if truth value is more than or equal to ip address
2025-06-20 23:52:07 +02:00
Christian Hesse
de2a90d841 doc/fw-addr-lists: add a warning on possible subsystem crash 2025-06-11 17:47:40 +02:00
Christian Hesse
e2d3f0f073 fw-addr-lists: delay on possible scripting subsystem crash
This happens in :convert when a list is way too large.

Let's use $LogPrintOnce here. If the scripting subsystem really crashes
the message will be purged from $LogPrintOnceMessages anyway (as all
global variables are lost).
2025-06-11 17:46:09 +02:00
Christian Hesse
595b4aea9d capsman-download-packages: revert changes for "new functionality"
(Though we keep the quoting for type.)

Well, turned out this functionality is for `/file/print` only,
but does not work with `/file/find`. 🫣🥴

This reverts commit 15fd522d3d.
2025-06-11 17:46:09 +02:00
Christian Hesse
0de6d006ae update list of contributors 2025-06-04 22:30:51 +02:00
Christian Hesse
1f4bf9ee63 check-routeros-update: remove a stale scheduler 2025-06-04 22:30:51 +02:00
Christian Hesse
c3d3d61f92 packages-update: support deferred reboot with longer interval 2025-06-04 22:30:51 +02:00
Christian Hesse
6130c94cc1 Merge branch 'file' into next 2025-06-04 22:30:51 +02:00
Christian Hesse
15fd522d3d capsman-download-packages: adopt new functionality from file menu 2025-06-04 22:30:51 +02:00
Christian Hesse
5b15c82bb1 capsman-download-packages: use $FileGet ...
... to work around restrictions in new file handling.
2025-06-04 22:30:48 +02:00
Christian Hesse
30b80e903d telegram-chat: use $FileExists ...
... to work around restrictions in new file handling.
2025-06-04 22:30:45 +02:00
Christian Hesse
80aed200fd mod/ssh-keys-import: use $FileExists ...
... to work around restrictions in new file handling.
2025-06-04 22:30:42 +02:00
Christian Hesse
2d81984aed mod/notification-email: use $RmFile 2025-06-04 22:30:42 +02:00
Christian Hesse
e3284ca770 mod/notification-email: use $FileExists ...
... to work around restrictions in new file handling.
2025-06-04 22:30:39 +02:00
Christian Hesse
daee05dbd7 backup-email: add a comment why files are not removed 2025-06-04 22:30:39 +02:00
Christian Hesse
43bac7c33c backup-email: check for .conf file 2025-06-04 22:30:39 +02:00
Christian Hesse
a2f837be59 backup-email: use :retry and $FileExists ...
... to work around restrictions in new file handling.
2025-06-04 22:30:36 +02:00
Christian Hesse
8353a8547f global-functions: $DownloadPackage: use $FileExists ...
... to work around restrictions in new file handling.
2025-06-04 22:30:33 +02:00
Christian Hesse
cb984a5e52 global-functions: introduce $FileExists 2025-06-04 22:28:25 +02:00
Christian Hesse
0e00a228d6 global-functions: $WaitForFile: use :retry for simplification, ...
... and to work around restrictions in new file handling.
2025-06-04 22:28:20 +02:00
Christian Hesse
e08bb2192d global-functions: $WaitForFile: drop the workaround
This was fixed in RouterOS 7.18rc1, so should be ok to remove now.
2025-06-04 22:28:20 +02:00
Christian Hesse
fb8e616846 global-functions: $RmFile: use $FileGet ...
... to work around restrictions in new file handling.
2025-06-04 22:28:17 +02:00
Christian Hesse
d993495e44 global-functions: $RmDir: use $FileGet ...
... to work around restrictions in new file handling.
2025-06-04 22:28:14 +02:00
Christian Hesse
1e4f168735 global-functions: $MkDir: use $FileGet ...
... to work around restrictions in new file handling.
2025-06-04 22:28:11 +02:00
Christian Hesse
b70e6e7984 global-functions: introduce $FileGet 2025-06-03 12:29:42 +02:00
Christian Hesse
4bc3bf40e6 Merge branch 'builtin-certs' into next 2025-06-03 11:06:59 +02:00
Christian Hesse
d69b399572 INITIAL-COMMANDS: use builtin certificates if possible 2025-06-03 11:06:59 +02:00
Christian Hesse
bf684a7197 global-functions: $CertificateAvailable: try to use builtin certificates
The builtin certificates were introduced with RouterOS 7.19, so requires
this hacky :parse workaround.
2025-05-28 15:08:26 +02:00
Christian Hesse
d59c4aee26 README: add a paragraph and link to jump 2025-05-28 14:16:57 +02:00
Christian Hesse
3d3b270748 README: give a hint on builtin certificate store
I guess this should become the default any time in future...
2025-05-28 14:07:57 +02:00
Christian Hesse
6a49c483b6 telegram-chat: rename variable...
... to better describe the use.
2025-05-23 17:38:22 +02:00
Christian Hesse
c50acd697a telegram-chat: fix detection of replies 2025-05-23 17:36:56 +02:00
Christian Hesse
4bd7d44cd2 global-functions: $ScriptInstallUpdate: fix syntax error 2025-05-23 11:16:40 +02:00
21 changed files with 190 additions and 87 deletions

View file

@ -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)

View file

@ -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

View file

@ -72,7 +72,15 @@ 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 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
different location (for example from github.com) install the corresponding
certificate chain.
@ -106,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!

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /caps-man/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /caps-man/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={
/caps-man/access-list/print where mac-address=$Mac;
/caps-man/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /interface/wireless/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={
/interface/wireless/access-list/print where mac-address=$Mac;
/interface/wireless/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={

View file

@ -27,9 +27,9 @@
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
:local Mac [ /interface/wireless/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={
/caps-man/access-list/print where mac-address=$Mac;
/interface/wifi/access-list/print where mac-address=$Mac;
/interface/wireless/access-list/print where mac-address=$Mac;
/caps-man/access-list/print without-paging where mac-address=$Mac;
/interface/wifi/access-list/print without-paging where mac-address=$Mac;
/interface/wireless/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={

View file

@ -22,7 +22,7 @@
:foreach AccList in=[ /interface/wifi/access-list/find where mac-address!="00:00:00:00:00:00" ] do={
:local Mac [ /interface/wifi/access-list/get $AccList mac-address ];
:if ($Seen->$Mac = 1) do={
/interface/wifi/access-list/print where mac-address=$Mac;
/interface/wifi/access-list/print without-paging where mac-address=$Mac;
:local Remove [ :tonum [ /terminal/ask prompt="\nNumeric id to remove, any key to skip!" ] ];
:if ([ :typeof $Remove ] = "num") do={

View file

@ -27,6 +27,7 @@
:global CleanName;
:global DeviceInfo;
:global FileExists;
:global FormatLine;
:global LogPrint;
:global MkDir;
@ -124,17 +125,19 @@
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 . ".conf") ".conf file" ] = true || \
[ $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 not remove the files here, as the mail is still queued!
} do={
:global ExitError; $ExitError $ExitOK [ :jobname ] $Err;
}

View file

@ -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!");
@ -53,7 +54,7 @@
"). Please place your packages!");
}
:foreach Package in=[ /file/find where type=package \
:foreach Package in=[ /file/find where type="package" \
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
:local File [ /file/get $Package ];
:if ($File->"package-architecture" = "mips") do={
@ -66,7 +67,7 @@
}
}
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={
$LogPrint info $ScriptName ("No packages available, downloading default set.");
:foreach Arch in={ "arm"; "mipsbe" } do={
:foreach Package in={ "routeros"; "wireless" } do={

View file

@ -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!");
@ -55,7 +56,7 @@
"). Please place your packages!");
}
:foreach Package in=[ /file/find where type=package \
:foreach Package in=[ /file/find where type="package" \
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
:local File [ /file/get $Package ];
:if ($File->"package-architecture" = "mips") do={
@ -68,7 +69,7 @@
}
}
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 0) do={
$LogPrint info $ScriptName ("No packages available, downloading default set.");
# NOT /interface/wifi/ #
:foreach Arch in={ "arm"; "mipsbe" } do={

View file

@ -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!");
@ -53,7 +54,7 @@
"). Please place your packages!");
}
:foreach Package in=[ /file/find where type=package \
:foreach Package in=[ /file/find where type="package" \
package-version!=$InstalledVersion name~("^" . $PackagePath) ] do={
:local File [ /file/get $Package ];
:if ($File->"package-architecture" = "mips") do={
@ -66,7 +67,7 @@
}
}
:if ([ :len [ /file/find where type=package name~("^" . $PackagePath) ] ] = 0) do={
:if ([ :len [ /file/find where type="package" name~("^" . $PackagePath) ] ] = 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" };

View file

@ -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...");

View file

@ -32,7 +32,10 @@ certificate is checked.
> ⚠️ **Warning**: The script does not limit the size of a list, but keep in
> mind that huge lists can exhaust your device's resources (RAM and CPU),
> and may take a long time to process.
> and may take a long time to process.
> Even crashes for the complete scripting (and CLI) subsystem are possible.
> This should be logged accordingly with warnings when global functions are
> reloaded from scheduler.
Requirements and installation
-----------------------------

View file

@ -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.

View file

@ -48,6 +48,12 @@
}
$WaitFullyConnected;
:if ([ :len [ /log/find where topics=({"script"; "warning"}) \
message=("\$LogPrintOnce: The message is already in log, scripting subsystem may have crashed before!") ] ] > 0) do={
$LogPrintOnce warning $ScriptName ("Scripting subsystem may have crashed, possibly caused by us. Delaying!");
:delay 5m;
}
:local ListComment ("managed by " . $ScriptName);
:foreach FwListName,FwList in=$FwAddrLists do={

View file

@ -38,6 +38,8 @@
:global ExitError;
:global FetchHuge;
:global FetchUserAgentStr;
:global FileExists;
:global FileGet;
:global FormatLine;
:global FormatMultiLines;
:global GetMacVendor;
@ -119,6 +121,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={
@ -358,6 +365,7 @@
:global CertificateAvailable;
:global CleanFilePath;
:global FileExists;
:global LogPrint;
:global MkDir;
:global RmFile;
@ -378,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;
}
@ -400,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;
@ -524,6 +532,47 @@
$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 ];
:global WaitForFile;
:if ([ $WaitForFile $FileName 0s ] = false) do={
:return false;
}
: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 ];
@ -875,6 +924,7 @@
:local Path [ :tostr $1 ];
:global CleanFilePath;
:global FileGet;
:global LogPrint;
:global RmDir;
:global WaitForFile;
@ -912,7 +962,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;
}
@ -1037,25 +1088,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;
@ -1065,25 +1117,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;
@ -1212,7 +1265,7 @@
:set SourceNew [ :tolf ($Result->"data") ];
}
} do={
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . . "': " . $Err);
$LogPrint warning $0 ("Failed fetching script '" . $ScriptVal->"name" . "': " . $Err);
:if ($ScriptVal->"source" = "#!rsc by RouterOS\n") do={
$LogPrint warning $0 ("Removing dummy. Typo on installation?");
/system/script/remove $Script;
@ -1724,15 +1777,16 @@
:global MAX;
:set FileName [ $CleanFilePath $FileName ];
:local I 1;
:local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 10);
:local Delay ([ $MAX [ $EitherOr $WaitTime 2s ] 100ms ] / 9);
:while ([ :len [ /file/find where name=$FileName ] ] = 0) do={
:if ($I >= 10) do={
:return false;
}
:delay $Delay;
:set I ($I + 1);
:do {
:retry {
:if ([ :len [ /file/find where name=$FileName ] ] = 0) do={
:error false;
}
} delay=$Delay max=10;
} on-error={
:return false;
}
:while ([ :len [ /file/find where name=$FileName ] ] > 0) do={

View file

@ -40,9 +40,11 @@
:global EitherOr;
:global EMailGenerateFrom;
:global FileExists;
:global IsDNSResolving;
:global IsTimeSync;
:global LogPrint;
:global RmFile;
:local AllDone true;
:local QueueLen [ :len $EmailQueue ];
@ -93,7 +95,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.");
@ -110,7 +112,7 @@
:set Wait false;
:if (($Message->"remove-attach") = true) do={
:foreach File in=$Attach do={
/file/remove $File;
$RmFile $File;
}
}
}

View file

@ -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;
}

View file

@ -119,11 +119,13 @@
:local Data false;
:onerror Err {
:set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
http-header-field=({ "accept: application/dns-message" }) \
url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \
"\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \
"\00\10" . "\00\01") ]) as-value ]->"data");
:retry {
:set Data ([ /tool/fetch check-certificate=yes-without-crl output=user \
http-header-field=({ "accept: application/dns-message" }) \
url=(($DohServer->"doh-url") . "?dns=" . [ :convert to=base64 ([ :rndstr length=2 ] . \
"\01\00" . "\00\01" . "\00\00" . "\00\00" . "\00\00" . "\09doh-check\05eworm\02de\00" . \
"\00\10" . "\00\01") ]) as-value ]->"data");
} delay=1s max=3;
} do={
$LogPrint warning $ScriptName ("Request to DoH server " . ($DohServer->"doh-url") . \
" failed: " . $Err);

View file

@ -31,19 +31,25 @@
:local Schedule do={
:local ScriptName [ :tostr $1 ];
:global PackagesUpdateDeferReboot;
:global GetRandomNumber;
:global IfThenElse;
:global LogPrint;
:global RebootForUpdate do={
/system/reboot;
}
:local Interval [ $IfThenElse ([ :totime $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 +159,7 @@
:error true;
}
} else={
:if ($PackagesUpdateDeferReboot = true) do={
:if ($PackagesUpdateDeferReboot = true || [ :totime $PackagesUpdateDeferReboot ] >= 1d) do={
$Schedule $ScriptName;
:set ExitOK true;
:error true;

View file

@ -30,6 +30,7 @@
:global CertificateAvailable;
:global EitherOr;
:global EscapeForRegEx;
:global FileExists;
:global GetRandom20CharAlNum;
:global IfThenElse;
:global LogPrint;
@ -100,7 +101,7 @@
$LogPrintVerbose debug $ScriptName ("Update " . $UpdateID . ": " . [ :serialize to=json $Update ]);
:local Message ($Update->"message");
:local IsReply ([ :typeof ($Message->"reply_to_message") ] = "string");
:local IsAnyReply ([ :typeof ($Message->"reply_to_message") ] = "array");
:local IsMyReply ($TelegramMessageIDs->[ :tostr ($Message->"reply_to_message"->"message_id") ]);
:if (($IsMyReply = 1 || $TelegramChatOffset->0 > 0 || $Uptime > 5m) && $UpdateID >= $TelegramChatOffset->2) do={
:local Trusted false;
@ -138,7 +139,7 @@
" from update " . $UpdateID . "!");
:set Done true;
}
:if ($Done = false && ($IsMyReply = 1 || ($IsReply = false && \
:if ($Done = false && ($IsMyReply = 1 || ($IsAnyReply = false && \
$TelegramChatActive = true)) && [ :len $Command ] > 0) do={
:if ([ $ValidateSyntax $Command ] = true) do={
:local State "";
@ -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");