Kevin
Kevin

Reputation: 123

backup script requires a pid lock to prevent multiple instances

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

Answers (2)

tripleee
tripleee

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

M. Adel
M. Adel

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

Related Questions