summary refs log tree commit diff
path: root/repack.sh
diff options
context:
space:
mode:
Diffstat (limited to 'repack.sh')
-rwxr-xr-xrepack.sh117
1 files changed, 117 insertions, 0 deletions
diff --git a/repack.sh b/repack.sh
new file mode 100755
index 0000000..2b324ab
--- /dev/null
+++ b/repack.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+if [[ $# -lt 2 ]]; then
+    >&2 echo "usage: repack.sh IN_ROOTFS OUT_DIR"
+    exit 1
+fi
+if [[ $EUID -ne 0 ]]; then
+    >&2 echo "this script must be run as root"
+    exit 1
+fi
+
+set -x
+script_dir=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd)
+in_rootfs="$1"
+out_dir="$2"
+out_tmp=$(mktemp -d -p "$(dirname "$out_dir")" .tmp.XXXXXXXXXX)
+chmod 0755 "$out_tmp"
+mountpoint=$(mktemp -d)
+_cleanup() {
+    # FIXME: this doesn't handle `gpgconf --kill all`
+    mountpoint -q "$mountpoint" && umount --recursive "$mountpoint"
+    rmdir "$mountpoint"
+    rm -rf "$out_tmp"
+}
+trap _cleanup EXIT
+
+cp "$in_rootfs" "$out_tmp"/rootfs.img
+# Randomize filesystem UUID
+fs_uuid=$(uuidgen)
+btrfstune -fU "$fs_uuid" "$out_tmp"/rootfs.img
+# Mount and mark read-only
+mount -o compress=zstd "$out_tmp"/rootfs.img "$mountpoint"
+btrfs property set -ts "$mountpoint" ro false
+# Mount /dev and /proc for mkinitcpio, etc.
+mount -t devtmpfs dev "$mountpoint"/dev
+mount -t proc proc "$mountpoint"/proc
+# Set up the usual tmpfs suspects
+mount -t tmpfs -o mode=755 tmpfs "$mountpoint"/run
+mount -t tmpfs tmpfs "$mountpoint"/tmp
+# Ensure no writes to /home or /var
+mount -t tmpfs -o mode=755 tmpfs "$mountpoint"/home
+mount -t tmpfs -o mode=755 tmpfs "$mountpoint"/var
+# Get network resolution working in the chroot.
+mount --bind "$(realpath /etc/resolv.conf)" "$mountpoint"/etc/resolv.conf
+
+# Modify /etc/os-release and /lib/steamos-atomupd/manifest.json. We want
+# VERSION_ID/version to remain the same as upstream so that Steam can still load
+# changelog entries.
+version=$(jq -r .version <"$mountpoint"/lib/steamos-atomupd/manifest.json)
+# We want to set our own BUILD_ID/buildid so that we can make multiple image
+# updates even if upstream doesn't make any changes. SteamOS requires the build
+# ID is of the form YYYYMMDD.N. The N must be an integer, at least as far as
+# Python 3's `int` built-in function is concerned; leading zeroes parse fine,
+# but when it's rendered back out to a string they get dropped, so we may as
+# well remove them ourselves.
+buildid=$(date +%Y%m%d.%H%M%S | sed -e 's/\.0\+\(.\+\)$/.\1/')
+jq --arg buildid "$buildid" '.buildid = $buildid' \
+    <"$mountpoint"/lib/steamos-atomupd/manifest.json >"$out_tmp"/manifest.json
+cat "$out_tmp"/manifest.json >"$mountpoint"/lib/steamos-atomupd/manifest.json
+sed -i -e "/^BUILD_ID=/c BUILD_ID=$buildid" "$mountpoint"/etc/os-release
+# For lack of a better place to make it incredibly obvious that this is an
+# unofficial image, modify NAME and PRETTY_NAME. (This sadly doesn't show up in
+# the Steam Deck UI, that seems to pull from /etc/lsb-release?)
+sed -i -e "/^NAME=/c NAME=\"SteamOS (iliana's version)\"" "$mountpoint"/etc/os-release
+sed -i -e "/^PRETTY_NAME=/c PRETTY_NAME=\"SteamOS (iliana's version)\"" "$mountpoint"/etc/os-release
+# Swap URLs in /etc/steamos-atomupd/client.conf.
+cat "$script_dir/atomupd-client.conf" >"$mountpoint"/etc/steamos-atomupd/client.conf
+# Replace /etc/rauc/keyring.pem.
+cat "$script_dir/iliana-rauc-keyring.pem" >"$mountpoint"/etc/rauc/keyring.pem
+
+# # We need a valid keyring to verify the signature of packages we want to
+# # install. We don't really want to mess with the state /etc/pacman.d/gnupg is in
+# # on the SteamOS rootfs, so we put one on /tmp.
+# chroot "$mountpoint" pacman-key --gpgdir /tmp/gnupg --init
+# chroot "$mountpoint" pacman-key --gpgdir /tmp/gnupg --populate
+# # Terminate GPG agent processes
+# chroot "$mountpoint" gpgconf --homedir /tmp/gnupg --kill all
+
+# Add our repo.
+sed -i -e '/\[testing\]/s;^;[fauxlo]\nServer = https://fauxlo.ili.fyi/pacman/$arch\nSigLevel = Never\n\n;' "$mountpoint"/etc/pacman.conf
+# Synchronize the fauxlo repo behind pacman's back. (-Sy would otherwise refresh
+# the other repos, which we want frozen in time.)
+curl -Ro "$mountpoint"/usr/lib/holo/pacmandb/sync/fauxlo.db https://fauxlo.ili.fyi/pacman/x86_64/fauxlo.db
+# Install packages.
+pacman --sysroot "$mountpoint" --gpgdir /tmp/gnupg --noconfirm -S \
+    linux-neptune-61
+
+# Set FastConnectable=true in /etc/bluetooth, as we don't have any concern over
+# battery life
+sed -i -e '/^#\?FastConnectable/c FastConnectable = true' "$mountpoint"/etc/bluetooth/main.conf
+# Don't disable multicast DNS.
+rm "$mountpoint"/usr/lib/systemd/resolved.conf.d/00-disable-mdns.conf
+
+# Mark read-only and unmount
+btrfs property set -ts "$mountpoint" ro true
+fstrim -v "$mountpoint"
+umount --recursive "$mountpoint"
+
+# Prepare bundle
+mkdir "$out_tmp"/bundle
+echo "$fs_uuid" >"$out_tmp"/bundle/UUID
+casync make --store="$out_tmp/steamdeck-$buildid-$version.castr" "$out_tmp"/bundle/rootfs.img.caibx "$out_tmp"/rootfs.img
+cat >"$out_tmp"/bundle/manifest.raucm <<EOF
+[update]
+compatible=steamos-amd64
+version=$version
+
+[image.rootfs]
+sha256=$(sha256sum "$out_tmp"/rootfs.img | awk '{ print $1 }')
+size=$(stat -c %s "$out_tmp"/rootfs.img)
+filename=rootfs.img.caibx
+EOF
+
+mv "$out_tmp" "$out_dir/$buildid"
+chown -R "$(logname)":"$(id -gn "$(logname)")" "$out_dir/$buildid"
+echo "$out_dir/$buildid"