[PATCH] D-BUS patch for udev-008

Attached is a patch against udev-008 to send out a D-BUS message when a
device node is added or removed.

Using D-BUS lingo, udev acquires the org.kernel.udev service and sends
out a NodeCreated or NodeDeleted signal on the
org.kernel.udev.NodeMonitor interface. Each signal carries two
parameters: the node in question and the corresponding sysfs path.

[Note: the D-BUS concepts of service, interface, object can be a bit
confusing at first glance]

An example program listening for these messages looks like this

#!/usr/bin/python

import dbus
import gtk

def udev_signal_received(dbus_iface, member, service, object_path, message):
    [filename, sysfs_path] = message.get_args_list()
    if member=='NodeCreated':
        print 'Node %s created for %s'%(filename, sysfs_path)
    elif member=='NodeDeleted':
        print 'Node %s deleted for %s'%(filename, sysfs_path)

def main():
    bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM)
    bus.add_signal_receiver(udev_signal_received,
                            'org.kernel.udev.NodeMonitor',  # interface
                            'org.kernel.udev',              # service
                            '/org/kernel/udev/NodeMonitor') # object

    gtk.mainloop()

if __name__ == '__main__':
    main()

and this is the output when hot-plugging some usb-storage.

[david@laptop udev-008]$ ~/node_monitor.py
Node /udev/sda created for /block/sda
Node /udev/sda1 created for /block/sda/sda1
Node /udev/sda1 deleted for /block/sda/sda1
Node /udev/sda deleted for /block/sda

The patch requires D-BUS 0.20 or later while the python example program
requires D-BUS from CVS as I only recently applied a patch against the
python bindings.
This commit is contained in:
david@fubar.dk 2003-12-08 09:19:19 -08:00 committed by Greg KH
parent 3d150dfb28
commit 5aebfbcb62
7 changed files with 206 additions and 3 deletions

View File

@ -20,6 +20,10 @@
# Leave this set to `false' for production use. # Leave this set to `false' for production use.
DEBUG = false DEBUG = false
# Set the following to `true' to make udev emit a D-BUS signal when a
# new node is created.
USE_DBUS = true
ROOT = udev ROOT = udev
VERSION = 008_bk VERSION = 008_bk
@ -34,6 +38,7 @@ etcdir = ${prefix}/etc
sbindir = ${exec_prefix}/sbin sbindir = ${exec_prefix}/sbin
mandir = ${prefix}/usr/share/man mandir = ${prefix}/usr/share/man
hotplugdir = ${etcdir}/hotplug.d/default hotplugdir = ${etcdir}/hotplug.d/default
dbusdir = ${etcdir}/dbus-1/system.d
configdir = ${etcdir}/udev/ configdir = ${etcdir}/udev/
srcdir = . srcdir = .
@ -138,6 +143,13 @@ endif
CFLAGS += -I$(PWD)/libsysfs CFLAGS += -I$(PWD)/libsysfs
ifeq ($(USE_DBUS), true)
CFLAGS += -DUSE_DBUS
CFLAGS += $(shell pkg-config --cflags dbus-1)
LIB_OBJS += $(shell pkg-config --libs-only-l dbus-1)
endif
all: $(ROOT) all: $(ROOT)
@for target in $(EXTRAS) ; do \ @for target in $(EXTRAS) ; do \
echo $$target ; \ echo $$target ; \
@ -240,7 +252,20 @@ small_release: $(DISTFILES) clean
@echo "Built $(RELEASE_NAME).tar.gz" @echo "Built $(RELEASE_NAME).tar.gz"
install: all ifeq ($(USE_DBUS), true)
install-dbus-policy:
$(INSTALL) -d $(DESTDIR)$(dbusdir)
$(INSTALL_DATA) udev_sysbus_policy.conf $(DESTDIR)$(dbusdir)
uninstall-dbus-policy:
- rm $(DESTDIR)$(dbusdir)/udev_sysbus_policy.conf
else
install-dbus-policy:
-
uninstall-dbus-policy:
-
endif
install: install-dbus-policy all
$(INSTALL) -d $(DESTDIR)$(udevdir) $(INSTALL) -d $(DESTDIR)$(udevdir)
$(INSTALL) -d $(DESTDIR)$(configdir) $(INSTALL) -d $(DESTDIR)$(configdir)
$(INSTALL) -d $(DESTDIR)$(hotplugdir) $(INSTALL) -d $(DESTDIR)$(hotplugdir)
@ -257,7 +282,7 @@ install: all
-C $$target $@ ; \ -C $$target $@ ; \
done ; \ done ; \
uninstall: uninstall: uninstall-dbus-policy
- rm $(hotplugdir)/udev.hotplug - rm $(hotplugdir)/udev.hotplug
- rm $(configdir)/udev.permissions - rm $(configdir)/udev.permissions
- rm $(configdir)/udev.rules - rm $(configdir)/udev.rules

