User Tools

Site Tools


docs:guide-user:base-system:hotplug

Hotplug

Procd (the init system and process management daemon) executes scripts located in /etc/hotplug.d/ when certain events happen, like for example when an interface goes up or down, when a new storage drive is detected, or when a button is pressed. It can be very useful with PPPoE connection or in an unstable network, or to use hardware buttons.

This functionality emulates/extends what was done by the long retired Hotplug2 package.

How it works

In the /etc/hotplug.d folder you will find some subfolders block, iface, net and ntp.

When the trigger event fires, Procd will execute all scripts in that trigger's subfolder, in alphabetical order. Which is why most scripts in there use a numeric prefix.

Directory Description
block Block device events (block device connected/disconnected)
button Buttons (not created by default, see /etc/rc.button instead)
iface Interface events (when a interface like LAN or WAN is connected/disconnected)
net Network-related events
ntp Time sync events (time step, time server stratum change)
usb USB devices like 3g-modem and tty*

There may (should) be others, for other types of triggers. By looking at the source in git there should be some also for buttons, sound devices, serial and usb serial dongles.

Usage

Simply place your script(s) into the right hotplug.d subdirectory, if there is none just create the right one.

Information provided to your scripts / Troubleshooting

Procd exposes a wealth of info when executes your scripts in /etc/hotplug.d, usually as environmental variables.

If you want to see what environmental variables it is providing, make a script that contains this line:

env > /tmp/envs_log.log

and place it in the folder you want to use, then trigger the event connected to that folder, and then you can see what envs were passed by reading the /tmp/envs_log.log text file

The block folder

For scripts in block folder, these are the (relevant) environmental variables

