Reputation: 123
i have a bash script that runs daily rsync incremental backups.
my problem is i end up with multipul instances running. im new to bash scripts so im not sure if i have an issue in my script? posted below.
but i have read about a pid lockfile?
could anyone show me how i would go about adding this into my script?
#!/bin/bash
PATH=/usr/lib64/qt- 3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
LinkDest=/home/backup/files/backupdaily/monday
WeekDay=$(date +%A |tr [A-Z] [a-z])
echo "$WeekDay"
case $WeekDay in
monday)
echo "Starting monday's backup"
rsync -avz --delete --exclude backup --exclude virtual_machines /home /home/backup/files/backupdaily/monday --log- file=/usr/local/src/backup/logs/backup_daily.log
;;
tuesday|wednesday|thursday|friday|saturday)
echo "Starting inc backup : $WeekDay"
rsync -avz --exclude backup --exclude virtual_machines --link-dest=$LinkDest /home /home/backup/files/backupdaily/$WeekDay --log- file=/usr/local/src/backup/logs/backup_daily.log
;;
sunday) exit 0
;;
esac
so it looks like this?
#!/bin/bash
PATH=/usr/lib64/qt- 3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
trap "rm -f /tmp/backup_daily_lockfile && exit" SIGINT SIGTERM #Put this on the top to handle CTRL+C or SIGTERM
test -f /tmp/backup_daily_lockfile && exit #before rsync to ensure that the script will not run if there is another one running
LinkDest=/home/backup/files/backupdaily/monday
WeekDay=$(date +%A |tr [A-Z] [a-z])
echo "$WeekDay"
touch /tmp/backup_daily_lockfile #Before the rsync
case $WeekDay in
monday)
echo "Starting monday's backup"
rsync -avz --delete --exclude backup --exclude virtual_machines /home /home/backup/files/backupdaily/monday --log-file=/usr/local/src/backup/logs/backup_daily.log
;;
tuesday|wednesday|thursday|friday|saturday)
echo "Starting inc backup : $WeekDay"
rsync -avz --exclude backup --exclude virtual_machines --link-dest=$LinkDest /home /home/backup/files/backupdaily/$WeekDay --log-file=/usr/local/src/backup/logs/backup_daily.log
;;
sunday) exit 0
;;
rm -f /tmp/backup_daily_lockfile #After the rsync
esac
Upvotes: 1
Views: 554
Reputation: 189607
Your proposed solution has a race condition. If two instances are running at approximately the same time, they could both execute the test
before either of them gets to the touch
. Then they will end up overwriting each others' files after all.
The proper fix is to use an atomic test and set. A common and simple solution is to use a temporary directory instead, and exit if mkdir
fails; otherwise, you have the lock.
# Try to grab lock; yield if unsuccessful
mkdir /tmp/backup_daily_lockdir || exit 1
# We have the lock; set up to remove on exit
trap "rmdir /tmp/backup_daily_lockdir" EXIT
# Also run exit trap if interrupted
trap 'exit 127' SIGINT SIGTERM
: the rest of your script here
There are other common solutions, but this has no external dependencies and is very easy to implement and understand.
Upvotes: 1
Reputation: 407
Add the following to your script:
trap "rm -f /tmp/lockfile && exit" SIGINT SIGTERM #Put this on the top to handle CTRL+C or SIGTERM
test -f /tmp/lockfile && exit #Before rsync to ensure that the script will not run if there is another one running
touch /tmp/lockfile #Before the rsync
rm -f /tmp/lockfile #After the rsync
rename the lock file path/name according to your needs, you can also name it with the current PID using $$ variable.
Upvotes: 0