blob: 5a69e1a435db34f68b28064cde9b9c94a29090db [file] [log] [blame]
#!/bin/sh
#
# You can run this script in case you boot with rdinit=/bin/sh and want to
# quickly mount the basic kernel filesystems. It mounts them, but doesn't
# switch_root.
#
. /helpers.sh
find_sata_blkdev()
{
local dev_node result=
for dev_node in /dev/sd?; do
[ -b "$dev_node" ] || continue
local blkdev=${dev_node#/dev/}
local dev_path=$(realpath "/sys/block/$blkdev/device")
if [ "${dev_path#*usb}" = "$dev_path" ]; then
result="$dev_node"
break
fi
done
[ -n "$result" ] && echo "$result"
}
# Finds the *last* /dev/mtd* device with the given realname
find_mtd()
{
local result=
while IFS=" :" read dev size erasesize name; do
name=${name#\"}
name=${name%\"}
if [ "$name" = "$1" ]; then
result=${dev#mtd}
# fall through in case there's a subsequent device with same name
fi
done </proc/mtd
[ -n "$result" ] && echo "$result"
}
find_gpt()
{
local result=
sgdisk -p "$1" >/tmp/gptpart 2>/dev/null
while read number start end size unit code name; do
if [ "$name" = "$2" ]; then
result=$number
fi
done </tmp/gptpart
rm -f /tmp/gptpart
[ -n "$result" ] && echo "$result"
}
find_mmc()
{
find_gpt /dev/mmcblk0 "$1"
}
find_hdd()
{
find_gpt "$1" "$2"
}
read_cmdline
# NOTE on ubi.mtd= vs. root=
#
# Previously, we relied on the installer+bootloader to set ubi.mtd=xxx, and
# then root=mtdblock:rootfs. The problem with that is it depends on the
# installer/bootloader understanding about UBI devices, which means the
# installer for a *previous* version needs to understand the format of kernel
# parameters for the *next* (newly-installed) version. That can make future
# upgrades more complicated.
#
# So what we do now is provide root=xxx, where xxx is the name of the mtd
# partition where the rootfs is installed (either rootfs0 or rootfs1). It's
# the responsibility of the installed image, ie. this script, to know whether
# the stuff in rootfs0/rootfs1 is UBI or not.
#
# However, for backward compatibility, we still need to support kernel options
# of the form
# ubi.mtd=rootfs0 root=mtdblock:rootfs
# which we treat as the new-style
# root=rootfs0
# ubi.mtd= only overrides root= if root= is old-style.
if [ -n "$UBI_MTD" ]; then
if [ -z "$ROOTDEV" -o "${ROOTDEV%%:*}" = "mtdblock" ]; then
ROOTDEV=$UBI_MTD
fi
fi
replacefirst() {
local left right
# same as sed -e 's/$2/$3/' $1
right=${1#*$2}
left=${1%%$2*}
echo "$left$3$right"
}
# Returns true if the string $1 starts with the string $2.
startswith() {
[ "${1#"$2"}" != "$1" ]
}
oldargstonewargs() {
local root_dev=$(replacefirst "$4" "payload=" "")
local hash_dev=$(replacefirst "$5" "hashtree=" "")
local hashstart=$(replacefirst "$6" "hashstart=" "")
local alg=$(replacefirst "$7" "alg=" "")
local root_digest=$(replacefirst "$8" "root_hexdigest=" "")
local salt=$(replacefirst "$9" "salt=" "")
local data_blockcount=$(($2 / 8))
local hash_blockstart=$(($hashstart / 8))
echo "$1 $2 $3 0 $root_dev $hash_dev 4096 4096 $data_blockcount $hash_blockstart $alg $root_digest $salt"
}
# From the verity command line, gets the hash start in Bytes!
get_hashstart() {
local hashstart=${6#hashstart=}
hashstart=$((hashstart * 512))
echo "$hashstart"
}
# Echo back the verity args, but with hashstart=0 for the loopback device.
clear_hashstart() {
echo "$1 $2 $3 $4 $5 hashstart=0 $7 $8 $9"
}
# host:path format in root= means we should do an NFS root
if [ "${ROOTDEV#*:/}" != "$ROOTDEV" ]; then
NFSROOT=$ROOTDEV
fi
if [ -n "$NFSROOT" ]; then
log "Mounting nfs: '$NFSROOT'"
wait # wait for any pending insmods launched by /init
NFSADDR=${NFSROOT%:*}
NFSOPTS="nolock,proto=tcp,mountproto=tcp,vers=3,mountvers=3,addr=$NFSADDR"
if [ -n "$IP" ]; then
# Can't necessarily count on the kernel to do this, in case our
# ethernet driver is a kernel module instead of built-in.
log " IP initialization: '$IP'"
echo "$IP" | {
IFS=: read client_ip server_ip gw_ip netmask hostname device \
autoconf dns0_ip dns1_ip junk
[ -z "$device" ] && device=eth0
if [ "$ip" != "auto" ]; then
ifconfig "$device" "$client_ip" netmask 255.255.255.255
fi
if [ -n "$gw_ip" ]; then
route add -net "$gw_ip" netmask 255.255.255.255 dev "$device"
fi
if [ "$NFSADDR" != "$gw_ip" ]; then
if [ -n "$gw_ip" ]; then
route add -net "$NFSADDR" netmask 255.255.255.255 gw "$gw_ip" \
dev "$device"
else
route add -net "$NFSADDR" netmask 255.255.255.255 dev "$device"
fi
fi
}
log " IP initialized."
fi
# Some PHYs take >1 second to get a link. Poll the connection with nc
# (with a nice short timeout so we cause transmit retries) until it's open,
# then move on to the real NFS mount.
for s in $(seq 10); do
nc -w1 "$NFSADDR" 2049 </dev/null && break
done &&
mount -o $NFSOPTS -t nfs "$NFSROOT" /rootfs ||
die "NFS mount failed"
log "Mounted nfsroot='$NFSROOT'"
elif [ -e /rootfs.img ]; then
cat /rootfs.img >/dev/ram0
mount -t squashfs -o ro /dev/ram0 /rootfs ||
die "root='/dev/ram0' mount failed"
log "Mounted root='/dev/ram0'"
elif [ -n "$ROOTDEV" ]; then
if startswith "$ROOTDEV" /dev; then
mount -o ro -t squashfs "$ROOTDEV" /rootfs ||
die "root='$ROOTDEV' mount failed"
log "Mounted root='$ROOTDEV'"
elif startswith "$ROOTDEV" 9p:; then
fsdev="${ROOTDEV#9p:}"
mount -t 9p -o trans=virtio,version=9p2000.L "$fsdev" /rootfs ||
die "root='$fsdev' (9p) mount failed"
log "Mounted root='$fsdev' (9p)"
else
for s in 1 1 0; do
KERNELNAME=$(replacefirst $ROOTDEV rootfs kernel)
mtd=/dev/mtd$(find_mtd "$ROOTDEV")
mmcraw=/dev/mmcblk0p$(find_mmc "$ROOTDEV")
sata_blkdev=$(find_sata_blkdev)
hdd=${sata_blkdev}$(find_hdd "$sata_blkdev" "$ROOTDEV")
IMAGENAME=$(replacefirst $ROOTDEV rootfs image)
mmcvfat=/dev/mmcblk0p$(find_mmc "$IMAGENAME")
[ -e "$mtd" -o -e "$mmcraw" -o -e "$hdd" -o -e "$mmcvfat" \
-o -e $ROOTDEV ] && break
log "No rootfs found, sleeping"
# eMMC is sometimes slow to appear; try again.
sleep $s
false
done
if [ -e "$mtd" ]; then
log "Found root='$ROOTDEV': $mtd"
# In this build, the rootdev mtd is always an UBI device.
ubidetach -p "$mtd" # Just in case kernel automounted it somewhere
ubiattach -p "${mtd}ro"
# In this build, the newly-found mtd is always named 'rootfs'
ubi_mtd=$(find_mtd "rootfs")
[ -n "$ubi_mtd" ] || (cat /proc/mtd; die "no mtd named 'rootfs'")
ROOTDEV=/dev/mtdblock$ubi_mtd
VERITY_CHAR_DEV=/dev/mtd$(find_mtd "$KERNELNAME")
elif [ -e "$mmcraw" ]; then
log "Found root='$ROOTDEV': $mmcraw"
ROOTDEV=$mmcraw
VERITYDEV=/dev/mmcblk0p$(find_mmc "$KERNELNAME")
elif [ -e "$hdd" ]; then
log "Found root='$ROOTDEV': $hdd"
ROOTDEV=$hdd
# On SpaceCast the kernel still lives in the NOR flash
VERITY_CHAR_DEV=/dev/mtd$(find_mtd "$KERNELNAME")
elif [ -e "$mmcvfat" ]; then
# TODO(jnewlin): Remove this after verifying vfat is not used.
log "Found root='$ROOTDEV': $mmcvfat"
mount -t vfat -o ro,nodev,noexec,nosuid "$mmcvfat" /vfat
VERITYDEV=/dev/loop0
ROOTDEV=/dev/loop1
losetup $VERITYDEV /vfat/vmlinuz.img
losetup $ROOTDEV /vfat/rootfs.img
else
cat /proc/mtd
log "root='$ROOTDEV' is not an mtd device."
fi
if [ -n "$VERITY_CHAR_DEV" ]; then
# dump the verity header, and read the verity settings, they are stored
# in the first 4096 bytes of the image.
mount -t tmpfs none /veritytmp
nanddump -x -f /veritytmp/verity.args -l 4096 -s 0 "$VERITY_CHAR_DEV"
args=$(readverity /veritytmp/verity.args)
hash_size=$(readverity -s /veritytmp/verity.args)
rm /veritytmp/verity.args
hash_offset=$(get_hashstart $args)
args=$(clear_hashstart $args)
nanddump -x -f /veritytmp/hash.dat -l "$hash_size" -s "$hash_offset" "$VERITY_CHAR_DEV"
VERITYDEV=/dev/loop3
losetup $VERITYDEV /veritytmp/hash.dat
else
args=$(readverity $VERITYDEV)
fi
args=$(replacefirst "$args" ROOT_DEV "$ROOTDEV")
args=$(replacefirst "$args" HASH_DEV "$VERITYDEV")
altargs=$(oldargstonewargs $args)
echo "dmsetup: $args"
echo "dmsetup: $altargs"
if ! dmsetup create vroot -r --table "$args" && ! dmsetup create vroot -r --table "$altargs"; then
veritynote=
read x y armplatform platform junk </proc/cpuinfo
if [ "$platform" = "BCM7425B0" ]; then
log 'dmsetup failed: platform is unsigned device, continuing anyway.'
SQUASHFS=$ROOTDEV
else
die "dmsetup failed"
fi
else
SQUASHFS="/dev/mapper/vroot"
veritynote="(verity)"
fi
mount -o ro -t squashfs "$SQUASHFS" /rootfs ||
die "root='$ROOTDEV' mount failed $veritynote"
log "Mounted root='$ROOTDEV' $veritynote"
fi
else
die "No root= or nfsroot= provided."
fi
mount -t tmpfs none /rootfs/tmp
#TODO(apenwarr): network setup code depends on this file, but it shouldn't.
# It should just always refuse to touch the network if the network was already
# set up.
[ -n "$NFSROOT" ] && echo NFS >/rootfs/tmp/NFS
true