#!/bin/bash

#########################################
# Name: gwsetup
#
# Summary: xFOCE disk setup script (run as root)
#
# Description: Setup a new xfoce sdcard
# - configure hostname
# - configure ops user
# - configure systemd services
# - configure SD card mounts 
# - install updates to rootfs files
# - optionally install a distribution
#
# Author: k. headley
#
# Copyright MBARI 2013
#
#########################################

#########################################
# Script configuration defaults
# casual users should not need to change
# anything below this section
#########################################

GW_HOST=""
XF_ARCH_PATH=""
XF_VERSION=""

DO_ALL="Y"
DO_HOSTNAME=""
DO_OPS_ACCT=""
DO_SUDO=""
DO_MOUNTS=""
DO_DIST=""
DO_OPS_ENV=""
DO_SYSD=""
DO_BUILD=""
DO_CLEAN=""
SKIP_BUILD=""
DO_XF_HOME=""

CLEAN_BAKS="N"
VERBOSE="N"
OPS_PW=brynner

#################################
# Script variable initialization
#################################

XF_OPS_HOME="/home/ops"
LIBSYSD="lib/systemd/system"
ETCSYSD="etc/systemd/system"
ETCSYSC="etc/sysconfig"
SD_MDEV="/dev/mmcblk0p3"
SD_MPOINT="/mnt/xfoce"

SD_FSTAB="${SD_MDEV}   ${SD_MPOINT}  auto   defaults  0  0"
XF_BUILD="${SD_MPOINT}/build"

XF_ARCH_NAME="" #`basename ${XF_ARCH_PATH}`
XF_ARCH_DIR="${XF_ARCH_PATH%%/${XF_ARCH_NAME}}"
XF_ARCH_VERSION="${XF_ARCH_NAME%%.tar.gz}"
XF_HOME="${XF_BUILD}/${XF_ARCH_VERSION}"
XF_ROOTFS="${XF_HOME}/src/gateway/rootfs"
XF_SCRIPTS="${XF_HOME}/src/scripts"

TEST="echo"
DATESTR=`date +%Y%m%d-%H%M%S`
WDIR=`pwd`

#################################
# Function Definitions
#################################
#################################
# name: sigTrap
# description: signal trap callback
# will interrupt 
# args: none
#################################
sigTrap(){
    exit 0;
}

#################################
# name: printUsage
# description: print use message
# args: none
#################################
printUsage(){
    echo
    echo "usage: `basename $0` [options] -a <hostname> -f <file>"
    echo "-a <hostname> : gateway hostname "
    echo "-f <file>     : xfoce archive tar.gz "
	echo "                Creates XF_HOME using specified archive"
	echo ""	
    echo "-x <version>  : xfoce version e.g. 0.25 "
	echo "                Creates an empty XF_HOME directory"
	echo ""
    echo "-c            : delete bakups           [$CLEAN_BAKS]"
    echo "-b            : skip build distribution"
	echo ""
	echo "Use -x to create an empty XF_HOME directory"
	echo ""
	echo "Advanced options:"
    echo "-B            : build distribution      [$DO_BUILD]"
    echo "-C            : clean bak files         [$DO_CLEAN]"
    echo "-H            : hostname                [$DO_HOSTNAME]"
    echo "-O            : ops account             [$DO_OPS_ACCT]"
    echo "-U            : sudo                    [$DO_SUDO]"
    echo "-M            : mounts                  [$DO_MOUNTS]"
    echo "-D            : distribution            [$DO_DIST]"
    echo "-E            : ops environment         [$DO_OPS_ENV]"
    echo "-S            : systemd files           [$DO_SYSD]"
    echo "-V            : verbose output          [$VERBOSE]"
    echo "-h            : print help message"
    echo ""
    echo
}

########################################
# name: vout
# description: print verbose message to stderr
# args:
#     msg: message
########################################
vout(){
    if [ "$VERBOSE" == "Y" ]
    then
	echo "$1" >&2
    fi
}

########################################
# name: imsg
# description: echos with indent
# args:
#     msg: message
#  indent: indent level
########################################
imsg(){
  OIFS=$IFS
  IFS=""
  msg_pad="                                        "
  let "msg_indent=${1}"
  shift
  all="${@}"
  printf "%s%s\n" ${msg_pad:0:${msg_indent}} ${all}
  IFS=$OIFS
}

########################################
# name: msg
# description: echos with default indent
# args:
#     msg: message
########################################
msg(){
 imsg $MSG_INDENT "${*}"
}

