Files
2026-09-24 13:54:28 +08:00

93 lines
5.2 KiB
Bash
Executable File

#!/usr/bin/env bash
source "$(dirname -- "${BASH_SOURCE[0]}")/lib.sh"
[[ $# == 0 ]] || die 'Usage: PROFILE=cli tools/build-rootfs'
profile=${PROFILE:-cli}
[[ $profile == cli || $profile == development || $profile == recovery ]] || die 'Supported profiles: cli, development, recovery'
use_xbps
check_void_pin
need python3
python3 -c 'import sys; assert sys.version_info >= (3, 14), "Rootfs assembly requires Python 3.14+ for zstd XBPS archives"'
cd "$FDS_ROOT"
mkdir -p out/logs out/manifests out/packages out/cache/rootfs
exec 9>out/.rootfs.lock
flock -n 9 || die 'Another rootfs build is already running'
missing=()
for package in qemu-user-aarch64 util-linux; do
if ! xbps-query -r "$FDS_VOID/masterdir-x86_64" "$package" >/dev/null 2>&1; then
missing+=("$package")
fi
done
if (( ${#missing[@]} )); then
tools/in-void xbps-install -y "${missing[@]}"
fi
tools/build-base-packages
work=$(mktemp -d "$FDS_ROOT/out/rootfs-build.XXXXXX")
root="$work/root"
printf 'Rootfs build workspace: %s\n' "$work"
# Keep failed workspaces for diagnosis. No partial result replaces a good archive.
mkdir -p "$root"
python3 tools/rootfs-layout "$root" packages/fds-base-files/files/layout.json
mkdir -p "$root/var/db/xbps/keys" "$work/config"
cp "$FDS_VOID/common/repo-keys/"*.plist "$root/var/db/xbps/keys/"
cp packages/fds-base-files/files/10-fds.conf "$work/config/"
mapfile -t packages < <(sed -e 's/#.*//' -e '/^[[:space:]]*$/d' image/base-packages.list "profiles/$profile.list")
(( ${#packages[@]} )) || die 'Empty image/base-packages.list'
for package in "${packages[@]}"; do
[[ $package =~ ^[a-zA-Z0-9][a-zA-Z0-9+_.-]*$ ]] || die "Invalid base package: $package"
done
# Extract with native XBPS in the build user namespace. The on-disk tree belongs
# to the host user; rootfs-archive restores ownership from package headers.
repository=https://repo-default.voidlinux.org/current/aarch64
if [[ ${FDS_OFFLINE:-0} == 1 ]]; then
repository="$FDS_ROOT/.host/frozen/$profile"
[[ -f $repository/aarch64-repodata ]] || die "Missing frozen repository for $profile"
fi
tools/in-void env XBPS_ARCH=aarch64 XBPS_TARGET_ARCH=aarch64 \
xbps-install -r "$root" -C "$work/config" \
-c "$FDS_ROOT/out/cache/rootfs" -i \
-R "$repository" \
-R "$FDS_ROOT/out/packages" -SyU --reproducible "${packages[@]}"
printf '%s\n' "$profile" >"$root/usr/share/fds/image-profile"
install -Dm644 fds-os.wiki/Internal-Storage.md "$root/usr/share/doc/fds/internal-storage.md"
install -Dm644 fds-os.wiki/Recovery.md "$root/usr/share/doc/fds/recovery.md"
install -Dm644 fds-os.wiki/Releases.md "$root/usr/share/doc/fds/releases.md"
install -Dm644 tools/capture-hardware "$root/usr/share/fds/capture-hardware"
python3 tools/rootfs-audit "$root" --unconfigured
epoch=$(git -C "$FDS_VOID" show -s --format=%ct HEAD)
tools/in-rootfs "$root" /usr/bin/env SOURCE_DATE_EPOCH="$epoch" /bin/bash /tmp/fds-finalize
# Apply the upstream iputils policy with direct QEMU and a namespace-local
# CAP_SETFCAP; the exported capability must be an actual persisted xattr.
tools/in-rootfs "$root" --direct /usr/bin/setcap CAP_NET_RAW+p /usr/bin/iputils-ping
tools/in-rootfs "$root" --direct /usr/bin/getcap /usr/bin/iputils-ping | grep -qx '/usr/bin/iputils-ping cap_net_raw=p'
python3 tools/rootfs-audit "$root"
tools/rootfs-runtime-check "$root"
# Preserve the exact selected package inputs, independently of future repository
# updates. Local FDS package versions can be rebuilt, so copy them per build.
archive_inputs=(out/cache/rootfs out/packages)
if [[ ${FDS_OFFLINE:-0} == 1 ]]; then
archive_inputs+=("$repository")
fi
python3 tools/rootfs-archive "$root" "$work" "${archive_inputs[@]}"
{
printf 'version=%s\n' "$(tools/version)"
printf 'profile=%s\nvoid_commit=%s\n' "$profile" "$(cat VOID_PACKAGES_COMMIT)"
printf 'emulation=private-user-namespace-binfmt\n'
tools/in-void xbps-query -p pkgver qemu-user-aarch64
date -u '+built_at=%Y-%m-%dT%H:%M:%SZ'
} >"$work/build.txt"
find packages/fds-base packages/fds-base-files packages/fds-init packages/fds-cli packages/fds-cartridged packages/fds-kernel packages/fds-eink packages/fds-dhcpcd profiles s6/source -type f -print0 | sort -z | \
xargs -0 sha256sum >"$work/build-inputs.sha256"
sha256sum image/base-packages.list tools/{build-rootfs,build-base-packages,build-fds,build-fds-package,build-kernel,in-void,in-rootfs,rootfs-namespace,finalize-rootfs,rootfs-audit,rootfs-archive,rootfs-runtime-check,rootfs-layout,rootfs_lib.py,lib.sh} \
>>"$work/build-inputs.sha256"
sha256sum fds-os.wiki/Recovery.md fds-os.wiki/Internal-Storage.md fds-os.wiki/Releases.md tools/capture-hardware tools/rust-notices tools/cargo-build .cargo/config.toml >>"$work/build-inputs.sha256"
cp out/manifests/fds-tools*.sha256 "$work/"
# The versioned build directory is the authoritative result; stable links are
# convenience pointers. Rename the archive last, after every acceptance check.
ln -sfn "${work##*/}/root" out/rootfs-aarch64
ln -sfn "../${work##*/}" out/manifests/rootfs-latest
ln -s "${work##*/}/rootfs-aarch64.tar" out/rootfs-aarch64.tar.next
mv -Tf out/rootfs-aarch64.tar.next out/rootfs-aarch64.tar
ln -s "${work##*/}/rootfs-aarch64.tar" "out/rootfs-$profile.tar.next"
mv -Tf "out/rootfs-$profile.tar.next" "out/rootfs-$profile.tar"
printf 'PASS: FDS rootfs built and verified: out/rootfs-aarch64.tar\n'