Monitorer un média amovible sous FreeBSD ou DragonFlyBSD

Quant on est sous GNU/Linux, il existe udev, très largement utilisé sur ce système d'exploitation (SE), mais lorsque l'on utilise un système BSD, et en particulier FreeBSD il nous est impossible d'utiliser cette bibliothèque. Cependant les développeurs de FreeBSD ont développé un outil similaire devd(8).

Il est accessible via un socket unix.

J'ai voulu voir comment l'utiliser grâce aux systèmes de notifications du noyau kqueue(2)/kevent(2), avec le langage Python.

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. 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.

Annexes