Files

270 lines
5.5 KiB
Bash
Executable File

#!/bin/sh
set -e
usage()
{
cat <<EOF
usage: $0 COMMAND [ARGS...]
Update contents of Infix images
Commands:
unpack PKG KEY-DIR DIR
Unpack the RAUC bundle PKG and the root filesystem contained in
it, using the keys stored in KEY-DIR, and store the results in
DIR.
pack DIR [KEY-DIR] PKG
Repackage the (possibly modified) root filesystem in DIR, updating
all signatures as necessary using the keys stored in KEY-DIR (or
the keys used to unpack the bundle, if not specified) and store
the resulting bundle in PKG.
exec DIR COMMAND [ARGS...]
Run COMMAND, possibly with ARGS, from the root of the filesystem
in DIR, inside of a fakeroot context that allows otherwise
privileged operations such as ownership modifications.
help
Show this message and exit.
Key directories:
KEY-DIR arguments must reference a directory that contains the
public/private keypair used to verify/sign an image. Most commonly,
board/common/signing-keys/development from the Infix source tree is
used to validate the input image.
Example:
Include a custom file inside a prebuilt Infix image, assign it to
the UID/GID 1337; and package up the results, signing it with the
same developer key that was used to create it:
ixbin unpack infix-aarch64.pkg ~/infix/board/common/signing-keys/development tmp
cp VBRUN300.DLL tmp/rootfs/lib/
ixbin exec tmp chown 1337:1337 lib/VBRUN300.DLL
ixbin pack tmp infix-vb3-aarch64.pkg
EOF
}
msg()
{
printf "\e[37;44mixbin: %-80s\e[0m\n" "$*"
}
err()
{
printf "\e[37;41mixbin: ERROR: %-73s\e[0m\n" "$*" >&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