#!/bin/sh
#
# NAME
#
#	makecard - prepare SD card with Linux or Logic Loader boot
#
# SYNOPSIS
#
#	makecard [-2] [-c pass] [-v] block-dev LogicLoader-dir Linux-dir
#
# DESCRIPTION
#
#	Formats a SD card and installs Linux or Logic Loader boot
#	files suitable for upgrading the Logic Loader version
#
#	The first argument is the base block device where the SD
#	card can be accessed (for example, /dev/sdf)  Note that
#	partition device names are created by appending the partition
#	number to the base block device (for example, /dev/sdf1)
#
#	The second and third arguments are the names of the directories
#	where the Logic Loader and Linux files are kept.  For each
#	of these, if the field is not blank, the directory will be
#	accessed to initialize the card.
#
#	If the optional "-2" parameter is specified and a Linux installation
#	is being made, only two partitions are created: the third partition
#	is not made, even if there is room to create it.  This can be
#	useful to expedite the process during debugging.
#
#   If the optional "-c" parameter is specified, the XDATA partition is
#   encrypted; "pass" is the passphrase to use for encryption.  If "pass"
#   is "-", a 43-character alphanumeric phrase is generated automatically
#   base on /dev/urandom and is displayed.
#
#	If the optional "-v" parameter is specified and a Linux installation
#	is being made, the user is prompted to remove and re-insert the
#	media after the files are written and CRC's are performed on the
#	BOOT and LINUX partitions
#
# ---------------------------------------------------------------------------
#
# Released as part # 02576 "SW, MICRO SD CARD SMC KERNEL INSTALLER" Rev A
#
# Partition encryption added (not released)

# Receives a stream of filtered output from mount and uses the first
# column of each line as device names to be unmounted
umount_from_stdin() {

    while true
    do
	read MOUNTDEV REST

	if [ -z "$MOUNTDEV" ]
	then
	   exit 0
	else
	   umount $MOUNTDEV
	fi
    done

    return 0
}

# Unmounts all partitions with device names  like the first parameter
umount_all() {

    mount | grep $1 | umount_from_stdin
    return 0
}

# Gets the size of the of the media at the named block device ($1)
# and echos it to stdout
get_size() {

    fdisk -l $1 2>/dev/null | \
	grep Disk | \
	( read V1 V2 V3 V4 V5 VREST; echo $V5 )

    return 0
}

# Generates passphrase with the given number of digits and displays
# on standard output and standard error
get_phrase()
{
	val=`tr -cd '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz' < /dev/urandom | dd bs=1 count=$1 2>/dev/null`
	echo >&2 "Generated passphrase = $val"
	echo $val
}

# Copies a file ($2) from the source directory ($1) to the destination
# directory ($3), optionally using a different name ($4) in the destination
# directory if the parameter is not blank
copy_file() {

    if [ ! -f $1/$2 ]
    then
	echo "File $2 not found in $1"
	exit 1
    else
	echo "-- $2"

	if [ -z "$4" ]
	then
	    cp $1/$2 $3
	else
	    cp $1/$2 $3/$4
	fi
    fi

    return 0
}

# Calls mkfs.vfat to initialize the media at the named partition ($1)
# in FAT32 format with a given name ($2)
setup_fat32() {

    if [ ! -b $1 ]
    then
		sleep 1
    fi

    if [ -b $1 ]
    then
    	mkfs.vfat -F 32 -n $2 $1
    else
		echo "Missing filesystem node for $1"
		exit 1
    fi

    return 0
}

# Calls mkfs.ext3 to initialize the media at the named partition ($1)
# in EXT3 format with a given name ($2); the partition is marked as not
# needing to be checked
setup_ext3() {

    if [ ! -b $1 ]
    then
		sleep 1
    fi

    if [ -b $1 ]
    then
		mkfs.ext3 -L $2 $1
		tune2fs -c 0 $1
	    else
		echo "Missing filesystem node for $1"
		exit 1
    fi

    return 0
}

# Gets the name of the kernel image in the given directory ($1)
get_uimage_name() {

    cd $1
    find . -mindepth 1 -type f -print | grep uImage | ( read X ; echo $X )
    return 0
}

