#!/bin/sh set -e usage() { cat <&2 } die() { err "$*" exit 1 } ensuredeps() { local DEPS="fakeroot mksquashfs unsquashfs awk env mkimage truncate dtc fdtget rauc" local missing= for dep in $DEPS; do command -v $dep >/dev/null && continue missing="$missing $dep" done if [ -n "$missing" ]; then die "Missing dependencies:$missing" fi } squnpack() { local sq="$WORKDIR"/pkg/rootfs.img # Capture the original compression algo and block size for when we # resquash it later on. unsquashfs -s "$sq" | awk ' /^Compression/ { printf(" -comp %s", $2); } /^Block size/ { printf(" -b %s", $3); } ' >"$WORKDIR"/mksquash-opts $FAKEROOT unsquashfs -d "$WORKDIR"/rootfs "$sq" } sqexec() { $FAKEROOT env -C "$WORKDIR"/rootfs "$@" } sqpack() { $FAKEROOT mksquashfs "$WORKDIR"/rootfs "$WORKDIR"/pkg/rootfs.img \ $(cat "$WORKDIR"/mksquash-opts) -noappend "$@" } sqsign() { local its="$1" local keys="$2" local hsize="$3" local out="$4" mkimage -E -p "$hsize" -B "$hsize" -k "$keys" -f "$its" "$WORKDIR"/sign.itb truncate -s $(($hsize)) "$WORKDIR"/sign.itb mv "$WORKDIR"/sign.itb "$out" } sqresign() { local keys="$1" local sq="$WORKDIR"/pkg/rootfs.img local itbh="$WORKDIR"/pkg/rootfs.itbh signsize=$(printf '0x%x' $(fdtget "$itbh" /images/rootfs data-position)) dtc -I dtb -O dts "$itbh" | awk -v sq="$sq" ' /timestamp =/ || /data-\w+ =/ || /signer-\w+ =/ || /value =/{ /* Remove old signature */ next; } /compression = "none"/ { /* Splice in reference to the squash */ print; sub("compression", "data"); sub("\"none\"", sprintf("/incbin/(\"%s\")", sq)); print; next; } { /* Keep the rest as-is */ print; }; ' >"$WORKDIR"/resign.its sqsign "$WORKDIR"/resign.its "$keys" "$signsize" "$itbh" } unpack() { local pkg="$1" local keys="$2" WORKDIR=$(readlink -f "$3") case "$#" in 3) ;; *) echo "Usage: ixbin unpack PKG KEYS DIR" >&2 exit 1 esac local crt=$(ls "$keys"/*.crt | head -n1) [ -r "$crt" ] || die "No public key found in $keys" msg "Setting up working directory" mkdir -p "$WORKDIR" cp -a "$keys" "$WORKDIR"/in-keys touch "$WORKDIR"/fakeroot-state FAKEROOT="fakeroot -i $WORKDIR/fakeroot-state -s $WORKDIR/fakeroot-state" msg "Unpacking RAUC bundle" rauc --keyring="$crt" extract "$pkg" "$WORKDIR"/pkg msg "Unpacking Squash filesystem" squnpack msg "OK, $WORKDIR/rootfs can now be modified" } run() { WORKDIR=$(readlink -f "$1") shift [ -r "$WORKDIR"/fakeroot-state ] || \ die "$WORKDIR does not contain an unpacked image" FAKEROOT="fakeroot -i $WORKDIR/fakeroot-state -s $WORKDIR/fakeroot-state" sqexec "$@" } pack() { WORKDIR=$(readlink -f "$1") local keys="$2" local pkg="$3" case "$#" in 3) ;; 2) keys="$WORKDIR"/in-keys pkg="$2" ;; *) echo "Usage: ixbin pack DIR [KEYS] DIR" >&2 exit 1 esac [ -r "$WORKDIR"/fakeroot-state ] || \ die "$WORKDIR does not contain an unpacked image" local crt=$(ls "$keys"/*.crt | head -n1) [ -r "$crt" ] || die "No public key found in $keys" local key=$(ls "$keys"/*.key | head -n1) [ -r "$crt" ] || die "No private key found in $keys" FAKEROOT="fakeroot -i $WORKDIR/fakeroot-state -s $WORKDIR/fakeroot-state" msg "Packing up Squash filesystem" sqpack [ -f "$WORKDIR"/pkg/rootfs.itbh ] && { msg "Updating Squash filesystem signature" sqresign "$keys" } msg "Creating RAUC bundle" rauc --keyring="$crt" --cert="$crt" --key="$key" bundle "$WORKDIR"/pkg "$pkg" msg "OK, updated bundle available in $pkg" } if [ $# -lt 1 ]; then usage exit 1 fi cmd="$1" shift case "$cmd" in unpack) ensuredeps unpack "$@" ;; "exec") ensuredeps run "$@" ;; pack) ensuredeps pack "$@" ;; help) usage ;; *) die "Unknown command \"$cmd\"" ;; esac