diff options
author | David Zeuthen <david@fubar.dk> | 2003-12-08 22:01:44 +0000 |
---|---|---|
committer | David Zeuthen <david@fubar.dk> | 2003-12-08 22:01:44 +0000 |
commit | 656008dee085d23daf65dab8356e49d018cc305d (patch) | |
tree | 6db1a15440971ed1b5c7e433e8e9655bcc64514e | |
parent | 6a751c825d0b08ad1b879c704b45b1562df7f5cd (diff) | |
download | hal-656008dee085d23daf65dab8356e49d018cc305d.tar.gz |
s/volume./block./ (udev_filter_func): new function for filtering D-BUS
messages from udev (setup_udev_listener): setup filter for udev
messages (hal_monitor_enter): Listen to D-BUS messages
Use global sysfs path (device_hotplug_add): Use global sysfs path
(device_hotplug_remove): Use global sysfs path (drivers_collect): Use
global sysfs path (mainloop_integration): Save D-BUS connection object
for later use (main): Get sysfs mount path once and for all
Add dbus_connection and sysfs_mount_path as extern variables
new function (filter_function): add check for Device.QueryCapability
Minor formatting stuff
Crude example of volume manager now that we got udev integration in place.
It doesn't really mount anything but prints out when it should mount.
You'll need a very recent udev from BitKeeper with D-BUS enabled (got
the patch accepted today)
-rw-r--r-- | ChangeLog | 31 | ||||
-rw-r--r-- | agents/linux26/sysfs/hal_monitor.c | 121 | ||||
-rw-r--r-- | agents/linux26/sysfs/main.c | 65 | ||||
-rw-r--r-- | agents/linux26/sysfs/main.h | 4 | ||||
-rwxr-xr-x | examples/volumed/volumed.py | 99 | ||||
-rw-r--r-- | hald/main.c | 73 | ||||
-rw-r--r-- | libhal/libhal.c | 8 |
7 files changed, 353 insertions, 48 deletions
@@ -1,3 +1,34 @@ +2003-12-08 David Zeuthen <david@fubar.dk> + + * agents/linux26/sysfs/hal_monitor.c: + (etc_mtab_process_all_block_devices): s/volume./block./ + (udev_filter_func): new function for filtering D-BUS messages from udev + (setup_udev_listener): setup filter for udev messages + (hal_monitor_enter): Listen to D-BUS messages + + * agents/linux26/sysfs/main.c: + (hal_sysfs_probe): Use global sysfs path + (device_hotplug_add): Use global sysfs path + (device_hotplug_remove): Use global sysfs path + (drivers_collect): Use global sysfs path + (mainloop_integration): Save D-BUS connection object for later use + (main): Get sysfs mount path once and for all + + * agents/linux26/sysfs/main.h: Add dbus_connection and sysfs_mount_path + as extern variables + + * hald/main.c: + (device_query_capability): new function + (filter_function): add check for Device.QueryCapability + + * libhal/libhal.c: Minor formatting stuff + + * examples/volumed/volumed.py: Crude example of volume manager now + that we got udev integration in place. It doesn't really mount anything + but prints out when it should mount. You'll need a very recent udev + from BitKeeper with D-BUS enabled (got the patch accepted today) + + 2003-12-06 David Zeuthen <david@fubar.dk> * tools/device-manager/hal-device-manager.glade: Forgot to add file diff --git a/agents/linux26/sysfs/hal_monitor.c b/agents/linux26/sysfs/hal_monitor.c index 246c9f91..966ef110 100644 --- a/agents/linux26/sysfs/hal_monitor.c +++ b/agents/linux26/sysfs/hal_monitor.c @@ -304,13 +304,13 @@ void etc_mtab_process_all_block_devices(dbus_bool_t setup_watcher) */ /* Yay! Found a mount point; set properties accordingly */ - hal_device_set_property_string(udi, "volume.device", + hal_device_set_property_string(udi, "block.device", mp->device); - hal_device_set_property_string(udi, "volume.mountPoint", + hal_device_set_property_string(udi, "block.mountPoint", mp->mount_point); - hal_device_set_property_string(udi, "volume.fileSystem", + hal_device_set_property_string(udi, "block.fileSystem", mp->fs_type); - hal_device_set_property_bool(udi, "volume.isMounted", TRUE); + hal_device_set_property_bool(udi, "block.isMounted", TRUE); found_mount_point = TRUE; } @@ -319,10 +319,9 @@ void etc_mtab_process_all_block_devices(dbus_bool_t setup_watcher) /* No mount point found; (possibly) remove all information */ if( !found_mount_point ) { - hal_device_set_property_bool(udi, "volume.isMounted", FALSE); - hal_device_remove_property(udi, "volume.mountPoint"); - hal_device_remove_property(udi, "volume.fileSystem"); - hal_device_remove_property(udi, "volume.device"); + hal_device_set_property_bool(udi, "block.isMounted", FALSE); + hal_device_remove_property(udi, "block.mountPoint"); + hal_device_remove_property(udi, "block.fileSystem"); } } @@ -625,12 +624,113 @@ static void device_removed(const char* udi) ethmon_remove(udi); } + +static DBusHandlerResult udev_filter_func(DBusConnection* connection, + DBusMessage* message, + void* user_data) +{ + char* filename; + char* sysfs_path; + char sysfs_dev_path[SYSFS_PATH_MAX]; + char* udi; + const char* object_path; + DBusError error; + + dbus_error_init(&error); + + object_path = dbus_message_get_path(message); + + /*printf("*** in udev_filter_func, object_path=%s\n", object_path);*/ + + if( dbus_message_is_signal(message, "org.kernel.udev.NodeMonitor", + "NodeCreated") ) + { + if( dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &filename, + DBUS_TYPE_STRING, &sysfs_path, + DBUS_TYPE_INVALID) ) + { + strncpy(sysfs_dev_path, sysfs_mount_path, SYSFS_PATH_MAX); + strncat(sysfs_dev_path, sysfs_path, SYSFS_PATH_MAX); + printf("NodeCreated: %s %s\n", filename, sysfs_dev_path); + + udi = find_udi_from_sysfs_path(sysfs_dev_path, + HAL_LINUX_HOTPLUG_TIMEOUT); + if( udi!=NULL ) + { + hal_device_set_property_string(udi, "block.device", filename); + } + } + } + else if( dbus_message_is_signal(message, "org.kernel.udev.NodeMonitor", + "NodeDeleted") ) + { + if( dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &filename, + DBUS_TYPE_STRING, &sysfs_path, + DBUS_TYPE_INVALID) ) + { + /* This is left intentionally blank since this means that a + * block device is removed and we'll catch that other places.. + + strncpy(sysfs_dev_path, sysfs_mount_path, SYSFS_PATH_MAX); + strncat(sysfs_dev_path, sysfs_path, SYSFS_PATH_MAX); + printf("NodeDeleted: %s %s\n", filename, sysfs_dev_path); + + udi = find_udi_from_sysfs_path(sysfs_dev_path, + HAL_LINUX_HOTPLUG_TIMEOUT); + if( udi!=NULL ) + { + hal_device_remove_property(udi, "block.device"); + } + */ + } + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + +static void setup_udev_listener() +{ + DBusError error; + DBusConnection* connection; + + /* Add filter for listening to udev */ + if( !dbus_connection_add_filter(dbus_connection, + udev_filter_func, NULL, NULL) ) + { + fprintf(stderr, "%s %d : Error creating connection handler\r\n", + __FILE__, __LINE__); + // TODO: clean up + return 1; + } + + dbus_error_init(&error); + dbus_bus_add_match(dbus_connection, + "type='signal'," + "interface='org.kernel.udev.NodeMonitor'," + /*"sender='org.kernel.udev',"*/ + "path='/org/kernel/udev/NodeMonitor'", &error); + + if( dbus_error_is_set(&error) ) + { + fprintf(stderr, "%s %d : Error subscribing to signals, " + "error=%s\r\n", + __FILE__, __LINE__, error.message); + // TODO: clean up + return 1; + } +} + /** Enter monitor mode * * @param loop G-Lib mainloop */ void hal_monitor_enter(GMainLoop* loop) { + DBusError error; + syslog(LOG_INFO, "Entering monitor mode.."); /* Find possible mount point for block devices and setup @@ -646,5 +746,10 @@ void hal_monitor_enter(GMainLoop* loop) hal_functions.device_removed = device_removed; hal_functions.device_new_capability = device_new_capability; + /* Setup listener for udev signals */ + setup_udev_listener(); + + + g_main_loop_run(loop); } diff --git a/agents/linux26/sysfs/main.c b/agents/linux26/sysfs/main.c index 30f9f90d..52eb2092 100644 --- a/agents/linux26/sysfs/main.c +++ b/agents/linux26/sysfs/main.c @@ -431,10 +431,10 @@ tryagain: return computed_udi; } -/** Given a sysfs-path for a device, this functions finds the HAL device - * representing the parent of the given device by truncating the sysfs - * path. There may not be a parent device, in which case this function - * returns #NULL. +/** Given a sysfs-path for a device, this functions finds the HAL + * device representing the the given device by looking at the sysfs + * path. There may not be a such a device, in which case this + * function returns #NULL. * * Optionally, the caller may specify for many how seconds to try. This is * useful for hotplug situations where the many hotplug events for a @@ -840,19 +840,13 @@ static void hal_sysfs_probe() { int rc; char path[SYSFS_PATH_MAX]; - char sysfs_path[SYSFS_PATH_MAX]; struct sysfs_directory* current; struct sysfs_directory* dir; is_probing = TRUE; - /* get mount path */ - rc = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX); - if( rc!=0 ) - DIE(("Couldn't get mount path for sysfs")); - /* traverse /sys/devices */ - snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, SYSFS_DEVICES_DIR); + snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_mount_path, SYSFS_DEVICES_DIR); dir = sysfs_open_directory(path); if( dir==NULL ) { @@ -898,7 +892,6 @@ static void device_hotplug_add(char* bus) int rc; const char* devpath; char path[SYSFS_PATH_MAX]; - char sysfs_path[SYSFS_PATH_MAX]; if( strcmp(bus, "input")==0 ) { @@ -912,12 +905,7 @@ static void device_hotplug_add(char* bus) if( devpath==NULL ) return; - /* get mount path for sysfs */ - rc = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX); - if( rc!=0 ) - DIE(("Couldn't get mount path for sysfs")); - - snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, devpath); + snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_mount_path, devpath); if( strcmp(bus, "usb")==0 ) { @@ -966,7 +954,6 @@ static void device_hotplug_remove(char* bus) const char* devpath; const char* device_udi = NULL; char path[SYSFS_PATH_MAX]; - char sysfs_path[SYSFS_PATH_MAX]; char** device_udis; int num_device_udis; @@ -983,14 +970,7 @@ static void device_hotplug_remove(char* bus) if( devpath==NULL ) return; - /* get mount path for sysfs */ - rc = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX); - if( rc!=0 ) - { - DIE(("Couldn't get mount path for sysfs")); - } - - snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_path, devpath); + snprintf(path, SYSFS_PATH_MAX, "%s%s", sysfs_mount_path, devpath); if( strcmp(bus, "usb")==0 ) { @@ -1117,21 +1097,13 @@ void drivers_collect(const char* bus_name) { int rc; char path[SYSFS_PATH_MAX]; - char sysfs_path[SYSFS_PATH_MAX]; struct sysfs_directory* current; struct sysfs_link* current2; struct sysfs_directory* dir; struct sysfs_directory* dir2; - /* get mount path for sysfs */ - rc = sysfs_get_mnt_path(sysfs_path, SYSFS_PATH_MAX); - if( rc!=0 ) - { - DIE(("Couldn't get mount path for sysfs")); - } - /* traverse /sys/bus/<bus>/drivers */ - snprintf(path, SYSFS_PATH_MAX, "%s/bus/%s/drivers", sysfs_path, bus_name); + snprintf(path, SYSFS_PATH_MAX, "%s/bus/%s/drivers", sysfs_mount_path, bus_name); dir = sysfs_open_directory(path); if( dir==NULL ) DIE(("Error opening sysfs directory at %s\n", path)); @@ -1165,13 +1137,20 @@ void drivers_collect(const char* bus_name) } +/** D-BUS connection object for out connection */ +DBusConnection* dbus_connection; + +/** Mount path for sysfs */ +char sysfs_mount_path[SYSFS_PATH_MAX]; + /** D-BUS mainloop integration for libhal. * - * @param dbus_connection D-BUS connection to integrate + * @param connection D-BUS connection to integrate */ -static void mainloop_integration(DBusConnection* dbus_connection) +static void mainloop_integration(DBusConnection* connection) { - dbus_connection_setup_with_g_main(dbus_connection, NULL); + dbus_connection = connection; + dbus_connection_setup_with_g_main(connection, NULL); } /** Usage */ @@ -1211,12 +1190,20 @@ LibHalFunctions hal_functions = {mainloop_integration, */ int main(int argc, char* argv[]) { + int rc; GMainLoop* loop; fprintf(stderr, "hal-sysfs-agent " PACKAGE_VERSION "\r\n"); loop = g_main_loop_new(NULL, FALSE); + /* get mount path for sysfs */ + rc = sysfs_get_mnt_path(sysfs_mount_path, SYSFS_PATH_MAX); + if( rc!=0 ) + { + DIE(("Couldn't get mount path for sysfs")); + } + if( hal_initialize(&hal_functions) ) { fprintf(stderr, "error: hal_initialize failed\r\n"); diff --git a/agents/linux26/sysfs/main.h b/agents/linux26/sysfs/main.h index bbb37ad7..957dc7a8 100644 --- a/agents/linux26/sysfs/main.h +++ b/agents/linux26/sysfs/main.h @@ -104,6 +104,10 @@ void drivers_collect(const char* bus_name); extern LibHalFunctions hal_functions; +extern DBusConnection* dbus_connection; + +extern char sysfs_mount_path[SYSFS_PATH_MAX]; + /* @} */ #endif /* MAIN_H */ diff --git a/examples/volumed/volumed.py b/examples/volumed/volumed.py new file mode 100755 index 00000000..5ace4793 --- /dev/null +++ b/examples/volumed/volumed.py @@ -0,0 +1,99 @@ +#!/usr/bin/python + +import dbus +import gtk +import time + +# This is just a very very crude example of what a volume daemon could +# look like... It actually doesn't mount anything; it only prints out +# messages when it should mount/unmount stuff. +# +# A volume daemon should also support optical and floppy disks, it should +# handle multi-session cdroms and much more. Maybe someone will write +# this one day... +# + +def get_mount_point(udi, device_name): + """Given a the UDI for a device and the name of the device file, + determine a name for the mount point""" + return '/mnt/somewhere/unique%f'%(time.time()) + +def attempt_mount(udi): + """See if a block device has enough information so we can mount it""" + dobj = hal_service.get_object(udi, 'org.freedesktop.Hal.Device') + if (not mount_dict.has_key(udi)) and dobj.PropertyExists('block.device'): + device = dobj.GetProperty('block.device') + mount_point = get_mount_point(udi, device) + print "mounting device=%s at %s udi=%s"%(device, mount_point, udi) + mount_dict[udi] = mount_point + +def unmount(udi): + """Unmount a device""" + mount_point = mount_dict[udi] + print "unmounting %s"%mount_point + del mount_dict[udi] + +def device_changed(dbus_if, member, svc, obj_path, message): + """Called when properties on a HAL device changes""" + print member + udi = obj_path + if udi in vol_list: + attempt_mount(udi) + +def gdl_changed(dbus_if, member, svc, obj_path, message): + """Called when a HAL device is added, removed or it got a + new capability""" + print member + if member=='NewCapability': + [udi, cap] = message.get_args_list() + if cap=='volume': + if not udi in vol_list: + vol_list.append(udi) + bus.add_signal_receiver(device_changed, + 'org.freedesktop.Hal.Device', + 'org.freedesktop.Hal', + udi) + attempt_mount(udi) + + print " %s %s"%(cap,udi) + + elif member=='DeviceRemoved': + [udi] = message.get_args_list() + if udi in vol_list: + vol_list.remove(udi) + bus.remove_signal_receiver(device_changed, + 'org.freedesktop.Hal.Device', + 'org.freedesktop.Hal', + udi) + unmount(udi) + + elif member=='DeviceAdded': + [udi] = message.get_args_list() + dobj = hal_service.get_object(udi, 'org.freedesktop.Hal.Device') + if dobj.QueryCapability('volume'): + vol_list.append(udi) + bus.add_signal_receiver(device_changed, + 'org.freedesktop.Hal.Device', + 'org.freedesktop.Hal', + udi) + attempt_mount(udi) + +def main(): + """Entry point""" + global bus, hal_service, vol_list, mount_dict + + vol_list = [] + mount_dict = {} + + bus = dbus.Bus(dbus.Bus.TYPE_SYSTEM) + hal_service = bus.get_service('org.freedesktop.Hal') + + bus.add_signal_receiver(gdl_changed, + 'org.freedesktop.Hal.Manager', + 'org.freedesktop.Hal', + '/org/freedesktop/Hal/Manager') + + gtk.mainloop() + +if __name__=='__main__': + main() diff --git a/hald/main.c b/hald/main.c index 65790c1c..5229767b 100644 --- a/hald/main.c +++ b/hald/main.c @@ -1135,6 +1135,73 @@ static DBusHandlerResult device_property_exists(DBusConnection* connection, } +/** Determine if a device got a capability + * + * <pre> + * bool Device.QueryCapability(string capability_name) + * + * raises org.freedesktop.Hal.NoSuchDevice, + * </pre> + * + * @param connection D-BUS connection + * @param message Message + * @return What to do with the message + */ +static DBusHandlerResult device_query_capability(DBusConnection* connection, + DBusMessage* message) +{ + dbus_bool_t rc; + const char* udi; + const char* caps; + char* capability; + HalDevice* d; + DBusMessage *reply; + DBusError error; + DBusMessageIter iter; + + LOG_TRACE(("entering")); + + udi = dbus_message_get_path(message); + + d = ds_device_find(udi); + if( d==NULL ) + { + raise_no_such_device(connection, message, udi); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + dbus_error_init(&error); + if( !dbus_message_get_args(message, &error, + DBUS_TYPE_STRING, &capability, + DBUS_TYPE_INVALID) ) + { + raise_syntax(connection, message, "QueryCapability"); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; + } + + reply = dbus_message_new_method_return(message); + if( reply==NULL ) + DIE(("No memory")); + + rc = FALSE; + caps = ds_property_get_string(d, "Capabilities"); + if( caps!=NULL ) + { + if( strstr(caps, capability)!=NULL ) + rc = TRUE; + } + + dbus_message_iter_init(reply, &iter); + dbus_message_iter_append_boolean(&iter, rc); + + if( !dbus_connection_send(connection, reply, NULL) ) + DIE(("No memory")); + + dbus_message_unref(reply); + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + + /** Enable a device. * * <pre> @@ -1846,6 +1913,12 @@ static DBusHandlerResult filter_function(DBusConnection* connection, { return device_add_capability(connection, message); } + else if( dbus_message_is_method_call(message, + "org.freedesktop.Hal.Device", + "QueryCapability") ) + { + return device_query_capability(connection, message); + } return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; } diff --git a/libhal/libhal.c b/libhal/libhal.c index 3bf3a135..6f22397d 100644 --- a/libhal/libhal.c +++ b/libhal/libhal.c @@ -451,6 +451,8 @@ static DBusHandlerResult filter_func(DBusConnection* connection, object_path = dbus_message_get_path(message); + /*printf("*** in filter_func, object_path=%s\n", object_path);*/ + if( dbus_message_is_signal(message, "org.freedesktop.Hal.Manager", "DeviceAdded") ) { @@ -631,7 +633,11 @@ int hal_initialize(const LibHalFunctions* cb_functions) } // TODO: narrow in instead of match *all* signals - dbus_bus_add_match(connection, "type='signal',interface='org.freedesktop.Hal.Manager',sender='org.freedesktop.Hal',path='/org/freedesktop/Hal/Manager'", &error); + dbus_bus_add_match(connection, + "type='signal'," + "interface='org.freedesktop.Hal.Manager'," + "sender='org.freedesktop.Hal'," + "path='/org/freedesktop/Hal/Manager'", &error); if( dbus_error_is_set(&error) ) { fprintf(stderr, "%s %d : Error subscribing to signals, " |