# Local filesystem mounting			-*- shell-script -*-

if [ -e "/scripts/halium-hooks" ]; then
	# Hook file found
	source /scripts/halium-hooks
	WITH_HOOKS="yes"
else
	WITH_HOOKS="no"
fi

_log_msg() {
	if [ "$quiet" = "y" ]; then return; fi
	printf "$@" > /dev/kmsg || true
}

pre_mountroot() {
	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-top"
	run_scripts /scripts/local-top
	[ "$quiet" != "y" ] && log_end_msg
}

tell_kmsg() {
	# Echos a string into /dev/kmsg, ignoring errors.
	echo "initrd: $1" >/dev/kmsg || true
}

halium_panic() {
	# Puts panic reason into kmsg and then starts the panic handlers
	REASON="$1"
	tell_kmsg "PANIC for reason: $REASON"
	panic $REASON
}

halium_hook() {
	# Allows calling an user-defined hook. Hooks must go in /scripts/halium-hooks.
	# Call this function like this:
	#     halium_hook test
	#
	# In this example, it will check for and eventually call the halium_hook_test()
	# function.

	func="halium_hook_${1}"
	shift

	if [ "${WITH_HOOKS}" == "yes" ] && [ "$(type -t ${func})" == "${func}" ]; then
		${func} ${@}
	fi
}

identify_boot_mode() {
	# Our current list of supported boot modes:
	## BOOT_MODE = halium and android
	BOOT_MODE='halium'

	# 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#*=}
			;;
		# Android 9 system-as-root
		skip_initramfs)
			normal_boot="y"
			;;
		# Android 10+ recovery-as-boot
		androidboot.force_normal_boot=1)
			normal_boot="y"
			;;
		# Android 12+ (GKI 2.0+) recovery-as-boot
		bootconfig)
			if grep -q 'androidboot.force_normal_boot = "1"' /proc/bootconfig; then
				normal_boot="y"
			fi
			;;
		esac
	done

	if echo "$android_bootmode" | grep charger; then
		BOOT_MODE="android"
	fi

	# System-as-root or a device without dedicated recovery partition
	if [ -f /ramdisk-recovery.img ] && [ -z "$normal_boot" ]; then
		BOOT_MODE="recovery"
	fi

	# On Android 8+ devices the 'android' boot mode is broken and should be avoided.
	# This behavior can be overridden with the cmdline flag 'halium_no_avoid_android_mode'
	# List of API levels and referred Android versions: https://source.android.com/setup/start/build-numbers
	if ! grep -wq halium_no_avoid_android_mode /proc/cmdline; then
		api_level=$(sed -n 's/^ro.build.version.sdk=//p' /android-system/build.prop) # e.g. 26 for Android 8.0
		[ -z "$api_level" ] && api_level=0
		tell_kmsg "Android system image API level is $api_level"
		if [ "$BOOT_MODE" = "android" ] && [ $api_level -ge 26 ]; then
			tell_kmsg "Android 8+ device detected! Rebooting to reset non-standard boot mode..."
			reboot -f
		fi
	fi

	tell_kmsg "boot mode: $BOOT_MODE"
}

identify_android_image() {
	# Checks for the provided Android image. If it's called system.img, it
	# should be mounted at Android's /system. If it's called android-rootfs.img,
	# it should be mounted at Android's /.
	# Sets $ANDROID_IMAGE_MODE to:
	#   * "rootfs" if the image should be mounted at '/android/'
	#   * "system" if the image should be mounted at '/android/system/'
	#   * "unknown" if neither is found

	SYSTEM_SEARCH_PATHS="/halium-system/var/lib/lxc/android/system.img"
	[ "${file_layout}" == "halium" ] && SYSTEM_SEARCH_PATHS="/tmpmnt/system.img ${SYSTEM_SEARCH_PATHS}"

	ROOTFS_SEARCH_PATHS="/halium-system/var/lib/lxc/android/android-rootfs.img"
	[ "${file_layout}" == "halium" ] && ROOTFS_SEARCH_PATHS="/tmpmnt/android-rootfs.img ${ROOTFS_SEARCH_PATHS}"

	for image in ${SYSTEM_SEARCH_PATHS}; do
		if [ -f "${image}" ]; then
			ANDROID_IMAGE_MODE="system"
			ANDROID_IMAGE="${image}"

			return
		fi
	done

	for image in ${ROOTFS_SEARCH_PATHS}; do
		if [ -f "${image}" ]; then
			ANDROID_IMAGE_MODE="rootfs"
			ANDROID_IMAGE="${image}"

			return
		fi
	done

	ANDROID_IMAGE_MODE="unknown"
}

