ACC SHELL
#!/bin/bash
#
#%stage: filesystem
#%param_j: "Journal device" device journaldev
#
# usage: update_list <id> <list>
update_list() {
local elem=$1
shift
case " $@ " in
*" $elem "*)
echo "$@"
return 0;;
esac
echo "$@ $elem"
}
# usage: block_driver <major id>
block_driver() {
sed -n "/^Block devices:/{n;: n;s/^[ ]*$1 \(.*\)/\1/p;n;b n}" < /proc/devices
}
# Convert a major:minor pair into a device number
# See /usr/src/linux/include/linux/kdev_t.h
mkdevn() {
local major=$1 minor=$2
echo $(( ($major * 0x100000) + $minor)) # 0x100000 == 2**20
}
# Extract the major part from a device number
devmajor() {
local devn=$1
echo $(( $devn / 0x100000 ))
}
# Extract the minor part from a device number
devminor() {
local devn=${1:-0}
echo $(( $devn % 0x100000 ))
}
# (We are using a devnumber binary inside the initrd.)
devnumber() {
set -- $(ls -lL $1)
mkdevn ${5%,} $6
}
# usage majorminor <major> <minor>
# returns the block device name
majorminor2blockdev() {
local major=${1:-0} minor=$2
if [ ! "$minor" ]; then
minor=$(IFS=: ; set -- $major ; echo $2)
major=$(IFS=: ; set -- $major ; echo $1)
fi
if [ $major -lt 0 ] ; then
return
fi
local retval=$(cat /proc/partitions | egrep "^[ ]*$major[ ]*$minor ")
echo /dev/${retval##* }
}
beautify_blockdev() {
local olddev="$1" udevdevs dev
case "$olddev" in
/dev/md*)
# setup-md.sh doesn't understand the md-uuid-* symlinks
echo "$olddev"
return
esac
# search for udev information
udevdevs=$(/sbin/udevadm info -q symlink --name=$olddev)
# look up ata device links
for dev in $udevdevs; do
if [ "$(echo $dev | grep /ata-)" ] ; then
echo "/dev/$dev"
return
fi
done
# look up scsi device links
for dev in $udevdevs; do
if [ "$(echo $dev | grep /scsi-)" ] ; then
echo "/dev/$dev"
return
fi
done
# take the first guess
for dev in $udevdevs; do
case "$dev" in
block/* | root)
continue
;;
*)
echo "/dev/$dev"
return
esac
done
# get pretty name from device-mapper
if [ -x /sbin/dmsetup -a "$blockdriver" = "device-mapper" ]; then
dm_name=$(dmsetup info -c --noheadings -o name -j $blockmajor -m $blockminor)
if [ "$dm_name" ] ; then
echo "/dev/mapper/$dm_name"
return
fi
fi
echo $olddev
}
dm_resolvedeps() {
local dm_deps dm_dep bd
local bds="$@"
[ ! "$bds" ] && bds=$blockdev
# resolve dependencies
for bd in $bds ; do
update_blockdev $bd >&2
if [ "$blockdriver" = device-mapper ]; then
root_dm=1
dm_deps=$(dmsetup deps -j $blockmajor -m $blockminor 2> /dev/null)
dm_deps=${dm_deps#*: }
dm_deps=${dm_deps//, /:}
dm_deps=${dm_deps//(/}
dm_deps=${dm_deps//)/}
for dm_dep in $dm_deps; do
majorminor2blockdev $dm_dep
done
else
echo -n "$bd "
fi
done
return 0
}
dm_resolvedeps_recursive() {
local dm_uuid dm_deps dm_dep bd
local bds="$@"
[ ! "$bds" ] && bds=$blockdev
# resolve dependencies
for bd in $bds ; do
update_blockdev $bd >&2
if [ "$blockdriver" = device-mapper ]; then
root_dm=1
dm_deps=$(dmsetup deps -j $blockmajor -m $blockminor 2> /dev/null)
dm_deps=${dm_deps#*: }
dm_deps=${dm_deps//, /:}
dm_deps=${dm_deps//(/}
dm_deps=${dm_deps//)/}
for dm_dep in $dm_deps; do
dm_resolvedeps $(majorminor2blockdev $dm_dep)
done
else
echo -n "$bd "
fi
done
[ "$root_dm" = 1 ]
}
# this receives information about the current blockdev so each storage layer has access to it for its current blockdev
update_blockdev() {
local curblockdev=$1
[ "$curblockdev" ] || curblockdev=$blockdev
# no blockdevs
[ "$curblockdev" ] || return
blockmajor=-1
blockminor=-1
if [ -e "$root_dir/${curblockdev#/}" ]; then
blockdevn="$(devnumber $root_dir/${curblockdev#/})"
blockmajor="$(devmajor $blockdevn)"
if [ ! "$blockmajor" ]; then
error 1 "Fatal storage error. Device $curblockdev could not be analyzed."
fi
blockminor="$(devminor $blockdevn)"
blockdriver="$(block_driver $blockmajor)"
if [ ! "$blockdriver" ]; then
error 1 "Fatal storage error. Device $curblockdev does not have a driver."
fi
# temporary hack to have devicemapper activated whenever a dm device was found
if [ "$blockdriver" = device-mapper ]; then
tmp_root_dm=1
fi
fi
if false; then
echo ""
echo "$curblockdev"
echo "===================="
echo ""
echo "bdev: $blockdev"
echo "devn: $blockdevn"
echo "majo: $blockmajor"
echo "mino: $blockminor"
echo "driv: $blockdriver"
echo ""
fi
}
# usage: resolve_device <device label> <device node>
resolve_device() {
local type="$1"
local x="$2"
local realrootdev="$2"
case "$realrootdev" in
LABEL=*|UUID=*)
# get real root via fsck hack
realrootdev=$(fsck -N "$rootdev" \
| sed -ne '2s/.* \/dev/\/dev/p' \
| sed -e 's/ *//g')
if [ -z "$realrootdev" -o ! -b "$realrootdev" ] ; then
echo "Could not expand $x to real device" >&2
exit 1
fi
realrootdev=$(/usr/bin/readlink -m $realrootdev)
;;
/dev/disk/*)
realrootdev=$(/usr/bin/readlink -m $realrootdev)
;;
*:*|//*)
[ "$type" = "Root" ] && x="$rootfstype-root"
;;
esac
# root device was already checked and non-existing
# non-root device is not fatal, but may not be
# shown to the following block resolver modules
[ -b "$realrootdev" ] || exit 0
[ "$x" != "$realrootdev" ] && x="$x ($realrootdev)"
# FIXME: we should really print this to stdout
echo -en "$type device:\t$x" >&2
if [ "$type" = "Root" ]; then
echo " (mounted on ${root_dir:-/} as $rootfstype)" >&2
else
echo >&2
fi
echo $realrootdev
}
#######################################################################################
if [ -z "$rootdev" ] ; then
# no rootdev specified, get current root opts from /etc/fstab and device from stat
# get rootdev via stat
rootcpio=`echo / | /bin/cpio --quiet -o -H newc`
rootmajor="$(echo $(( 0x${rootcpio:62:8} )) )"
rootminor="$(echo $(( 0x${rootcpio:70:8} )) )"
# get opts from fstab and device too if stat failed
sed -e '/^[ \t]*#/d' < $root_dir/etc/fstab >"$work_dir/pipe"
while read fstab_device fstab_mountpoint fstab_type fstab_options dummy ; do
if [ "$fstab_mountpoint" = "/" ]; then
update_blockdev "$fstab_device" # get major and minor
# let's see if the stat device is the same as the fstab device
if [ "$rootmajor" -eq 0 ] || [ "$blockmajor" -eq "$rootmajor" -a "$blockminor" -eq "$rootminor" ]; then # if both match
rootdev="$fstab_device" # use the fstab device so the user can decide
# how to access the root device
fi
rootfstype="$fstab_type"
rootfsopts="$fstab_options"
break
fi
done < "$work_dir/pipe"
if [ $((rootmajor)) -gt 0 -a -z "$rootdev" ] ; then
# don't check for non-device mounts
rootdev="$(majorminor2blockdev $rootmajor $rootminor)"
update_blockdev $rootdev
rootdev="$(beautify_blockdev $rootdev)"
fi
fi
#if we don't know where the root device belongs to
if [ -z "$rootfstype" ] ; then
# get type from /etc/fstab or /proc/mounts (actually not needed)
x1=$(cat $root_dir/etc/fstab /proc/mounts 2>/dev/null \
| grep -E "$rootdev[[:space:]]" | tail -n 1)
rootfstype=$(echo $x1 | cut -f 3 -d " ")
fi
# check for journal device
if [ "$rootfsopts" -a -z "$journaldev" ] ; then
jdev=${rootfsopts#*,jdev=}
if [ "$jdev" != "$rootfsopts" ] ; then
journaldev=${jdev%%,*}
fi
logdev=${rootfsopts#*,logdev=}
if [ "$logdev" != "$rootfsopts" ] ; then
journaldev=${logdev%%,*}
fi
fi
# WARNING: dirty hack to get the resume device of the current system
for o in $(cat /proc/cmdline); do
case "$o" in
resume=*)
resumedev=${o##resume=}
;;
esac
done
# check for nfs root and set the rootfstype accordingly
case "$rootdev" in
/dev/nfs)
rootfstype=nfs
;;
/dev/*)
if [ ! -e "$rootdev" ]; then
error 1 "Root device ($rootdev) not found"
fi
;;
*://*) # URL type
rootfstype=${rootdev%%://*}
interface=${interface:-default}
;;
scsi:*)
;;
*:*)
rootfstype=nfs
interface=${interface:-default}
;;
esac
if [ -z "$rootfstype" ]; then
eval $(udevadm info -q env -n $rootdev | sed -n '/ID_FS_TYPE/p' )
rootfstype=$ID_FS_TYPE
[ $? -ne 0 ] && rootfstype=
[ "$rootfstype" = "unknown" ] && $rootfstype=
ID_FS_TYPE=
fi
if [ ! "$rootfstype" ]; then
error 1 "Could not find the filesystem type for root device $rootdev
Currently available -d parameters are:
Block devices /dev/<device>
NFS <server>:<path>
URL <protocol>://<path>"
fi
# We assume that we always have to load a module for the rootfs
rootfsmod=$rootfstype
# Check if we have to load a module for the rootfs type
# XXX: This check should happen more generically for all modules
if [ ! "$(find $root_dir/lib/modules/$kernel_version/ -name $rootfstype.ko -o -name $rootfstype.ko.gz)" ]; then
if grep -q ${rootfstype}_fs_type $map ; then
# No need to load a module, since this is compiled in
rootfsmod=
fi
fi
# blockdev is the list current block devices.
# It will get modified by the various scrips as they descend through
# the device setup, starting with the mount information
# and ending at the block device
fallback_rootdev="$rootdev"
save_var fallback_rootdev
save_var rootdev
save_var resumedev
save_var journaldev
save_var dumpdev
save_var rootfsopts
save_var rootfstype
blockdev="$(resolve_device Root $rootdev) $(resolve_device Resume $resumedev) $(resolve_device Journal $journaldev) $(resolve_device Dump $dumpdev)"
ACC SHELL 2018