#!/bin/sh -e
### BEGIN INIT INFO
# Provides:          udev
# Required-Start:    mountkernfs
# Required-Stop:
# Default-Start:     S
# Default-Stop:
# Short-Description: Start systemd-udevd, populate /dev and load drivers.
### END INIT INFO

# we need to unmount /dev/pts/ and remount it later over the devtmpfs
proc unmount_devpts {
  if mountpoint -q /dev/pts/ {
    umount -n -l /dev/pts/
  }

  if mountpoint -q /dev/shm/ {
    umount -n -l /dev/shm/
  }
}

# mount a devtmpfs over /dev, if somebody did not already do it
proc mount_devtmpfs {
  if grep -E -q "^[^[:space:]]+ /dev devtmpfs" /proc/mounts {
    mount -n -o remount,nosuid,size=$tmpfs_size,mode=0755 -t devtmpfs devtmpfs /dev
    return
  }

  if ! mount -n -o nosuid,size=$tmpfs_size,mode=0755 -t devtmpfs devtmpfs /dev {
    log_failure_msg "udev requires devtmpfs support, not started"
    log_end_msg 1
  }

  return 0
}

proc create_dev_makedev {
  if test -e /sbin/MAKEDEV {
    ln -sf /sbin/MAKEDEV /dev/MAKEDEV
  } else {
    ln -sf /bin/true /dev/MAKEDEV
  }
}

proc supported_kernel {
  case{
    2.[012345].*|2.6.[0-9]|2.6.[0-9][!0-9]* { return 1 }
    2.6.[12][0-9]|2.6.[12][0-9][!0-9]* { return 1 }
    2.6.3[0-1]|2.6.3[0-1][!0-9]* { return 1 }
  }
  return 0
}

# shell version of /usr/bin/tty
proc my_tty {
  test -x /bin/readlink || return 0
  test -e /proc/self/fd/0 || return 0
  readlink --silent /proc/self/fd/0 || true
}

proc warn_if_interactive {
  if test $RUNLEVEL = "S" -a $PREVLEVEL = "N" {
    return
  }

  setvar TTY = $(my_tty)
  if test -z $TTY -o $TTY = "/dev/console" -o $TTY = "/dev/null" {
    return
  }

  printf "\n\n\nIt has been detected that the command\n\n\t$0 $[join(ARGV)]\n\n"
  printf "has been run from an interactive shell.\n"
  printf "It will probably not do what you expect, so this script will wait\n"
  printf "60 seconds before continuing. Press ^C to stop it.\n"
  printf "RUNNING THIS COMMAND IS HIGHLY DISCOURAGED!\n\n\n\n"
  sleep 60
}

proc make_static_nodes {
  test -e /lib/modules/$(uname -r)/modules.devname || return 0
  test -x /bin/kmod || return 0

  /bin/kmod static-nodes --format=tmpfiles --output=/proc/self/fd/1 | \
  while read type name mode uid gid age arg {
    test -e $name && continue
    case (type) {
      c|b|c!|b! { mknod -m $mode $name $type $(echo $arg | sed 's/:/ /') }
      d|d! { mkdir $name }
      * { echo "unparseable line ($type $name $mode $uid $gid $age $arg)" >&2 }
    }

    if test -x /sbin/restorecon {
      /sbin/restorecon $name
    }
  }
}


##############################################################################

setvar PATH = ""/sbin:/bin""
setvar NAME = ""systemd-udevd""
setvar DAEMON = ""/lib/systemd/systemd-udevd""
setvar DESC = ""the hotplug events dispatcher""

test -x $DAEMON || exit 0

# defaults
setvar tmpfs_size = ""10M""

if test -e /etc/udev/udev.conf {
  source /etc/udev/udev.conf
}

source /lib/lsb/init-functions

if ! supported_kernel {
  log_failure_msg "udev requires a kernel >= 2.6.32, not started"
  log_end_msg 1
}

if test ! -e /proc/filesystems {
  log_failure_msg "udev requires a mounted procfs, not started"
  log_end_msg 1
}

if ! grep -q '[[:space:]]devtmpfs$' /proc/filesystems {
  log_failure_msg "udev requires devtmpfs support, not started"
  log_end_msg 1
}

if test ! -d /sys/class/ {
  log_failure_msg "udev requires a mounted sysfs, not started"
  log_end_msg 1
}

if ! ps --no-headers --format args ax | egrep -q '^\[' {
  log_warning_msg "udev does not support containers, not started"
  exit 0
}

if test -d /sys/class/mem/null -a ! -L /sys/class/mem/null || \
   test -e /sys/block -a ! -e /sys/class/block {
  log_warning_msg "CONFIG_SYSFS_DEPRECATED must not be selected"
  log_warning_msg "Booting will continue in 30 seconds but many things will be broken"
  sleep 30
}

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

case (1) {
    start {
    if init_is_upstart 2>/dev/null {
	exit 1
    }

    if test ! -e "/run/udev/" {
	warn_if_interactive
    }

    if test -w /sys/kernel/uevent_helper {
	echo > /sys/kernel/uevent_helper
    }

    if ! mountpoint -q /dev/ {
	unmount_devpts
	mount_devtmpfs
	test -d /proc/1 || mount -n /proc
    }

    make_static_nodes

    # clean up parts of the database created by the initramfs udev
    udevadm info --cleanup-db

    # set the SELinux context for devices created in the initramfs
    test -x /sbin/restorecon && /sbin/restorecon -R /dev

    log_daemon_msg "Starting $DESC" $NAME
    if $DAEMON --daemon {
	log_end_msg $?
    } else {
	log_warning_msg $?
	log_warning_msg "Waiting 15 seconds and trying to continue anyway"
	sleep 15
    }

    log_action_begin_msg "Synthesizing the initial hotplug events"
    if udevadm trigger --action=add {
	log_action_end_msg $?
    } else {
	log_action_end_msg $?
    }

    create_dev_makedev

    # wait for the systemd-udevd childs to finish
    log_action_begin_msg "Waiting for /dev to be fully populated"
    if udevadm settle {
	log_action_end_msg 0
    } else {
	log_action_end_msg 0 'timeout'
    }
    }

    stop {
    log_daemon_msg "Stopping $DESC" $NAME
    if start-stop-daemon --stop --name $NAME --user root --quiet --oknodo --retry 5 {
	log_end_msg $?
    } else {
	log_end_msg $?
    }
    }

    restart {
    if init_is_upstart 2>/dev/null {
	exit 1
    }
    log_daemon_msg "Stopping $DESC" $NAME
    if start-stop-daemon --stop --name $NAME --user root --quiet --oknodo --retry 5 {
	log_end_msg $?
    } else {
	log_end_msg $? || true
    }

    log_daemon_msg "Starting $DESC" $NAME
    if $DAEMON --daemon {
	log_end_msg $?
    } else {
	log_end_msg $?
    }
    }

    reload|force-reload {
    udevadm control --reload-rules
    }

    status {
    status_of_proc $DAEMON $NAME && exit 0 || exit $?
    }

    * {
    echo "Usage: /etc/init.d/udev {start|stop|restart|reload|force-reload|status}" >&2
    exit 1
    }
}

exit 0