mount_android_partitions() {
	fstab=$1
	mount_root=$2
	real_userdata=$3

	tell_kmsg "checking fstab $fstab for additional mount points"

	# On systems with A/B partition layout, current slot is provided via cmdline parameter.
	ab_slot_suffix=$(grep -o 'androidboot\.slot_suffix=..' /proc/cmdline |  cut -d "=" -f2)
	[ ! -z "$ab_slot_suffix" ] && tell_kmsg "A/B slot system detected! Slot suffix is $ab_slot_suffix"

	cat ${fstab} | while read line; do
		set -- $line

		# stop processing if we hit the "#endhalium" comment in the file
		echo $1 | egrep -q "^#endhalium" && break

		# Skip any unwanted entry
		echo $1 | egrep -q "^#" && continue
		([ -z "$1" ] || [ -z "$2" ] || [ -z "$3" ] || [ -z "$4" ]) && continue
		([ "$2" = "/system" ] || [ "$2" = "/data" ] || [ "$2" = "/" ]) && continue

		label=$(echo $1 | awk -F/ '{print $NF}')
		[ -z "$label" ] && continue

		tell_kmsg "checking mount label $label"

		# 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
			# On A/B systems not all of the partitions are duplicated, so we have to check with and without suffix
			if [ -e "/dev/disk/$dir/$label$ab_slot_suffix" ]; then
				path="/dev/disk/$dir/$label$ab_slot_suffix"
				break
			elif [ -e "/dev/disk/$dir/$label" ]; then
				path="/dev/disk/$dir/$label"
				break
			fi
		done

		[ ! -e "$path" ] && continue

		mkdir -p ${mount_root}/$2
		tell_kmsg "mounting $path as ${mount_root}/$2"
		mount $path ${mount_root}/$2 -t $3 -o $4
	done

	# Provide a bind mount from /cache to /userdata/cache on systems without a dedicated cache partition
	if [ ! -e ${mount_root}/cache ]; then
		if [ ! -d ${real_userdata}/cache ]; then
			mkdir ${real_userdata}/cache
		fi
		mkdir ${mount_root}/cache
		mount -o bind ${real_userdata}/cache ${mount_root}/cache
	fi

	# Create an appropriate symlink for vendor files
	if [ ! -e ${mount_root}/vendor ]; then
		ln -sf system/vendor ${mount_root}/vendor
	fi
}

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
		tell_kmsg "resized userdata filesystem to fill $path"
	fi
}

resize_lvm_if_needed() {
	# Like resize_userdata_if_needed, but for devices with the furios
	# LVM vg in userdata.
	#
	# Note: this is meant to be done as an online resize. Thus, the stamp
	# file is checked on the mounted rootfs partition.

	pv=${1}
	vg=${2}
	lv=${3}

	if [ ! -e "/halium-system/var/lib/halium/requires-lvm-resize" ]; then
		# Bye bye
		return
	fi

	part="/dev/${selected_vg}/${lv}"

	# Resize the underlying Physical Volume
	if ! lvm pvresize ${pv}; then
		tell_kmsg "Unable to resize PV ${pv}"
		return
	fi

	# Now resize the rootfs LV with all the free extents
	if ! lvm lvresize -l +100%FREE ${part}; then
		tell_kmsg "Unable to resize LV ${lv}"
		return
	fi

	# Finally resize the filesystem
	if [ "$(blkid ${part} -o value -s TYPE)" == "ext4" ]; then
		e2fsck -fy ${part}

		if ! resize2fs -f ${part}; then
			tell_kmsg "Unable to resize ext4 partition ${part}"
			return
		fi
	else
		tell_kmsg "Unsupported filesystem on ${part}"
	fi

	rm -f /halium-system/var/lib/halium/requires-lvm-resize
}

