#!/bin/bash

#########################################
# Name: xfsdcard
#
# Summary: configure xFOCE Gateway SD Card
#
# Description: 
# - Copies boot and root partitions to SD Card
# - Creates data partition
# - formats the data partition
#
# Author: k.headley
#
# Copyright MBARI 2013
#
#########################################

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

OWD=`pwd`
SD_DEVICE=""
IPATH=""
XPATH="${XF_HOME}"
KEEP_MOUNTS="N"

BOOT_MOUNT="/media/xf-boot"
ROOT_MOUNT="/media/xf-root"
DATA_MOUNT="/media/xf-data"

MAX_LABEL=8
TEST_MODE="N"

MLO_NAME="MLO"
UBOOT_NAME="u-boot.img"
UIMAGE_NAME="uImage-beaglebone.bin"
ROOTFS_NAME="xfoce-cloud9-beaglebone.tar.bz2"

MLO_ONAME="MLO"
UBOOT_ONAME="u-boot.img"
UIMAGE_ONAME="uImage"

MLO_OUT="MLO"
UBOOT_OUT="u-boot.img"
UIMG_OUT="uImage"

BOOT_PAR_SLOT=1
BOOT_PAR_SZ="64"
BOOT_PAR_TYPE="C"
BOOT_FS_LABEL="GWBOOT"
BOOT_FS_TYPE="vfat"
BOOT_FS_OPTS="-F 32 -n ${BOOT_FS_LABEL}"
# boot:[rw,nosuid,nodev,uid=1000,gid=1000,shortname=mixed,dmask=0077,utf8=1,showexec,flush,uhelper=udisks]

ROOT_PAR_SLOT=2
ROOT_PAR_SZ="1500"
ROOT_PAR_TYPE="L"
ROOT_FS_LABEL="GWROOT"
ROOT_FS_TYPE="ext4"
ROOT_FS_OPTS="-j -L ${ROOT_FS_LABEL}"
#root:[rw,nosuid,nodev,uhelper=udisks)]

DATA_PAR_SLOT=3
DATA_PAR_SZ=""
DATA_PAR_TYPE="L"
DATA_FS_LABEL="GWDATA"
DATA_FS_TYPE="ext3"
DATA_FS_OPTS="-j -L ${DATA_FS_LABEL} -O large_file"
#data:[rw,nosuid,nodev,uhelper=udisks)]


BOOT_DEVICE="$SD_DEVICE$BOOT_PAR_SLOT"
ROOT_DEVICE="$SD_DEVICE$ROOT_PAR_SLOT"
DATA_DEVICE="$SD_DEVICE$DATA_PAR_SLOT"

GW_SETUP="${XPATH}/src/scripts/gwsetup"
XF_DIST=""

TEST=""

#################################
# Script variable initialization
#################################
VERBOSE="FALSE"


#################################
# 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`"
    echo "-i <path>   : image directory"	
    echo "-o <odev>   : output SD Card device"
    echo "-x <path>   : path to xfoce home [$XPATH]"
    echo "-d <file>   : xfoce tar.gz       [$XF_DIST]"
    echo "-l <label>  : data volume label  [$DATA_FS_LABEL]"
    echo "-t          : test mode          [$TEST_MODE]"
    echo "-k          : keep mounts        [$KEEP_MOUNTS]"
    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" == "TRUE" ]
    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
}

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


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

while getopts d:i:o:kl:thvx: Option
do
    case $Option in
	d )  XF_DIST="$OPTARG"
	;;
	i )  IPATH="$OPTARG"
	;;
	o )  SD_DEVICE="$OPTARG"
	;;
	x )  XPATH="$OPTARG"
	;;
	l )  DATA_FS_LABEL="$OPTARG"
	;;
	t )  TEST_MODE="Y"
		TEST="echo"
	;;
	k ) KEEP_MOUNTS="Y"
	;;
	v ) VERBOSE="TRUE"
	;;
	h)printUsage
	  exit 0
	;;
	*) exit 0 # getopts outputs error message
	;;
    esac
done

let "errcount=0"


if [ "${TEST_MODE}" == "Y" ]
then
	TEST="echo"
else
	TEST=""
fi

BOOT_DEVICE="$SD_DEVICE$BOOT_PAR_SLOT"
ROOT_DEVICE="$SD_DEVICE$ROOT_PAR_SLOT"
DATA_DEVICE="$SD_DEVICE$DATA_PAR_SLOT"

