#! /bin/sh
#
# udevd	init script to setup /dev
#
# chkconfig: 2345 02 95
# description: manage user-space device nodes in /dev
# processname: udevd
# pidfile: /var/run/udevd.pid
# config: /etc/udev/udev.conf

WITHOUT_RC_COMPAT=1

. /etc/init.d/functions

SourceIfNotEmpty /etc/udev/udev.conf

: ${udev_root:=/dev}
: ${udev_tmpfs:=1}

udev_root=${udev_root%/}

prog=udevd
sysfs_dir=/sys
bin=/sbin/udev
udevd=/sbin/udevd

LOCKFILE=/var/lock/subsys/udevd
PIDFILE=/var/run/udevd.pid
RETVAL=0

make_extra_nodes ()
{
	# there are a few things that sysfs does not export for us.
	# these things go here (and remember to remove them in 
	# remove_extra_nodes()
	#
	# Thanks to Gentoo for the initial list of these.
	ln -snf /proc/self/fd $udev_root/fd 2>&1 >/dev/null
	ln -snf /proc/self/fd/0 $udev_root/stdin 2>&1 >/dev/null
	ln -snf /proc/self/fd/1 $udev_root/stdout 2>&1 >/dev/null
	ln -snf /proc/self/fd/2 $udev_root/stderr 2>&1 >/dev/null
	ln -snf /proc/kcore $udev_root/core 2>&1 >/dev/null
	#ln -snf /proc/asound/oss/sndstat $udev_root/sndstat
	return 0
}

get_pts_attributes()
{
	local rc line opts
	line=`grep -F " $udev_root/pts " /etc/mtab 2>/dev/null | head -1`
	test -n "$line" || return 1
	set -- $line ''
	opts=$4
	echo $opts
	return 0
}

attach_pts_filesystem()
{
	test -f /proc/mounts || return 0
	local RETVAL opts rc
	opts="`get_pts_attributes`"
	rc=$?
	RETVAL=0
	if test $rc = 0; then
	    if grep -qF " $udev_root/pts " /proc/mounts; then
		mountcmd="mount --move pts $udev_root/pts"
	    else
		mountcmd="mount -t devpts devpts $udev_root/pts -o $opts"
	    fi
	    mkdir -p $udev_root/pts && $mountcmd
	    RETVAL=$?
	fi
	return $RETVAL
}

attach_shm_filesystem()
{
	test -f /proc/mounts || return 0
	local mountcmd
	if grep -qF " $udev_root/shm " /proc/mounts; then
		mountcmd="mount --move shm $udev_root/shm"
	else
		mountcmd="mount -t tmpfs shmfs $udev_root/shm"
	fi
	mkdir -p $udev_root/shm && $mountcmd
	return $?
}