Variable name Description
ACTION Either “add” or “remove”
DEVICENAME seems same as DEVNAME below
DEVNAME Device or partition name (if I connect a drive I get a hotplug call with “sda” and another hotplug call with “sda1”)
DEVPATH full device path (for example “/devices/pci0000:00/0000:00:0b.0/usb1/1-1/1-1:1.0/host7/target7:0:0/7:0:0:0/block/sdc/sdc1 ”
DEVTYPE what the DEVNAME e DEVICENAME are names of, I've seen “partition” here when a device with a readable partition is inserted and a “disk” when that device is removed.
MAJOR major device number
MINOR minor device number
SEQNUM seqnum (a number)
SUBSYSTEM seems this is only “block”

The iface folder

There are three main environment variables that are passed to each iface hotplug script:

Variable name Description
ACTION Either “ifup” or “ifdown”
INTERFACE Name of the interface which went up or down (e.g. “wan” or “ppp0”)
DEVICE Physical device name which interface went up or down (e.g. “eth0.1” or “br-lan”)

The ntp folder

Variable name description
ACTION step, stratum, unsync or periodic
freq_drift_ppm ntp variables
offset ntp variables
stratum ntp variables
poll_interval ntp variables

Even without NTP sync, you will receive a periodic hotplug event, with stratum=16, about every 11 minutes out of the box.

The usb folder

Variable name description
ACTION add, remove as above
DEVNAME eg, “bus/usb/001/002”
DEVPATH eg, “/devices/platform/ehci-platform/usb1/1-1”
DEVICENAME eg “1-1”
DEVNUM eg 002
DRIVER “usb”
TYPE eg 9/0/1
PRODUCT the vendor/productcode/version, eg “424/2640/0” see lsusb
SEQNUM ? eg 335
BUSNUM eg 001
MAJOR eg 189
MINOR eg 1

Examples

cat << "EOF" > /etc/hotplug.d/iface/99-my-action
[ "${ACTION}" = "ifup" ] && {
    logger -t hotplug "Device: ${DEVICE} / Action: ${ACTION}"
} 
EOF

Every time an interface goes up then the if/fi statement will be executed.

Restart wlan on USB WiFi hotplug

Niii has posted this quick example for a USB WiFi device hotplug event to trigger an init.d network restart wlan0 script.

To determine RTL8188SU_PRODID variable:

# lsusb -v
  idVendor           0x0bda Realtek Semiconductor Corp.
  idProduct          0x8171 RTL8188SU 802.11n WLAN Adapter
  bcdDevice            2.00
cat << "EOF" > /etc/hotplug.d/usb/20-rtl8188su
BINARY="/sbin/wifi up"
RTL8188SU_PRODID="bda/8171/200"
 
if [ "${PRODUCT}" = "${RTL8188SU_PRODID}" ]; then
    if [ "${ACTION}" = "add" ]; then
        ${BINARY}
    fi
fi
EOF

An other script to create a symlink instead of renaming the device.
I test if DEVICE_NAME is empty because when I plug usb device I retrieve two add event, and the first come before created device, so symlink fails.

cat << "EOF" > /etc/hotplug.d/usb/20-cp210x
CP210_PRODID="10c4/ea60/100"
SYMLINK="my_link"
 
if [ "${PRODUCT}" = "${CP210_PRODID}" ];
    then if [ "${ACTION}" = "add" ];
      then
          DEVICE_NAME=$(ls /sys/${DEVPATH} | grep tty)
          if [ -z ${DEVICE_NAME} ];
              then logger -t hotplug "Warning DEVICE_NAME is empty"
              exit
          fi
          logger -t hotplug "Device name of cp210 is ${DEVICE_NAME}"
          ln -s /dev/${DEVICE_NAME} /dev/${SYMLINK}
          logger -t hotplug "Symlink from /dev/${DEVICE_NAME} to /dev/${SYMLINK} created"
    fi
fi
 
if [ "${PRODUCT}" = "${CP210_PRODID}" ];
    then if [ "${ACTION}" = "remove" ];
        then 
        rm /dev/${SYMLINK}
        logger -t hotplug "Symlink /dev/${SYMLINK} removed"
    fi
fi
EOF

Script that detects if plugged usb device is bluetooth or not

cat << "EOF" > /etc/hotplug.d/usb/20-bt_test
BT_PRODID="a12/1/"
BT_PRODID_HOT=`echo ${PRODUCT} | cut -c 1-6`
 
#logger -t hotplug "PRODUCT ID is ${BT_PRODID_HOT}"
 
if [ "${BT_PRODID_HOT}" = "${BT_PRODID}" ]; then
    if [ "${ACTION}" = "add" ]; then
        logger -t hotplug "bluetooth device has been plugged in!"
        if [ "${BSBTID_NEW}" = "${BSBTID_OLD}" ]; then
            logger -t hotplug "bluetooth device hasn't changed"
        else
            logger -t hotplug "bluetooth device has changed"
        fi
    fi
    if [ "${ACTION}" = "remove" ]; then
        logger -t hotplug "bluetooth device has been removed!"
    fi
else
    logger -t hotplug "USB device is not bluetooth"
fi
EOF

Auto start mjpg-streamer when an usb camera is plugged in

cat << "EOF" > /etc/hotplug.d/usb/20-mjpg_start
case "${ACTION}" in
    add)
            # start process
        /etc/init.d/mjpg-streamer start
            ;;
    remove)
            # stop process
        /etc/init.d/mjpg-streamer stop
            ;;
esac
EOF

Custom automount script for xfs

cat << "EOF" > /etc/hotplug.d/block/xfs_automount
# if a new block device is connected
if [ "${ACTION}" = "add" ] ; then
    # getting device UUID
    detected_uuid="$(xfs_admin -u /dev/${DEVICENAME} | awk '{print $3}')"
    # deciding mountpoint for known UUID
    mountpoint=""
    case "${detected_uuid}" in
        6a5d7c5c-c9d0-41cc-8f19-78d97f839c05)
            mountpoint="/path/to/first/mountpoint"
            ;;
        02880b1f-0c67-46b6-9b05-5535680ccc89)
            mountpoint="/path/to/second/mountpoint"
            ;;
    esac
 
    # if we have a known UUID we have a mountpoint so we can mount it
    if [ "${mountpoint}" != "" ] ; then 
        mount /dev/${DEVICENAME} ${mountpoint}
    fi
