Add build-zfs-srm, a script to build ZFS support for SystemRescue

This commit is contained in:
Daniel Richard G 2024-02-27 22:16:16 -05:00
parent 53b50c42e1
commit dbc09046b4

View file

@ -0,0 +1,248 @@
#! /usr/bin/env bash
#
# build-zfs-srm - build ZFS support for SystemRescue
#
# This script builds a SystemRescue Module (SRM) file that adds support
# for the ZFS file system to a running instance of SystemRescue.
#
# Author: Daniel Richard G.
# SPDX-License-Identifier: GPL-3.0-or-later
#
# SystemRescue cannot be distributed with ZFS support due to licensing
# issues, but users are free to build ZFS for SystemRescue themselves.
# As the build process is non-trivial, it has been elaborated in this
# script as a service to the SystemRescue community.
#
# Usage:
# ./build-zfs-srm [--latest]
#
# By default, this script will build the version of ZFS that was current
# (in the AUR repo) at the time of the host system's release. If the
# --latest option is given, then it will instead build the latest version
# available now (when the script is run).
#
# Note that the build is performed reproducibly; i.e. re-running the
# build in the same environment should yield exactly the same output
# file. Thus, builds performed with --latest will produce different
# output as new ZFS versions become available, whereas builds performed
# without should (in theory) remain unchanged in perpetuity.
#
# For more information, refer to
# https://www.system-rescue.org/scripts/build-zfs-srm/
#
use_latest_zfs=no
while [ -n "$1" ]
do
case "$1" in
--latest) use_latest_zfs=yes ;;
-h|--help) echo "$0: see comment header of script for usage info"; exit 0 ;;
-*) echo "$0: error: unrecognized option \"$1\""; exit 1 ;;
*) echo "$0: error: unrecognized argument \"$1\""; exit 1 ;;
esac
shift
done
# Sanity checks
if [ ! -f /etc/arch-release ] || ! /usr/bin/pacman --version >/dev/null 2>&1
then
echo "$0: error: this script must be run on SystemRescue / Arch Linux"
exit 1
fi
if [ $(id -u) -ne 0 ]
then
echo "$0: error: this script must be run as root"
exit 1
fi
if [ $(awk '$1=="MemAvailable:"{print $2}' /proc/meminfo) -lt 3500000 ] && \
! make --version >/dev/null 2>&1
then
echo "$0: error: not enough RAM available for build, ~4 GB needed"
exit 1
fi
set -e -u
# Use this timestamp for reproducibility
t_epoch=$(stat -c '%Y' /etc/os-release)
t_date=$(date -d @${t_epoch} -R)
# Are we in an actual live running instance of SystemRescue?
# (The expected alternative is an "archlinux" Docker container)
in_live_system=$(test "_$(findmnt -n -o SOURCE /)" = _airootfs && echo true || echo false)
srm_file=/tmp/$(. /etc/os-release && echo ${ID}-${VERSION_ID}-zfs.srm)
srm_info=${srm_file%.srm}.txt
cat <<END
==== Building ${srm_file} ====
Reproducible build timestamp: ${t_epoch} (${t_date})
Running in SystemRescue live system: ${in_live_system}
END
run_command()
{
echo "+ $*" >&2
env "$@"
}
# Install some prerequisites
run_command pacman -Sy --needed --noconfirm base-devel git
reinstall_if_missing()
{
local pkg="$1"
local file="$2"
test -f ${file} || run_command pacman -S --noconfirm ${pkg}
}
# Many packages in the SystemRescue ISO have had files removed to save on
# space, but we will need to restore some of them to build ZFS. Reinstall
# the following packages as needed:
reinstall_if_missing curl /usr/include/curl/curl.h
reinstall_if_missing glibc /usr/lib/libc_nonshared.a
reinstall_if_missing libtirpc /usr/include/tirpc/rpc/xdr.h
reinstall_if_missing linux-api-headers /usr/include/linux/limits.h
reinstall_if_missing openssl /usr/include/openssl/evp.h
reinstall_if_missing pam /usr/include/security/pam_modules.h
reinstall_if_missing systemd-libs /usr/include/libudev.h
reinstall_if_missing util-linux-libs /usr/include/uuid/uuid.h
reinstall_if_missing zlib /usr/include/zlib.h
if ${in_live_system}
then
# More disk space is available in a tmpfs
work_dir=/tmp/zfsbuild
else
work_dir=/home/zfsbuild
fi
if [ ! -d ${work_dir} ]
then
run_command useradd --create-home --home-dir ${work_dir} zfsbuild
fi
run_as_user()
{
local cmd="$1"
setpriv \
--reuid=zfsbuild \
--regid=zfsbuild \
--init-groups \
--no-new-privs \
--reset-env \
bash -e -x -c "${cmd}"
}
cd ${work_dir}
# Build these two essential ZFS packages from the AUR
for aur_pkg in \
zfs-dkms \
zfs-utils
do
if [ ! -d ${aur_pkg} ]
then
run_as_user "git clone https://aur.archlinux.org/${aur_pkg}.git"
fi
if [ ! -f ${aur_pkg}.repro.stamp -a ${use_latest_zfs} = no ]
then
run_as_user "cd ${aur_pkg} && rev=\$(git rev-list -n 1 --first-parent --before=@${t_epoch} HEAD) && git checkout \${rev}"
touch ${aur_pkg}.repro.stamp
fi
if [ ! -f ${aur_pkg}.pgp.stamp ]
then
run_as_user ". ${aur_pkg}/PKGBUILD && gpg --recv-keys \${validpgpkeys[*]}"
touch ${aur_pkg}.pgp.stamp
fi
if [ ! -f ${aur_pkg}.build.stamp ]
then
run_as_user "cd ${aur_pkg} && makepkg --clean"
run_as_user "cd ${aur_pkg} && git rev-parse HEAD" > ${aur_pkg}.commit.txt
touch ${aur_pkg}.build.stamp
fi
done
# Install more prerequisites
run_command pacman -S --needed --noconfirm \
dkms linux-lts linux-lts-headers squashfs-tools
# Tweak DKMS configuration
x=/etc/dkms/framework.conf
if ! grep -q '^dkms_tree=' $x && ${in_live_system}
then
# More disk space is available in a tmpfs
mkdir -p /tmp/dkms
(echo; echo 'dkms_tree="/tmp/dkms"') >> $x
fi
if ! grep -q '^sign_file=' $x
then
# Do not sign the kernel modules as this breaks reproducibility
(echo; echo 'sign_file="/nope"') >> $x
fi
if ! ${in_live_system}
then
# The Docker container does not extract/install man pages from
# packages, but we want the SRM to include those
perl -pi -e '/^NoExtract\s*=/ && m! usr/share/man/! and s/^/#/' \
/etc/pacman.conf
fi
# Kernel module builds need the kernel file in the standard location
x=/run/archiso/bootmnt/sysresccd/boot/x86_64/vmlinuz
y=/boot/vmlinuz-linux-lts
if [ -f $x -a ! -f $y ]
then
run_command ln -s $x $y
fi
# Do not pass the -j option to pahole(1) as it breaks reproducibility
# https://github.com/acmel/dwarves/issues/42
perl -pi -e 's/^(\s*)(extra_paholeopt=".* -j")/${1}true $2/' \
/lib/modules/*-lts/build/scripts/pahole-flags.sh
# Install the newly-built ZFS packages, and let DKMS do its thing
run_command pacman -U --needed --noconfirm \
zfs-utils/zfs-utils-*.pkg.tar.zst \
zfs-dkms/zfs-dkms-*.pkg.tar.zst
# Generate list of files in the zfs-utils package
pacman -Ql zfs-utils \
| sed 's!^zfs-utils /!!' \
| grep -v '/$' \
> zfs-utils.files.txt
# mksquashfs(1) uses this
export SOURCE_DATE_EPOCH=${t_epoch}
# Create the SRM file
rm -f ${srm_file}
(cd / && tar cf - --sort=name \
usr/lib/modules/*-lts/updates/dkms/* \
usr/lib/modules/*-lts/modules.* \
-T ${work_dir}/zfs-utils.files.txt) \
| run_command mksquashfs - ${srm_file} -comp xz -tar -exports
tee ${srm_info} <<END
==== SystemRescue Module (SRM) build successful ====
Build host : $(. /etc/os-release && echo ${NAME} ${VERSION_ID})
Repro. timestamp : @${t_epoch} (${t_date})
zfs-dkms version : $(. zfs-dkms/PKGBUILD && echo ${pkgver}-${pkgrel})
* AUR Git commit : $(cat zfs-dkms.commit.txt 2>/dev/null || echo unknown)
zfs-utils version: $(. zfs-utils/PKGBUILD && echo ${pkgver}-${pkgrel})
* AUR Git commit : $(cat zfs-utils.commit.txt 2>/dev/null || echo unknown)
SRM file location: ${srm_file}
SRM file size : $(stat -c '%s' ${srm_file}) bytes
SRM file SHA-1 : $(sha1sum < ${srm_file} | awk '{print $1}')
SRM file SHA-512 : $(sha512sum < ${srm_file} | awk '{print $1}')
Please visit https://www.system-rescue.org/Modules/ for instructions on
loading the SRM file into a running instance of SystemRescue.
END
# EOF