|
| 1 | +#!/bin/ash |
| 2 | +# |
| 3 | +# SPDX-License-Identifier: GPL-3.0-or-later |
| 4 | + |
| 5 | +# args: source, newroot, mountpoint |
| 6 | +_mnt_dmsnapshot() { |
| 7 | + local img="${1}" |
| 8 | + local newroot="${2}" |
| 9 | + local mnt="${3}" |
| 10 | + local img_fullname="${img##*/}"; |
| 11 | + local img_name="${img_fullname%%.*}" |
| 12 | + local dm_snap_name="${dm_snap_prefix}_${img_name}" |
| 13 | + local ro_dev ro_dev_size rw_dev |
| 14 | + |
| 15 | + ro_dev="$(losetup --find --show --read-only -- "${img}")" |
| 16 | + echo "${ro_dev}" >> /run/archiso/used_block_devices |
| 17 | + ro_dev_size="$(blockdev --getsz "${ro_dev}")" |
| 18 | + |
| 19 | + if [ "${cow_persistent}" = "P" ]; then |
| 20 | + if [ -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" ]; then |
| 21 | + msg ":: Found '/run/archiso/cowspace/${cow_directory}/${img_name}.cow', using as persistent." |
| 22 | + else |
| 23 | + msg ":: Creating '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' as persistent." |
| 24 | + truncate -s "${cow_spacesize}" "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" |
| 25 | + fi |
| 26 | + else |
| 27 | + if [ -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" ]; then |
| 28 | + msg ":: Found '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' but non-persistent requested, removing." |
| 29 | + rm -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" |
| 30 | + fi |
| 31 | + msg ":: Creating '/run/archiso/cowspace/${cow_directory}/${img_name}.cow' as non-persistent." |
| 32 | + truncate -s "${cow_spacesize}" "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" |
| 33 | + fi |
| 34 | + |
| 35 | + rw_dev="$(losetup --find --show "/run/archiso/cowspace/${cow_directory}/${img_name}.cow")" |
| 36 | + echo "${rw_dev}" >> /run/archiso/used_block_devices |
| 37 | + |
| 38 | + dmsetup create "${dm_snap_name}" --table \ |
| 39 | + "0 ${ro_dev_size} snapshot ${ro_dev} ${rw_dev} ${cow_persistent} ${cow_chunksize}" |
| 40 | + |
| 41 | + if [ "${cow_persistent}" != "P" ]; then |
| 42 | + rm -f "/run/archiso/cowspace/${cow_directory}/${img_name}.cow" |
| 43 | + fi |
| 44 | + |
| 45 | + _mnt_dev "/dev/mapper/${dm_snap_name}" "${newroot}${mnt}" "-w" "defaults" |
| 46 | + readlink -f "/dev/mapper/${dm_snap_name}" >> /run/archiso/used_block_devices |
| 47 | +} |
| 48 | + |
| 49 | +# args: source, newroot, mountpoint |
| 50 | +_mnt_overlayfs() { |
| 51 | + local src="${1}" |
| 52 | + local newroot="${2}" |
| 53 | + local mnt="${3}" |
| 54 | + mkdir -p "/run/archiso/cowspace/${cow_directory}/upperdir" "/run/archiso/cowspace/${cow_directory}/workdir" |
| 55 | + mount -t overlay -o \ |
| 56 | + "lowerdir=${src},upperdir=/run/archiso/cowspace/${cow_directory}/upperdir,workdir=/run/archiso/cowspace/${cow_directory}/workdir" \ |
| 57 | + airootfs "${newroot}${mnt}" |
| 58 | +} |
| 59 | + |
| 60 | + |
| 61 | +# args: /path/to/image_file, mountpoint |
| 62 | +_mnt_sfs() { |
| 63 | + local img="${1}" |
| 64 | + local mnt="${2}" |
| 65 | + local img_fullname="${img##*/}" |
| 66 | + local sfs_dev |
| 67 | + |
| 68 | + # shellcheck disable=SC2154 |
| 69 | + # defined via initcpio's parse_cmdline() |
| 70 | + if [ "${copytoram}" = "y" ]; then |
| 71 | + msg -n ":: Copying squashfs image to RAM..." |
| 72 | + if ! cp -- "${img}" "/run/archiso/copytoram/${img_fullname}" ; then |
| 73 | + echo "ERROR: while copy '${img}' to '/run/archiso/copytoram/${img_fullname}'" |
| 74 | + launch_interactive_shell |
| 75 | + fi |
| 76 | + img="/run/archiso/copytoram/${img_fullname}" |
| 77 | + msg "done." |
| 78 | + fi |
| 79 | + sfs_dev="$(losetup --find --show --read-only -- "${img}")" |
| 80 | + echo "${sfs_dev}" >> /run/archiso/used_block_devices |
| 81 | + _mnt_dev "${sfs_dev}" "${mnt}" "-r" "defaults" |
| 82 | +} |
| 83 | + |
| 84 | +# args: /path/to/image_file, mountpoint |
| 85 | +_mnt_erofs() { |
| 86 | + local img="${1}" |
| 87 | + local mnt="${2}" |
| 88 | + local img_fullname="${img##*/}" |
| 89 | + local erofs_dev |
| 90 | + |
| 91 | + # shellcheck disable=SC2154 |
| 92 | + # defined via initcpio's parse_cmdline() |
| 93 | + if [ "${copytoram}" = "y" ]; then |
| 94 | + msg -n ":: Copying EROFS image to RAM..." |
| 95 | + if ! cp -- "${img}" "/run/archiso/copytoram/${img_fullname}" ; then |
| 96 | + echo "ERROR: while copy '${img}' to '/run/archiso/copytoram/${img_fullname}'" |
| 97 | + launch_interactive_shell |
| 98 | + fi |
| 99 | + img="/run/archiso/copytoram/${img_fullname}" |
| 100 | + msg "done." |
| 101 | + fi |
| 102 | + erofs_dev="$(losetup --find --show --read-only -- "${img}")" |
| 103 | + echo "${erofs_dev}" >> /run/archiso/used_block_devices |
| 104 | + _mnt_dev "${erofs_dev}" "${mnt}" "-r" "defaults" "erofs" |
| 105 | +} |
| 106 | + |
| 107 | +# args: device, mountpoint, flags, opts |
| 108 | +_mnt_dev() { |
| 109 | + local dev="${1}" |
| 110 | + local mnt="${2}" |
| 111 | + local flg="${3}" |
| 112 | + local opts="${4}" |
| 113 | + local fstype="${5:-auto}" |
| 114 | + |
| 115 | + mkdir -p "${mnt}" |
| 116 | + |
| 117 | + msg ":: Mounting '${dev}' to '${mnt}'" |
| 118 | + |
| 119 | + while ! poll_device "${dev}" 30; do |
| 120 | + echo "ERROR: '${dev}' device did not show up after 30 seconds..." |
| 121 | + echo " Falling back to interactive prompt" |
| 122 | + echo " You can try to fix the problem manually, log out when you are finished" |
| 123 | + launch_interactive_shell |
| 124 | + done |
| 125 | + |
| 126 | + if mount -t "${fstype}" -o "${opts}" "${flg}" "${dev}" "${mnt}"; then |
| 127 | + msg ":: Device '${dev}' mounted successfully." |
| 128 | + else |
| 129 | + echo "ERROR; Failed to mount '${dev}'" |
| 130 | + echo " Falling back to interactive prompt" |
| 131 | + echo " You can try to fix the problem manually, log out when you are finished" |
| 132 | + launch_interactive_shell |
| 133 | + fi |
| 134 | +} |
| 135 | + |
| 136 | +_verify_checksum() { |
| 137 | + local _status |
| 138 | + cd "/run/archiso/bootmnt/${archisobasedir}/${arch}" || exit 1 |
| 139 | + sha512sum -c airootfs.sha512 > /tmp/checksum.log 2>&1 |
| 140 | + _status=$? |
| 141 | + cd -- "${OLDPWD}" || exit 1 |
| 142 | + return "${_status}" |
| 143 | +} |
| 144 | + |
| 145 | +_verify_signature() { |
| 146 | + local _status |
| 147 | + local sigfile="${1}" |
| 148 | + cd "/run/archiso/bootmnt/${archisobasedir}/${arch}" || exit 1 |
| 149 | + gpg --homedir /gpg --status-fd 1 --verify "${sigfile}" 2>/dev/null | grep -qE '^\[GNUPG:\] GOODSIG' |
| 150 | + _status=$? |
| 151 | + cd -- "${OLDPWD}" || exit 1 |
| 152 | + return ${_status} |
| 153 | +} |
| 154 | + |
| 155 | +run_hook() { |
| 156 | + [ -z "${arch}" ] && arch="$(uname -m)" |
| 157 | + [ -z "${copytoram_size}" ] && copytoram_size="75%" |
| 158 | + [ -z "${archisobasedir}" ] && archisobasedir="arch" |
| 159 | + [ -z "${dm_snap_prefix}" ] && dm_snap_prefix="arch" |
| 160 | + # shellcheck disable=SC2154 |
| 161 | + # defined via initcpio's parse_cmdline() |
| 162 | + [ -z "${archisodevice}" ] && archisodevice="/dev/disk/by-label/${archisolabel}" |
| 163 | + [ -z "${cow_spacesize}" ] && cow_spacesize="256M" |
| 164 | + # shellcheck disable=SC2154 |
| 165 | + # defined via initcpio's parse_cmdline() |
| 166 | + if [ -n "${cow_label}" ]; then |
| 167 | + cow_device="/dev/disk/by-label/${cow_label}" |
| 168 | + [ -z "${cow_persistent}" ] && cow_persistent="P" |
| 169 | + elif [ -n "${cow_device}" ]; then |
| 170 | + [ -z "${cow_persistent}" ] && cow_persistent="P" |
| 171 | + else |
| 172 | + cow_persistent="N" |
| 173 | + fi |
| 174 | + |
| 175 | + [ -z "${cow_flags}" ] && cow_flags="defaults" |
| 176 | + [ -z "${cow_directory}" ] && cow_directory="persistent_${archisolabel}/${arch}" |
| 177 | + [ -z "${cow_chunksize}" ] && cow_chunksize="8" |
| 178 | + |
| 179 | + # set mount handler for archiso |
| 180 | + export mount_handler="archiso_mount_handler" |
| 181 | +} |
| 182 | + |
| 183 | +# This function is called normally from init script, but it can be called |
| 184 | +# as chain from other mount handlers. |
| 185 | +# args: /path/to/newroot |
| 186 | +archiso_mount_handler() { |
| 187 | + local newroot="${1}" |
| 188 | + local sigfile |
| 189 | + |
| 190 | + if ! mountpoint -q "/run/archiso/bootmnt"; then |
| 191 | + _mnt_dev "${archisodevice}" "/run/archiso/bootmnt" "-r" "defaults" |
| 192 | + if [ "${copytoram}" != "y" ]; then |
| 193 | + readlink -f "${archisodevice}" >> /run/archiso/used_block_devices |
| 194 | + fi |
| 195 | + fi |
| 196 | + |
| 197 | + # shellcheck disable=SC2154 |
| 198 | + # defined via initcpio's parse_cmdline() |
| 199 | + if [ "${checksum}" = "y" ]; then |
| 200 | + if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sha512" ]; then |
| 201 | + msg -n ":: Self-test requested, please wait..." |
| 202 | + if _verify_checksum; then |
| 203 | + msg "done. Checksum is OK, continue booting." |
| 204 | + else |
| 205 | + echo "ERROR: one or more files are corrupted" |
| 206 | + echo "see /tmp/checksum.log for details" |
| 207 | + launch_interactive_shell |
| 208 | + fi |
| 209 | + else |
| 210 | + echo "ERROR: checksum=y option specified but ${archisobasedir}/${arch}/airootfs.sha512 not found" |
| 211 | + launch_interactive_shell |
| 212 | + fi |
| 213 | + fi |
| 214 | + |
| 215 | + # shellcheck disable=SC2154 |
| 216 | + # defined via initcpio's parse_cmdline() |
| 217 | + if [ "${verify}" = "y" ]; then |
| 218 | + if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs.sig" ]; then |
| 219 | + sigfile="airootfs.sfs.sig" |
| 220 | + elif [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs.sig" ]; then |
| 221 | + sigfile="airootfs.erofs.sig" |
| 222 | + fi |
| 223 | + if [ -n "${sigfile}" ]; then |
| 224 | + msg -n ":: Signature verification requested, please wait..." |
| 225 | + if _verify_signature "${sigfile}"; then |
| 226 | + msg "done. Signature is OK, continue booting." |
| 227 | + else |
| 228 | + echo "ERROR: one or more files are corrupted" |
| 229 | + launch_interactive_shell |
| 230 | + fi |
| 231 | + else |
| 232 | + echo "ERROR: verify=y option specified but GPG signature not found in ${archisobasedir}/${arch}/" |
| 233 | + launch_interactive_shell |
| 234 | + fi |
| 235 | + fi |
| 236 | + |
| 237 | + if [ "${copytoram}" = "y" ]; then |
| 238 | + msg ":: Mounting /run/archiso/copytoram (tmpfs) filesystem, size=${copytoram_size}" |
| 239 | + mkdir -p /run/archiso/copytoram |
| 240 | + mount -t tmpfs -o "size=${copytoram_size}",mode=0755 copytoram /run/archiso/copytoram |
| 241 | + fi |
| 242 | + |
| 243 | + if [ -n "${cow_device}" ]; then |
| 244 | + _mnt_dev "${cow_device}" "/run/archiso/cowspace" "-r" "${cow_flags}" |
| 245 | + readlink -f "${cow_device}" >> /run/archiso/used_block_devices |
| 246 | + mount -o remount,rw "/run/archiso/cowspace" |
| 247 | + else |
| 248 | + msg ":: Mounting /run/archiso/cowspace (tmpfs) filesystem, size=${cow_spacesize}..." |
| 249 | + mkdir -p /run/archiso/cowspace |
| 250 | + mount -t tmpfs -o "size=${cow_spacesize}",mode=0755 cowspace /run/archiso/cowspace |
| 251 | + fi |
| 252 | + mkdir -p "/run/archiso/cowspace/${cow_directory}" |
| 253 | + chmod 0700 "/run/archiso/cowspace/${cow_directory}" |
| 254 | + |
| 255 | + if [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" ]; then |
| 256 | + _mnt_sfs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.sfs" "/run/archiso/airootfs" |
| 257 | + elif [ -f "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs" ]; then |
| 258 | + _mnt_erofs "/run/archiso/bootmnt/${archisobasedir}/${arch}/airootfs.erofs" "/run/archiso/airootfs" |
| 259 | + fi |
| 260 | + if [ -f "/run/archiso/airootfs/airootfs.img" ]; then |
| 261 | + _mnt_dmsnapshot "/run/archiso/airootfs/airootfs.img" "${newroot}" "/" |
| 262 | + else |
| 263 | + _mnt_overlayfs "/run/archiso/airootfs" "${newroot}" "/" |
| 264 | + fi |
| 265 | + |
| 266 | + if [ "${copytoram}" = "y" ]; then |
| 267 | + umount -d /run/archiso/bootmnt |
| 268 | + rmdir /run/archiso/bootmnt |
| 269 | + fi |
| 270 | +} |
| 271 | + |
| 272 | +# vim: set ft=sh: |
0 commit comments