Permalink
Switch branches/tags
Nothing to show
Find file
0a513bb Oct 22, 2017
518 lines (428 sloc) 15.6 KB
# Local filesystem mounting -*- shell-script -*-
pre_mountroot()
{
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
run_scripts /scripts/local-top
[ "$quiet" != "y" ] && log_end_msg
}
identify_boot_mode()
{
# Our current list of supported boot modes:
## BOOT_MODE = ubuntu and android
BOOT_MODE='ubuntu'
# The boot reason is exported via /proc/cmdline
# The standard method is using androidboot.mode parameter.
for x in $(cat /proc/cmdline); do
case ${x} in
androidboot.mode=*)
android_bootmode=${x#*=}
;;
esac
done
if echo "$android_bootmode" | grep charger; then
BOOT_MODE="android"
fi
## Some devices may be using 'bootreason', others 'boot_reason'
## XXX: Find a better way to handle device specifics here
# Krillin
if [ -f /sys/class/BOOT/BOOT/boot/boot_mode ]; then
boot_reason=`cat /sys/class/BOOT/BOOT/boot/boot_mode`
case "${boot_reason}" in
1) BOOT_MODE="android" ;; # Meta
4) BOOT_MODE="android" ;; # Factory
8) BOOT_MODE="android" ;; # Power off charging
9) BOOT_MODE="android" ;; # Low power charging
esac
fi
echo "initrd: boot mode: $BOOT_MODE" >/dev/kmsg || true
}
set_ubuntu_version_properties() {
ubuntu_system=$1
android_data=$2
channel_ini=$1/etc/system-image/channel.ini
def_language=$1/custom/default_language
ubuntu="unknown"
device="unknown"
custom="unknown"
version="unknown"
channel="unknown"
def_lang="unknown"
if [ -f "$channel_ini" ]; then
IFS=','
for i in `grep version_detail $channel_ini | awk -F ' ' '{print $2}'`; do
id=${i%=*}
case $id in
ubuntu) ubuntu=${i#ubuntu=} ;;
device) device=${i#device=} ;;
custom) custom=${i#custom=} ;;
version) version=${i#version=} ;;
esac
done
unset IFS
channel=`grep channel $channel_ini | awk -F ' ' '{print $2}'`
fi
if [ -f "$def_language" ]; then
lang=`cat $def_language`
if [ -n "$lang" ]; then
def_lang=$lang
fi
fi
# Write down so the android property system can load them automatically
mkdir -p $android_data/property
chmod 700 $android_data/property
echo -n "$ubuntu" > $android_data/property/persist.ubuntu.version.rootfs
echo -n "$device" > $android_data/property/persist.ubuntu.version.device
echo -n "$custom" > $android_data/property/persist.ubuntu.version.custom
echo -n "$channel" > $android_data/property/persist.ubuntu.version.channel
echo -n "$version" > $android_data/property/persist.ubuntu.version
echo -n "$def_lang" > $android_data/property/persist.ubuntu.default_language
chmod 600 $android_data/property/persist.ubuntu*
}
mount_android_partitions() {
fstab=$1
mount_root=$2
echo "initrd: checking fstab $fstab for additional mount points" >/dev/kmsg || true
cat ${fstab} | while read line; do
set -- $line
# stop processing if we hit the "#endubuntu" comment in the file
echo $1 | egrep -q "^#endubuntu" && break
# Skip any unwanted entry
echo $1 | egrep -q "^#" && continue
([ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]) && continue
([ "$2" = "/system" ] || [ "$2" = "/data" ]) && continue
label=$(echo $1 | awk -F/ '{print $NF}')
[ -z "$label" ] && continue
echo "initrd: checking mount label $label" >/dev/kmsg || true
# In case fstab provides /dev/mmcblk0p* lines
path="/dev/$label"
for dir in by-partlabel by-name by-label by-path by-uuid by-partuuid by-id; do
if [ -e "/dev/disk/$dir/$label" ]; then
path="/dev/disk/$dir/$label"
break
fi
done
[ ! -e "$path" ] && continue
mkdir -p ${mount_root}/$2
echo "initrd: mounting $path as ${mount_root}/$2" >/dev/kmsg || true
mount $path ${mount_root}/$2 -t $3 -o $4
done
}
mount_ubuntu_overlay() {
source=$1
target=$2
if [ -d ${source} ]; then
OLD_PWD=$PWD
cd ${source}
for overlay in `find . -type f`; do
[ -f ${target}/${overlay} ] && mount --bind ${source}/${overlay} ${target}/${overlay}
done
cd $OLD_PWD
fi
}
sync_dirs() {
base=$1
source=$2
target=$3
OLD_PWD=$PWD
cd $base
for file in $source/*
do
# Skip empty directories
[ ! -e "$base/$file" ] && continue
# If the target already exists as a file or link, there's nothing we can do
[ -e "$target/$file" -o -L "$target/$file" ] && [ ! -d "$target/$file" ] && continue
# If the target doesn't exist, just copy it over
if [ ! -e "$target/$file" -a ! -L "$target/$file" ]; then
cp -Ra "$base/$file" "$target/$file"
continue
fi
# That leaves us with directories and a recursive call
[ -d $file ] && sync_dirs $base $file $target
done
cd $OLD_PWD
}
resize_userdata_if_needed() {
# See if the filesystem on the userdata partition needs resizing (usually on first boot).
# If the difference between the partition size and the filesystem size is above a small
# threshold, assume it needs resizing to fill the partition.
path=$1
# Partition size in 1k blocks
case $path in
/dev/mmcblk*)
pblocks=$(grep ${path#/dev/*} /proc/partitions | awk {'print $3'})
;;
/dev/disk*)
pblocks=$(grep $(basename $(readlink $path)) /proc/partitions | awk {'print $3'})
;;
esac
# Filesystem size in 4k blocks
fsblocks=$(dumpe2fs -h $path | grep "Block count" | awk {'print $3'})
# Difference between the reported sizes in 1k blocks
dblocks=$(($pblocks-4*$fsblocks))
if [ $dblocks -gt 10000 ];then
resize2fs -f $path
echo "initrd: resized userdata filesystem to fill $path" >/dev/kmsg || true
fi
}
mountroot()
{
# list of possible userdata partition names
partlist="userdata UDA DATAFS USERDATA"
pre_mountroot
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-premount"
run_scripts /scripts/local-premount
[ "$quiet" != "y" ] && log_end_msg
# Mount root
#
# Create a temporary mountpoint for the bindmount
mkdir -p /tmpmnt
# Make sure the device has been created by udev before we try to mount
udevadm settle
# find the right partition
for partname in $partlist; do
part=$(find /dev -name $partname|tail -1)
[ -z "$part" ] && continue
path=$(readlink -f $part)
[ -n "$path" ] && break
done
# override with a possible cmdline parameter
if grep -q datapart= /proc/cmdline; then
for x in $(cat /proc/cmdline); do
case ${x} in
datapart=*)
path=${x#*=}
;;
esac
done
fi
if [ -z "$path" ]; then
echo "initrd: Couldn't find data partition. Spawning adbd ..." >/dev/kmsg || true
panic "Couldn't find data partition. Spawning adbd ..."
fi
echo "initrd: checking filesystem integrity for the userdata partition" >/dev/kmsg || true
# Mounting and umounting first, let the kernel handle the journal and
# orphaned inodes (faster than e2fsck). Then, just run e2fsck forcing -y.
# Also check the amount of time used by to check the filesystem.
fsck_start=`date +%s`
mount -o errors=remount-ro $path /tmpmnt
umount /tmpmnt
e2fsck -y $path > /run/initramfs/e2fsck.out 2>&1
fsck_end=`date +%s`
echo "initrd: checking filesystem for userdata took (including e2fsck) $((fsck_end-fsck_start)) seconds" >/dev/kmsg || true
resize_userdata_if_needed ${path}
echo "initrd: mounting $path" >/dev/kmsg || true
# Mount the data partition to a temporary mount point
# FIXME: data=journal used as a workaround for bug 1387214
mount -o discard,data=journal $path /tmpmnt
if grep -q systempart= /proc/cmdline; then
for x in $(cat /proc/cmdline); do
case ${x} in
systempart=*)
syspart=${x#*=}
;;
esac
done
fi
identify_boot_mode
# Real partition or image, we both need charger mode.....
if ( [ -e /tmpmnt/system.img ] || [ -n "$syspart" ] ) && [ "$BOOT_MODE" = "android" ]; then
# Factory/charger mode, just boot directly into the android rootfs
mkdir -p /ubuntu-system
mkdir -p /android-rootfs
mkdir -p /android-system
echo "initrd: mounting ubuntu system partition" >/dev/kmsg || true
if [ -n "$syspart" ]; then
mount -o rw $syspart /ubuntu-system
else
mount -o loop,rw /tmpmnt/system.img /ubuntu-system
fi
mount -o remount,ro /ubuntu-system
echo "initrd: mounting android system image" >/dev/kmsg || true
mount -o loop,ro /ubuntu-system/var/lib/lxc/android/system.img /android-system
echo "initrd: extracting android ramdisk" >/dev/kmsg || true
OLD_CWD=$(pwd)
mount -n -t tmpfs tmpfs /android-rootfs
cd /android-rootfs
cat /android-system/boot/android-ramdisk.img | gzip -d | cpio -i
cd $OLD_CWD
echo "initrd: using android ramdisk as rootfs" >/dev/kmsg || true
mount --move /android-rootfs ${rootmnt}
# Mounting system
mount --move /android-system ${rootmnt}/system
mkdir -p ${rootmnt}/ubuntu-system
mount --move /ubuntu-system ${rootmnt}/ubuntu-system
# Mounting userdata
mkdir -p ${rootmnt}/data
mkdir -p ${rootmnt}/userdata
mount --move /tmpmnt ${rootmnt}/userdata
mkdir -p ${rootmnt}/userdata/android-data
mount -o bind ${rootmnt}/userdata/android-data ${rootmnt}/data
# Set ubuntu version properties
set_ubuntu_version_properties ${rootmnt}/ubuntu-system ${rootmnt}/data
# Mount all the remaining android partitions
mount_android_partitions "${rootmnt}/fstab*" ${rootmnt}
# Make sure we're booting into android's init
ln -s ../init ${rootmnt}/sbin/init
ln -s ../init ${rootmnt}/sbin/recovery
echo "initrd: booting android..." >/dev/kmsg || true
elif [ -e /tmpmnt/system.img -o -n "$syspart" ]; then
# Loop-mounted flipped model
# Transition .developer_mode to .writable_image
[ -e /tmpmnt/.developer_mode ] && mv /tmpmnt/.developer_mode /tmpmnt/.writable_image
# Prepare the root filesystem
# NOTE: We mount it read-write in all cases, then remount read-only.
# This is to workaround a behaviour change in busybox which now
# uses read-only loops if the fs is initially mounted read-only.
# An alternative implementation would be to add losetup support
# to busybox and do the mount in two steps (rw loop, ro fs).
if [ -n "$syspart" ]; then
mount -o rw $syspart ${rootmnt}
else
mount -o loop,rw /tmpmnt/system.img ${rootmnt}
fi
if [ -e /tmpmnt/.writable_image ]; then
echo "initrd: mounting system.img (image developer mode)" >/dev/kmsg || true
mountroot_status="$?"
else
echo "initrd: mounting system.img (user mode)" >/dev/kmsg || true
mount -o remount,ro ${rootmnt}
mountroot_status="$?"
fi
mount --move /tmpmnt ${rootmnt}/userdata
# Set ubuntu version properties
mkdir -p ${rootmnt}/userdata/android-data
set_ubuntu_version_properties ${rootmnt} ${rootmnt}/userdata/android-data
# Mount the android system partition to a temporary location
mkdir -p /android-system
MOUNT="ro"
[ -e ${rootmnt}/userdata/.writable_device_image -a -e ${rootmnt}/userdata/.writable_image ] && MOUNT="rw"
echo "initrd: mounting device image as $MOUNT" >/dev/kmsg || true
mount -o loop,$MOUNT ${rootmnt}/var/lib/lxc/android/system.img /android-system
# Get device information
device=$(grep ^ro.product.device= /android-system/build.prop |sed -e 's/.*=//')
[ -z "$device" ] && device="unknown"
echo "initrd: device is $device" >/dev/kmsg || true
# Mount some tmpfs
mkdir -p ${rootmnt}/android
mount -o rw,size=4096 -t tmpfs none ${rootmnt}/android
mount -o rw,nosuid,noexec,relatime,mode=755 -t tmpfs tmpfs ${rootmnt}/run
# Create some needed paths on tmpfs
mkdir -p ${rootmnt}/android/data ${rootmnt}/android/system
# Prepare the fstab
FSTAB=${rootmnt}/etc/fstab
touch ${rootmnt}/run/image.fstab
mount -o bind ${rootmnt}/run/image.fstab $FSTAB || panic "drop to adb"
echo "/dev/root / rootfs defaults,ro 0 0" >> $FSTAB
# Process the list of bind-mounts
# (but don't mount them, mountall will do it)
cat ${rootmnt}/etc/system-image/writable-paths | while read line; do
set -- $line
# Skip invalid/commented entries
([ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ] || [ -z "$5" ]) && continue
[ "$1" = "#" ] && continue
# Skip invalid mount points
dstpath="${rootmnt}/$1"
[ ! -e "$dstpath" ] && continue
if [ "$3" = "temporary" ]; then
# Temporary entries are simple, just mount a tmpfs
echo "tmpfs $1 tmpfs $5 0 0" >> $FSTAB
elif [ "$3" = "persistent" ] || [ "$3" = "synced" ]; then
# Figure out the source path
if [ "$2" = "auto" ]; then
srcpath="${rootmnt}/userdata/system-data/$1"
path="/userdata/system-data/$1"
else
srcpath="${rootmnt}/userdata/$2"
path="/userdata/$2"
fi
if [ ! -e "$srcpath" ]; then
# Process new persistent or synced paths
dstown=$(stat -c "%u:%g" $dstpath)
dstmode=$(stat -c "%a" $dstpath)
mkdir -p ${srcpath%/*}
if [ ! -d "$dstpath" ]; then
# Deal with redirected files
if [ "$4" = "transition" ]; then
cp -a $dstpath $srcpath
else
touch $srcpath
chown $dstown $srcpath
chmod $dstmode $srcpath
fi
else
# Deal with redirected directories
if [ "$4" = "transition" ] || [ "$3" = "synced" ]; then
cp -aR $dstpath $srcpath
else
mkdir $srcpath
chown $dstown $srcpath
chmod $dstmode $srcpath
fi
fi
elif [ "$3" = "synced" ]; then
# Process existing synced paths
sync_dirs $dstpath . $srcpath
fi
# Write the fstab entry
if [ "$5" = "none" ]; then
echo "$path $1 none bind 0 0" >> $FSTAB
else
echo "$path $1 none bind,$5 0 0" >> $FSTAB
fi
else
continue
fi
done
# Extract the fstab from the android initrd
# NOTE: we should find a faster way of doing that or cache it
OLD_CWD=$(pwd)
mount -n -t tmpfs tmpfs ${rootmnt}/var/lib/lxc/android/rootfs
cd ${rootmnt}/var/lib/lxc/android/rootfs
cat /android-system/boot/android-ramdisk.img | gzip -d | cpio -i
cd $OLD_CWD
# Mount all the Android partitions
mount_android_partitions "${rootmnt}/var/lib/lxc/android/rootfs/fstab*" ${rootmnt}/android
# system is a special case
echo "initrd: mounting ${rootmnt}/var/lib/lxc/android/system.img as ${rootmnt}/android/system" >/dev/kmsg || true
mount --move /android-system ${rootmnt}/android/system
# Ubuntu overlay available in the Android system image (hardware specific configs)
mount_ubuntu_overlay ${rootmnt}/android/system/ubuntu ${rootmnt}
# Apply device-specific udev rules
if [ ! -f ${rootmnt}/android/system/ubuntu/lib/udev/rules.d/70-android.rules ] && [ "$device" != "unknown" ]; then
mount --bind ${rootmnt}/usr/lib/lxc-android-config/70-$device.rules ${rootmnt}/lib/udev/rules.d/70-android.rules
fi
# Bind-mount /lib/modules from Android
[ -e ${rootmnt}/android/system/lib/modules ] && mount --bind ${rootmnt}/android/system/lib/modules ${rootmnt}/lib/modules
# Bind-mount /var/lib/ureadahead if available on persistent storage
# this is required because ureadahead runs before mountall
if [ -e ${rootmnt}/userdata/system-data/var/lib/ureadahead ] && \
[ -e ${rootmnt}/var/lib/ureadahead ]; then
mount --bind ${rootmnt}/userdata/system-data/var/lib/ureadahead ${rootmnt}/var/lib/ureadahead
fi
# Setup the swap device
[ -e ${rootmnt}/userdata/SWAP.img ] && swapon ${rootmnt}/userdata/SWAP.img
# Apply customized content
for user in ${rootmnt}/userdata/user-data/*
do
if [ -d ${rootmnt}/custom/home ] && [ ! -e "$user/.customized" ]; then
echo "initrd: copying custom content tp " >/dev/kmsg || true
cp -Rap ${rootmnt}/custom/home/* "$user/"
cp -Rap ${rootmnt}/custom/home/.[a-zA-Z0-9]* "$user/"
touch "$user/.customized"
dstown=$(stat -c "%u:%g" "$user")
chown -R $dstown "$user/"
fi
done
# Old flipped model
elif [ -d /tmpmnt/ubuntu ]; then
mount --bind /tmpmnt/ubuntu ${rootmnt}
mountroot_status="$?"
# Possibly a re-partitioned device
else
echo "initrd: Couldn't find a system partition." >/dev/kmsg || true
panic "Couldn't find a system partition. Spawning adbd ..."
fi
[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
run_scripts /scripts/local-bottom
[ "$quiet" != "y" ] && log_end_msg
}