#! /bin/bash
#
# udev	init script to setup /udev
#
# description: manage user-space device nodes in /udev

. /etc/rc.d/init.d/functions

. /etc/udev/udev.conf
# strip trailling slash:
udev_root=${udev_root%/}
udev_root2=${udev_root}.old

UDEVSTART=/sbin/udevstart
prog=udev
sysfs_dir=/sys
bin=/sbin/udev
hotplug=/sbin/udevsend
# default maximum size of the /dev tmpfs
tmpfs_size="10M"

case "$(uname -r)" in
  2.[012345].*)
    gprintf "udev requires a 2.6.x kernel, not started.\n"
    exit 1
    ;;
esac
# don't use udev if devfs is in use.
if [ -e $udev_root/.devfsd ]; then
    gprintf "devfsd used instead of udev!!!\n"
    exit 1
fi

run_udev () {
	# handle block devices and their partitions
	for i in ${sysfs_dir}/block/*; do
		# add each drive
		export DEVPATH=${i#${sysfs_dir}}
		$bin block

		# add each partition, on each device
		for j in $i/*; do
			if [ -f $j/dev ]; then
				export DEVPATH=${j#${sysfs_dir}}
				$bin block
			fi
		done
	done
	# all other device classes
	for i in ${sysfs_dir}/class/*; do
		for j in $i/*; do
			if [ -f $j/dev ]; then
				export DEVPATH=${j#${sysfs_dir}}
				CLASS=`echo ${i#${sysfs_dir}} | \
					cut --delimiter='/' --fields=3-`
				$bin $CLASS
			fi
		done
	done
	return 0
}


# we need to unmount /dev/pts/ and remount it later over the tmpfs
unmount_devpts() {
  if grep -q $1/pts /proc/mounts; then
    umount -l $1/pts/
  fi

  if grep -q $1/shm /proc/mounts; then
    umount -l $1/shm/
  fi
}

# mount a tmpfs over /dev, if somebody did not already do it
mount_tmpfs() {
  if ! grep -E -q "^[^[:space:]]+ $udev_root tmpfs" /proc/mounts; then
      unmount_devpts $udev_root
      mount -n -o size=$tmpfs_size,mode=0755 -t tmpfs none $udev_root
  fi
  make_extra_nodes
  if ! grep -q $udev_root/pts /proc/mounts; then
      mount -n -t devpts -o mode=620 none $udev_root/pts
  fi
  if ! grep -q $udev_root/shm /proc/mounts; then
      mount -n -t tmpfs  none $udev_root/shm
  fi
}

make_node () {
    dev="$1"
    type="$2"
    major="$3"
    minor="$4"
    
    if [ "$type" = c -a ! -c "$dev" -o "$type" = b -a ! -b "$dev" ]; then
	rm -f "$dev"
	mknod "$dev" "$type" "$major" "$minor"
    fi
}

make_extra_nodes () {
	# there are a few things that sysfs does not export for us.
	# these things are listed in /etc/udev/links.conf
	 grep '^[^#]' /etc/udev/links.conf | \
	 while read type name arg1; do
	   [ "$type" -a "$name" -a ! -e "$udev_root/$name" -a ! -L "/dev/$name" ] ||continue
	   case "$type" in
	     L) ln -s $arg1 $udev_root/$name ;;
	     D) mkdir -p $udev_root/$name ;;
	     M) mknod --mode=600 $udev_root/$name $arg1 ;;
	     *) gprintf "links.conf: unparseable line (%s %s %s)\n" "$type" "$name" "$arg1" ;;
	   esac
	 done
}

# When modifying this script, do not forget that between the time that
# the new /dev has been mounted and udevstart has been run there will be
# no /dev/null. This also means that you cannot use the "&" shell command.

##############################################################################
case "$1" in
  start)
	[ "`runlevel`" != "unknown" -a -f /var/lock/subsys/udev ] && exit 0
	[[ -d /var/lock/subsys/ ]] && touch /var/lock/subsys/udev 2> /dev/null
	fgrep -q '/dev ' /proc/mounts && [[ -e /$udev_root/.started ]] && exit 0
	# don't use udev if sysfs is not mounted.
	if [ ! -d $sysfs_dir/block ]; then
		echo not starting because /sys is not mounted
		exit 1
	fi
	if [ ! -d $udev_root ]; then
		mkdir $udev_root
	fi

	# we'd better handle this in an udev event:
	[[ -e /sys/class/firmware/timeout ]] && echo 50 > /sys/class/firmware/timeout

	# Creating initial udev device nodes:
	mount_tmpfs

	# keep device mapper devices (lvm/dmraid) created in initrd
	if [ -d /initrd$udev_root ]; then
	    rm -rf /initrd$udev_root/shm
	    cp -a /initrd$udev_root/* $udev_root
	fi

	[ -d /initrd$udev_root ] && cp -a /initrd$udev_root/* $udev_root
	touch $udev_root/.started

	# Disable the usual hotplug multiplexer and let devd/udev to handle the
	# _whole_ hotplug event from the kernel up to the multiplexing of
	# /etc/hotplug.d/ :
	echo /sbin/udevsend > /proc/sys/kernel/hotplug
	udevd -d

	# propagate /udev from /sys - we only need this while we do not
	# have initramfs and an early user-space with which to do early
	# device bring up (aka coldplug)
	export ACTION=add
	$UDEVSTART
	/sbin/udev_input_coldplug start
	action "Start %s\n" udev /bin/true
	for i in /etc/udev/conf.d/*; do [[ "$i" = ${i%\~} ]] && [[ -x $i ]] && $i; done
	pam_console_apply
	;;
  stop)
	rm -f /var/lock/subsys/udev $udev_root/.started
  	exit 0
	;;
  force-stop)
	# Removing udev device nodes:
	export ACTION=remove
	#run_udev
	killall udevd
	[[ ! -d $udev_root2 ]] && mkdir $udev_root2
	mount --move $udev_root $udev_root2
	unmount_devpts $udev_root2
	# unmounting with -l should never fail
	action "Stopping %s" udev umount -l $udev_root2 2>/dev/null
	sysctl -n -w kernel.hotplug="/sbin/hotplug" >/dev/null 2>&1
	rmdir $udev_root2
	rm -f /var/lock/subsys/udev
	;;
  status)
	if [ -f /var/lock/subsys/udev ]; then
		action "%s is running\n" udev /bin/true
		exit 0
	fi
	action "%s is stopped\n" udev /bin/true
	exit 3
	;;
  restart)
	[[ -f /var/lock/subsys/udev ]] || exit 0
	[[ -e /dev/snd/controlC0 ]] && ACTION=remove DEVPATH=/class/sound/mixer /etc/dev.d/sound/alsa.dev
	$UDEVSTART
	pam_console_apply
	;;
  force-reload)
	$0 force-stop
	$0 start
	service syslog restart
	;;
  reload)
	$0 restart
	;;
  *)
  	gprintf "Usage: %s {start|stop|status|restart|force-reload|force-stop}\n" "$0"
	exit 1
esac

exit 0
