Support EROFS

EROFS, like Squashfs, is a read-only file system. It can be used to store airootfs in an image file.
Its advantage is the support for POSIX ACLs. EROFS downside is that currently it only supports LZ4 compression (LZMA support is not yet fully implemented).

A difference from Squashfs is that, EROFS stores change time (ctime) not modification time (mtime). The reverse is true for Squashfs.

Implements https://gitlab.archlinux.org/archlinux/archiso/-/issues/59
This commit is contained in:
nl6720 2020-10-24 15:53:57 +03:00
parent 711ab4cd1e
commit bc67933af1
No known key found for this signature in database
GPG Key ID: 5CE88535E188D369
6 changed files with 85 additions and 12 deletions

View File

@ -49,9 +49,11 @@ The image file is constructed from some of the variables in **profiledef.sh**: `
- `squashfs`: Create a squashfs image directly from the airootfs work directory
- `ext4+squashfs`: Create an ext4 partition, copy the airootfs work directory to it and create a squashfs image from it
* `airootfs_image_tool_options`: An array of options to pass to the tool to create the airootfs image. Currently only
`mksquashfs` is supported - see `mksquashfs --help` for all possible options (defaults to `('-comp' 'xz')`).
- `file_permissions`: An associative array that lists files and/or directories who need specific ownership or
- `erofs`: Create an EROFS image for the airootfs work directory
* `airootfs_image_tool_options`: An array of options to pass to the tool to create the airootfs image. `mksquashfs` and
`mkfs.erofs` are supported. See `mksquashfs --help` or `mkfs.erofs --help` for all possible options (defaults to
`('-comp' 'xz')` for squashfs).
* `file_permissions`: An associative array that lists files and/or directories who need specific ownership or
permissions. The array's keys contain the path and the value is a colon separated list of owner UID, owner GID and
access mode. E.g. `file_permissions=(["/etc/shadow"]="0:0:400")`.

View File

@ -81,12 +81,36 @@ _mnt_sfs() {
_mnt_dev "${sfs_dev}" "${mnt}" "-r" "defaults"
}
# args: /path/to/image_file, mountpoint
_mnt_erofs() {
local img="${1}"
local mnt="${2}"
local img_fullname="${img##*/}"
local erofs_dev
# shellcheck disable=SC2154
# defined via initcpio's parse_cmdline()
if [ "${copytoram}" = "y" ]; then
msg -n ":: Copying EROFS image to RAM..."
if ! cp -- "${img}" "/run/archiso/copytoram/${img_fullname}" ; then
echo "ERROR: while copy '${img}' to '/run/archiso/copytoram/${img_fullname}'"
launch_interactive_shell
fi
img="/run/archiso/copytoram/${img_fullname}"
msg "done."
fi
erofs_dev="$(losetup --find --show --read-only -- "${img}")"
echo "${erofs_dev}" >> /run/archiso/used_block_devices
_mnt_dev "${erofs_dev}" "${mnt}" "-r" "defaults" "erofs"
}
# args: device, mountpoint, flags, opts
_mnt_dev() {
local dev="${1}"
local mnt="${2}"
local flg="${3}"
local opts="${4}"
local fstype="${5:-auto}"
mkdir -p "${mnt}"
@ -99,7 +123,7 @@ _mnt_dev() {
launch_interactive_shell
done
if mount -o "${opts}" "${flg}" "${dev}" "${mnt}"; then
if mount -t "${fstype}" -o "${opts}" "${flg}" "${dev}" "${mnt}"; then
msg ":: Device '${dev}' mounted successfully."
else
echo "ERROR; Failed to mount '${dev}'"
@ -120,8 +144,9 @@ _verify_checksum() {
_verify_signature() {
local _status
local sigfile="${1}"
cd "/run/archiso/bootmnt/${archisobasedir}/${arch}" || exit 1
gpg --homedir /gpg --status-fd 1 --verify airootfs.sfs.sig 2>/dev/null | grep -qE '^\[GNUPG:\] GOODSIG'
gpg --homedir /gpg --status-fd 1 --verify "${sigfile}" 2>/dev/null | grep -qE '^\[GNUPG:\] GOODSIG'
_status=$?
cd -- "${OLDPWD}" || exit 1
return ${_status}
@ -160,6 +185,7 @@ run_hook() {
# args: /path/to/newroot
archiso_mount_handler() {
local newroot="${1}"
local sigfile
if ! mountpoint -q "/run/archiso/bootmnt"; then
_mnt_dev "${archisodevice}" "/run/archiso/bootmnt" "-r" "defaults"
@ -190,15 +216,20 @@ archiso_mount_handler() {
# defined via initcpio's parse_cmdline()
if [ "${verify}" = "y" ]; then
if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs.sig" ]; then
sigfile="airootfs.sfs.sig"
elif [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs.sig" ]; then
sigfile="airootfs.erofs.sig"
fi
if [ -n "${sigfile}" ]; then
msg -n ":: Signature verification requested, please wait..."
if _verify_signature; then
if _verify_signature "${sigfile}"; then
msg "done. Signature is OK, continue booting."
else
echo "ERROR: one or more files are corrupted"
launch_interactive_shell
fi
else
echo "ERROR: verify=y option specified but ${archisobasedir}/${arch}/airootfs.sfs.sig not found"
echo "ERROR: verify=y option specified but GPG signature not found in ${archisobasedir}/${arch}/"
launch_interactive_shell
fi
fi
@ -221,7 +252,11 @@ archiso_mount_handler() {
mkdir -p "/run/archiso/cowspace/${cow_directory}"
chmod 0700 "/run/archiso/cowspace/${cow_directory}"
if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" ]; then
_mnt_sfs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" "/run/archiso/airootfs"
elif [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs" ]; then
_mnt_erofs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs" "/run/archiso/airootfs"
fi
if [ -f "/run/archiso/airootfs/airootfs.img" ]; then
_mnt_dmsnapshot "/run/archiso/airootfs/airootfs.img" "${newroot}" "/"
else

View File

@ -39,6 +39,7 @@ _curl_get() {
archiso_pxe_http_mount_handler () {
newroot="${1}"
local img_type="sfs"
msg ":: Mounting /run/archiso/httpspace (tmpfs) filesystem, size='${archiso_http_spc}'"
mkdir -p "/run/archiso/httpspace"
@ -46,7 +47,12 @@ archiso_pxe_http_mount_handler () {
# shellcheck disable=SC2154
# defined via initcpio's parse_cmdline()
_curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sfs" "/${arch}"
if ! curl -L -f -o /dev/null -s -r 0-0 "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sfs"; then
if curl -L -f -o /dev/null -s -r 0-0 "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.erofs"; then
img_type="erofs"
fi
fi
_curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.${img_type}" "/${arch}"
# shellcheck disable=SC2154
# defined via initcpio's parse_cmdline()
@ -56,7 +62,7 @@ archiso_pxe_http_mount_handler () {
# shellcheck disable=SC2154
# defined via initcpio's parse_cmdline()
if [ "${verify}" = "y" ]; then
_curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.sfs.sig" "/${arch}"
_curl_get "${archiso_http_srv}${archisobasedir}/${arch}/airootfs.${img_type}.sig" "/${arch}"
fi
mkdir -p "/run/archiso/bootmnt"

View File

@ -200,13 +200,30 @@ _mkairootfs_squashfs() {
install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}"
_msg_info "Creating SquashFS image, this may take some time..."
_run_mksquashfs "${airootfs_dir}"
}
# Makes an EROFS file system from a source directory.
_mkairootfs_erofs() {
local fsuuid
[[ -e "${airootfs_dir}" ]] || _msg_error "The path '${airootfs_dir}' does not exist" 1
install -d -m 0755 -- "${isofs_dir}/${install_dir}/${arch}"
local image_path="${isofs_dir}/${install_dir}/${arch}/airootfs.erofs"
# Generate reproducible file system UUID from SOURCE_DATE_EPOCH
fsuuid="$(uuidgen --sha1 --namespace 93a870ff-8565-4cf3-a67b-f47299271a96 --name "${SOURCE_DATE_EPOCH}")"
_msg_info "Creating EROFS image, this may take some time..."
mkfs.erofs -U "${fsuuid}" "${airootfs_image_tool_options[@]}" -- "${image_path}" "${airootfs_dir}"
_msg_info "Done!"
}
_mkchecksum() {
_msg_info "Creating checksum file for self-test..."
cd -- "${isofs_dir}/${install_dir}/${arch}"
if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then
sha512sum airootfs.sfs > airootfs.sha512
elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then
sha512sum airootfs.erofs > airootfs.sha512
fi
cd -- "${OLDPWD}"
_msg_info "Done!"
}
@ -214,7 +231,11 @@ _mkchecksum() {
_mksignature() {
_msg_info "Signing SquashFS image..."
cd -- "${isofs_dir}/${install_dir}/${arch}"
if [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.sfs" ]]; then
gpg --detach-sign --default-key "${gpg_key}" airootfs.sfs
elif [[ -e "${isofs_dir}/${install_dir}/${arch}/airootfs.erofs" ]]; then
gpg --detach-sign --default-key "${gpg_key}" airootfs.erofs
fi
cd -- "${OLDPWD}"
_msg_info "Done!"
}
@ -634,6 +655,13 @@ _validate_requirements_airootfs_image_type_ext4+squashfs() {
_validate_requirements_airootfs_image_type_squashfs
}
_validate_requirements_airootfs_image_type_erofs() {
if ! command -v mkfs.erofs; then
(( validation_error=validation_error+1 ))
_msg_error "Validating '${airootfs_image_type}': mkfs.erofs is not available on this host. Install 'erofs-utils'!" 0
fi
}
# SYSLINUX El Torito
_add_xorrisofs_options_bios.syslinux.eltorito() {
xorrisofs_options+=(

View File

@ -10,6 +10,7 @@ install_dir="arch"
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' 'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito')
arch="x86_64"
pacman_conf="pacman.conf"
airootfs_image_type="squashfs"
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
file_permissions=(
["/etc/shadow"]="0:0:400"

View File

@ -10,6 +10,7 @@ install_dir="arch"
bootmodes=('bios.syslinux.mbr' 'bios.syslinux.eltorito' 'uefi-x64.systemd-boot.esp' 'uefi-x64.systemd-boot.eltorito')
arch="x86_64"
pacman_conf="pacman.conf"
airootfs_image_type="squashfs"
airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M')
file_permissions=(
["/etc/shadow"]="0:0:400"