#!/bin/bash
# rc.statelite will grab all the mount points we need to check 
# for keeping an image together.  This will have to do until unionfs
# is ready.
# don't do chkconfig: 345 00 99
# this file runs in a chroot environment.
# description: statelite initialization script

# get all the database files.
#set -x
SL=".statelite"
ME=`hostname`
MNTDIR="/sysroot"
SYNCTREE="${MNTDIR}/$SL/litetree" 	# the list of directories to sync from
SYNCLIST="${MNTDIR}/$SL/litefile" 	# the list of files to sync
TREEMOUNT="${MNTDIR}/$SL/mnt"  	# where I mount all the trees.
PERSISTENT="${MNTDIR}/$SL/persistent/$ME"
TMPFS="${MNTDIR}/$SL/tmpfs"
DEFAULT="${MNTDIR}/.default"
LOG="${MNTDIR}/${SL}/statelite.log"
ELIST=[]    # entry list, each entry will contain the type and the path
declare -a CLIST 
declare -a PLIST 


if [ ! -d $MNTDIR ]; then
	echo "statelite is only to be run in initrdfs"
	exit 1
fi



GetSyncInfo () {

	# who is our xCAT server?  He's most likely our dhcp identifier.
	
	if [ ! -x ${MNTDIR}/usr/bin/openssl ]; then
		echo "Image does not include openssl!"  
		exit 1
	fi
	
	# wish we had bash!
	#for x in `cat /proc/cmdline`; do
	#	[[ "$x" = "XCAT=*" ]] || continue
	#	XCATSERVER="${x#XCAT=}"
	#done

	for i in `cat /proc/cmdline`; do
		KEY=`echo $i | awk -F= '{print $1}'`
		if [ "$KEY" == 	"XCAT" ]; then
			XCATSERVER=`echo $i | awk -F= '{print $2}'`
			break
		fi
	done

    hn=`hostname`
	

	if [ -z $XCATSERVER ]; then
		echo "Cannot find the xCAT server for node $hn"
		exit 1
	fi

    # add one random sleeping time
    SLI=$(( $RANDOM%50 ))
    sleep $SLI
	# request the list of files from xCAT:
	xCATCmd $XCATSERVER litefile  \
		| sed  -e 's/<[^>]*>//g' \
		| egrep -v '^ *$' 	\
		| sed -e 's/^ *//' \
		| awk -F: '{print $2}' \
		| sed -e 's/^ *//' \
		>  $SYNCLIST

    MAX_RETRIES=15
    RETRY=0
    while [ ! -s $SYNCLIST ]; do
        # the file is empty, we should retry several times
        RETRY=$(( $RETRY+1 ))
        if [ $RETRY -eq $MAX_RETRIES ]; then
            echo "FATAL error: could not get the entries from litefile table..."
            /bin/bash
        fi

        SLI=$(( $RANDOM%50 ))
        sleep $SLI

    	xCATCmd $XCATSERVER litefile  \
		| sed  -e 's/<[^>]*>//g' \
		| egrep -v '^ *$' 	\
		| sed -e 's/^ *//' \
		| awk -F: '{print $2}' \
		| sed -e 's/^ *//' \
		>  $SYNCLIST
    done

	# files will now be inside /.snapshot/tmpfs/synclist in the form:
	# options path
    
    SLI=$(( $RANDOM%50 ))
    sleep $SLI

	xCATCmd $XCATSERVER litetree  \
		| sed  -e 's/<[^>]*>//g' \
		| egrep -v '^ *$' \
		| sed -e 's/^ *//' \
		| awk '{print $2}' \
		> $SYNCTREE

    RETCODE=$?

    RETRY=0
    while [ ! -s $SYNCTREE ] && [ "$RETCODE" -ne "0" ]; do
        # the file is empty, we should retry several times
        RETRY=$(( $RETRY + 1 ))
        if [ $RETRY -eq $MAX_RETRIES ]; then
            echo "FATAL error: could not get the entries from litetree table..."
            /bin/bash
        fi

        SLI=$(( $RANDOM%50 ))
        sleep $SLI
    	xCATCmd $XCATSERVER litetree  \
		| sed  -e 's/<[^>]*>//g' \
		| egrep -v '^ *$' \
		| sed -e 's/^ *//' \
		| awk '{print $2}' \
		> $SYNCTREE

        RETCODE=$?
    done
}

xCATCmd () {
# $1 is the xCAT server
# $2 is the command
	echo "<xcatrequest>\n<command>${2}</command>\n</xcatrequest>" | /usr/sbin/chroot /sysroot /usr/bin/openssl s_client -quiet -connect ${1} -rand /bin/nice 2>/dev/null

}