identify_file_layout() {
	# Determine if we have a Halium rootfs.img & system.img

	# $file_layout = "halium" means there is a separate rootfs.img and system.img on userdata
	#
	# = "partition" means the rootfs is located on the device's system partition
	# and will contain /var/lib/lxc/android/system.img
	#
	# = "subdir" means the rootfs is located in a folder on the device's userdata partition
	# and will contain /var/lib/lxc/android/system.img

	if [ -e /tmpmnt/rootfs.img ]; then
		imagefile=/tmpmnt/rootfs.img
		file_layout="halium"
	elif [ -e /tmpmnt/ubuntu.img ]; then
		imagefile=/tmpmnt/ubuntu.img
		file_layout="legacy"
	elif [ -d /tmpmnt/halium-rootfs ]; then
		imagefile=/tmpmnt/halium-rootfs
		file_layout="subdir"
	else
		file_layout="partition"
	fi

}

load_kernel_modules() {
	mkdir -p /lib/modules
	cd /lib/modules
	ln -sf /lib/modules "/lib/modules/$(uname -r)"

	files="/override/modules.load.recovery /override/modules.load /lib/modules/modules.load.recovery /lib/modules/modules.load"
	for file in $files; do
		if [ -f "$file" ]; then
			module_list="$file"
			break
		fi
	done

	if [ -n "$module_list" ]; then
	        tell_kmsg "Loading kernel modules from $module_list"

		cat $module_list | while read line; do
			set -- $line
			# Skip commented entries
			[ "$1" = "#" ] && continue
			tell_kmsg "Loading module $1"
			modprobe -a "$1"
		done
	fi

	cd -
}


unlock_encrypted_partition() {
	part="${1}"
	header="${2}"
	name="${3}"

	# FIXME: quit plymouth, it would be better to hide/reshow but we
	# can't when using the minui backend
	[ -e "/usr/bin/plymouth" ] && plymouth quit || true

	halium_hook setup_touchscreen

	tries="0"
	while [ "${1}" ]; do
		CRYPTTAB_TRIED="${tries}" unl0kr | crypted-helper --device "${part}" --header "${header}" --name "${name}" --rootmnt "${rootmnt}" --strip-newlines
		err="${?}"
		case "${err}" in
			2)
				# Wrong passphrase
				let tries=tries+1
				;;
			0)
				if [ ! -e /dev/mapper/${name} ]; then
					halium_panic "Root partition unlocked, but device has not been mapped"
				fi

				break
				;;
			*)
				# Unknown error
				halium_panic "Unknown error ${err} while unlocking root partition"
				break
				;;
		esac
	done

	halium_hook teardown_touchscreen

	[ ! -d "/run/plymouth" ] && mkdir -m 0755 /run/plymouth
	[ -e "/usr/sbin/plymouthd" ] && PLYMOUTH_FORCE_SCALE="1" /usr/sbin/plymouthd --mode=boot --attach-to-session --pid-file=/run/plymouth/pid --ignore-serial-consoles --kernel-command-line "splash plymouth.ignore-udev" || true
	[ -e "/usr/bin/plymouth" ] && PLYMOUTH_FORCE_SCALE="1" /usr/bin/plymouth --show-splash || true
}

run_furios_recovery() {
	# FIXME: quit plymouth, it would be better to hide/reshow but we
	# can't when using the minui backend
	[ -e "/usr/bin/plymouth" ] && plymouth quit || true

	halium_hook setup_touchscreen

	furios-recovery

	halium_hook teardown_touchscreen

	[ ! -d "/run/plymouth" ] && mkdir -m 0755 /run/plymouth
	[ -e "/usr/sbin/plymouthd" ] && PLYMOUTH_FORCE_SCALE="1" /usr/sbin/plymouthd --mode=boot --attach-to-session --pid-file=/run/plymouth/pid --ignore-serial-consoles --kernel-command-line "splash plymouth.ignore-udev" || true
	[ -e "/usr/bin/plymouth" ] && PLYMOUTH_FORCE_SCALE="1" /usr/bin/plymouth --show-splash || true
}

signal_root_move_done() {
	# Signal to crypted-helper that the root move has
	# been done so that it can chroot() into it

	# No need to do this if the system is already encrypted
	[ -e /run/crypted-helper.pid ] || return

	touch /run/halium-mounted
	count=0
	while [ -e /run/halium-mounted ] && [ ${count} -lt 20 ]; do
		sleep 1

		let count=count+1
	done
}

