#!/bin/sh
# backup sys
# Backup system files.
#
# (c) 2004, Eko M. Budi, for VLocity Linux
# Released under GNU GPL
#

usage(){
clear
cat<<EOF
backupsys - backup or restore system files

This utility is designed to backup/restore VLocity Linux system files.
The backup can be done manually, or using cron daemon automatically.
The restore will be manual, or when you reinstall VLocity Linux.

Usage: backupsys <command> [option] [files ...] 
Command is one of:
  -b, --backup    : backup to the backup-archive (default)
  -r, --restore   : restore files from the backup archive
  -d, --diff      : list the files that need to be backup
  -l, --list      : list files in the backup
  -h, --help      : shows this message
Option is:
  -u, --update     : backup/restore newer files only
  -f, --file <name>: archive name for restore, default from config file
  files            : files to restore
Common examples:
  backupsys                 : backup
  backupsys -b -u           : backup newer only
  backupsys -r -u           : restore newer only
  backupsys -r /etc/passwd  : restore a file only
Configuration files:
/etc/backupsys              : the main configuration
/etc/cron/daily/zbackupsys  : cron entry
EOF
}

message()
{
cat<<EOF
This directory contains the system backup, created by backupsys.
The file name convention is:

   VOLUME-VERSION-LEVEL.tar.bz2.

VOLUME : the volume name, usually the hostname
VERSION: backup version, usually the distro version
LEVEL  : backup number, 0 is the newest
 
Some tips:
* If you want to activate the backupsys automatically each day,
  use VASM, select FILE SYSTEM menu the BACKUPSYS,
  or directly call vbackupsys or backupsys.

* If you want more control edit /etc/backupsys.conf.

* The easiest way to see the contents of each volume is
  using mc (midnight commander). 
  
* You can restore the backup using vbackupsys.

* VLocity Linux installer can use this information during install.

EOF
}


LOG_FILE=/var/log/backupsys.log
LOG_ROTATE=200

echol() {
    echo "$*"
    echo $* >> $LOG_FILE
}

log_start() {
    local LOG_GO=""
    echol "Backupsys on `date`"
    mv $LOG_FILE $LOG_FILE.bak
    tail -n $LOG_ROTATE $LOG_FILE.bak | while read LINE; do
	if [ "$LOG_GO" ]; then
	    echo "$LINE" >> $LOG_FILE
	elif [ "`echo $LINE | cut -f-2 -d ' '`" = "Backupsys on" ]; then
	    echo "$LINE" > $LOG_FILE
	    LOG_GO=1
	fi
    done
}

if [ ! -r /etc/backupsys.conf ]; then
    echol "No /etc/backupsys.conf. Do nothing then."
    exit 0 
fi

VOLNAME=backupsys
VOLVERSION=0.0
BACKUP_GROUP=adm
BACKUP_MNT="/home"
BACKUP_DIR="backupsys"

. /etc/backupsys.conf

BACKUP_FILE=""
BACKUP_BASE=""
ARCH_SUFFIX="tar.bz2"
BACKUP_TEMP=`mktemp -qd /var/tmp/backupsys.XXXXXX`
if [ $? != 0 ]; then
    echol "ERROR: Cannot create temporary directory."
    exit 1
fi

clean_exit()
{
    rm -rf $BACKUP_TEMP
    exit $1
}

if [ $BACKUP_LEVEL -lt 0 ]; then
    BACKUP_LEVEL=0
fi
if [ $BACKUP_LEVEL -gt 9 ]; then
    BACKUP_LEVEL=9
fi

####################################################
# The engine
explode_backup() {
    if [ -f $1 ]; then
	tar -xjf $1 2>&1
#        if [ -f backup/symlinks.sh ]; then
#	    . backup/symlinks.sh
#        fi
    fi
}

make_backup() {
    # make symlinks creation script
#    echo '#!/bin/sh' > backup/symlinks.sh
#    find . -type l -print | while read LINE; do
#      DNAME="`dirname $LINE`"
#      LNAME="`basename $LINE`"
#      LTO="`readlink $LINE`"
#      echo "(cd $DNAME; rm -rf $LNAME; ln -sf $LTO $LNAME)" >> backup/symlinks.sh
#      rm -f $LINE
#    done
    tar -cjf $1 .  2>&1
    chmod 660 $1
    chgrp $BACKUP_GROUP $1
}

##################################################
# Backup routines
mount_backup()
{
    if [ "$BACKUP_DEV" ]; then
	if ! mount | grep -qe "^$BACKUP_DEV "; then
	    mount $BACKUP_DEV $BACKUP_MNT -t $BACKUP_FS >/dev/null 2>&1
	    if [ $? = 0 ]; then
		echol "ERROR: Cannot mount $BACKUP_DEV"
		clean_exit 1
	    fi
	fi
    fi
}

# find backup file
find_backup()
{
    if [ ! -d $BACKUP_MNT ]; then
    	echol "ERROR: Base directory $BACKUP_MNT does not exist."
	clean_exit 1
    fi
    BACKUP_BASE=$BACKUP_MNT/$BACKUP_DIR
    VOLSHORT=$VOLNAME-$VOLVERSION
    mkdir -p $BACKUP_BASE
    chmod 770 $BACKUP_BASE
    chgrp $BACKUP_GROUP $BACKUP_BASE
    BACKUP_FILE=$BACKUP_BASE/$VOLSHORT-0.$ARCH_SUFFIX
}

