#!/bin/bash DEBUG=0 ROOTDEV='' function screen_init { # Clear screen clear # Output message file if it exists [[ -f /etc/msg ]] && cat /etc/msg } # # Mounts the fakeroot from the kernel "root" param # function mount_fakeroot { local rootdev=${1} local fakeroot=${2} mount -o ro ${rootdev} ${fakeroot} } function log { local msg="${1}" echo -e "${msg}" if [[ ${DEBUG} -ne 0 ]]; then echo "Press enter to continue" read fi } # # Resolves the path to the root device from the cmdline root= syntax. # Currently handles UUID syntax and /dev/sdx syntax # function parse_cmdline { local cmdline=${1} dev='' for i in ${cmdline[@]}; do case "${i}" in root=*) if [[ ${i:5:4} == 'UUID' ]]; then #mount by uuid ROOTDEV="/dev/disk/by-uuid/$(echo ${i} | cut -d '=' -f 3)" else # mount by dev ROOTDEV="$(echo ${i} | cut -d '=' -f 2)" fi ;; initdebug) # Enable debug mode (this is gonna be slow DEBUG=1 ;; esac done } # # Returns type of partition. If part is LUKS encrypted, returns 'luks'. If # anything else, returns 'fs'. # # Most installations of the mount command don't require specification of the # filesystem, but won't automatically detect luks partitions and prompt for a # password. This allows the script to be smarter about encrypted partitions. # function get_part_type { path=${1} typestr=$(blkid -s TYPE ${path}) if [[ $(echo ${typestr} | grep 'crypto_LUKS') ]]; then echo 'luks' else echo 'fs' fi } # # Takes an encrypted device path and executes cryptsetup luksOpen. Returns path # to the new decrypted block device. This path takes the rough form of # /dev/mapper/_dev_sdx # function setup_encrypted { path=${1} name=$(echo ${path} | tr / _) # Decrypted block dev path is /dev/mapper/${name} cryptsetup luksOpen ${path} ${name} # Notify user and wait for input on failure if [[ $? -gt 0 ]]; then echo "An error was detected mounting the encrypted root." >&2 echo "Pausing. Press enter to continue." >&2 read fi # Success. Return the path of the decrypted root device echo "/dev/mapper/${name}" } # # Main function to keep the main operations code nicely separated from the # rest. # function main { # display fanciful boot image screen_init # Mount the /proc and /sys filesystems. mount -t devtmpfs none /dev mount -t proc none /proc mount -t tmpfs none /run mount -t sysfs none /sys local fakeroot='/mnt/root' if [[ ! -d ${fakeroot} ]]; then log "Fake root location ${fakeroot} does not exist. Creating." mkdir ${fakeroot} fi log "Parsing cmdline arguments" parse_cmdline "$(cat /proc/cmdline)" log "Root device: ${ROOTDEV}" if [[ $(get_part_type ${ROOTDEV}) == 'luks' ]]; then # Set new rootdev location (/dev/mapper/something). This will update it to # the decrypted block device path. log "Root device ${ROOTDEV} is encrypted." ROOTDEV=$(setup_encrypted ${ROOTDEV}) log "New rootdev: ${ROOTDEV}" fi # Mount the fakeroot. log "Mounting fakeroot" mount_fakeroot ${ROOTDEV} ${fakeroot} # Clean up. # We actually don't do this because switch_root does this for us umount /proc umount /sys umount /run # Boot the real McCoy exec switch_root ${fakeroot} /sbin/init if [[ $? -gt 0 ]]; then log "There was an error performing switch_root to ${fakeroot}." log "Starting recovery shell." /bin/bash fi } main ${@}