#!/bin/sh -e

supported_kernel() {
  case "$(uname -r)" in
    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 ;;
  esac
  return 0
}

tempdir() {
  local dir=$(tempfile --prefix=udev.)
  rm $dir
  mkdir $dir
  echo $dir
}

chrooted() {
  if [ "$(stat -c %d/%i /)" = "$(stat -Lc %d/%i /proc/1/root 2>/dev/null)" ];
  then
    # the devicenumber/inode pair of / is the same as that of /sbin/init's
    # root, so we're *not* in a chroot and hence return false.
    return 1
  fi
  echo "A chroot environment has been detected, udev not started."
  return 0
}

in_debootstrap() {
  # debootstrap --second-stage may be run in an emulator instead of a chroot,
  # we need to check for this special case because start-stop-daemon would
  # not be available. (#520742)
  if [ -d /debootstrap/ ]; then
    echo "Being installed by debootstrap, udev not started."
    return 0
  fi
  return 1
} 

can_start_udevd() {
  if ! supported_kernel; then
    echo "udev requires a kernel >= 2.6.32, not started."
    return 1
  fi

  if [ ! -d /sys/class/ ]; then
    echo "udev requires a mounted sysfs, not started."
    return 1
  fi

  if ! ps --no-headers --format args ax | egrep -q '^\['; then
    echo "udev does not support containers, not started."
    return 1
  fi

  if ! grep -q '[[:space:]]devtmpfs$' /proc/filesystems; then
    echo "udev requires devtmpfs support, not started."
    return 1
  fi

  if [ -e /etc/udev/disabled ]; then
    echo "/etc/udev/disabled has been detected, udev not started."
    return 1
  fi

  return 0
}

enable_udev() {
  can_start_udevd || return 0

  invoke-rc.d udev start

  # restart some daemons because their /dev sockets might have been hidden by
  # the devtmpfs
  kill -s HUP 1
  local sysloginits="inetutils-syslogd rsyslog socklog-run sysklogd syslog-ng"
  for script in $sysloginits; do
    [ -x /etc/init.d/$script ] && invoke-rc.d $script restart || true
  done
}

update_initramfs() {
  [ -x /usr/sbin/update-initramfs -a -e /etc/initramfs-tools/initramfs.conf ] \
    || return 0
  update-initramfs -u
}

write_interfaces_rules() {
  local devpath
  for devpath in /sys/class/net/*; do
    [ -d "$devpath" ] || continue
    udevadm test --action=add $devpath > /dev/null || true
  done
}

upgrade_fixes() {
  # 167-1 introduced /run/udev/ but does not move the old database on
  # upgrades when it decides to switch to /run/.
  if ! chrooted && [ -d /dev/.udev/ -a ! -d /run/udev/ ] \
      && grep -E -q "^[^[:space:]]+ /run tmpfs " /proc/mounts; then
    mv /dev/.udev/ /run/udev/
  fi

  if dpkg --compare-versions "$2" lt "171-3"; then
    # in 171-2 this directory becomes a symlink to libudev0, so it must be
    # manually deleted because dpkg cannot automatically deal with this
    if [ -e /usr/share/doc/udev -a ! -L /usr/share/doc/udev ]; then
      rm -rf /usr/share/doc/udev
      ln -s libudev0 /usr/share/doc/udev
    fi
  fi

  if dpkg --compare-versions "$2" lt "204-1"; then
    # We dropped udev-mtab with udev 204.
    update-rc.d udev-mtab remove
  fi
}

update_hwdb() {
  udevadm hwdb --update --usr || true
}

# In udev-204, we ship systemd-udevd.service (upstream name), whereas previous
# versions used udev.service. We replace udev.service with a symlink to
# systemd-udevd.service, but systemd (both 44 and 204) exposes weird behavior:
# After a daemon-reload, it forgets about the /sbin/udevd process in the
# udev.service cgroup, so a restart will lead to having two udevd processes
# running — one in the udev.service cgroup and one in the systemd-udevd.service
# cgroup.
#
# To fix this, we explicitly stop udev.service and the corresponding sockets,
# then issue the daemon-reload, then restart the new systemd-udevd.service (via
# invoke-rc.d).
handle_service_rename() {
  if dpkg --compare-versions "$2" lt "204-1"; then
    if [ -d /run/systemd/system ]; then
      systemctl stop udev.service udev-control.socket udev-kernel.socket >/dev/null 2>&1 || true
    fi
  fi
}

case "$1" in
    configure)
    # update/create hwdb before we (re)start udev
    update_hwdb

    # Add new system group used by udev rules
    addgroup --quiet --system input

    if [ -z "$2" ]; then # first install
      if ! chrooted && ! in_debootstrap; then
	write_interfaces_rules
	enable_udev
      fi
    else # upgrades
      upgrade_fixes "$@"
      if ! chrooted; then
	if [ -e /etc/udev/kernel-upgrade ]; then
	  echo "Kernel upgrade mode, udevd has not been restarted."
	  echo "Please reboot the system as soon as possible."
	  rm /etc/udev/kernel-upgrade
	elif can_start_udevd; then
          handle_service_rename
	  rm -f /run/systemd/system/systemd-udevd.service
	  rm -f /run/systemd/system/udev.service
          # This is necessary for the handle_service_rename case, but does not
          # hurt in general (invoke-rc.d does it, too).
	  if [ -d /run/systemd/system ] ; then
	    systemctl daemon-reload || true
	  fi
	  invoke-rc.d udev restart
	fi
      fi
    fi

    update_initramfs
    ;;

    abort-upgrade|abort-remove|abort-deconfigure)
    ;;

    triggered)
    update_hwdb
    exit 0
    ;;

    interfaces)
    write_interfaces_rules
    ;;

    *)
    echo "$0 called with unknown argument '$1'" >&2
    exit 1
    ;;
esac

#DEBHELPER#

