#!/bin/bash
set -eo pipefail

help=$'Generate Tarball with image and MANIFEST Script

Generates an image tarball from given file as input.
Creates a MANIFEST for image verification and recreation
Packages the image and MANIFEST together in a tarball

usage: gen-image-tar [OPTION] <Image FILE>...

Options:
   -t, --type <imageType> TypeList: bios,cpld.   Bios Image is *.fd.enc; Cpld Image is *.bin
   -o, --out <file>       Specify destination file. Defaults to
                          `pwd`/obmc-*.tar.gz if unspecified.
   -p, --private-key <path>  Private key path.
   -m, --machine <name>   Optionally specify the target machine name of this
                          image.
   -v, --version <name>   Specify the version of image file
   -h, --help             Display this help text and exit.
'
type_list=("bios" "cpld")
extension_list=(".fd.enc" ".bin")
purpose_list=("xyz.openbmc_project.Software.Version.VersionPurpose.Host" "xyz.openbmc_project.Software.Version.VersionPurpose.Cpld")
outfile=""
machine=""
version=""
image_type=""
private_key=""
FAIL_FLAG="FAIL!"

encrypt_sign () {
    local ENCRYPT_FILE=$1
    local USER_KEY=$2
    local MD5_FILE="md5.txt"
    local ENCRYPT_FILE_PKG="$ENCRYPT_FILE.enc"
    local ENC_FILE="enc.txt"
    if [ ! $ENCRYPT_FILE ] || [ ! -f $ENCRYPT_FILE ]; then
        echo $FAIL_FLAG" Image File($ENCRYPT_FILE) is not exists ! exit."
        return
    fi

    if [ ! $USER_KEY ] || [ ! -f $USER_KEY ]; then
        echo $FAIL_FLAG" Private Key is not exists ! exit."
        return
    fi
    md5sum $ENCRYPT_FILE | awk '{print $1}' > $MD5_FILE
    # use private key to sign
    openssl rsautl -sign -in $MD5_FILE -inkey $USER_KEY -out $ENC_FILE >> /dev/null 2>&1
    ret=$(echo $?)
    if [ $ret -ne 0 ]
    then
        rm -f ${MD5_FILE} ${ENC_FILE}
        echo $FAIL_FLAG" Sign File Fail $ret."
        return
    fi

    cat $ENCRYPT_FILE > ${ENCRYPT_FILE_PKG}
    cat $ENC_FILE >> ${ENCRYPT_FILE_PKG}
    rm -f ${MD5_FILE} ${ENC_FILE} 
    echo  ${ENCRYPT_FILE_PKG}
    return
}

while [[ $# -gt 0 ]]; do
  key="$1"
  case $key in
    -t|--type)
    image_type="$2"
    shift 2
    ;;
    -o|--out)
      outfile="$2"
      shift 2
      ;;
    -m|--machine)
      machine="$2"
      shift 2
      ;;
    -v|--version)
      version="$2"
      shift 2
      ;;
    -p|--private-key)
      private_key="$2"
      shift 2
      ;;
    -h|--help)
      echo "$help"
      exit
      ;;
    -*)
      echo "Unrecognised option $1"
      echo "$help"
      exit
      ;;
    *)
      file="$1"
      shift 1
      ;;
  esac
done

if [[ -n $private_key ]] && [[ ! -f $private_key ]]; then
  echo "Please provide private key path with -p option."
  exit 1
fi

if [[ -z $image_type ]]; then
  echo "Please provide image type with -t option"
  exit 1
fi
if [[ $image_type != "bios" ]] && [[ -z $private_key ]];then
   echo "Please provide -p private key to encrypt image file."
   exit 1
fi
if [ ! -f "${file}" ]; then
  echo "${file} not found, Please enter a valid image file"
  echo "$help"
  exit 1
fi

if [[ -z $version ]]; then
  echo "Please provide version of image with -v option"
  exit 1
fi

listIndex=-1
for((i = 0 ;i < ${#type_list[@]};i++))
do 
	if [[ $image_type == ${type_list[$i]} && $file == *${extension_list[$i]} ]]
	then
		listIndex=$i
    break
	fi
done

if [[ $listIndex -eq -1 ]]; then
  echo "File and type do not match! Please use -h option to get more information."
  exit 1
fi

if [[ -z $outfile ]]; then
  outfile=`pwd`/obmc-${type_list[$listIndex]}.tar.gz
else
  if [[ $outfile != /* ]]; then
    outfile=`pwd`/$outfile
  fi
fi

scratch_dir=`mktemp -d`
# Remove the temp directory on exit.
# The files in the temp directory may contain read-only files, so add
# --interactive=never to skip the prompt.
trap "{ rm -r --interactive=never ${scratch_dir}; }" EXIT

manifest_location="MANIFEST"
files_to_sign="$manifest_location"
enc_file_name=${file}
if [[ $image_type != "bios" ]];then
  enc_file_name=$(encrypt_sign ${file} ${private_key})
  status=$(awk 'BEGIN {print index("'$enc_file_name'", "'$FAIL_FLAG'");}')
  if [ $status -ne 0 ];then
      echo "Encyrpt Image Fail! $enc_file_name"
      exit 1
  fi
fi
# Go to scratch_dir
cp ${enc_file_name} ${scratch_dir}   # enc file
cd "${scratch_dir}"
files_to_sign+=" $(basename ${enc_file_name})"

echo "Creating MANIFEST for the image"
echo -e "purpose=${purpose_list[$listIndex]}\n\
version=$version" > $manifest_location

if [[ ! -z "${machine}" ]]; then
    echo -e "MachineName=${machine}" >> $manifest_location
fi

tar -czvf $outfile $files_to_sign $additional_files
echo "Image tarball is at $outfile"
