hotplugd(8) (opens new window) is a really small
and useful utility looking for device events on OpenBSD. This tool is
equivalent to
devd(8) (opens new window) on FreeBSD
and a bit similar to
udev(7) (opens new window) on
Linux.
hotplugd(8) (opens new window) will listen for the
kernel events (based on the special file
/dev/hotplug (opens new window) and execute a
particular script with information about the device as arguments. When
the device is attached, hotplugd will execute /etc/hotplug/attach
and when the same device detach, it will execute
/etc/hotplug/detach.
So, why this is really useful? Because you can create your own action
based on the desired device! Furthermore, you can use any kind of
language... If you want to use a shell, a perl or a python script, you
can. Just be careful, hotplugd is running as root user by default,
it means all your script can do bad things without protection.
Well, I will give you an example. I am using a 4G device (and sometime
my smartphone) as router. When I plug the USB cable on my computer,
and when I decide to share the connection, a
urndis(4) (opens new window) interface is
automatically created. This new interface name is a combination of the
driver name and an index (as integer). In my case, it will create
urndis0 interface.
hotplugd will offer you all required information about the device by
sharing them directly as command arguments. The idea here is to use
attach and detach scripts as command router. When the device is
attached/detached, attach script will look linearly on different
scripts and if one of them exists, it will execute it.
By priority order:
/etc/hotplug/device/${interface_name}/etc/hotplug/device/${driver_name}/etc/hotplug/class/${class_id}
Firstly, we will initialize the tree:
mkdir /etc/hotplug
mkdir /etc/hotplug/device
mkdir /etc/hotplug/class
# attach script
touch /etc/hotplug/attach
chmod 700 /etc/hotplug/attach
# detach script
touch /etc/hotplug/detach
chmod 700 /etc/hotplug/detach
# urndis0 script
touch /etc/hotplug/device/urndis0
chmod 700 /etc/hotplug/device/urndis0
We will create attach script located in /etc/hotplug/attach.
#!/bin/sh
DEVCLASS="${1}"
DEVNAME="${2}"
DEVDRIVER=$(echo ${DEVNAME} | sed -E 's/^([a-z]+)([0-9]+$)/\1/')
DEVINDEX=$(echo ${DEVNAME} | sed -E 's/^([a-z]+)([0-9]+$)/\2/')
if test -x /etc/hotplug/device/${DEVNAME}
then
logger execute /etc/hotplug/device/${DEVNAME}
/etc/hotplug/device/${DEVNAME} attach ${*}
elif test -x /etc/hotplug/device/${DEVDRIVE}
then
logger execute /etc/hotplug/device/${DEVDRIVER}
/etc/hotplug/device/${DEVDRIVER} attach ${*}
elif test -x /etc/hotplug/class/${DEVCLASS}
then
logger execute /etc/hotplug/class/${DEVCLASS}
/etc/hotplug/class/${DEVCLASS} attach ${*}
fi
Now the detach script located in /etc/hotplug/detach.
#!/bin/sh
DEVCLASS="${1}"
DEVNAME="${2}"
DEVDRIVER=$(echo ${DEVNAME} | sed -E 's/^([a-z]+)([0-9]+$)/\1/')
DEVINDEX=$(echo ${DEVNAME} | sed -E 's/^([a-z]+)([0-9]+$)/\2/')
if test -x /etc/hotplug/device/${DEVNAME}
then
logger execute /etc/hotplug/device/${DEVNAME}
/etc/hotplug/device/${DEVNAME} detach ${*}
elif test -x /etc/hotplug/device/${DEVDRIVE}
then
logger execute /etc/hotplug/device/${DEVDRIVER}
/etc/hotplug/device/${DEVDRIVER} detach ${*}
elif test -x /etc/hotplug/class/${DEVCLASS}
then
logger execute /etc/hotplug/class/${DEVCLASS}
/etc/hotplug/class/${DEVCLASS} detach ${*}
fi
We can now create ou script to manage urndis0 interface located in
/etc/hotplug/device/urndis0. This script will assume we have
configured urndis0 by creating
/etc/hostname.urndis0 (opens new window) file.
#!/bin/sh
EVENT="${1}"
DEVCLASS="${2}"
DEVNAME="${3}"
_attach() {
logger attach ${DEVNAME}
sh /etc/netstart ${DEVNAME}
}
case "${EVENT}"
in
attach) _attach;;
esac
Well, now it's the time to test it by enabling and starting
hotplugd(8) (opens new window).
rcctl enable hotplugd
rcctl start hotplugd
Branch your device and follow /var/log/message log file.
tail -f /var/log/message
You should see something like that.
Jan 11 10:07:12 kin user: execute /etc/hotplug/device/urndis0
Jan 11 10:07:12 kin user: attach urndis0
Jan 11 10:07:13 kin dhclient[75457]: urndis0: 192.168.1.2 lease accepted from 192.168.1.1 (0a:6c:4b:1a:6d:35)
You can check directly with
ifconfig(8) (opens new window) if it's right...
$ ifconfig urndis0
urndis0: flags=808843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST,AUTOCONF4> mtu 1500
lladdr 02:16:13:45:ac:de
index 27 priority 0 llprio 3
groups: egress
inet 192.168.1.2 netmask 0xffffff00 broadcast 192.168.1.1
It works! But... What if I don't have the good device name? Okay, by
default, I assume urndis devices are safe and plugged by me (damn,
this is not the paranoid method). I will create another script called
urndis located in /etc/hotplug/device/urndis. This one will
execute dhclient(8) (opens new window) directly on
the interface without using
netstart(8) (opens new window).
#!/bin/sh
EVENT="${1}"
DEVCLASS="${2}"
DEVNAME="${3}"
_attach() {
logger attach ${DEVNAME}
dhclient ${DEVNAME}
}
case "${EVENT}"
in
attach) _attach;;
esac
And when we disable temporarily /etc/hotplug/device/urndis0 by
removing the execute mode...
chmod -x /etc/hotplug/device/urndis0
...we can now see that in /var/log/message.
Jan 11 10:54:11 kin user: urndis0 urndis 0
Jan 11 10:54:11 kin user: execute /etc/hotplug/device/urndis
Jan 11 10:54:11 kin /bsd: urndis0 at uhub0 port 1 configuration 1 interface 0 "Android" rev 2.00/ff.ff addr 3
Jan 11 10:54:11 kin /bsd: urndis0: using RNDIS, address 02:b6:13:63:74:6a
Jan 11 10:54:11 kin user: attach urndis0
Jan 11 10:54:11 kin dhclient[45455]: urndis0: 192.168.1.2 lease accepted from 192.168.11 (0a:12:ef:17:7d:23)
It seems to works! This is a simple way to connect device without any security and control.