#! /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 <&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} </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