Coin web de Frédéric Péters

fpeters@0d.be

Découvrir D-BUS

16 janvier 2005, 22:54

Je continue dans la même veine exploratrice, hal, udev, sysfs, hotplug, d-bus, toutes ces technos apparues récemment et qui s'imposent petit à petit comme essentielles à un système GNU/Linux récent.

Mis en forme et réfléchis correctement, ça pourrait faire une intéressante série d'articles qui s'adresseraient aux vieux, encore habitués à un /dev/ géré manuellement à grands coups de mknod.

Pourquoi ? Pour ne plus avoir à ressortir des méthodes de vieux singes quand un device n'est pas disponible, genre créer un script de démarrage de l'acabit suivant:

#! /bin/sh
test -e /dev/raw1394 || mknod -m 660 /dev/raw1394 c 171 0
chown root.video /dev/raw1394

(ce que, soit dit en passant, j'ai encore fait le mois passé)

Une série d'article de « mise à niveau », oui, ce serait pas mal. En attendant ceux-ci, quelques notes incohérentes sur ce weblog, ça peut dépanner.

Encore une introduction de trentes lignes, allez, hop, D-BUS.

Projet porté par la plate-forme freedesktop, D-BUS a une URL et un site web expliquant de quoi il retourne. Des bouts de documentation, aussi.

Python API: Using Remote Objects

The Python bindings are not yet documented, but the bindings themselves are in good shape.

À part ça, la doc explique que D-BUS est un système pour les communications interprocess, en gros on se retrouve avec des services genre HAL, fournissant une série de fonctions et de messages utiles, et des clients, genre vous et moi mais aussi gnome-volume-manager, qui interrogent les services et sont parfois prévenus lors d'événements particuliers.

Il y a aussi toute une histoire de bus, il peut y en avoir plusieurs, le bus système, le bus de session, etc. Perso dans mon install le bus de session n'est pas créé, on peut faire sans (mais cf dbus-launch(1)). Implémentons donc un service système, listant les interfaces réseaux disponibles par exemple. En Python parce que petit joueur...

#! /usr/bin/env python

import dbus
import gtk

def GetInterfaces(message):
    return ['eth0', 'eth1', 'ppp0'] # hardcoded in this short example

bus = dbus.SystemBus()
service = dbus.Service("com.example.NetworkInterfaces", bus=bus)
object = dbus.Object("/", service, [GetInterfaces])
gtk.main()

Que se passe-t-il ici ? Une fonction, qui retourne une liste; un bus système qu'on instancie; un service qu'on crée sur ce bus; un objet (en gros un truc qui écoute) qu'on définit sur ce service, le "/" étant le "chemin" de l'objet (vu qu'il pourrait y en avoir plusieurs par service) et la liste en troisième paramètre étant la liste des fonctions appelables.

À l'exécution, ça ne donnera rien d'autre qu'un message d'erreur disant qu'il ne dispose pas des droits pour s'attacher au bus système, passer en root ne changera rien, il faut définir dans la configuration du bus que le service untel peut être créé et appartenir à tel utilisateur, dans /etc/dbus-1/system.d/foo.conf, on a donc:

<busconfig>
  <policy user="fred"> <!-- c'est moi :) -->
    <allow own="com.example.NetworkInterfaces"/>
  </policy>
  <policy context="default">
    <allow receive_interface="com.example.NetworkInterfaces"/>
  </policy>
</busconfig>

L'utilisateur fred peut ainsi fournir le service et n'importe qui peut se connecter à cette interface. Exécution du script, ça tient.

Le client maintenant, super simple:

import dbus
bus = dbus.SystemBus()
remote_service = bus.get_service('com.example.NetworkInterfaces')
remote_object = remote_service.get_object('/', 'com.example.NetworkInterfaces')
print remote_object.GetInterfaces()

Exécution et ça affiche [eth0, eth1, ppp0], gagné.