#!/bin2/sh
#
# $Id: init,v 1.56 2004/05/18 10:48:15 herbert Exp $

mount_device() {
	unset flags fstype
	set -f
	set +f $cmdline
	for i; do
		case "$i" in
		rootflags=*)
			flags=${i#rootflags=}
			;;
		rootfstype=*)
			fstype=${i#rootfstype=}
			;;
		esac
	done
	if [ -n "$fstype" ]; then
		mount -n${ro}t "$fstype" ${flags:+-o "$flags"} $device /mnt
		return
	fi
	IFS=,
	set -f
	set +f -- $FSTYPES auto
	unset IFS
	for i; do
		if
			mount -n${ro}t "$i" ${flags:+-o "$flags"} \
				$device /mnt > /dev/null 2>&1
		then
			break
		fi
	done
}

parse_numeric() {
	case $1 in
	*:*)
		minor=${1#*:}
		major=${1%:*}
		;;
	*)
		minor=$((0x${1#??}))
		major=$((0x${1%??}))
		;;
	esac
}

try_name() {
	[ -f /sys/block/$1/dev ] || return 1
	read dev < /sys/block/$1/dev
	parse_numeric $dev
	if ! [ $2 ]; then
		return
	fi

	[ -f /sys/block/$1/range ] || return 1
	read range < /sys/block/$1/range
	[ $2 -lt $range ] || return 1
	minor=$(($minor + $2))
}

get_sysfs_device() {
	local root
	root=$1

	if [ -b "$root" ]; then
		local o=-Lc
		if ! stat -L . > /dev/null 2>&1; then
			root=$(readlink -f "$root")
			o=-c
		fi
		eval "$(stat $o 'major=$((0x%t)); minor=$((0x%T))' "$root")"
		return
	fi

	case $root in
	/dev/*)
		;;
	*)
		parse_numeric $root
		return
		;;
	esac

	origroot="$root"

	for separator in ! .; do
		IFS=/
		set -f
		set +f ${origroot#/dev/}
		IFS="$separator"
		root=$*
		unset IFS
		try_name "$root" && return

		part=${root##*[!0-9]}
		root=${root%$part}
		if [ -z "$root" ]; then
			return
		fi
		try_name "$root" $part && return

		case $root in
		*[0-9]p)
			;;
		*)
			return 0
			;;
		esac
		try_name "${root%p}" $part && return
	done

	return 0
}

get_device() {
	major=$(($rootdev >> 8))
	minor=$(($rootdev & 255))
	if [ $rootdev -eq 0 ] || [ $major -eq 58 ] || [ $major -eq 254 ]; then
		get_sysfs_device "$ROOT" ||
			echo Failed to decode root device "$ROOT" >&2
	fi
	mknod dev2/root2 b $major $minor
	device=/dev2/root2
}

mount_root() {
	local sysfs=

	mount -nt proc proc proc
	mount_tmpfs dev2
	mount -nt devfs devfs devfs
	if mount -nt sysfs sysfs sys > /dev/null 2>&1; then
		sysfs=yes
	fi

	get_device
	mount_device

	if [ $sysfs ]; then
		umount -n sys
	fi
	umount -n devfs
	umount -n dev2
	umount -n proc
}

get_cmdline() {
	init=/sbin/init
	root=
	ide_options=
	ro=r
	noresume=
	resume=${RESUME}
	for i in $(cat proc/cmdline); do
		case $i in
		init=*)
			init=${i#init=}
			;;
		root=*)
			root=${i#root=}
			;;
		ide*=* | hd[!=]*=*)
			ide_options="$ide_options $i"
			;;
		ro)
			ro=r
			;;
		rw)
			ro=
			;;
		noresume | noresume=*)
			noresume=$i
			;;
		resume=*)
			resume=$i
			;;
		esac
	done

	ide_options=${ide_options# }

	CMDROOT=
	case $root in
	/dev/*)
		CMDROOT=$root
		;;
	esac
}

ide_module_to_driver() {
	ret=$1
	case $ret in
	aec62xx)
		ret='AEC62xx[ _]IDE'
		;;
	alim15x3)
		ret='ALI15x3[ _]IDE'
		;;
	amd74xx)
		ret='AMD[ _]IDE'
		;;
	atiixp)
		ret='ATIIXP[ _]IDE'
		;;
	cmd64x)
		ret='CMD64x[ _]IDE'
		;;
	cs5520)
		ret='CyrixIDE'
		;;
	cs5530)
		ret='CS5530[ _]IDE'
		;;
	cy82c693)
		ret='Cypress[ _]IDE'
		;;
	generic)
		ret='PCI[ _]IDE'
		;;
	hpt34x)
		ret='HPT34x[ _]IDE'
		;;
	hpt366)
		ret='HPT366[ _]IDE'
		;;
	it8172)
		ret='IT8172IDE'
		;;
	ns87415)
		ret='NS87415IDE'
		;;
	opti621)
		ret='Opti621[ _]IDE'
		;;
	pdc202xx_new)
		ret='Promise[ _]IDE'
		;;
	pdc202xx_old)
		ret='Promise[ _]Old[ _]IDE'
		;;
	piix)
		ret='PIIX[ _]IDE'
		;;
	rz1000)
		ret='RZ1000[ _]IDE'
		;;
	sc1200)
		ret='SC1200[ _]IDE'
		;;
	serverworks)
		ret='Serverworks[ _]IDE'
		;;
	siimage)
		ret='SiI[ _]IDE'
		;;
	sis5513)
		ret='SIS[ _]IDE'
		;;
	sl82c105)
		ret='W82C105[ _]IDE'
		;;
	slc90e66)
		ret='SLC90e66[ _]IDE'
		;;
	triflex)
		ret='TRIFLEX[ _]IDE'
		;;
	trm290)
		ret='TRM290[ _]IDE'
		;;
	via82cxxx)
		ret='VIA[ _]IDE'
		;;
	esac
}

unload_unused_ide() {
	oldstyle=$1
	shift

	if ! [ $oldstyle ]; then
		mount -nt sysfs sysfs sys
	fi

	for i; do
		if [ $oldstyle ]; then
			rmmod $i > /dev/null 2>&1
			continue
		fi

		ide_module_to_driver $i
		if [ -z "$ret" ]; then
			continue
		fi

		IFS=''
		set -- /sys/bus/pci/drivers/$ret/*:*
		unset IFS
		if [ ! -h "$1" ]; then
			rmmod $i > /dev/null 2>&1
		fi
	done

	if ! [ $oldstyle ]; then
		umount -n sys
	fi
}

do_swsusp() {
	local device major minor sysfs=
	local resume="$resume"

	if mount -nt sysfs sysfs sys > /dev/null 2>&1; then
		sysfs=yes
	fi

	if [ -n "$resume" ]; then
		device=${resume#*=}
		if get_sysfs_device "$device"; then
			if [ -f /sys/power/resume ]; then
				echo -n "$major:$minor" >/sys/power/resume
			fi
		else
			echo Failed to decode swap device "$device" >&2
		fi
	fi

	if [ $sysfs ]; then
		umount -n sys
	fi
}

mount_tmpfs() {
	mount -nt tmpfs tmpfs "$1" > /dev/null 2>&1 ||
		mount -nt ramfs ramfs "$1"
}

call() {
	. "$@"
}

export PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/bin2

. /linuxrc.conf

echo "initrd-tools: $VERSION"

if [ $BUSYBOX ]; then
	umount() {
		if [ "$1" = -n ]; then
			shift
		fi
		command umount "$@"
	}
fi

read root < bin/root
umount -n bin
echo $root > proc/sys/kernel/real-root-dev

get_cmdline

[ -c /dev/.devfsd ] && DEVFS=yes

mount -nt devfs devfs devfs
if [ $IDE_CORE != none ] && [ -n "$ide_options" ]; then
	echo modprobe -k $IDE_CORE "options=\"$ide_options\""
	modprobe -k $IDE_CORE options="$ide_options"
fi
call /loadmodules
case `uname -m` in
	ppc) call /loadmodules.powerpc;
	;;
esac

if [ $DELAY -gt 0 ]; then
	echo "Waiting for $DELAY seconds, press ENTER to obtain a shell."

	trap "timeout=yes" USR1
	timeout=
	{ sleep $DELAY; kill -USR1 $$ 2> /dev/null; }&
	pid=$!
	read line
	trap "" USR1
	kill $pid
	wait

	[ $timeout ] || exec sh
fi

call /script
ROOT=${CMDROOT:-$ROOT}

if [ -n "$resume$noresume" ]; then
	do_swsusp
fi

umount -n devfs
umount -n proc

for i in /scripts/*; do
	[ -f "$i" ] || continue
	case "$i" in
	*.sh)
		(. $i)
		;;
	*)
		$i
		;;
	esac
done

cd /
mount -nt proc proc proc
rootdev=$(cat proc/sys/kernel/real-root-dev)
cmdline=$(cat /proc/cmdline)
umount -n proc
if [ $rootdev != 256 ]; then
	mount_root
	cd mnt
	[ $DEVFS ] && mount -nt devfs devfs dev
	pivot_root . initrd
fi
if ! [ -x ${init#/} ]; then
	init=/sbin/init
fi
if type chroot > /dev/null 2>&1; then
	exec chroot . $init "$@" < dev/console > dev/console 2>&1
fi
exec $init "$@" < dev/console > dev/console 2>&1