create_static_inodes()
{
    local rv
    [ -d /etc/udev/devices -a -n "`ls -A /etc/udev/devices`" ] && \
	cp -a /etc/udev/devices/* "$udev_root/"
    # Also allow static devices cpio compressed archive. Single device inodes
    # inside /etc/udev/devices are good for just a few entries, but if one needs
    # a static dev replacement compatible w/ udev, we have to use some
    # sort of a compressed archive to save disk space inside /etc.
    if [ -f /etc/udev/static_devices.cpio.bz2 ]; then
	pushd "$udev_root" >/dev/null;
	rv=$?
	[ $rv -ne 0 ] && return $rv
	    bzip2 -cd /etc/udev/static_devices.cpio.bz2 | \
		cpio --extract --preserve-modification-time 2>/dev/null;
	popd >/dev/null
    fi
}


prepare_filesystem()
{
	local RETVAL mounted
	if [ ! -d $udev_root ]; then
	    mkdir -p $udev_root || return 1
	fi

	# remove the database if it is there as we always want to start fresh
	[ -d $udev_db ] && rm -rf $udev_db 2>/dev/null

	# Check if we should mount a tmpfs to $udev_root
	if [ "x$udev_tmpfs" != "x1" ]; then
	    /sbin/udevstart
	    RETVAL=$?
	    return $RETVAL
	fi

	cd "$udev_root"
	RETVAL=$?
	[ $RETVAL -ne 0 ] && return $RETVAL
	if ! grep -qF "udev $udev_root tmpfs" /proc/mounts; then
		mounted=0
		mount -t tmpfs udev $udev_root
		ACTION=add DEVPATH=/class/mem/null $bin mem/null;# && \
		attach_pts_filesystem && attach_shm_filesystem
		RETVAL=$?
	else
		ACTION=add DEVPATH=/class/mem/null $bin mem/null;# && \
		mounted=1
		RETVAL=0
	fi
	
	if [ $RETVAL = 0 ]; then
		create_static_inodes;
		/sbin/udevstart && make_extra_nodes
		mount -o remount,$tmpfs_options $udev_root
		RETVAL=$?
	fi

	[ $RETVAL != 0 -a $mounted = 0 ] && detach_filesystem
	return $RETVAL
}

detach_pts_filesystem()
{
	local opts
	opts="`get_pts_attributes`"
	if test $? = 0; then
		umount $udev_root/pts 2>/dev/null
		umount -l $udev_root/pts 2>/dev/null
	fi
	return 0
}

detach_filesystem()
{
	# Check if we had to mount a tmpfs to $udev_root
	[ "x$udev_tmpfs" = "x1" ] || return 0
	umount $udev_root/shm
	detach_pts_filesystem
	umount -l $udev_root
	attach_pts_filesystem
}

start()
{
	# don't use udev if sysfs is not mounted.
	[ ! -d $sysfs_dir/block ] && exit 1

	echo -n $"Preparing dev filesystem:"
	prepare_filesystem
	RETVAL=$?
	if [ $RETVAL = 0 ]; then
		echo_success
		echo
	else
		echo_failure
		echo
		return $RETVAL
	fi

	# if there's no pidfile yet then, probably, we're starting from scratch.
	# in this case we should make sure that hotplug didn't invoke an instance of udevd
	# before
	/sbin/pidof $udevd >/dev/null && stop_daemon --no-announce --pidfile none $udevd
		
	# We want to start udevd ourselves if it isn't already running.  This
	# lets udevd run at a sane nice level...
	start_daemon --lockfile "$LOCKFILE" --expect-user root --pidfile "$PIDFILE" --make-pidfile -- $udevd
	RETVAL=$?
	[ "$RETVAL" == "0" ] && echo "" >/proc/sys/kernel/hotplug
	return $RETVAL
}


stop()
{
  	# be careful
	# Maybe I'm deadly wrong...
	local do_fscleanup
	do_fscleanup=
	[ -f "$LOCKFILE" ] && do_fscleanup=1
	stop_daemon --pidfile "$PIDFILE" --lockfile "$LOCKFILE" $udevd
	RETVAL=$?
	echo "/sbin/hotplug" >/proc/sys/kernel/hotplug
	if [ -n "$do_fscleanup" ]; then
		echo -n $"Removing udev device nodes: "
		detach_filesystem
		echo_success
		echo
	fi
	return $RETVAL
}

restart()
{
    stop
    start
}

case "$1" in
  start)
  	start
	;;
  stop)
  	stop
	;;
  status)
	status --pidfile "$PIDFILE" -- $prog
	exit $?
	;;
  condrestart)
	;;
  condstop)
	msg=`status --pidfile "$PIDFILE" -- $prog`
	RETVAL=$?
	if [ $RETVAL -eq 0 ]; then
	    stop
	fi
	;;
  restart)
	restart
	;;

  reload)
  	# nothing to do here
	;;
  *)
  	echo "Usage: $0 {start|stop|status|restart|condrestart|condstop}"
	exit 1
esac

exit $RETVAL
