#!/bin/sh . /etc/initrd.defaults . /etc/initrd.d/00-splash.sh . /etc/initrd.d/00-common.sh . /etc/initrd.d/00-fsdev.sh . /etc/initrd.d/00-devmgr.sh . /etc/initrd.d/00-zfs.sh . /etc/initrd.d/00-modules.sh . /etc/initrd.d/00-livecd.sh real_root_init() { if [ -z "${REAL_ROOT}" ] && [ "${FAKE_ROOT}" != "/dev/ram0" ]; then REAL_ROOT="${FAKE_ROOT}" fi if [ -z "${REAL_INIT}" ] && [ "${FAKE_INIT}" != "/linuxrc" ]; then REAL_INIT="${FAKE_INIT}" fi if [ -z "${REAL_ROOTFLAGS}" ]; then REAL_ROOTFLAGS="${FAKE_ROOTFLAGS}" fi # let zfs code setup its parameters zfs_real_root_init } bootstrap_key() { # $1 = ROOT/SWAP local KEYDEVS=$(device_list) eval local keyloc='"${CRYPT_'${1}'_KEY}"' media_find "key" "${keyloc}" "CRYPT_${1}_KEYDEV" "/mnt/key" ${KEYDEVS} } find_nfs() { if [ -z "${IP}" ]; then # IP is not set, return straight away return 1 fi if ! busybox udhcpc -n -T 15 -q; then bad_msg "udhcpc returned error, skipping nfs setup..." return 1 fi local options= [ -e /rootpath ] && NFSROOT=$(cat /rootpath) if [ -z "${NFSROOT}" ]; then # Obtain NFSIP # TODO: this is bogus, because dmesg is a circular buffer... # TODO: provide dmesg as symlink (see gen_initramfs.sh) options=$(busybox dmesg | grep rootserver | sed -e "s/,/ /g") local opt= optn= for opt in ${options}; do optn=$(echo $opt | sed -e "s/=/ /g" | cut -d " " -f 1) if [ "${optn}" = "rootserver" ]; then NFSIP=$(echo $opt | sed -e "s/=/ /g" | cut -d " " -f 2) fi done # Obtain NFSPATH # TODO: this is bogus, because dmesg is a circular buffer... # TODO: provide dmesg as symlink (see gen_initramfs.sh) options=$(busybox dmesg | grep rootpath | sed -e "s/,/ /g") for opt in ${options}; do optn=$(echo $opt | sed -e "s/=/ /g" | cut -d " " -f 1) if [ "${optn}" = "rootpath" ]; then NFSPATH=$(echo $opt | sed -e "s/=/ /g" | cut -d " " -f 2) fi done # Setup NFSROOT if [ -n "${NFSIP}" ] && [ -n "$NFSPATH" ]; then NFSROOT="${NFSIP}:${NFSPATH}" else bad_msg "The DHCP Server did not send a valid root-path." bad_msg "Please check your DHCP setup, or set nfsroot=<...>" return 1 fi fi # expecting a valid NFSROOT here, or the code should have returned NFSOPTIONS=${NFSROOT#*,} NFSROOT=${NFSROOT%%,*} if [ "${NFSOPTIONS}" = "${NFSROOT}" ]; then NFSOPTIONS="${DEFAULT_NFSOPTIONS}" else NFSOPTIONS="${DEFAULT_NFSOPTIONS},${NFSOPTIONS}" fi local path= # override path if on livecd if is_livecd; then path="${CDROOT_PATH}" good_msg "Attempting to mount NFS CD image on ${NFSROOT}." else path="${NEW_ROOT}" good_msg "Attempting to mount NFS root on ${NFSROOT}." fi good_msg "NFS options: ${NFSOPTIONS}" mount -t nfs -o ${NFSOPTIONS} "${NFSROOT}" "${path}" if [ "${?}" = "0" ]; then REAL_ROOT="/dev/nfs" return 0 else bad_msg "NFS Mounting failed. Is the path corrent ?" return 1 fi } test_success() { retcode=$? # If last command failed send error message and fall back to a shell if [ "$retcode" != '0' ] then error_string=$1 error_string="${error_string:-run command}" bad_msg 'Failed to $1; failing back to the shell...' run_shell fi } crypt_exec() { if [ "${CRYPT_SILENT}" = '1' ] then eval ${1} >/dev/null 2>/dev/null else ask_for_password --ply-tries 5 \ --ply-cmd "${1}" \ --ply-prompt "Encryption password (${LUKS_DEVICE}): " \ --tty-tries 5 \ --tty-cmd "${1}" || return 1 return 0 fi } prompt_user() { # $1 = variable whose value is the path (examples: "REAL_ROOT", # "LUKS_KEYDEV") # $2 = label # $3 = optional explanations for failure eval local oldvalue='$'${1} [ $# != 2 -a $# != 3 ] && \ bad_msg "Bad invocation of function prompt_user." bad_msg "Please file a bug report with this message" && exit 1 [ -n "${3}" ] && local explnt=" or : ${3}" || local explnt="." splashcmd verbose bad_msg "Could not find the ${2} in ${oldvalue}${explnt}" bad_msg "Please specify another value or:" bad_msg "- press Enter for the same" bad_msg '- type "shell" for a shell' bad_msg '- type "q" to skip...' echo -n "${2}(${oldvalue}) :: " read ${1} case $(eval echo '$'${1}) in 'q') eval ${1}'='${oldvalue} warn_msg "Skipping step, this will likely cause a boot failure." break ;; 'shell') eval ${1}'='${oldvalue} warn_msg "To leave and try again just press +D" run_shell ;; '') eval ${1}'='${oldvalue} ;; esac splashcmd quiet } cmdline_hwopts() { # Scan CMDLINE for any "doscsi" or "noscsi"-type arguments local FOUND local TMP_HWOPTS for x in $HWOPTS do for y in $CMDLINE do if [ "${y}" = "do${x}" ] then MY_HWOPTS="${MY_HWOPTS} $x" elif [ "${y}" = "no${x}" ] then MY_HWOPTS="$(echo ${MY_HWOPTS} | sed -e \"s/${x}//g\" -)" fi if [ "$(echo ${y} | cut -b -7)" = "keymap=" ] then MY_HWOPTS="${MY_HWOPTS} keymap" fi done done # Shouldnt need to sort this as the following loop should figure out the # duplicates and strip them out #MY_HWOPTS=$(echo ${MY_HWOPTS}| sort) for x in ${MY_HWOPTS} do FOUND=0 for y in ${TMP_HWOPTS} do if [ "${y}" = "${x}" ] then continue 2 fi done TMP_HWOPTS="${TMP_HWOPTS} ${x}" eval DO_$(echo ${x} | sed 's/-//')=1 done MY_HWOPTS=${TMP_HWOPTS} } setup_keymap() { if [ "${DO_keymap}" ] then if [ ! -e /dev/vc/0 -a ! -e /dev/tty0 ] then DEVBIND=1 mount -o bind ${NEW_ROOT}/dev /dev fi [ ! -e /dev/tty0 ] && ln -s /dev/tty1 /dev/tty0 [ -f /lib/keymaps/keymapList ] && choose_keymap [ "${DEVBIND}" = '1' ] && umount /dev if [ -e /etc/sysconfig/keyboard ] && is_livecd then mkdir -p ${NEW_ROOT}/etc/sysconfig/ cp /etc/sysconfig/keyboard ${NEW_ROOT}/etc/sysconfig/keyboard fi fi } choose_keymap() { good_msg "Loading keymaps" if [ -z "${keymap}" ] then splashcmd verbose cat /lib/keymaps/keymapList read -t 10 -p '<< Load keymap (Enter for default): ' keymap case ${keymap} in 1|azerty) keymap=azerty ;; 2|be) keymap=be ;; 3|bg) keymap=bg ;; 4|br-a) keymap=br-a ;; 5|br-l) keymap=br-l ;; 6|by) keymap=by ;; 7|cf) keymap=cf ;; 8|croat) keymap=croat ;; 9|cz) keymap=cz ;; 10|de) keymap=de ;; 11|dk) keymap=dk ;; 12|dvorak) keymap=dvorak ;; 13|es) keymap=es ;; 14|et) keymap=et ;; 15|fi) keymap=fi ;; 16|fr) keymap=fr ;; 17|gr) keymap=gr ;; 18|hu) keymap=hu ;; 19|il) keymap=il ;; 20|is) keymap=is ;; 21|it) keymap=it ;; 22|jp) keymap=jp ;; 23|la) keymap=la ;; 24|lt) keymap=lt ;; 25|mk) keymap=mk ;; 26|nl) keymap=nl ;; 27|no) keymap=no ;; 28|pl) keymap=pl ;; 29|pt) keymap=pt ;; 30|ro) keymap=ro ;; 31|ru) keymap=ru ;; 32|se) keymap=se ;; 33|sg) keymap=sg ;; 34|sk-y) keymap=sk-y ;; 35|sk-z) keymap=sk-z ;; 36|slovene) keymap=slovene ;; 37|trf) keymap=trf ;; 38|trq) keymap=trq ;; 39|ua) keymap=ua ;; 40|uk) keymap=uk ;; 41|us) keymap=us ;; 42|wangbe) keymap=wangbe ;; 43|sf|ch*) keymap=sf ;; esac fi if [ -e /lib/keymaps/${keymap}.map ] then good_msg "Loading the ''${keymap}'' keymap" loadkmap < /lib/keymaps/${keymap}.map mkdir -p /etc/sysconfig echo "XKEYBOARD=${keymap}" > /etc/sysconfig/keyboard splashcmd set_msg "Set keymap to ${keymap}" elif [ -z "${keymap}" ] then good_msg good_msg "Keeping default keymap" splashcmd set_msg "Keeping default keymap" else bad_msg "Sorry, but keymap ''${keymap}'' is invalid!" unset keymap choose_keymap fi } start_volumes() { # Here, we check for /dev/device-mapper, and if it exists, we setup a # a symlink, which should hopefully fix bug #142775 and bug #147015 if [ -e /dev/device-mapper ] && [ ! -e /dev/mapper/control ]; then mkdir -p /dev/mapper ln -sf /dev/device-mapper /dev/mapper/control fi if [ "${USE_MDADM}" = "1" ]; then if [ -e "/sbin/mdadm" ]; then /sbin/mdadm --assemble --scan else bad_msg "mdadm not found: skipping mdadm raid assembly!" fi fi if [ "${USE_MULTIPATH_NORMAL}" = "1" ]; then good_msg "Scanning for multipath devices" /sbin/multipath -v 0 # TODO(lxnay): horrible sleep! sleep 2 good_msg "Activating multipath devices" /sbin/dmsetup ls --target multipath --exec "/sbin/kpartx -a -v" fi if [ "${USE_DMRAID_NORMAL}" = "1" ]; then if [ -e "/sbin/dmraid" ]; then good_msg "Activating Device-Mapper RAID(s)" /sbin/dmraid -ay ${DMRAID_OPTS} else bad_msg "/sbin/dmraid not found" fi fi if [ "${USE_LVM_NORMAL}" = "1" ]; then if [ -e "/sbin/lvm" ]; then if is_mdev; then for dev in ${RAID_DEVICES}; do setup_md_device "${dev}" done fi # This is needed for /sbin/lvm to accept the following logic local cmds="#! /sbin/lvm" # If there is a cahe, update it. Unbreak at least dmcrypt [ -d /etc/lvm/cache ] && cmds="${cmds} \nvgscan" # To activate volumegroups on all devices in the cache cmds="${cmds} \nvgchange -ay --sysinit" if is_mdev; then # To create symlinks so users can use # real_root=/dev/vg/root # This needs to run after vgchange, using # vgchange --mknodes is too early. cmds+="${cmds} \nvgmknodes --ignorelockingfailure" fi # And finally execute it all (/proc/... needed if lvm # is compiled without readline) good_msg "Scanning for and activating Volume Groups" printf "%b\n" "${cmds}" | /sbin/lvm /proc/self/fd/0 else bad_msg "/sbin/lvm not found: skipping LVM activation" fi fi # If zfs is enabled, this will initialize the volumes zfs_start_volumes is_udev && udevadm settle } start_iscsi() { if [ ! -e /usr/sbin/iscsistart ]; then return 0 # disabled fi if [ ! -n "${ISCSI_NOIBFT}" ] then good_msg "Activating iSCSI via iBFT" iscsistart -b fi if [ -n "${ISCSI_INITIATORNAME}" ] && [ -n "${ISCSI_TARGET}" ] && [ -n "${ISCSI_ADDRESS}" ]; then good_msg "Activating iSCSI via cmdline" if [ "${ISCSI_TGPT}" ] then ADDITIONAL="${ADDITIONAL} -g ${ISCSI_TGPT}" else ADDITIONAL="${ADDITIONAL} -g 1" fi if [ "${ISCSI_PORT}" ] then ADDITIONAL="${ADDITIONAL} -p ${ISCSI_PORT}" fi if [ "${ISCSI_USERNAME}" ] then ADDITIONAL="${ADDITIONAL} -u ${ISCSI_USERNAME}" fi if [ "${ISCSI_PASSWORD}" ] then ADDITIONAL="${ADDITIONAL} -w ${ISCSI_PASSWORD}" fi if [ "${ISCSI_USERNAME_IN}" ] then ADDITIONAL="${ADDITIONAL} -U ${ISCSI_USERNAME_IN}" fi if [ "${ISCSI_PASSWORD_IN}" ] then ADDITIONAL="${ADDITIONAL} -W ${ISCSI_PASSWORD_IN}" fi if [ "${ISCSI_DEBUG}" ] then ADDITIONAL="${ADDITIONAL} -d ${ISCSI_DEBUG}" fi iscsistart -i "${ISCSI_INITIATORNAME}" -t "${ISCSI_TARGET}" \ -a "${ISCSI_ADDRESS}" ${ADDITIONAL} # let iscsid settle - otherwise mounting the iSCSI-disk # will fail (very rarely, though) sleep 1 fi } # Open a LUKS device # It is either the root or a swap, other devices are supported in the scripts provided with sys-fs/cryptsetup-luks # $1 - root/swap open_luks() { # TODO(lxnay): what has been seen, cannot be unseen. # TODO(lxnay): there is so much wrong in this function... case $1 in root) local TYPE=ROOT ;; swap) local TYPE=SWAP ;; esac eval local LUKS_DEVICE='"${CRYPT_'${TYPE}'}"' LUKS_NAME="$1" LUKS_KEY='"${CRYPT_'${TYPE}'_KEY}"' LUKS_KEYDEV='"${CRYPT_'${TYPE}'_KEYDEV}"' LUKS_TRIM='"${CRYPT_'${TYPE}'_TRIM}"' local DEV_ERROR=0 KEY_ERROR=0 KEYDEV_ERROR=0 local mntkey="/mnt/key/" cryptsetup_options='' [ ! -e /sbin/cryptsetup ] && bad_msg "The ramdisk does not support LUKS" && exit 1 while [ 1 ] do local gpg_cmd="" # if crypt_silent=1 and some error occurs, enter shell quietly if [ \( ${CRYPT_SILENT} -eq 1 \) -a \( \( \( ${DEV_ERROR} -eq 1 \) -o \( ${KEY_ERROR} -eq 1 \) \) -o \( ${KEYDEV_ERROR} -eq 1 \) \) ] then run_shell elif [ ${DEV_ERROR} -eq 1 ] then prompt_user "LUKS_DEVICE" "${LUKS_NAME}" DEV_ERROR=0 elif [ ${KEY_ERROR} -eq 1 ] then prompt_user "LUKS_KEY" "${LUKS_NAME} key" KEY_ERROR=0 elif [ ${KEYDEV_ERROR} -eq 1 ] then prompt_user "LUKS_KEYDEV" "${LUKS_NAME} key device" KEYDEV_ERROR=0 else local luks_dev=$(find_real_device "${LUKS_DEVICE}") [ -n "${luks_dev}" ] && LUKS_DEVICE="${luks_dev}" # otherwise hope... setup_md_device "${LUKS_DEVICE}" /sbin/cryptsetup isLuks "${LUKS_DEVICE}" if [ $? -ne 0 ] then bad_msg "The LUKS device ${LUKS_DEVICE} does not contain a LUKS header" ${CRYPT_SILENT} DEV_ERROR=1 continue else # Handle keys if [ "x${LUKS_TRIM}" = "xyes" ] then good_msg "Enabling TRIM support for ${LUKS_NAME}." ${CRYPT_SILENT} cryptsetup_options="${cryptsetup_options} --allow-discards" fi if [ -n "${LUKS_KEY}" ] then local REAL_LUKS_KEYDEV="${LUKS_KEYDEV}" if [ ! -e "${mntkey}${LUKS_KEY}" ] then REAL_LUKS_KEYDEV=$(find_real_device "${LUKS_KEYDEV}") if [ -b "${REAL_LUKS_KEYDEV}" ] && [ -n "${REAL_LUKS_KEYDEV}" ] then good_msg "Using key device ${REAL_LUKS_KEYDEV}." ${CRYPT_SILENT} else good_msg "Please insert removable device ${LUKS_KEYDEV} for ${LUKS_NAME}" ${CRYPT_SILENT} # abort after 10 secs local count=10 while [ ${count} -gt 0 ] do count=$((count-1)) sleep 1 REAL_LUKS_KEYDEV=$(find_real_device "${LUKS_KEYDEV}") if [ -b "${REAL_LUKS_KEYDEV}" ] && [ -n "${REAL_LUKS_KEYDEV}" ] then good_msg "Removable device ${REAL_LUKS_KEYDEV} detected." ${CRYPT_SILENT} break fi done if [ ! -b "${REAL_LUKS_KEYDEV}" ] then eval CRYPT_${TYPE}_KEY=${LUKS_KEY} bootstrap_key ${TYPE} eval LUKS_KEYDEV='"${CRYPT_'${TYPE}'_KEYDEV}"' REAL_LUKS_KEYDEV=$(find_real_device "${LUKS_KEYDEV}") if [ ! -b "${REAL_LUKS_KEYDEV}" ]; then KEYDEV_ERROR=1 bad_msg "Removable device ${LUKS_KEYDEV} not found." ${CRYPT_SILENT} continue fi # continue otherwise will mount keydev which is mounted by bootstrap continue fi fi # At this point a device was recognized, now let's see if the key is there [ ! -d "$mntkey" ] && mkdir -p ${mntkey} 2>/dev/null >/dev/null mount -n -o ro ${REAL_LUKS_KEYDEV} ${mntkey} >/dev/null 2>/dev/null if [ "$?" != '0' ] then KEYDEV_ERROR=1 bad_msg "Mounting of device ${REAL_LUKS_KEYDEV} failed." ${CRYPT_SILENT} continue else good_msg "Removable device ${REAL_LUKS_KEYDEV} mounted." ${CRYPT_SILENT} sleep 2 # keyfile exists? if [ ! -e "${mntkey}${LUKS_KEY}" ]; then umount -n ${mntkey} 2>/dev/null >/dev/null KEY_ERROR=1 KEYDEV_ERROR=1 bad_msg "Key {LUKS_KEY} on device ${REAL_LUKS_KEYDEV} not found." ${CRYPT_SILENT} continue fi fi fi # At this point a candidate key exists (either mounted before or not) good_msg "${LUKS_KEY} on device ${REAL_LUKS_KEYDEV} found" ${CRYPT_SILENT} if [ "$(echo ${LUKS_KEY} | grep -o '.gpg$')" = ".gpg" ] && [ -e /usr/bin/gpg ] ; then [ -e /dev/tty ] && mv /dev/tty /dev/tty.org mknod /dev/tty c 5 1 cryptsetup_options="${cryptsetup_options} -d -" gpg_cmd="/usr/bin/gpg --logger-file /dev/null --quiet --decrypt ${mntkey}${LUKS_KEY} |" else cryptsetup_options="${cryptsetup_options} -d ${mntkey}${LUKS_KEY}" fi fi # At this point, keyfile or not, we're ready! crypt_exec "${gpg_cmd}/sbin/cryptsetup ${cryptsetup_options} luksOpen ${LUKS_DEVICE} ${LUKS_NAME}" crypt_exec_ret=$? [ -e /dev/tty.org ] \ && rm -f /dev/tty \ && mv /dev/tty.org /dev/tty if [ ${crypt_exec_ret} -eq 0 ] then good_msg "LUKS device ${LUKS_DEVICE} opened" ${CRYPT_SILENT} break else bad_msg "Failed to open LUKS device ${LUKS_DEVICE}" ${CRYPT_SILENT} DEV_ERROR=1 KEY_ERROR=1 KEYDEV_ERROR=1 fi fi fi done umount ${mntkey} 2>/dev/null >/dev/null rmdir -p ${mntkey} 2>/dev/null >/dev/null } start_luks() { # if key is set but key device isn't, find it [ -n "${CRYPT_ROOT_KEY}" ] && [ -z "${CRYPT_ROOT_KEYDEV}" ] \ && sleep 6 && bootstrap_key "ROOT" if [ -n "${CRYPT_ROOT}" ]; then open_luks "root" if [ -n "${REAL_ROOT}" ] then # Rescan volumes start_volumes else REAL_ROOT="/dev/mapper/root" fi fi # TODO(lxnay): this sleep 6 thing is hurting my eyes sooooo much. # same for swap, but no need to sleep if root was unencrypted [ -n "${CRYPT_SWAP_KEY}" ] && [ -z "${CRYPT_SWAP_KEYDEV}" ] \ && { [ -z "${CRYPT_ROOT}" ] && sleep 6; bootstrap_key "SWAP"; } if [ -n "${CRYPT_SWAP}" ]; then open_luks "swap" if [ -z "${REAL_RESUME}" ] then # Resume from swap as default REAL_RESUME="/dev/mapper/swap" fi fi } sdelay() { # Sleep a specific number of seconds if SDELAY is set if [ -n "${SDELAY}" ] then good_msg "Waiting ${SDELAY} seconds..." sleep ${SDELAY} elif is_livecd then good_msg 'Hint: Use scandelay[=seconds] if your live medium is slowand boot fails' fi } setup_md_device() { local device [ -z "$1" ] && device="${REAL_ROOT}" || device="$1" [ -z "${device}" ] && return # LiveCD if [ $(echo ${device}|sed -e 's#\(luks:\)\?\(/dev/md\)[[:digit:]]\+#\2#') = "/dev/md" ] then good_msg 'Detected real_root as a md device. Setting up the device node...' MD_NUMBER=$(echo ${device}|sed -e 's#\(luks:\)\?/dev/md\([[:digit:]]\+\)#\2#') if [ ! -e /dev/md${MD_NUMBER} ] then mknod /dev/md${MD_NUMBER} b 9 ${MD_NUMBER} >/dev/null 2>&1 [ $? -ne 0 ] && bad_msg "Creation of /dev/md${MD_NUMBER} failed..." fi mdstart ${MDPART} /dev/md${MD_NUMBER} fi } resume_init() { if [ -z "${REAL_RESUME}" ]; then return 0 fi if [ "${NORESUME}" = "1" ]; then return 0 fi local resume_dev=$(find_real_device "${REAL_RESUME}") if [ -n "${resume_dev}" ]; then REAL_RESUME="${resume_dev}" good_msg "Detected real_resume=${resume_dev}" else bad_msg "Cannot resolve real_resume=${REAL_RESUME}" bad_msg "Something bad may happen, crossing fingers" fi swsusp_resume } swsusp_resume() { # determine swap resume partition local device=$(ls -lL "${REAL_RESUME}" | sed 's/\ */ /g' | \ cut -d \ -f 5-6 | sed 's/,\ */:/') [ -f /sys/power/resume -a -n "${device}" ] && \ echo "${device}" > /sys/power/resume } getdvhoff() { echo $(( $(hexdump -n 4 -s $((316 + 12 * $2)) -e '"%i"' $1) * 512)) } get_mounts_list() { awk ' /^[[:blank:]]*#/ { next } { print $1 } ' ${NEW_ROOT}/etc/initramfs.mounts } get_mount_fstype() { [ -e "${NEW_ROOT}"/etc/fstab ] || return 1 awk -v fs="$1" ' /^[[:blank:]]*#/ { next } $2 == fs { print $3 } ' ${NEW_ROOT}/etc/fstab } get_mount_options() { [ -e "${NEW_ROOT}"/etc/fstab ] || return 1 awk -v fs="$1" ' /^[[:blank:]]*#/ { next } $2 == fs { print $4 } ' ${NEW_ROOT}/etc/fstab } get_mount_device() { [ -e "${NEW_ROOT}"/etc/fstab ] || return 1 awk -v fs="$1" ' /^[[:blank:]]*#/ { next } $2 == fs { print $1 } ' ${NEW_ROOT}/etc/fstab } # If the kernel is handed a mount option is does not recognize, it # WILL fail to mount. util-linux handles auto/noauto, but busybox # passes it straight to the kernel which then rejects the mount. To # make like a little easier, busybox mount does not care about # leading, trailing or duplicate commas. strip_mount_options() { sed -r 's/(,|^)(no)?auto(,|$)/,/g' } # Read /etc/initramfs.mounts from ${NEW_ROOT} and mount the # listed filesystem mountpoints. For instance, /usr, which is # required by udev & systemd. ensure_initramfs_mounts() { local fslist= if [ -f "${NEW_ROOT}/etc/initramfs.mounts" ]; then fslist="$(get_mounts_list)" else fslist="/usr" fi local dev= fstype= opts= mnt= cmd= for fs in ${fslist}; do mnt="${NEW_ROOT}${fs}" if mountpoint -q "${mnt}"; then good_msg "${fs} already mounted, skipping..." continue fi dev=$(get_mount_device "${fs}") [ -z "${dev}" ] && continue # Resolve it like util-linux mount does [ -L "${dev}" ] && dev=$(readlink "${dev}") # In this case, it's probably part of the filesystem # and not a mountpoint [ -z "${dev}" ] && continue fstype=$(get_mount_fstype "${fs}") if get_mount_options "${fs}" | fgrep -q bind; then opts="bind" dev="${NEW_ROOT}${dev}" else # ro must be trailing, and the options will always # contain at least 'defaults' opts="$(get_mount_options ${fs} | strip_mount_options)" opts="${opts},ro" fi cmd="mount -t ${fstype} -o ${opts} ${dev} ${mnt}" good_msg "Mounting ${dev} as ${fs}: ${cmd}" if ! ${cmd}; then bad_msg "Unable to mount ${dev} for ${fs}" fi done } fstype_init() { local fstype="${1}" if [ "${fstype}" = "btrfs" ]; then # start BTRFS volume detection, if available [ -x /sbin/btrfs ] && /sbin/btrfs device scan elif [ -z "${fstype}" ]; then warn_msg "Unable to detect the filesystem type (empty variable)" fi } _rootdev_detect() { local got_good_root=0 while [ "${got_good_root}" != "1" ]; do case "${REAL_ROOT}" in LABEL=*|UUID=*) local root_dev=$(find_real_device "${REAL_ROOT}") if [ -n "${root_dev}" ]; then REAL_ROOT="${root_dev}" good_msg "Detected root: ${REAL_ROOT}" else bad_msg "Unable to resolve root: ${REAL_ROOT}" got_good_root=0 prompt_user "REAL_ROOT" "root block device" continue fi ;; ZFS*) # zfs_rootdev_init will tweak ${REAL_ROOT} zfs_rootdev_init if [ "${?}" = "0" ]; then got_good_root=1 else got_good_root=0 prompt_user "REAL_ROOT" "root block device" continue fi ;; esac if [ -z "${REAL_ROOT}" ]; then # No REAL_ROOT determined/specified. # Prompt user for root block device. prompt_user "REAL_ROOT" "root block device" got_good_root=0 # Check for a block device or NFS elif [ -b "${REAL_ROOT}" ] || is_nfs; then got_good_root=1 else bad_msg "${REAL_ROOT} is an invalid root device..." REAL_ROOT="" got_good_root=0 fi done return 0 } _rootdev_mount() { local mount_opts=ro local mount_fstype="${ROOTFSTYPE}" local fstype=$(get_device_fstype "${REAL_ROOT}") if is_zfs_fstype "${fstype}"; then mount_fstype=zfs mount_opts=$(zfs_get_real_root_mount_flags) fi good_msg "Detected fstype: ${fstype}" good_msg "Using mount fstype: ${mount_fstype}" fstype_init "${fstype}" local mopts="${mount_opts}" [ -n "${REAL_ROOTFLAGS}" ] && \ mopts="${mopts},${REAL_ROOTFLAGS}" good_msg "Using mount opts: -o ${mopts}" mount -t "${mount_fstype}" -o "${mopts}" \ "${REAL_ROOT}" "${NEW_ROOT}" || return 1 return 0 } rootdev_init() { good_msg "Initializing root device..." while true; do if ! _rootdev_detect; then bad_msg "Could not mount specified ROOT, try again" prompt_user "REAL_ROOT" "root block device" continue fi if is_livecd && ! is_nfs; then # CD already mounted; no further checks necessary break fi if [ "${LOOPTYPE}" = "sgimips" ]; then # sgimips mounts the livecd root partition directly # there is no isofs filesystem to worry about break fi good_msg "Mounting ${REAL_ROOT} as root..." # Try to mount the device as ${NEW_ROOT} local out=1 if is_nfs; then find_nfs && out=0 else _rootdev_mount && out=0 fi if [ "${out}" != "0" ]; then bad_msg "Could not mount specified ROOT, try again" prompt_user "REAL_ROOT" "root block device" continue fi # now that the root filesystem is mounted, before # checking the validity of ${NEW_ROOT} and ${REAL_INIT}, # ensure that ${NEW_ROOT}/etc/initramfs.mounts entries # are mounted. ensure_initramfs_mounts # NFS does not need further checks here. is_nfs && break if [ ! -d "${NEW_ROOT}/dev" ]; then _msg="The filesystem ${REAL_ROOT}," _msg="${_msg} mounted at ${NEW_ROOT}" _msg="${_msg} does not contain /dev" _msg="${_msg}, init will likely fail..." bad_msg "${_msg}" prompt_user "REAL_ROOT" "root block device" continue fi if [ ! -x "${NEW_ROOT}${REAL_INIT}" ]; then _msg="The filesystem ${REAL_ROOT}," _msg="${_msg} mounted at ${NEW_ROOT}" _msg="${_msg} does not contain a valid" _msg="${_msg} init=${REAL_INIT}" bad_msg "${_msg}" prompt_user "REAL_ROOT" "root block device" continue fi break done } # If devtmpfs is mounted, try move it to the new root # If that fails, try to unmount all possible mounts of devtmpfs as # stuff breaks otherwise move_mounts_to_chroot() { for fs in /run /dev /sys /proc; do if grep -qs "$fs" /proc/mounts; then local chroot_dir="${CHROOT}${fs}" mkdir -p "${chroot_dir}" if ! mount --move $fs "${chroot_dir}" then umount $fs || \ bad_msg "Failed to move and umount $fs!" fi fi done }