#!/bin/bash # Copyright (C) 2009-2010 Stelios Stavroulakis # sabaki # sabaki 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. # sabaki 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 sabaki. If not, see . # run as root: ./sabaki bus:devnum [dir1 dir2 dir3 ...] # dir1, dir2, dir3 should be the full paths to dir1, dir2, dir3 # to see the exit status, run as root: echo $? VERSION="0.2" TODAY=`date '+20%y%m%d'` startdir=/root/taisabaki tempdir=/tmp setup_file=$startdir/sabaki_setup.txt trg_min_limit=512 bkp_start_date=`date '+20%y%m%d %R'` file=$startdir/sabaki_last.txt bkp_msg_file=$startdir/sabaki_messages.txt magic_file=$startdir/.magicnum exclude_file=$startdir/exclude.txt temp_file=$startdir/temp1 host=`hostname` process=`ps -e | grep -c sabaki` if [ "$process" -gt "2" ] ; then exit 1 fi if [ ! -e $startdir ] ; then mkdir $startdir fi if [ ! -e $exclude_file ] ; then touch $exclude_file fi # read command line params i=0 for WORD in "$@"; do clp[$i]=$WORD i=`expr $i + 1` done max=$i if [ "$max" -eq "0" ] ; then echo "no arguments defined - backup interrupted" >> $bkp_msg_file exit 2 fi if [ "${clp[0]}" == "--version" ] ; then echo "sabaki $VERSION" exit 0 fi if [ "${clp[0]}" == "--print" ] ; then if [ -e $setup_file ] ; then cat $setup_file fi exit 0 fi if [ "${clp[0]}" == "--add" ] ; then if [ "$max" -eq "2" ] ; then echo "${clp[1]}" >> $setup_file fi exit 0 fi if [ "${clp[0]}" == "--magic" ] ; then if [ ! -e $magic_file ] ; then echo `< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16` >> $magic_file else rm $magic_file echo `< /dev/urandom tr -dc _A-Z-a-z-0-9 | head -c16` >> $magic_file fi exit 0 fi if [ "${clp[0]}" == "--msg" ] ; then if [ -e $bkp_msg_file ] ; then cat $bkp_msg_file fi exit 0 fi if [ -e $temp_file ] ; then rm $temp_file fi if [ "${clp[0]}" == "--replace" ] ; then if [ "$max" -eq "2" ] ; then sed "s/${clp[1]}//g;/^$/d" $setup_file > $temp_file mv $temp_file $setup_file fi if [ "$max" -eq "3" ] ; then sed "s/${clp[1]}/${clp[2]}/g;/^$/d" $setup_file > $temp_file mv $temp_file $setup_file fi exit 0 fi if [ -e $temp_file ] ; then rm $temp_file fi if [ -e $bkp_msg_file ] ; then rm $bkp_msg_file fi echo "start date : $bkp_start_date" >> $bkp_msg_file # check last backup date if [ -e $file ] ; then last_date=`cat $file | awk '{print $1}'` if [ "$last_date" == "$TODAY" ] ; then echo "configured to run in a host once a day - backup interrupted" >> $bkp_msg_file exit 3 fi fi srcdir=/home bkp_src_index=0 if [ "$max" -gt "1" ] ; then bkp_src_index=1 fi # check that the usb bus:devnum contains the colon char sub=`expr index "${clp[0]}" :` if [ "$sub" -eq "0" ] ; then echo "target is not defined - backup interrupted" >> $bkp_msg_file exit 4 else # check if usb dev is connected TEMP= RES=`lsusb | grep ${clp[0]}` if [ "$RES" == "$TEMP" ] ; then echo "target is not connected - backup interrupted" >> $bkp_msg_file exit 5 fi mountdir=/media fi # check that bus:devnum is within setup if [ "${clp[0]}" != "" ] ; then dev_in_setup=`grep -c ${clp[0]} $setup_file` if [ "$dev_in_setup" -eq "0" ] ; then echo "bus:devnum not in setup - backup interrupted" >> $bkp_msg_file exit 6 fi fi # find the mounted devices lines=`/sbin/fdisk -l | awk '{print $1}' | grep dev | awk 'END{print NR}'` for ((i=0;i<$lines;i+=1)); do j=`expr $i + 1` mdev[$i]=`/sbin/fdisk -l | awk '{print $1}' | grep dev | awk -v db=$j 'NR == db'` done # find the boot device bdev=`/sbin/fdisk -l | grep \* | grep dev | awk '{print $1}'` # use bdev to exclude all sda devices from mountpoint search for magicnum # exclude from mount points the partitions that are similar to boot partition len=`expr length $bdev` if [ "$len" -gt "6" ] ; then len=`expr $len - 1` sub_bdev=${bdev:0:$len} else echo "unusual source partitions - please check manually - backup interrupted" >> $bkp_msg_file exit 7 fi j=0 for ((i=0;i<$lines;i+=1)); do len=`expr length ${mdev[$i]} - 1` sub_mdev=${mdev[$i]:0:$len} if [ "$sub_mdev" != "$sub_bdev" ] ; then k=6 maxm=10 for ((m=0;m<$maxm;m+=1)); do mpoint[$m]=`df | grep "$sub_mdev" | awk -v db=$k '{print $db}'` if [ "${mpoint[$m]}" == "" ] ; then break fi k=`expr $k + 1` done spaces=`expr $k - 6 - 1` if [ "$spaces" -gt "3" ] ; then echo "ridiculously many spaces in mount point - backup interrupted" >> $bkp_msg_file exit 8 fi if [ "$spaces" -eq "0" ] ; then mount_point[$j]=`df | grep ${mdev[$i]} | awk '{ print $6 }'` fi if [ "$spaces" -eq "1" ] ; then mount_point[$j]=`df | grep ${mdev[$i]} | awk '{ print $6, $7 }'` fi if [ "$spaces" -eq "2" ] ; then mount_point[$j]=`df | grep ${mdev[$i]} | awk '{ print $6, $7, $8 }'` fi if [ "$spaces" -eq "3" ] ; then mount_point[$j]=`df | grep ${mdev[$i]} | awk '{ print $6, $7, $8, $9 }'` fi j=`expr $j + 1` fi done mplen=$j if [ ! -e $magic_file ] ; then echo "magic file is missing - backup interrupted" >> $bkp_msg_file exit 9 fi # find the mount point corresponding to the target with the right magic number j=0 num=0 count=0 flag=0 for ((i=0;i<$mplen;i+=1)); do if [ -e "${mount_point[$i]}/.magicnum" ] ; then tmagic=`cat "${mount_point[$i]}/.magicnum" | awk '{print $1}'` if [ "$tmagic" != "" ] ; then mlen=`expr length $tmagic` if [ "$mlen" -ne "16" ] ; then echo "16 is the right length for the magic number - backup interrupted" >> $bkp_msg_file exit 10 fi flag=1 num=`grep -c $tmagic $magic_file` if [ "$num" -gt "0" ] ; then count=`expr $count + 1` mindex[$j]=$i j=`expr $j + 1` fi fi fi done if [ "$flag" -eq "0" ] ; then echo "no magic number in mount points - backup interrupted" >> $bkp_msg_file exit 11 fi if [ "$flag" -eq "1" ] ; then if [ "$count" -eq "0" ] ; then echo "no matching magic number in target - backup interrupted" >> $bkp_msg_file exit 12 fi fi if [ "$count" -gt "1" ] ; then echo "identical magic numbers in mount points - backup interrupted" >> $bkp_msg_file exit 13 fi selected_mount_point=${mount_point[${mindex[0]}]} mp_host_file=$selected_mount_point/.sabaki_host smpoint_len=`expr length "$selected_mount_point"` if [ "$smpoint_len" -gt "32" ] ; then echo "mount point is too long - backup interrupted" >> $bkp_msg_file exit 14 fi bkp_msg_file2=$selected_mount_point/sabaki_messages.txt if [ ! -e "$mp_host_file" ] ; then echo "no host file in mount point - backup interrupted" >> $bkp_msg_file exit 15 else mphost=`cat "$mp_host_file" | awk '{print $1}'` if [ "$mphost" != "$host" ] ; then echo "no host in mount point - backup interrupted" >> $bkp_msg_file exit 16 fi fi # compute backup source space usage bkp_src_usage=0 if [ "$bkp_src_index" -eq "1" ] ; then for ((i=$bkp_src_index;i<$max;i+=1)); do cap=`du -s "${clp[$i]}" 2>/dev/null | awk '{print $1}'` bkp_src_usage=$[$bkp_src_usage + $cap] done else bkp_src_usage=`du -s $srcdir 2>/dev/null | awk '{print $1}'` fi # compute backup target capacity bkp_trg_cap=`df "$selected_mount_point" | awk '{ field = $2 }; END { print field }'` # compute backup target usage bkp_trg_usage=`df "$selected_mount_point" | awk '{ field = $3 }; END { print field }'` # compute backup target avail bkp_trg_avail=`df "$selected_mount_point" | awk '{ field = $4 }; END { print field }'` if [ "$bkp_src_usage" -ge "$bkp_trg_cap" ] ; then echo "insufficient target capacity - backup interrupted" >> $bkp_msg_file exit 17 fi if [ -e "$bkp_msg_file2" ] ; then rm "$bkp_msg_file2" fi if [ -e $file ] ; then rm $file fi IFS=$'\n' if [ ! -e "$selected_mount_point/$host" ] ; then mkdir "$selected_mount_point/$host" fi if [ "$bkp_src_index" -eq "1" ] ; then for ((i=$bkp_src_index;i<$max;i+=1)); do rsync -rRupt --safe-links --whole-file --exclude-from=$exclude_file "${clp[$i]}" "$selected_mount_point/$host" 1>/dev/null 2>&1 done else rsync -rRupt --safe-links --whole-file --exclude-from=$exclude_file $srcdir "$selected_mount_point/$host" 1>/dev/null 2>&1 fi bkp_trg_avail=`df "$selected_mount_point" | awk '{ field = $4 }; END { print field }'` lim=`expr $bkp_trg_avail \* 100 / $bkp_trg_cap` if [ "$lim" -eq "0" ] ; then echo "Warning: target almost full" >> $bkp_msg_file fi bkp_end_date=`date '+20%y%m%d %R'` echo "end date : $bkp_end_date" >> $bkp_msg_file echo $bkp_end_date >> $file cp $bkp_msg_file "$selected_mount_point" exit 0