#!/bin/bash

# script to help determine what is using backup space
# written by Adrian Bridgett

topdir="/var/lib/backuppc"
#topdir="/home/gbr/projects/it"
hostsfile="/etc/backuppc/hosts"
#hostsfile="/home/gbr/projects/it/hosts"
friday="Fri"
december="Dec"
pretend="1"        # if this is '1' then we'll only pretend to prune
deletenonconforming="1"   # delete any backups that don't conform to Fridays, end of month, end of year
keepmonthly=15    # keep slightly more months than in a year
keepyearly=4
keepweekly=10     # keep slightly more weeks than in two months
cutoffyear=2009   # anything older than this, we don't touch
email="gbr@majentis.com"


set -e

usage()
{
  cat <<EOF
Usage: `basename $0` -a|-h hostname [-i|-f]

reports backup stats for all hosts or a single host.
will report last five incrementals [-i or default]
or last five full backups [-f]

EOF
  exit 1
}

main()
{
  hosts=""
#  while getopts "ah:if" opt; do
#    case "$opt" in
#      h) hosts="$hosts $OPTARG";;
#      a) hosts=`/bin/ls "$topdir/pc"`;;
#      i) type="incr";;
#      f) type="full";;
#    esac
#  done
#  shift $(($OPTIND - 1))

#  [ "$hosts" ] || usage

  if [ -f /tmp/backup.list ]
  then
    rm /tmp/backup.list
  fi
  touch /tmp/backup.list

  if [ -f /tmp/backup.date ]
  then
    rm /tmp/backup.date
  fi
  touch /tmp/backup.date

  if [ -f /tmp/backup.delete ]
  then
    rm /tmp/backup.delete
  fi
  touch /tmp/backup.delete

#  keepyearly=$(($keepyearly + 1))
#  echo keepyearly $keepyearly

  # get all hosts in the host file 
  for HOST in $(cat $hostsfile | grep ^[A-Za-z0-9] | grep -v host | awk '{print $1}')
  do
    print_stats $HOST
  done

  # go through the known backups file for all hosts
  while read line; 
  do
    parse_date $line
  done < /tmp/backup.list

  # get all the Fridays into one file, and the non Fridays into another
  cat /tmp/backup.date | grep -v "$friday" > /tmp/backup.notfri
  cat /tmp/backup.date | grep "$friday" > /tmp/backup.valid

  # go through the non fridays and look for the last day of the month
  while read line; 
  do
    parse_lastday $line
  done < /tmp/backup.notfri
  
  # go through the delete file, and delete the backups
  echo "Deleting invalid date backups..."
  if [ $deletenonconforming -eq "1" ]
  then
    if [ $pretend -eq "1" ]
    then
    
      if [ -f /tmp/mail.delete ]
      then
        rm /tmp/mail.delete
      fi
      echo "These are the delete commands I would have run:" > /tmp/mail.delete
      echo " " >> /tmp/mail.delete
      echo "Deleting invalid date backups..."  >> /tmp/mail.delete
      echo " " >> /tmp/mail.delete

    fi
    
    while read line
    do
      delete_backup $line
    done < /tmp/backup.delete
  fi
  
  # go through the valid file and delete anything too old
  echo "Deleting expired backups..."
  echo " " >> /tmp/mail.delete
  echo "Deleting expired backups..." >> /tmp/mail.delete
  echo " " >> /tmp/mail.delete

  while read line
  do
    age_backup $line
  done < /tmp/backup.valid
  
  

  /usr/lib/sendmail -i $email < /tmp/mail.delete  
  
}

# get all the backups known for the passed in host and save in file /tmp/backup.list
print_stats()
{
  local host="$1"

  echo HOST: $host  

  grep "full" "$topdir/pc/$host/backups" | \
  
  awk -v host=$host 'BEGIN { }
         {printf "%d %d %s\n", $1, $3, host}' >> /tmp/backup.list
 
}

# convert the date in seconds to date text and save in file /tmp/backup.date
parse_date()
{
  local number=$1
  local secs=$2
  local host=$3

  date=$(perl -e "print scalar(localtime($secs))")

  # get the components I want
  day=$(echo $date | awk '{print $1}')
  month=$(echo $date | awk '{print $2}')
  year=$(echo $date | awk '{print $5}')
  num=$(echo $date | awk '{print $3}')
  
  echo $day $num $month $year $number $host $secs >> /tmp/backup.date
}


# if a day is the last day of the month, attach it to the valid file other it goes into the delete file
parse_lastday()
{
   local day=$1
   local num=$2
   local month=$3
   local year=$4
   local number=$5
   local host=$6
   local sec=$7

   # get the last work day of the month
#   last=$(cal $month $year | awk '{ print $2, $3, $4, $5, $6 }' | tr -s '[:blank:]' '\n' | tail -n1)
   last=$(cal $month $year | tr -s '[:blank:]' '\n' | tail -n1)

   # if the date is the last workday of the month, save it as well   
echo last workday: $last  $num
   if [ $last -eq $num ]
   then
     echo $day $num $month $year $number $host $sec >> /tmp/backup.valid
   else
     echo $day $num $month $year $number $host $sec >> /tmp/backup.delete
   fi
   
}

