Ad-hoc remote backups to tape
I have a nice SCSI tape connected to a single server. This allows for on-demand backups, with the hope (and seldom, with the established knowledge) that I can recover the data I have there.
Old computers, decommissioned computers and systems I wish to erase and reuse are seldom backed-up, just because of the effort in doing it. I will need to manually run something or the other, and who wants this chore?
I know that there are many full-featured backup systems out there, OSS and all, with the capability of doing what I want to do, however, these commonly use backup agents, tape formats and what’s more, just to make a simple one-time backup (which is what I want) – it looked too bloated for my needs.
Again – my needs are: take this machine, run a simple script which can be obtained from an NFS share, wait for X minutes doing something else, and be assured your system is backed up.
I have written the script below to satisfy these requirements. Hope it helps others. Notice the single SSH leading connection and its functionality. It leaves a raw text file on tape with a simple description of the backup process, and the next tracks are the contents of each mount point.
I was a bit spartan with comments, but in general, this script should be quite self-explanatory:
#!/bin/bash
# This script will backup local disk to remote tape
# Written by Ez-Aton - http://run.tournament.org.il/
SERVER=kruvi # The name of the server with the direct attached tape
SRV_USER=root
TAPE=/dev/nst0 # Non-rewinding tape. We need to be able to add more tracks and not overwrite our own track
SSH="ssh -o StrictHostKeyChecking=no -o ControlMaster=auto -o ControlPath=~/.ssh/socket-%r@%h:%p"
WORK_FILE=/tmp/work.$$
TAR_LOG=/tmp/backup.log
TAR_ARG="czf - --one-file-system"
MOUNTS=`df -TlP | grep -v tmpfs | tail -n +2 | awk '{print $7}'`
# Assume nobody is stupid enough to use white spaces in mount paths
NUM_MOUNTS=`echo $MOUNTS | wc -w`
SUM_FILE=/tmp/summery.txt
clean_log () {
: > $TAR_LOG
}
first_disk () {
# Assume first disk is the first entry in /proc/partitions
DISK="/dev/`cat /proc/partitions | head -n 3 | tail -n 1 | awk '{print $4}'`"
}
create_sum () {
echo "Creating summery"
# Collect information and place it in the file. It will be the first track of the tape
echo "Hostname: `hostname`" > $SUM_FILE
echo >> $SUM_FILE
date >> $SUM_FILE
echo >> $SUM_FILE
for i in $MOUNTS; do df -h $i | tail -n +2 >> $SUM_FILE ; done
echo >> $SUM_FILE
echo "There will be $(($NUM_MOUNTS + 1)) tracks in addition to the first one" >> $SUM_FILE
}
create_leading_ssh () {
# Use a nice trick for giving password only once:
$SSH -f $SRV_USER@$SERVER 'while true; do sleep 100; done'
echo "post leading"
}
monitor_proc () {
# Monitor SSH process
# Run in the background
touch $WORK_FILE
PID=`ps aux | grep "$SSH" | grep -v grep | awk '{print $2}'`
if [ -z "$PID" ]
then
echo "Done so soon?"
return 1
fi
while [ -f $WORK_FILE ]
do
sleep 10
done
kill $PID
}
test_tape_cmd () {
CMD="mt -f $TAPE status"
}
remote_tape_append () {
CMD="cat > $TAPE"
}
test_tape () {
test_tape_cmd
if ! $SSH $SRV_USER@$SERVER $CMD
then
echo "Tape on $SERVER is not ready"
exit 1
fi
}
backup_mount () {
# Backup the actual mount
# $1 - the path of the mount
remote_tape_append
if [ -z "$1" ]
then
echo "Mount path is empty?"
exit 1
fi
echo "Backing up $1"
cd "$1"
tar $TAR_ARG . | $SSH $SRV_USER@$SERVER "$CMD" > $TAR_LOG 2>&1
}
append_header () {
remote_tape_append
cat $SUM_FILE | $SSH $SRV_USER@$SERVER "$CMD"
}
add_mbr () {
remote_tape_append
first_disk
if [ -z "$DISK" ]
then
echo "Can't decide on the first boot disk. Exiting now"
echo "No MBR backup exists"
exit 0
fi
echo "Backing MBR"
dd if=$DISK bs=1M count=1 | $SSH $SRV_USER@$SERVER "$CMD"
}
create_sum
create_leading_ssh
monitor_proc &
test_tape
append_header
for i in $MOUNTS
do
backup_mount $i
done
add_mbr
rm $WORK_FILE
