]> Git [git.vados.ru] :: Repos - Mikrotiks/Mikrotiks.git/commitdiff
Add files
authorvados-dev <192440777+vados-dev@users.noreply.github.com>
Thu, 12 Mar 2026 03:06:27 +0000 (06:06 +0300)
committervados-dev <192440777+vados-dev@users.noreply.github.com>
Thu, 12 Mar 2026 03:06:27 +0000 (06:06 +0300)
32 files changed:
.bak/Makefile [new file with mode: 0644]
.bak/ROSdiff.sh [new file with mode: 0644]
.bak/get_backups.sh [new file with mode: 0644]
.bak/test.sh [new file with mode: 0644]
.bak/tmp/Makefile [new file with mode: 0644]
.bashrc [new file with mode: 0644]
.config/.mikrotiks [new file with mode: 0644]
.config/mc/hotlist [new file with mode: 0644]
.config/mc/ini [new file with mode: 0644]
.config/mc/panels.ini [new file with mode: 0644]
.gitconfig [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.lesshst [new file with mode: 0644]
.profile [new file with mode: 0644]
.repo_.gitconfig.json [new file with mode: 0644]
.selected_editor [new file with mode: 0644]
.wget-hsts [new file with mode: 0644]
Makefile [new file with mode: 0644]
bin/bash-progress-indicator/LICENSE [new file with mode: 0644]
bin/bash-progress-indicator/README.md [new file with mode: 0644]
bin/bash-progress-indicator/main.sh [new file with mode: 0644]
bin/bash-progress-indicator/progress.sh [new file with mode: 0644]
bin/bash-progress-indicator/progress_advanced.sh [new file with mode: 0644]
bin/bash-progress-indicator/spinner.sh [new file with mode: 0644]
bin/check_repo.sh [new file with mode: 0755]
bin/logs [new symlink]
bin/ros-conf/README.md [new file with mode: 0644]
bin/ros-conf/setup-ssh-keys.sh [new file with mode: 0644]
bin/ros-conf/sync-script.sh [new file with mode: 0644]
bin/ros-diff.sh [new file with mode: 0755]
bin/scripts/mktmpfs.rsc [new file with mode: 0644]
bin/test.sh [new file with mode: 0644]

diff --git a/.bak/Makefile b/.bak/Makefile
new file mode 100644 (file)
index 0000000..7f1bb20
--- /dev/null
@@ -0,0 +1,86 @@
+# Makefile
+
+MK_PATH:=$(dir $(realpath $(lastword $(MAKEFILE_LIST))))
+WORKSPACE_LOC:=$(MK_PATH)../../
+
+WorkFiles      := checksums.json AM-GlobalFunc.rsc
+WORK_DIR       := /var/www/ros.vados.ru
+
+DATE            ?= $(shell (date '+%T %d.%m.%Y'))
+DTSTAMP         ?= $(shell (date '+%Y%d%m%H%M%S'))
+VERSION         ?= $(shell git symbolic-ref --short HEAD 2>/dev/null)/$(shell git rev-list --count HEAD 2>/dev/null)/$(shell git rev-parse --short=8 HEAD 2>/dev/null)
+OWNER           ?= $(shell whoami)
+
+#SEDCMD                ?= $(shell sed -e "/^:global CommitId/c :global CommitId \"${COMMITID:-unknown}\";")/$(shell sed )
+
+all: $(WorkFiles)
+
+.PHONY: $(WorkFiles)
+
+checksums.json : ALL_RSC := $(wildcard *.rsc */*.rsc)
+AM-GlobalFunc.rsc : COMMITID   := $(VERSION)
+AM-GlobalFunc.rsc : COMMITINFO := "$(DATE) - Commit owner: $(OWNER)"
+
+ifeq ($@,AM-GlobalFunc.rsc)
+define sed-cmd =
+       cd $(WORK_DIR) && \
+       sed \
+               -e "/^:global CommitId/c :global CommitId \"${COMMITID:-unknown}\";" \
+               -e "/^:global CommitInfo/c :global CommitInfo \"${COMMITINFO:-unknown}\";" \
+               < "./html/${1}"
+       endef
+endif
+
+ifeq ($@,checksums.json)
+       define get-sums =
+       cd $(WORK_DIR)/html && \
+       md5sum $(find -name '*.rsc' | sort) | \
+       sed -e "s| \./||" -e 's|.rsc$||' | \
+       jq --raw-input --null-input '[ inputs | split (" ") | { (.[1]): (.[0]) }] | add' > $@
+       endef
+endif
+
+$(WorkFiles):
+ifeq ($@,checksums.json)
+       $(get-sums) $(ALL_RSC); > $@
+endif
+
+checksums: checksums.json
+           cd $(WORK_DIR)/html
+
+checksums.json: $(WORK_DIR)/bin/checksums.sh $(ALL_RSC)
+       $(WORK_DIR)/bin/checksums.sh > $(WORK_DIR)/html/$@
+
+
+$(FuncFile): ./html/$@
+       $(sed-cmd) $< > $<~
+       mv $<~ $<
+
+#$(WORK_DIR)/html/AM-GlobalFunc.rsc
+#      cd $(WORK_DIR)/html && $(WORK_DIR)/bin/commitinfo.sh $< > $<~
+#      mv $<~ $<
+
+#commitinfo: push
+#      $(WORK_DIR)/bin/$@.sh
+#clean
+
+#checkout: git checkout HEAD .
+
+#push: 
+#      git $@ origin
+
+#ifeq (git,$(firstword $(MAKECMDGOALS)))
+#    # Remaining arguments form the commit string
+#    GIT_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
+#    # ...and turn them into do-nothing targets
+#    $(eval $(GIT_ARGS):;@:)
+#endif
+
+# git function to push to repo
+#git:
+#    git add . && git commit -m "$(GIT_ARGS)" && git push
+
+
+#clean:
+#      rm -f $(HTML) checksums.json
+#      make -C tmpl/ clean
diff --git a/.bak/ROSdiff.sh b/.bak/ROSdiff.sh
new file mode 100644 (file)
index 0000000..f1f4e7c
--- /dev/null
@@ -0,0 +1,153 @@
+#!/bin/bash
+#
+# https://dzen.ru/a/ZXWKq1L35Em2EHex?ysclid=mlt10qkrsb471483043
+#
+# Use: ./ROSdiff.sh RoutrName SSH_IP SSH_Port
+# Last Backups: ls -l $backuppath
+# History: ls -l $backuppath/history
+# Add to cron
+# crontab -e 
+# 0 20 * * * /var/www/ros.vados.ru/Mikrotiks/.bin/ROSdiff.sh MikroMaster 10.30.30.81 2222
+#
+
+routers=( 10.30.30.10 10.30.30.81 )
+
+date=$(date +%d-%m-%Y)
+time=$(date +%H-%M)
+
+GEN_DATE=$(date '+%Y-%m-%d %H:%M:%S %z')
+DTStamp=$(date '+%Y%m%d%H%M%S')
+
+SSHhost="undefined"
+SSHport="2222"
+SSHuser="mikro_bak"
+SSHpassword="Peskar55"
+
+BaseDir="/var/www/ros.vados.ru/Mikrotiks"
+#$HOME
+
+HostsFile="${BaseDir}/.mikrotiks"
+BackupDir="${BaseDir}/backups"
+BackTemp="${BackupDir}/tmp"
+
+Log="undefined"
+RouterName="undefined"
+
+SSH_KEY=$BaseDir"/.ssh/id_rsa"
+SSH_OPTS="-i $SSH_KEY -o PasswordAuthentication=no -p $SSHport"
+# Require router-specific SSH key
+if [ ! -f "$SSH_KEY" ]; then
+    echo "Error: SSH key not found at $SSH_KEY"
+    echo "Run ./setup-ssh-keys.sh to generate the key"
+    exit 1
+fi
+###############################
+# Backup listing 
+###############################
+# Get Names Addresses and Ports
+# for SSHhost in $( cat $HostsFile ); do
+#IFS=$'\n'       # make newlines the only separator
+readarray -t lines < $HostsFile
+set -f 
+for HR in "${lines[@]}"; do
+while IFS=$' ' read -a line || [ -n "$line" ]; do
+[[ -z ${line[0]} ]] && continue
+${BaseDir}/.bin/rdiff.sh ${line[0]} ${SSHuser} ${line[1]} ${line[2]}
+#echo ${line[0]}
+#echo ${SSHuser}
+#echo ${line[1]}
+#echo ${line[2]}
+#readarray -t lines < $HostsFile
+
+#while IFS=" " read -r "${lines[@]}" -a line ; do
+
+#for line in "${lines[@]}"; 
+#do
+#    echo "$line"
+done <<<"$(echo -e $HR)" 
+done
+exit 0
+
+#cat $HostsFile | while IFS=" " read -a line ; do
+# || [ -n "$line" ]; do
+#[[ -z ${line[0]} ]] && continue
+
+for SSHhost in ${routers[@]}; do
+RouterName=$(ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} /system/identity/get name | echo $1);
+# awk '{print $2}');
+sleep 2
+echo $RouterName
+#${BaseDir}/.bin/rdiff.sh ${RouterName} ${SSHuser} ${SSHhost} ${SSHport}
+# ${line[0]} ${line[1]} ${line[2]}
+
+done
+exit 0
+
+for SSHhost in ${routers[@]}; do
+
+RouterName=$(ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} system identity print | awk '{print $2}');
+
+RouterDir="${BackupDir}/${RouterName}"
+HistoryDir="${RouterDir}history"
+echo $HistoryDir
+RouterTemp="${BackTemp}/${RouterName}"
+Log="${RouterTemp}log.txt"
+echo $Log
+echo ${RouterName}
+
+precedent_export_name=${RouterName}"-config-export-precedent.rsc"
+pen=${RouterName}'-config-export-precedent.rsc'
+echo ${pen}
+
+current_export_name="$RouterName-config-export-current.rsc"
+current_backup_name="$routername-config-backup-current.backup"
+diff_export_name="$routername-config-export-diff.rsc"
+
+current_export_name_history="$routername-$(date +%Y-%m-%d-%H-%M)-config-export-current.rsc"
+current_backup_name_history="$routername-$(date +%Y-%m-%d-%H-%M)-config-backup-current.backup"
+diff_export_name_history="$routername-$(date +%Y-%m-%d-%H-%M)-config-export-diff.rsc"
+exit 0
+
+echo "Create tmp directory..."
+mkdir -p $routertmp
+echo "tmp directory created $routername $routertmp ($time)." >> $routerlog
+echo
+echo "Create backup directory..."
+mkdir -p $routerpath
+echo "Backups directory created $routername $routerpath ($time)." >> $routerlog
+echo
+echo "Create history directory..."
+mkdir -p $routerhistory
+echo "Backups directory created $routername $routerhistory ($time)." >> $routerlog
+echo
+
+cd $routerpath
+echo "SSH connect to $routername..." 
+echo "Create configuration $routername..."
+#ssh $SSH_OPTS $username"@"$i" /export file=export.rsc";
+sshpass -p $sshpassword ssh -o StrictHostKeyChecking=no $sshuser@$sshhost -p $sshport export >$current_export_name
+echo
+
+diff -I "RouterOS" $current_export_name $routerpath/$precedent_export_name > $diff_export_name
+
+if [ "$?" -ne "0" ]; then
+sshpass -p $sshpassword ssh -o StrictHostKeyChecking=no $sshuser@$sshhost -p $sshport export file=$current_export_name
+sshpass -p $sshpassword ssh -o StrictHostKeyChecking=no $sshuser@$sshhost -p $sshport system backup save name=$current_backup_name
+sshpass -p $sshpassword sftp -o StrictHostKeyChecking=no -oPort=$sshport $sshuser@$sshhost:$current_backup_name
+
+rm -f $precedent_export_name
+
+cp $current_export_name $backuppath"/history/"$current_export_name_history
+cp $current_backup_name $backuppath"/history/"$current_backup_name_history
+mv $diff_export_name $backuppath"/history/"$diff_export_name_history
+
+mv -f $current_export_name $precedent_export_name
+rm -f $diff_export_name
+#exit 1
+fi
+
+mv -f $current_export_name $precedent_export_name
+rm -f $diff_export_name
+
+#exit 0
+done
diff --git a/.bak/get_backups.sh b/.bak/get_backups.sh
new file mode 100644 (file)
index 0000000..8924bf4
--- /dev/null
@@ -0,0 +1,109 @@
+#!/bin/bash
+date=$(date +%d-%m-%Y)
+time=$(date +%H-%M)
+username="mikro_bak"
+mikrotik=$HOME"/.mikrotiks"
+backup_path=$HOME"/backups"
+tmp=$HOME"/tmp"
+log=$tmp"/log.txt"
+SSH_KEY="$HOME/.ssh/id_rsa"
+SSH_OPTS="-i $SSH_KEY -o PasswordAuthentication=no -p 2222"
+#-------------------------------#
+smb_path_backup="//192.168.1.2/Backups"
+domain="WORKGROUP"
+usrname="backuper"
+passwd="root.mikrots.backuper"
+# Require router-specific SSH key
+if [ ! -f "$SSH_KEY" ]; then
+    echo "Error: SSH key not found at $SSH_KEY"
+    echo "Run ./setup-ssh-keys.sh to generate the key"
+    exit 1
+fi
+################
+# Backup listing
+################
+# Get addresses
+for i in $( cat $mikrotik ); do
+mkdir -p $tmp"/"$i
+# Get Devices Names
+#ssh $SSH_OPTS "$ROUTER_USER@$ROUTER_IP"
+RESULT=$(ssh $SSH_OPTS $username"@"$i" /system/identity print" | awk ' {print $2} ');
+#RESULT=$(ssh $username"@"$i" -p 2222 system identity print" | awk ' {print $2} ');
+echo "Start backup Devices"
+echo "Start backup Devices Mikrotiks ($time) $RESULT" > $log
+echo "Create Backup $i..."
+ssh $SSH_OPTS $username"@"$i" /system/backup save name=binary.backup";
+#ssh $username"@"$i" -p 2222 system backup save name=binary.backup";
+if [ $? -eq 0 ]; then
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
+echo "Create Backup $i success ($time)" >> $log
+echo 
+else
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[ERROR]"
+echo "Createbackup $i failed ($time)" >> $log
+echo
+fi
+
+echo "Create configuration $i..."
+#ssh $SSH_OPTS $username"@"$i" /export file=export.rsc;"
+#ssh $username"@"$i" -p 2222 export file=export.rsc";
+ssh $SSH_OPTS $username"@"$i" export file=export.rsc; delay 3s;"
+if [ $? -eq 0 ]; then
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
+echo "Create configuration $i success ($time)" >> $log
+echo
+else
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[ERROR]"
+echo "Create configuration $i failed ($time)" >> $log
+echo
+fi
+echo "Create backups directory..."
+mkdir -p $tmp/$i/$date/
+echo "Backups directory created $i ($time)" >> $log
+echo
+echo "Download backup files $i..."
+sftp $SSH_OPTS "sftp://"$username"@"$i"/binary.backup" $tmp/$i/$date/$i"-"$time".backup";
+scp $SSH_OPTS "$username@$i:export.rsc" $tmp/$i/$date/$i"-"$time".rsc";
+#sftp "ssh://"$username"@"$i":2222/binary.backup" $tmp/$i/$date/$i"-"$time".backup";
+#sftp "ssh://"$username"@"$i":2222/export.rsc" $tmp/$i/$date/$i"-"$time".rsc";
+if [ $? -eq 0 ]; then
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
+echo "Download backups $i success ($time)" >> $log
+echo
+else
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[ERROR]"
+echo "Download backups $i failed ($time)" >> $log
+echo
+fi
+
+echo "Compress backups..."
+cd $tmp/$i/
+RESULT=$(tar -czvf $date".tar.gz" $date)
+echo "Backups compressed ($time)" >> $log
+
+#echo "Connect to network share $smb_path_backup..."
+#RESULT=$(cat /home/Mikrotiks/sudos | sudo -S -u root mount -t cifs $smb_path_backup /mnt/samba -o username=$usrname,password=$passwd,domain=$domain)
+#echo "Networkshare $smb_path_backup connected ($time)" >> $log
+
+echo "Create directory for backups device $i..."
+#RESULT=$(cat /home/Mikrotiks/sudos | sudo -S -u root mkdir -p /mnt/samba/Mikrotik/$i)
+RESULT=$(mkdir -p $backup_path"/"$i)
+echo "Directory for backup device $i created in network share ($time)" >> $log
+
+echo "Place backups in network share"
+#RESULT=$(cat /home/Mikrotiks/sudos | sudo -S -u root mv $tmp/$i/$date".tar.gz" "/mnt/samba/Mikrotik/$i/$date.tar.gz")
+RESULT=$(mv $tmp/$i/$date".tar.gz" $backup_path"/"$i"/"$date".tar.gz")
+echo "Backups $i moved to $backup_path"/"$i ($time)" >> $log
+echo "" >> $log
+
+#RESULT=$(cat /home/Mikrotiks/sudos | sudo -S -u root mv $log "/mnt/samba/MIkrotik/$i/$date.log.txt")
+RESULT=$(mv $log $backup_path"/"$i/$date".log.txt")
+
+echo "Remove local backup files device $i"
+ssh $SSH_OPTS "$username@$i /file remove binary.backup";
+ssh $SSH_OPTS "$username@$i /file remove export.rsc";
+#rm -r -f $tmp
+
+#cat /home/Mikrotiks/sudos | sudo -S -u root umount $smb_path_backup
+#cat /home/Mikrotiks/sudos | sudo -S -u root umount $smb_path_backup
+done
diff --git a/.bak/test.sh b/.bak/test.sh
new file mode 100644 (file)
index 0000000..d42de8f
--- /dev/null
@@ -0,0 +1,127 @@
+#!/bin/bash
+
+while IFS=" " read -a line -r || [ -n "$line" ]; do
+
+
+
+date=$(date +%d-%m-%Y)
+time=$(date +%H-%M)
+
+sshuser="mikro_bak"
+sshpassword="Peskar55"
+
+homepath="/var/www/ros.vados.ru/Mikrotiks"
+
+mikrotik_file=$homepath"/.mikrotiks"
+backuppath=$homepath"/backups"
+tmp="."
+log=$tmp"/log.txt"
+
+SSH_KEY=$homepath"/.ssh/id_rsa"
+# Require router-specific SSH key
+if [ ! -f "$SSH_KEY" ]; then
+    echo "Error: SSH key not found at $SSH_KEY"
+    echo "Run ./setup-ssh-keys.sh to generate the key"
+    exit 1
+fi
+#export IFS=" "
+SSH_OPTS="-i "$SSH_KEY" -o PasswordAuthentication=no -p 2222"
+
+RESULT=$(ssh $SSH_OPTS $sshuser@10.30.30.10 system identity print | awk ' {print $2} ');
+echo 
+echo $RESULT
+echo
+exit 0
+#RESULT=(ssh $SSH_OPTS $sshuser"@10.30.30.10" /system/identity print") >> ./ident.txt
+# | awk ' {print $2} ' >> ./ident.txt
+
+#readarray -t lines < "$mikrotik_file"
+cat $mikrotik_file | while read -r lines ; do
+for line in "${lines}" ; do
+echo
+#echo $line[$1]
+#echo $line[$2]
+echo $1
+echo
+done
+done
+exit 0
+
+#for i in $( cat $mikrotik_file ) ; do 
+#cat $mikrotik_file | while read -r line ; do
+#-a HR ; do
+#  [[ -z $0 ]] && continue  # skip empty lines
+set -- $line
+echo
+echo "line = "$line
+echo
+#  [[ -z ${line[0]} ]] && continue  # skip empty lines
+echo $@
+echo
+routername=$1
+#${HR[0]}
+sshhost=$2
+#${HR[1]}
+sshport=$3
+#${HR[2]}
+
+SSH_OPTS="-i "$SSH_KEY" -o PasswordAuthentication=no -p "$sshport" "$sshuser"@"$sshhost 
+
+current_export_name=$routername"-config-export-current.rsc"
+
+echo
+echo $routername
+echo
+echo $current_export_name
+echo
+
+
+#echo "Get current export file ($time) "$RESULT
+# >> $log
+#sshpass -p $sshpassword ssh -o StrictHostKeyChecking=no $sshuser@$sshhost -p $sshport export >$current_export_name
+ssh $SSH_OPTS " export file="$current_export_name"; delay 3s;" && continue
+if [ $? -eq 0 ]; then
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[OK]"
+echo "Create configuration $routername success ($time)"
+# >> $log
+echo
+else
+echo -n "$(tput hpa $(tput cols))$(tput cub 6)[ERROR]"
+echo "Create configuration $i failed ($time)"
+# >> $log
+echo
+fi
+
+done
+#done
+#exit 0
+# cat $mikrotik_file | while read -a HR ; do
+#  [[ -z ${HR[0]} ]] && continue  # skip empty lines
+#while IFS=" " read -a line -r || [ -n "$line" ]; do 
+#echo $line
+#echo ${line[0]}
+#echo ${line[1]}
+#echo ${line[2]}
+#echo ${line[3]}
+#RouterName=${line[0]}
+#SSHhost=${line[1]}
+#SSHport=${line[2]}
+
+#SSH_OPTS="-i $SSH_KEY -o PasswordAuthentication=no -p $SSHport"
+#current_export_name="$RouterName-config-export-current.rsc"
+#ssh $SSH_OPTS $SSHuser@$SSHhost export >$current_export_name
+# 2>&1
+# "; delay 3s;" && continue
+# sshpass -p $SSHpassword ssh -o StrictHostKeyChecking=no $SSHuser@$SSHhost -p $SSHport export >$current_export_name
+
+# Escape backslashes, dollar signs, and quotes
+#  line=$(echo "$line" | sed 's/\\/\\\\/g' | sed 's/\$/\\$/g' | sed 's/"/\\"/g')
+#  if [ -z "$SCRIPT_CONTENT" ]; then
+#    SCRIPT_CONTENT="$line"
+#  else
+#    SCRIPT_CONTENT="$SCRIPT_CONTENT\\n$line"
+#  fi
+#continue
+#done < "$HostsFile"
+exit 0
+
diff --git a/.bak/tmp/Makefile b/.bak/tmp/Makefile
new file mode 100644 (file)
index 0000000..f9aa32a
--- /dev/null
@@ -0,0 +1,149 @@
+# Makefile
+
+BUILD_DIR       = $(shell pwd)
+
+BIN_DIR         = bin
+commitinfo.sh   := $(wildcard bin/commitinfo.sh)
+
+HTML_DIR        = html
+ALL_RSC         := $(wildcard html/*.rsc html/*/*.rsc)
+GLOB_RSC        := $(wildcard html/AM-GlobalFunc.rsc)
+
+DATE            ?= $(shell (date '+%T %d.%m.%Y'))
+DTSTAMP_FMT            ?= "+%Y%m%d%H%M"
+DTSTAMP         ?= $(shell (date $(DTSTAMP_FMT)))
+VERSION         ?= $(shell git symbolic-ref --short HEAD 2>/dev/null)/$(shell git rev-list --count HEAD 2>/dev/null)/$(shell git rev-parse --short=8 HEAD 2>/dev/null)
+RUN_OWNER       := $(shell whoami 2>/dev/null)
+COMM_REPO              := $(shell git rev-parse --show-toplevel | rev | cut -d/ -f1 | rev 2>/dev/nul)
+COMM_BRANCH            := $(shell git symbolic-ref --short HEAD 2>/dev/null)
+
+COMM_TAG := $(shell git rev-list --abbrev-commit --tags --max-count=1)
+# `2>/dev/null` suppress errors and `|| true` suppress the error codes.
+TAG := $(shell git describe --abbrev=0 --tags ${COMM_TAG} 2>/dev/null || true)
+# here we strip the version prefix
+TAG_VERS :=$(TAG:v%=%)
+# get the latest commit hash in the short form
+COMM_HASH := $(shell git rev-parse --short=8 HEAD 2>/dev/null) # Get short commit hash
+#COMMIT := $(shell git rev-parse --short HEAD)
+# get the latest commit date in the form of YYYYmmddHHMM ($(DTSTAMP_FMT))
+COMM_DATE := $(shell git log -1 --format=%cd --date=format:$(DTSTAMP_FMT))
+ifneq ($(COMM_HASH), $(COMM_TAG))
+    TAG_VERS :=$(TAG_VERS)-next-$(COMM_HASH)-$(COMM_DATE)
+endif
+ifeq ($(TAG_VERS), )
+    TAG_VERS :=$(COMM_HASH)-$(COMM_DATE)
+endif
+ifneq ($(shell git status --porcelain), )
+    TAG_VERS :=$(TAG_VERS)-dirty
+endif
+
+COMMIT_ID       := $(VERSION)
+COMM_INFO       := $(shell echo -e "Autocommit in repo: $(COMM_REPO), generated by owner: $(RUN_OWNER), in $(DATE)." 2>/dev/null)
+
+export BUILD_DIR BIN_DIR HTML_DIR DATE DTSTAMP VERSION COMMIT_ID COMM_TAG COMM_HASH COMM_INFO
+
+SHELL := /bin/bash
+
+export BUILD_DIR BIN_DIR HTML_DIR DATE DTSTAMP VERSION COMMIT_ID COMM_TAG COMM_HASH COMM_INFO COMM_DATE
+
+.ONESHELL:
+
+.DEFAULT_GOAL := run
+
+export BUILD_DIR BIN_DIR HTML_DIR DATE DTSTAMP VERSION COMMIT_ID COMM_TAG COMM_HASH COMM_INFO
+
+include $(BUILD_DIR)/.config/config.mk
+
+.PHONY: run check notify checksums commitinfo test
+
+run: check
+       @echo "[run] start main flow"
+       checksums
+       commitinfo
+       @echo "[run] done"
+
+check:
+       @bash bin/check_repo.sh
+
+notify:
+       @bash bin/notify_telegram.sh "manual notify from make"
+
+checksums: checksums.json
+
+checksums.json: bin/checksums.sh $(ALL_RSC)
+       bin/checksums.sh > html/tmp/$@
+
+test:
+       @bash -n bin/check_repo.sh
+       @bash -n bin/notify_telegram.sh
+       @bash -n bin/checksums.sh
+       @bash -n bin/commitinfo.sh
+       @echo "syntax ok"
+
+
+.DEFAULT_GOAL := all
+#.PHONY: all checksums git-check commitinfo clean
+#all: checksums git-check commitinfo
+
+
+gitcheck: $(BUILD_DIR)
+       cd $ && 
+       @if git diff --quiet && git diff --cached --quiet && [ -z "$$(git ls-files --others --exclude-standard)" ]; then \
+               echo "The first checks have been passed, the repo seems to be clean... But... Still, let's check a little more!"; \
+           git add . && \
+               if [[ -n "$$(git status --porcelain)" ]]; then \
+                       echo "Uncommitted changes detected! Commit it..."; \
+#                      git commit -m "$(COMM_INFO)"; \
+#                      git push; \
+           exit 1; \
+               else \
+                       echo "repo clean"; \
+               fi \
+       else \
+               @echo "Warning: Uncommitted changes detected! Go to autocommit steps..."; \
+               git branch -v; \
+#              git commit -am "$(COMM_INFO)"; \
+#              git push; \
+       fi
+
+
+#@if [ -n "$$(git diff --quiet)" ] && [ -n "$$(git diff --cached --quiet)" ] && [ -n "$$(git ls-files --others --exclude-standard)" ]; then \
+#[ -n "$$(git status --porcelain)" ]
+
+check-uncommitted: 
+               @if [ -n "$$(git diff --quiet)" ] && [ -n "$$(git diff --cached --quiet)" ] && [ -n "$$(git ls-files --others --exclude-standard)" ]; then \
+                       echo "Warning: Uncommitted changes detected! Go to autocommit steps..."; \
+               else \
+               echo "The first checks have been passed, the repo seems to be clean... But... Still, let's check a little more!"; \
+                       if git status --porcelain; then \
+                               echo "Repository is clean (no uncommitted or untracked changes). Exit 0."; \
+                               exit 0; \
+                       else \
+                               echo "Error! Git status is not porcelain! Check it mannualy. Exit 1."; \
+                               exit 1; \
+                       fi \
+               fi
+
+
+#    if [[ -n "`$(rungit) status --porcelain`" ]];: then \
+       echo "Warning: Uncommitted changes detected! Go to autocmmit..."; \
+        git commit -m "$(COMM_INFO)"; \
+       git push origin $(COMM_BANCH); \
+    else \
+       echo "Repository is clean (no uncommitted or untracked changes). Exit 0."; \
+       exit 0; \
+    fi
+
+commitinfo: $(commitinfo.sh)
+
+.PHONY: $(commitinfo.sh)
+$(commitinfo.sh): $(GLOB_RSC)
+               $(commitinfo.sh) $< > $<~
+               mv $<~ $<
+
+
+clean:
+               git checkout HEAD -- .
+
+#      rm -f $(HTML) checksums.json
+#      make -C contrib/ clean
diff --git a/.bashrc b/.bashrc
new file mode 100644 (file)
index 0000000..701dfd0
--- /dev/null
+++ b/.bashrc
@@ -0,0 +1,127 @@
+# ~/.bashrc: executed by bash(1) for non-login shells.
+# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
+# for examples
+
+# If not running interactively, don't do anything
+case $- in
+    *i*) ;;
+      *) return;;
+esac
+
+# don't put duplicate lines or lines starting with space in the history.
+# See bash(1) for more options
+HISTCONTROL=ignoreboth
+
+# append to the history file, don't overwrite it
+shopt -s histappend
+
+# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
+HISTSIZE=1000
+HISTFILESIZE=2000
+
+# check the window size after each command and, if necessary,
+# update the values of LINES and COLUMNS.
+shopt -s checkwinsize
+
+# If set, the pattern "**" used in a pathname expansion context will
+# match all files and zero or more directories and subdirectories.
+#shopt -s globstar
+
+# make less more friendly for non-text input files, see lesspipe(1)
+[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
+
+# set variable identifying the chroot you work in (used in the prompt below)
+if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
+    debian_chroot=$(cat /etc/debian_chroot)
+fi
+
+# set a fancy prompt (non-color, unless we know we "want" color)
+case "$TERM" in
+    xterm-color|*-256color) color_prompt=yes;;
+esac
+
+# uncomment for a colored prompt, if the terminal has the capability; turned
+# off by default to not distract the user: the focus in a terminal window
+# should be on the output of commands, not on the prompt
+#force_color_prompt=yes
+
+if [ -n "$force_color_prompt" ]; then
+    if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
+       # We have color support; assume it's compliant with Ecma-48
+       # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
+       # a case would tend to support setf rather than setaf.)
+       color_prompt=yes
+    else
+       color_prompt=
+    fi
+fi
+
+if [ "$color_prompt" = yes ]; then
+    PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
+else
+    PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
+fi
+unset color_prompt force_color_prompt
+
+# If this is an xterm set the title to user@host:dir
+case "$TERM" in
+xterm*|rxvt*)
+    PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
+    ;;
+*)
+    ;;
+esac
+
+# enable color support of ls and also add handy aliases
+if [ -x /usr/bin/dircolors ]; then
+    test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
+    alias ls='ls --color=auto'
+    #alias dir='dir --color=auto'
+    #alias vdir='vdir --color=auto'
+
+    alias grep='grep --color=auto'
+    alias fgrep='fgrep --color=auto'
+    alias egrep='egrep --color=auto'
+fi
+
+# colored GCC warnings and errors
+#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
+
+# some more ls aliases
+alias ll='ls -alF'
+alias la='ls -A'
+alias l='ls -CF'
+
+# Add an "alert" alias for long running commands.  Use like so:
+#   sleep 10; alert
+alias alert='n8otify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
+
+# Alias definitions.
+# You may want to put all your additions into a separate file like
+# ~/.bash_aliases, instead of adding them here directly.
+# See /usr/share/doc/bash-doc/examples in the bash-doc package.
+
+if [ -f ~/.bash_aliases ]; then
+    . ~/.bash_aliases
+fi
+
+# enable programmable completion features (you don't need to enable
+# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
+# sources /etc/bash.bashrc).
+if ! shopt -oq posix; then
+  if [ -f /usr/share/bash-completion/bash_completion ]; then
+    . /usr/share/bash-completion/bash_completion
+  elif [ -f /etc/bash_completion ]; then
+    . /etc/bash_completion
+  fi
+fi
+
+# Terminal Prompt full paths
+export PROMPT_DIRTRIM=5
+export force_color_prompt=yes
+export GIT_SSH=$(which ssh)
+#'"c:\WINDOWS\System32\OpenSSH\ssh.exe" -T'
+eval $(ssh-agent)
+ssh-add
+GPG_TTY=`tty`
+export GPG_TTY
diff --git a/.config/.mikrotiks b/.config/.mikrotiks
new file mode 100644 (file)
index 0000000..53a2c1b
--- /dev/null
@@ -0,0 +1,3 @@
+MikroNUC 10.30.30.10 2222 mikro_bak Peskar55
+MikroMaster 10.30.30.81 2222 mikro_bak Peskar55
+MikroYellow 10.30.30.86 2222 mikro_bak Peskar55
diff --git a/.config/mc/hotlist b/.config/mc/hotlist
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/.config/mc/ini b/.config/mc/ini
new file mode 100644 (file)
index 0000000..3152b04
--- /dev/null
@@ -0,0 +1,165 @@
+[Midnight-Commander]
+verbose=true
+shell_patterns=true
+auto_save_setup=true
+preallocate_space=false
+auto_menu=false
+use_internal_view=true
+use_internal_edit=true
+clear_before_exec=true
+confirm_delete=true
+confirm_overwrite=true
+confirm_execute=false
+confirm_history_cleanup=true
+confirm_exit=false
+confirm_directory_hotlist_delete=false
+confirm_view_dir=false
+safe_delete=false
+safe_overwrite=false
+use_8th_bit_as_meta=false
+mouse_move_pages_viewer=true
+mouse_close_dialog=false
+fast_refresh=false
+drop_menus=true
+wrap_mode=true
+old_esc_mode=true
+cd_symlinks=true
+show_all_if_ambiguous=false
+use_file_to_guess_type=true
+alternate_plus_minus=false
+only_leading_plus_minus=true
+show_output_starts_shell=false
+xtree_mode=false
+file_op_compute_totals=true
+classic_progressbar=true
+use_netrc=true
+ftpfs_always_use_proxy=false
+ftpfs_use_passive_connections=true
+ftpfs_use_passive_connections_over_proxy=false
+ftpfs_use_unix_list_options=true
+ftpfs_first_cd_then_ls=true
+ignore_ftp_chattr_errors=true
+editor_fill_tabs_with_spaces=false
+editor_return_does_auto_indent=false
+editor_backspace_through_tabs=false
+editor_fake_half_tabs=true
+editor_option_save_position=true
+editor_option_auto_para_formatting=false
+editor_option_typewriter_wrap=false
+editor_edit_confirm_save=true
+editor_syntax_highlighting=true
+editor_persistent_selections=true
+editor_drop_selection_on_copy=true
+editor_cursor_beyond_eol=false
+editor_cursor_after_inserted_block=false
+editor_visible_tabs=true
+editor_visible_spaces=true
+editor_line_state=false
+editor_simple_statusbar=false
+editor_check_new_line=false
+editor_show_right_margin=false
+editor_group_undo=true
+editor_state_full_filename=true
+editor_ask_filename_before_edit=false
+nice_rotating_dash=true
+mcview_remember_file_position=false
+auto_fill_mkdir_name=true
+copymove_persistent_attr=true
+pause_after_run=2
+mouse_repeat_rate=100
+double_click_speed=250
+old_esc_mode_timeout=1000000
+max_dirt_limit=10
+num_history_items_recorded=60
+vfs_timeout=60
+ftpfs_directory_timeout=900
+ftpfs_retry_seconds=30
+fish_directory_timeout=900
+editor_tab_spacing=8
+editor_word_wrap_line_length=72
+editor_option_save_mode=0
+editor_backup_extension=~
+editor_filesize_threshold=64M
+editor_stop_format_chars=-+*\\,.;:&>
+mcview_eof=
+skin=default
+
+filepos_max_saved_entries=1024
+shadows=true
+shell_directory_timeout=900
+
+[Layout]
+output_lines=0
+left_panel_size=118
+top_panel_size=0
+message_visible=false
+keybar_visible=false
+xterm_title=true
+command_prompt=true
+menubar_visible=false
+free_space=true
+horizontal_split=false
+vertical_equal=true
+horizontal_equal=true
+
+[Misc]
+timeformat_recent=%b %e %H:%M
+timeformat_old=%b %e  %Y
+ftp_proxy_host=gate
+ftpfs_password=anonymous@
+display_codepage=ASCII
+source_codepage=ASCII
+autodetect_codeset=
+spell_language=en
+clipboard_store=
+clipboard_paste=
+
+[Colors]
+base_color=
+xterm-256color=
+color_terminals=
+linux=
+xterm=
+
+[Panels]
+simple_swap=false
+show_mini_info=true
+kilobyte_si=false
+mix_all_files=false
+show_backups=true
+show_dot_files=true
+fast_reload=false
+fast_reload_msg_shown=false
+mark_moves_down=true
+reverse_files_only=true
+auto_save_setup_panels=false
+navigate_with_arrows=true
+panel_scroll_pages=true
+panel_scroll_center=false
+mouse_move_pages=true
+filetype_mode=true
+permission_mode=false
+torben_fj_mode=false
+quick_search_mode=2
+select_flags=6
+
+[FindFile]
+file_case_sens=true
+file_shell_pattern=true
+file_find_recurs=true
+follow_symlinks=true
+file_skip_hidden=false
+file_all_charsets=false
+content_case_sens=true
+content_regexp=false
+content_first_hit=false
+content_whole_words=false
+content_all_charsets=false
+ignore_dirs_enable=true
+ignore_dirs=
+
+[Panelize]
+Find *.orig after patching=find . -name \\*.orig -print
+Find rejects after patching=find . -name \\*.rej -print
+Modified git files=git ls-files --modified
+Find SUID and SGID programs=find . \\( \\( -perm -04000 -a -perm /011 \\) -o \\( -perm -02000 -a -perm /01 \\) \\) -print
diff --git a/.config/mc/panels.ini b/.config/mc/panels.ini
new file mode 100644 (file)
index 0000000..92992b2
--- /dev/null
@@ -0,0 +1,35 @@
+[New Left Panel]
+display=listing
+reverse=false
+case_sensitive=true
+exec_first=false
+sort_order=name
+list_mode=full
+brief_cols=2
+user_format=half type name | size | perm
+user_status0=half type name | size | perm
+user_status1=half type name | size | perm
+user_status2=half type name | size | perm
+user_status3=half type name | size | perm
+user_mini_status=false
+list_format=full
+
+[New Right Panel]
+display=listing
+reverse=false
+case_sensitive=true
+exec_first=false
+sort_order=name
+list_mode=full
+brief_cols=2
+user_format=half type name | size | perm
+user_status0=half type name | size | perm
+user_status1=half type name | size | perm
+user_status2=half type name | size | perm
+user_status3=half type name | size | perm
+user_mini_status=false
+list_format=full
+
+[Dirs]
+current_is_left=true
+other_dir=/mnt/d/dst/D41/vbmeta-tools
diff --git a/.gitconfig b/.gitconfig
new file mode 100644 (file)
index 0000000..1d9bed2
--- /dev/null
@@ -0,0 +1,25 @@
+[user]
+       name = vados-dev
+       email = vados@vados.ru
+       signingkey = 1FD2694762FCE438
+[color]
+       ui = auto
+[safe]
+       directory = /home/vados/sl8541e_cus_go
+       directory = /var/www/ros.vados.ru
+       directory = /var/www/ros.vados.ru/html
+       directory = /var/www/ros.vados.ru/Mikrotiks
+       directory = /var/www/ros.vados.ru/Mikrotiks/backups
+       directory = /.data/nfs/repos/Mikrotiks
+       directory = /.data/nfs/repos/Mikrotiks/Mikrotiks.git
+       directory = /.data/nfs/repos/Mikrotiks/ros.vados.ru.git
+[init]
+       defaultBranch = main
+[core]
+       autocrlf = false
+[protocol]
+       version = 2
+[commit]
+       gpgsign = true
+[gpg]
+       program = gpg2
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..d4e18e1
--- /dev/null
@@ -0,0 +1,26 @@
+# folder for backups repo
+backups/
+backups/**
+bin/logs/
+.gnupg/
+.local/
+.cache/
+oxidized/
+upload/
+test/
+.cache/
+.docker/
+.gnupg/
+.local/
+.ssh/
+.vscode/
+**/Precedent-Config.rsc
+
+.bash_history
+#.bak
+# backup and temporary files
+*~
+# patches and related files
+*.orig
+*.patch
+*.rej
diff --git a/.lesshst b/.lesshst
new file mode 100644 (file)
index 0000000..4d1c30b
--- /dev/null
+++ b/.lesshst
@@ -0,0 +1 @@
+.less-history-file:
diff --git a/.profile b/.profile
new file mode 100644 (file)
index 0000000..52115e0
--- /dev/null
+++ b/.profile
@@ -0,0 +1,31 @@
+# ~/.profile: executed by the command interpreter for login shells.
+# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
+# exists.
+# see /usr/share/doc/bash/examples/startup-files for examples.
+# the files are located in the bash-doc package.
+
+# the default umask is set in /etc/profile; for setting the umask
+# for ssh logins, install and configure the libpam-umask package.
+#umask 022
+
+# if running bash
+if [ -n "$BASH_VERSION" ]; then
+    # include .bashrc if it exists
+    if [ -f "$HOME/.bashrc" ]; then
+       . "$HOME/.bashrc"
+    fi
+fi
+
+# set PATH so it includes user's private bin if it exists
+if [ -d "$HOME/bin" ] ; then
+    PATH="$HOME/bin:$PATH"
+fi
+
+if [ -d "$HOME/.bin" ] ; then
+    PATH="$HOME/.bin:$PATH"
+fi
+
+# set PATH so it includes user's private bin if it exists
+if [ -d "$HOME/.local/bin" ] ; then
+    PATH="$HOME/.local/bin:$PATH"
+fi
diff --git a/.repo_.gitconfig.json b/.repo_.gitconfig.json
new file mode 100644 (file)
index 0000000..8631e7a
--- /dev/null
@@ -0,0 +1,20 @@
+{
+  "user.name": [
+    "vados-dev"
+  ],
+  "user.email": [
+    "vados@vados.ru"
+  ],
+  "color.ui": [
+    "auto"
+  ],
+  "safe.directory": [
+    "/var/www/ros.vados.ru/Mikrotiks"
+  ],
+  "init.defaultbranch": [
+    "main"
+  ],
+  "core.autocrlf": [
+    "false"
+  ]
+}
\ No newline at end of file
diff --git a/.selected_editor b/.selected_editor
new file mode 100644 (file)
index 0000000..dbc0072
--- /dev/null
@@ -0,0 +1,2 @@
+# Generated by /usr/bin/select-editor
+SELECTED_EDITOR="/usr/bin/mcedit"
diff --git a/.wget-hsts b/.wget-hsts
new file mode 100644 (file)
index 0000000..33cdbf5
--- /dev/null
@@ -0,0 +1,5 @@
+# HSTS 1.0 Known Hosts database for GNU Wget.
+# Edit at your own risk.
+# <hostname>   <port>  <incl. subdomains>      <created>       <max-age>
+github.com     0       1       1771536570      31536000
+codeload.github.com    0       0       1771536571      31536000
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..49bd3bb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,110 @@
+# Makefile
+
+BUILD_DIR       = $(shell pwd)
+REPO_DIR        ?= $(BUILD_DIR)
+
+ALL_RSC         := $(wildcard html/*.rsc html/*/*.rsc)
+commitinfo.sh   := $(wildcard bin/commitinfo.sh)
+GLOB_RSC        := $(wildcard html/AM-GlobalFunc.rsc)
+
+SHELL := /bin/bash
+
+include ../.config/config.mk
+
+COMM_TAG := $(shell git rev-list --abbrev-commit --tags --max-count=1)
+# `2>/dev/null` suppress errors and `|| true` suppress the error codes.
+TAG := $(shell git describe --abbrev=0 --tags ${COMM_TAG} 2>/dev/null || true)
+# here we strip the version prefix
+TAG_VERS :=$(TAG:v%=%)
+# get the latest commit hash in the short form
+COMM_HASH := $(shell git rev-parse --short=8 HEAD 2>/dev/null) # Get short commit hash
+#COMMIT := $(shell git rev-parse --short HEAD)
+# get the latest commit date in the form of YYYYmmddHHMM ($(DTSTAMP_FMT))
+COMM_DATE := $(shell git log -1 --format=%cd --date=format:$(DTSTAMP_FMT))
+ifneq ($(COMM_HASH), $(COMM_TAG))
+    TAG_VERS :=$(TAG_VERS)-next-$(COMM_HASH)-$(COMM_DATE)
+endif
+ifeq ($(TAG_VERS), )
+    TAG_VERS :=$(COMM_HASH)-$(COMM_DATE)
+endif
+ifneq ($(shell git status --porcelain), )
+    TAG_VERS :=$(TAG_VERS)-dirty
+endif
+
+.ONESHELL:
+
+export BUILD_DIR REPO_DIR ALL_RSC GLOB_RSC
+
+.DEFAULT_GOAL := all
+
+.PHONY: all check commit notify test
+
+all:
+       @$(MAKE) check; rc=$$?; \
+       if [ $$rc -eq 0 ]; then \
+               echo "[add] check $$rc, go to commit..."; \
+               $(MAKE) commit; cm=$$?; \
+               if [ $$cm -eq 0 ]; then \
+                       echo "[all] commit exit $$cm. Exit Ok."; \
+               else \
+                       $(MAKE) notify MSG="[all] commit exit $$cm. Check it!"; \
+               fi \
+       else \
+               echo "[all] check exit $$rc, repo is clean exit Ok."; \
+       fi
+       @echo "[all] done"
+
+run:
+       @$(MAKE) check; rc=$$?; \
+       if [ $$rc -eq 0 ]; then \
+               echo "[run] check $$rc, go to commitinfo.sh..."; \
+               $(MAKE) $(commitinfo.sh); ci=$$?; \
+               if [ $$ci -eq 0 ]; then \
+                       echo "[run] commitinfo.sh exit $$ci. Go to checksums.sh..."; \
+                       $(MAKE) checksums; cs=$$?; \
+                       if [ $$cs -eq 0 ]; then \
+                               echo "[run] checksums.sh exit $$cs. Do git add commit and push..."; \
+                               git add .; \
+                               git commit -m '$(COMM_INFO)'; \
+                               git push; \
+                       else \
+                               $(MAKE) notify MSG="[run] checksums.sh exit $$cs, check it!"; \
+                       fi \
+                       else \
+                               $(MAKE) notify MSG="[run] commitinfo.sh exit $$ci, check it!"; \
+                       fi \
+       else \
+               echo "[run] check exit $$rc, repo is clean exit Ok."; \
+       fi
+       @echo "[run] done"
+
+check:
+       @bash bin/check_repo.sh
+
+commit:
+       cd $(BUILD_DIR)
+       git add .
+       git commit -m '$(COMM_INFO)'
+       git push
+
+notify:
+       @bash bin/notify_telegram.sh "$(MSG)"
+
+checksums: checksums.json
+
+checksums.json: bin/checksums.sh $(ALL_RSC)
+       bin/checksums.sh > html/tmp/$@
+
+$(commitinfo.sh): $(GLOB_RSC)
+       $(commitinfo.sh) $< > $<~
+       mv $<~ $<
+
+test:
+       @bash -n bin/check_repo.sh
+       @bash -n bin/notify_telegram.sh
+       @bash -n bin/checksums.sh
+       @bash -n bin/commitinfo.sh
+       @echo "syntax ok"
+
+#clean:
+#              git checkout HEAD -- .
diff --git a/bin/bash-progress-indicator/LICENSE b/bin/bash-progress-indicator/LICENSE
new file mode 100644 (file)
index 0000000..830c241
--- /dev/null
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2018 Leandro Nunes
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/bin/bash-progress-indicator/README.md b/bin/bash-progress-indicator/README.md
new file mode 100644 (file)
index 0000000..8bbeb1a
--- /dev/null
@@ -0,0 +1,28 @@
+# bash-progress-indicator
+Pure Bash script progress indicators
+
+## Usage
+```
+chmod +x main.sh
+./main.sh {progress_indicator_type}
+```
+
+## progress_indicator_type
+#### progress
+![type_progress](https://user-images.githubusercontent.com/2450417/37887129-6a7fafec-3096-11e8-8bc0-7768e958119e.gif)
+
+#### progress_advanced
+![type_progress_advanced](https://user-images.githubusercontent.com/2450417/37887130-6ddce736-3096-11e8-9696-25b86becbce3.gif)
+
+#### spinner1
+![type_spinner1](https://user-images.githubusercontent.com/2450417/37887236-0e8ccf0c-3097-11e8-9c6d-c6f4fc60b712.gif)
+#### spinner2
+![type_spinner2](https://user-images.githubusercontent.com/2450417/37887241-12e1c814-3097-11e8-91b2-e43e96ff8cd0.gif)
+#### spinner3
+![type_spinner3](https://user-images.githubusercontent.com/2450417/37887242-13012e98-3097-11e8-80cb-ebca61da3109.gif)
+
+## I wrote an article about this technique [pt-br]
+[Medium - [Bash] Construindo indicador de progresso](https://medium.com/meninunes/bash-construindo-indicador-de-progresso-8de94c37683)
+
+## License
+[MIT License](LICENSE) © [Leandro Nunes](https://lnfnunes.com.br)
diff --git a/bin/bash-progress-indicator/main.sh b/bin/bash-progress-indicator/main.sh
new file mode 100644 (file)
index 0000000..cf565e7
--- /dev/null
@@ -0,0 +1,30 @@
+#!/bin/bash -e
+# shellcheck disable=SC1091
+
+declare -rx STEPS=(
+  'pre-install'
+  'install'
+  'post-install'
+)
+declare -rx CMDS=(
+  'sleep 10'
+  'sleep 10'
+  'sleep 10'
+)
+
+case $1 in
+  progress)
+    . 'progress.sh'
+    ;;
+  progress_advanced)
+    . 'progress_advanced.sh'
+    ;;
+  spinner*)
+    . 'spinner.sh'
+    ;;
+  *)
+    echo "Invalid option $1!"
+    exit 1
+esac
+
+start
diff --git a/bin/bash-progress-indicator/progress.sh b/bin/bash-progress-indicator/progress.sh
new file mode 100644 (file)
index 0000000..b5ca26e
--- /dev/null
@@ -0,0 +1,23 @@
+#!/bin/bash -e
+
+declare -rx BAR_SIZE="##########"
+declare -rx CLEAR_LINE="\\033[K"
+
+start() {
+  local MAX_STEPS=${#STEPS[@]}
+  local MAX_BAR_SIZE="${#BAR_SIZE}"
+
+  tput civis -- invisible
+
+  echo -ne "\\r[${BAR_SIZE:0:0}] 0 %$CLEAR_LINE"
+  for step in "${!STEPS[@]}"; do
+    ${CMDS[$step]}
+
+    perc=$(((step + 1) * 100 / MAX_STEPS))
+    percBar=$((perc * MAX_BAR_SIZE / 100))
+    echo -ne "\\r[${BAR_SIZE:0:percBar}] $perc %$CLEAR_LINE"
+  done
+  echo ""
+
+  tput cnorm -- normal
+}
diff --git a/bin/bash-progress-indicator/progress_advanced.sh b/bin/bash-progress-indicator/progress_advanced.sh
new file mode 100644 (file)
index 0000000..ad4f151
--- /dev/null
@@ -0,0 +1,27 @@
+#!/bin/bash -e
+
+start() {
+  local MAX_STEPS=${#STEPS[@]}
+  local BAR_SIZE="##########"
+  local MAX_BAR_SIZE="${#BAR_SIZE}"
+  local CLEAR_LINE="\\033[K"
+
+  tput civis -- invisible
+
+  for step in "${!STEPS[@]}"; do
+    perc=$((step * 100 / MAX_STEPS))
+    percBar=$((perc * MAX_BAR_SIZE / 100))
+    echo -ne "\\r- ${STEPS[step]} [ ]$CLEAR_LINE\\n"
+    echo -ne "\\r[${BAR_SIZE:0:percBar}] $perc %$CLEAR_LINE"
+
+    ${CMDS[$step]}
+
+    perc=$(((step + 1) * 100 / MAX_STEPS))
+    percBar=$((perc * MAX_BAR_SIZE / 100))
+    echo -ne "\\r\\033[1A- ${STEPS[step]} [✔]$CLEAR_LINE\\n"
+    echo -ne "\\r[${BAR_SIZE:0:percBar}] $perc %$CLEAR_LINE"
+  done
+  echo ""
+
+  tput cnorm -- normal
+}
diff --git a/bin/bash-progress-indicator/spinner.sh b/bin/bash-progress-indicator/spinner.sh
new file mode 100644 (file)
index 0000000..b68cf89
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/bash -e
+
+declare -x FRAME
+declare -x FRAME_INTERVAL
+
+set_spinner() {
+  case $1 in
+    spinner1)
+      FRAME=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏")
+      FRAME_INTERVAL=0.1
+      ;;
+    spinner2)
+      FRAME=("-" "\\" "|" "/")
+      FRAME_INTERVAL=0.25
+      ;;
+    spinner3)
+      FRAME=("◐" "◓" "◑" "◒")
+      FRAME_INTERVAL=0.5
+      ;;
+    spinner4)
+      FRAME=(":(" ":|" ":)" ":D")
+      FRAME_INTERVAL=0.5
+      ;;
+    spinner5)
+      FRAME=("◇" "◈" "◆")
+      FRAME_INTERVAL=0.5
+      ;;
+    spinner6)
+      FRAME=("⚬" "⚭" "⚮" "⚯")
+      FRAME_INTERVAL=0.25
+      ;;
+    spinner7)
+      FRAME=("░" "▒" "▓" "█" "▓" "▒")
+      FRAME_INTERVAL=0.25
+      ;;
+    spinner8)
+      FRAME=("☉" "◎" "◉" "●" "◉")
+      FRAME_INTERVAL=0.1
+      ;;
+    spinner9)
+      FRAME=("❤" "♥" "♡")
+      FRAME_INTERVAL=0.15
+      ;;
+    spinner10)
+      FRAME=("✧" "☆" "★" "✪" "◌" "✲")
+      FRAME_INTERVAL=0.1
+      ;;
+    spinner11)
+      FRAME=("●" "◕" "☯" "◔" "◕")
+      FRAME_INTERVAL=0.25
+      ;;
+    *)
+      echo "No spinner is defined for $1"
+      exit 1
+  esac
+}
+
+start() {
+  local step=0
+
+#  tput civis -- invisible
+
+  while [ "$step" -lt "${#CMDS[@]}" ]; do
+    ${CMDS[$step]} & pid=$!
+
+    while ps -p $pid &>/dev/null; do
+      echo -ne "\\r[   ] ${STEPS[$step]} ..."
+
+      for k in "${!FRAME[@]}"; do
+        echo -ne "\\r[ ${FRAME[k]} ]"
+        sleep $FRAME_INTERVAL
+      done
+    done
+
+    echo -ne "\\r[ ✔ ] ${STEPS[$step]}\\n"
+    step=$((step + 1))
+  done
+
+#  tput cnorm -- normal
+}
+
+set_spinner "$1"
diff --git a/bin/check_repo.sh b/bin/check_repo.sh
new file mode 100755 (executable)
index 0000000..1ecb927
--- /dev/null
@@ -0,0 +1,25 @@
+#!/usr/bin/env bash
+
+cd "${REPO_DIR:-.}"
+
+dirty="$(git ls-files -u || true)"
+lsfiles="$(git ls-files --others --exclude-standard || true)"
+
+# Conflict or unresolved state: stop and notify.
+if [[ -n "$dirty" ]]; then
+    echo "[check_repo] repo has conflicts, stop"
+    echo "[check_repo] unmerged files:"
+    printf "%s\n" "$dirty"
+    echo "[check_repo] resolve conflicts and run: git add <files> && git commit"
+    bash bin/notify_telegram.sh "STOP: repo conflicts in $(pwd)"
+    exit 1
+fi
+
+# Exit 0 only when repo is NOT clean to allow autocommit flow.
+if git diff --quiet && git diff --cached --quiet && [[ -z "$lsfiles" ]]; then
+    echo "[check_repo] repo clean. Exit 1 from check_repo.sh."
+    exit 1
+else
+    echo "[check_repo] repo not clean. Exit 0 from check_repo.sh."
+    exit 0
+fi
diff --git a/bin/logs b/bin/logs
new file mode 120000 (symlink)
index 0000000..927bfe5
--- /dev/null
+++ b/bin/logs
@@ -0,0 +1 @@
+/var/log/Mikrotiks
\ No newline at end of file
diff --git a/bin/ros-conf/README.md b/bin/ros-conf/README.md
new file mode 100644 (file)
index 0000000..973a2a7
--- /dev/null
@@ -0,0 +1,41 @@
+# RouterOS Configuration Scripts
+
+Personal RouterOS configuration scripts for home network management.
+
+## Overview
+
+This repository contains RouterOS scripts to configure and diagnose a MikroTik router. Configuration scripts set up router modes (routing, bridging, NAT, DHCP). Check scripts display router settings and diagnostics.
+
+## Quick Start
+
+### Running Scripts
+
+Run scripts on the router using forward slashes:
+
+```routeros
+/system script run config/firewall
+/system script run check/nat
+```
+
+## Network Configuration
+
+The `combo1` port is renamed to `combo1-WAN` for routing mode or `combo1-bridge` for switching mode. The `bridge` interface is used for the internal network.
+
+The WAN interface uses `192.168.200.2/24` with gateway `192.168.200.1`. The bridge interface uses `192.168.88.1/24` as the gateway for the internal network. DHCP serves addresses from `192.168.88.100-192.168.88.199`.
+
+## Hardware
+
+These scripts are tested on CRS106, a MikroTik switch/router.
+
+## Repository Structure
+
+```text
+routeros-config/
+├── scripts/
+│   ├── config/          # Configuration scripts
+│   ├── check/           # Diagnostic scripts
+│   └── README.md        # Format and syntax guidelines
+└── README.md            # This file
+```
+
+For format and syntax guidelines, see [scripts/README.md](scripts/README.md).
diff --git a/bin/ros-conf/setup-ssh-keys.sh b/bin/ros-conf/setup-ssh-keys.sh
new file mode 100644 (file)
index 0000000..6653373
--- /dev/null
@@ -0,0 +1,28 @@
+#!/bin/bash
+# Setup SSH keys for RouterOS router
+
+ROUTER_IP="10.30.30.81"
+ROUTER_USER="mikro_bak"
+KEY_NAME=$ROUTER_USER"_rsa@"$ROUTER_IP
+KEY_PATH="$HOME/.ssh/$KEY_NAME"
+
+# Check/create .ssh directory
+if [ ! -d "$HOME/.ssh" ]; then
+    mkdir -p "$HOME/.ssh"
+    chmod 700 "$HOME/.ssh"
+fi
+
+# Generate SSH key if it doesn't exist
+if [ ! -f "$KEY_PATH" ]; then
+    ssh-keygen -t rsa -b 2048 -f "$KEY_PATH" -N "" -C "$ROUTER_USER@$ROUTER_IP"
+fi
+
+# Upload and import key on router
+scp "$KEY_PATH.pub" "$ROUTER_USER@$ROUTER_IP -p 2222":/
+ssh "$ROUTER_USER@$ROUTER_IP -p 2222" "/user ssh-keys import public-key-file=$KEY_NAME.pub user=$ROUTER_USER"
+
+# Verify key works
+if ! ssh -i "$KEY_PATH" -o PasswordAuthentication=no "$ROUTER_USER@$ROUTER_IP -p 2222" "/system identity print" >/dev/null 2>&1; then
+    echo "Error: SSH key authentication failed"
+    exit 1
+fi
diff --git a/bin/ros-conf/sync-script.sh b/bin/ros-conf/sync-script.sh
new file mode 100644 (file)
index 0000000..ca4c1de
--- /dev/null
@@ -0,0 +1,139 @@
+#!/bin/bash
+# Upload all scripts and sync to RouterOS
+
+ROUTER_IP="10.30.30.10"
+ROUTER_USER="mikro_bak"
+SSH_KEY="$HOME/.ssh/mikro_bak_rsa"
+RSC_FILE="import_scripts.rsc"
+
+# Require router-specific SSH key
+if [ ! -f "$SSH_KEY" ]; then
+    echo "Error: SSH key not found at $SSH_KEY"
+    echo "Run ./setup-ssh-keys.sh to generate the key"
+    exit 1
+fi
+
+SSH_OPTS="-i $SSH_KEY -o PasswordAuthentication=no"
+
+# Generate .rsc import file
+echo "Generating import file..."
+
+# Get git commit hash and dirty status
+GIT_HASH=$(git rev-parse --short HEAD 2>/dev/null || echo "unknown")
+if [ -z "$(git status --porcelain 2>/dev/null)" ]; then
+    GIT_STATUS="$GIT_HASH"
+else
+    GIT_STATUS="$GIT_HASH-dirty"
+fi
+
+# Get current date with timezone offset
+GEN_DATE=$(date '+%Y-%m-%d %H:%M:%S %z')
+
+# Write header
+cat > "$RSC_FILE" << RSC_HEADER
+# RouterOS script import file
+# Generated by sync-script.sh
+# Date: $GEN_DATE
+# Git: $GIT_STATUS
+
+RSC_HEADER
+
+# Write header for creating scripts section
+printf ':put "=== Creating scripts ==="\n' >> "$RSC_FILE"
+printf '\n' >> "$RSC_FILE"
+
+# Create function for script creation
+printf ':global createScriptIfMissing do={\n' >> "$RSC_FILE"
+printf '    :if ([/system script print count-only where name=$scriptName] = 0) do={\n' >> "$RSC_FILE"
+printf '        :put ("Creating script: " . $scriptName);\n' >> "$RSC_FILE"
+printf '        /system script add name=$scriptName\n' >> "$RSC_FILE"
+printf '    }\n' >> "$RSC_FILE"
+printf '}\n\n' >> "$RSC_FILE"
+
+# Write all add commands first
+for SCRIPT_FILE in scripts/config/*.rsc scripts/check/*.rsc; do
+    if [ ! -f "$SCRIPT_FILE" ]; then
+        continue
+    fi
+    
+    SCRIPT_NAME=$(sed -n '1p' "$SCRIPT_FILE" | sed 's/^# //')
+    POLICY=$(sed -n '3p' "$SCRIPT_FILE" | sed -n 's/^# policy=\(.*\)/\1/p')
+    
+    if [ -z "$POLICY" ]; then
+        echo "Error: Missing policy in $SCRIPT_FILE (line 3 should be '# policy=read,write')"
+        exit 1
+    fi
+    
+    # Call function with script name
+    printf '$createScriptIfMissing scriptName="%s"\n' "$SCRIPT_NAME" >> "$RSC_FILE"
+done
+
+# Empty line between sections
+printf '\n' >> "$RSC_FILE"
+printf ':put ""\n' >> "$RSC_FILE"
+printf ':put "=== Updating scripts ==="\n' >> "$RSC_FILE"
+printf '\n' >> "$RSC_FILE"
+
+# Write all set commands
+for SCRIPT_FILE in scripts/config/*.rsc scripts/check/*.rsc; do
+    if [ ! -f "$SCRIPT_FILE" ]; then
+        continue
+    fi
+    
+    SCRIPT_NAME=$(sed -n '1p' "$SCRIPT_FILE" | sed 's/^# //')
+    COMMENT=$(sed -n '2p' "$SCRIPT_FILE" | sed 's/^# //')
+    POLICY=$(sed -n '3p' "$SCRIPT_FILE" | sed -n 's/^# policy=\(.*\)/\1/p')
+    
+    # Escape comment for RouterOS (escape quotes)
+    ESCAPED_COMMENT=$(echo "$COMMENT" | sed 's/"/\\"/g')
+    
+    # Read script content and escape for RouterOS .rsc format
+    # Loop through file line by line, escape special chars, join with \n
+    SCRIPT_CONTENT=""
+    while IFS= read -r line || [ -n "$line" ]; do
+        # Escape backslashes, dollar signs, and quotes
+        line=$(echo "$line" | sed 's/\\/\\\\/g' | sed 's/\$/\\$/g' | sed 's/"/\\"/g')
+        if [ -z "$SCRIPT_CONTENT" ]; then
+            SCRIPT_CONTENT="$line"
+        else
+            SCRIPT_CONTENT="$SCRIPT_CONTENT\\n$line"
+        fi
+    done < "$SCRIPT_FILE"
+    
+    # Write set command directly to file
+    printf ':put "Updating script: %s"; /system script set "%s" source="' "$SCRIPT_NAME" "$SCRIPT_NAME" >> "$RSC_FILE"
+    echo "$SCRIPT_CONTENT" | sed 's/\\n/\\n\\\n    /g' >> "$RSC_FILE"
+    printf '" comment="%s" policy=%s\n\n' "$ESCAPED_COMMENT" "$POLICY" >> "$RSC_FILE"
+done
+
+# Delete the helper function
+printf '\n:set createScriptIfMissing;\n' >> "$RSC_FILE"
+
+# Print all scripts (excluding source/contents)
+printf ':put ""\n:put "=== All system scripts ==="\n/system script print proplist=name,comment,owner,policy,dont-require-permissions,run-count,last-started,invalid\n' >> "$RSC_FILE"
+
+# Show generated .rsc file and ask for confirmation
+echo ""
+echo "=== Generated import file ($RSC_FILE) ==="
+head -20 "$RSC_FILE"
+echo "..."
+echo ""
+read -p "Upload and import this file? (y/N): " -n 1 -r
+echo
+if [[ ! $REPLY =~ ^[Yy]$ ]]; then
+    echo "Aborted"
+    rm -f "$RSC_FILE"
+    exit 1
+fi
+
+# Upload .rsc file
+echo "Uploading import file..."
+scp $SSH_OPTS "$RSC_FILE" "$ROUTER_USER@$ROUTER_IP":/
+
+# Import on router
+echo "Importing scripts..."
+ssh $SSH_OPTS "$ROUTER_USER@$ROUTER_IP" "/import file-name=$RSC_FILE"
+
+# Cleanup
+rm -f "$RSC_FILE"
+echo "Done!"
diff --git a/bin/ros-diff.sh b/bin/ros-diff.sh
new file mode 100755 (executable)
index 0000000..be2c8c6
--- /dev/null
@@ -0,0 +1,665 @@
+#!/bin/bash
+#set +e -u
+#o pipefail
+# Add to cron
+# crontab -e 
+#*/20 * * * * /var/www/ros.vados.ru/Mikrotiks/.bin/ros-diff.sh
+#set +eo pipefail
+#set -x
+#GEN_DATE=$(date '+%Y-%m-%d %H:%M:%S %z')
+#GEN_DATE_TIME=$(date '+%d.%m.%Y %T %Z')
+#
+#ASK_NEXT=true
+#ask_forNext() {
+#    local ask $1
+#    local item $2
+#    echo -n $ask
+#read item
+#case "$item" in
+#    y|Y) echo "Enter «y», continue..."
+#        ;;
+#    n|N) echo "Enter «n», exit..."
+#       exit 0
+#        ;;
+#    *) echo "Nothing was entered. We perform the default action..."
+#        ;;
+#esac
+#}
+#${CMD_SSH} ${SSH_OPTS} ${SSHuser}@${SSHhost} system script run MkTmpfs;
+#
+#### Utils #############################################################################################
+CMD_FIND=$(which find)
+CMD_MV=$(which mv)
+CMD_GZ=$(which gzip)
+CMD_CHO=$(which chown)
+CMD_CHM=$(which chmod)
+CMD_MKD=$(which mkdir)" -p "
+CMD_RM=$(which rm)
+CMD_DATE=$(date +%Y%m%d_%H%M) # date in format YYYYMMDD_HHmm
+CMD_SSL=$(which openssl)
+CMD_SSH=$(which ssh)
+CMD_SCP=$(which scp)
+CMD_SFTP=$(which sftp)
+
+ScriptName=$(basename -- "$0")
+# HomeDir=$HOME
+HomeDir="/var/www/ros.vados.ru/Mikrotiks"
+HostsFile=${HomeDir}"/.config/.mikrotiks"
+BinDir=${HomeDir}"/bin"
+GitDir=${HomeDir}"/backups"
+
+# Set SSH defaults:
+DEFAULT_SSH_PORT="22"
+DEFAULT_SSH_USER="admin"
+DEFAULT_CONNECT_ATTEMPTS=5
+DEFAULT_CONNECT_TIMEOUT=5
+DEFAULT_SSH_KEY=${HomeDir}"/.ssh/id_rsa"
+# Set default diff args:
+DEFAULT_DIFF_ARGS=("-I \"RouterOS\"")
+#
+# Set debug and log options:
+DEBUG_OUT=true
+SAVE_LOG=true
+# Set default LogFile:
+DEFAULT_LOG="/var/log/Mikrotiks/ros-diff.log"
+#
+# Default backup variables:
+DEFAULT_BIN_CRYPT=true
+DEFAULT_BINPWD="BinPwd123"
+DEFAULT_EXP_CRYPT=false
+DEFAULT_EXPPWD="ExpPwd321"
+
+# Handy tput commands:
+#tput bold - Bold effect    #'\033[1m'
+#tput rev - Display inverse colors
+#tput sgr0 - Reset everything    #'\033[0m'
+#tput setaf {CODE}- Set foreground color, see color {CODE} below
+#tput setab {CODE}- Set background color, see color {CODE} below
+# Colors:
+#0    Black
+#1    Red    #'\033[1;31m'
+#2    Green    #'\033[1;32m'
+#3    Yellow    #'\033[1;33m'
+#4    Blue    # '\033[1;34m'
+#5    Magenta    # '\033[1;35m'
+#6    Cyan    # '\033[1;36m'
+#7    White    # '\033[1;37m'
+if [ -t 1 ] && $DEBUG_OUT; then
+    reset=$(tput sgr0)
+    bold=$(tput bold)
+    red=$(tput setaf 1)
+    green=$(tput setaf 2)
+    yellow=$(tput setaf 3)
+    blue=$(tput setaf 4)
+    magenta=$(tput setaf 5)
+    cyan=$(tput setaf 6)
+    white=$(tput setaf 7)
+    toend=$(tput hpa $(tput cols))$(tput cub 6)
+else
+    reset='' bold='' red='' green='' yellow='' blue='' magenta='' cyan='' white='' toend=''
+fi
+
+info() {
+    echo -e "\n${blue}ℹ  $*${reset}"
+}
+success() {
+    echo -e "\n${green}✅  $*${reset}"
+}
+error() {
+    echo -e "\n${red}❌ $*${reset}" >&2
+}
+warning() {
+    echo -e "${yellow}⚠  $*${reset}" >&2
+}
+section() {
+    echo -e "\n${magenta}................[$(tput rev) $* ${reset}${magenta}]................${reset}\n"
+}
+
+FRAME=("⠋" "⠙" "⠹" "⠸" "⠼" "⠴" "⠦" "⠧" "⠇" "⠏")
+FRAME_INTERVAL=0.1
+
+start() {
+  local step=0
+  while [ "$step" -lt "${#CMDS[@]}" ]; do
+    ${CMDS[$step]} & pid=$!
+    while ps -p $pid &>/dev/null; do
+      echo -ne "\\r[   ] ${STEPS[$step]} ..."
+      for k in "${!FRAME[@]}"; do
+        echo -ne "\\r[ ${FRAME[k]} ]"
+        sleep $FRAME_INTERVAL
+      done
+    done
+    echo -ne "\\r[ ✔ ] ${STEPS[$step]}\\n"
+    step=$((step + 1))
+  done
+}
+#echo '⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
+spinner()
+{
+    local pid=$!
+    local delay=0.75
+    local spinstr='|/-\'
+    #'⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
+    while [ "$(ps a | awk '{print $1}' | grep $pid)" ]; do
+        local temp=${spinstr#?}
+        printf " [%c] " "${spinstr}"
+        local spinstr=$temp${spinstr%"$temp"}
+        sleep $delay
+        printf "\b\b\b\b\b\b"
+    done
+    printf "    \b\b\b\b"
+}
+
+save_log() {
+    local log="${DEFAULT_LOG}"
+    if [ -n "${LogFile}" ]; then
+        log="${LogFile}"
+    fi
+    if ${SAVE_LOG}; then
+        echo "$(date '+%b %d %T') - $*" >> ${log}
+        return 0
+    else
+        return 1
+    fi
+}
+
+get_connections_str() {
+    local opts
+    local log_msg
+    local host
+    local ssh_str
+    local scp_str
+
+# Require router-specific SSH key
+    if [ -n "$DEFAULT_SSH_KEY" ]; then
+        opts=("-i ${DEFAULT_SSH_KEY}" "-o PasswordAuthentication=no")
+    else
+    log_msg="- Error: SSH key not found at $DEFAULT_SSH_KEY\nRun ./setup-ssh-keys.sh to generate the key"
+        if [ -t 1 ] && ${DEBUG_OUT}; then
+            error "${RouterName} ${log_msg}"
+        fi
+    save_log "${log_msg}"
+    exit 1
+    fi
+#    if [ -n "$DEFAULT_CONNECT_ATTEMPTS" ]; then
+#        opts+=("-o ConnectionAttempts=${DEFAULT_CONNECT_ATTEMPTS}")
+#    fi
+#    if [ -n "$DEFAULT_CONNECT_TIMEOUT" ]; then
+#        opts+=("-o ConnectTimeout=${DEFAULT_CONNECT_TIMEOUT}")
+#    fi
+    #opts+=("-o PreferredAuthentications=publickey" "-o StrictHostKeyChecking=no" "-o UserKnownHostsFile=/dev/null" \
+    #"-o GlobalKnownHostsFile=/dev/null" "-o CheckHostIP=no")
+SSH_OPTS="${opts[*]}"
+
+# Require router host IP
+    if [ -n "${SSHhost}" ]; then
+        host="${SSHhost}"
+    else
+        log_msg="- Error! SSH Host not found. Exit 1."
+        if [ -t 1 ] && ${DEBUG_OUT}; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        exit 1
+    fi
+
+    ssh_str=("$CMD_SSH" "-2" "-4")    
+    scp_str=("${CMD_SCP}" "-2" "-4" "-B ${SSH_OPTS}")
+    
+    if [ -n "${SSHport}" ]; then
+        ssh_str+=("-p ${SSHport}")
+        scp_str+=("-P ${SSHport}")
+    else
+        ssh_str+=("-p ${DEFAULT_SSH_PORT}")
+        scp_str+=("-P ${DEFAULT_SSH_PORT}")
+    fi
+    
+    if [ -n "${SSHuser}" ]; then
+        ssh_str+=("-l ${SSHuser}")
+        scp_str+=("${SSHuser}@${host}")
+    else
+        ssh_str+=("-l ${DEFAULT_SSH_USER}")
+        scp_str+=("${DEFAULT_SSH_USER}@${host}")
+    fi
+
+    ssh_str+=("${host}")
+
+ssh_str+=("${SSH_OPTS}")
+SSH_STR="${ssh_str[*]}"
+SCP_STR="${scp_str[*]}"
+#SFTP_STR="${sftp_str[*]}"
+#SFTP_OPTS="-i ${DEFAULT_SSH_KEY} -o PasswordAuthentication=no -oPort=${SSHport}"
+}
+
+#>/dev/null 2>&1
+###############################
+# Backup listing 
+###############################
+# Get Names Addresses and Ports in $HostsFile
+#declare -rx STEPS=(
+#  'download'
+#  'check'
+#  'backup'
+#)
+#IFS=$'\n'
+run_ssh_cmd() {
+    local run="${1}"
+    warning "${run}"
+    if ${SSH_STR} ${run}; then
+        return 0
+    else
+        return 1
+    fi
+}
+
+download_config() {
+    local conf="${1}"
+    local log_msg
+
+    if ${SSH_STR} export >${conf}; then
+        log_msg="- Config download success!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        return 0
+    else
+        log_msg="- Config download ${conf} error! Exit Error 1."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        exit 1
+    fi
+}
+
+compare_config() {
+    local config_file="${1}"
+    local precedent_file="${2}" 
+    local diff_file="${3}"
+    local diff_args=${DEFAULT_DIFF_ARGS}
+    local log_msg
+
+    diff ${diff_args} ${config_file} ${precedent_file} >${diff_file}
+    if [ "$?" -ne "0" ]; then
+        log_msg="- There is a difference! Create backup..."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            section " CREATE BACKUP "
+            sleep 1
+            info "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        return 0
+    else
+        log_msg="- The files are identical. No backup is required."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            section " START CLEANUP "
+            sleep 1
+            info "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        log_msg="- Remove ${diff_file} file."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            info "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        ${CMD_RM} -f ${diff_file}
+        log_msg="- Remove ${config_file} file."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            info "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        ${CMD_RM} -f ${config_file}
+
+        return 1
+    fi
+}
+
+check_directory() {
+    local chk_dir="${1}"
+    local log_msg
+
+ if [[ -d ${chk_dir} && -r ${chk_dir} ]]
+  then
+   return 0
+  else
+    if $CMD_MKD ${chk_dir}; then
+        log_msg="- Direcory ${chk_dir} created."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        return 0
+    else
+        log_msg="- Error create direcory ${chk_dir}! Exit 1."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+        exit 1
+    fi
+# This script must be run by a special user in his home directory.
+# Therefore, the following lines are not needed.
+#   $CMD_CHO root:root $dir
+#   $CMD_CHM 755 $ST_FULL
+ fi
+}
+
+#${SSH_STR} /system script environment get [find name=BackupPassword] value;
+#exit 0
+backup_binary() {
+    local bin_name="${1}"
+    local crypt="${2:-$DEFAULT_BIN_CRYPT}"
+    local bin_pass="${3:-$DEFAULT_BINPWD}"
+    local log_msg
+    local crypt_str
+    #${SSH_STR} :put [/system script environment get [find name=BackupPassword] value];
+
+    if ${SSH_STR} /system/script environment find where name=BackupEncrypt && ${SSH_STR} /system/script environment find where name=BackupPassword; then
+        
+        bin_pass=${SSH_STR} /system/script/environment/get ([ /system/script/environment find name='BackupPassword' ]->value);
+        crypt_str="dont-encrypt=no password=${bin_pass}"
+        warning "${crypt_str}"
+    else
+        if [ -n ${crypt} ] && [ -n {passwd} ]; then
+            crypt_str="dont-encrypt=no password=${passwd}"
+        else
+            crypt_str="dont-encrypt=yes"
+        fi
+
+    fi
+ #   if [ -n $]; then
+
+#    local BKPSTR="system backup save name=${bin_name} dont-encrypt=no password=$BKP_BINPWD"
+# T_BKPCLN="file remove [find name=$TGT_BKPNAME_BIN]"
+}
+
+readarray -t lines < $HostsFile
+#declare -r STEPS=($lines)
+#declare -r MAX_STEPS=${#lines[@]}
+#declare -r BAR_SIZE="##########"
+#declare -r MAX_BAR_SIZE=${#BAR_SIZE}
+
+for HR in "${lines[@]}"; do
+#  perc=$(((HR + 1) * 100 / MAX_STEPS))
+#  percBar=$((perc * MAX_BAR_SIZE / 100))
+# declare -rx CMDS=(
+#  "${CMD_SSH} ${SSH_OPTS} ${SSHuser}@${SSHhost} export >$current_config"
+#  'sleep 10'
+#  'sleep 1'
+#)
+while IFS=$' ' read -a HR ; do
+#|| [ -n "$HR" ]; do
+[[ -z ${HR[0]} ]] && continue
+
+DStamp=$(date '+%Y%m%d')
+DTStamp=$(date '+%Y%m%d%H%M%S')
+
+RouterName=${HR[0]}
+SSHhost=${HR[1]}
+SSHport=${HR[2]}
+SSHuser=${HR[3]}
+SSHpassword=${HR[4]}
+
+get_connections_str
+backup_binary "BinaryTest.backup"
+
+exit 0
+#warning "SSH_STR = ${SSH_STR}"
+#warning "SCP_STR = ${SCP_STR}"
+#exit 0
+
+BaseDir=${HomeDir}"/backups/${RouterName}/"
+TempDir=${BaseDir}"tmp/"
+HistoryDir=${BaseDir}"history/"
+LogFile="/var/log/Mikrotiks/${RouterName}.log"
+log_msg="undefined"
+
+log_msg="- Start backup script ${ScriptName} for ${RouterName}"
+if [ -t 1 ] && $DEBUG_OUT; then
+    info "${RouterName} ${log_msg}"
+    echo
+fi
+save_log "${log_msg}"
+
+log_msg="- Check and creatre services directories for ${RouterName} if not exsist..."
+if [ -t 1 ] && $DEBUG_OUT; then
+    section " CHECK DIRS "
+    info "${RouterName} ${log_msg}"
+fi
+save_log "${log_msg}"
+
+CheckDirs=("${BaseDir}" "${TempDir}" "${HistoryDir}")
+for dir in "${CheckDirs[@]}"; do
+(check_directory "${dir[@]}")
+done
+
+log_msg="All Directories for ${RouterName} was created sucessfully!"
+if [ -t 1 ] && $DEBUG_OUT; then
+    success "${log_msg}"
+fi
+save_log "- ${log_msg}"
+
+log_msg="Set variables for ${RouterName}..."
+if [ -t 1 ] && $DEBUG_OUT; then
+    info "${log_msg}"
+fi
+save_log "- ${log_msg}"
+
+precedent_config=${BaseDir}"Precedent-Config.rsc"
+current_config=${TempDir}"Config.rsc"
+diff_config=${TempDir}"Diff-Config.rsc"
+current_backup="Binary.backup"
+
+log_msg="Set variables for ${RouterName} success!"
+if [ -t 1 ] && $DEBUG_OUT; then
+    success "${log_msg}"
+fi
+save_log "- ${log_msg}"
+
+section " CHECK CONFIG "
+log_msg="- Download ${current_config} file to Temp Directory..."
+if [ -t 1 ] && $DEBUG_OUT; then
+    info "${RouterName} ${log_msg}"
+fi
+save_log "- ${log_msg}"
+
+download_config "${current_config}"
+
+log_msg="- Comparing with the previous config..."
+if [ -t 1 ] && $DEBUG_OUT; then
+    info "${RouterName} ${log_msg}"
+fi
+save_log "- ${log_msg}"
+
+if compare_config ${current_config} ${precedent_config} ${diff_config} ${RouterName} ${LogFile}; then
+    BackupDir=${BaseDir}"${DStamp}/"
+    ${CMD_MKD} ${BackupDir}
+
+    save_config=${BackupDir}"${DTStamp}-Config.rsc"
+    save_backup=${BackupDir}"${DTStamp}-Binary.backup"
+
+    log_msg="- Copy ${current_config} file to ${BackupDir} directory..."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${RouterName} ${log_msg}"
+    fi
+    save_log "- ${log_msg}"
+
+    cp ${current_config} ${save_config}
+
+    ${CMD_RM} -f ${precedent_config}
+
+    ${CMD_MV} -f ${current_config} ${precedent_config}
+
+    log_msg="- Copy configuration to ${BackupDir}/${save_config} and ${precedent_config} success."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        success "${RouterName} ${log_msg}"
+    fi
+    save_log "- ${log_msg}"
+
+    log_msg="Create ${current_backup} file on ${RouterName}..."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${log_msg}"
+    fi
+    save_log "- ${log_msg}"
+#   if [ $? -eq 0 ]; then
+    if ${SSH_STR} system backup save name=${current_backup}; then
+        log_msg="Create binary backup ${current_backup} on ${RouterName} success."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${log_msg}"
+        fi
+        save_log "- ${log_msg}"
+
+        log_msg="- Start download ${current_backup} file to ${BackupDir}..."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            info "${RouterName} ${log_msg}"
+        fi
+        save_log "- ${log_msg}"
+
+#       if ${SFTP_STR}:$current_backup; then
+        #   ${CMD_SFTP} ${SFTP_OPTS} ${SSHuser}@${SSHhost}:$current_backup
+        if ${SCP_STR}:/${current_backup} ${save_backup}; then
+            sleep 2
+            log_msg="- Binary Backup download complete!"
+            if [ -t 1 ] && $DEBUG_OUT; then
+                success "${RouterName} ${log_msg}"
+            fi
+            save_log "${log_msg}"
+        else
+            log_msg="- Error! Save binary backup on ${RoutrName} failed!"
+            if [ -t 1 ] && $DEBUG_OUT; then
+                error "${log_msg}"
+            fi
+            save_log "${log_msg}"
+        fi
+    else
+        log_msg="Error create binary backup ${current_backup} on ${RouterName}!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${log_msg}"
+        fi
+        save_log "- ${log_msg}"
+    fi
+
+    log_msg="- Remove ${current_backup} file on ${RouterName}."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        section "CLEANUP"
+        info "${log_msg}"
+    fi
+    save_log "- ${log_msg}"
+
+    if ${SSH_STR} /file remove ${current_backup}; then
+        log_msg="- Remove ${current_backup} file on ${RouterName} complete succesfully!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+    save_log "${log_msg}"
+    else
+        log_msg="- Error Remove ${current_backup} file on ${RouterName}!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    fi
+
+    cd "${BaseDir}"
+
+    CurrentHistoryDir=${HistoryDir}"${DStamp}/"
+    ${CMD_MKD} -p ${CurrentHistoryDir}
+    diff_config_history=${CurrentHistoryDir}"${DTStamp}-Diff-Config.rsc"
+    log_msg="- Move ${diff_config} file to ${CurrentHistoryDir}."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${RouterName} ${log_msg}"
+    fi
+    save_log "${log_msg}"
+    
+    if ${CMD_MV} -f ${diff_config} ${diff_config_history}; then
+        log_msg="- Move ${diff_config} file to ${CurrentHistoryDir} complete succesfully!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    else
+        log_msg="- Error move ${diff_config} file to ${CurrentHistoryDir}!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    fi
+
+    log_msg="- Go to Git directory (${GitDir}), add backups files and commit him."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        section " COMMIT "
+        info "${RouterName} ${log_msg}"
+    fi
+    save_log "${log_msg}"
+    cd "${GitDir}/"
+    git add .
+    log_msg="- Git add commit..."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${RouterName} ${log_msg}"
+    fi
+    save_log "${log_msg}"
+    if git commit -m "Backup for ${RouterName} sucessfully creatd at $(date '+%b %d %T')."; then
+        log_msg=" - Git add commit success."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    else
+        log_msg="- Git add commit Error!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    fi
+    log_msg="- Git push commit..."
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${RouterName} ${log_msg}"
+    fi
+    save_log "${log_msg}"
+    if git push origin main; then
+        log_msg=" - Git push commit success."
+        if [ -t 1 ] && $DEBUG_OUT; then
+            success "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    else
+        log_msg="- Git push commit Error!"
+        if [ -t 1 ] && $DEBUG_OUT; then
+            error "${RouterName} ${log_msg}"
+        fi
+        save_log "${log_msg}"
+    fi
+else
+    log_msg="- ${RouterName} backup complete!"
+    if [ -t 1 ] && $DEBUG_OUT; then
+        info "${RouterName} ${log_msg}"
+    fi
+        save_log "${log_msg}"
+fi
+
+log_msg="- Remove Temp directory."
+if [ -t 1 ] && $DEBUG_OUT; then
+    info "${RouterName} ${log_msg}"
+fi
+    save_log "${log_msg}"
+
+${CMD_RM} -d ${TempDir}
+log_msg="- backup complete!"
+if [ -t 1 ] && $DEBUG_OUT; then
+    success "${RouterName} ${log_msg}"
+fi
+save_log "${log_msg}"
+
+done <<<"$(echo -e $HR)"
+LogFile="${DEFAULT_LOG}"
+#  echo -ne "\\r[${BAR_SIZE:0:percBar}] $perc %"
+#echo "[] $perc %"
+done
+log_msg="All Done! Exit 0."
+if [ -t 1 ] && $DEBUG_OUT; then
+    section " DONE "
+    success "${log_msg}"
+fi
+save_log "${log_msg}"
+exit 0
diff --git a/bin/scripts/mktmpfs.rsc b/bin/scripts/mktmpfs.rsc
new file mode 100644 (file)
index 0000000..dbe979c
--- /dev/null
@@ -0,0 +1,3 @@
+:global MkDir;
+:put [($MkDir /usb1/tmpfs)];
+:log warning ("\$MkDir = " . $MkDir . ".");
diff --git a/bin/test.sh b/bin/test.sh
new file mode 100644 (file)
index 0000000..67b9dd5
--- /dev/null
@@ -0,0 +1,237 @@
+#!/bin/bash
+# Add to cron
+# crontab -e 
+#*/20 * * * * /var/www/ros.vados.ru/Mikrotiks/.bin/ros-diff.sh
+#set +eo pipefail
+#set -x
+#
+DEBUG_OUT=true
+if [ -t 1 ] && $DEBUG_OUT; then
+    reset='\033[0m'
+    bold=$(tput bold)
+    #'\033[1m'
+    red=$(tput setaf 7)$(tput setab 1)
+    #'\033[1;31m'
+    green=$(tput setaf 4)$(tput setab 7)$(tput bold)
+    #'\033[1;32m'
+    yellow='\033[1;33m'
+    blue='\033[1;34m'
+    magenta='\033[1;35m'
+    cyan='\033[1;36m'
+    white='\033[1;37m'
+else
+    reset='' bold='' red='' green='' yellow='' blue='' cyan='' magenta='' white=''
+fi
+
+info() {
+    if $DEBUG_OUT; then    
+    echo -e "${blue}ℹ $*${reset}"
+    fi    
+}
+success() {
+    if $DEBUG_OUT; then
+    echo -e "${bold}${green}✅ $*${reset}"
+    fi
+}
+error() {
+    if $DEBUG_OUT; then
+    echo -e "${red}❌ Error: $*${reset}" >&2
+    fi
+}
+warning() {
+    if $DEBUG_OUT; then
+    echo -e "${yellow}⚠ $*${reset}" >&2
+    fi
+}
+section() {
+    if $DEBUG_OUT; then
+    echo -e "\n${magenta}====$*====${reset}"
+    fi
+}
+toend=$(tput hpa $(tput cols))$(tput cub 6)
+toend_ok() {
+    if $DEBUG_OUT; then
+    echo -n "${toend}${white}[${green}OK${white}]"
+    fi
+}
+toend_error() {
+    if $DEBUG_OUT; then
+    echo -n "${toend}${white}[${red}ERROR${white}]"
+    fi
+}
+BR() {
+    if $DEBUG_OUT; then
+    echo -e "\n"
+    fi
+}
+
+error "error"
+success "success"
+exit 0
+
+# HomeDir=$HOME
+HomeDir="/var/www/ros.vados.ru/Mikrotiks"
+HostsFile=${HomeDir}"/.config/.mikrotiks"
+BinDir=${HomeDir}"/.bin"
+GitDir=${HomeDir}"/backups"
+
+SSH_KEY=${HomeDir}"/.ssh/id_rsa"
+# Require router-specific SSH key
+if [ ! -f "$SSH_KEY" ]; then
+    error "Error: SSH key not found at $SSH_KEY"
+    error "Run ./setup-ssh-keys.sh to generate the key"
+    exit 1
+fi
+
+###############################
+# Backup listing 
+###############################
+# Get Names Addresses and Ports in $HostsFile
+
+readarray -t lines < $HostsFile
+
+for HR in "${lines[@]}"; do
+while IFS=$' ' read -a HR ; do
+#|| [ -n "$HR" ]; do
+[[ -z ${HR[0]} ]] && continue
+
+#GEN_DATE=$(date '+%Y-%m-%d %H:%M:%S %z')
+GEN_DATE=$(date '+%d.%m.%Y')
+GEN_TIME=$(date '+%b %d %T')
+GEN_DATE_TIME=$(date '+%d.%m.%Y %T %Z')
+DStamp=$(date '+%Y%m%d')
+
+RouterName=${HR[0]}
+SSHhost=${HR[1]}
+SSHport=${HR[2]}
+SSHuser=${HR[3]}
+SSHpassword=${HR[4]}
+
+BaseDir=${HomeDir}"/backups/"${RouterName}
+TempDir=${BaseDir}"/tmp"
+HistoryDir=${BaseDir}"/history"
+LogFile="/var/log/Mikrotiks/"${RouterName}".log"
+
+SSH_OPTS="-i $SSH_KEY -o PasswordAuthentication=no -p ${SSHport}"
+SFTP_OPTS="-i $SSH_KEY -o PasswordAuthentication=no -oPort=${SSHport}"
+echo "${GEN_DATE_TIME} - Start backup script ${ARGV[0]} for ${RouterName}" >> ${LogFile}
+section "Create dirs"
+info "Create servise directories for ${RouterName}..."
+echo "${GEN_TIME} - Create services directories for ${RouterName}..." >> ${LogFile}
+mkdir -p ${BaseDir}
+mkdir -p ${TempDir}
+mkdir -p ${HistoryDir}
+echo "${GEN_TIME} - All Directories for ${RouterName} was created sucessfully!" >> ${LogFile}
+success "All directories for ${RouterName} was created sucessfully!"
+echo "${GEN_TIME} - Set variables for ${RouterName}..." >> ${LogFile}
+info "Set variables for ${RouterName}..."
+precedent_config=${BaseDir}"/Precedent-Config.rsc"
+current_config="Config.rsc"
+current_backup="Binary.backup"
+diff_config=${TempDir}"/Diff-Config.rsc"
+echo "${GEN_TIME} - Set variables for ${RouterName} success!" >> ${LogFile}
+success "Set variables for ${RouterName} success!"
+#ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} system script run MkTmpfs;
+cd ${TempDir}
+section ""
+BR 
+section "Start checkout process"
+info "Download ${current_config} file to Temp Directory..."
+echo "${GEN_TIME} - Download ${current_config} file to ${TempDir}" >> ${LogFile}
+ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} export >$current_config
+if [ $? -eq 0 ]; then
+echo
+toend_ok
+echo
+echo "${GEN_TIME} - Download complete!" >> ${LogFile}
+else
+echo
+toend_error
+echo
+echo "${GEN_TIME} - Download ${current_config} failed!" >> ${LogFile}
+exit 1
+fi
+info "Comparing with the previous config..."
+echo "${GEN_TIME} - Comparing with the previous config..." >> ${LogFile}
+diff -I "RouterOS" ${current_config} ${precedent_config} >${diff_config}
+if [ "$?" -ne "0" ]; then
+echo "${GEN_TIME} - There is a difference! Create backup..." >> ${LogFile}
+section "Create backup for ${RouterName}"
+BackupDir=${BaseDir}"/"${DStamp}
+mkdir -p ${BackupDir}
+DTStamp=$(date '+%Y%m%d%H%M%S')
+save_config=${DTStamp}"-Config.rsc"
+save_backup=${DTStamp}"-Binary.backup"
+diff_config_history=${DTStamp}"-Diff-Config.rsc"
+echo "${GEN_TIME} - Copy ${current_config} file to ${BackupDir} directory..." >> ${LogFile}
+cd ${TempDir}
+rm -f ${precedent_config}
+cp ${current_config} ${BackupDir}"/"${save_config}
+mv -f ${current_config} ${precedent_config}
+echo "${GEN_TIME} - Copy configuration to ${BackupDir}/${save_config} and ${precedent_config} success." >> ${LogFile}
+success "Copy configuration to ${BackupDir}/${save_config} and ${precedent_config} success."
+info "Create ${current_backup} file on ${RouterName}..."
+echo "${GEN_TIME} - Create ${current_backup} file on ${RouterName}..." >> ${LogFile}
+ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} system backup save name=${current_backup}
+if [ $? -eq 0 ]; then
+echo
+toend_ok
+echo
+echo "${GEN_TIME} - Create binary backup ${current_backup} on ${RouterName} success." >> ${LogFile}
+info "Start download ${current_backup} file to ${BackupDir}..."
+echo "${GEN_TIME} - Start download ${current_backup} file to ${BackupDir}..." >> ${LogFile}
+sftp ${SFTP_OPTS} ${SSHuser}@${SSHhost}:$current_backup
+sleep 1
+success "Download complete!"
+echo "${GEN_TIME} - Download complete!" >> ${LogFile}
+cd ${BackupDir}
+sleep 2
+mv -f ${TempDir}"/"${current_backup} ${save_backup}
+echo "${GEN_TIME} - Remove ${current_backup} file on ${RouterName}." >> ${LogFile}
+ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} /file remove ${current_backup}
+else
+echo
+toend_error
+echo
+echo "${GEN_TIME} - Create binary backup ${current_backup} failed!" >> ${LogFile}
+ssh ${SSH_OPTS} ${SSHuser}@${SSHhost} /file remove $current_backup
+exit 1
+fi
+cd ${TempDir}
+CurrentHistoryDir=${HistoryDir}"/"${DStamp}
+mkdir -p ${CurrentHistoryDir}
+echo "${GEN_TIME} - Move ${diff_config} file to ${CurrentHistoryDir}." >> ${LogFile}
+mv -f ${diff_config} ${CurrentHistoryDir}"/"${diff_config_history}
+echo "${GEN_TIME} - Move ${diff_config} file to ${CurrentHistoryDir} complete." >> ${LogFile}
+echo "${GEN_TIME} - Go to Git directory (${GitDir}), add backups files and commit him." >> ${LogFile}
+rm -d ${TempDir}
+cd ${GitDir}
+git add .
+echo "${GEN_TIME} - Git add commit..." >> ${LogFile}
+git commit -m "Backup for ${RouterName} sucessfully creatd at ${GEN_TIME}."
+echo "${GEN_TIME} - Done." >> ${LogFile}
+echo "${GEN_TIME} - Git push..." >> ${LogFile}
+git push origin main
+echo "${GEN_TIME} - Done." >> ${LogFile}
+echo "${GEN_TIME} - ${RouterName} backup complete!"  >> ${LogFile}
+success "${RouterName} backup complete!"
+fi
+section "The files are identical. No backup is required."
+echo "${GEN_TIME} - The files are identical. No backup is required." >> ${LogFile}
+echo "${GEN_TIME} - Remove ${diff_config} file." >> ${LogFile}
+info "Remove ${diff_config} file."
+rm -f ${diff_config}
+echo "${GEN_TIME} - Remove ${current_config} file." >> ${LogFile}
+info "Remove ${current_config} file."
+rm -f ${current_config}
+echo "${GEN_TIME} - Remove Temp directory." >> ${LogFile}
+info "Remove Temp directory."
+rm -d ${TempDir}
+section ""
+success "${RouterName} backup complete!"
+echo "${GEN_TIME} - ${RouterName} backup complete!" >> ${LogFile}
+done <<<"$(echo -e $HR)"
+done
+section "All Done!"
+echo "All Done!" >> ${LogFile}
+exit 0