#!/bin/sh -e

PATH="/sbin:/bin"

UDEV=/sbin/udev

. /etc/udev/udev.conf

[ -x $UDEV ] || exit 0

case "$(uname -r)" in
  2.[012345].*)
    echo "udev requires a 2.6.x kernel, not started."
    exit 0
    ;;
esac

# FIXME - to be enabled after /proc mounting is moved to a different script
#if [ ! -e /proc/sys/kernel/hotplug ]; then
#    echo "udev requires hotplug support, not started."
#    exit 0
#fi

##############################################################################
# FIXME see README.Debian
mount_sysfs() {
  [ -d /sys ] || mkdir /sys
  [ -d /sys/class ] || mount -t sysfs sysfs: /sys
  [ -d /proc/1 ] || mount -n /proc
}

# FIXME see README.Debian
umount_proc() {
  umount -n /proc
}

mount_ramfs() {
  if grep -E -q "^[^[:space:]]+ /u?dev ramfs" /proc/mounts; then
    return 0
  fi

  [ -d /etc/udev/.dev ] && mount --bind $udev_root /etc/udev/.dev

  echo -n "Mounting ramfs over $udev_root..."
  mount -n -t ramfs none $udev_root
  echo "done."
}

# We must manually create /dev/null because the shell needs it for "&".
# If we were using initramfs the kernel would create it for us.
create_dev_null() {
  [ -c $udev_root/null ] || mknod --mode=666 $udev_root/null c 1 3
}

synthesize_events() {
  /sbin/udevstart
}

# this has been obsoleted by udevstart
old_synthesize_events() {
  export UDEV_NO_SLEEP=1
  export ACTION DEVPATH

  # add tty devices and all other device classes
  for i in /sys/class/*; do
    [ -d "$i" ] || continue
    for j in $i/*; do
      [ -f "$j/dev" ] || continue
      DEVPATH=${j#/sys}
      class=${DEVPATH#/class/}
      class=${class%/*}
#      echo -n " $DEVPATH($class)"
      $UDEV $class || echo -n " failed: $DEVPATH"
    done
  done
  # add block devices and their partitions
  for i in /sys/block/*; do
    [ -d "$i" ] || continue
    DEVPATH=${i#/sys}
#    echo -n " $DEVPATH"
    $UDEV block || echo -n " failed: $DEVPATH"
    for j in $i/*; do
      [ -f "$j/dev" ] || continue
      DEVPATH=${j#/sys}
#      echo -n " $DEVPATH"
      $UDEV block || echo -n " failed: $DEVPATH"
    done
  done

  return 0
}

make_extra_nodes () {
  grep '^[^#]' /etc/udev/links.conf | \
  while read type name arg1; do
    [ "$type" -a "$name" \
      -a ! -e "$udev_root/$name" -a ! -L "$udev_root/$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
      ;;
    *)
      echo "unparseable line ($type $name $arg1)"
      ;;
    esac
  done
}

##############################################################################
case "$1" in
  start)
    mount_sysfs
    mount_ramfs
    create_dev_null
    # We want to start udevd ourselves if it isn't already running.
    # This lets udevd run at a sane nice level...
    udevd &
    ACTION=add
    echo -n "Creating initial udev device nodes..."
    synthesize_events
    make_extra_nodes
    umount_proc
    echo "done."
    ;;
  remove)
    # I'm not sure this is useful
    ACTION=remove
    echo -n "Removing udev device nodes..."
    old_synthesize_events
    echo "done."
    ;;
  stop)
    start-stop-daemon --stop --exec /sbin/udevd --oknodo --quiet
    # this will usually not work because /dev will be busy
    echo -n "Unmounting $udev_root..."
    if umount $udev_root 2> /dev/null; then
      echo "done."
      umount /etc/udev/.dev || true
    else
      echo "failed."
    fi
    ;;
  restart|force-reload)
    echo -n "Creating again udev device nodes..."
    ACTION=add
    synthesize_events
    make_extra_nodes
    echo "done."
    ;;
  *)
    echo "Usage: /etc/init.d/udev {start|stop|restart|force-reload}"
    exit 1
    ;;
esac

exit 0