########################################
# name: exitError
# description: print use message to stderr
# args:
#     msg:        error message
#     returnCode: exit status to return
########################################
exitError(){
    echo >&2
    echo "$1" >&2
    echo >&2
    exit $2
}

########################################
# name: mkbak
# description: create backup copy of a file
# args:
#        file: target file
#     DATESTR: date/time string
#              defined above
#  returnCode: exit status to return
########################################
mkbak(){
	local target="${1}"
	local orig="$target.orig.gws"
	local bak="$target.${DATESTR}.bak.gws"

	if [ -f "${target}" ]
	then
		if [ ! -f "${orig}" ]
		then
			cp $target $orig
		else
			cp $target $bak
		fi
	fi
}

##########################
# Script main entry point
##########################


# Argument processing
#if [ "$#" -lt 2 ];then
#    printUsage
#    exit 0
#fi

while getopts a:bcf:hx:BCHOUMDESV Option
do
    case $Option in
	a ) GW_HOST="$OPTARG"
	;;
	f ) XF_ARCH_PATH="$OPTARG"
	;;
	b ) SKIP_BUILD="Y"
	;;
	x ) XF_VERSION="$OPTARG"
	;;
	B ) DO_BUILD="Y"
		DO_ALL="N"
	;;
	C ) DO_CLEAN="Y"
		DO_ALL="N"
	;;
	c ) CLEAN_BAKS="Y"
	;;
	H ) DO_HOSTNAME="Y"
		DO_ALL="N"
	;;
	O ) DO_OPS_ACCT="Y"
		DO_ALL="N"
	;;
	U ) DO_SUDO="Y"
		DO_ALL="N"
	;;
	M ) DO_MOUNTS="Y"
		DO_ALL="N"
	;;
	D ) DO_DIST="Y"
		DO_ALL="N"
	;;
	E ) DO_OPS_ENV="Y"
		DO_ALL="N"
	;;
	S ) DO_SYSD="Y"
		DO_ALL="N"
	;;
	V ) VERBOSE="Y"
	;;
	h)printUsage
	  exit 0
	;;
	*) exit 0 # getopts outputs error message
	;;
    esac
done


# call sigTrap on INT,TERM or EXIT
# trap sigTrap INT TERM EXIT

# reset trapped signals
# trap - INT TERM EXIT


if [ "${DO_ALL}" == "Y" ] 
then
	DO_HOSTNAME="Y"
	DO_OPS_ACCT="Y"
	DO_SUDO="Y"
	DO_MOUNTS="Y"
	DO_DIST="Y"
	DO_OPS_ENV="Y"
	DO_SYSD="Y"
	DO_BUILD="Y"
	DO_CLEAN="N"
fi

if [ "${CLEAN_BAKS}" == "Y" ] || [ "${DO_CLEAN}" == "Y" ]
then
	DO_CLEAN="Y"
else
	DO_CLEAN="N"
fi

if [ "${SKIP_BUILD}" == "Y" ] 
then
	DO_BUILD="N"
fi

vout "hostname : [${GW_HOST}]"
vout "archive  : [${XF_ARCH_PATH}]"
vout "version  : [${XF_VERSION}]"
vout "clean    : [${DO_CLEAN}]"
vout "verbose  : [${VERBOSE}]"
vout "all      : [${DO_ALL}]"
vout "build    : [${DO_BUILD}]"
vout "hostname : [${DO_HOSTNAME}]"
vout "ops_acct : [${DO_OPS_ACCT}]"
vout "sudo     : [${DO_SUDO}]"
vout "mounts   : [${DO_MOUNTS}]"
vout "dist     : [${DO_DIST}]"
vout "ops_env  : [${DO_OPS_ENV}]"
vout "systemd  : [${DO_SYSD}]"

let "now_date=`date +%s`"
let "valid_date=`date  +%s --date=\"Nov 1 00:00:00 UTC 2013\"`"

if [ "${now_date}" -lt "${valid_date}" ]
then
	now_hr=`date`
	echo
	echo "error - set system clock time is invalid [${now_hr}]"
	echo "  set system clock to current UTC time before continuing"
	echo "  e.g., date -s \"Nov 14 22:28:57 UTC 2013\""
	echo
	exit 1
fi

if [ -z "${GW_HOST}" ] && [ "${DO_HOSTNAME}" == "Y" ]
then
	printUsage
	exitError "hostname required" 1
fi