MountTrees () {
	mkdir -p $TREEMOUNT
	if [ -z $SYNCTREE ]; then
		echo "Can't read $SYNCTREE.  Something is wrong with this image..." >/dev/console
		exit 1
	fi
	for i in `cat $SYNCTREE | grep -v '^#' | grep ':'`;
	do
		SERV=`echo $i | awk -F: '{print $1}'`  # SERV is (SERV):/blah/blah/blah
		MNT=`echo $i | awk -F: '{print $2}'`   # MNT is server:(/blah/blah/blah)
		mkdir -p ${TREEMOUNT}/${SERV}/${MNT}
		MAX=15
		TRIES=1
		while ! mount $SERV:$MNT ${TREEMOUNT}/${SERV}/${MNT} -r -n -o nolock,tcp
		do
			if [ "$TRIES" = "$MAX" ]; then
				echo "Can't mount $i.  I give up.. ">/dev/console
				break
				#exit 1
			fi
			TRIES=$[ $TRIES + 1 ]
			S=$[ $RANDOM % 20 ]
			echo "Can't mount $SERV:$MNT... Sleeping $S seconds then trying again" >/dev/console
			sleep $S
		done
	done
}


ResolveLinksOld () {

	# go through each file and do the right thing to it.
	cat $SYNCLIST | grep -v "^#" | \
	while read type path
	do
		FindFile ${path} ${type}
	done
}


