diff --git a/fedora/bootmenu/dracut/90ryoku-snapshot/module-setup.sh b/fedora/bootmenu/dracut/90ryoku-snapshot/module-setup.sh new file mode 100644 index 0000000000..0191a0e2c3 --- /dev/null +++ b/fedora/bootmenu/dracut/90ryoku-snapshot/module-setup.sh @@ -0,0 +1,26 @@ +#!/usr/bin/bash +# +# dracut module: boots a snapper snapshot from the "Ryoku snapshots" GRUB +# menu, read-only or restored. It runs after dracut has unlocked LUKS, so an +# encrypted disk restores the same way as a plain one. Only the images +# `ryoku boot-menu sync` builds for the snapshot entries carry it (dracut +# --add ryoku-snapshot); Fedora's own initramfs images stay as they are. + +check() { + return 255 +} + +depends() { + echo btrfs +} + +installkernel() { + hostonly='' instmods overlay +} + +# shellcheck disable=SC2154 # dracut sets moddir +install() { + inst_multiple mkdir mount umount mv date ln + inst_hook pre-mount 90 "$moddir/ryoku-snapshot-restore.sh" + inst_hook pre-pivot 10 "$moddir/ryoku-snapshot-preview.sh" +} diff --git a/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-preview.sh b/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-preview.sh new file mode 100644 index 0000000000..0a9d0b10ab --- /dev/null +++ b/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-preview.sh @@ -0,0 +1,44 @@ +#!/usr/bin/bash +# +# pre-pivot hook. rd.ryoku.preview= boots that +# read-only snapshot for a look: the snapshot is the lower layer of an overlay +# whose writes go to RAM, so the system runs normally and nothing on disk +# changes. sysroot.mount has already mounted the snapshot read-only (the +# entry's rootflags name it); the overlay is stacked on top of /sysroot, and +# its lower layer is a second mount under /run, which switch-root carries +# into the booted system. fstab's options for / name a btrfs subvolume, which +# the overlay refuses on remount, so systemd-remount-fs is masked for this +# boot only (/run). +# +# dracut sources hooks, so this returns and never exits. + +# shellcheck source=/dev/null +type getarg >/dev/null 2>&1 || . /lib/dracut-lib.sh + +ryoku_snapshot_preview() { + local snap dev run="${RYOKU_RUN:-/run}" newroot="${NEWROOT:-/sysroot}" + local base="$run/ryoku/preview" + snap=$(getarg rd.ryoku.preview=) || return 0 + case "$snap" in + "" | /* | *..* | *[!A-Za-z0-9._/-]*) warn "ryoku: refusing snapshot path '$snap'"; return 0 ;; + esac + dev=$(label_uuid_to_dev "$(getarg root=)") + mkdir -p "$base/lower" "$base/rw" + if ! mount -t btrfs -o "ro,subvol=$snap" "$dev" "$base/lower"; then + warn "ryoku: cannot mount $snap; booting it read-only as it is" + return 0 + fi + mount -t tmpfs -o mode=0755 ryoku-preview "$base/rw" + mkdir -p "$base/rw/upper" "$base/rw/work" + if ! mount -t overlay ryoku-preview \ + -o "lowerdir=$base/lower,upperdir=$base/rw/upper,workdir=$base/rw/work" "$newroot"; then + warn "ryoku: overlay failed; booting $snap read-only as it is" + umount "$base/rw" "$base/lower" + return 0 + fi + mkdir -p "$run/systemd/system" + ln -sf /dev/null "$run/systemd/system/systemd-remount-fs.service" + info "ryoku: previewing $snap; changes stay in RAM" +} + +ryoku_snapshot_preview diff --git a/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-restore.sh b/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-restore.sh new file mode 100644 index 0000000000..202fe2bcc6 --- /dev/null +++ b/fedora/bootmenu/dracut/90ryoku-snapshot/ryoku-snapshot-restore.sh @@ -0,0 +1,60 @@ +#!/usr/bin/bash +# +# pre-mount hook. rd.ryoku.restore= makes that +# snapshot the root subvolume again before it is mounted: the current root is +# renamed to .broken-