# delete the backup passed in
delete_backup()
{
   local day=$1
   local num=$2
   local month=$3
   local year=$4
   local number=$5
   local host=$6
   local secs=$7
   
   
   # special case anything in 'cutoffyear' or older is skipped, since we put this backup planinto place in 2010
   if [ $year -gt $cutoffyear ]
   then
     if [ $pretend -eq "1" ]
     then
       echo "/usr/share/backuppc/bin/BackupPC_manualDelete -c $host -d $number  DATE: $day  $year-$month-$num" >> /tmp/mail.delete
     else
#       /usr/share/backuppc/bin/BackupPC_manualDelete -c $host -d $number
       echo
     fi
   fi
}


age_backup()
{
   local day=$1
   local num=$2
   local month=$3
   local year=$4
   local number=$5
   local host=$6
   local secs=$7
   
   # get the current date in seconds since 1970, and separate (date format: Sun Jan 31 13:09:54 CST 2010)
   local now=$(date +"%s")
   local nowday=$(date | awk '{print $1}')
   local nowmonth=$(date | awk '{print $2}')
   local nowyear=$(date | awk '{print $6}')

   local oneday=86400
   local oneweek=604800

   # expire the weeklys
   temp=$(($oneweek * $keepweekly))
   weekkeep=$(($now - $temp))   
   if [ $secs -lt $weekkeep ]  # if the timestamp is more than $keepweekly weeks away from current
   then
     # the backup is past our week count, is it a month end

     # get the last day of the month
     last=$(cal $month $year | tr -s '[:blank:]' '\n' | tail -n1)
     
     if [ $num -ne $last ]      # so, we are not the last day of a month
     then
       delete_backup $day $num $month $year $number $host $secs
       echo Week: $day  $year-$month-$num  SECS:$secs  KEEP:$weekkeep  NOW:$now   $temp
       return
     fi
   fi  

   # expire the monthly (we don't do December, yearly takes care of that)
   echo Checking Month...
   if [ $month != $december ]
   then
     delmonth=0
     delyear=$year
     monthname=$month
     monthnum=0
     $(monthtonum)   # convert month to number
     echo Month Number: $monthnum
     temp=$(($monthnum - $keepmonthly))
echo delmonth temp $temp

     delmonth=$temp
     while [ $delmonth -lt 1 ]
     do
       delmonth=$((12 + $delmonth))     # get the right month
       delyear=$(($delyear - 1))    # and go to the previous year
     done
     
     # get last day of delete month
     last=$(cal $month $year | tr -s '[:blank:]' '\n' | tail -n1)
     delsecs=$(date --date $delyear-$delmonth-$last +"%s")   # convert date to seconds since 1970
     
     # if the timestamp is less than our delete date
     if [ $secs -lt $delsecs ]
     then
       delete_backup $day $num $month $year $number $host $secs
#       echo Month: $day  $year-$month-$num  SECS:$secs  KEEP:$weekkeep  NOW:$now   $temp
       return
     fi
   fi
   
   # we'll expire the years
   # if the year isn't our currrent year, and month isn't December, then delete
   echo Checking Year...
   if [ $year -lt $nowyear ]   # is the passed in year less than the current year?
   then
     if [ $month != $december ]  # is the month not December
     then
       delete_backup $day $num $month $year $number $host $secs
#       echo Year: $day  $year-$month-$num
       return
     else   # month IS December
       temp=$(($nowyear - $keepyearly))   # claculate cut off year
       if [ $year -lt $temp ]     # year is past our cutoff
       then
         delete_backup $day $num $month $year $number $host $secs
       fi
     fi
   fi
   
   # get the last work day of the month
#   last=$(cal $month $year | awk '{ print $2, $3, $4, $5, $6 }' | tr -s '[:blank:]' '\n' | tail -n1)

   # if the date is the last workday of the month, check it's age
#   if [ $last -eq $num ]
#   then
#      diff=( $now - $secs )
#      echo Monthly delete: $diff
#   else
#      diff=( $now - $secs )
#      echo Weekly delete: $diff
#   fi
   
}


# This function expects English Style months
monthtonum()
{
  if [ $month = "Jan" ]
  then
    monthnum=1
  fi
  
  if [ $month = "Feb" ]
  then
    monthnum=2
  fi
  
  if [ $month = "Mar" ]
  then
    monthnum=3
  fi
  
  if [ $month = "Apr" ]
  then
    monthnum=4
  fi
  
  if [ $month = "May" ]
  then
    monthnum=5
  fi
  
  if [ $month = "Jun" ]
  then
    monthnum=6		
  fi
  
  if [ $month = "Jul" ]
  then
    monthnum=7
  fi
  
  if [ $month = "Aug" ]
  then
    monthnum=8
  fi
  
  if [ $month = "Sep" ]
  then
    monthnum=9
  fi
  
  if [ $month = "Oct" ]
  then
    monthnum=10
  fi
  
  if [ $month = "Nov" ]
  then
    monthnum=11
  fi
  
  if [ $month = "Dec" ]
  then
    monthnum=12
  fi

  echo monthtonum $monthnum
}

main "$@"

