AviGNU - Mot-clé - kqueue-keventGroupe d'utilisateurs de logiciels libres du Grand Avignon2024-01-02T17:40:01+01:00Administrateururn:md5:8ed776652564792dba453bac492a5a6cDotclearMonitorer un média amovible sous FreeBSD ou DragonFlyBSDurn:md5:6568e3bc539d49878a975a7758d301a42014-04-16T23:12:00+02:002014-04-16T22:51:30+02:00Olivier DuchateauProgrammationDragonFlyFreeBSDkqueue-keventPythonsocket <p>Quant on est sous GNU/Linux, il existe <a href="http://www.freedesktop.org/software/systemd/libudev/">udev</a>, très largement utilisé sur ce système d'exploitation (<acronym title="Système d'Exploitation">SE</acronym>), mais lorsque l'on utilise un système <a href="http://fr.wikipedia.org/wiki/Berkeley_Software_Distribution">BSD</a>, et en particulier <a href="http://www.freebsd.org/">FreeBSD</a> il nous est impossible d'utiliser cette bibliothèque. Cependant les développeurs de FreeBSD ont développé un outil similaire <a href="http://www.freebsd.org/cgi/man.cgi?query=devd&sektion=8&manpath=FreeBSD+10.0-RELEASE">devd(8)</a>.</p>
<p>Il est accessible via un <a href="http://fr.wikipedia.org/wiki/Berkeley_sockets#Socket_unix">socket unix</a>.</p>
<p>J'ai voulu voir comment l'utiliser grâce aux systèmes de notifications du noyau <a href="http://www.freebsd.org/cgi/man.cgi?query=kqueue&manpath=FreeBSD+10.0-RELEASE">kqueue(2)/kevent(2)</a>, avec le langage <a href="http://www.python.org/">Python</a>.</p>
<p>Je détaille un peu le script, tout d'abord nous allons initialiser un <em>socket</em> (le programme va fonctionner comme un client).</p>
<pre>
[...]
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()
[...]
</pre>
<p><code>fd</code> (<em>file descriptor</em>) est nécessaire pour <code>kevent</code>.</p>
<p>Les fonctions utilisées par kqueue/kevent sous Python sont accessible via le module <a href="https://docs.python.org/2.7/library/select.html">select</a>. Nous allons uniquement lire les données qui transitent par <code>/var/run/devd.pipe</code>.</p>
<p>Ci-dessous l'initialisation du mécanisme de notification.</p>
<pre>
[...]
# 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)
[...]
</pre>
<p>Nous pouvons « boucler » pour afficher les résultats quand un périphérique est branché. <strong>Un truc magique avec <code>kqueue/kevent</code> on a directement accès à la taille du tampon à lire.</strong></p>
<pre>
[...]
for event in events:
# Display data from socket (event.data is size to read)
print s.recv(event.data)
[...]
</pre>
<p>Voici le résultat lorsqu'une clé USB est branchée.</p>
<pre>
!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
</pre>
<p>La dernière ligne est intéressante, car c'est le nom de la partition que l'on pourra « monter » sur le système.</p>