#!/bin/bash
### BEGIN INIT INFO
# Provides:            mountfs mountvirtfs $local_fs
# Required-Start:      fstab
# Should-Start:
# Required-Stop:
# Should-Stop:
# Default-Start:       3 4 5
# Default-Stop:
# Short-Description:   Mounts file systems.
# Description:         Mounts file systems.
# X-LFS-Provided-By:   LFS
### END INIT INFO

. /.initrd/initenv
. /etc/init.d/template

InitDevFs()
{
	while read -r n t i j; do
		[ -e "/dev/$n" ] || mknod "/dev/$n" "$t" "$i" "$j"
	done <<-EOF
	ram     b 1 1
	null    c 1 3
	zero    c 1 5
	full    c 1 7
	random  c 1 8
	kmsg    c 1 11
	systty  c 4 0
	tty0    c 4 0
	tty1    c 4 1
	tty     c 5 0
	console c 5 1
	ptmx    c 5 2
	EOF

	while read -r l t; do
		[ -e "/dev/$l" ] || ln -s "$t" "/dev/$l"
	done <<-EOF
	core   /proc/kcore
	fd     /proc/self/fd
	stdin  /proc/self/fd/0
	stdout /proc/self/fd/1
	stderr /proc/self/fd/2
	EOF
}

MountVirtualFs()
{
	InitDevFs

	for dir in /dev /run /sys /sys/firmware/efi/efivars; do
		[ ! -d "$dir" ] || ! dir=$(findmnt -nso TARGET "$dir") ||
			action "Mounting filesystem [$dir]:"  mount "$dir"
	done

	InitDevFs

	mkdir -p /run/lock/subsys /run/user /run/udev /run/systemd

	:> /run/utmp
	chmod 0664 /run/utmp

	touch "$LOCKFILE"
}

MoveFilesystems()
{
	local n
	for n in dev run ${EXPORT_FS-}; do
		[ ! -d "$rootmnt/$n" ] || ! mountpoint -q "/$n" ||
			action "Moving filesystem [/$n]:" mount --move "/$n" "$rootmnt/$n"
	done
}

UnmountFilesystems()
{
	local sig retry msg mnt points exclude

	exclude=("-e" "/" "-e" "/proc")
	[ -n "${UMOUNT_ROOTMNT-}" ] || exclude+=("-e" "$rootmnt(/.*)?")

	points=()
	readarray -t points < <(findmnt -klno TARGET | grep -Evx "${exclude[@]}" | sort -d)

	sig=15; msg=''

	for (( retry=3; retry > 0; retry-- )) do
		for (( i=$(( ${#points[@]} - 1 )); i >= 0; i-- )) do
			mnt="${points[$i]}"

			[ -n "$mnt" ] || continue

			action "Unmounting filesystem$msg [$mnt]:" umount -fl "$mnt"

			if mountpoint -q "$mnt"; then
				fuser -s -k -$sig "$mnt"
				continue
			fi
			unset "points[$i]"
		done

		[ "${#points[@]}" -gt 0 ] ||
			break

		sleep 0.5

		sig=9; msg=' (retry)'
	done
}

start()
{
	MountVirtualFs
	touch "$LOCKFILE"
}

stop()
{
	# Move some filesystems to real root.
	[ -n "${UMOUNT_ROOTMNT-}" ] || MoveFilesystems

	# Unmount file systems, killing processes if we have to.
	UnmountFilesystems

	rm -f "$LOCKFILE"
}

switch "${1-}"
