summaryrefslogtreecommitdiff
path: root/init
blob: 8ea174abde9a687e58bb6de79e6fb81686b85ade (plain)
    1 #!/bin/bash
    2 
    3 export DEBUG=0
    4 export INTERACTIVE=0
    5 export ROOTDEV=''
    6 
    7 screen_init() {
    8   # Clear screen
    9   clear
   10 
   11   # Output message file if it exists
   12   [ -f /etc/msg ] && cat /etc/msg
   13 }
   14 
   15 
   16 #
   17 # Mounts the fakeroot from the kernel "root" param
   18 #
   19 mount_fakeroot() {
   20   local rootdev=${1}
   21   local fakeroot=${2}
   22 
   23   mount -o ro ${rootdev} ${fakeroot}
   24 }
   25 
   26 
   27 log() {
   28   local msg="${1}"
   29   echo -e "${msg}"
   30   if [ "${DEBUG}" -ne 0 ]; then
   31     echo "Press enter to continue"
   32     read
   33   fi
   34 }
   35  
   36  
   37 #
   38 # Resolves the path to the root device from the cmdline root= syntax.
   39 # Currently handles UUID syntax and /dev/sdx syntax
   40 #
   41 parse_cmdline() {
   42   local cmdline=${1}
   43 
   44   for i in ${cmdline[@]}; do
   45     case "${i}" in
   46       root=*)
   47         if [ "${i:5:4}" == 'UUID' ]; then
   48           # mount by uuid
   49           local uuid=$(echo ${i} | cut -d '=' -f 3)
   50           ROOTDEV="$(blkid -U ${uuid})"
   51         elif [ "${i:5:5}" == 'LABEL' ]; then
   52           # mount by label
   53           local label=$(echo ${i} | cut -d '=' -f 3)
   54           ROOTDEV="$(blkid -L ${label})"
   55         else
   56           # mount by dev
   57           ROOTDEV="$(echo ${i} | cut -d '=' -f 2)"
   58         fi
   59       ;;
   60       initdebug)
   61         # Enable debug mode (this is gonna be slow)
   62         DEBUG=1
   63       ;;
   64       interactive)
   65         # Enable interactive mode
   66         INTERACTIVE=1
   67       ;;
   68     esac
   69   done
   70 }
   71 
   72  
   73 #
   74 # Returns type of partition. If part is LUKS encrypted, returns 'luks'. If
   75 # anything else, returns 'fs'.
   76 #
   77 # Most installations of the mount command don't require specification of the
   78 # filesystem, but won't automatically detect luks partitions and prompt for a
   79 # password. This allows the script to be smarter about encrypted partitions.
   80 #
   81 get_part_type() {
   82   local path="${1}"
   83   local typestr="$(blkid -s TYPE ${path})"
   84   if [ "$(echo ${typestr} | grep 'crypto_LUKS')" ]; then
   85     echo 'luks'
   86   else
   87     echo 'fs'
   88   fi
   89 }
   90 
   91 
   92 #
   93 # Takes an encrypted device path and executes cryptsetup luksOpen. Returns path
   94 # to the new decrypted block device. This path takes the rough form of
   95 # /dev/mapper/_dev_sdx
   96 #
   97 setup_encrypted() {
   98   local path="${1}"
   99   local name="$(echo ${path} | tr / _)"
  100 
  101   # Decrypted block dev path is /dev/mapper/${name}
  102   cryptsetup luksOpen ${path} ${name}
  103 
  104   # Notify user and wait for input on failure
  105   if [ "$?" -gt 0 ]; then
  106     echo "An error was detected mounting the encrypted root." >&2
  107     echo "Pausing. Press enter to continue." >&2
  108     read
  109   fi
  110 
  111   # Probe the new crypto device for an additional partition table
  112   partprobe "/dev/mapper/${name}" 2>/dev/null 1>/dev/null
  113 
  114   # Success. Return the path of the decrypted root device
  115   echo "/dev/mapper/${name}"
  116 }
  117 
  118 
  119 #
  120 # Waits up to a threshold (in seconds) for the specified path to appear as a
  121 # block device. A check for device presence occurs once per second.
  122 #
  123 # If the device appears within the threshold time, the function returns early
  124 # with error code 0 (all is well - no need to wait more).
  125 #
  126 # If the block device fails to appear within the threshold time, the function
  127 # returns code 2 (not found)
  128 #
  129 # @param dev     Path to the device to wait for
  130 # @param timeout Maximum time (in seconds) to wait for the device to appear
  131 #
  132 wait_dev() {
  133   local dev=${1}
  134   local timeout=${2}
  135 
  136   local wait=0
  137 
  138   while [ ${wait} -lt ${timeout} ]; do
  139     # If the path exists as a block device, exit the wait loop
  140     [ -b "${dev}" ] && return 0
  141     # Increment the wait counter
  142     wait=$(( wait + 1 ))
  143     # Wait another second for the device to appear
  144     sleep 1
  145   done
  146 
  147   return 2
  148 }
  149 
  150 
  151 #
  152 # Main function to keep the main operations code nicely separated from the
  153 # rest.
  154 #
  155 main() {
  156   # display fanciful boot image
  157   screen_init
  158 
  159   # Mount the /proc and /sys filesystems.
  160   mount -t devtmpfs none /dev
  161   mount -t proc     none /proc
  162   mount -t tmpfs    none /run
  163   mount -t sysfs    none /sys
  164 
  165   local fakeroot='/mnt/root'
  166 
  167   if [ ! -d "${fakeroot}" ]; then
  168     log "Fake root location ${fakeroot} does not exist. Creating."
  169     mkdir ${fakeroot}
  170   fi
  171 
  172   log "Parsing cmdline arguments"
  173 
  174   parse_cmdline "$(cat /proc/cmdline)"
  175 
  176   log "Root device: ${ROOTDEV}"
  177 
  178   log "Waiting up to 10 seconds for root device to appear."
  179   wait_dev "${ROOTDEV}" 10
  180 
  181   # Drop to maintenance shell if root device does not exist.
  182   if [ "$?" -ne 0 ]; then
  183     log "ERROR: Root device ${ROOTDEV} does not exist or can not be accessed."
  184     log "       Dropping to maintenance shell for troubleshooting."
  185     log "       (You may just need to wait longer for the root device)"
  186     /bin/bash -i
  187   fi
  188 
  189   if [ "$(get_part_type ${ROOTDEV})" == 'luks' ]; then
  190     # Set new rootdev location (/dev/mapper/something). This will update it to
  191     # the decrypted block device path.
  192     log "Root device ${ROOTDEV} is encrypted."
  193     ROOTDEV=$(setup_encrypted ${ROOTDEV})
  194     log "New rootdev: ${ROOTDEV}"
  195   fi
  196 
  197   # Drop to interactive shell if requested
  198   if [ "${INTERACTIVE}" == 1 ]; then
  199     log "Interractive shell requested. Type 'exit' to continue boot sequence."
  200     /bin/bash --norc
  201   fi
  202 
  203   # Mount the fakeroot.
  204   log "Mounting fakeroot"
  205   mount_fakeroot ${ROOTDEV} ${fakeroot}
  206 
  207   # Ensure switch_root will be possible for destination fakeroot
  208   if [ ! -f "${fakeroot}/sbin/init" ]; then
  209     log "ERROR: Destination fakeroot ${fakeroot} does not have an init script."
  210     log "       Cannot proceed. Dropping to shell for troubleshooting."
  211     /bin/bash -i
  212   fi
  213 
  214   # Boot the real McCoy
  215   log "Switching root"
  216   exec switch_root ${fakeroot} /sbin/init
  217 
  218   # This will be reached if previous command failed
  219   log "There was an error performing switch_root to ${fakeroot}."
  220   log "Starting recovery shell."
  221   /bin/bash -i
  222 }
  223 
  224 main ${@}

Generated by cgit