# === Start of script ===

if [ "$1" = "-2" ]
then
  TWO="Y"
  shift
else
  TWO="N"
fi

if [ "$1" = "-c" ]
then

  which 2>/dev/null cryptsetup
  
  if [ "$?" -ne 0 ]
  then
    echo "Cannot find cryptsetup utility: encrypted partitions cannot be created"
    exit 1
  fi

  DOCRYPT="Y"
  CRYPTPHRASE="$2"
  shift
  shift
  
  if [ -z "$CRYPTPHRASE" ]
  then
    echo "No crypto phrase was specified"
    exit 1
  fi
  
else
  DOCRYPT="N"
fi  

if [ "$1" = "-v" -o "$1" = "-V" ]
then
  POSTVERIFY="Y"
  shift
else
  POSTVERIFY="N"
fi

DEV="$1"
LLDIR="$2"
LINUXDIR="$3"
CURUSER=`whoami`

if [ "$CURUSER" != "root" ]
then
	echo "This script must be run as root "
	#echo "This script must be run as root (current user is $CURUSER)"
	exit 1
fi

if [ -z "$DEV" ]
then
    echo "No device was specified"
    exit
fi

if [ ! -b $DEV ]
then
    echo "$DEV does not exist or is not a block device"
    exit 1
fi

if [ -z "$LLDIR" ]
then
    echo "LogicLoader directory not specified; no Logic Loader files will be created"
else
    if [ ! -d "$LLDIR" ]
    then
        echo "Provided LogicLoader directory ($LLDIR) was not found"
        exit 1
    fi
fi

if [ -z "$LINUXDIR" ]
then
    echo "Linux directory not specified; Linux partitions will not be initialized"
else
    if [ ! -d "$LINUXDIR" ]
    then
	echo "Provided Linux directory ($LINUXDIR) was not found"
	exit 1
    fi
fi

if [ -f "$LINUXDIR/rootfs.tar.gz" ]
then
    RFSARCH="$LINUXDIR/rootfs.tar.gz"
else
    if [ -f "$LINUXDIR/rfs/rootfs.tar.gz" ]
    then
        RFSARCH="$LINUXDIR/rfs/rootfs.tar.gz"
    else
        echo "Missing root filesystem archive typically at $LINUXDIR/rootfs.tar.gz"
        exit 1
    fi
fi

echo "Unmounting all volumes on $DEV"
umount_all $DEV

sleep 5 # jweeks

echo ""
echo "Initializing $DEV using /dev/zero"
dd if=/dev/zero of=$DEV bs=1024 count=1024

echo ""
echo -n "Calculating size of media on $DEV ... "
SIZE=`get_size $DEV`
echo "$SIZE bytes"

if [ -z "$SIZE" ]
then
    echo "No size was reported"
    exit 1
fi

if [ "$SIZE" -lt 4000000000 ]
then
    echo "The device is too small for use"
    exit 1
fi

echo -n "Calculating size of media on $DEV in cylinders ... "
CYLINDERS=`echo $SIZE/255/63/512 | bc`
echo $CYLINDERS

echo ""
echo "Configuring $DEV physical attributes"

{
    echo ,13,0x0C,*

    if [ "$TWO" != "Y" ]
    then
       if [ "$SIZE" -gt 8000000000 ]
       then
           echo ,523,,-
       fi
    fi

    echo ,,,-
} | sfdisk -D -H 255 -S 63 -C $CYLINDERS $DEV

echo ""
echo "Writing FAT32 filesystem on ${DEV}1"
dd if=/dev/zero of=${DEV}1 bs=512 count=1
setup_fat32 ${DEV}1 BOOT

