[5/7,releng] Add and use mkreproefi reproducible EFI build tool

Message ID 20190907112240.1028433-6-git@esotericnonsense.com
State New
Headers show
Series Making archiso deterministic | expand

Commit Message

Daniel Edgecumbe Sept. 7, 2019, 11:22 a.m. UTC
It is not possible to deterministically create FAT16 filesystems
using the kernel drivers, so we add this dependency on 'mtools'
and create efiboot.img using it.

Motivation: https://reproducible-builds.org

Signed-off-by: Daniel Edgecumbe <git@esotericnonsense.com>
---
 Makefile                |  2 ++
 archiso/mkreproefi      | 62 +++++++++++++++++++++++++++++++++++++++++
 configs/releng/build.sh | 10 ++-----
 3 files changed, 66 insertions(+), 8 deletions(-)
 create mode 100755 archiso/mkreproefi

Patch

diff --git a/Makefile b/Makefile
index 4ce70e7..1af9fdf 100644
--- a/Makefile
+++ b/Makefile
@@ -1,5 +1,6 @@ 
 # SPDX-License-Identifier: GPL-2.0
 # Copyright (C) 2005-2019 Arch Linux Release Engineering Team
+# Copyright (C) 2019 Daniel Edgecumbe <email@esotericnonsense.com>
 
 V=42
 
@@ -22,6 +23,7 @@  install: install-program install-initcpio install-examples install-doc
 
 install-program:
 	install -D -m 755 archiso/mkarchiso $(DESTDIR)/usr/bin/mkarchiso
+	install -D -m 755 archiso/mkreproefi $(DESTDIR)/usr/bin/mkreproefi
 
 install-initcpio:
 	install -d $(SCRIPT_DIR) $(HOOKS_DIR) $(INSTALL_DIR)
diff --git a/archiso/mkreproefi b/archiso/mkreproefi
new file mode 100755
index 0000000..ba3ba12
--- /dev/null
+++ b/archiso/mkreproefi
@@ -0,0 +1,62 @@ 
+#!/bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2019 Daniel Edgecumbe <email@esotericnonsense.com>
+
+set -e
+trap '[[ -d "${_tmpdir}" ]] && rm -rf "${_tmpdir}"' exit
+
+_tmpdir=$(mktemp -d)
+touch "${_tmpdir}/mkreproefi_was_here"
+
+die() {
+    echo $@ >&2
+    set -ex
+    exit 1
+}
+
+eecho() {
+    echo "${@}" >&2
+}
+
+usagedie() {
+    eecho "Usage: mkreproefi INPUT OUTPUT [FS_LABEL] [SIZE]"
+    eecho "Create an EFI image from an input directory"
+    eecho "Example: SOURCE_DATE_EPOCH=1234567890 mkreproefi efi/ efi.img MYEFI 64M"
+    die
+}
+
+checkdeps() {
+    type -P mmd > /dev/null || die "mmd not installed; install mtools?"
+    type -P mcopy > /dev/null || die "mcopy not installed; install mtools?"
+    type -P truncate > /dev/null || die "truncate not installed; install coreutils?"
+    type -P mkfs.fat > /dev/null || die "mkfs.fat not installed; install dosfstools?"
+}
+
+checkdeps
+
+[[ ${1} == "--help" ]] && usagedie
+[[ ${1} == "-h" ]] && usagedie
+
+[[ ${1} ]] || usagedie
+_input="${1}"
+
+[[ ${2} ]] || usagedie
+_output="${2}"
+
+if [[ ${3} ]]; then _fs_label="${3}"; else _fs_label="MKREPROEFI"; fi
+
+# Sane default.
+if [[ ${4} ]]; then _size="${4}"; else _size="256M"; fi
+
+[[ -d "${_input}" ]] || die "${_input} is not a directory"
+[[ ! -f "${_output}" ]] || die ${_output} already exists, not removing
+
+cp -a "${_input}"/* "${_tmpdir}"/
+
+# IMPORTANT NOTE: the epoch on FAT16 is 1980-01-01, not 1970-01-01 as in UNIX.
+# @315532800 is the lowest
+[[ ${SOURCE_DATE_EPOCH} ]] && find "${_tmpdir}" -mindepth 1 -print0 | xargs -0 touch -hcd "@${SOURCE_DATE_EPOCH}"
+
+truncate -s "${_size}" "${_output}"
+mkfs.fat --invariant -n "${_fs_label}" "${_output}"
+find "${_tmpdir}" -mindepth 1 -type d -printf '%P\0' | sort -z | xargs -I {} -0 -n 1 mcopy -i "${_output}" -m "${_tmpdir}/{}" "::{}"
diff --git a/configs/releng/build.sh b/configs/releng/build.sh
index 419ad7d..273b501 100755
--- a/configs/releng/build.sh
+++ b/configs/releng/build.sh
@@ -178,13 +178,6 @@  make_efi() {
 
 # Prepare efiboot.img::/EFI for "El Torito" EFI boot mode
 make_efiboot() {
-    mkdir -p ${work_dir}/iso/EFI/archiso
-    truncate -s 64M ${work_dir}/iso/EFI/archiso/efiboot.img
-    mkfs.fat -n ARCHISO_EFI ${work_dir}/iso/EFI/archiso/efiboot.img
-
-    mkdir -p ${work_dir}/efiboot
-    mount ${work_dir}/iso/EFI/archiso/efiboot.img ${work_dir}/efiboot
-
     mkdir -p ${work_dir}/efiboot/EFI/archiso
     cp ${work_dir}/iso/${install_dir}/boot/x86_64/vmlinuz ${work_dir}/efiboot/EFI/archiso/vmlinuz.efi
     cp ${work_dir}/iso/${install_dir}/boot/x86_64/archiso.img ${work_dir}/efiboot/EFI/archiso/archiso.img
@@ -210,7 +203,8 @@  make_efiboot() {
     cp ${work_dir}/iso/EFI/shellx64_v2.efi ${work_dir}/efiboot/EFI/
     cp ${work_dir}/iso/EFI/shellx64_v1.efi ${work_dir}/efiboot/EFI/
 
-    umount -d ${work_dir}/efiboot
+    mkdir -p ${work_dir}/iso/EFI/archiso
+    mkreproefi ${work_dir}/efiboot ${work_dir}/iso/EFI/archiso/efiboot.img ARCHISO_EFI 64M
 }
 
 # Build airootfs filesystem image