# if version specified, use that
# [disables code build]
# otherwise, use arch path
if [ -n "${XF_VERSION}" ]
then
	XF_ARCH_NAME=""
	XF_ARCH_DIR=""
	XF_ARCH_VERSION="xfoce-${XF_VERSION}"
	XF_HOME="${XF_BUILD}/${XF_ARCH_VERSION}"
	XF_ROOTFS="${XF_HOME}/src/gateway/rootfs"
	XF_SCRIPTS="${XF_HOME}/src/scripts"
	DO_DIST="N"
	DO_XF_HOME="Y"
elif [ -n "${XF_ARCH_PATH}" ]
then
	XF_ARCH_NAME=`basename ${XF_ARCH_PATH}`
	XF_ARCH_DIR="${XF_ARCH_PATH%%/${XF_ARCH_NAME}}"
	XF_ARCH_VERSION="${XF_ARCH_NAME%%.tar.gz}"
	XF_HOME="${XF_BUILD}/${XF_ARCH_VERSION}"
	XF_ROOTFS="${XF_HOME}/src/gateway/rootfs"
	XF_SCRIPTS="${XF_HOME}/src/scripts"
	DO_XF_HOME="N"
elif [ "${DO_CLEAN}" = "Y" ] || [ "${DO_HOSTNAME}" = "Y" ] || [ "${DO_SUDO}" = "Y" ] || [ "${DO_OPS_ENV}" = "Y" ] 
then
 vout "Archive or version not required"
else
	printUsage
	exitError "archive or version required" 1
fi


if [ "${DO_HOSTNAME}" == "Y" ] 
then
	vout "Configuring hostname"
	# network config
	# - hostname
	# - /etc/hostname

	now_host=`hostname`
	if [ "${now_host}" != "${GW_HOST}" ]
	then
		mkbak /etc/hostname
		hostname ${GW_HOST}
		echo ${GW_HOST} > /etc/hostname
	else
	vout "Hostname OK - skipping"
	fi
fi


if [ "${DO_OPS_ACCT}" == "Y" ] 
then
	vout "Creating user accounts"
	# users
	# - ops
adduser ops <<RESPONSE
$OPS_PW
$OPS_PW
RESPONSE

	vout "Configuring groups"
	addgroup ops
	usermod -aG sudo ops
	usermod -aG users ops
	usermod -aG lock ops
	usermod -aG uucp ops
	usermod -aG dialout ops
	usermod -aG operator ops
	usermod -aG tty ops
fi

if [ "${DO_SUDO}" == "Y" ] 
then
	vout "Configuring sudo"
	# sudo
	# - add ops
	# modify /etc/sudoers (enable sudo group)
	sudo adduser ops sudo

	grep -e "^[ \t]*%sudo.*ALL" /etc/sudoers
	sudo_modfied=$?
	if [ "${sudo_modfied}" -ne 0 ]
	then
		mkbak /etc/sudoers
		echo " %sudo	ALL=(ALL) ALL" >> /etc/sudoers
	else
	vout "sudo config exists - skipping"
	fi
fi

if [ "${DO_MOUNTS}" == "Y" ] 
then
	vout "Configuring mounts"
	# mounts
	# - /mnt/xfgw
	# - /etc/fstab
	# - /mnt/xfgw/build
	if [ ! -d ${SD_MPOINT} ]
	then
		mkdir -p ${SD_MPOINT}
	else
	vout "xFOCE mount point exists - skipping"
	fi
	chown ops:ops ${SD_MPOINT}
	chmod 775 ${SD_MPOINT}

	vout "Mounting data partition ${SD_MDEV} on ${SD_MPOINT}"
	mount ${SD_MDEV} ${SD_MPOINT}

	if [ ! -d ${XF_BUILD} ]
	then
		vout "Creating build directory [${XF_BUILD}]"
		mkdir -p ${XF_BUILD}
	else
	vout "xFOCE build directory exists - skipping"
	fi
	chown ops:ops ${XF_BUILD}
	chmod 775 ${XF_BUILD}

	vout "Configuring fstab"
	grep -e "$SD_MDEV.*$SD_MPOINT" /etc/fstab 
	has_sdmount=$?
	if [ "${has_sdmount}" -ne 0 ]
	then
		mkbak /etc/fstab
		echo ${SD_FSTAB} >> /etc/fstab
	else
	vout "fstab entry exists - skipping"
	fi
fi

