Quant on est sous GNU/Linux, il existe [udev|http://www.freedesktop.org/software/systemd/libudev/], très largement utilisé sur ce système d’exploitation (??SE|Système d’Exploitation??), mais lorsque l’on utilise un système [BSD|http://fr.wikipedia.org/wiki/Berkeley_Software_Distribution], et en particulier [FreeBSD|http://www.freebsd.org/] il nous est impossible d’utiliser cette bibliothèque. Cependant les développeurs de FreeBSD ont développé un outil similaire [devd(8)|http://www.freebsd.org/cgi/man.cgi?query=devd&sektion=8&manpath=FreeBSD+10.0-RELEASE].

Il est accessible via un [socket unix|http://fr.wikipedia.org/wiki/Berkeley_sockets#Socket_unix].

J’ai voulu voir comment l’utiliser grâce aux systèmes de notifications du noyau [kqueue(2)/kevent(2)|http://www.freebsd.org/cgi/man.cgi?query=kqueue&manpath=FreeBSD+10.0-RELEASE], avec le langage [Python|http://www.python.org/].

Je détaille un peu le script, tout d’abord nous allons initialiser un  »socket » (le programme va fonctionner comme un client).

///
[…]
s_file = os.path.join(« /var », « run », « devd.pipe »)

# Create new socket object
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
s.connect(s_file)

# Return the socket’s file descriptor
fd = s.fileno()

[…]
///

@@fd@@ ( »file descriptor ») est nécessaire pour @@kevent@@.

Les fonctions utilisées par kqueue/kevent sous Python sont accessible via le module [select| https://docs.python.org/2.7/library/select.html]. Nous allons uniquement lire les données qui transitent par @@/var/run/devd.pipe@@.

Ci-dessous l’initialisation du mécanisme de notification.

///
[…]
# Kernel queue object
kq = select.kqueue()

# Event to monitor (only attach)
event = [select.kevent(fd, filter=select.KQ_FILTER_READ, flags=select.KQ_EV_ADD),]

# Initialize kevent structure (like EV_SET macro in sys/event.h)
ev_set = kq.control(event, 0, 0)
[…]
///

Nous pouvons « boucler » pour afficher les résultats quand un périphérique est branché. __Un truc magique avec @@kqueue/kevent@@ on a directement accès à la taille du tampon à lire.__

///
[…]
for event in events:
# Display data from socket (event.data is size to read)
print s.recv(event.data)
[…]
///

Voici le résultat lorsqu’une clé USB est branchée.

///
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/2.2.0
!system=DEVFS subsystem=CDEV type=CREATE cdev=ugen2.2

!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/2.2.1
!system=DEVFS subsystem=CDEV type=CREATE cdev=usb/2.2.2

!system=USB subsystem=DEVICE type=ATTACH ugen=ugen2.2 cdev=ugen2.2 vendor=0x0930
product=0x653d devclass=0x00 devsubclass=0x00 sernum= »0B4085607142DAD4″ release
=0x0100 mode=host port=6 parent=ugen2.1
!system=USB subsystem=INTERFACE type=ATTACH ugen=ugen2.2 cdev=ugen2.2 vendor=0x0
930 product=0x653d devclass=0x00 devsubclass=0x00 sernum= »0B4085607142DAD4″ rele
ase=0x0100 mode=host interface=0 endpoints=2 intclass=0x08 intsubclass=0x06 intp
rotocol=0x50
+umass0 at bus=1 hubaddr=6 port=2 devaddr=2 interface=0 vendor=0x0930 product=0x
653d devclass=0x00 devsubclass=0x00 sernum= »0B4085607142DAD4″ release=0x0100 mod
e=host intclass=0x08 intsubclass=0x06 intprotocol=0x50 on uhub2

!system=DEVFS subsystem=CDEV type=CREATE cdev=pass2

!system=DEVFS subsystem=CDEV type=CREATE cdev=da0

!system=DEVFS subsystem=CDEV type=CREATE cdev=da0s1
///

La dernière ligne est intéressante, car c’est le nom de la partition que l’on pourra « monter » sur le système.