You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
genkernel_fork/defaults/initrd.scripts

1673 lines
52 KiB

#!/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
modules_load() {
for module in $*
do
echo ${module} >> /etc/modules/extra_load
done
modules_scan extra_load
}
modules_scan() {
local MODS
local loaded
MODS=$(cat /etc/modules/${1} 2>/dev/null)
[ -n "${MODS}" ] && [ -z "${QUIET}" ] && \
echo -ne "${BOLD} ::${NORMAL} Loading from ${1}: "
for x in ${MODS}
do
MLOAD=$(echo ${MLIST} | sed -e "s/.*${x}.*/${x}/")
if [ "${MLOAD}" = "${x}" ] # Only module to no-load
then
[ -z "${QUIET}" ] && \
echo -e "${BOLD} ::${NORMAL} Skipping ${x}..."
elif [ "${MLOAD}" = "${MLIST}" ]
then
if [ -n "${DEBUG}" ]; then
echo -ne "${BOLD} ::${NORMAL} "
echo -ne "Scanning for ${x}..."
fi
modprobe ${x} > /dev/null 2>&1
loaded=${?}
[ -n "${DEBUG}" -a "${loaded}" = "0" ] && \
echo "loaded"
[ -n "${DEBUG}" -a "${loaded}" != "0" ] && \
echo "not loaded"
[ -z "${DEBUG}" -a "${loaded}" = "0" ] && \
[ -z "${QUIET}" ] && \
echo -en "${x} "
else
[ -z "${QUIET}" ] && \
echo -e "${BOLD} ::${NORMAL} Skipping ${x}..."
fi
done
[ -n "${MODS}" ] && [ -z "${QUIET}" ] && echo
}
modules_init() {
if [ -z "${DO_modules}" ]; then
good_msg 'Skipping module load; disabled via commandline'
elif [ -d "/lib/modules/${KV}" ]; then
good_msg 'Loading modules'
# Load appropriate kernel modules
if [ "${NODETECT}" != '1' ]; then
for modules in ${MY_HWOPTS}
do
modules_scan ${modules}
done
fi
# Always eval doload=...
modules_load ${MDOLIST}
else
good_msg 'Skipping module load; no modules in the ramdisk!'
fi
# Give udev time to execute all the rules. This may be beneficial
# for usb-storage devices.
is_udev && udevadm settle
}
uppercase() {
# needs tr on busybox
echo ${1} | tr 'a-z' 'A-Z'
}
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
}
findmediamount() {
# $1 = mount dir name / media name
# $2 = recognition file
# $3 = variable to have the device path
# $4 = actual mount dir path (full path)
# args remaining are possible devices
local media=$1 recon=$2 vrbl=$3 mntdir=$4
shift 4
good_msg "Looking for the ${media}" ${CRYPT_SILENT}
if [ "$#" -gt "0" ]
then
[ ! -d "${mntdir}" ] && mkdir -p ${mntdir} 2>/dev/null >/dev/null
if [ -n "${ISOBOOT}" ]
then
mntcddir="${mntdir%${media}}iso"
if [ ! -f ${mntcddir} ]
then
mkdir ${mntcddir}
fi
else
mntcddir=${mntdir}
fi
for x in $*
do
# Check for a block device to mount
if [ -b "${x}" ]
then
skip=0
bsn=$(basename "${x}")
#
# If disk and it has at least one partition, skip.
# We use /sys/block/${bsn}/${bsn}[0-9]* to make sure that we
# don't skip device mapper devices. Even the craziest scenario
# deserves a fair chance.
#
for part in $(ls /sys/block/${bsn}/${bsn}*[0-9]* 2>/dev/null)
do
skip=1
break;
done
if [ ${skip} -eq 1 ]
then
continue
fi
good_msg "Attempting to mount media: ${x}" ${CRYPT_SILENT}
mount -r -t ${CDROOT_TYPE} ${x} ${mntcddir} >/dev/null 2>&1
if [ "$?" = '0' ]
then
if [ -n "${ISOBOOT}" ]; then
if [ -f ${mntcddir}/${ISOBOOT} ]; then
mount -o loop ${mntcddir}/${ISOBOOT} ${mntdir}
if [ "$?" = "0" ]; then
good_msg "iso mounted on ${mntdir}"
fi
fi
fi
# Check for the media
if [ -f "${mntdir}/${recon}" ]
then
#set REAL_ROOT, CRYPT_ROOT_KEYDEV or whatever ${vrbl} is
eval ${vrbl}'='"${x}"
good_msg "Media found on ${x}" ${CRYPT_SILENT}
break
else
umount ${mntcddir}
fi
fi
fi
done
fi
eval local result='$'${vrbl}
[ -n "${result}" ] || bad_msg "Media not found" ${CRYPT_SILENT}
}
devicelist() {
# Locate the cdrom device with our media on it.
# CDROM DEVICES
local DEVICES="/dev/cdroms/* /dev/ide/cd/* /dev/sr*"
# USB Keychain/Storage
DEVICES="$DEVICES /dev/sd*"
# IDE devices
DEVICES="$DEVICES /dev/hd*"
# virtio devices
DEVICES="$DEVICES /dev/vd*"
# USB using the USB Block Driver
DEVICES="$DEVICES /dev/ubd* /dev/ubd/*"
# iSeries devices
DEVICES="$DEVICES /dev/iseries/vcd*"
# builtin mmc/sd card reader devices
DEVICES="$DEVICES /dev/mmcblk* /dev/mmcblk*/*"
# fallback scanning, this might scan something twice, but it's better than
# failing to boot.
local parts=$(awk '/([0-9]+[[:space:]]+)/{print "/dev/" $4}' \
/proc/partitions)
[ -e /proc/partitions ] && DEVICES="${DEVICES} ${parts}"
echo ${DEVICES}
}
bootstrap_cd() {
local DEVICES=
# The device was specified on the command line, so there's no need
# to scan a bunch of extra devices
[ -n "${CDROOT_DEV}" ] && DEVICES="${CDROOT_DEV}"
[ -z "${CDROOT_DEV}" ] && DEVICES=$(devicelist)
findmediamount "cdrom" "${SUBDIR}/${CDROOT_MARKER}" \
"REAL_ROOT" "${CDROOT_PATH}" ${DEVICES}
}
bootstrap_key() {
# $1 = ROOT/SWAP
local KEYDEVS=$(devicelist)
eval local keyloc='"${CRYPT_'${1}'_KEY}"'
findmediamount "key" "${keyloc}" "CRYPT_${1}_KEYDEV" "/mnt/key" ${KEYDEVS}
}
cache_cd_contents() {
# Check loop file exists and cache to ramdisk if DO_cache is enabled
if [ "${LOOPTYPE}" != "noloop" ] && [ "${LOOPTYPE}" != "sgimips" ]
then
check_loop
if [ "${DO_cache}" ]
then
# TODO: Check the size of the image versus the size of our tmpfs
# along with the amount of available RAM and increase tmpfs size
# if necessary. (Not having awk sucks...)
# z=0
# for i in $(cat /proc/meminfo | grep -e ^MemFree -e ^Cached | \
# cut -d: -f2 | cut -dk -f1 | sed -e "s/^\s*//") ; do
# z=$(($z + $i)) ; done
# echo $z
good_msg "Copying loop file for caching..."
# Verify that the needed directory exists
mkdir -p "$(dirname ${NEW_ROOT}/mnt/${LOOP})"
cp -a ${CDROOT_PATH}/${LOOP} ${NEW_ROOT}/mnt/${LOOP}
if [ $? -ne 0 ]
then
warn_msg "Failed to cache the loop file! Lack of RAM?"
rm -rf ${NEW_ROOT}/mnt/${LOOP} 2>/dev/null
rm -rf ${NEW_ROOT}/mnt/livecd.* 2>/dev/null
rm -rf ${NEW_ROOT}/mnt/image.* 2>/dev/null
rm -rf ${NEW_ROOT}/mnt/zisofs 2>/dev/null
fi
fi
fi
}
mount_sysfs() {
mount -t sysfs sysfs /sys -o noexec,nosuid,nodev >/dev/null 2>&1
ret=$?
[ ${ret} -eq 0 ] || bad_msg "Failed to mount /sys!"
}
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
}
check_loop() {
if [ -z "${LOOP}" ] || [ ! -e "${CDROOT_PATH}/${LOOP}" ]; then
bad_msg "Invalid loop location: ${LOOP}"
bad_msg "Please export LOOP with a valid location"
bad_msg "or reboot and pass a proper loop=..."
bad_msg "kernel command line"
run_shell
fi
}
run_shell() {
/bin/ash
}
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
}
# Courtesy of dracut. Licensed under GPL-2.
# Taken from: dracut/modules.d/90crypt/crypt-lib.sh
# ask_for_password
#
# Wraps around plymouth ask-for-password and adds fallback to tty password ask
# if plymouth is not present.
#
# --cmd command
# Command to execute. Required.
# --prompt prompt
# Password prompt. Note that function already adds ':' at the end.
# Recommended.
# --tries n
# How many times repeat command on its failure. Default is 3.
# --ply-[cmd|prompt|tries]
# Command/prompt/tries specific for plymouth password ask only.
# --tty-[cmd|prompt|tries]
# Command/prompt/tries specific for tty password ask only.
# --tty-echo-off
# Turn off input echo before tty command is executed and turn on after.
# It's useful when password is read from stdin.
ask_for_password() {
local cmd; local prompt; local tries=3
local ply_cmd; local ply_prompt; local ply_tries=3
local tty_cmd; local tty_prompt; local tty_tries=3
local ret
while [ $# -gt 0 ]; do
case "$1" in
--cmd) ply_cmd="$2"; tty_cmd="$2" shift;;
--ply-cmd) ply_cmd="$2"; shift;;
--tty-cmd) tty_cmd="$2"; shift;;
--prompt) ply_prompt="$2"; tty_prompt="$2" shift;;
--ply-prompt) ply_prompt="$2"; shift;;
--tty-prompt) tty_prompt="$2"; shift;;
--tries) ply_tries="$2"; tty_tries="$2"; shift;;
--ply-tries) ply_tries="$2"; shift;;
--tty-tries) tty_tries="$2"; shift;;
--tty-echo-off) tty_echo_off=yes;;
esac
shift
done
{ flock -s 9;
# Prompt for password with plymouth, if installed and running.
if is_plymouth_started
then
"${PLYMOUTH_BIN}" ask-for-password \
--prompt="$ply_prompt" \
--number-of-tries=$ply_tries \
--command="$ply_cmd"
ret=$?
else
splashcmd verbose
if [ "$tty_echo_off" = yes ]; then
stty_orig="$(stty -g)"
stty -echo
fi
local i=1
while [ $i -le $tty_tries ]; do
[ -n "$tty_prompt" ] && \
printf "$tty_prompt [$i/$tty_tries]:" >&2
eval "$tty_cmd" && ret=0 && break
ret=$?
i=$(($i+1))
[ -n "$tty_prompt" ] && printf '\n' >&2
done
[ "$tty_echo_off" = yes ] && stty $stty_orig
# no need for: splashcmd quiet
# since fbsplash does not support it
if [ $ret -ne 0 ] && is_fbsplash
then
splashcmd set_msg 'Disk unlocked.'
fi
fi
} 9>/.console_lock
[ $ret -ne 0 ] && bad_msg "Wrong password"
return $ret
}
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 <Ctrl>+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}
}
load_modules() {
# Load modules listed in MY_HWOPTS if /lib/modules exists for the running
# kernel version
if [ -d "/lib/modules/${KV}" ]
then
good_msg 'Loading modules'
# Load appropriate kernel modules
for modules in $MY_HWOPTS
do
modules_scan $modules
done
else
good_msg 'Skipping module load; no modules in the ramdisk!'
fi
}
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...
# please use 'tr' and this line, or remove it
# eval local TYPE=$(uppercase $1)
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
}
quiet_kmsg() {
# if QUIET is set make the kernel less chatty
[ -n "$QUIET" ] && echo '0' > /proc/sys/kernel/printk
}
verbose_kmsg() {
# if QUIET is set make the kernel less chatty
[ -n "$QUIET" ] && echo '6' > /proc/sys/kernel/printk
}
cdupdate() {
if is_livecd
then
if [ -x /${CDROOT_PATH}/cdupdate.sh ]
then
good_msg "Running cdupdate.sh"
${CDROOT_PATH}/cdupdate.sh
if [ "$?" != '0' ]
then
bad_msg "Executing cdupdate.sh failed!"
run_shell
fi
else
good_msg 'No cdupdate.sh script found, skipping...'
fi
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
}
do_rundebugshell() {
splashcmd verbose
good_msg 'Type "exit" to continue with normal bootup.'
[ -x /bin/sh ] && /bin/sh || /bin/ash
splashcmd quiet
}
rundebugshell() {
if [ -n "$DEBUG" ]
then
good_msg 'Starting debug shell as requested by "debug" option.'
good_msg "Stopping by: ${1}"
do_rundebugshell
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
}
find_loop() {
for loop in ${LOOPS}
do
if [ -e "${CDROOT_PATH}""${loop}" ]
then
LOOP="${loop}"
fi
done
}
find_looptype() {
LOOPTYPE="${LOOP##*.}"
[ "${LOOPTYPE}" == "loop" ] && LOOPTYPE="normal"
[ "${LOOP}" == "/zisofs" ] && LOOPTYPE="${LOOP#/}"
[ -z "${LOOPTYPE}" ] && LOOPTYPE="noloop"
}
getdvhoff() {
echo $(( $(hexdump -n 4 -s $((316 + 12 * $2)) -e '"%i"' $1) * 512))
}
setup_squashfs_aufs() {
# Setup aufs directories and vars
local overlay=/mnt/overlay
local static=/mnt/livecd
for i in "${overlay}" "${static}"; do
[ ! -d "${i}" ] && mkdir -p "${i}"
done
good_msg "Loading aufs"
modprobe aufs > /dev/null 2>&1
mount -t squashfs -o loop,ro "${CDROOT_PATH}/${LOOPEXT}${LOOP}" "${static}"
mount -t tmpfs none "${overlay}"
mount -t aufs -o br:${overlay}:${static} aufs "${NEW_ROOT}"
[ ! -d "${NEW_ROOT}${overlay}" ] && mkdir -p "${NEW_ROOT}${overlay}"
[ ! -d "${NEW_ROOT}${static}" ] && mkdir -p "${NEW_ROOT}${static}"
echo "aufs / aufs defaults 0 0" > "${NEW_ROOT}"/etc/fstab
for i in "${overlay}" "${static}"; do
mount --move "${i}" "${NEW_ROOT}${i}"
done
# have handy /mnt/cdrom (CDROOT_PATH) as well
local new_cdroot="${NEW_ROOT}${CDROOT_PATH}"
[ ! -d "${new_cdroot}" ] && mkdir -p "${new_cdroot}"
mount --bind "${CDROOT_PATH}" "${new_cdroot}"
}
livecd_init() {
good_msg "Making tmpfs for ${NEW_ROOT}"
mount -n -t tmpfs -o mode=0755 tmpfs "${NEW_ROOT}"
local dirs=
dirs="dev mnt proc run sys tmp mnt/livecd"
dirs="${dirs} mnt/key tmp/.initrd mnt/gentoo"
for i in ${dirs}; do
mkdir -p "${NEW_ROOT}/${i}"
chmod 755 "${NEW_ROOT}/${i}"
done
[ ! -d "${CDROOT_PATH}" ] && mkdir -p "${CDROOT_PATH}"
[ ! -e "${NEW_ROOT}/dev/null" ] && mknod "${NEW_ROOT}"/dev/null c 1 3
[ ! -e "${NEW_ROOT}/dev/console" ] && \
mknod "${NEW_ROOT}"/dev/console c 5 1
# For SGI LiveCDs ...
if [ "${LOOPTYPE}" = "sgimips" ]; then
[ ! -e "${NEW_ROOT}/dev/sr0" ] && \
mknod "${NEW_ROOT}/dev/sr0" b 11 0
[ ! -e "${NEW_ROOT}/dev/loop0" ] && \
mknod "${NEW_ROOT}/dev/loop0" b 7 0
fi
# Required for splash to work. Not an issue with the initrd as this
# device isn't created there and is not needed.
if [ -e /dev/tty1 ]; then
[ ! -e "${NEW_ROOT}/dev/tty1" ] && \
mknod "${NEW_ROOT}/dev/tty1" c 4 1
fi
if ! is_nfs && [ "${LOOPTYPE}" != "sgimips" ]; then
bootstrap_cd
fi
if [ "${REAL_ROOT}" = '' ]
then
warn_msg "No bootable medium found. Waiting for new devices..."
COUNTER=0
while [ ${COUNTER} -lt 3 ]; do
sleep 3
let COUNTER=${COUNTER}+1
done
sleep 1
bootstrap_cd
fi
if [ "${REAL_ROOT}" = '' ]
then
# leave stale mounts around, make possible to debug
bad_msg 'Could not find CD to boot, something else needed!'
CDROOT=0
fi
}
livecd_mount() {
# Let Init scripts know that we booted from CD
export CDBOOT
CDBOOT=1
good_msg 'Determining looptype ...'
cd "${NEW_ROOT}"
# Find loop and looptype
[ -z "${LOOP}" ] && find_loop
[ -z "${LOOPTYPE}" ] && find_looptype
cache_cd_contents
# If encrypted, find key and mount, otherwise mount as usual
if [ -n "${CRYPT_ROOT}" ]
then
CRYPT_ROOT_KEY="$(head -n 1 "${CDROOT_PATH}"/${CDROOT_MARKER})"
CRYPT_ROOT='/dev/loop0'
good_msg 'You booted an encrypted livecd' "${CRYPT_SILENT}"
losetup /dev/loop0 "${CDROOT_PATH}/${LOOPEXT}${LOOP}"
test_success 'Preparing loop filesystem'
start_luks
case ${LOOPTYPE} in
normal)
MOUNTTYPE="ext2"
;;
*)
MOUNTTYPE="${LOOPTYPE}"
;;
esac
mount -t "${MOUNTTYPE}" -o ro /dev/mapper/root \
"${NEW_ROOT}/mnt/livecd"
test_success 'Mount filesystem'
FS_LOCATION='mnt/livecd'
else
# Setup the loopback mounts, if unencrypted
if [ "${LOOPTYPE}" = 'normal' ]; then
_livecd_mount_normal
FS_LOCATION='mnt/livecd'
elif [ "${LOOPTYPE}" = 'squashfs' ]; then
_livecd_mount_squashfs
FS_LOCATION='mnt/livecd'
elif [ "${LOOPTYPE}" = 'gcloop' ]; then
_livecd_mount_gcloop
FS_LOCATION='mnt/livecd'
elif [ "${LOOPTYPE}" = 'zisofs' ]; then
FS_LOCATION="${CDROOT_PATH/\/}/${LOOPEXT}${LOOP}"
elif [ "${LOOPTYPE}" = 'noloop' ]; then
FS_LOCATION="${CDROOT_PATH/\/}"
elif [ "${LOOPTYPE}" = 'sgimips' ]; then
_livecd_mount_sgimips
FS_LOCATION='mnt/livecd'
fi
fi
is_nfs && _livecd_mount_unpack_nfs
# Manually copy livecd content to tmpfs if aufs is disabled
is_aufs || _livecd_mount_copy_content
}
# Unpack additional packages from NFS mount
# This is useful for adding kernel modules to /lib
# We do this now, so that additional packages can add whereever
# they want.
_livecd_mount_unpack_nfs() {
if [ -e "${CDROOT_PATH}/add" ]; then
for targz in $(ls ${CDROOT_PATH}/add/*.tar.gz); do
tarname=$(basename ${targz})
good_msg "Adding additional package ${tarname}"
(cd ${NEW_ROOT} ; /bin/tar -xzf ${targz})
done
fi
}
_livecd_mount_sgimips() {
# getdvhoff finds the starting offset (in bytes) of the squashfs
# partition on the cdrom and returns this offset for losetup
#
# All currently supported SGI Systems use SCSI CD-ROMs, so
# so we know that the CD-ROM is usually going to be /dev/sr0.
#
# We use the value given to losetup to set /dev/loop0 to point
# to the liveCD root partition, and then mount /dev/loop0 as
# the LiveCD rootfs
good_msg 'Locating the SGI LiveCD Root Partition'
echo ' ' | \
losetup -o $(getdvhoff "${NEW_ROOT}${REAL_ROOT}" 0) \
"${NEW_ROOT}${CDROOT_DEV}" \
"${NEW_ROOT}${REAL_ROOT}"
test_success 'losetup /dev/sr0 /dev/loop0'
good_msg 'Mounting the Root Partition'
mount -t squashfs -o ro "${NEW_ROOT}${CDROOT_DEV}" \
"${NEW_ROOT}/mnt/livecd"
test_success 'mount /dev/loop0 /'
}
_livecd_mount_gcloop() {
good_msg 'Mounting gcloop filesystem'
echo ' ' | losetup -E 19 -e ucl-0 -p0 \
"${NEW_ROOT}/dev/loop0" \
"${CDROOT_PATH}/${LOOPEXT}${LOOP}"
test_success 'losetup the loop device'
mount -t ext2 -o ro "${NEW_ROOT}/dev/loop0" "${NEW_ROOT}/mnt/livecd"
test_success 'Mount the losetup loop device'
}
_livecd_mount_normal() {
good_msg 'Mounting loop filesystem'
mount -t ext2 -o loop,ro \
"${CDROOT_PATH}/${LOOPEXT}${LOOP}" \
"${NEW_ROOT}/mnt/livecd"
test_success 'Mount filesystem'
}
_livecd_mount_squashfs() {
# if AUFS, redirect to the squashfs+aufs setup function
if is_aufs; then
good_msg 'Mounting squashfs & aufs filesystems'
setup_squashfs_aufs
test_success 'Mount filesystem'
return # preserve old behaviour
fi
good_msg 'Mounting squashfs filesystem'
local cached_squashfs_path="${NEW_ROOT}/mnt/${LOOP}"
local squashfs_path="${CDROOT_PATH}/${LOOPEXT}${LOOP}"
# Upgrade to cached version if possible
if [ -n "${DO_cache}" ] && [ -f "${cached_squashfs_path}" ]; then
squashfs_path="${cached_squashfs_path}"
fi
mount -t squashfs -o loop,ro "${squashfs_path}" \
"${NEW_ROOT}/mnt/livecd" || {
bad_msg "squashfs filesystem could not be mounted."
do_rundebugshell
}
}
# Manually copy livecd read-only content into the final livecd root
# filesystem directory, which has been mounted as tmpfs.
_livecd_mount_copy_content() {
local fs_loc="${NEW_ROOT}/${FS_LOCATION}"
good_msg "Copying read-write image contents to tmpfs"
# Copy over stuff that should be writable
(
cd "${fs_loc}" && cp -a ${ROOT_TREES} "${NEW_ROOT}"
) || {
bad_msg "Copy failed, dropping into a shell."
do_rundebugshell
}
# Now we do the links.
for x in ${ROOT_LINKS}; do
if [ -L "${fs_loc}/${x}" ]; then
ln -s "$(readlink ${fs_loc}/${x})" "${x}" 2>/dev/null
continue
fi
# List all subdirectories of x
find "${fs_loc}/${x}" -type d 2>/dev/null | \
while read directory; do
# Strip the prefix of the FS_LOCATION
directory="${directory#${fs_loc}/}"
# Skip this directory if we already linked a parent
# directory
if [ "${current_parent}" != "" ]; then
var=$(echo "${directory}" | \
grep "^${current_parent}")
if [ "${var}" != "" ]; then
continue
fi
fi
local root_d="${NEW_ROOT}/${directory}"
local fsloc_d="${FS_LOCATION}/${directory}"
# Test if the directory exists already
if [ ! -e "/${root_d}" ]; then
# It does not exist, make a link to the livecd
ln -s "/${FS_LOCATION}/${directory}" \
"${directory}" 2>/dev/null
current_parent="${directory}"
continue
fi
# It does exist, link all the individual files
local fs_d="/${fs_loc}/${directory}"
for file in $(ls "${fs_d}"); do
[ -d "${fs_d}/${file}" ] && continue
[ -e "${root_d}/${file}" ] && continue
ln -s "/${fsloc_d}/${file}" \
"${directory}/${file}" 2> /dev/null
done
done
done
mkdir initramfs proc tmp sys run 2>/dev/null
chmod 1777 tmp
# have handy /mnt/cdrom (CDROOT_PATH) as well
_new_cdroot="${NEW_ROOT}${CDROOT_PATH}"
[ ! -d "${_new_cdroot}" ] && mkdir -p "${_new_cdroot}"
mount --bind "${CDROOT_PATH}" "${_new_cdroot}"
}
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
}