[LEDE-DEV] [PATCH 1/4] Add new script: scripts/its-maker.sh

J Mo jmomo at jmomo.net
Wed Sep 7 22:04:25 PDT 2016


its-maker.sh creates an .its file, given a series of arguments, which is then used to create a FIT image.

Required to support the tew827dru, but intended to support the creation of any valid .its file.

Signed-off-by: jmomo <jmomo at jmomo.net>
---
 scripts/its-maker.sh | 598 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 598 insertions(+)
 create mode 100644 scripts/its-maker.sh

This is a new script to make ITS files, which are then used to produce a FIT image.

The existing mkits.sh script was device-specific and otherwise can not produce the FIT I need.

It does not support configurations, yet, but I'll add that if desired.

After I wrote my script, I became aware that Jason Wu was working on fixing up mkits.sh, but there hasn't been any progress and I'm not sure he's still interested in working on it. I will make him aware of my work: https://patchwork.ozlabs.org/patch/599455/

diff --git a/scripts/its-maker.sh b/scripts/its-maker.sh
new file mode 100644
index 0000000..7f4ba26
--- /dev/null
+++ b/scripts/its-maker.sh
@@ -0,0 +1,598 @@
+#!/bin/bash
+#
+# Create a u-boot FIT ITS (Image Tree Source) file given a convoluted series of arguments.
+#
+# Combination use of leading tabs and spaces is intentional for here-doc (<<-) and should be preserved.
+#
+# TODO:
+#   Support for Configurations not done.
+#   Clean up trap on interupt, etc.
+#   Mandatory/optional fields could be better.
+#   Consider harmonizing with mkimage arguments?
+# 
+# References:
+#   https://casper.berkeley.edu/svn/trunk/roach/sw/uboot/doc/uImage.FIT/source_file_format.txt
+#   https://lxr.missinglinkelectronics.com/uboot/doc/uImage.FIT/beaglebone_vboot.txt
+#   http://lists.denx.de/pipermail/u-boot/2008-March/030898.html
+#   https://wiki.linaro.org/WorkingGroups/Security/Verified-U-boot
+
+VERSION=1.0
+MYNAME=$(basename $0)
+declare -a ar_IMG_NAME
+declare -a ar_IMG_DESCR
+declare -a ar_IMG_FILE
+declare -a ar_IMG_TYPE
+declare -a ar_IMG_ARCH
+declare -a ar_IMG_OS
+declare -a ar_IMG_COMPRESSION
+declare -a ar_IMG_LOAD_ADDR
+declare -a ar_IMG_ENTRY_ADDR
+declare -a ar_IMG_HASHES
+declare -a ar_CFG_IDS
+
+# case +([0-9]) regex requires shopt -s extglob.
+shopt -s extglob
+
+echoerr() {
+	# Print errors to stderr.
+	echo "$@" 1>&2;
+	if [[ -n "$SEEN_ERROR" ]] ; then declare -r SEEN_ERROR=1 ; fi # If we saw any errors, set SEEN_ERROR=1, for later use.
+}
+
+echodebug() {
+	# Print debug messages to stderr if debugging enabled.
+	if [[ "$SCRIPT_DEBUG" == 1 ]] ; then
+		echo "DEBUG: $@" 1>&2;
+	fi
+}
+
+f_printusage() {
+	# Print usage info.
+	cat <<-EOF
+		Usage:
+
+		  --out|-O                     Output file, otherwise output goes to stdout.
+		  --device|-i                  Device for which we are building this ITS.
+		  --fit-type|-T                The FIT format type. Defaults to "flat_dt".
+		  --fit-description|-D         The FIT Description line.
+
+		  Image Commands: (all image commands must be followed by an integer ID.
+
+		    --img-name|-n              The name of the image.
+		    --img-descr|-d             The description of the image.
+		    --img-file|-f              The image data file.
+		    --img-type|-t              The type/format of the image.
+		    --img-arch|-a              The arch of the image.
+		    --img-os|-o                The OS of the image.
+		    --img-compression|-c       The compression of the image.
+		    --img-load-addr|-l         The load address for the image.
+		    --img-entry-addr|-e        The entry address for the image.
+		    --img-hashes|-s            The image hash(es), comma-seperated.
+
+		  --debug                      Debug the $MYNAME script.
+		  help|--help|-h|-H            Show help info.
+
+		Example:
+
+		  $MYNAME --device Widget5K --fit-type flat_dt --fit-description "Widget 5000 Extreme Edition Plus" --img-name 0 "upgrade-script" --img-descr 0 "Script to upgrade the firmware." --img-file 0 ~/tmp/myfile.scr --img-type 0 script --img-compression 0 none --img-name 1 "OS" --img-descr 1 "Widget 5000 Xe+ Operating System" --img-file 1 ~/tmp/myfile.bin --img-type 1 firmware --img-compression 1 none --img-arch 1 ARM --img-hashes 1 crc32,sha1
+
+	EOF
+}
+
+f_help () {
+	# Print some helpful information.
+	cat <<- EOF
+
+		$MYNAME constructs a u-boot FIT DTS file for use with mkimage.
+
+		$MYNAME version: $VERSION
+	EOF
+	f_printusage
+	return 0
+}
+
+f_register_img_id () {
+	# Register the IMG_ID in our ar_IMG_IDS array if needed.
+	if ! [[ "${ar_IMG_IDS[$1]}" ]] ; then
+		ar_IMG_IDS+=("$IMG_ID")
+		echodebug "IMG_ID $IMG_ID added to ar_IMG_IDS"
+	fi
+}
+
+f_assemble_dts_header () {
+	cat <<-EOF >> $DTS_BODY
+	/dts-v1/;
+	/ {
+	  description = "${HEADER_DESCR}";
+	  #address-cells = <1>;
+	EOF
+}
+
+f_assemble_img_header () {
+	cat <<-EOF >> $DTS_BODY
+	    images {
+	EOF
+}
+
+f_assemble_img_body_header () {
+	cat <<-EOF >> $DTS_BODY
+	      ${ar_IMG_NAME[$IMG_ID]}@${IMG_ID} {
+	        data = /incbin/("${ar_IMG_FILE[$IMG_ID]}");
+	        description = "${ar_IMG_DESCR[$IMG_ID]}";
+	        type = "${ar_IMG_TYPE[$IMG_ID]}";
+	        compression = "${ar_IMG_COMPRESSION[$IMG_ID]}";
+	EOF
+}
+
+f_assemble_img_body_arch () {
+	cat <<-EOF >> $DTS_BODY
+	        arch = "${ar_IMG_ARCH[$IMG_ID]}";
+	EOF
+}
+
+f_assemble_img_body_os () {
+	cat <<-EOF >> $DTS_BODY
+	        os = "${ar_IMG_OS[$IMG_ID]}";
+	EOF
+}
+
+f_assemble_img_body_load-entry () {
+	cat <<-EOF >> $DTS_BODY
+	        load = <${ar_IMG_LOAD_ADDR[$IMG_ID]}>;
+	        entry = <${ar_IMG_ENTRY_ADDR[$IMG_ID]}>;
+	EOF
+}
+
+f_assemble_img_body_hash () {
+	cat <<-EOF >> $DTS_BODY
+	        hash@${HASH_NUM} {
+	          algo = "${HASH_NAME}";
+	        };
+	EOF
+}
+
+f_assemble_img_body_footer () {
+	cat <<-EOF >> $DTS_BODY
+	      };
+	EOF
+}
+
+f_assemble_img_footer () {
+	cat <<-EOF >> $DTS_BODY
+	    };
+	EOF
+}
+
+f_assemble_cfg_header () {
+	cat <<-EOF >> $DTS_BODY
+	    default = "config at 1";
+	    configurations {
+	EOF
+}
+
+f_assemble_cfg_body () {
+	# FIXME: Not done.
+	cat <<-EOF >> $DTS_BODY
+	        config at 1 {
+	          description = "OpenWrt";
+	          kernel = "kernel at 1";
+	          fdt = "fdt at 1";
+	        };
+	EOF
+}
+
+f_assemble_cfg_footer () {
+	cat <<-EOF >> $DTS_BODY
+	      };
+	EOF
+}
+
+f_assemble_dts_footer () {
+	cat <<-EOF >> $DTS_BODY
+	  };
+	EOF
+}
+
+f_validate_in_args3 () {
+	# Validate $3 input argument.
+	if [[ -z "$ARG3" ]] ; then
+		echoerr -e "\nERROR: $ARG1 $IMG_ID argument missing.\n"
+		exit 1
+	fi
+	if ( echo "$ARG3" | egrep "^--" &> /dev/null ) ; then
+		# Look out for accidental missing values. However, this does incorrectly prohibit unusual valid data.
+		echoerr -e "\nERROR: Suspected missing value for $ARG1 $IMG_ID.\n"
+		exit 1
+	fi
+}
+
+# --
+
+# No input? Print usage and exit 1.
+[[ "$#" -eq 0 ]] && { f_printusage ; exit 1 ; }
+
+while [[ "$#" -gt 0 ]] ; do case "$1" in
+	--debug)
+		SCRIPT_DEBUG=1
+		# set -o functrace
+		# set -x
+		shift 1
+	;;
+	help|--help|-h|-H)
+		f_help
+		exit $?
+	;;
+	--out|-O)
+		OUT_FILE=$2
+		echodebug "Outfile set to $2"
+		shift 2
+	;;
+	--device|-i)
+		DEVICE=$2
+		echodebug "Device set to $2"
+		shift 2
+	;;
+	--fit-type|-T)
+		if [[ -z "$FIT_TYPE" ]] ; then
+			FIT_TYPE=$2
+			echodebug "FIT type set to $2"
+			shift 2
+		else
+			echoerr -e "\nERROR: --fit-fype was set more than once.\n"
+			exit 1
+		fi
+	;;
+	--fit-description|-D)
+		if [[ -z "$HEADER_DESCR" ]] ; then
+			HEADER_DESCR=$2
+			echodebug "FIT description set to \"$2\""
+			shift 2
+		else
+			echoerr -e "\nERROR: --fit-description was set more than once.\n"
+			exit 1
+		fi
+	;;
+	--img-name|-n)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_NAME[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_NAME[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-name $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-name ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-descr|-d)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_DESCR[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_DESCR[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-descr $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-descr ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-file|-f)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_FILE[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_FILE[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-file $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-file ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-type|-t)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_TYPE[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_TYPE[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-type $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-type ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-arch|-a)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_ARCH[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-arch $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-arch ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-os|-o)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_OS[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_OS[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-os $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-os ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-compression|-c)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_COMPRESSION[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_COMPRESSION[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-compression $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-compression ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-load-addr|-l)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_LOAD_ADDR[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-load-addr $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-load-addr ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-entry-addr|-e)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_ENTRY_ADDR[$IMG_ID]=$3
+					echodebug "$1 $IMG_ID set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-entry-addr $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-entry-addr ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	--img-hashes|-s)
+		case "$2" in
+			+([0-9]))
+				IMG_ID=$2 ARG1=$1 ARG2=$2 ARG3=$3
+				f_validate_in_args3
+				if [[ -z "${ar_IMG_HASHES[$IMG_ID]}" ]] ; then
+					f_register_img_id $IMG_ID
+					ar_IMG_HASHES[$IMG_ID]=$3
+					echodebug "$1 ${IMG_ID} set to \"$3\""
+				else
+					echoerr -e "\nERROR: --img-hashes $IMG_ID was set more than once.\n"
+					exit 1
+				fi
+				shift 3 ; unset IMG_ID ARG1 ARG2 ARG3
+			;;
+			*)
+				echoerr -e "\nERROR: Invalid --img-hashes ID. Must be an integer.\n"
+				exit 1
+			;;
+		esac
+	;;
+	*)
+		echoerr -e "\nERROR: Invalid argument \"$1\".\n"
+		f_printusage
+		exit 1
+	;;
+esac ; done
+
+# Build the ITS.
+# NOTE: The ITS format is complicated. It's our job to build the ITS. It's mkimage's job to determine if the content is valid.
+#  We do some basic validity checking, but producing an invalid ITS is a valid scenerio.
+
+DTS_BODY=$(mktemp)
+
+# Assemble the header.
+#
+
+# If we didn't get a FIT/header description, make one up by default.
+if [[ -z "$HEADER_DESCR" ]] ; then
+	if [[ -z "$DEVICE" ]] ; then
+		HEADER_DESCR="LEDE FIT image"
+	else # use $DEVICE if we have it.
+		HEADER_DESCR="LEDE FIT image for ${DEVICE}"
+	fi
+fi
+
+f_assemble_dts_header
+
+# At least one image entry is required by the ITS format.
+if [[ -z "${ar_IMG_IDS[@]}" ]] ; then
+	echoerr -e "\nERROR: At least one valid image is required.\n"
+	exit 1
+fi
+
+f_assemble_img_header
+
+# Assemble an Image block for each.
+for IMGBLOCK in ${ar_IMG_IDS[@]} ; do 
+	IMG_ID=$IMGBLOCK
+	echodebug "Processing IMG_ID $IMG_ID"
+	# The following fields are required for all images: description, type, data, compression.
+	for EACH in "${ar_IMG_DESCR[$IMG_ID]}" "${ar_IMG_TYPE[$IMG_ID]}" "${ar_IMG_FILE[$IMG_ID]}" "${ar_IMG_COMPRESSION[$IMG_ID]}" ; do
+		if [[ -z "$EACH" ]] ; then
+			MISSING_IMG_REQUIRED=1
+		fi
+	done ; unset EACH
+	[[ "$MISSING_IMG_REQUIRED" == 1 ]] && { 
+		echoerr -e "\nERROR: Missing one or more required attributes for IMG_ID $IMG_ID.\n"
+		exit 1 ; }
+	f_assemble_img_body_header
+	case "${ar_IMG_TYPE[$IMG_ID]}" in # ARCH is conditionally mandatory for certain image types.
+		standalone|kernel|firmware|ramdisk|fdt)
+			if [[ -z "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then
+				echoerr -e "\nERROR: --img-arch required for this image type.\n"
+				exit 1
+			fi
+		;;
+	esac
+	if [[ -n "${ar_IMG_ARCH[$IMG_ID]}" ]] ; then # Add architecture.
+		f_assemble_img_body_arch
+	fi
+	case "${ar_IMG_TYPE[$IMG_ID]}" in # OS is conditionally mandatory for kernels.
+		kernel)
+			if [[ -z "${ar_IMG_OS[$IMG_ID]}" ]] ; then
+				echoerr -e "\nERROR: --img-os required for this image type.\n"
+				exit 1
+			fi
+		;;
+	esac
+	if [[ -n "${ar_IMG_OS[$IMG_ID]}" ]] ; then # Add OS.
+		f_assemble_img_body_os
+	fi
+	case "${ar_IMG_TYPE[$IMG_ID]}" in # LOAD/ENTRY is conditionally mandatory for standalone kernels.
+		standalone|kernel)
+			if [[ -z "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] || [[ -z "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]]; then
+				echoerr -e "\nERROR: --img-load-addr and --img-entry-addr are required for this image type.\n"
+				exit 1
+			fi
+		;;
+	esac
+	if [[ -n "${ar_IMG_LOAD_ADDR[$IMG_ID]}" ]] && [[ -n "${ar_IMG_ENTRY_ADDR[$IMG_ID]}" ]]; then # Load and entry required together.
+		f_assemble_img_body_load-entry
+		# FIXME: Error on one but not the other.
+	fi
+	if [[ -n "${ar_IMG_HASHES[$IMG_ID]}" ]] ; then # Hashes are optional.
+		echodebug "IMG_ID $IMG_ID has hashes"
+		HASH_NUM=0
+		while IFS=',' ; do
+			for EACH in ${ar_IMG_HASHES[$IMG_ID]} ; do
+				echodebug "Processing IMG_ID $IMG_ID HASH_ID $EACH"
+				HASH_NAME=$EACH
+				f_assemble_img_body_hash
+				HASH_NUM=$(( HASH_NUM + 1 ))
+			done ; unset EACH
+			break
+		done ; unset HASH_NUM HASH_NAME
+	fi
+	f_assemble_img_body_footer
+done ; unset IMGBLOCK IMG_ID
+
+f_assemble_img_footer
+
+# Assemble a Configuration block for each.
+# FIXME: not done.
+for EACH in ${ar_CFG_IDS[@]} ; do
+	CFG_ID=$EACH
+	f_assemble_cfg_header
+	f_assemble_cfg_body
+	f_assemble_cfg_footer
+done ; unset EACH CFG_ID
+
+# Assemble the footer.
+f_assemble_dts_footer
+
+# If we don't have an output file, print to stdout.
+if [[ -z "$OUT_FILE" ]] ; then
+	echodebug "Printing DTS to stdout"
+	cat "$DTS_BODY" && rm -f "$DTS_BODY"
+else
+	# Make sure we are not going to clobber a file.
+	if [[ -f "$OUT_FILE" ]] ; then
+		echoerr -e "\nERROR: Output file \"OUT_FILE\" already exists!.\n"
+		exit 1
+	fi
+	echodebug "Writing output file."
+	cat "$DTS_BODY" > $OUT_FILE ; X_WRITE_OUT=$?
+	if [[ "$X_WRITE_OUT" == 0 ]] ; then
+		echo -e "\nDTS file written to: $OUT_FILE\n"
+		rm -f "$DTS_BODY"
+	else
+		echoerr -e "\nERROR: Writing output file failed.\n"
+		exit 1
+	fi
+fi
+
-- 
2.9.3




More information about the Lede-dev mailing list