2021-06-09 17:04:43 +02:00
|
|
|
#!/bin/bash
|
2021-06-12 21:48:13 +02:00
|
|
|
# Copyright 2021 Luca Paris
|
|
|
|
#This file is part of masync.
|
|
|
|
|
|
|
|
#masync is free software: you can redistribute it and/or modify
|
|
|
|
#it under the terms of the GNU General Public License as published by
|
|
|
|
#the Free Software Foundation, either version 3 of the License, or
|
|
|
|
#(at your option) any later version.
|
|
|
|
|
|
|
|
#masync is distributed in the hope that it will be useful,
|
|
|
|
#but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
#GNU General Public License for more details.
|
|
|
|
|
|
|
|
#You should have received a copy of the GNU General Public License
|
|
|
|
#along with masync. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
|
2021-06-09 17:04:43 +02:00
|
|
|
source ~/bin/.synccmd.sh
|
|
|
|
SYNCFILE=~/.syncdir.sync
|
|
|
|
MYPID=$$
|
|
|
|
STATUS_RUNNING=RUNNING
|
|
|
|
STATUS_STOPPED=STOPPED
|
|
|
|
|
|
|
|
RED="\e[31m"
|
|
|
|
GREEN="\e[32m"
|
|
|
|
ENDCOLOR="\e[0m"
|
|
|
|
|
2021-06-12 21:48:13 +02:00
|
|
|
HELP_CMD_NAME='masync'
|
2021-06-10 09:33:11 +02:00
|
|
|
HELP_LOCAL_DIR="/home/$USER/localsync/"
|
|
|
|
HELP_REMOTE_DIR="remoteuser@server:/home/remoteuser/sync/"
|
2021-06-09 17:04:43 +02:00
|
|
|
|
|
|
|
myhelp() {
|
2021-06-10 14:19:57 +02:00
|
|
|
echo "Usage: ${HELP_CMD_NAME} {COMMAND} [OPTION]"
|
2021-06-09 17:04:43 +02:00
|
|
|
echo 'Description: '
|
2021-06-12 21:48:13 +02:00
|
|
|
echo -e '\tThis tool allows you to mirror and keep synchronised one or more folders on a remote server with arbitraries local folders.'
|
2021-06-09 17:04:43 +02:00
|
|
|
echo -e '\tIt has three main commands init, start, stop, remove'
|
2021-06-12 21:48:13 +02:00
|
|
|
echo -e "\tNOTE: Before using it, you must have configured ssh on your remote server!"
|
2021-06-09 17:04:43 +02:00
|
|
|
echo -e "\tthe typical use is to start a sync with the command"
|
|
|
|
echo -e "\t\t${HELP_CMD_NAME} init -l ${HELP_LOCAL_DIR} -r ${HELP_REMOTE_DIR}"
|
|
|
|
echo -e "\tAbove command starts to mirror and sync the local folder ${HELP_LOCAL_DIR} with the remote folder ${HELP_REMOTE_DIR}"
|
|
|
|
}
|
|
|
|
|
2021-06-10 09:33:11 +02:00
|
|
|
hastrailingslash() {
|
|
|
|
case "$1" in
|
|
|
|
*/)
|
|
|
|
echo true
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
echo false
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
}
|
|
|
|
|
2021-06-09 17:04:43 +02:00
|
|
|
syncexists() {
|
|
|
|
localpath_hash=$(echo "$1" | md5sum | cut -f1 --delimiter=" " -)
|
|
|
|
if [[ $(cat "${SYNCFILE}" | grep "$localpath_hash" | wc -l) -ge 1 ]]; then
|
|
|
|
echo true
|
|
|
|
else
|
|
|
|
echo false
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
initsyncpath() {
|
|
|
|
echo 'Starting initial sync...'
|
|
|
|
## write the file with remotepath and localpath for future use
|
|
|
|
localpath_hash=$(echo "$1" | md5sum | cut -f1 --delimiter=" " -)
|
|
|
|
sync $localpath_hash $2 $1
|
|
|
|
## create sync with status stopped -> after this start the loop
|
|
|
|
echo $localpath_hash "p$MYPID" w$(date +%s) $STATUS_STOPPED $1 $2 >> ${SYNCFILE}
|
|
|
|
loopsyncpath $1
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
startsyncpath() {
|
|
|
|
echo 'Starting sync...'
|
|
|
|
## write the file with remotepath and localpath for future use
|
|
|
|
localpath_hash=$(echo "$1" | md5sum | cut -f1 --delimiter=" " -)
|
|
|
|
sync $localpath_hash $2 $1
|
|
|
|
## create sync with status stopped -> after this start the loop
|
|
|
|
loopsyncpath $1
|
|
|
|
}
|
|
|
|
|
|
|
|
loopsyncpath() {
|
|
|
|
echo "loopsyncpath $1"
|
|
|
|
#echo $(sed "1q;d" ~/.syncdir.sync) | sed -e "s/STOPPED/RUNNING/"
|
|
|
|
re_num='^[0-9]+$'
|
|
|
|
if [[ $1 =~ $re_num && $1 -gt 0 ]]; then
|
|
|
|
## $1 is the index of line to substitute
|
|
|
|
nline=$1
|
|
|
|
else
|
|
|
|
## $1 is the path of sync of line to substitute
|
|
|
|
localpath_hash=$(echo "$1" | md5sum | cut -f1 --delimiter=" " -)
|
|
|
|
nline=$(grep -n $localpath_hash "$SYNCFILE" | cut -f1 -d ":")
|
|
|
|
echo $nline
|
|
|
|
fi
|
|
|
|
sed -n -s "$nline"p "$SYNCFILE" | while read hash pid when status localpath remotepath; do
|
|
|
|
if [ $status = $STATUS_RUNNING ]; then
|
|
|
|
echo 'Sync already running do nothing...'
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
## starting loop on background and catch pid
|
|
|
|
nohup syncloop.sh $hash $localpath $remotepath 1>~/syncloop_$hash.nohup 2>&1 &
|
|
|
|
mypid=$!
|
|
|
|
echo "mypid: $mypid"
|
|
|
|
when=$(date +%s)
|
|
|
|
## if line exists i must replace with new pid
|
|
|
|
sed -i -e "$nline {s/$STATUS_STOPPED/$STATUS_RUNNING/; s/p[0-9]\+/p$mypid/; s/w[0-9]\+/w$when/}" "$SYNCFILE"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
nsync() {
|
|
|
|
## find the nline of a sync starting from an hash or a number
|
|
|
|
re_num='^[0-9]+$'
|
|
|
|
if [[ $1 =~ $re_num && $1 -gt 0 ]]; then
|
|
|
|
## $1 is the index of line to substitute
|
|
|
|
nline=$1
|
|
|
|
else
|
|
|
|
## $1 is the path of sync of line to substitute
|
|
|
|
localpath_hash=$(echo "$1" | md5sum | cut -f1 --delimiter=" " -)
|
|
|
|
nline=$(grep -n $1 "$SYNCFILE" | cut -f1 -d ":")
|
|
|
|
fi
|
|
|
|
echo $nline
|
|
|
|
}
|
|
|
|
|
|
|
|
stoploopsyncpath() {
|
|
|
|
echo "stoploopsyncpath $1"
|
|
|
|
#echo $(sed "1q;d" ~/.syncdir.sync) | sed -e "s/STOPPED/RUNNING/"
|
|
|
|
nline=$(nsync "$1")
|
|
|
|
sed -n -s "$nline"p "$SYNCFILE" | while read hash pid when status localpath remotepath; do
|
|
|
|
if [ $status = $STATUS_STOPPED ]; then
|
|
|
|
echo 'Sync already stopped do nothing...'
|
|
|
|
exit 0
|
|
|
|
else
|
|
|
|
## stop process and all descendants
|
|
|
|
pid=$(echo $pid | cut -c 2-)
|
|
|
|
kill $(ps -o pid= --ppid $pid)
|
|
|
|
when=$(date +%s)
|
|
|
|
sed -i -e "$nline {s/$STATUS_RUNNING/$STATUS_STOPPED/; s/w[0-9]\+/w$when/}" "$SYNCFILE"
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
removeloopsyncpath() {
|
|
|
|
echo "removeloopsyncpath $1"
|
|
|
|
#echo $(sed "1q;d" ~/.syncdir.sync) | sed -e "s/STOPPED/RUNNING/"
|
|
|
|
nline=$(nsync "$1")
|
|
|
|
sed -n -s "$nline"p "$SYNCFILE" | while read hash pid when status localpath remotepath; do
|
|
|
|
if [ $status = $STATUS_RUNNING ]; then
|
|
|
|
echo 'Sync is running stop it and delete from tasks..'
|
|
|
|
stoploopsyncpath $nline
|
|
|
|
else
|
|
|
|
echo 'Sync is stopped delete it from tasks..'
|
|
|
|
fi
|
|
|
|
sed -i "$nline"d "$SYNCFILE"
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
emptysyncfile() {
|
|
|
|
if [[ $(cat ${SYNCFILE} | wc -l) -eq 0 ]]; then
|
|
|
|
echo true
|
|
|
|
else
|
|
|
|
echo false
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
syncoutofindex() {
|
|
|
|
if [[ $1 -gt $(cat ${SYNCFILE} | wc -l) ]]; then
|
|
|
|
echo true
|
|
|
|
else
|
|
|
|
echo false
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
if [ "$1" == '-h' ]; then
|
|
|
|
myhelp
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
|
|
|
|
case "$1" in
|
|
|
|
init)
|
|
|
|
shift
|
|
|
|
while getopts ":l:r:" option; do
|
|
|
|
case "${option}" in
|
|
|
|
l) echo "l option: ${option} value ${OPTARG}"
|
|
|
|
localpath=${OPTARG}
|
|
|
|
if [ ! -d "$localpath" ]; then
|
|
|
|
echo 'local path to sync not exists... do you want to create it?'
|
|
|
|
test_no='^(N|n)[[:alnum:]]+'
|
|
|
|
read -r ans
|
|
|
|
#no " in regular expression match
|
|
|
|
if [[ ${ans} =~ ${test_no} ]]; then
|
|
|
|
echo '... Aborting...'
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
## create path
|
|
|
|
mkdir -p "${localpath}"
|
|
|
|
fi
|
2021-06-10 09:33:11 +02:00
|
|
|
lhts=$(hastrailingslash $localpath)
|
|
|
|
if [ ${lhts} = false ]; then
|
|
|
|
localpath="${localpath}"/
|
|
|
|
fi
|
2021-06-09 17:04:43 +02:00
|
|
|
;;
|
|
|
|
r) echo "r option: ${option} value ${OPTARG}"
|
|
|
|
#match an adress in this form username@from_host:/home/test
|
|
|
|
remotepath=${OPTARG}
|
|
|
|
re_isremote='^[[:alnum:]]+\@([[:alnum:]]+|([0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})):/[[:alnum:]]+/?'
|
|
|
|
if ! [[ $remotepath =~ $re_isremote ]]; then
|
|
|
|
echo 'Incorrect format for destination path... aborting'
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
if [[ ${localpath} == "" ]]; then
|
|
|
|
cpath=$(pwd)
|
|
|
|
echo "Setting local path to ${cpath}/"
|
|
|
|
localpath=${cpath}/
|
|
|
|
fi
|
|
|
|
synce=$(syncexists ${localpath})
|
|
|
|
if [ ${synce} = true ]; then
|
|
|
|
echo 'Folder you have specified is already synched: you can only start, stop or remove sync'
|
|
|
|
cat $SYNCFILE
|
|
|
|
exit 1
|
|
|
|
else
|
2021-06-10 09:33:11 +02:00
|
|
|
rhts=$(hastrailingslash $remotepath)
|
|
|
|
if [ ${rhts} = false ]; then
|
|
|
|
remotepath="${remotepath}"/
|
|
|
|
fi
|
2021-06-09 17:04:43 +02:00
|
|
|
initsyncpath $localpath $remotepath
|
|
|
|
fi
|
|
|
|
|
|
|
|
;;
|
|
|
|
\?) myhelp
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
|
|
|
;;
|
|
|
|
start)
|
|
|
|
shift
|
|
|
|
while getopts ":l:s:" option; do
|
|
|
|
case "${option}" in
|
|
|
|
l) localsync=${OPTARG}
|
|
|
|
if [[ -d "$localsync" ]]; then
|
|
|
|
synce=$(syncexists ${localsync})
|
|
|
|
if [ ${synce} = true ]; then
|
|
|
|
echo "Sync local folder ${localsync}"
|
|
|
|
grep ${localsync} $SYNCFILE | while read hash pid when status localpath remotepath; do
|
|
|
|
startsyncpath ${localpath} ${remotepath}
|
|
|
|
done
|
|
|
|
else
|
|
|
|
echo "local folder ${localsync} not in sync task, please before use init"
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "ATTENTION Folder: $localsync not exists Aborting!"
|
|
|
|
exit 2
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
s) indexsync=${OPTARG}
|
|
|
|
empty=$(emptysyncfile)
|
|
|
|
if [ ${empty} = true ]; then
|
|
|
|
echo "Sync ${indexsync} not exists, sync file empty, please use init first"
|
|
|
|
else
|
|
|
|
oi=$(syncoutofindex $indexsync)
|
|
|
|
if [ ${oi} = true ]; then
|
|
|
|
echo "Sync ${indexsync} out of index"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
sed -n -s "$indexsync"p "$SYNCFILE" | while read hash pid when status localpath remotepath; do
|
|
|
|
startsyncpath ${localpath} ${remotepath}
|
|
|
|
done
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
\?) myhelp
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
stop)
|
|
|
|
shift
|
|
|
|
while getopts ":l:s:" option; do
|
|
|
|
case "${option}" in
|
|
|
|
l) localsync=${OPTARG}
|
|
|
|
if [[ -d "$localsync" ]]; then
|
|
|
|
#echo "Sync this local folder: $2"
|
|
|
|
synce=$(syncexists ${localsync})
|
|
|
|
if [ ${synce} = true ]; then
|
|
|
|
echo "Stopping Sync local folder ${localsync}"
|
|
|
|
stoploopsyncpath ${localsync}
|
|
|
|
else
|
|
|
|
echo "Can't stop local sync for folder ${localsync}. It is not in sync task, please before use init"
|
|
|
|
exit 2
|
|
|
|
fi
|
|
|
|
else
|
|
|
|
echo "ATTENTION Folder: ${localsync} not exists Aborting!"
|
|
|
|
exit 2
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
s) indexsync=${OPTARG}
|
|
|
|
empty=$(emptysyncfile)
|
|
|
|
if [ ${empty} = true ]; then
|
|
|
|
echo "Sync ${indexsync} not exists, sync file empty, please use init first"
|
|
|
|
else
|
|
|
|
oi=$(syncoutofindex $indexsync)
|
|
|
|
if [ ${oi} = true ]; then
|
|
|
|
echo "Sync ${indexsync} out of index"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
stoploopsyncpath $indexsync
|
|
|
|
#echo "Starting Sync ${indexsync}"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
\?) myhelp
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
list)
|
|
|
|
if [ ! -f $SYNCFILE ]; then
|
|
|
|
echo 'Sync file empty'
|
|
|
|
else
|
|
|
|
if [ $(cat $SYNCFILE | wc -l) -eq 0 ]; then
|
|
|
|
echo 'Sync file empty'
|
|
|
|
else
|
|
|
|
echo -e "$(cat $SYNCFILE | cat -n | sed -e "s/RUNNING/\\${GREEN}RUNNING\\${ENDCOLOR}/" -e "s/STOPPED/\\${RED}STOPPED\\${ENDCOLOR}/")"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
remove)
|
|
|
|
shift
|
|
|
|
while getopts ":l:s:" option; do
|
|
|
|
case "${option}" in
|
|
|
|
l) localsync=${OPTARG}
|
|
|
|
#echo "Sync this local folder: $2"
|
|
|
|
synce=$(syncexists ${localsync})
|
|
|
|
if [ ${synce} = true ]; then
|
|
|
|
echo "Removing Sync local folder ${localsync}"
|
|
|
|
removeloopsyncpath ${localsync}
|
|
|
|
else
|
|
|
|
echo "Can't remove local sync for folder ${localsync}. It is not in sync task"
|
|
|
|
exit 2
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
s) indexsync=${OPTARG}
|
|
|
|
empty=$(emptysyncfile)
|
|
|
|
if [ ${empty} = true ]; then
|
|
|
|
echo "Sync ${indexsync} not exists, sync file empty, please use init first"
|
|
|
|
else
|
|
|
|
oi=$(syncoutofindex $indexsync)
|
|
|
|
if [ ${oi} = true ]; then
|
|
|
|
echo "Sync ${indexsync} out of index"
|
|
|
|
exit 1
|
|
|
|
else
|
|
|
|
removeloopsyncpath $indexsync
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
;;
|
|
|
|
\?) myhelp
|
|
|
|
exit 1
|
|
|
|
;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
;;
|
|
|
|
*)
|
|
|
|
myhelp
|
|
|
|
exit 1
|
|
|
|
esac
|