MLO_PATH="${IPATH}/${MLO_NAME}"
UBOOT_PATH="${IPATH}/${UBOOT_NAME}"
UIMAGE_PATH="${IPATH}/${UIMAGE_NAME}"
ROOTFS_PATH="${IPATH}/${ROOTFS_NAME}"

GW_SETUP="${XPATH}/src/scripts/gwsetup"

if [ ! -f "${XF_DIST}" ]
then
	if [ -f "${XPATH}/${XF_DIST}" ]
	then
		XF_DIST="${XPATH}/${XF_DIST}"
	fi
fi

vout
vout "SD device   : [${SD_DEVICE}]"
vout "image path  : [${IPATH}]"
vout "xfoce path  : [${XPATH}]"
vout "MLO         : [${MLO_PATH}]"
vout "uImage      : [${UIMAGE_PATH}]"
vout "u-boot      : [${UBOOT_PATH}]"
vout "rootfs      : [${ROOTFS_PATH}]"
vout "gw setup    : [${GW_SETUP}]"
vout "xf_dist     : [${XF_DIST}]"

vout "boot label  : [${BOOT_FS_LABEL}]"
vout "root label  : [${ROOT_FS_LABEL}]"
vout "data label  : [${DATA_FS_LABEL}]"
vout "keep mounts : [${KEEP_MOUNTS}]"
vout "test        : [${TEST_MODE}]"
vout "verbose     : [${VERBOSE}]"
vout

CALLER=`whoami`
if [ "${CALLER}" != "root" ]
then
	echo
	echo "error - must run as root/sudo"
	let "errcount+=1"
fi

if [ ! -d "${XPATH}" ] || [ ! -f "${GW_SETUP}" ] 
then
	echo
	echo "error - XFOCE path or files not found"
	echo "        Check paths and file types"
	echo "        xpath[${XPATH}]"
	let "errcount+=1"
fi

if [ ! -z "${XF_DIST}" ] && [ ! -f "${XF_DIST}" ]
then
	echo
	echo "error - XFOCE distribution not found"
	echo "        xf-dist [${XF_DIST}]"
	let "errcount+=1"
fi

if [ ! -d "${IPATH}" ] || [ ! -b "${SD_DEVICE}" ]
then
	echo
	echo "error - Image path or output device are invalid"
	echo "        Check paths and file types"
	echo "        img[${IDEV}] device[${SD_DEVICE}]"
	let "errcount+=1"
fi

if [ ! -e ${MLO_PATH} ] || [ ! -e ${UBOOT_PATH} ] || [ ! -e ${UIMAGE_PATH} ]
then
	echo
	echo "error - one or more boot files are missing in ${IPATH}"
	let "errcount+=1"
fi

mount -l|grep ${SD_DEVICE}
odev_check=$?
if [ "${odev_check}" -eq 0 ]
then
	echo
	echo "error - output device mounted"
	let "errcount+=1"
fi

if [ "${#DATA_FS_LABEL}" -gt 8 ]
then
	echo
	echo "warning: label len > ${MAX_LABEL} - truncating"
	DATA_FS_LABEL="${DATA_FS_LABEL:0:${FS_MAX_LABEL}}"
	echo "warning: label len > ${MAX_LABEL} - using ${DATA_FS_LABEL}"
fi

if [ "${errcount}" -gt 0 ]
then
	echo
	echo "`basename $0` - ${errcount} errors found - exiting"
	echo
	exit 1
fi



if [ "${TEST_MODE}" == "N" ]
then

#//////////////////////////
# Real mode - execute commands
#//////////////////////////
vout "partitioning SD card ${SD_DEVICE}..."

sfdisk -uM ${SD_DEVICE} <<EOF
0,${BOOT_PAR_SZ},${BOOT_PAR_TYPE},*
,${ROOT_PAR_SZ},${ROOT_PAR_TYPE}
,,${DATA_PAR_TYPE}
EOF

check_result=$?

if [ "${check_result}" -ne 0 ]
then
	echo
	echo "sfdisk returned error code [${check_result}] - exiting"
	echo
	exit 1
fi
# DOS expects first 512 bytes clear (see fdisk(8))
dd if=/dev/zero of=${BOOT_DEVICE} bs=512 count=1

vout "formatting boot partition..."
mkfs.vfat ${BOOT_FS_OPTS} ${BOOT_DEVICE}

