#!/bin/sh . common.sh DEVNAME=$1 case "$DEVNAME" in /dev/loop*|/dev/ram*|/dev/dm-*|/dev/md*|/dev/fd*) exit ;; esac [ -b "$DEVNAME" ] || exit debug_log "grok-block.${DEVNAME##*/}" addmenu_choosekey() { dev=$1 dir=$2 addmenu "$dev//$dir" \ "[ Use the GPG key on $dev ]" \ "menu-select boot-gpg $dev $dir" } addmenu_repairhfs() { local device="$1" addmenu "$device//reboot" \ "[ Reboot into Mac OS X in order to repair disk $device ]" \ "eject /cdrom; sleep 2; reboot -f" addmenu "$device//fsck" \ "[ (DANGEROUS) Try to repair errors on $device with fsck.hfsplus ]" \ "/bin/openvt -sw -- sh -c 'fsck.hfsplus $device && remenu'" } addmenu_chooseroot() { local device="$1" loopfile="$2" addmenu "$device//$loopfile" \ "[ Boot the system on $device${loopfile:+ in file $(basename $loopfile)} ]" \ "menu-select --fs=$ID_FS_TYPE boot-luks $device ${loopfile:-$device}" } addmenu_choose_native_root() { local device="$1" loopfile="$2" addmenu "$device//$device" \ "[ Boot the system on $device ]" \ "menu-select --fs=$ID_FS_TYPE boot-native $device" } addmenu_makeroot() { local device="$1" loopfile="$2" megs="$3" copy_cdrom="$4" ( addmenu "$device//$loopfile" \ "[ Install Samizdat to $device (in file $(basename $loopfile)) ]" \ "menu-select --fs=$ID_FS_TYPE boot-new $device $loopfile $megs $copy_cdrom" ) & } addmenu_destroy_hard_drive() { local device="$1" ( addmenu "$device//$device" \ "[ Install Samizdat to $device -- THIS DESTROYS ALL DATA ]" \ "menu-select boot-destroy-disk $device" ) & } retry_mount() { tries=20 until mntout="$(mount "$@" 2>&1)" do tries=$(( tries - 1 )) case "$mntout" in *"Device or resource busy"*) if [ $tries -le 0 ]; then warn "mount $@ failed: $mntout" return 1 else sleep 1 continue fi ;; *) warn "mount $@ failed: $mntout" break ;; esac done } Gpg2() { gpg2 --lock-never --no-permission-warning --no-auto-check-trustdb --no-options "$@" } gpg_verify() { [ -e "$1" ] || return bootwait samizdat-gpg export GNUPGHOME=/gpg/gnupghome Gpg2 --verify "$1" } gpg_can_decrypt() { [ -e "$1" ] || return bootwait samizdat-gpg Gpg2 --decrypt "$1" | Gpg2 --decrypt "$1" >/dev/null } is_lvm() { for n in 0 1 2 3; do [ "LVM2 001" = "$(dd if="$1" bs=1 skip=$((512*n+24)) count=8 2>/dev/null)" ] && return 0 done return 1 } is_device_without_partitions() { case "$1" in /dev/nbd*|/dev/sr*|*[0-9]) return 1 ;; esac [ "$(parted -sm "$1" print | grep -c :)" = 1 ] } is_incomplete_samizdat_install() { # TODO: Possibly only some of the partitions are incomplete local partition_names="$(parted -sm "$1" print | sed 1,2d | awk -F: -e '{printf "%s:", $6}')" [ "$partition_names" = 'samizdat-grub-incomplete:samizdat-plaintext-incomplete:samizdat-luks-encrypted-incomplete:' ] } parent_device() { local d="$1" while [ "$d" != "${d%[0-9]}" ]; do d=${d%[0-9]}; done printf '%s' "$d" } wait_for_files_() { : wait_for_files: Polling... ( set +x local f for f in "$@"; do while ! [ -e "$f" ]; do sleep 0.1; done done ) : wait_for_files: ...finished. } grok_block() { local mountpoint="/mnt/${DEVNAME##*/}" mkdir -p "$mountpoint" case "$ID_FS_TYPE" in ntfs) mount_type='-t ntfs-3g' ;; "") mount_type= ;; *) mount_type="-t $ID_FS_TYPE" ;; esac # Skip partitions that we created. # The name 'samizdat-plaintext' is recognized and used to add the menu entry, below. case "$DEVNAME" in # Avoid mouting this multiple times in case this script gets called multiple times, # because while it's mounted, the dmsetup stuff will fail with device busy. /dev/nbd0) if [ -e /bootwait/samizdat-nbd-dev ] then return else bootwait nbd-script wait_for_files_ /sys/block/nbd0/pid fi ;; esac case "$ID_PART_ENTRY_NAME" in samizdat-grub-incomplete|samizdat-plaintext-incomplete|samizdat-luks-encrypted-incomplete) return ;; samizdat-grub|samizdat-luks-encrypted) return ;; esac if [ "$ID_FS_TYPE" = hfsplus ] && ! fsck.hfsplus -q "$DEVNAME"; then (if fsck.hfsplus "$DEVNAME"; then grok-block "$DEVNAME" else addmenu_repairhfs "$DEVNAME" fi) & return fi if ! mountpoint -q "$mountpoint"; then retry_mount $mount_type -o ro "$DEVNAME" "$mountpoint" fi if ! mountpoint -q "$mountpoint"; then rmdir "$mountpoint" is_device_without_partitions "$DEVNAME" || is_incomplete_samizdat_install "$DEVNAME" && addmenu_destroy_hard_drive "$DEVNAME" # TODO: Need option to boot the partitions we create # TODO: And what if we create partitions and then reboot the machine mid-install? elif [ "$ID_PART_ENTRY_NAME" = samizdat-plaintext ]; then if gpg_verify "$mountpoint"/disk.key && gpg_can_decrypt "$mountpoint"/disk.key; then addmenu_choose_native_root "$(parent_device "$DEVNAME")" fi umount "$mountpoint" elif [ "$DEVNAME" = /dev/nbd0 ]; then # This is our rootfs, over the network umount "$mountpoint" rmdir "$mountpoint" bootdone samizdat-nbd-dev else umount=true # Device has an unencrypted filesystem on it. # So we mount it and look for loop-back overlays. if [ -d "$mountpoint/samizdat.gpg" ]; then # check the key somehow? addmenu_choosekey "$DEVNAME" "$mountpoint/samizdat.gpg" fi N=1; while [ -e "$mountpoint/samizdat.$N" ] do if gpg_verify "$mountpoint/samizdat.$N"k; then addmenu_chooseroot "$DEVNAME" "$mountpoint/samizdat.$N" # this menu entry chooses the root fs, and should prompt and wait for the matching key umount=false fi N=$((N+1)) done freeblocks=$(stat -f -c %f "$mountpoint") blocksize=$(stat -f -c %S "$mountpoint") freemegs=$((freeblocks * blocksize / 1024 / 1024)) if [ "$freemegs" -ge 300 ]; then umount=false # bootwait samizdat-cdrom # cdromblocks=$(stat -f -c %b /cdrom) # cdromblocksize=$(stat -f -c %S /cdrom) # cdrommegs=$((cdromblocks * cdromblocksize / 1024 / 1024)) cdrommegs=700 # TODO: go back to checking the size if [ "$freemegs" -ge "$((cdrommegs * 3))" ]; then addmenu_makeroot "$DEVNAME" "${mountpoint}/samizdat.$N" "$((cdrommegs * 3))" 1 elif [ "$freemegs" -ge "$((cdrommegs * 2))" ]; then addmenu_makeroot "$DEVNAME" "${mountpoint}/samizdat.$N" "$((cdrommegs * 2))" 1 elif [ "$freemegs" -ge "$cdrommegs" ]; then addmenu_makeroot "$DEVNAME" "${mountpoint}/samizdat.$N" "$((freemegs / 2))" 0 else addmenu_makeroot "$DEVNAME" "${mountpoint}/samizdat.$N" 256 0 fi fi if $umount; then umount "$mountpoint" rmdir "$mountpoint" fi fi } # Get me all them nice udev variables eval "$(PATH=$PATH:/lib/udev vol_id "$DEVNAME" | sed "s/'/'\\\\''/; s/=\(.*\)/='\1'/" )" CDROM_ID_FS_UUID_ENC='73256269-4002-4e42-adbd-0e49ed1c7438' CDROM_ID_FS_LABEL_ENC=$(sed 's/ /\\x20/g' /lib/samizdat/vol_id.txt) if [ "$ID_FS_UUID_ENC" = "$CDROM_ID_FS_UUID_ENC" -o \ "$ID_FS_LABEL_ENC" = "$CDROM_ID_FS_LABEL_ENC" ] then # Recognize and mount the Samizdat if ! mountpoint -q /cdrom; then mkdir -p /cdrom . mdadm-dup.sh dup_mount_cdrom "$DEVNAME" /cdrom && bootdone samizdat-cdrom if [ -e /cdrom/gnupghome ]; then # TODO: don't use first match mkdir -p /gpg/gnupghome cp /cdrom/gnupghome/* /gpg/gnupghome bootdone samizdat-gpg fi fi else grok_block & fi # vim:set et sw=2: