#!/bin/sh : ${ROOT_MKFS_CMD:=mkfs.ext4 -q} : ${ROOT_FS_TYPE:=ext4} losetup() { /sbin/losetup "$@"; } luks_secret() { local parms=$-; # this junk keeps set -x from being too annoying set +x [ -n "$luks_secret" ] || luks_secret="$(head -c256 /dev/urandom)" printf %s "$luks_secret" case $parms in *x*) set -x; set -x ;; esac } floor4() { # Negatives round up, but aren't used. echo $(($1 / 4 * 4)) } ceil4() { local x="$1" [ $((x % 4)) -eq 0 ] || x=$((x + 4 - x % 4)) printf '%d\n' "$x" } init_samizdat() { local imgfile="$1" megs="$2" keyfile="$3" dev init_samizdat_blockdev "$imgfile" "$megs" "$keyfile" || return local blockdev=/dev/mapper/samizdatcrypt mount -t btrfs -o subvol=ROOT /cdrom/live/filesystem.btrfs /root || return btrfs device add "$blockdev" /root || return mount -o rw,remount /root || return btrfs subvolume create /root/gpg || return # TODO: Restart gpg agent with stored credentials. # TODO: Actually, if we unconditionally added a ramdisk, we could go # ahead with the boot, and then do this whole thing from the installed # system (after pivot_root). That way, there would be no need to # restart. # Really, the option to install could be identical to the option to # boot from RAM except that it would record the intent to install; or # else it could be removed entirely, with an option to persist added # as some kind of UI element. mv /gpg/gnupghome /root/gpg/ || return bootdone root-mounted } open_samizdat() { open_samizdat_blockdev "$@" || return local blockdev=/dev/mapper/samizdatcrypt losetup -f /cdrom/live/filesystem.btrfs || return modprobe btrfs || return btrfs device scan || return mount -t btrfs -o subvol=ROOT "$blockdev" /root || return bootdone root-mounted } init_samizdat_lodev() { local imgfile="$1" megs=$(ceil4 "$2") truncate -s ${megs}M "$imgfile" || return dev=$(losetup -f) && losetup "$dev" "$imgfile" || return echo "$dev" } open_samizdat_blockdev() { local imgfile="$1" keyfile="$2" dev local cryptname=samizdatcrypt dev=$(losetup -f) && losetup "$dev" "$imgfile" || return gpg2 --verify "$keyfile" || return # The first --decrypt merely strips the signature. The option is # poorly named for that case. gpg2 --decrypt "$keyfile" | gpg2 --decrypt | cryptsetup --key-file - luksOpen "$dev" "$cryptname" || return [ -b /dev/mapper/"$cryptname" ] || return } init_samizdat_blockdev() { local imgfile="$1" megs="$2" keyfile="$3" dev local cryptname=samizdatcrypt dev=$(init_samizdat_lodev "$imgfile" "$megs") || return [ ! -b /dev/mapper/"$cryptname" ] || return luks_secret >/dev/null luks_secret | gpg2 --default-recipient-self --encrypt --armor | gpg2 --clearsign --output "$keyfile" || return luks_secret | cryptsetup luksFormat "$dev" - || return cryptsetup luksDump "$dev" >&2 luks_secret | cryptsetup --key-file - luksOpen "$dev" "$cryptname" || return [ -b /dev/mapper/"$cryptname" ] || return } majmin() { local dev="$1" major minor eval $(stat -c 'major=%t minor=%T' "$dev") || return [ "$major" -a "$minor" ] || return printf '%d:%d\n' 0x$major 0x$minor } cryptdev_to_dev() { local dev="$1" majmin majmin=$(majmin "$dev") || return set -- /sys/dev/block/$majmin/slaves/* [ $# = 1 ] || return cryptsetup status "$dev" |while read k v; do if [ "$k" = device: ]; then echo $v; break; fi; done } cryptdev_to_backing_file() { local dev="$1" majmin result majmin="$(majmin "$dev")" || return set -- /sys/dev/block/$majmin/slaves/* [ $# = 1 ] || return read result < "$1"/loop/backing_file || return printf '%s\n' "$result" } lodev_to_file() { local result majmin dev="$1" majmin="$(majmin "$dev")" || return read result < /sys/dev/block/$majmin/loop/backing_file || return printf '%s' "$result" } mountpoint_to_dev() { local wantmp="$1" dev mp rest mountpoint -q "$wantmp" || return while read dev mp rest; do if [ "$mp" = "$wantmp" ]; then echo "$dev"; return; fi; done < /proc/mounts return 1 } get_cdrom_sizelimit() { # returns bytes local dev="$1" sectors sectors=$(blockdev --getsz "$dev") || return if dd count=2 if="$dev" bs=2048 skip=$((sectors/4 - 2)) of=/dev/null 2>/dev/null; then return else echo $(((sectors-8)*512)) fi } init_gpg() { bootwait samizdat-cdrom export GNUPGHOME=/gpg/gnupghome (umask 077; rsync --exclude '/luks-key*' --ignore-existing -rpP /cdrom/samizdat/gpg/ /gpg/) if samizdat-password-agent >/var/log/samizdat-password-agent.log 2>&1; then clear true else false fi } start_meter() { local startmsg="$*" (exec >&4 clear echo -n $startmsg set +x while sleep 2; do echo -n . done) & meterpid=$! } stop_meter() { local endmsg="$*" kill $meterpid echo " $endmsg" >&4 }