Guest User

Fedora Rescue Mount Bash Program

a guest
Jul 9th, 2021
88
342 days
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #!/bin/bash
  2. #
  3. # /boot/recovery/rescue-moount
  4. #
  5. # Mounts all of the guest's detected file systems to the specified mount point.
  6. #
  7.  
  8. declare -A MOUNT_PT_TO_FS_TYPE MOUNT_PT_TO_MOUNT_OPTS
  9. declare -A MOUNT_PT_TO_DEV_UUID MOUNT_PT_TO_DEV_PATH MOUNT_PT_TO_LABEL
  10.  
  11. # -----------------------------------------------------------------------------
  12. # Populates global metadata arrays with mount point specifications.
  13. #  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
  14. # Arguments
  15. #   1 - fstab_path: fully qualified path to fstab(5) file
  16. # -----------------------------------------------------------------------------
  17. populate_metadata() {
  18.   local fstab_path="$1"
  19.   local blkid_line
  20.   while read -r blkid_line; do
  21.     local blkid_arr=(${blkid_line})
  22.     local dev_uuid="${blkid_arr[0]}"
  23.     local dev_path="${blkid_arr[1]}"
  24.     local dev_label="$(blkid "${dev_path}"                                    \
  25.        | grep ":\sUUID=\"${dev_uuid}\"\s"                                    \
  26.        | sed 's/^.*LABEL="\([^"]*\)".*$/\1/g')"
  27.  
  28.    local fstab_line
  29.    while read -r fstab_line; do
  30.      local fstab_arr=(${fstab_line})
  31.      local mount_pt="${fstab_arr[0]}"
  32.      local fs_type="${fstab_arr[1]}"
  33.      local mount_opts="${fstab_arr[2]}"
  34.      MOUNT_PT_TO_FS_TYPE[${mount_pt}]="${fs_type}"
  35.      MOUNT_PT_TO_MOUNT_OPTS["${mount_pt}"]="${mount_opts}"
  36.      MOUNT_PT_TO_DEV_UUID["${mount_pt}"]="${dev_uuid}"
  37.      MOUNT_PT_TO_DEV_PATH["${mount_pt}"]="${dev_path}"
  38.      if [[ -n "${dev_label}" ]]; then
  39.        MOUNT_PT_TO_LABEL["${mount_pt}"]="${dev_label}"
  40.      fi
  41.    
  42.    # Emit (mount point, fs type, mount options)-triplets, one for each mount
  43.    # point discovered on the current block device.  Filter out 'swap' fs types
  44.    # entirely since they never require mounting in a recovery environment.
  45.    done < <(grep '^\s*\(UUID='"${dev_uuid}"'\)\|'"${dev_path}"'\(\)'         \
  46.            "${fstab_path}"                                                   \
  47.        | awk -c '{print $2, $3, $4}'                                         \
  48.        | grep -v '^swap')
  49.  
  50.  # emit (uuid, path)-pairs, one for each block device currently attached
  51.  done < <(blkid                                                              \
  52.      | awk -c '{ print $2, $1 }'                                             \
  53.      | grep '^UUID='                                                         \
  54.      | sed 's/"\|://g'                                                       \
  55.      | cut -c 6-                                                             \
  56.      | sort -k2d)
  57. }
  58.  
  59. # -----------------------------------------------------------------------------
  60. # Mount all discovered file systems to the specified mount point.
  61. #  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
  62. # Arguments:
  63. #   1 - mount_pt_root: path to which to mount the root filesystem and all
  64. #       descendants
  65. # -----------------------------------------------------------------------------
  66. do_mount() {
  67.  local mount_pt_root="$1"
  68.  IFS=$'\n' local traversal=( $(printf '%s\n' "${!MOUNT_PT_TO_FS_TYPE[@]}"    \
  69.      | awk -c '{ print length($1), $1 }'                                     \
  70.      | sort -k1n -k2d                                                        \
  71.      | awk -c '{ print $2 }'                                                 \
  72.      ) )
  73.  
  74.  for key in "${traversal[@]}"; do
  75.    local dest="${mount_pt_root%/}/${key#/}"
  76.    local dest_parent="${dest%/[^/]*}"
  77.    if ( [[ "${key}" == "/" ]] || mountpoint -q "${dest_parent}" )            \
  78.        && ! mountpoint -q "${dest}"; then
  79.      local fs_type="${MOUNT_PT_TO_FS_TYPE[${key}]}"
  80.      local mount_opts="${MOUNT_PT_TO_MOUNT_OPTS[${key}]}"
  81.      local dev_uuid="${MOUNT_PT_TO_DEV_UUID[${key}]}"
  82.      mount -t "${fs_type}" -o "${mount_opts}" -U "${dev_uuid}" "${dest}" >&2
  83.      local result=$?
  84.      
  85.      # display attempt and result
  86.      local src="${MOUNT_PT_TO_DEV_PATH[${key}]#/dev/}"
  87.       if [[ -v "MOUNT_PT_TO_LABEL[${key}]" ]]; then
  88.         src+=":${MOUNT_PT_TO_LABEL[${key}]}"
  89.       fi
  90.       src+=":${fs_type}"
  91.       echo "print('MOUNT  {:>20} -> {:28} {:>10}'.format("                    \
  92.           "'${src}'  if len('${src}')  <= 20 else '${src}'[:15] + '...',"     \
  93.           "'${dest}' if len('${dest}') <= 28 else '...' + '${dest}'[-23:],"   \
  94.           "'SUCCESS' if ${result}      ==  0 else 'FAIL (${result})'"         \
  95.           "))" | python3
  96.       sleep 0.1
  97.     elif ! mountpoint -q "${mount_pt_parent}"; then
  98.       >&2 printf "%s -- mountpoint: %s, reason: %s, parent: %s\n" \
  99.           "unable to mount" "${dest}" "parent not mounted" "${dest_parent}"
  100.     else
  101.       >&2 printf "unable to mount -- mountpoint: %s, reason: %s\n" "${dest}"  \
  102.           "already mounted"
  103.     fi
  104.   done
  105. }
  106.  
  107. # -----------------------------------------------------------------------------
  108. # Carefully parse fstab and mount all relevant file systems discovered.
  109. #  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --  --
  110. # Arguments:
  111. #   1 - fstab_path: fully qualified path to fstab file
  112. #   2 - mount_pt: place at which to mount the root filesystem of our system
  113. # -----------------------------------------------------------------------------
  114. main() {
  115.   if (( $UID != 0 )); then
  116.     2>&1 echo "error -- this program must be run as root"
  117.     return 1
  118.   fi
  119.  
  120.   IFS=$'\n' local dup_uuids=( $(lsblk -o name,UUID                          \
  121.       | grep -v 'live-[a-zA-Z0-9]\+\s'                                      \
  122.       | awk -c '{ print $2 }'                                               \
  123.       | grep -E '^([a-f0-9]{4}-?){8}$'                                      \
  124.       | sort                                                                \
  125.       | uniq -d) )
  126.   if (( ${#dup_uuids[@]} != 0 )); then
  127.     2>&1 echo "error -- found attached devices with duplicate UUIDs: " \
  128.           "${dup_uuids[*]}"
  129.     return 1
  130.   fi
  131.  
  132.   if (( $# != 2 )); then
  133.     2>&1 echo "usage: ${0} FSTAB_PATH MOUNT_POINT_PATH"
  134.     return 1
  135.   fi
  136.  
  137.   local fstab_path="${1}"
  138.   if [[ ! -f "${fstab_path}" ]]                                               \
  139.       || [[ ! -r "${fstab_path}" ]]                                           \
  140.       || [[ ! -s "${fstab_path}" ]]; then
  141.     2>&1 echo "error -- ${fstab_path} is not a readable, non-empty file"
  142.     return 1
  143.   fi
  144.  
  145.   local mount_pt="${2}"
  146.   if [[ ! -d "${mount_pt}" ]] || [[ -n "$(ls -A ${mount_pt})" ]]; then
  147.     2>&1 echo "error -- ${2} is not an empty directory"
  148.     return 1
  149.   fi
  150.  
  151.   populate_metadata "${fstab_path}"
  152.   if (( ${#MOUNT_PT_TO_FS_TYPE[@]} == 0 )); then
  153.     2>&1 echo "error -- unable to parse ${1} as an fstab file"
  154.     return 1
  155.   fi
  156.  
  157.   do_mount "${mount_pt}"
  158.   ec=$?
  159.   if (( $ec == 0 )); then
  160.     local ans
  161.     read -p "Bind /run, /proc, /dev, and /sys in preparation to chroot? (y/N)" ans
  162.     if [[ "${ans}" =~ ^(y|Y) ]]; then
  163.       for fs in run sys proc dev; do
  164.         local dest="${mount_pt%/}/${fs}"
  165.         if ! mountpoint -q "${dest}"; then
  166.           echo "BIND   /${fs} => ${dest}"
  167.           mount --rbind "/${fs}" "${dest}"
  168.           mount --make-rslave "${dest}"
  169.         fi
  170.       done
  171.     fi
  172.   fi
  173.   return ${ec}
  174. }
  175.  
  176. main "$@"
RAW Paste Data