# this is a recursive procedure
# increment_backup <level>
increment_backup()
{
    (
    cd $BACKUP_BASE
    local NUM1=$1
    local NUM2=`expr $NUM1 '+' 1`
    if [ -f $VOLSHORT-$NUM1.$ARCH_SUFFIX ]; then
	if [ $NUM2 -lt $BACKUP_LEVEL ]; then
	    increment_backup $NUM2
	fi
	mv -f $VOLSHORT-$NUM1.$ARCH_SUFFIX $VOLSHORT-$NUM2.$ARCH_SUFFIX
	echol "Increment $VOLSHORT-$NUM1.$ARCH_SUFFIX"
    fi
    )
}

# this procedure run on BACKUP_TEMP
backup_file()
{
    [ "$UPDATE" ] && [ $1 -ot ./$1 ] && return 1
    DIRNAME=`dirname $1`
    mkdir -p ./$DIRNAME
    cp -a $1 ./$1
    echol "Backup $1" 
    NEWER_FOUND=1
}

backup_quick()
{
    log_start
    NEWER_FOUND=""
    local UPDATE=""
    while [ $1 ]; do
	case $1 in
	    -u|--update)
		UPDATE="-u"
		;;
	esac
	shift
    done
    [ -z "$UPDATE" ] && increment_backup

    (
    cd $BACKUP_TEMP; 
    explode_backup $BACKUP_FILE
    for F1 in $SRCLIST; do
	for F2 in $F1; do
	    if [ -d $F2 ]; then
		find $F2 -type l | while read LINE; do
		    backup_file $LINE
		done
		find $F2 -type f | while read LINE; do
		    backup_file $LINE
		done
	    elif [ -h $F2 ]; then
		backup_file $F2
	    elif [ -f $F2 ]; then 
		backup_file $F2
	    fi
	done
    done
    if [ "$NEWER_FOUND" ]; then
	make_backup $BACKUP_FILE
	echol "Add volume $BACKUP_FILE"
	if [ ! -f $BACKUP_BASE/README ]; then
	    message > $BACKUP_BASE/README
	fi
    else
	echol "Volume $BACKUP_FILE is up to date."
    fi
    )
}

restore_link()
{
    [ "$UPDATE" ] && [ /$1 -nt $1 ] && return 0
    rm -f /$1
    cp -a $1 /$1
    echol "Relink $1"
}

restore_file()
{
    if [ -h $1 ]; then
	restore_link $1
    elif [ -f $1 ]; then
	[ "$UPDATE" ] && [ /$1 -nt $1 ] && return 0
	mkdir -p `dirname $1`
	rm -f /$1
	cp -a $UPDATE $1 /$1
	echol "Restore $1"
    else
	echol "ERROR: cannot find $1"
    fi
}

restore()
{
    log_start
    local UPDATE=""
    while [ $1 ]; do
	case $1 in
	    -u|--update)
		UPDATE="-u"
		shift
		;;
	    -f|--file)
		shift
		BACKUP_FILE=$1
		shift
		;;
	    *)
		break
		;;
	esac
    done
    echol "Volume=$BACKUP_FILE"
    (cd $BACKUP_TEMP
    explode_backup $BACKUP_FILE
    if [ "$*" ]; then
	for F1 in $@; do
	    for F2 in .$F1; do
		if [ -d $F2 ]; then
		    find $F2 -type l | while read LINE; do
			restore_link $LINE
		    done
		    find $F2 -type f | while read LINE; do
			restore_file $LINE
		    done
		else
		    restore_file $F2
		fi
	    done
	done
    else
	find -type l | while read LINE; do
	    restore_link $LINE
	done
	find -type f | while read LINE; do
	    restore_file $LINE
	done
    fi
    )
    rm -rf $BACKUP_TEMP
}

diff_backup() {
    while [ $1 ]; do
	case $1 in
	    -f|--file)
		shift
		;;
	    *)
		BACKUP_FILE=$1
		break
		;;
	esac
    done
    (cd /; tar -djf $BACKUP_FILE 2>/dev/null | grep -ve '^.:' | cut -f2- -d .)
}

list_backup() {
    while [ $1 ]; do
	case $1 in
	    -f|--file)
		shift
		;;
	    *)
		BACKUP_FILE=$1
		break
		;;
	esac
    done
    tar -tjf $BACKUP_FILE | grep -v "^./backup" | cut -f2- -d . | sort
}


################################################
# MAIN PROG
find_backup
CMD=$1
shift
case $CMD in
    --backup-cron)
	if [ "$CRON_ACTIVATED" = "1" ]; then
	    backup_quick $@
	else
	    echol "Cron backup is not activated"
	fi
	;;
    --update|-u)
	backup_quick -u
	;;
    --backup|-b|"")
	backup_quick $@
	;;
   --restore|-r)
	restore $@
	;;
   --diff|-d)
	diff_backup $@
	;;
   --list|-l)
	list_backup $@
	;;
   --help|-h|*)
	usage
	;;
esac

clean_exit