1
TODO
View File

@ -21,7 +21,6 @@ greg@kroah.com
will have an upgrade path. will have an upgrade path.
- do early boot logic (putting udev into initramfs, handle pivot-root, - do early boot logic (putting udev into initramfs, handle pivot-root,
etc.) etc.)
- add hooks to call D-BUS when new node is created or removed
- lots of other stuff... - lots of other stuff...
- actually use the BUS= value to determine where the LABEL rule should look - actually use the BUS= value to determine where the LABEL rule should look
(right now it's ignored, and we only look in the current sysfs directory.) (right now it's ignored, and we only look in the current sysfs directory.)

View File

@ -100,6 +100,42 @@ static int create_path(char *file)
return 0; return 0;
} }
#ifdef USE_DBUS
/** Send out a signal that a device node is created
*
* @param dev udevice object
* @param path Sysfs path of device
*/
static void sysbus_send_create(struct udevice *dev, const char *path)
{
char filename[255];
DBusMessage* message;
DBusMessageIter iter;
if (sysbus_connection == NULL)
return;
strncpy(filename, udev_root, sizeof(filename));
strncat(filename, dev->name, sizeof(filename));
/* object, interface, member */
message = dbus_message_new_signal("/org/kernel/udev/NodeMonitor",
"org.kernel.udev.NodeMonitor",
"NodeCreated");
dbus_message_iter_init(message, &iter);
dbus_message_iter_append_string(&iter, filename);
dbus_message_iter_append_string(&iter, path);
if ( !dbus_connection_send(sysbus_connection, message, NULL) )
dbg("error sending d-bus signal");
dbus_message_unref(message);
dbus_connection_flush(sysbus_connection);
}
#endif /* USE_DBUS */
/* /*
* we possibly want to add some symlinks here * we possibly want to add some symlinks here
* only numeric owner/group id's are supported * only numeric owner/group id's are supported
@ -323,6 +359,12 @@ int udev_add_device(char *path, char *subsystem)
dbg("name='%s'", dev.name); dbg("name='%s'", dev.name);
retval = create_node(&dev); retval = create_node(&dev);
#ifdef USE_DBUS
if (retval == 0) {
sysbus_send_create(&dev, path);
}
#endif /* USE_DBUS */
exit: exit:
if (class_dev) if (class_dev)
sysfs_close_class_device(class_dev); sysfs_close_class_device(class_dev);

View File

@ -100,6 +100,42 @@ static int delete_node(struct udevice *dev)
return retval; return retval;
} }
#ifdef USE_DBUS
/** Send out a signal that a device node is deleted
*
* @param name Name of the device node, e.g. /udev/sda1
* @param path Sysfs path of device
*/
static void sysbus_send_remove(const char* name, const char *path)
{
char filename[255];
DBusMessage* message;
DBusMessageIter iter;
if (sysbus_connection == NULL)
return;
strncpy(filename, udev_root, sizeof(filename));
strncat(filename, name, sizeof(filename));
/* object, interface, member */
message = dbus_message_new_signal("/org/kernel/udev/NodeMonitor",
"org.kernel.udev.NodeMonitor",
"NodeDeleted");
dbus_message_iter_init(message, &iter);
dbus_message_iter_append_string(&iter, filename);
dbus_message_iter_append_string(&iter, path);
if ( !dbus_connection_send(sysbus_connection, message, NULL) )
dbg("error sending d-bus signal");
dbus_message_unref(message);
dbus_connection_flush(sysbus_connection);
}
#endif /* USE_DBUS */
/* /*
* Look up the sysfs path in the database to see if we have named this device * Look up the sysfs path in the database to see if we have named this device
* something different from the kernel name. If we have, us it. If not, use * something different from the kernel name. If we have, us it. If not, use
@ -122,5 +158,10 @@ int udev_remove_device(char *path, char *subsystem)
dbg("name is '%s'", dev->name); dbg("name is '%s'", dev->name);
udevdb_delete_dev(path); udevdb_delete_dev(path);
#ifdef USE_DBUS
sysbus_send_remove(name, device);
#endif /* USE_DBUS */
return delete_node(dev); return delete_node(dev);
} }

