From 2f01543464e992a8cc6098590486f26fbeb394ad Mon Sep 17 00:00:00 2001 From: David Zeuthen Date: Fri, 22 Jan 2010 13:29:09 -0500 Subject: [PATCH] First cut at device-mapper multipath support --- data/org.freedesktop.UDisks.Device.xml | 51 +++++ src/device-private.c | 69 +++++++ src/device-private.h | 16 ++ src/device.c | 340 +++++++++++++++++++++++++++++-- src/helpers/job-create-partition-table.c | 11 +- src/helpers/job-create-partition.c | 51 ++--- src/helpers/job-delete-partition.c | 66 +++--- src/probers/part-id.c | 331 ++++++++++++++++++++++++------ src/probers/udisks-dm-export.c | 281 ++++++++++++++++++++----- tools/udisks.c | 55 +++++ 10 files changed, 1086 insertions(+), 185 deletions(-) diff --git a/data/org.freedesktop.UDisks.Device.xml b/data/org.freedesktop.UDisks.Device.xml index 7114b86..84d38d2 100644 --- a/data/org.freedesktop.UDisks.Device.xml +++ b/data/org.freedesktop.UDisks.Device.xml @@ -1471,6 +1471,13 @@ UNIX special device file for device. Example: /dev/sda. + + + If not blank, the preferred device file (typically a symlink to the value of the DeviceFile property) to present in user interface. + Example: /dev/mapper/mpathb or + /dev/vg_phobos/lv_root. + + Symlinks to UNIX special device file that are stable and uniquely identifies the device. @@ -1606,6 +1613,16 @@ TRUE if the device is a Linux LVM2 physical. See LinuxLvm2PV properties for details. + + + TRUE if the device is a component (e.g. active path) of a Linux dm-multipath device. + + + + + TRUE if the device is a Linux dm-multipath device. + + The size of the device in bytes. @@ -2704,6 +2721,40 @@ + + + + + + + The object path of the multi-path device the component is currently part of. + This property is only valid if + DeviceIsLinuxDmmpComponent + is TRUE. + + + + + + + + + + The symbolic name for the multipath device, e.g. mpathb. + This property is only valid if + DeviceIsLinuxDmmp + is TRUE. + + + + + The object paths of currently active component devices, e.g. paths. + This property is only valid if + DeviceIsLinuxDmmp + is TRUE. + + + diff --git a/src/device-private.c b/src/device-private.c index 4d3a7db..7d53ca2 100644 --- a/src/device-private.c +++ b/src/device-private.c @@ -199,6 +199,18 @@ device_set_device_file (Device *device, } void +device_set_device_file_presentation (Device *device, + const gchar *value) +{ + if (G_UNLIKELY (g_strcmp0 (device->priv->device_file_presentation, value) != 0)) + { + g_free (device->priv->device_file_presentation); + device->priv->device_file_presentation = g_strdup (value); + emit_changed (device, "device_file_presentation"); + } +} + +void device_set_device_file_by_id (Device *device, GStrv value) { @@ -419,6 +431,26 @@ device_set_device_is_linux_lvm2_pv (Device *device, gboolean value) } void +device_set_device_is_linux_dmmp (Device *device, gboolean value) +{ + if (G_UNLIKELY (device->priv->device_is_linux_dmmp != value)) + { + device->priv->device_is_linux_dmmp = value; + emit_changed (device, "device_is_linux_dmmp"); + } +} + +void +device_set_device_is_linux_dmmp_component (Device *device, gboolean value) +{ + if (G_UNLIKELY (device->priv->device_is_linux_dmmp_component != value)) + { + device->priv->device_is_linux_dmmp_component = value; + emit_changed (device, "device_is_linux_dmmp_component"); + } +} + +void device_set_device_size (Device *device, guint64 value) { @@ -1501,3 +1533,40 @@ device_set_linux_lvm2_pv_group_logical_volumes (Device *device, emit_changed (device, "linux_lvm2_pv_group_logical_volumes"); } } + + +void +device_set_linux_dmmp_component_holder (Device *device, + const gchar *value) +{ + if (G_UNLIKELY (g_strcmp0 (device->priv->linux_dmmp_component_holder, value) != 0)) + { + g_free (device->priv->linux_dmmp_component_holder); + device->priv->linux_dmmp_component_holder = g_strdup (value); + emit_changed (device, "linux_dmmp_component_holder"); + } +} + +void +device_set_linux_dmmp_name (Device *device, + const gchar *value) +{ + if (G_UNLIKELY (g_strcmp0 (device->priv->linux_dmmp_name, value) != 0)) + { + g_free (device->priv->linux_dmmp_name); + device->priv->linux_dmmp_name = g_strdup (value); + emit_changed (device, "linux_dmmp_name"); + } +} + +void +device_set_linux_dmmp_slaves (Device *device, + GStrv value) +{ + if (G_UNLIKELY (!ptr_str_array_equals_strv (device->priv->linux_dmmp_slaves, value))) + { + ptr_str_array_free (device->priv->linux_dmmp_slaves); + device->priv->linux_dmmp_slaves = ptr_str_array_from_strv (value); + emit_changed (device, "linux_dmmp_slaves"); + } +} diff --git a/src/device-private.h b/src/device-private.h index 695acb4..1394ab8 100644 --- a/src/device-private.h +++ b/src/device-private.h @@ -96,6 +96,7 @@ struct DevicePrivate /**************/ char *device_file; + char *device_file_presentation; dev_t dev; GPtrArray *device_file_by_id; GPtrArray *device_file_by_path; @@ -117,6 +118,8 @@ struct DevicePrivate gboolean device_is_linux_md; gboolean device_is_linux_lvm2_lv; gboolean device_is_linux_lvm2_pv; + gboolean device_is_linux_dmmp; + gboolean device_is_linux_dmmp_component; guint64 device_size; guint64 device_block_size; gboolean device_is_mounted; @@ -222,6 +225,11 @@ struct DevicePrivate void *drive_ata_smart_blob; gsize drive_ata_smart_blob_size; + gchar *linux_dmmp_component_holder; + + gchar *linux_dmmp_name; + GPtrArray *linux_dmmp_slaves; + /* the following properties are not (yet) exported */ char *dm_name; GPtrArray *slaves_objpath; @@ -239,6 +247,7 @@ void device_set_job_percentage (Device *device, gdouble value); void device_set_device_detection_time (Device *device, guint64 value); void device_set_device_media_detection_time (Device *device, guint64 value); void device_set_device_file (Device *device, const gchar *value); +void device_set_device_file_presentation (Device *device, const gchar *value); void device_set_device_file_by_id (Device *device, GStrv value); void device_set_device_file_by_path (Device *device, GStrv value); void device_set_device_is_system_internal (Device *device, gboolean value); @@ -259,6 +268,8 @@ void device_set_device_is_linux_md_component (Device *device, gboolean value); void device_set_device_is_linux_md (Device *device, gboolean value); void device_set_device_is_linux_lvm2_lv (Device *device, gboolean value); void device_set_device_is_linux_lvm2_pv (Device *device, gboolean value); +void device_set_device_is_linux_dmmp (Device *device, gboolean value); +void device_set_device_is_linux_dmmp_component (Device *device, gboolean value); void device_set_device_size (Device *device, guint64 value); void device_set_device_block_size (Device *device, guint64 value); void device_set_device_is_mounted (Device *device, gboolean value); @@ -357,6 +368,11 @@ void device_set_linux_lvm2_pv_group_extent_size (Device *device, guint64 value); void device_set_linux_lvm2_pv_group_physical_volumes (Device *device, GStrv value); void device_set_linux_lvm2_pv_group_logical_volumes (Device *device, GStrv value); +void device_set_linux_dmmp_component_holder (Device *device, const gchar *value); + +void device_set_linux_dmmp_name (Device *device, const gchar *value); +void device_set_linux_dmmp_slaves (Device *device, GStrv value); + void device_set_dm_name (Device *device, const gchar *value); void device_set_slaves_objpath (Device *device, GStrv value); void device_set_holders_objpath (Device *device, GStrv value); diff --git a/src/device.c b/src/device.c index 3ed95fe..83f88e3 100644 --- a/src/device.c +++ b/src/device.c @@ -135,6 +135,17 @@ static void force_luks_teardown (Device *device, ForceRemovalCompleteFunc callback, gpointer user_data); +/* TODO: this is kinda a hack */ +static const gchar * +get_dmmp_device_node (Device *device) +{ + static gchar buf[1024]; + + g_assert (device->priv->device_is_linux_dmmp); + g_snprintf (buf, sizeof (buf), "/dev/mapper/%s", device->priv->linux_dmmp_name); + return buf; +} + enum { PROP_0, @@ -145,6 +156,7 @@ enum PROP_DEVICE_MAJOR, PROP_DEVICE_MINOR, PROP_DEVICE_FILE, + PROP_DEVICE_FILE_PRESENTATION, PROP_DEVICE_FILE_BY_ID, PROP_DEVICE_FILE_BY_PATH, PROP_DEVICE_IS_SYSTEM_INTERNAL, @@ -165,6 +177,8 @@ enum PROP_DEVICE_IS_LINUX_MD, PROP_DEVICE_IS_LINUX_LVM2_LV, PROP_DEVICE_IS_LINUX_LVM2_PV, + PROP_DEVICE_IS_LINUX_DMMP, + PROP_DEVICE_IS_LINUX_DMMP_COMPONENT, PROP_DEVICE_SIZE, PROP_DEVICE_BLOCK_SIZE, PROP_DEVICE_IS_MOUNTED, @@ -273,6 +287,11 @@ enum PROP_LINUX_LVM2_PV_GROUP_EXTENT_SIZE, PROP_LINUX_LVM2_PV_GROUP_PHYSICAL_VOLUMES, PROP_LINUX_LVM2_PV_GROUP_LOGICAL_VOLUMES, + + PROP_LINUX_DMMP_COMPONENT_HOLDER, + + PROP_LINUX_DMMP_NAME, + PROP_LINUX_DMMP_SLAVES, }; enum @@ -333,6 +352,9 @@ get_property (GObject *object, case PROP_DEVICE_FILE: g_value_set_string (value, device->priv->device_file); break; + case PROP_DEVICE_FILE_PRESENTATION: + g_value_set_string (value, device->priv->device_file_presentation); + break; case PROP_DEVICE_FILE_BY_ID: g_value_set_boxed (value, device->priv->device_file_by_id); break; @@ -393,6 +415,12 @@ get_property (GObject *object, case PROP_DEVICE_IS_LINUX_LVM2_PV: g_value_set_boolean (value, device->priv->device_is_linux_lvm2_pv); break; + case PROP_DEVICE_IS_LINUX_DMMP: + g_value_set_boolean (value, device->priv->device_is_linux_dmmp); + break; + case PROP_DEVICE_IS_LINUX_DMMP_COMPONENT: + g_value_set_boolean (value, device->priv->device_is_linux_dmmp_component); + break; case PROP_DEVICE_SIZE: g_value_set_uint64 (value, device->priv->device_size); break; @@ -723,6 +751,21 @@ get_property (GObject *object, g_value_set_boxed (value, device->priv->linux_lvm2_pv_group_logical_volumes); break; + case PROP_LINUX_DMMP_COMPONENT_HOLDER: + if (device->priv->linux_dmmp_component_holder != NULL) + g_value_set_boxed (value, device->priv->linux_dmmp_component_holder); + else + g_value_set_boxed (value, "/"); + break; + + case PROP_LINUX_DMMP_NAME: + g_value_set_string (value, device->priv->linux_dmmp_name); + break; + + case PROP_LINUX_DMMP_SLAVES: + g_value_set_boxed (value, device->priv->linux_dmmp_slaves); + break; + default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -804,11 +847,20 @@ device_class_init (DeviceClass *klass) G_MAXINT64, 0, G_PARAM_READABLE)); - g_object_class_install_property (object_class, PROP_DEVICE_FILE, g_param_spec_string ("device-file", - NULL, - NULL, - NULL, - G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_FILE, + g_param_spec_string ("device-file", + NULL, + NULL, + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_FILE_PRESENTATION, + g_param_spec_string ("device-file-presentation", + NULL, + NULL, + NULL, + G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_DEVICE_FILE_BY_ID, g_param_spec_boxed ("device-file-by-id", @@ -933,6 +985,20 @@ device_class_init (DeviceClass *klass) NULL, FALSE, G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_IS_LINUX_DMMP, + g_param_spec_boolean ("device-is-linux-dmmp", + NULL, + NULL, + FALSE, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_DEVICE_IS_LINUX_DMMP_COMPONENT, + g_param_spec_boolean ("device-is-linux-dmmp-component", + NULL, + NULL, + FALSE, + G_PARAM_READABLE)); g_object_class_install_property (object_class, PROP_DEVICE_SIZE, g_param_spec_uint64 ("device-size", NULL, @@ -1540,6 +1606,29 @@ device_class_init (DeviceClass *klass) NULL, dbus_g_type_get_collection ("GPtrArray", G_TYPE_STRING), G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_LINUX_DMMP_COMPONENT_HOLDER, + g_param_spec_boxed ("linux-dmmp-component-holder", + NULL, + NULL, + DBUS_TYPE_G_OBJECT_PATH, + G_PARAM_READABLE)); + + g_object_class_install_property (object_class, + PROP_LINUX_DMMP_NAME, + g_param_spec_string ("linux-dmmp-name", + NULL, + NULL, + NULL, + G_PARAM_READABLE)); + g_object_class_install_property (object_class, + PROP_LINUX_DMMP_SLAVES, + g_param_spec_boxed ("linux-dmmp-slaves", + NULL, + NULL, + dbus_g_type_get_collection ("GPtrArray", + DBUS_TYPE_G_OBJECT_PATH), + G_PARAM_READABLE)); } static void @@ -1557,6 +1646,7 @@ device_init (Device *device) device->priv->linux_md_slaves = g_ptr_array_new (); device->priv->linux_lvm2_pv_group_physical_volumes = g_ptr_array_new (); device->priv->linux_lvm2_pv_group_logical_volumes = g_ptr_array_new (); + device->priv->linux_dmmp_slaves = g_ptr_array_new (); device->priv->slaves_objpath = g_ptr_array_new (); device->priv->holders_objpath = g_ptr_array_new (); @@ -1608,6 +1698,7 @@ device_finalize (GObject *object) /* free properties */ g_free (device->priv->device_file); + g_free (device->priv->device_file_presentation); g_ptr_array_foreach (device->priv->device_file_by_id, (GFunc) g_free, NULL); g_ptr_array_foreach (device->priv->device_file_by_path, (GFunc) g_free, NULL); g_ptr_array_free (device->priv->device_file_by_id, TRUE); @@ -1668,6 +1759,12 @@ device_finalize (GObject *object) g_ptr_array_foreach (device->priv->linux_md_slaves, (GFunc) g_free, NULL); g_ptr_array_free (device->priv->linux_md_slaves, TRUE); + g_free (device->priv->linux_dmmp_component_holder); + + g_free (device->priv->linux_dmmp_name); + g_ptr_array_foreach (device->priv->linux_dmmp_slaves, (GFunc) g_free, NULL); + g_ptr_array_free (device->priv->linux_dmmp_slaves, TRUE); + g_free (device->priv->linux_lvm2_lv_name); g_free (device->priv->linux_lvm2_lv_uuid); g_free (device->priv->linux_lvm2_lv_group_name); @@ -2580,7 +2677,9 @@ update_info_drive (Device *device) device_set_drive_serial (device, g_udev_device_get_property (device->priv->d, "ID_SERIAL_SHORT")); } - if (g_udev_device_has_property (device->priv->d, "ID_WWN")) + if (g_udev_device_has_property (device->priv->d, "ID_WWN_WITH_EXTENSION")) + device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN_WITH_EXTENSION") + 2); + else if (g_udev_device_has_property (device->priv->d, "ID_WWN")) device_set_drive_wwn (device, g_udev_device_get_property (device->priv->d, "ID_WWN") + 2); /* pick up some things (vendor, model, connection_interface, connection_speed) @@ -2804,8 +2903,8 @@ update_info_luks_cleartext (Device *device) ret = FALSE; - dkd_dm_name = g_udev_device_get_property (device->priv->d, "UDISKS_DM_NAME"); - dkd_dm_target_types = g_udev_device_get_property (device->priv->d, "UDISKS_DM_TARGET_TYPES"); + dkd_dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME"); + dkd_dm_target_types = g_udev_device_get_property (device->priv->d, "UDISKS_DM_TARGETS_TYPE"); if (dkd_dm_name != NULL && g_strcmp0 (dkd_dm_target_types, "crypt") == 0 && device->priv->slaves_objpath->len == 1) { @@ -2913,6 +3012,182 @@ update_info_linux_lvm2_lv (Device *device) /* ---------------------------------------------------------------------------------------------------- */ +/* update device_is_linux_dmmp and linux_dmmp_* properties */ +static gboolean +update_info_linux_dmmp (Device *device) +{ + const gchar *dm_name; + const gchar* const *target_types; + gboolean is_dmmp; + guint n; + GPtrArray *p; + Device *component; + gchar *s; + + is_dmmp = FALSE; + p = NULL; + + dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME"); + if (dm_name == NULL) + goto out; + + target_types = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE"); + if (target_types == NULL || g_strcmp0 (target_types[0], "multipath") != 0) + goto out; + + if (device->priv->slaves_objpath->len == 0) + goto out; + + device_set_linux_dmmp_name (device, dm_name); + + p = g_ptr_array_new (); + for (n = 0; n < device->priv->slaves_objpath->len; n++) + { + const gchar *component_objpath = device->priv->slaves_objpath->pdata[n]; + if (component == NULL) + { + component = daemon_local_find_by_object_path (device->priv->daemon, component_objpath); + } + g_ptr_array_add (p, (gpointer) component_objpath); + } + g_ptr_array_add (p, NULL); + device_set_linux_dmmp_slaves (device, (GStrv) p->pdata); + + if (component == NULL) + goto out; + + /* copy some of the Drive* properties from the (first) components - we could check here whether + * it matches the other components and warn if it doesn't (it should) + * + * TODO: what about DriveAdapter and DrivePorts? Set them to NULL for now + */ + device_set_drive_vendor (device, component->priv->drive_vendor); + device_set_drive_model (device, component->priv->drive_model); + device_set_drive_revision (device, component->priv->drive_revision); + device_set_drive_serial (device, component->priv->drive_serial); + device_set_drive_wwn (device, component->priv->drive_wwn); + device_set_drive_connection_interface (device, "virtual_multipath"); + device_set_drive_connection_speed (device, 0); + /* GStrv vs GPtrArray.. device_set_drive_media_compatibility (device, component->priv->drive_media_compatibility); */ + device_set_drive_media (device, component->priv->drive_media); + device_set_drive_is_media_ejectable (device, component->priv->drive_is_media_ejectable); + device_set_drive_can_detach (device, component->priv->drive_can_detach); + device_set_drive_can_spindown (device, component->priv->drive_can_spindown); + device_set_drive_is_rotational (device, component->priv->drive_is_rotational); + device_set_drive_rotation_rate (device, component->priv->drive_rotation_rate); + device_set_drive_write_cache (device, component->priv->drive_write_cache); + + s = g_strdup_printf ("/dev/mapper/%s", dm_name); + device_set_device_file_presentation (device, s); + g_free (s); + + is_dmmp = TRUE; + + out: + if (p != NULL) + g_ptr_array_free (p, TRUE); + device_set_device_is_linux_dmmp (device, is_dmmp); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* updates device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device */ +static gboolean +update_info_partition_on_linux_dmmp (Device *device) +{ + const gchar *dm_name; + const gchar* const *targets_type; + const gchar* const *targets_params; + gchar *params; + gint partition_slave_major; + gint partition_slave_minor; + guint64 offset_sectors; + guint64 offset; + guint partition_number; + Device *partition_slave; + gchar *s; + + params = NULL; + + dm_name = g_udev_device_get_property (device->priv->d, "DM_NAME"); + if (dm_name == NULL) + goto out; + + targets_type = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_TYPE"); + if (targets_type == NULL || g_strcmp0 (targets_type[0], "linear") != 0) + goto out; + + targets_params = g_udev_device_get_property_as_strv (device->priv->d, "UDISKS_DM_TARGETS_PARAMS"); + if (targets_params == NULL) + goto out; + params = decode_udev_encoded_string (targets_params[0]); + + if (sscanf (params, + "%d:%d %" G_GUINT64_FORMAT, + &partition_slave_major, + &partition_slave_minor, + &offset_sectors) != 3) + goto out; + + partition_slave = daemon_local_find_by_dev (device->priv->daemon, + makedev (partition_slave_major, partition_slave_minor)); + if (partition_slave == NULL) + goto out; + + offset = offset_sectors * 512; + + device_set_partition_slave (device, partition_slave->priv->object_path); + device_set_partition_offset (device, offset); + device_set_partition_size (device, device->priv->device_size); + partition_number = g_udev_device_get_property_as_int (device->priv->d, "UDISKS_PARTITION_NUMBER"); + if (partition_number > 0) + device_set_partition_number (device, partition_number); + + /* all the other Partition* has been set as part of update_info_partition() by reading + * UDISKS_PARTITION_* properties + */ + + device_set_device_is_partition (device, TRUE); + device_set_device_is_drive (device, FALSE); + + s = g_strdup_printf ("/dev/mapper/%s", dm_name); + device_set_device_file_presentation (device, s); + g_free (s); + + out: + g_free (params); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +/* update device_is_linux_dmmp_component and linux_dmmp_component_* properties */ +static gboolean +update_info_linux_dmmp_component (Device *device) +{ + gboolean is_dmmp_component; + + is_dmmp_component = FALSE; + + if (device->priv->holders_objpath->len == 1) + { + Device *holder; + + holder = daemon_local_find_by_object_path (device->priv->daemon, device->priv->holders_objpath->pdata[0]); + if (holder != NULL && holder->priv->device_is_linux_dmmp) + { + is_dmmp_component = TRUE; + device_set_linux_dmmp_component_holder (device, holder->priv->object_path); + } + } + + device_set_device_is_linux_dmmp_component (device, is_dmmp_component); + return TRUE; +} + +/* ---------------------------------------------------------------------------------------------------- */ + /* update device_is_linux_lvm2_pv and linux_lvm2_pv_* properties */ static gboolean update_info_linux_lvm2_pv (Device *device) @@ -3799,9 +4074,9 @@ update_info (Device *device) goto out; } - /* ignore dm devices that are not active */ - if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-") - && g_udev_device_get_property (device->priv->d, "UDISKS_DM_STATE") == NULL) + /* ignore dm devices that are suspended */ + if (g_str_has_prefix (g_udev_device_get_name (device->priv->d), "dm-") && + g_strcmp0 (g_udev_device_get_property (device->priv->d, "DM_SUSPENDED"), "0") != 0) goto out; major = g_udev_device_get_property_as_int (device->priv->d, "MAJOR"); @@ -4086,6 +4361,18 @@ update_info (Device *device) if (!update_info_linux_lvm2_pv (device)) goto out; + /* device_is_linux_dmmp and linux_dmmp_* properties */ + if (!update_info_linux_dmmp (device)) + goto out; + + /* device_is_partition and partition_* properties for dm-0 "partitions" on a multi-path device */ + if (!update_info_partition_on_linux_dmmp (device)) + goto out; + + /* device_is_linux_dmmp_component and linux_dmmp_component_* properties */ + if (!update_info_linux_dmmp_component (device)) + goto out; + /* device_is_linux_md_component and linux_md_component_* properties */ if (!update_info_linux_md_component (device)) goto out; @@ -4273,8 +4560,19 @@ device_local_is_busy (Device *device, /* or if another block device is using/holding us (e.g. if holders/ is non-empty in sysfs) */ if (device->priv->holders_objpath->len > 0) { - g_set_error (error, ERROR, ERROR_BUSY, "One or more block devices are holding %s", device->priv->device_file); - goto out; + if (device->priv->device_is_linux_dmmp) + { + /* This is OK */ + } + else + { + g_set_error (error, + ERROR, + ERROR_BUSY, + "One or more block devices are holding %s", + device->priv->device_file); + goto out; + } } /* If we are an extended partition, we are also busy if one or more logical partitions are busy @@ -6690,7 +6988,10 @@ device_partition_delete_authorized_cb (Daemon *daemon, n = 0; argv[n++] = PACKAGE_LIBEXEC_DIR "/udisks-helper-delete-partition"; - argv[n++] = enclosing_device->priv->device_file; + if (enclosing_device->priv->device_is_linux_dmmp) + argv[n++] = (gchar *) get_dmmp_device_node (enclosing_device); + else + argv[n++] = enclosing_device->priv->device_file; argv[n++] = device->priv->device_file; argv[n++] = offset_as_string; argv[n++] = size_as_string; @@ -7528,8 +7829,10 @@ device_partition_create_authorized_cb (Daemon *daemon, n = 0; argv[n++] = PACKAGE_LIBEXEC_DIR "/udisks-helper-create-partition"; - argv[n++] = device->priv->device_file; - ; + if (device->priv->device_is_linux_dmmp) + argv[n++] = (gchar *) get_dmmp_device_node (device); + else + argv[n++] = device->priv->device_file; argv[n++] = offset_as_string; argv[n++] = size_as_string; argv[n++] = (char *) type; @@ -8002,7 +8305,10 @@ device_partition_table_create_authorized_cb (Daemon *daemon, n = 0; argv[n++] = PACKAGE_LIBEXEC_DIR "/udisks-helper-create-partition-table"; - argv[n++] = device->priv->device_file; + if (device->priv->device_is_linux_dmmp) + argv[n++] = (gchar *) get_dmmp_device_node (device); + else + argv[n++] = device->priv->device_file; argv[n++] = (char *) scheme; for (m = 0; options[m] != NULL; m++) { diff --git a/src/helpers/job-create-partition-table.c b/src/helpers/job-create-partition-table.c index 2051c08..c93223b 100644 --- a/src/helpers/job-create-partition-table.c +++ b/src/helpers/job-create-partition-table.c @@ -107,11 +107,14 @@ main (int argc, ret = 0; } - /* reread partition table */ - if (!reread_partition_table (device)) + /* tell kernel reread partition table (but only if we are a kernel partition) */ + if (!g_str_has_prefix (device, "/dev/mapper/mpath")) { - ret = 1; - goto out; + if (!reread_partition_table (device)) + { + ret = 1; + goto out; + } } out: diff --git a/src/helpers/job-create-partition.c b/src/helpers/job-create-partition.c index 8a8ee6b..f34fbfe 100644 --- a/src/helpers/job-create-partition.c +++ b/src/helpers/job-create-partition.c @@ -133,33 +133,36 @@ main (int argc, } } - /* OK, now tell the kernel about the newly added partition */ - fd = open (device, O_RDONLY); - if (fd < 0) + /* OK, now tell the kernel about the newly added partition (but only if we are a kernel partition) */ + if (!g_str_has_prefix (device, "/dev/mapper/mpath")) { - g_printerr ("Cannot open %s: %m\n", device); - goto out; - } - memset (&a, '\0', sizeof(struct blkpg_ioctl_arg)); - memset (&p, '\0', sizeof(struct blkpg_partition)); - p.pno = out_num; - p.start = out_start; - p.length = out_size; - a.op = BLKPG_ADD_PARTITION; - a.datalen = sizeof(p); - a.data = &p; - if (ioctl (fd, BLKPG, &a) == -1) - { - g_printerr ("Error doing BLKPG ioctl with BLKPG_ADD_PARTITION for partition %d " - "of size %" G_GUINT64_FORMAT " at offset %" G_GUINT64_FORMAT " on %s: %m\n", - out_num, - out_start, - out_size, - device); + fd = open (device, O_RDONLY); + if (fd < 0) + { + g_printerr ("Cannot open %s: %m\n", device); + goto out; + } + memset (&a, '\0', sizeof(struct blkpg_ioctl_arg)); + memset (&p, '\0', sizeof(struct blkpg_partition)); + p.pno = out_num; + p.start = out_start; + p.length = out_size; + a.op = BLKPG_ADD_PARTITION; + a.datalen = sizeof(p); + a.data = &p; + if (ioctl (fd, BLKPG, &a) == -1) + { + g_printerr ("Error doing BLKPG ioctl with BLKPG_ADD_PARTITION for partition %d " + "of size %" G_GUINT64_FORMAT " at offset %" G_GUINT64_FORMAT " on %s: %m\n", + out_num, + out_start, + out_size, + device); + close (fd); + goto out; + } close (fd); - goto out; } - close (fd); /* send the start and size back to the daemon - it needs to know, to * wait for the created partition, because the partition may not have diff --git a/src/helpers/job-delete-partition.c b/src/helpers/job-delete-partition.c index 1eca3fd..44945d2 100644 --- a/src/helpers/job-delete-partition.c +++ b/src/helpers/job-delete-partition.c @@ -91,35 +91,45 @@ main (int argc, goto out; } - /* don't ask libparted to poke the kernel - it won't work if other partitions are mounted/busy */ - if (part_del_partition ((char *) device, offset, FALSE)) - { - gint fd; - struct blkpg_ioctl_arg a; - struct blkpg_partition p; + gboolean is_kernel_partition; + is_kernel_partition = !g_str_has_prefix (device, "/dev/mapper/mpath"); - /* now, ask the kernel to delete the partition */ - fd = open (device, O_RDONLY); - if (fd < 0) - { - g_printerr ("Cannot open %s: %m\n", device); - goto out; - } - memset (&a, '\0', sizeof(struct blkpg_ioctl_arg)); - memset (&p, '\0', sizeof(struct blkpg_partition)); - p.pno = part_number; - a.op = BLKPG_DEL_PARTITION; - a.datalen = sizeof(p); - a.data = &p; - if (ioctl (fd, BLKPG, &a) == -1) + /* don't ask libparted to poke the kernel - it won't work if other + * partitions are mounted/busy (unless it's not a kernel partition) + */ + if (part_del_partition ((char *) device, + offset, + is_kernel_partition ? FALSE : TRUE)) + { + /* now, ask the kernel to delete the partition (but only if we are a kernel partition) */ + if (is_kernel_partition) { - g_printerr ("Error doing BLKPG ioctl with BLKPG_DEL_PARTITION for partition %d on %s: %m\n", - part_number, - device); + gint fd; + struct blkpg_ioctl_arg a; + struct blkpg_partition p; + + fd = open (device, O_RDONLY); + if (fd < 0) + { + g_printerr ("Cannot open %s: %m\n", device); + goto out; + } + memset (&a, '\0', sizeof(struct blkpg_ioctl_arg)); + memset (&p, '\0', sizeof(struct blkpg_partition)); + p.pno = part_number; + a.op = BLKPG_DEL_PARTITION; + a.datalen = sizeof(p); + a.data = &p; + if (ioctl (fd, BLKPG, &a) == -1) + { + g_printerr ("Error doing BLKPG ioctl with BLKPG_DEL_PARTITION for partition %d on %s: %m\n", + part_number, + device); + close (fd); + goto out; + } close (fd); - goto out; } - close (fd); /* zero the contents of what was the _partition_ * @@ -129,9 +139,9 @@ main (int argc, /* scrub signatures */ if (!scrub_signatures (device, offset, size)) { - g_printerr ("Cannot scrub filesystem signatures at " - "offset=%" G_GINT64_FORMAT " and size=%" G_GINT64_FORMAT "\n", - offset, size); + g_printerr ("Cannot scrub filesystem signatures at " + "offset=%" G_GINT64_FORMAT " and size=%" G_GINT64_FORMAT "\n", + offset, size); } else { diff --git a/src/probers/part-id.c b/src/probers/part-id.c index d6aebbc..b3d8f60 100644 --- a/src/probers/part-id.c +++ b/src/probers/part-id.c @@ -41,6 +41,53 @@ usage (int argc, exit (1); } +static gchar * +decode_udev_encoded_string (const gchar *str) +{ + GString *s; + gchar *ret; + const gchar *end_valid; + guint n; + + s = g_string_new (NULL); + for (n = 0; str[n] != '\0'; n++) + { + if (str[n] == '\\') + { + gint val; + + if (str[n + 1] != 'x' || str[n + 2] == '\0' || str[n + 3] == '\0') + { + g_print ("**** NOTE: malformed encoded string '%s'\n", str); + break; + } + + val = (g_ascii_xdigit_value (str[n + 2]) << 4) | g_ascii_xdigit_value (str[n + 3]); + + g_string_append_c (s, val); + + n += 3; + } + else + { + g_string_append_c (s, str[n]); + } + } + + if (!g_utf8_validate (s->str, -1, &end_valid)) + { + g_print ("**** NOTE: The string '%s' is not valid UTF-8. Invalid characters begins at '%s'\n", s->str, end_valid); + ret = g_strndup (s->str, end_valid - s->str); + g_string_free (s, TRUE); + } + else + { + ret = g_string_free (s, FALSE); + } + + return ret; +} + static int sysfs_get_int (const char *dir, const char *attribute) @@ -81,13 +128,220 @@ sysfs_get_uint64 (const char *dir, return result; } +/* ---------------------------------------------------------------------------------------------------- */ + +static gchar * +get_syspath (struct udev *udev, + const gchar *device_file) +{ + struct udev_device *device; + struct stat statbuf; + gchar *ret; + + ret = NULL; + + if (stat (device_file, &statbuf) != 0) + { + g_printerr ("Error statting %s: %m\n", device_file); + goto out; + } + + device = udev_device_new_from_devnum (udev, 'b', statbuf.st_rdev); + if (device == NULL) + { + g_printerr ("Error getting udev device for %s: %m\n", device_file); + goto out; + } + ret = g_strdup (udev_device_get_syspath (device)); + udev_device_unref (device); + + out: + return ret; +} + +/** + * get_part_table_device_file: + * @udev: An udev context. + * @given_device_file: The device file given on the command line. + * @out_offset: Return location for offset or %NULL. + * @out_partition_number: Return location for partition number or %NULL. + * + * If @given_device_file is not a partition, returns a copy of it and + * sets @out_offset and @out_partition_number to 0. + * + * Otherwise, returns the device file for the block device for which + * @given_device_file is a partition of and returns the offset of the + * partition in @out_offset and the partition number in + * @out_partition_number. + * + * If something goes wrong, %NULL is returned. + */ +static gchar * +get_part_table_device_file (struct udev *udev, + const gchar *given_device_file, + guint64 *out_offset, + guint *out_partition_number) +{ + gchar *ret; + guint64 offset; + guint partition_number; + gchar *devpath; + + devpath = NULL; + offset = 0; + ret = NULL; + + devpath = get_syspath (udev, given_device_file); + if (devpath == NULL) + goto out; + + partition_number = sysfs_get_int (devpath, "partition"); + + /* find device file for partition table device */ + if (partition_number > 0) + { + struct udev_device *device; + gchar *partition_table_devpath; + guint n; + + /* partition */ + partition_table_devpath = g_strdup (devpath); + for (n = strlen (partition_table_devpath) - 1; partition_table_devpath[n] != '/'; n--) + partition_table_devpath[n] = '\0'; + partition_table_devpath[n] = '\0'; + + device = udev_device_new_from_syspath (udev, partition_table_devpath); + if (device == NULL) + { + g_printerr ("Error getting udev device for syspath %s: %m\n", partition_table_devpath); + goto out; + } + ret = g_strdup (udev_device_get_devnode (device)); + udev_device_unref (device); + if (ret == NULL) + { + /* This Should Not Happen™, but was reported in a distribution upgrade + scenario, so handle it gracefully */ + g_printerr ("Error getting devnode from udev device path %s: %m\n", partition_table_devpath); + goto out; + } + g_free (partition_table_devpath); + + offset = sysfs_get_uint64 (devpath, "start") * 512; + } + else + { + struct udev_device *device; + const char *targets_type; + const char *encoded_targets_params; + + device = udev_device_new_from_syspath (udev, devpath); + if (device == NULL) + { + g_printerr ("Error getting udev device for syspath %s: %m\n", devpath); + goto out; + } + + targets_type = udev_device_get_property_value (device, "UDISKS_DM_TARGETS_TYPE"); + encoded_targets_params = udev_device_get_property_value (device, "UDISKS_DM_TARGETS_PARAMS"); + if (g_strcmp0 (targets_type, "linear") == 0) + { + gint partition_slave_major; + gint partition_slave_minor; + guint64 offset_sectors; + gchar *targets_params; + + targets_params = decode_udev_encoded_string (encoded_targets_params); + if (sscanf (targets_params, + "%d:%d\x20%" G_GUINT64_FORMAT, + &partition_slave_major, + &partition_slave_minor, + &offset_sectors) == 3) + { + struct udev_device *mp_device; + + mp_device = udev_device_new_from_devnum (udev, 'b', makedev (partition_slave_major, + partition_slave_minor)); + if (mp_device != NULL) + { + const char *dm_uuid; + + ret = g_strdup (udev_device_get_devnode (mp_device)); + offset = offset_sectors * 512; + + /* now figure out partition_number + * + * this is kind of a hack.. but works since UUID is of the + * form part2-mpath-3600508b400105df70000e00000d80000 + */ + partition_number = 0; + dm_uuid = udev_device_get_property_value (device, "DM_UUID"); + if (dm_uuid != NULL && g_str_has_prefix (dm_uuid, "part")) + partition_number = atoi (dm_uuid + 4); + + udev_device_unref (mp_device); + g_free (targets_params); + udev_device_unref (device); + goto out; + } + } + g_free (targets_params); + } + udev_device_unref (device); + + /* not a kernel partition */ + ret = g_strdup (given_device_file); + partition_number = 0; + } + + out: + if (out_offset != NULL) + *out_offset = offset; + if (out_partition_number != NULL) + *out_partition_number = partition_number; + + g_free (devpath); + + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static guint +count_entries (PartitionTable *pt) +{ + guint ret; + guint num_top_level; + guint n; + + ret = 0; + + num_top_level = part_table_get_num_entries (pt); + for (n = 0; n < num_top_level; n++) + { + PartitionTable *nested; + + if (part_table_entry_is_in_use (pt, n)) + ret++; + + nested = part_table_entry_get_nested (pt, n); + if (nested != NULL) + { + ret += part_table_get_num_entries (nested); + } + } + + return ret; +} + +/* ---------------------------------------------------------------------------------------------------- */ + int main (int argc, char *argv[]) { guint n; gint fd; - gint partition_number; gchar *devpath; const gchar *device_file; gchar *partition_table_device_file; @@ -128,75 +382,21 @@ main (int argc, goto out; } - devpath = getenv ("DEVPATH"); - if (devpath != NULL) - { - devpath = g_build_filename ("/sys", devpath, NULL); - } - else - { - struct udev_device *device; - struct stat statbuf; - - if (stat (device_file, &statbuf) != 0) - { - g_printerr ("Error statting %s: %m\n", device_file); - goto out; - } - - device = udev_device_new_from_devnum (udev, 'b', statbuf.st_rdev); - if (device == NULL) - { - g_printerr ("Error getting udev device for %s: %m\n", device_file); - goto out; - } - devpath = g_strdup (udev_device_get_syspath (device)); - udev_device_unref (device); - } - - partition_number = sysfs_get_int (devpath, "partition"); - - /* find device file for partition table device */ - if (partition_number > 0) - { - struct udev_device *device; - gchar *partition_table_devpath; - - /* partition */ - partition_table_devpath = g_strdup (devpath); - for (n = strlen (partition_table_devpath) - 1; partition_table_devpath[n] != '/'; n--) - partition_table_devpath[n] = '\0'; - partition_table_devpath[n] = '\0'; + guint64 partition_offset; + guint partition_number; - device = udev_device_new_from_syspath (udev, partition_table_devpath); - if (device == NULL) - { - g_printerr ("Error getting udev device for syspath %s: %m\n", partition_table_devpath); - goto out; - } - partition_table_device_file = g_strdup (udev_device_get_devnode (device)); - udev_device_unref (device); - if (partition_table_device_file == NULL) - { - /* This Should Not Happen™, but was reported in a distribution upgrade - scenario, so handle it gracefully */ - g_printerr ("Error getting devnode from udev device path %s: %m\n", partition_table_devpath); - goto out; - } - g_free (partition_table_devpath); - } - else - { - /* not partition */ - partition_table_device_file = g_strdup (device_file); - } + partition_table_device_file = get_part_table_device_file (udev, + device_file, + &partition_offset, + &partition_number); + g_printerr ("got `%s' and %" G_GUINT64_FORMAT "\n", partition_table_device_file, partition_offset); fd = open (partition_table_device_file, O_RDONLY); /* TODO: right now we also use part_id to determine if media is available or not. This * should probably be done elsewhere */ - if (partition_number == 0) + if (partition_offset == 0) { if (fd < 0) { @@ -221,9 +421,8 @@ main (int argc, } close (fd); - if (partition_number > 0) + if (partition_offset > 0) { - guint64 partition_offset; PartitionTable *partition_table_for_entry; gint entry_num; gchar *type; @@ -234,7 +433,6 @@ main (int argc, guint64 size; /* partition */ - partition_offset = sysfs_get_uint64 (devpath, "start") * 512; part_table_find (partition_table, partition_offset, &partition_table_for_entry, &entry_num); if (entry_num == -1) { @@ -273,6 +471,7 @@ main (int argc, { g_print ("UDISKS_PARTITION_TABLE=1\n"); g_print ("UDISKS_PARTITION_TABLE_SCHEME=%s\n", part_get_scheme_name (part_table_get_scheme (partition_table))); + g_print ("UDISKS_PARTITION_TABLE_COUNT=%d\n", count_entries (partition_table)); } out: diff --git a/src/probers/udisks-dm-export.c b/src/probers/udisks-dm-export.c index 4f05b13..b008d92 100644 --- a/src/probers/udisks-dm-export.c +++ b/src/probers/udisks-dm-export.c @@ -18,6 +18,194 @@ usage (void) /* ---------------------------------------------------------------------------------------------------- */ + +/* This code is from udev - will become public libudev API at some point */ + +/* count of characters used to encode one unicode char */ +static int utf8_encoded_expected_len(const char *str) +{ + unsigned char c = (unsigned char)str[0]; + + if (c < 0x80) + return 1; + if ((c & 0xe0) == 0xc0) + return 2; + if ((c & 0xf0) == 0xe0) + return 3; + if ((c & 0xf8) == 0xf0) + return 4; + if ((c & 0xfc) == 0xf8) + return 5; + if ((c & 0xfe) == 0xfc) + return 6; + return 0; +} + +/* decode one unicode char */ +static int utf8_encoded_to_unichar(const char *str) +{ + int unichar; + int len; + int i; + + len = utf8_encoded_expected_len(str); + switch (len) { + case 1: + return (int)str[0]; + case 2: + unichar = str[0] & 0x1f; + break; + case 3: + unichar = (int)str[0] & 0x0f; + break; + case 4: + unichar = (int)str[0] & 0x07; + break; + case 5: + unichar = (int)str[0] & 0x03; + break; + case 6: + unichar = (int)str[0] & 0x01; + break; + default: + return -1; + } + + for (i = 1; i < len; i++) { + if (((int)str[i] & 0xc0) != 0x80) + return -1; + unichar <<= 6; + unichar |= (int)str[i] & 0x3f; + } + + return unichar; +} + +/* expected size used to encode one unicode char */ +static int utf8_unichar_to_encoded_len(int unichar) +{ + if (unichar < 0x80) + return 1; + if (unichar < 0x800) + return 2; + if (unichar < 0x10000) + return 3; + if (unichar < 0x200000) + return 4; + if (unichar < 0x4000000) + return 5; + return 6; +} + +/* check if unicode char has a valid numeric range */ +static int utf8_unichar_valid_range(int unichar) +{ + if (unichar > 0x10ffff) + return 0; + if ((unichar & 0xfffff800) == 0xd800) + return 0; + if ((unichar > 0xfdcf) && (unichar < 0xfdf0)) + return 0; + if ((unichar & 0xffff) == 0xffff) + return 0; + return 1; +} + +/* validate one encoded unicode char and return its length */ +static int utf8_encoded_valid_unichar(const char *str) +{ + int len; + int unichar; + int i; + + len = utf8_encoded_expected_len(str); + if (len == 0) + return -1; + + /* ascii is valid */ + if (len == 1) + return 1; + + /* check if expected encoded chars are available */ + for (i = 0; i < len; i++) + if ((str[i] & 0x80) != 0x80) + return -1; + + unichar = utf8_encoded_to_unichar(str); + + /* check if encoded length matches encoded value */ + if (utf8_unichar_to_encoded_len(unichar) != len) + return -1; + + /* check if value has valid range */ + if (!utf8_unichar_valid_range(unichar)) + return -1; + + return len; +} + +static int is_whitelisted(char c, const char *white) +{ + if ((c >= '0' && c <= '9') || + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + strchr("#+-.:=@_", c) != NULL || + (white != NULL && strchr(white, c) != NULL)) + return 1; + return 0; +} + +/** + * _udev_util_encode_string: + * @str: input string to be encoded + * @str_enc: output string to store the encoded input string + * @len: maximum size of the output string, which may be + * four times as long as the input string + * + * Encode all potentially unsafe characters of a string to the + * corresponding hex value prefixed by '\x'. + * + * Returns: 0 if the entire string was copied, non-zero otherwise. + */ +static int +_udev_util_encode_string(const char *str, char *str_enc, size_t len) +{ + size_t i, j; + + if (str == NULL || str_enc == NULL) + return -1; + + for (i = 0, j = 0; str[i] != '\0'; i++) { + int seqlen; + + seqlen = utf8_encoded_valid_unichar(&str[i]); + if (seqlen > 1) { + if (len-j < (size_t)seqlen) + goto err; + memcpy(&str_enc[j], &str[i], seqlen); + j += seqlen; + i += (seqlen-1); + } else if (str[i] == '\\' || !is_whitelisted(str[i], NULL)) { + if (len-j < 4) + goto err; + sprintf(&str_enc[j], "\\x%02x", (unsigned char) str[i]); + j += 4; + } else { + if (len-j < 1) + goto err; + str_enc[j] = str[i]; + j++; + } + } + if (len-j < 1) + goto err; + str_enc[j] = '\0'; + return 0; +err: + return -1; +} + +/* ---------------------------------------------------------------------------------------------------- */ /* based on the export patch in https://bugzilla.redhat.com/show_bug.cgi?id=438604 */ static int @@ -30,13 +218,17 @@ dm_export (int major, int minor) char *target_type; char *params; const char *name; - const char *uuid; struct dm_info info; + GString *target_types_str; + GString *start_str; + GString *length_str; + GString *params_str; + gchar buf[4096]; ret = FALSE; dmt = NULL; - dmt = dm_task_create (DM_DEVICE_STATUS); + dmt = dm_task_create (DM_DEVICE_TABLE); if (dmt == NULL) { perror ("dm_task_create"); @@ -73,63 +265,60 @@ dm_export (int major, int minor) perror ("dm_task_get_name"); goto out; } - g_print ("UDISKS_DM_NAME=%s\n", name); - - uuid = dm_task_get_uuid (dmt); - if (uuid != NULL) - { - g_print ("UDISKS_DM_UUID=%s\n", uuid); - } if (!info.exists) { - g_print ("UDISKS_DM_STATE=NOTPRESENT\n"); goto out; } - g_print ("UDISKS_DM_STATE=%s\n", - info.suspended ? "SUSPENDED" : - (info.read_only ? " READONLY" : "ACTIVE")); - - if (!info.live_table && !info.inactive_table) - { - g_print ("UDISKS_DM_TABLE_STATE=NONE\n"); - } - else - { - g_print ("UDISKS_DM_TABLE_STATE=%s%s%s\n", - info.live_table ? "LIVE" : "", - info.live_table && info.inactive_table ? "/" : "", - info.inactive_table ? "INACTIVE" : ""); - } - - if (info.open_count != -1) - { - g_print ("UDISKS_DM_OPENCOUNT=%d\n", info.open_count); - } - - g_print ("UDISKS_DM_LAST_EVENT_NR=%" G_GUINT32_FORMAT "\n", (guint32) info.event_nr); - - g_print ("UDISKS_DM_MAJOR=%d\n", info.major); - g_print ("UDISKS_DM_MINOR=%d\n", info.minor); - if (info.target_count != -1) - g_print ("UDISKS_DM_TARGET_COUNT=%d\n", info.target_count); + g_print ("UDISKS_DM_TARGETS_COUNT=%d\n", info.target_count); + + target_types_str = g_string_new (NULL); + start_str = g_string_new (NULL); + length_str = g_string_new (NULL); + params_str = g_string_new (NULL); - /* export all table types */ + /* export all tables */ next = NULL; - next = dm_get_next_target (dmt, next, &start, &length, &target_type, ¶ms); - if (target_type != NULL) + do { - g_print ("UDISKS_DM_TARGET_TYPES=%s", target_type); - while (next != NULL) + next = dm_get_next_target (dmt, next, &start, &length, &target_type, ¶ms); + if (target_type != NULL) + { + g_string_append (target_types_str, target_type); + g_string_append_printf (start_str, "%" G_GUINT64_FORMAT, start); + g_string_append_printf (length_str, "%" G_GUINT64_FORMAT, length); + if (params != NULL && strlen (params) > 0) + { + _udev_util_encode_string (params, buf, sizeof (buf)); + g_string_append (params_str, buf); + } + } + + if (next != NULL) { - next = dm_get_next_target (dmt, next, &start, &length, &target_type, ¶ms); - if (target_type) - g_print (",%s", target_type); + g_string_append_c (target_types_str, ' '); + g_string_append_c (start_str, ' '); + g_string_append_c (length_str, ' '); + g_string_append_c (params_str, ' '); } - g_print ("\n"); } + while (next != NULL); + + if (target_types_str->len > 0) + g_print ("UDISKS_DM_TARGETS_TYPE=%s\n", target_types_str->str); + if (start_str->len > 0) + g_print ("UDISKS_DM_TARGETS_START=%s\n", start_str->str); + if (length_str->len > 0) + g_print ("UDISKS_DM_TARGETS_LENGTH=%s\n", length_str->str); + if (params_str->len > 0) + g_print ("UDISKS_DM_TARGETS_PARAMS=%s\n", params_str->str); + + g_string_free (target_types_str, TRUE); + g_string_free (start_str, TRUE); + g_string_free (length_str, TRUE); + g_string_free (params_str, TRUE); ret = TRUE; diff --git a/tools/udisks.c b/tools/udisks.c index 7517fa1..ece774c 100644 --- a/tools/udisks.c +++ b/tools/udisks.c @@ -291,6 +291,7 @@ typedef struct gint64 device_major; gint64 device_minor; char *device_file; + char *device_file_presentation; char **device_file_by_id; char **device_file_by_path; gboolean device_is_system_internal; @@ -312,6 +313,8 @@ typedef struct gboolean device_is_linux_md; gboolean device_is_linux_lvm2_lv; gboolean device_is_linux_lvm2_pv; + gboolean device_is_linux_dmmp; + gboolean device_is_linux_dmmp_component; char **device_mount_paths; uid_t device_mounted_by_uid; gboolean device_presentation_hide; @@ -420,6 +423,12 @@ typedef struct guint64 linux_lvm2_pv_group_extent_size; char **linux_lvm2_pv_group_physical_volumes; char **linux_lvm2_pv_group_logical_volumes; + + gchar *linux_dmmp_component_holder; + + gchar *linux_dmmp_name; + gchar **linux_dmmp_slaves; + } DeviceProperties; static void @@ -442,6 +451,8 @@ collect_props (const char *key, props->device_minor = g_value_get_int64 (value); else if (strcmp (key, "DeviceFile") == 0) props->device_file = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "DeviceFilePresentation") == 0) + props->device_file_presentation = g_strdup (g_value_get_string (value)); else if (strcmp (key, "DeviceFileById") == 0) props->device_file_by_id = g_strdupv (g_value_get_boxed (value)); else if (strcmp (key, "DeviceFileByPath") == 0) @@ -482,6 +493,10 @@ collect_props (const char *key, props->device_is_linux_lvm2_lv = g_value_get_boolean (value); else if (strcmp (key, "DeviceIsLinuxLvm2PV") == 0) props->device_is_linux_lvm2_pv = g_value_get_boolean (value); + else if (strcmp (key, "DeviceIsLinuxDmmp") == 0) + props->device_is_linux_dmmp = g_value_get_boolean (value); + else if (strcmp (key, "DeviceIsLinuxDmmpComponent") == 0) + props->device_is_linux_dmmp_component = g_value_get_boolean (value); else if (strcmp (key, "DeviceIsMounted") == 0) props->device_is_mounted = g_value_get_boolean (value); else if (strcmp (key, "DeviceMountPaths") == 0) @@ -711,6 +726,24 @@ collect_props (const char *key, else if (strcmp (key, "LinuxLvm2PVGroupLogicalVolumes") == 0) props->linux_lvm2_pv_group_logical_volumes = g_strdupv (g_value_get_boxed (value)); + else if (strcmp (key, "LinuxDmmpComponentHolder") == 0) + props->linux_dmmp_component_holder = g_strdup (g_value_get_boxed (value)); + + else if (strcmp (key, "LinuxDmmpName") == 0) + props->linux_dmmp_name = g_strdup (g_value_get_string (value)); + else if (strcmp (key, "LinuxDmmpSlaves") == 0) + { + guint n; + GPtrArray *object_paths; + + object_paths = g_value_get_boxed (value); + + props->linux_dmmp_slaves = g_new0 (char *, object_paths->len + 1); + for (n = 0; n < object_paths->len; n++) + props->linux_dmmp_slaves[n] = g_strdup (object_paths->pdata[n]); + props->linux_dmmp_slaves[n] = NULL; + } + else handled = FALSE; @@ -723,6 +756,7 @@ device_properties_free (DeviceProperties *props) { g_free (props->native_path); g_free (props->device_file); + g_free (props->device_file_presentation); g_strfreev (props->device_file_by_id); g_strfreev (props->device_file_by_path); g_strfreev (props->device_mount_paths); @@ -785,6 +819,11 @@ device_properties_free (DeviceProperties *props) g_strfreev (props->linux_lvm2_pv_group_physical_volumes); g_strfreev (props->linux_lvm2_pv_group_logical_volumes); + g_free (props->linux_dmmp_component_holder); + + g_free (props->linux_dmmp_name); + g_strfreev (props->linux_dmmp_slaves); + g_free (props); } @@ -1091,6 +1130,9 @@ do_show_info (const char *object_path) props->device_major, props->device_minor); g_print (" device-file: %s\n", props->device_file); + g_print (" presentation: %s\n", + (props->device_file_presentation != NULL && strlen (props->device_file_presentation) > 0) ? + props->device_file_presentation : "(not set)"); for (n = 0; props->device_file_by_id[n] != NULL; n++) g_print (" by-id: %s\n", (char *) props->device_file_by_id[n]); for (n = 0; props->device_file_by_path[n] != NULL; n++) @@ -1207,6 +1249,19 @@ do_show_info (const char *object_path) for (n = 0; props->linux_lvm2_pv_group_logical_volumes[n] != NULL; n++) g_print (" %s\n", props->linux_lvm2_pv_group_logical_volumes[n]); } + if (props->device_is_linux_dmmp) + { + g_print (" dm-multipath:\n"); + g_print (" name: %s\n", props->linux_dmmp_name); + g_print (" components:\n"); + for (n = 0; props->linux_dmmp_slaves[n] != NULL; n++) + g_print (" %s\n", props->linux_dmmp_slaves[n]); + } + if (props->device_is_linux_dmmp_component) + { + g_print (" dm-multipath component:\n"); + g_print (" multipath device: %s\n", props->linux_dmmp_component_holder); + } if (props->device_is_luks) { -- 2.7.4