if [ ! -z "$LINUXDIR" ]
then
    echo ""
    echo "Writing EXT3 filesystem on ${DEV}2"
    setup_ext3 ${DEV}2 LINUX

    if [ "$TWO" != "Y" ]
    then
        if [ "$SIZE" -gt 8000000000 ]
        then
        	if [ "$DOCRYPT" = "Y" ]
        	then
        	
        		SECURESD=makecard_sd
        		
        		echo ""
        		echo "Setting up ${DEV}3 with encryption"
        		
        		if [ "$CRYPTPHRASE" = "-" ]
        		then
        			CRYPTPHRASE=`get_phrase 43`
        		fi
        		
        		if [ -h /dev/mapper/$SECURESD ]
        		then
        			echo "Removing existing instance of $SECURESD" 
		            sync
	            	cryptsetup remove $SECURESD
	            fi
	            
        		echo "$CRYPTPHRASE" | cryptsetup create --cipher aes-cbc-essiv:sha256 --key-size 256 --hash sha256 $SECURESD ${DEV}3
        		
	            echo ""
	            echo "Writing EXT3 filesystem XDATA on encrypted partition ${DEV}3"
	            setup_ext3 /dev/mapper/$SECURESD XDATA
	            sync
	            cryptsetup remove $SECURESD

			else
			
	            echo ""
	            echo "Writing EXT3 filesystem on ${DEV}3"
	            setup_ext3 ${DEV}3 XDATA
	            
        	fi
        
        fi
    fi
fi

echo ""
echo "Mounting BOOT partition"

if [ ! -d /mnt ]
then
    mkdir /mnt
fi

if [ ! -d /mnt/BOOT ]
then
    mkdir /mnt/BOOT
fi

mount ${DEV}1 /mnt/BOOT

if [ ! -z "$LLDIR" ]
then
    echo ""
    echo "Loading LogicLoader files to BOOT partition"
    copy_file $LLDIR MLO /mnt/BOOT
fi

if [ ! -z "$LINUXDIR" ]
then

    echo ""
    echo "Creating startup script on BOOT partition"
    {
   	echo "load elf /sd/u-boot"
        echo "exec -"
    } > /mnt/BOOT/script

    echo ""
    echo "Loading u-boot to BOOT partition"
    copy_file ${LINUXDIR}/bootloader u-boot.bin /mnt/BOOT
    SRCIMG=`get_uimage_name $LINUXDIR`
    copy_file ${LINUXDIR} $SRCIMG /mnt/BOOT uImage

fi

echo ""
echo "Flushing writes to device"
sync

echo ""
echo "Unmounting BOOT partition"
umount ${DEV}1

if [ ! -z "$LINUXDIR" ]
then

     echo ""
     echo "Mounting LINUX partition"

     if [ ! -d /mnt/LINUX ]
     then
	mkdir /mnt/LINUX
     fi

     mount ${DEV}2 /mnt/LINUX

     echo ""
     echo "Writing root filesystem"
     THISDIR=`pwd`
     cd /mnt/LINUX
     tar xvpsf $RFSARCH

     cd "$THISDIR"

     echo ""
     echo "Flushing writes to device"
     sync

     echo ""
     echo "Unmounting LINUX partition"
     umount ${DEV}2
fi

if [ ! -z "$LINUXDIR" ]
then

  if [ "$POSTVERIFY" = "Y" ]
  then

    echo ""
    echo "Remove the micro-SD card and re-insert it; then press Enter to continue"
    read dummyvar

    if [ ! -d "/media/BOOT" ]
    then
        echo ""
	echo "** ERROR: there is no mounted BOOT partition **"
	exit 1
    fi
    
    if [ ! -d "/media/LINUX" ]
    then
        echo ""
	echo "** ERROR: there is no mounted BOOT partition **"
	exit 1
    fi

    echo ""
    echo "BOOT partition:"
    cd /media/BOOT
    cksum *

    echo ""
    echo "LINUX partition:"
    cd /media/LINUX
    #tar -c --atime-preserve -f - * | cksum
    ALLFILES=`find . -type f -printf '"%p"\n' | sort`
    CATABLEFILES=`echo $ALLFILES | xargs file | egrep -v '[:].*symbolic' | sed 's/[:][ ]\+.\+//1'`
    ( echo $ALLFILES ; echo $CATABLEFILES | xargs cat ) | cksum

    echo ""
    echo "Unmounting partitions"
    cd /media
    umount BOOT LINUX

  fi
fi

