#!/bin/sh

PATH=/sbin:/bin
export PATH

MkDir() {
	[ -d $1 ] || mkdir -m ${2:-0755} $1
}

MkDirs() {
	while [ -n "$1" ]; do
		MkDir $1
		shift
	done
}

MkCD() {
	[ -e /dev/$1 ] || mknod /dev/$1 c $2 $3
}

echo "Loading, please wait..."

MkDir /root 0700
MkDirs /dev /sys /proc /tmp
mkdir -p /var/lock
mount -t sysfs -o nodev,noexec,nosuid none /sys
mount -t proc -o nodev,noexec,nosuid none /proc

for t in devtmpfs tmpfs; do
	mount -t $t -o size=4M,mode=0755 udev /dev && break
done
MkCD console 5 1
MkCD null 1 3
MkDirs /dev/pts /dev/shm /dev/.initramfs /dev/.run /dev/.run/udev /dev/.run/udev/db /dev/.run/udev/queue
ln -sf .run/udev /dev/.udev

echo > /proc/sys/kernel/hotplug

BOOT=local

. /scripts/functions

run_scripts /conf/initramfs.conf

# Parse command line options
break=
init=/sbin/init
quiet=n
readonly=y
rootmnt=/root
debug=
cryptopts=${CRYPTOPTS}
panic=
MODULES=

for x in $(cat /proc/cmdline); do
	case $x in
	init=*)
		init=${x#init=}
		;;
	root=*)
		ROOT=${x#root=}
		;;
	rootflags=*)
		ROOTFLAGS="-o ${x#rootflags=}"
		;;
	rootfstype=*)
		ROOTFSTYPE="${x#rootfstype=}"
		;;
	rootsubdir=*)
		ROOTSUBDIR="${x#rootsubdir=}"
		;;
	rootdelay=*)
		ROOTDELAY="${x#rootdelay=}"
		;;
	cryptopts=*)
		cryptopts="${x#cryptopts=}"
		;;
	modules=*)
		MODULES="${MODULES:+$MODULES }${x#modules=}"
		;;
	nfsroot=*)
		[ -n "$NFSROOT" ] || NFSROOT="${x#nfsroot=}"
		;;
	nbd=*)
		NBD="${x#nbd=}"
		;;
	netif=*)
		NETIF="${x#netif=}"
		;;
	BOOTIF=*)
		BOOTMAC="${x#BOOTIF=}"
		;;
	ip=*)
		[ -n "$IPOPTS" ] || IPOPTS="${x#ip=}"
		;;
	boot=*)
		BOOT=${x#boot=}
		;;
	resume=*)
		RESUME="${x#resume=}"
		;;
	noresume)
		NORESUME=y
		;;
	resume2=*)
		RESUME2="${x#resume2=}"
		;;
	noresume2)
		NORESUME2=y
		;;
	panic=*)
		panic="${x#panic=}"
		;;
	quiet)
		quiet=y
		;;
	ro)
		readonly=y
		;;
	rw)
		readonly=n
		;;
	debug)
		debug=y
		exec >/tmp/initramfs.debug 2>&1
		set -x
		;;
	debug=*)
		debug=y
		set -x
		;;
	break=*)
		break=${x#break=}
		;;
	break)
		break=premount
		;;
	*.*=*)
		module=${x%.*}
		param=${x#*.}
		echo "option $module $(substchar $param "," " ")" >> /etc/modprobe.d/boot-options
		;;
	esac
done

[ -n "$NORESUME" ] || resume="$RESUME"
[ -n "$NORESUME2" ] || resume2="$RESUME2"

AddUdevRule() {
	case $2 in
		LABEL=*|UUID=*)
			cat >> /etc/udev/rules.d/99-initramfs.rules <<__RULE__
ENV{ID_FS_USAGE}=="filesystem|other", ENV{ID_FS_${2%=*}}=="${2#*=}", SYMLINK+="$1"
__RULE__
			;;
	esac
}

AddUdevRule root $ROOT
AddUdevRule resume $resume

maybe_break top

run_scripts /scripts/init-top

[ "$quiet" != "y" ] && log_begin_msg "Starting udevd"
udevd --daemon
udevadm trigger --attr-match dev
udevadm settle || true
[ "$quiet" != "y" ] && log_end_msg

maybe_break modules
log_begin_msg "Loading essential drivers"
load_modules
log_end_msg

maybe_break premount

[ "$quiet" != "y" ] && log_begin_msg "Finishing udevd initialization"
udevadm trigger
udevadm settle || true
[ "$quiet" != "y" ] && log_end_msg

[ "$ROOT" != "/dev/nfs" ] && ROOT="$(GetDevPath root "$ROOT")" || BOOT=nfs
resume="$(GetDevPath resume "$resume")"

run_scripts /scripts/init-premount

maybe_break mount
log_begin_msg "Mounting root file system"
. /scripts/${BOOT}
parse_numeric ${ROOT}
mountroot
log_end_msg

maybe_break bottom

[ "$quiet" != "y" ] && log_begin_msg "Stopping udevd"

# Stop udevd, we'll miss a few events while we run init, but we catch up
udevadm settle
[ -s /dev/.udev/udevd.pid ] && kill $(cat /dev/.udev/udevd.pid)
cd /proc
for p in [1-9]*; do
	[ -x $p/exe ] && kill $p
done
cd - >/dev/null

# ignore any failed event because the init script will trigger again all events
nuke /dev/.udev/queue/

Src() {
	if [ -e "$1" ]; then
		. "$1"
		return 0
	fi
	return 1
}

# Read udev config from the real filesystem if possible
Src $rootmnt/etc/udev/udev.conf || Src /etc/udev/udev.conf

# Move /dev created in initramfs to the real filesystem if this is enabled
# in the udev configuration.
if [ "$use_initramfs_dev" = 1 ]; then

	# Pass udev version from initramfs to the real system.
	udev_version="$(/sbin/udevd --version 2>/dev/null)"
	echo "${udev_version:-105}" > /dev/.initramfs/udev_version

	# Optionally move the real filesystem's /dev to beneath our tmpfs
	if [ -z "$no_static_dev" ]; then
		mkdir -m 0700 /dev/.static
		mkdir /dev/.static/dev
		mount -o bind $rootmnt/dev /dev/.static/dev
	fi

	# Now move it all to the real filesystem
	mount -o move /dev $rootmnt/dev

	# create a temporary symlink to the final /dev for other initramfs
	# scripts
	nuke /dev
	ln -s $rootmnt/dev /dev
fi

[ "$quiet" != "y" ] && log_end_msg

run_scripts /scripts/init-bottom

while [ ! -x ${rootmnt}${init} ]; do
	panic "Target filesystem doesn't have ${init}"
done

umount /sys
umount /proc

# Chain to real filesystem
maybe_break init
# If /dev was not moved to the real filesystem, unmount it
exec </dev/console >/dev/console 2>&1
[ "$use_initramfs_dev" = 1 ] || umount -l /dev
exec run-init ${rootmnt} ${init} "$@"