if [ "${DO_XF_HOME}" == "Y" ] && [ -d "${XF_BUILD}" ]
then
 vout "Creating empty distribution directory [${XF_HOME}]"
 mkdir -p ${XF_HOME}
else
vout "skipping xfhome [requires version, mount]"	
fi

if [ "${DO_DIST}" == "Y" ] && [ -d "${XF_BUILD}" ]
then
	# install xfoce distribution

	if [ ! -f "${XF_BUILD}/${XF_ARCH_NAME}" ] 
	then
		if [ ! -f ${XF_ARCH_PATH} ]
		then
			vout "Distribution archive not found - exiting"
			exit 1
		else
			vout "Installing distribution archive"
			cp ${XF_ARCH_PATH} ${XF_BUILD}/${XF_ARCH_NAME}
			chown ops:ops ${XF_BUILD}/${XF_ARCH_NAME}
			chmod 664 ${XF_BUILD}/${XF_ARCH_NAME}
		fi
	else
		vout "Distribution archive exists - skipping"
	fi

	if [ ! -d "${XF_HOME}" ]
	then
	vout "Installing gateway sources"
			cd ${XF_BUILD}
			su -p -c "\
			tar xzvf ${XF_ARCH_NAME};" ops
	else
	vout "Gateway source installed - skipping"
	fi

	if [ -e "${XF_HOME}" ] && [ "${DO_BUILD}" == "Y" ]
	then
	vout "Building gateway sources"
			su -p -c "\
			cd ${XF_HOME}; \
			. src/scripts/gwconf b; \
			./configure; \
			make" ops
	else
	vout "Not building gateway sources"
	fi

	cd ${WDIR}
else
vout "skipping build [requires archive, mount] [DO_DIST:$DO_DIST XF_BUILD: $XF_BUILD]"	
fi

if [ "${DO_OPS_ENV}" == "Y" ] 
then
	# ops environment: .profile, .bash, xfoce/build links
	vout "ops environment..."
	mkbak ${XF_OPS_HOME}/.profile
	#cp ${XF_ROOTFS}/${XF_OPS_HOME}/.profile ${XF_OPS_HOME}/.

# /////////////////////
# write .profile
# /////////////////////
vout "writing .profile"	
cat <<XF_PROFILE_END > ${XF_OPS_HOME}/.profile
#!/bin/bash
 if [ -n "$BASH_VERSION" ]
 then
   # include .bashrc if it exists
   if [ -f "$HOME/.bashrc" ]
   then
     . "$HOME/.bashrc"
   fi
 fi

 if [ -f ~/.xfenv ]
 then
  . ~/.xfenv
 fi

XF_PROFILE_END
# /////////////////////

	chown ops:ops ${XF_OPS_HOME}/.profile
	chmod 644 ${XF_OPS_HOME}/.profile

	mkbak ${XF_OPS_HOME}/.xfenv
	#cp ${XF_ROOTFS}/${XF_OPS_HOME}/.xfenv ${XF_OPS_HOME}/.

# /////////////////////
# write .xfenv
# /////////////////////
vout "writing .xfenv [using $XF_HOME]"	
cat <<XFENV_END > ${XF_OPS_HOME}/.xfenv
#!/bin/bash

  # bootstrap xFOCE home
  XF_HOME=${XF_HOME}

  . ${XF_SCRIPTS}/xfhome ${XF_HOME}

XFENV_END
# /////////////////////
		
	chown ops:ops ${XF_OPS_HOME}/.xfenv
	chmod 644 ${XF_OPS_HOME}/.xfenv

	vout "creating symlinks"	
	vout "XF_HOME:$XF_HOME"	
	vout "XF_BUILD:$XF_BUILD"	
	vout "XF_OPS_HOME:$XF_OPS_HOME"	
	
	LINK="${XF_OPS_HOME}/xfoce"
	TARGET="${XF_HOME}"
	if [ -e ${LINK} ] && [ -L ${LINK} ]
	then
		vout "link ${LINK} exists - removing"
		rm ${LINK}
	fi
	ln -s ${TARGET} ${LINK}

	LINK="${XF_OPS_HOME}/build"
	TARGET="${XF_BUILD}"
	if [ -e ${LINK} ] && [ -L ${LINK} ]
	then
		vout "link ${LINK} exists - removing"
		rm ${LINK}
	fi
	ln -s ${TARGET} ${LINK}

fi