fi
# unmounting happens automatically at device disconnection anyway so no logic for that
EOF

Coldplug

If you had notice the udev and eudev were removed in the openwrt 18.0.* release, don't be afraid because you still can make the things works.
Using hotplug scripts as coldplug
You just need to pay atention at the ACTION env var, at the boot are executed 'bind' actions.
So, just add this option to hotplug run accordinly. In my case I used this:

cat << "EOF" > /etc/hotplug.d/usb/22-symlinks
# Description: Action executed on boot (bind) and with the system on the fly
if [ "${ACTION}" = "bind" ] ; then
  case "${PRODUCT}" in
    1bc7*) # Telit HE910 3g modules product id prefix
      DEVICE_NAME="$(ls /sys/$DEVPATH | grep tty)"
      DEVICE_TTY="$(ls /sys/$DEVPATH/tty/)"
      # Module Telit HE910-* connected to minipciexpress slot MAIN
      if [ "${DEVICENAME}" = "1-1.3:1.0" ] ; then
        ln -s /dev/${DEVICE_TTY} /dev/ttyMODULO1_DIAL
        logger -t hotplug "Symlink from /dev/${DEVICE_TTY} to /dev/ttyMODULO1_DIAL created"
      elif [ "${DEVICENAME}" = "1-1.3:1.6" ] ; then
        ln -s /dev/${DEVICE_TTY} /dev/ttyMODULO1_DATA
        logger -t hotplug "Symlink from /dev/${DEVICE_TTY} to /dev/ttyMODULO1_DATA created"
      # Module Telit HE910-* connected to minipciexpress slot SECONDARY
      elif [ "${DEVICENAME}" = "1-1.2:1.0" ] ; then
        ln -s /dev/${DEVICE_TTY} /dev/ttyMODULO2_DIAL
        logger -t hotplug "Symlink from /dev/${DEVICE_TTY} to /dev/ttyMODULO2_DIAL created"
      elif [ "${DEVICENAME}" = "1-1.2:1.6" ] ; then
        ln -s /dev/${DEVICE_TTY} /dev/ttyMODULO2_DATA
        logger -t hotplug "Symlink from /dev/${DEVICE_TTY} to /dev/ttyMODULO2_DATA created"
      fi
    ;;
  esac
fi
# Action to remove the symlinks
if [ "$ACTION" = "remove" ]  ; then
  case "${PRODUCT}" in
    1bc7*)  # Telit HE910 3g modules product id prefix
     # Module Telit HE910-* connected to minipciexpress slot MAIN
      if [ "${DEVICENAME}" = "1-1.3:1.0" ] ; then
        rm /dev/ttyMODULO1_DIAL
        logger -t hotplug "Symlink /dev/ttyMODULO1_DIAL removed"
      elif [ "${DEVICENAME}" = "1-1.3:1.6" ] ; then
        rm /dev/ttyMODULO1_DATA
        logger -t hotplug "Symlink /dev/ttyMODULO1_DATA removed"
      # Module Telit HE910-* connected to minipciexpress slot SECONDARY
      elif [ "${DEVICENAME}" = "1-1.2:1.0" ] ; then
        rm /dev/ttyMODULO2_DIAL
        logger -t hotplug "Symlink /dev/ttyMODULO2_DIAL removed"
      elif [ "${DEVICENAME}" = "1-1.2:1.6" ] ; then
        rm /dev/ttyMODULO2_DATA
        logger -t hotplug "Symlink /dev/ttyMODULO2_DATA removed"
      fi
    ;;
  esac
fi
EOF
docs/guide-user/base-system/hotplug.txt · Last modified: 2019/07/16 14:20 by vgaetera