vout "formatting root partition..."
mkfs.ext4 ${ROOT_FS_OPTS} ${ROOT_DEVICE}

vout "formatting data partition..."
mke2fs ${DATA_FS_OPTS} ${DATA_DEVICE}

vout "copying files to boot partition..."
mkdir ${BOOT_MOUNT}
mount ${BOOT_DEVICE} ${BOOT_MOUNT}
cp ${MLO_PATH} ${BOOT_MOUNT}/${MLO_ONAME}
cp ${UBOOT_PATH} ${BOOT_MOUNT}/${UBOOT_ONAME}
cp ${UIMAGE_PATH} ${BOOT_MOUNT}/${UIMAGE_ONAME}

vout "copying files to root partition..."
mkdir ${ROOT_MOUNT}
mount ${ROOT_DEVICE} ${ROOT_MOUNT}
cd ${ROOT_MOUNT}
tar xjvf ${ROOTFS_PATH}
cd ${OWD}
cp ${GW_SETUP} ${ROOT_MOUNT}/home/root/.

if [ ! -z "${XF_DIST}" ]
then
vout "copying files to data partition..."
mkdir ${DATA_MOUNT}
mount ${DATA_DEVICE} ${DATA_MOUNT}
mkdir ${DATA_MOUNT}/build
cp ${XF_DIST} ${DATA_MOUNT}/build
fi

if [ "${KEEP_MOUNTS}" == "N" ]
then
vout "unmounting boot device [${BOOT_DEVICE}]"
	umount ${BOOT_DEVICE}
vout "unmounting root device [${ROOT_DEVICE}]"
	umount ${ROOT_DEVICE}
vout "unmounting data device [${DATA_DEVICE}]"
	umount ${DATA_DEVICE}
	sleep 1

	rm -r ${BOOT_MOUNT}
	rm -r ${ROOT_MOUNT}
	rm -r ${DATA_MOUNT}
fi

else

#//////////////////////////
# Test mode - print commands
#//////////////////////////
cat <<TEST_OUT

vout "partitioning SD card ${SD_DEVICE}..."
sfdisk -uM ${SD_DEVICE} <<EOF
0,${BOOT_PAR_SZ},${BOOT_PAR_TYPE},*
,${ROOT_PAR_SZ},${ROOT_PAR_TYPE}
,,${DATA_PAR_TYPE}
EOF
dd if=/dev/zero of=${BOOT_DEVICE} bs=512 count=1

vout "formatting boot partition..."
mkfs.msdos ${BOOT_FS_OPTS} ${BOOT_DEVICE}
vout "formatting root partition..."
mkfs.ext4 ${ROOT_FS_OPTS} ${ROOT_DEVICE}
vout "formatting data partition..."
mke2fs ${DATA_FS_OPTS} ${DATA_DEVICE}

vout "copying files to boot partition..."
mkdir ${BOOT_MOUNT}
mount ${BOOT_DEVICE} ${BOOT_MOUNT}
cp ${MLO_PATH} ${BOOT_MOUNT}/${MLO_ONAME}
cp ${UBOOT_PATH} ${BOOT_MOUNT}/${UBOOT_ONAME}
cp ${UIMAGE_PATH} ${BOOT_MOUNT}/${UIMAGE_ONAME}

vout "copying files to root partition..."
mkdir ${ROOT_MOUNT}
mount ${ROOT_DEVICE} ${ROOT_MOUNT}
cd ${ROOT_MOUNT}
tar xjvf ${ROOTFS_PATH}
cd ${OWD}
cp ${GW_SETUP} ${ROOT_MOUNT}/home/root/.

#vout "copying files to data partition..."
#mkdir ${DATA_MOUNT}
#mount ${DATA_DEVICE} ${DATA_MOUNT}
#mkdir ${DATA_MOUNT}/build

if [ "${KEEP_MOUNTS}" == "N" ]
then
vout "unmounting boot device [${BOOT_DEVICE}]"
	umount ${BOOT_DEVICE}
vout "unmounting root device [${ROOT_DEVICE}]"
	umount ${ROOT_DEVICE}
vout "unmounting data device [${DATA_DEVICE}]"
	umount ${DATA_DEVICE}
	sleep 1
vout "removing mounts"
	rm -r ${BOOT_MOUNT}
	rm -r ${ROOT_MOUNT}
	rm -r ${DATA_MOUNT}
fi

TEST_OUT
fi

vout "done"
exit 0

