[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.
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
VERSION = 008_bk
@ -34,6 +38,7 @@ etcdir = ${prefix}/etc
sbindir = ${exec_prefix}/sbin
mandir = ${prefix}/usr/share/man
hotplugdir = ${etcdir}/hotplug.d/default
dbusdir = ${etcdir}/dbus-1/system.d
configdir = ${etcdir}/udev/
srcdir = .
@ -138,6 +143,13 @@ endif
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)
@for target in $(EXTRAS) ; do \
echo $$target ; \
@ -240,7 +252,20 @@ small_release: $(DISTFILES) clean
@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)$(configdir)
$(INSTALL) -d $(DESTDIR)$(hotplugdir)
@ -257,7 +282,7 @@ install: all
-C $$target $@ ; \
done ; \
uninstall:
uninstall: uninstall-dbus-policy
- rm $(hotplugdir)/udev.hotplug
- rm $(configdir)/udev.permissions
- rm $(configdir)/udev.rules

1
TODO
View File

@ -21,7 +21,6 @@ greg@kroah.com
will have an upgrade path.
- do early boot logic (putting udev into initramfs, handle pivot-root,
etc.)
- add hooks to call D-BUS when new node is created or removed
- lots of other stuff...
- 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.)

View File

@ -100,6 +100,42 @@ static int create_path(char *file)
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
* 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);
retval = create_node(&dev);
#ifdef USE_DBUS
if (retval == 0) {
sysbus_send_create(&dev, path);
}
#endif /* USE_DBUS */
exit:
if (class_dev)
sysfs_close_class_device(class_dev);

View File

@ -100,6 +100,42 @@ static int delete_node(struct udevice *dev)
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
* 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);
udevdb_delete_dev(path);
#ifdef USE_DBUS
sysbus_send_remove(name, device);
#endif /* USE_DBUS */
return delete_node(dev);
}

64
udev.c
View File

@ -63,6 +63,60 @@ static inline char *get_seqnum(void)
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)
{
char *action;
@ -111,6 +165,11 @@ int main(int argc, char **argv, char **envp)
/* initialize our configuration */
udev_init_config();
#ifdef USE_DBUS
/* connect to the system message bus */
sysbus_connect();
#endif /* USE_DBUS */
/* initialize udev database */
retval = udevdb_init(UDEVDB_DEFAULT);
if (retval != 0) {
@ -133,6 +192,11 @@ int main(int argc, char **argv, char **envp)
}
udevdb_exit();
#ifdef USE_DBUS
/* disconnect from the system message bus */
sysbus_disconnect();
#endif /* USE_DBUS */
exit:
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 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

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>