diff options
-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, " |