static BOOL hal_enumerate_devices(void) { LibHalContext *ctx; DBusError error; int i, num; char **list; if (!p_libhal_ctx_new) return FALSE; if (!(ctx = p_libhal_ctx_new())) return FALSE; p_libhal_ctx_set_dbus_connection( ctx, connection ); p_libhal_ctx_set_device_added( ctx, hal_new_device ); p_libhal_ctx_set_device_removed( ctx, hal_removed_device ); p_libhal_ctx_set_device_property_modified( ctx, hal_property_modified ); p_dbus_error_init( &error ); if (!p_libhal_ctx_init( ctx, &error )) { WARN( "HAL context init failed: %s\n", error.message ); p_dbus_error_free( &error ); return FALSE; } /* retrieve all existing devices */ if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error ); else { for (i = 0; i < num; i++) hal_new_device( ctx, list[i] ); p_libhal_free_string_array( list ); } return TRUE; }
static BOOL udisks_enumerate_devices(void) { DBusMessage *request, *reply; DBusError error; char **paths; int i, count; request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices" ); if (!request) return FALSE; p_dbus_error_init( &error ); reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error ); p_dbus_message_unref( request ); if (!reply) { WARN( "failed: %s\n", error.message ); p_dbus_error_free( &error ); return FALSE; } p_dbus_error_free( &error ); if (p_dbus_message_get_args( reply, &error, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &paths, &count, DBUS_TYPE_INVALID )) { for (i = 0; i < count; i++) udisks_new_device( paths[i] ); p_dbus_free_string_array( paths ); } else WARN( "unexpected args in EnumerateDevices reply\n" ); p_dbus_message_unref( reply ); return TRUE; }
static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, void *user_data ) { char *path; DBusError error; p_dbus_error_init( &error ); if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceAdded" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_new_device( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceRemoved" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_removed_device( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceChanged" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_changed_device( path ); } else TRACE( "ignoring message type=%d path=%s interface=%s method=%s\n", p_dbus_message_get_type( msg ), p_dbus_message_get_path( msg ), p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ) ); p_dbus_error_free( &error ); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
/* HAL callback for new device */ static void new_device( LibHalContext *ctx, const char *udi ) { DBusError error; char *parent, *mount_point, *device, *type; p_dbus_error_init( &error ); if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) goto done; if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error ))) goto done; if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error ))) goto done; if (!p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error )) goto done; if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error ))) p_dbus_error_free( &error ); /* ignore error */ add_dos_device( udi, device, mount_point, type ); if (type) p_libhal_free_string( type ); p_libhal_free_string( parent ); p_libhal_free_string( device ); p_libhal_free_string( mount_point ); /* add property watch for mount point */ p_libhal_device_add_property_watch( ctx, udi, &error ); done: p_dbus_error_free( &error ); }
static DWORD WINAPI hal_thread( void *arg ) { DBusError error; DBusConnection *dbc; LibHalContext *ctx; int i, num; char **list; if (!(ctx = p_libhal_ctx_new())) return 1; p_dbus_error_init( &error ); if (!(dbc = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error ))) { WINE_WARN( "failed to get system dbus connection: %s\n", error.message ); p_dbus_error_free( &error ); return 1; } p_libhal_ctx_set_dbus_connection( ctx, dbc ); p_libhal_ctx_set_device_added( ctx, new_device ); p_libhal_ctx_set_device_removed( ctx, removed_device ); p_libhal_ctx_set_device_property_modified( ctx, property_modified ); if (!p_libhal_ctx_init( ctx, &error )) { WINE_WARN( "HAL context init failed: %s\n", error.message ); p_dbus_error_free( &error ); return 1; } /* retrieve all existing devices */ if (!(list = p_libhal_get_all_devices( ctx, &num, &error ))) p_dbus_error_free( &error ); else { for (i = 0; i < num; i++) new_device( ctx, list[i] ); p_libhal_free_string_array( list ); } __TRY { while (p_dbus_connection_read_write_dispatch( dbc, -1 )) /* nothing */ ; } __EXCEPT( assert_fault ) { WINE_WARN( "dbus assertion failure, disabling HAL support\n" ); return 1; } __ENDTRY; p_libhal_ctx_shutdown( ctx, &error ); p_dbus_error_free( &error ); /* just in case */ p_dbus_connection_close( dbc ); p_libhal_ctx_free( ctx ); return 0; }
/* HAL callback for removed device */ static void hal_removed_device( LibHalContext *ctx, const char *udi ) { DBusError error; TRACE( "removed %s\n", wine_dbgstr_a(udi) ); if (!remove_dos_device( -1, udi )) { p_dbus_error_init( &error ); p_libhal_device_remove_property_watch( ctx, udi, &error ); p_dbus_error_free( &error ); } else remove_volume( udi ); }
/* HAL callback for new device */ static void hal_new_device( LibHalContext *ctx, const char *udi ) { DBusError error; char *parent = NULL; char *mount_point = NULL; char *device = NULL; char *type = NULL; char *uuid_str = NULL; GUID guid, *guid_ptr = NULL; enum device_type drive_type; p_dbus_error_init( &error ); if (!(device = p_libhal_device_get_property_string( ctx, udi, "block.device", &error ))) goto done; if (!(mount_point = p_libhal_device_get_property_string( ctx, udi, "volume.mount_point", &error ))) goto done; if (!(parent = p_libhal_device_get_property_string( ctx, udi, "info.parent", &error ))) goto done; if (!(uuid_str = p_libhal_device_get_property_string( ctx, udi, "volume.uuid", &error ))) p_dbus_error_free( &error ); /* ignore error */ else guid_ptr = parse_uuid( &guid, uuid_str ); if (!(type = p_libhal_device_get_property_string( ctx, parent, "storage.drive_type", &error ))) p_dbus_error_free( &error ); /* ignore error */ if (type && !strcmp( type, "cdrom" )) drive_type = DEVICE_CDROM; else if (type && !strcmp( type, "floppy" )) drive_type = DEVICE_FLOPPY; else drive_type = DEVICE_UNKNOWN; if (p_libhal_device_get_property_bool( ctx, parent, "storage.removable", &error )) { add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr ); /* add property watch for mount point */ p_libhal_device_add_property_watch( ctx, udi, &error ); } else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); done: if (type) p_libhal_free_string( type ); if (parent) p_libhal_free_string( parent ); if (device) p_libhal_free_string( device ); if (uuid_str) p_libhal_free_string( uuid_str ); if (mount_point) p_libhal_free_string( mount_point ); p_dbus_error_free( &error ); }
static DWORD WINAPI dbus_thread( void *arg ) { static const char udisks_match[] = "type='signal'," "interface='org.freedesktop.UDisks'," "sender='org.freedesktop.UDisks'"; DBusError error; p_dbus_error_init( &error ); if (!(connection = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error ))) { WARN( "failed to get system dbus connection: %s\n", error.message ); p_dbus_error_free( &error ); return 1; } if (p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL )) p_dbus_bus_add_match( connection, udisks_match, &error ); if (!udisks_enumerate_devices()) { p_dbus_bus_remove_match( connection, udisks_match, &error ); p_dbus_connection_remove_filter( connection, udisks_filter, NULL ); #ifdef SONAME_LIBHAL if (!hal_enumerate_devices()) { p_dbus_connection_close( connection ); p_dbus_error_free( &error ); return 1; } #endif } __TRY { while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ; } __EXCEPT( assert_fault ) { WARN( "dbus assertion failure, disabling support\n" ); return 1; } __ENDTRY; p_dbus_connection_close( connection ); return 0; }
static DBusHandlerResult udisks_filter( DBusConnection *ctx, DBusMessage *msg, void *user_data ) { char *path; DBusError error; p_dbus_error_init( &error ); /* udisks signals */ if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceAdded" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_new_device( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceRemoved" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_removed_device( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.UDisks", "DeviceChanged" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_changed_device( path ); } /* udisks2 signals */ else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesAdded" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { TRACE( "added %s\n", wine_dbgstr_a(path) ); udisks2_add_devices( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.ObjectManager", "InterfacesRemoved" ) && p_dbus_message_get_args( msg, &error, DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID )) { udisks_removed_device( path ); } else if (p_dbus_message_is_signal( msg, "org.freedesktop.DBus.Properties", "PropertiesChanged" )) { const char *udi = p_dbus_message_get_path( msg ); TRACE( "changed %s\n", wine_dbgstr_a(udi) ); udisks2_add_devices( udi ); } else TRACE( "ignoring message type=%d path=%s interface=%s method=%s\n", p_dbus_message_get_type( msg ), p_dbus_message_get_path( msg ), p_dbus_message_get_interface( msg ), p_dbus_message_get_member( msg ) ); p_dbus_error_free( &error ); return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; }
/* HAL callback for removed device */ static void removed_device( LibHalContext *ctx, const char *udi ) { DBusError error; struct dos_drive *drive; WINE_TRACE( "removed %s\n", wine_dbgstr_a(udi) ); LIST_FOR_EACH_ENTRY( drive, &drives_list, struct dos_drive, entry ) { if (strcmp( udi, drive->udi )) continue; p_dbus_error_init( &error ); p_libhal_device_remove_property_watch( ctx, udi, &error ); remove_dos_device( drive ); p_dbus_error_free( &error ); return; } }
/* UDisks2 is almost, but not quite, entirely unlike UDisks. * It would have been easy to make it backwards compatible, but where would be the fun in that? */ static BOOL udisks2_add_devices( const char *changed ) { DBusMessage *request, *reply; DBusMessageIter dict, iter, block; DBusError error; const char *udi; request = p_dbus_message_new_method_call( "org.freedesktop.UDisks2", "/org/freedesktop/UDisks2", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects" ); if (!request) return FALSE; p_dbus_error_init( &error ); reply = p_dbus_connection_send_with_reply_and_block( connection, request, udisks_timeout, &error ); p_dbus_message_unref( request ); if (!reply) { WARN( "failed: %s\n", error.message ); p_dbus_error_free( &error ); return FALSE; } p_dbus_error_free( &error ); p_dbus_message_iter_init( reply, &dict ); if (p_dbus_message_iter_get_arg_type( &dict ) == DBUS_TYPE_ARRAY) { p_dbus_message_iter_recurse( &dict, &iter ); while ((udi = udisks_next_dict_entry( &iter, &block ))) { if (!starts_with( udi, "/org/freedesktop/UDisks2/block_devices/" )) continue; if (changed && strcmp( changed, udi )) continue; udisks2_add_device( udi, &dict, &block ); } } else WARN( "unexpected args in GetManagedObjects reply\n" ); p_dbus_message_unref( reply ); return TRUE; }
/* UDisks callback for new device */ static void udisks_new_device( const char *udi ) { static const char *dev_name = "org.freedesktop.UDisks.Device"; DBusMessage *request, *reply; DBusMessageIter iter, variant; DBusError error; const char *device = NULL; const char *mount_point = NULL; const char *type = NULL; GUID guid, *guid_ptr = NULL; int removable = FALSE; enum device_type drive_type = DEVICE_UNKNOWN; request = p_dbus_message_new_method_call( "org.freedesktop.UDisks", udi, "org.freedesktop.DBus.Properties", "GetAll" ); if (!request) return; p_dbus_message_iter_init_append( request, &iter ); p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dev_name ); p_dbus_error_init( &error ); reply = p_dbus_connection_send_with_reply_and_block( connection, request, -1, &error ); p_dbus_message_unref( request ); if (!reply) { WARN( "failed: %s\n", error.message ); p_dbus_error_free( &error ); return; } p_dbus_error_free( &error ); p_dbus_message_iter_init( reply, &iter ); if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY) { const char *name; p_dbus_message_iter_recurse( &iter, &iter ); while ((name = udisks_next_dict_entry( &iter, &variant ))) { if (!strcmp( name, "DeviceFile" )) p_dbus_message_iter_get_basic( &variant, &device ); else if (!strcmp( name, "DeviceIsRemovable" )) p_dbus_message_iter_get_basic( &variant, &removable ); else if (!strcmp( name, "IdType" )) p_dbus_message_iter_get_basic( &variant, &type ); else if (!strcmp( name, "DriveMediaCompatibility" )) { DBusMessageIter media; p_dbus_message_iter_recurse( &variant, &media ); while (p_dbus_message_iter_get_arg_type( &media ) == DBUS_TYPE_STRING) { const char *media_type; p_dbus_message_iter_get_basic( &media, &media_type ); if (!strncmp( media_type, "optical_dvd", 11 )) drive_type = DEVICE_DVD; if (!strncmp( media_type, "floppy", 6 )) drive_type = DEVICE_FLOPPY; else if (!strncmp( media_type, "optical_", 8 ) && drive_type == DEVICE_UNKNOWN) drive_type = DEVICE_CDROM; p_dbus_message_iter_next( &media ); } } else if (!strcmp( name, "DeviceMountPaths" )) { DBusMessageIter paths; p_dbus_message_iter_recurse( &variant, &paths ); if (p_dbus_message_iter_get_arg_type( &paths ) == DBUS_TYPE_STRING) p_dbus_message_iter_get_basic( &paths, &mount_point ); } else if (!strcmp( name, "IdUuid" )) { char *uuid_str; p_dbus_message_iter_get_basic( &variant, &uuid_str ); guid_ptr = parse_uuid( &guid, uuid_str ); } } } TRACE( "udi %s device %s mount point %s uuid %s type %s removable %u\n", debugstr_a(udi), debugstr_a(device), debugstr_a(mount_point), debugstr_guid(guid_ptr), debugstr_a(type), removable ); if (type) { if (!strcmp( type, "iso9660" )) { removable = TRUE; drive_type = DEVICE_CDROM; } else if (!strcmp( type, "udf" )) { removable = TRUE; drive_type = DEVICE_DVD; } } if (device) { if (removable) add_dos_device( -1, udi, device, mount_point, drive_type, guid_ptr ); else if (guid_ptr) add_volume( udi, device, mount_point, DEVICE_HARDDISK_VOL, guid_ptr ); } p_dbus_message_unref( reply ); }
static DWORD WINAPI dbus_thread( void *arg ) { static const char udisks_match[] = "type='signal'," "interface='org.freedesktop.UDisks'," "sender='org.freedesktop.UDisks'"; static const char udisks2_match_interfaces[] = "type='signal'," "interface='org.freedesktop.DBus.ObjectManager'," "path='/org/freedesktop/UDisks2'"; static const char udisks2_match_properties[] = "type='signal'," "interface='org.freedesktop.DBus.Properties'"; DBusError error; p_dbus_error_init( &error ); if (!(connection = p_dbus_bus_get( DBUS_BUS_SYSTEM, &error ))) { WARN( "failed to get system dbus connection: %s\n", error.message ); p_dbus_error_free( &error ); return 1; } /* first try UDisks2 */ p_dbus_connection_add_filter( connection, udisks_filter, NULL, NULL ); p_dbus_bus_add_match( connection, udisks2_match_interfaces, &error ); p_dbus_bus_add_match( connection, udisks2_match_properties, &error ); if (udisks2_add_devices( NULL )) goto found; p_dbus_bus_remove_match( connection, udisks2_match_interfaces, &error ); p_dbus_bus_remove_match( connection, udisks2_match_properties, &error ); /* then try UDisks */ p_dbus_bus_add_match( connection, udisks_match, &error ); if (udisks_enumerate_devices()) goto found; p_dbus_bus_remove_match( connection, udisks_match, &error ); p_dbus_connection_remove_filter( connection, udisks_filter, NULL ); /* then finally HAL */ #ifdef SONAME_LIBHAL if (!hal_enumerate_devices()) { p_dbus_error_free( &error ); return 1; } #endif found: __TRY { while (p_dbus_connection_read_write_dispatch( connection, -1 )) /* nothing */ ; } __EXCEPT( assert_fault ) { WARN( "dbus assertion failure, disabling support\n" ); return 1; } __ENDTRY; return 0; }