ResolveLinks () {
    exec <$SYNCLIST
    i=0 
    while read type path 
    do
        ELIST[$i]="$type $path";
        i=$[ $i + 1 ];
    done

    num=${#ELIST[@]}
    # put all the child entry to the end of the ELIST array
    for ((i=0;i<$num;i++)); do
        set -- ${ELIST[$i]}
        type=$1
        path=$2
    
        parent="`dirname $path`/"
        efound=0
        for ((j=0;j<$num;j++)); do
            set -- ${ELIST[$j]}
            jtype=$1
            jpath=$2
            if [ "$parent" = "$jpath" ]; then
                efound=1
            fi  
        done
    
        if [ "$efound" = "1" ]; then
            # put it into CLIST
            CLIST[$[ ${#CLIST[@]} ]]=${ELIST[$i]}
        else
            # put it into PLIST
            PLIST[$[ ${#PLIST[@]} ]]=${ELIST[$i]}
        fi  
    done

    num=${#PLIST[@]}
    for ((i=0;i<$num;i++)); do
        set -- ${PLIST[$i]}
        FindFile ${2} ${1} 0
    done

    num=${#CLIST[@]}
    for ((i=0;i<$num;i++)); do
        set -- ${CLIST[$i]}
        FindFile ${2} ${1} 1
    done
}




ProcessType () {
	#MOUNT=$1  	# mount point where this is.
	#PATH=$2	  	# file
	#TYPE=$3		# type of file
    #isChild=$4     # child = 1, parent = 0
	
    PPATH=`dirname ${2}`

	# every type has to have a base dir in tmpfs
	if [ ! -d ${TMPFS}${PPATH} ] && [ ! -L ${TMPFS}${PPATH} ]; then
		mkdir -p ${TMPFS}${PPATH}
		echo "mkdir -p ${TMPFS}${PPATH}" >>$LOG
	fi	
	
	case "${3}" in 
		tmpfs,rw)
            if [ -d ${TMPFS}${2} ]; then
			    cp -r -a ${1}* ${TMPFS}${2}
			    echo "cp -r -a ${1}* ${TMPFS}${2}" >>$LOG
            else
                cp -r -a ${1} ${TMPFS}${2}
                echo "cp -r -a ${1} ${TMPFS}${2}" >>$LOG
            fi
			# the link will already be in place on the image, so nothing else to do!
			;;
		con)
			# cons go in tmpfs
			cat ${1} >>${TMPFS}${2}
			echo "cat ${1} >>${TMPFS}${2}" >>$LOG
			;;	
        bind)
            ORIG=`echo ${2} |  sed -e 's/\/$//'`
            TARGET=`echo ${1}`
            
            if [ -d ${TMPFS}${2} ]; then
                cp -r -a ${1}* ${TMPFS}${2}
                echo "cp -r -a ${1}* ${TMPFS}${2}" >>$LOG
            else
                cp -r -a ${1} ${TMPFS}${2}
                echo "cp -r -a ${1} ${TMPFS}${2}" >>$LOG
            fi
            
            if [ "$isChild" = "0" ]; then
                echo "mount --bind ${TMPFS}${2} /sysroot${ORIG}" >>$LOG
                mount --bind ${TMPFS}${2} /sysroot${ORIG}>>$LOG 2>&1           
            fi
            ;;
        bind,persistent)
            if [ ! -d ${PERSISTENT}${PPATH} ]; then
                mkdir -p ${PERSISTENT}${PPATH}
                echo "mkdir -p ${PERSISTENT}${PPATH}" >>$LOG
            fi

            # if the file doesn't exist, then copy it over to persistent
            if [ ! -e ${PERSISTENT}${2} ]; then
                echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG
                cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG
            fi

            ORIG=`echo ${2} |  sed -e 's/\/$//'`
            TARGET=`echo ${PERSISTENT}${2}`

            echo "mount --bind ${TARGET} /sysroot/${ORIG}" >>$LOG
            mount --bind ${TARGET} /sysroot/${ORIG}>>$LOG 2>&1
            ;;
		persistent*)
			# everything from root image points to tmpfs	
			# so have tmpfs point to persistent

			# make tree in persistent and tmpfs
            # need to check whether the option of its parent direcotry is persistent or not

            TMPDIR=`dirname ${2}`
            if [ ! -e ${PERSISTENT}${TMPDIR} ]; then
                mkdir -p ${PERSISTENT}${TMPDIR}
                echo "mkdir -p ${PERSISTENT}${TMPDIR}" >>$LOG
            fi

            if [ "$isChild" = "1" ]; then
                num=${#PLIST[@]}
                for ((i=0;i<$num; i++)); do
                    set -- ${PLIST[$i]}
                    itype=$1
                    ipath=$2
                    if [ "$PPATH" = "$ipath" ]; then
                        if [[ ! "$itype" =~ "persistent*" ]]; then
                            if [ ! -e ${PERSISTENT}${2} ]; then
                                echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG
                                cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG
                            fi
                            # mount it to ${TARGET}
                            echo "mount --bind ${PERSISTENT}${2} ${TARGET}" >>$LOG
                            mount --bind ${PERSISTENT}${2} ${TARGET}
                        fi
                    fi
                done
            else
			    if [ ! -d ${PERSISTENT}${PPATH} ] && [! -d `readlink -m ${PERSISTENT}${PPERS}`]; then
                    # unless the entry is one directory or one link to the directory
                    rm -rf ${PERSISTENT}${PPERS}
				    mkdir -p ${PERSISTENT}${PPERS}
				    echo "mkdir -p ${PERSISTENT}${PPERS}" >>$LOG
			    fi
	
			    # if the file doesn't exist, then copy it over to persistent
			    if [ ! -e ${PERSISTENT}${2} ]; then
				    # if its not there, then take it from something else
				    echo "cp -r -a ${1} ${PERSISTENT}${2}" >>$LOG
				    cp -r -a ${1} ${PERSISTENT}${2} 2>&1 >>$LOG
				
			    fi
                #if target is a directory, then remove it first,
                #otherwise, the link will be created under this dir instead of replacing it.
                # whack of trailing / for persistent directories:
                TARGET=`echo ${TMPFS}${2} |  sed -e 's/\/$//'`
                if [ -d ${TARGET} ]; then
                    echo "rm -Rf ${TARGET}" >>$LOG
                    rm -Rf ${TARGET} 2>&1 >>$LOG
                fi

                # finally make the tmpfs link point to the persistent file

			    # you have to get rid of the /sysroot in the beginning 
			    # so that when the chroot happens the link is valid.	
                LINK=`echo ${PERSISTENT}${2} | sed -e 's/^\/sysroot//'`

			    echo "ln -sf ${LINK} ${TARGET}" >>$LOG
			    ln -sf ${LINK} ${TARGET}        >>$LOG 2>&1
            fi

			;;
		ro)
			# need to make sure directory exists:
			if [ ! -d ${TMPFS}${PPATH} ]; then
				mkdir -p ${TMPFS}${PPATH} >>$LOG 2>&1
			fi
			TARGET=`echo ${TMPFS}${2} |  sed -e 's/\/$//'`
			#LINK=`echo ${1} | sed -e "s/^${MNTDIR}//"`
			LINK=`echo ${1} | sed -e "s/^\/sysroot//"`
			
			echo "ln -sf ${LINK} ${TARGET}" >>$LOG 2>&1
			ln -sf ${LINK} ${TARGET} >>$LOG 2>&1
			;;
		*)
			;;
	esac
}


FindFile () {
	# $1 = Pathname to locate
	# $2 = Type of file
    # $3 = 0 or 1: 0 means parent, 1 means child
	path=$1
	type=$2
    isChild=$3
	FOUND=0
	for DIR in `cat ${SYNCTREE}`
	do
        DIR=${DIR/:/}
		if [ -e ${TREEMOUNT}/${DIR}${path} ]; then
			FOUND=1  # we found it!
            if [ -d ${TREEMOUNT}/${DIR}${path} ] && [ "0" -eq `ls -A ${TREEMOUNT}/${DIR}${path} |wc -l` ]; then
                FOUND=0
            else
			    ProcessType ${TREEMOUNT}/${DIR}${path} ${path} ${type} ${isChild}
			    if [ "${2}" = "con" ]; then
				    continue
			    else
				    break
			    fi
			fi
		fi	
	done


	## Default behavior is to get from the image
	if [ "$FOUND" = "0"  ]; then
		if [ -e "${DEFAULT}${path}" ]; then
			ProcessType ${DEFAULT}${path} ${path} ${type} ${isChild}
		else
			echo "Could not find ${path} in defaults or any other place" >/dev/console
		fi
		# if it wasn't found, mount rw in tmpfs
	fi
}


########################################################################################
# Start / MAIN / main
########################################################################################

# load up our files from xCAT
GetSyncInfo

# mount all the tree roots.  Usually there's probably only one.
MountTrees

# find the file and then see if its the one we need.
ResolveLinks

# make sure mtab points to the right place:
ln -sf /proc/mounts ${TMPFS}/etc/mtab

# catch all hack for debugging:
#cp -r -a ${DEFAULT}/* /.snapshot/tmpfs/
# foo
