#!/bin/sh -e

PATH="/sbin:/bin"

UDEVSTART=/sbin/udevstart

# default size of the /dev tmpfs
tmpfs_size="1M"

[ -x $UDEVSTART ] || exit 0

. /etc/udev/udev.conf

[ -e /etc/default/devpts ] && . /etc/default/devpts

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

if [ ! -e /proc/sys/kernel/hotplug ]; then
    echo "udev requires hotplug support, not started."
    exit 0
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
    return 0
  fi

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

  echo -n "Mounting a tmpfs over $udev_root..."
  mount -n -o size=$tmpfs_size,mode=0755 -t tmpfs none $udev_root
  echo "done."
}

# I hate this hack.  -- Md
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
}

# we need to unmount /dev/pts/ and remount it later over the tmpfs
unmount_devpts() {
  if mountpoint -q /dev/pts/; then
    MOUNT_DEVPTS=mounted

    umount -l /dev/pts/
  fi

  if mountpoint -q /dev/shm/; then
    set -- $(IFS=' '; grep -E "^[^[:space:]]+ /dev/shm tmpfs " /proc/mounts)
    MOUNT_DEVSHM="$1 $2 -t $3 -o $4"

    umount -l /dev/shm/
  fi
}

mount_devpts() {
  [ "$TTYGRP" ] || TTYGRP=5
  [ "$TTYMODE" ] || TTYMODE=620

  [ "$MOUNT_DEVPTS" ] && \
	mount -t devpts devpts /dev/pts -ogid=$TTYGRP,mode=$TTYMODE
  [ "$MOUNT_DEVSHM" ] && mount $MOUNT_DEVSHM
}

# 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)
    unmount_devpts
    mount_tmpfs
    ACTION=add
    echo -n "Creating initial device nodes..."
    $UDEVSTART
    make_extra_nodes
    mount_devpts
    echo "done."
    ;;
  remove)
    # I'm not sure this is useful
    ACTION=remove
    echo -n "Removing device nodes..."
    old_synthesize_events
    echo "done."
    ;;
  stop)
    start-stop-daemon --stop --exec /sbin/udevd --oknodo --quiet
    unmount_devpts
    echo -n "Unmounting $udev_root..."
    # unmounting with -l should never fail
    if umount -l $udev_root; then
      echo "done."
      umount -l /etc/udev/.dev || true
    else
      echo "failed."
    fi
    mount_devpts
    ;;
  restart|force-reload)
    echo -n "Recreating device nodes..."
    ACTION=add
    $UDEVSTART
    make_extra_nodes
    echo "done."
    ;;
  *)
    echo "Usage: /etc/init.d/udev {start|stop|restart|force-reload}"
    exit 1
    ;;
esac

exit 0

