#!/bin/sh

rescue()
{
	printf "This is the PID 1 rescue shell.\n"
	printf "Manually \\e[94m/bin/mount\\e[0m a new rootfs and exec \\e[94m/sbin/switch_root\\e[0m to it.\n"
	printf "OR exec \\e[94m/sbin/init\\e[0m to start \\e[94m/etc/inittab\\e[0m to reboot or poweroff.\n"

	# Set flag which indicates that we have obtained controlling terminal.
	export PID1_SHELL=true

	# Interactive shell with controlling tty as PID 1.
	exec setsid cttyhack sh
}

no_root()
{
	printf "The device \\e[94m%s\\e[0m supposed to contain the root FS not found.\n" 
	printf "Please fix this fatal problem and exit this shell.\n\n"
}

no_mount()
{
	printf "Could not mount device \\e[94m%s\\e[0m. This shouldn't happen.\n" 
	printf "Please fix this fatal problem and exit this shell.\n\n"
}

check_root()
{
	mkdir -pv /.root

	case "$root" in
		/dev/* ) device=$root ;;
#		UUID=* ) eval $root; device="/dev/disk/by-uuid/$UUID"          ;;
		UUID=* ) eval $root; device="$(blkid --uuid ${UUID})"   ;;
#		LABEL=*) eval $root; device="/dev/disk/by-label/$LABEL"        ;;
		LABEL=*) eval $root; device="$(blkid --label ${LABEL})" ;;
		PARTUUID=* ) eval $root; device="$(blkid | grep PARTUUID=\"${PARTUUID}\"  | cut -d':' -f1)"  ;;
		""     ) echo -e "No root device specified." ; rescue             ;;
	esac
	echo -e "New root device: \\e[94m$device\\e[0m"

	while [ ! -b "$device" ] ; do
		no_root $device
		rescue
	done

	[ -n "$rootfstype" ] || rootfstype=$(blkid -o value -s TYPE $device)
	echo -e "New root file system type: \\e[94m$rootfstype\\e[0m"

	[ -n "$rootflags" ] && rootflags="$rootflags,"
	rootflags="$rootflags$ro"

	# Autocheck for encryption, if the device is a mapper device, assume encryption.
	# Note, this is not true on LVM devices!
	if [[ "$root" == /dev/mapper/* ]]; then
		ENCRYPT='yes'
	fi

	# Kernel parameters are in the form of: APPEND root=/dev/mapper/root cryptdevice=/dev/sda2:root ro
	cryptstring=$cryptdevice
	cryptdevice=${cryptstring%:*}
	target=${cryptstring#*:}
}

mount_root()
{
	if [ "$ENCRYPT" == 'yes' ]; then
		# Check if cryptsetup exists and is executable
		if [ -x /sbin/cryptsetup ] ; then
			while ! eval cryptsetup open $cryptdevice $target; do
				sleep 1;
			done
		else
			echo -e "Warning cannot find cryptsetup"
			sleep 1
		fi
	fi

	echo mount -t "$rootfstype" -o "$rootflags" "$device" "/.root"
	if ! mount -t "$rootfstype" -o "$rootflags" "$device" "/.root" ; then
		no_mount $1
		rescue
	else
		echo -e "Successfully mounted device $root"
	fi
}

echo -e "PKGLINUX \\e[94minitramfs\\e[0m has started (SHELL @ PID 1) ..."

mkdir -pv /dev /proc /tmp /sys /run /var/log

mount -n -t devtmpfs devtmpfs /dev
mount -n -t proc     proc     /proc
mount -n -t sysfs    sysfs    /sys
mount -n -t tmpfs    tmpfs    /run
mount -n -t tmpfs    tmpfs    /tmp

#echo -e "Detecting and exporting hardware infomation ..."
#mdev -s
#echo /sbin/mdev > /proc/sys/kernel/hotplug
#find /sys/ -name modalias | xargs sort -u | xargs -n 1 /sbin/modprobe 2> /dev/null

# This is needed since eudev (around version 3.0) because it no longer creates static devices nodes, like /dev/fuse and /dev/net/tun
echo -e "Creating static device nodes ..."
/bin/kmod static-nodes --format=tmpfiles | \
while read type name mode uid gid age arg; do
  [ -e $name ] && continue
  case "$type" in
    c|b|c!|b!) mknod -m $mode $name $type $(echo $arg | sed 's/:/ /') ;;
    d|d!) mkdir $name ;;
    *) echo -e "unparseable line ($type $name $mode $uid $gid $age $arg)" >&2 ;;
  esac
done

#echo -e "echo /sbin/mdev > /proc/sys/kernel/hotplug"
#echo /sbin/mdev > /proc/sys/kernel/hotplug
#echo -e "/sbin/mdev -s"
#/sbin/mdev -s

# Detect and export hardware infomation
echo -e "Starting \\e[94mudevd\\e[0m as a daemon ..."
udevd --daemon --resolve-names=never
# Enable trigger event to autoload modules for devices
echo -e "Triggering with udevadm ..."
udevadm trigger --action=add --type=subsystems
udevadm trigger --action=add --type=devices
echo -e "Settling with udevadm ..."
udevadm settle

# Load the dm-crypt module, if it is a module but don't show an error message when it doesn't exit (-q)
modprobe -q dm-crypt

init=/sbin/init
root=
cryptdevice=
rootdelay=
#rootfstype=auto
rootfstype=
ro="ro"
rootflags=
device=
single=
sfs=""
net=""
prefix=""

read -r cmdline < /proc/cmdline

for param in $cmdline ; do
	case $param in
		init=*        ) init=${param#init=}               ;;
		root=*        ) root=${param#root=}               ;;
		cryptdevice=* ) cryptdevice=${param#cryptdevice=} ;;
		rootdelay=*   ) rootdelay=${param#rootdelay=}     ;;
		rootfstype=*  ) rootfstype=${param#rootfstype=}   ;;
		rootflags=*   ) rootflags=${param#rootflags=}     ;;
		sfs=*         ) sfs=${param#sfs=}                 ;;
		prefix=*      ) prefix=${param#prefix=}           ;;
		ro            ) ro="ro"                           ;;
		rw            ) ro="rw"                           ;;
		single        ) single="single"                   ;;
		net           ) net="net"                         ;;
	esac
done

[ -n "$rootdelay" ] && sleep "$rootdelay"
echo -e "Checking the root device ..."
check_root

[ -n "$rootdelay" ] && sleep "$rootdelay"
if [ -n "$sfs" ]; then
	dev_mnt=/.tmp/dev_mnt
	mkdir -p $dev_mnt
	dev_fst=$(blkid -o value -s TYPE $device)
	echo -e "Trying to mount device $device with file system type: $dev_fst"
	if mount -t $dev_fst $device $dev_mnt 2>/dev/null; then
		echo -e "Mounted device $device with file system type: $dev_fst"
		[ -n "$prefix" -a -d "$dev_mnt/$prefix" ] && prefix_fail=false || prefix_fail=true
		for prefix_dir in \
			"$dev_mnt/pkg" \
			"$dev_mnt/bin" \
			"$dev_mnt/etc" \
			"$dev_mnt/lib" \
			"$dev_mnt/lib32" \
			"$dev_mnt/lib64" \
			"$dev_mnt/sbin" \
			"$dev_mnt/usr" \
			"$dev_mnt/usr/bin" \
			"$dev_mnt/usr/lib" \
			"$dev_mnt/usr/lib32" \
			"$dev_mnt/usr/sbin" 
		do
			if $prefix_fail; then
				break
			fi	
			if ! [ -d "$prefix_dir" ]; then
				prefix_fail=true
			fi
		done
		if $prefix_fail; then
			echo -e "Checking $dev_mnt/$sfs/pkglinux.sfs"
			if [ -d $dev_mnt/$sfs -a -f $dev_mnt/$sfs/pkglinux.sfs ] ; then
				umount $dev_mnt 2>/dev/null
				rm -rf $dev_mnt 2>/dev/null
				exec /etc/init.sfs $device $sfs
			fi
			echo -e "$dev_mnt/$sfs/pkglinux.sfs not found. Try $dev_mnt/$prefix."
		else
			echo -e "$dev_mnt/$prefix OK to boot. Forget $dev_mnt/$sfs/pkglinux.sfs."
		fi
		umount $dev_mnt 2>/dev/null
	fi
	rm -rf $dev_mnt 2>/dev/null
fi

[ "$single" = "single" ] && rescue

if [ -n "$net" ]; then
	modprobe e1000 2>/dev/null
	modprobe igb 2>/dev/null
	modprobe ixgbe 2>/dev/null
	/etc/autorun/dhcp.sh
	echo "Starting telnetd..."
	#telnetd -F -l /bin/sh -p 2323
	nc -ll -p 2323 -e /bin/sh
fi

echo -e "Mounting the root ..."
mount_root

echo -e "Binding to the root ..."
mount -v --bind /dev  /.root/dev
mount -v --bind /proc /.root/proc
mount -v --bind /sys  /.root/sys
mount -v --bind /run  /.root/run
mount -v --bind /tmp  /.root/tmp

echo -e "Switching to the root ..."

[ ! -h "/.root/bin/"    ] && [ -d "/.root/bin/"    ] && mount --rbind "/.root/pkg/native/bin"    "/.root/bin"
[ ! -h "/.root/etc/"    ] && [ -d "/.root/etc/"    ] && mount --rbind "/.root/pkg/native/etc"    "/.root/etc"
[ ! -h "/.root/lib/"    ] && [ -d "/.root/lib/"    ] && mount --rbind "/.root/pkg/native/lib"    "/.root/lib"
[ ! -h "/.root/lib32/"  ] && [ -d "/.root/lib32/"  ] && mount --rbind "/.root/pkg/native/lib32"  "/.root/lib32"
[ ! -h "/.root/lib64/"  ] && [ -d "/.root/lib64/"  ] && mount --rbind "/.root/pkg/native/lib64"  "/.root/lib64"
[ ! -h "/.root/libx32/" ] && [ -d "/.root/libx32/" ] && mount --rbind "/.root/pkg/native/libx32" "/.root/libx32"
[ ! -h "/.root/sbin/"   ] && [ -d "/.root/sbin/"   ] && mount --rbind "/.root/pkg/native/sbin"   "/.root/sbin"
[ ! -h "/.root/usr/"    ] && [ -d "/.root/usr/"    ] && mount --rbind "/.root/pkg/native/usr"    "/.root/usr"

# Wait 2 second or until any keybord key is pressed.
#read -t 2 -n1 -s key

killall -w udevd
#udevadm control --exit
if [ -n "" ]; then
	echo "Restarting telnetd..."
	#killall -w telnetd
	killall -w nc
	echo "Starting telnetd..."
	#cd /.root && telnetd -l /bin/sh -p 2323
	cd /.root && nc -l -p 2323 -e /bin/sh
fi

exec switch_root /.root "$init" "$@"

echo -e "/init has a serious bug."

# Wait until any key has been pressed.
read -n1 -s
