summary refs log tree commit diff
path: root/repack.sh
blob: 2b324ab11935240d57b8b7225d3ed13ae24a2d47 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
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"