if [ "${DO_SYSD}" == "Y" ] && [ -d "${XF_ROOTFS}" ]
then
	vout "Applying rootfs updates"
	# install rootfs patches
	# - dropbear SSH (systemd)
	# - socat (systemd)
	# - xfgpio (systemd)
	vout "Systemd..."
	grep -e "[ \t]*KillMode[ \t]*=[ \t]*process" /${LIBSYSD}/dropbear\@.service
	dbssh_modified=$?
	if [ "${dbssh_modified}" -ne 0 ]
	then
	vout "/${LIBSYSD}/dropbear\@.service"
		mkbak /${LIBSYSD}/dropbear\@.service
		cp ${XF_ROOTFS}/${LIBSYSD}/dropbear\@.service /${LIBSYSD}/.
	else
	vout "/${LIBSYSD}/dropbear\@.service modified - skipping"
	fi

	if [ ! -e "/${ETCSYSC}/socatd" ]
	then
	vout "/${ETCSYSC}/socatd"
		mkbak /${ETCSYSC}/socatd
		cp ${XF_ROOTFS}/${ETCSYSC}/socatd /${ETCSYSC}/. 
	else
	vout "/${ETCSYSC}/socatd exists - skipping"
	fi

	if [ ! -e "/${ETCSYSC}/socatd-pty0" ]
	then
	vout "/${ETCSYSC}/socatd-pty0"
		mkbak /${ETCSYSC}/socatd-pty0
		cp ${XF_ROOTFS}/${ETCSYSC}/socatd-pty0 /${ETCSYSC}/. 
	else
	vout "/${ETCSYSC}/socatd-pty0 exists - skipping"
	fi

	if [ ! -e "/${ETCSYSC}/xfgpio" ]
	then
	vout "/${ETCSYSC}/xfgpio"
		mkbak /${ETCSYSC}/xfgpio
		cp ${XF_ROOTFS}/${ETCSYSC}/xfgpio /${ETCSYSC}/. 
	else
	vout "/${ETCSYSC}/xfgpio exists - skipping"
	fi

	if [ ! -e "/${ETCSYSD}/socatd" ]
	then
	vout "/${ETCSYSD}/socatd.service"
		mkbak /${ETCSYSD}/socatd.service
		cp ${XF_ROOTFS}/${ETCSYSD}/socatd.service /${ETCSYSD}/. 
	else
	vout "/${ETCSYSD}/socatd.service - skipping"
	fi

	if [ ! -e "/${ETCSYSD}/socatd\@.service" ]
	then
	vout "/${ETCSYSD}/socatd\@.service"
		mkbak /${ETCSYSD}/socatd\@.service
		cp ${XF_ROOTFS}/${ETCSYSD}/socatd\@.service /${ETCSYSD}/. 
	else
	vout "/${ETCSYSD}/socatd\@.service - skipping"
	fi

	if [ ! -e "/${ETCSYSD}/xfgpio.service" ]
	then
	vout "/${ETCSYSD}/xfgpio.service"
		mkbak /${ETCSYSD}/xfgpio.service
		cp ${XF_ROOTFS}/${ETCSYSD}/xfgpio.service /${ETCSYSD}/. 
	else
	vout "/${ETCSYSD}/xfgpio.service - skipping"
	fi
else
vout "skipping systemd updates [requires dist]"
fi

if [ "${DO_CLEAN}" == "Y" ]
then
	vout "Cleaning backups"
	rm /etc/*.bak.gws
	rm ${XF_OPS_HOME}/*.bak.gws
	rm ${XF_OPS_HOME}/.*.bak.gws
	rm /${LIBSYSD}/*.bak.gws
	rm /${ETCSYSD}/*.bak.gws
	rm /${ETCSYSC}/*.bak.gws
else
	vout "Clean backups - skipping"
fi

if [ -d "${SD_MPOINT}" ]
then
chown ops:ops ${SD_MPOINT}
chmod 775 ${SD_MPOINT}
fi

if [ -d "${XF_BUILD}" ]
then
chown ops:ops ${XF_BUILD}
chmod 775 ${XF_BUILD}
fi

echo
echo "Set the system time, e.g.:"
echo "   date --set=\"Thu Nov 21 03:50 UTC\""
echo
vout "gwsetup done"
vout ""

#mkbak ${XF_OPS_HOME}/.bashrc
#cp ${XF_ROOTFS}/${XF_OPS_HOME}/.bashrc ${XF_OPS_HOME}/.
#chown ops:ops ${XF_OPS_HOME}/.bashrc
#chmod 644 ${XF_OPS_HOME}/.bashrc