manage_bootman_partition() {
	commands_file="/furios-persist/bootman/commands"
	while IFS= read -r cmd; do
		# Skip empty lines
		[ -z "$cmd" ] && continue

		tell_kmsg "Executing: $cmd from bootman installation commands"
		eval "$cmd"

		if [ $? -ne 0 ]; then
			tell_kmsg "Failed to execute: $cmd from bootman installation commands"
		fi
	done < "$commands_file"

	# commands operation can be for adding or removing new partitions
	# don't touch partitions file if manage_bootman_partition is running to remove an installation
	if [ -f "/furios-persist/bootman/wip-partitions" ]; then
		echo $(cat /furios-persist/bootman/wip-partitions) >> /furios-persist/bootman/partitions
	fi

	rm -f /furios-persist/bootman/wip-partitions /furios-persist/bootman/commands

	# maybe not 100% neccesary but better safe than sorry
	lvm vgscan
}

run_bootman() {
	# FIXME: quit plymouth, it would be better to hide/reshow but we
	# can't when using the minui backend
	[ -e "/usr/bin/plymouth" ] && plymouth quit || true

	halium_hook setup_touchscreen

	# usually after selecting something bootman should reboot
	# if it doesn't then just try booting from the already selected syspart in mountroot
	bootman &> /dev/null
	if [ $? -ne 0 ]; then
		tell_kmsg "Bootman failed with exit status $?"
	fi

	halium_hook teardown_touchscreen
}

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

	# Put all of this script's output into /dev/kmsg
	exec &>/dev/kmsg

	load_kernel_modules
	tell_kmsg "Finished loading kernel modules"
	sleep 1

	# busybox mdev -s
	# udevadm trigger

	# 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

	if [ -f "/usr/bin/lvglcharger" ]; then
		if grep -q "androidboot.bootreason=usb" /proc/cmdline; then
			if [ -d "/sys/class/power_supply/charger" ]; then
				while [ ! -e "/sys/class/power_supply/charger/online" ]; do
					sleep 1
				done
				while [ "$(cat /sys/class/power_supply/charger/online)" -eq 0 ]; do
					sleep 1
				done
			fi

			lvglcharger
		fi
	fi

	# 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

	# On systems with A/B partition layout, current slot is provided via cmdline parameter.
	ab_slot_suffix=$(grep -o 'androidboot\.slot_suffix=..' /proc/cmdline |  cut -d "=" -f2)
	if [ -z "$path" ] && [ ! -z "$ab_slot_suffix" ] ; then
		tell_kmsg "Searching for A/B data partition on slot $ab_slot_suffix."

		for partname in $partlist; do
			part=$(find /dev -name "$partname$ab_slot_suffix" | tail -1)
			[ -z "$part" ] && continue
			path=$(readlink -f $part)
			[ -n "$path" ] && break
		done
	fi

	# 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
		halium_panic "Couldn't find data partition."
	fi

	# Check the cmdline for hints on the current requested mode
	BOOT_TO_RECOVERY="yes"
	for x in $(cat /proc/cmdline); do
		case ${x} in
		# Android 9 system-as-root
		skip_initramfs)
			BOOT_TO_RECOVERY="no"
			;;
		# Android 10+ recovery-as-boot
		androidboot.force_normal_boot=1)
			BOOT_TO_RECOVERY="no"
			;;
		# Android 12+ (GKI 2.0+) recovery-as-boot
		bootconfig)
			if grep -q 'androidboot.force_normal_boot = "1"' /proc/bootconfig; then
				BOOT_TO_RECOVERY="no"
			fi
		;;
		esac
	done

	# Determine whether we should boot to recovery
	if [ "${BOOT_TO_RECOVERY}" == "yes" ]; then
		run_furios_recovery
	fi

	# Prefer LVM mounts. If lvm.disable is specified then use the fallback rootfs image
	use_lvm="yes"
	if grep -q furios.lvm /proc/cmdline; then
		for x in $(cat /proc/cmdline); do
			case ${x} in
			furios.lvm.disable)
				use_lvm="no"
				;;
			furios.lvm.vg=*)
				search_vg=${x#*=}
				;;
			furios.lvm.root_lv=*)
				root_lv=${x#*=}
				;;
			furios.lvm.reserved_lv=*)
				reserved_lv=${x#*=}
				;;
			furios.lvm.persistent_lv=*)
				persistent_lv=${x#*=}
				;;
			esac
		done
	fi

	if [ "${use_lvm}" == "yes" ]; then
		# Set default search vgs and root_lv
		[ -z "${search_vg}" ] && search_vg="furios droidian"
		[ -z "${root_lv}" ] && root_lv="furios-rootfs droidian-rootfs"
		[ -z "${reserved_lv}" ] && reserved_lv="furios-reserved droidian-reserved"
		[ -z "${persistent_lv}" ] && persistent_lv="furios-persistent droidian-persistent"
		[ -z "${encrypted_name}" ] && encrypted_name="furios_encrypted droidian_encrypted"

		lvm vgscan
		for try in 1 2 3 4 5; do
			lvm vgscan --mknodes
			for vg in ${search_vg}; do
				# Try each possible root_lv option
				for r_lv in ${root_lv}; do
					if lvm vgchange -ay ${vg} && [ -e "/dev/${vg}/${r_lv}" ]; then
						tell_kmsg "Found LVM VG ${vg} with root LV ${r_lv}"
						selected_vg="${vg}"
						_syspart="/dev/${selected_vg}/${r_lv}"
						file_layout="partition"
						# Store the found root_lv for later use
						found_root_lv="${r_lv}"
						break 2
					fi
				done
			done
			[ -n "${_syspart}" ] && break
			sleep 2
		done

		# If _syspart is empty, LVM discovery failed. Let's continue normally
		if [ -z "${_syspart}" ]; then
			unset use_lvm
		else
			# Found a valid VG and root_lv, now check reserved_lv
			for res_lv in ${reserved_lv}; do
				if [ -e "/dev/${selected_vg}/${res_lv}" ]; then
					found_reserved_lv="${res_lv}"
					break
				fi
			done

			# Check persistent_lv
			for pers_lv in ${persistent_lv}; do
				if [ -e "/dev/${selected_vg}/${pers_lv}" ]; then
					found_persistent_lv="${pers_lv}"
					break
				fi
			done

			# Check if reserved LV is LUKS encrypted
			if [ -n "${found_reserved_lv}" ] && [ "$(blkid /dev/${selected_vg}/${found_reserved_lv} -o value -s TYPE)" == "crypto_LUKS" ]; then
				# LUKS header, we should unlock
				use_luks="yes"

				# Try each possible encrypted name
				for enc_name in ${encrypted_name}; do
					if [ -e "/dev/mapper/${enc_name}" ]; then
						unlocked_syspart_name="${enc_name}"
						tell_kmsg "Found existing encrypted volume ${unlocked_syspart_name}"
						break
					fi
				done

				# If no existing encrypted volume found, use first name in the list
				if [ -z "${unlocked_syspart_name}" ]; then
					unlocked_syspart_name=$(echo ${encrypted_name} | awk '{print $1}')
				fi

				unlock_encrypted_partition /dev/${selected_vg}/${found_root_lv} /dev/${selected_vg}/${found_reserved_lv} ${unlocked_syspart_name}
				_syspart="/dev/mapper/${unlocked_syspart_name}"
			fi
		fi
	fi

	if [ "${use_lvm}" != "yes" ]; then
		tell_kmsg "checking filesystem integrity for the userdata partition"
		# 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/e2fsck.out 2>&1
		fsck_end=$(date +%s)
		tell_kmsg "checking filesystem for userdata took (including e2fsck) $((fsck_end - fsck_start)) seconds"

		resize_userdata_if_needed ${path}

		tell_kmsg "mounting $path"

		# Mount the data partition to a temporary mount point
		# FIXME: data=journal used on ext4 as a workaround for bug 1387214
		[ `blkid $path -o value -s TYPE` = "ext4" ] && OPTIONS="data=journal,"
		mount -o discard,$OPTIONS $path /tmpmnt

		# Set $_syspart if it is specified as systempart= on the command line
		# If the .ignore_systempart flag is in the data partition, ignore
		if grep -q systempart= /proc/cmdline && [ ! -e /tmpmnt/.ignore_systempart ]; then
			for x in $(cat /proc/cmdline); do
				case ${x} in
				systempart=*)
					_syspart=${x#*=}
					;;
				esac
			done
		fi

		identify_file_layout
	fi

	FURIOS_PERSIST=""
	dt_compatible=$(sed 's/$/\n/' /sys/firmware/devicetree/base/compatible | head -n1)
	if [ -n "${dt_compatible}" ] && { [ "$dt_compatible" = "furilabs,flx1" ] || [ "$dt_compatible" = "furilabs,flx1s" ]; }; then
		FURIOS_PERSIST="/dev/disk/by-partlabel/vendor_boot_a"
	fi

	# bootman does not work with encrypted systems
	if [ "${use_lvm}" == "yes" ] && [ -z "${unlocked_syspart_name}" ] && [ -n "${FURIOS_PERSIST}" ] && [ -e "${FURIOS_PERSIST}" ] && [ -n "${selected_vg}" ]; then
		mkdir -p /furios-persist

		# if this doesn't mount we will catch it in the next branch so not the cleanest, but gets the job done
		filesystem=$(blkid -o value -s TYPE "${FURIOS_PERSIST}")
		if [ "${filesystem}" == "ext4" ]; then
			mount "${FURIOS_PERSIST}" /furios-persist
		fi

		if grep -q "/furios-persist" /proc/mounts; then
			if [ -f "/furios-persist/bootman/commands" ]; then
				manage_bootman_partition
			fi

			# if there is only one partition there is no point in boot manager starting up
			# there are 2x32mb partitions, these are persist and reserved. ignore these when we are getting a count
			lvm_partition_count=$(lvm lvs --noheadings --options lv_size | grep -v "32.00m" | wc -l)
			dev_partition_count=$(cat /furios-persist/bootman/partitions | grep "/dev" | wc -l)
			partition_count=$((lvm_partition_count + dev_partition_count))
			if [ ${partition_count} -gt 1 ]; then
				if [ ! -f "/furios-persist/bootman/next-boot" ]; then
					run_bootman

					if [ -f "/furios-persist/bootman/old-boot" ]; then
						chosen_part=$(cat /furios-persist/bootman/old-boot)
						if [ -n "${chosen_part}" ]; then
							case "${chosen_part}" in
							/*)
								_syspart="${chosen_part}"
								;;
							*)
								_syspart="/dev/${selected_vg}/${chosen_part}"
								;;
							esac
							tell_kmsg "Boot manager selected to boot the partition without reflashing ${chosen_part}"
						else
							tell_kmsg "Failed to get boot manager old boot, file is empty"
						fi
					else
						tell_kmsg "Failed to get boot manager old boot, file does not exist, falling back to furios-rootfs"
					fi
				else
					chosen_part=$(cat /furios-persist/bootman/next-boot)
					if [ -n "${chosen_part}" ]; then
						case "${chosen_part}" in
						/*)
							_syspart="${chosen_part}"
							;;
						*)
							_syspart="/dev/${selected_vg}/${chosen_part}"
							;;
						esac
						tell_kmsg "Boot manager selected to boot the partition ${chosen_part}"
					else
						tell_kmsg "Failed to get boot manager next boot, file is empty"
					fi
				fi
			fi

			# save current boot to use for comparison in bootman. instead of reflash and reboot every time,
			# bootman can check against old-boot and just continue current boot if users choice has not changed
			if [ -f "/furios-persist/bootman/next-boot" ]; then
				mv "/furios-persist/bootman/next-boot" "/furios-persist/bootman/old-boot"
			fi

			umount /furios-persist
		else
			tell_kmsg "Failed to mount furios-persist"
		fi
	fi

	# If both $imagefile and $_syspart are set, something is wrong. The strange
	# output from this could be a clue in that situation.
	tell_kmsg "rootfs is $imagefile $_syspart"

	# 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).

	mkdir -p /halium-system

	tell_kmsg "mounting system rootfs at /halium-system"
	if [ -n "$_syspart" ]; then
		mount -o rw $_syspart /halium-system

		[ "${use_lvm}" == "yes" ] && resize_lvm_if_needed "${path}" "${selected_vg}" "${found_root_lv}"
	elif [ -f "$imagefile" ]; then
		# Rootfs is an image file
		mount -o loop,rw $imagefile /halium-system
	elif [ -d "$imagefile" ]; then
		# Rootfs is a directory
		mount -o bind /tmpmnt/halium-rootfs /halium-system
	fi

	# Identify image mode: either "rootfs" or "system"
	mkdir -p /android-rootfs
	mkdir -p /android-system

	identify_android_image
	[ $ANDROID_IMAGE_MODE = "unknown" ] && tell_kmsg "WARNING: Android system image not found."

	tell_kmsg "mounting $_syspart $imagefile"

	# Mount the android system partition to a temporary location
	MOUNT="ro"
	MOUNT_LOCATION="/android-$ANDROID_IMAGE_MODE"
	[ -e /tmpmnt/.writable_device_image -o -e /halium-system/.writable_device_image ] && MOUNT="rw"
	tell_kmsg "mounting android system image ($ANDROID_IMAGE) $MOUNT, in $MOUNT_LOCATION ($ANDROID_IMAGE_MODE mode)"
	if [ -n "${ANDROID_IMAGE}" ]; then
		mount -o loop,$MOUNT "$ANDROID_IMAGE" $MOUNT_LOCATION \
			|| tell_kmsg "WARNING: Failed to mount Android system.img."
	else
		tell_kmsg "WARNING: Unable to mount Android system image as it hasn't been found."
	fi

	[ $ANDROID_IMAGE_MODE = "rootfs" ] && mount -o bind $MOUNT_LOCATION/system /android-system

	identify_boot_mode

	if [ "$BOOT_MODE" = "recovery" ]; then
		tell_kmsg "Recovery boot mode for system-as-root devices"

		# Clean up mounted partitions so recovery can manage them
		umount -d /android-system /android-rootfs /halium-system /tmpmnt
		dmsetup remove_all

		mount -n -t tmpfs tmpfs ${rootmnt}
		cd ${rootmnt}
		if [ -d /lib/modules ]; then
			mkdir -p lib/modules
			mv /lib/modules/* lib/modules/
		fi
		cat /ramdisk-recovery.img | gzip -d | cpio -i
		cd -
		mkdir -p ${rootmnt}/sbin
		ln -s ../init ${rootmnt}/sbin/init
	elif ([ -e $imagefile ] || [ -n "$_syspart" ]) && [ "$BOOT_MODE" = "android" ]; then
		# Bootloader says this is factory or charger mode, boot into Android.
		tell_kmsg "Android boot mode for factory or charger mode"

		mount --move /android-rootfs ${rootmnt}
		[ $ANDROID_IMAGE_MODE = "system" ] && mount --move /android-system ${rootmnt}/system

		[ "${use_luks}" == "yes" ] && signal_root_move_done

		# Mount all the Android partitions
		mount_android_partitions "${rootmnt}/fstab*" ${rootmnt} /tmpmnt

		mkdir -p ${rootmnt}/halium-system
		mount --move /halium-system ${rootmnt}/halium-system

		# Mounting userdata
		mkdir -p ${rootmnt}/data
		mkdir -p /tmpmnt/android-data
		mount -o bind /tmpmnt/android-data ${rootmnt}/data

		# Make sure we're booting into android's init
		ln -s ../init ${rootmnt}/sbin/init
		ln -s ../init ${rootmnt}/sbin/recovery
		tell_kmsg "booting android..."
	elif [ -e $imagefile ] || [ -n "$_syspart" ]; then
		# Regular image boot
		tell_kmsg "Normal boot"

		mount --move /halium-system ${rootmnt}
		mkdir -p ${rootmnt}/android

		[ "${use_luks}" == "yes" ] && signal_root_move_done

		# Mounting userdata outside of /android, to avoid having LXC container access it
		mkdir -p ${rootmnt}/userdata
		[ "${use_lvm}" != "yes" ] && mount --move /tmpmnt ${rootmnt}/userdata

		mount --move /android-rootfs ${rootmnt}/var/lib/lxc/android/rootfs
		[ $ANDROID_IMAGE_MODE = "system" ] && mount -o rw,size=4096 -t tmpfs none ${rootmnt}/android
		[ $ANDROID_IMAGE_MODE = "rootfs" ] && mount -o bind ${rootmnt}/var/lib/lxc/android/rootfs ${rootmnt}/android

		mkdir -p ${rootmnt}/android/data ${rootmnt}/android/system

		# Create a fake android data, shared by rootfs and LXC container
		mkdir -p ${rootmnt}/userdata/android-data
		mount -o bind ${rootmnt}/userdata/android-data ${rootmnt}/android/data
		[ ! -h ${rootmnt}/data ] && ln -sf /android/data ${rootmnt}/data

		# Mount all the Android partitions
		mount_android_partitions "${rootmnt}/var/lib/lxc/android/rootfs/fstab*" ${rootmnt}/android ${rootmnt}/userdata

		# system is a special case
		tell_kmsg "moving Android system to /android/system"
		mount --move /android-system ${rootmnt}/android/system

		# 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
	else
		# Possibly a re-partitioned device
		halium_panic "Couldn't find a system partition."
	fi

	[ "$quiet" != "y" ] && log_begin_msg "Running /scripts/local-bottom"
	run_scripts /scripts/local-bottom
	[ "$quiet" != "y" ] && log_end_msg
}