64
udev.c
View File

@ -63,6 +63,60 @@ static inline char *get_seqnum(void)
return seqnum; return seqnum;
} }
#ifdef USE_DBUS
/** Global variable for the connection the to system message bus or #NULL
* if we cannot connect or acquire the org.kernel.udev service
*/
DBusConnection* sysbus_connection;
/** Disconnect from the system message bus */
static void sysbus_disconnect()
{
if (sysbus_connection == NULL)
return;
dbus_connection_disconnect(sysbus_connection);
sysbus_connection = NULL;
}
/** Connect to the system message bus */
static void sysbus_connect()
{
DBusError error;
/* Connect to a well-known bus instance, the system bus */
dbus_error_init(&error);
sysbus_connection = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
if (sysbus_connection == NULL) {
dbg("cannot connect to system message bus, error %s: %s",
error.name, error.message);
dbus_error_free(&error);
return;
}
/* Acquire the org.kernel.udev service such that listeners
* know that the message is really from us and not from a
* random attacker. See the file udev_sysbus_policy.conf for
* details.
*
* Note that a service can have multiple owners (though there
* is a concept of a primary owner for reception of messages)
* so no race is introduced if two copies of udev is running
* at the same time.
*/
dbus_bus_acquire_service(sysbus_connection, "org.kernel.udev", 0,
&error);
if (dbus_error_is_set(&error)) {
printf("cannot acquire org.kernel.udev service, error %s: %s'",
error.name, error.message);
sysbus_disconnect();
return;
}
}
#endif /* USE_DBUS */
int main(int argc, char **argv, char **envp) int main(int argc, char **argv, char **envp)
{ {
char *action; char *action;
@ -111,6 +165,11 @@ int main(int argc, char **argv, char **envp)
/* initialize our configuration */ /* initialize our configuration */
udev_init_config(); udev_init_config();
#ifdef USE_DBUS
/* connect to the system message bus */
sysbus_connect();
#endif /* USE_DBUS */
/* initialize udev database */ /* initialize udev database */
retval = udevdb_init(UDEVDB_DEFAULT); retval = udevdb_init(UDEVDB_DEFAULT);
if (retval != 0) { if (retval != 0) {
@ -133,6 +192,11 @@ int main(int argc, char **argv, char **envp)
} }
udevdb_exit(); udevdb_exit();
#ifdef USE_DBUS
/* disconnect from the system message bus */
sysbus_disconnect();
#endif /* USE_DBUS */
exit: exit:
return retval; return retval;
} }

9
udev.h
View File

@ -93,4 +93,13 @@ extern char udev_config_filename[PATH_MAX+NAME_MAX];
extern char udev_rules_filename[PATH_MAX+NAME_MAX]; extern char udev_rules_filename[PATH_MAX+NAME_MAX];
extern char default_mode_str[NAME_MAX]; extern char default_mode_str[NAME_MAX];
#ifdef USE_DBUS
#define DBUS_API_SUBJECT_TO_CHANGE
#include <dbus/dbus.h>
extern DBusConnection* sysbus_connection;
#endif /* USE_DBUS */
#endif #endif

23
udev_sysbus_policy.conf Normal file
View File

@ -0,0 +1,23 @@
<!DOCTYPE busconfig PUBLIC
"-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
"http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
<busconfig>
<!-- This configuration file specifies the required security policies
for udev to work. -->
<!-- Only root can own the udev service and only root can use the
org.kernel.udev.NodeMonitor interface to send signals -->
<policy user="root">
<allow own="org.kernel.udev"/>
<allow send_interface="org.kernel.udev.NodeMonitor"/>
</policy>
<!-- Allow anyone to listen to the org.kernel.udev.NodeMonitor interface
for messages send from the owner of the org.kernel.udev service -->
<policy context="default">
<allow receive_interface="org.kernel.udev.NodeMonitor"/>
</policy>
</busconfig>