So the way this works is that with multiple paths, more than one block
device will point to the Drive in question.
$ ./udisksctl status
PORT MODEL REVISION SERIAL BLOCK
--------------------------------------------------------------------------------
HP LOGICAL VOLUME 3.00
5001438008F61790 sda sda1 sda2
SEAGATE ST3300657SS 0006 3SJ1QNMQ00009052NECM sdan sdl
SEAGATE ST3300657SS 0006 3SJ1RFP900009051HZ5S sdaf sdd
SEAGATE ST3300657SS 0006 3SJ1RJS700009050VYEA sdal sdj
SEAGATE ST3300657SS 0006 3SJ1RPFJ00009052BZ10 sdah sdf
SEAGATE ST3300657SS 0006 3SJ1RSJC00009052MWTB sdam sdk
SEAGATE ST3300657SS 0006 3SJ1RWZ100009101T12H sdai sdg
SEAGATE ST3300657SS 0006 3SJ1S3NE00009101TB5Y sdao sdm
SEAGATE ST3300657SS 0006 3SJ1S40K00009101T1XU sdak sdi
SEAGATE ST3300657SS 0006 3SJ1S4MH00009052RG6Z sdae sdc
SEAGATE ST3300657SS 0006 3SJ1S66L00009052QGZA sdag sde
SEAGATE ST3300657SS 0006 3SJ1S7C500009052RKPP sdaj sdh
SEAGATE ST3300657SS 0006 3SJ1S7K600009051M0CE sdad sdb
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30010853 sds
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30012560 sdn
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30014347 sdac
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30021345 sdaa
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30024753 sdt
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30025874 sdw
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30030732 sdr
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30031826 sdv
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30032003 sdz
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30039741 sdp
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30063724 sdx
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30064055 sdq
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30064486 sdy
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30064749 sdo
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30065104 sdu
WDC WD1002FAEX-00Y9A0 01.01V10 WD-WCAW30067287 sdab
Still need to hook up support for dm-multipath such that we get e.g.
SEAGATE ST3300657SS 0006 3SJ1QNMQ00009052NECM sdan sdl mpatha
Signed-off-by: David Zeuthen <davidz@redhat.com>
{
GDBusObject *object = G_DBUS_OBJECT (l->data);
UDisksLinuxDrive *drive;
- GUdevDevice *drive_device;
- const gchar *drive_sysfs_path;
+ GList *drive_devices;
+ GList *j;
if (!UDISKS_IS_LINUX_DRIVE (object))
continue;
drive = UDISKS_LINUX_DRIVE (object);
- drive_device = udisks_linux_drive_get_device (drive);
+ drive_devices = udisks_linux_drive_get_devices (drive);
- drive_sysfs_path = g_udev_device_get_sysfs_path (drive_device);
-
- if (g_str_has_prefix (block_device_sysfs_path, drive_sysfs_path))
+ for (j = drive_devices; j != NULL; j = j->next)
{
- ret = g_dbus_object_get_object_path (object);
- g_object_unref (drive_device);
- goto out;
+ GUdevDevice *drive_device = G_UDEV_DEVICE (j->data);
+ const gchar *drive_sysfs_path;
+
+ drive_sysfs_path = g_udev_device_get_sysfs_path (drive_device);
+ if (g_str_has_prefix (block_device_sysfs_path, drive_sysfs_path))
+ {
+ ret = g_dbus_object_get_object_path (object);
+ g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (drive_devices);
+ goto out;
+ }
}
- g_object_unref (drive_device);
+ g_list_foreach (drive_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (drive_devices);
}
out:
UDisksDaemon *daemon;
- GUdevDevice *device;
+ /* list of GUdevDevice objects for scsi_device objects */
+ GList *devices;
/* interfaces */
UDisksDrive *iface_drive;
/* note: we don't hold a ref to drive->daemon or drive->mount_monitor */
- g_object_unref (drive->device);
+ g_list_foreach (drive->devices, (GFunc) g_object_unref, NULL);
+ g_list_free (drive->devices);
if (drive->iface_drive != NULL)
g_object_unref (drive->iface_drive);
g_value_set_object (value, udisks_linux_drive_get_daemon (drive));
break;
- case PROP_DEVICE:
- g_value_set_object (value, udisks_linux_drive_get_device (drive));
- break;
-
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
break;
case PROP_DEVICE:
- g_assert (drive->device == NULL);
- drive->device = g_value_dup_object (value);
+ g_assert (drive->devices == NULL);
+ drive->devices = g_list_prepend (NULL, g_value_dup_object (value));
break;
default:
GString *str;
/* initial coldplug */
- udisks_linux_drive_uevent (drive, "add", NULL);
+ udisks_linux_drive_uevent (drive, "add", drive->devices->data);
/* compute the object path */
vendor = g_strdup (udisks_drive_get_vendor (drive->iface_drive));
"Device",
"The device for the object",
G_UDEV_TYPE_DEVICE,
- G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS));
}
/**
- * udisks_linux_drive_get_device:
+ * udisks_linux_drive_get_devices:
* @drive: A #UDisksLinuxDrive.
*
- * Gets the current #GUdevDevice for @drive. Connect to
- * #GObject::notify to track changes to the #UDisksLinuxDrive:device
- * property.
+ * Gets the current #GUdevDevice objects associated with @drive.
*
- * Returns: A #GUdevDevice. Free with g_object_unref().
+ * Returns: A list of #GUdevDevice objects. Free each element with
+ * g_object_unref(), then free the list with g_list_free().
*/
-GUdevDevice *
-udisks_linux_drive_get_device (UDisksLinuxDrive *drive)
+GList *
+udisks_linux_drive_get_devices (UDisksLinuxDrive *drive)
{
+ GList *ret;
g_return_val_if_fail (UDISKS_IS_LINUX_DRIVE (drive), NULL);
- return g_object_ref (drive->device);
+ ret = g_list_copy (drive->devices);
+ g_list_foreach (ret, (GFunc) g_object_ref, NULL);
+ return ret;
}
/* ---------------------------------------------------------------------------------------------------- */
}
/* ---------------------------------------------------------------------------------------------------- */
-
-
-/* ---------------------------------------------------------------------------------------------------- */
/* org.freedesktop.UDisks.Drive */
static gboolean
GDBusInterface *_iface)
{
UDisksDrive *iface = UDISKS_DRIVE (_iface);
+ GUdevDevice *device;
+
+ if (drive->devices == NULL)
+ goto out;
+
+ device = G_UDEV_DEVICE (drive->devices->data);
/* this is the _almost_ the same for both ATA and SCSI devices (cf. udev's ata_id and scsi_id)
* but we special case since there are subtle differences...
*/
- if (g_udev_device_get_property_as_boolean (drive->device, "ID_ATA"))
+ if (g_udev_device_get_property_as_boolean (device, "ID_ATA"))
{
const gchar *model;
- model = g_udev_device_get_property (drive->device, "ID_MODEL_ENC");
+ model = g_udev_device_get_property (device, "ID_MODEL_ENC");
if (model != NULL)
{
gchar *s;
g_free (s);
}
- udisks_drive_set_vendor (iface, g_udev_device_get_property (drive->device, ""));
- udisks_drive_set_revision (iface, g_udev_device_get_property (drive->device, "ID_REVISION"));
- udisks_drive_set_serial (iface, g_udev_device_get_property (drive->device, "ID_SERIAL_SHORT"));
- udisks_drive_set_wwn (iface, g_udev_device_get_property (drive->device, "ID_WWN_WITH_EXTENSION"));
+ udisks_drive_set_vendor (iface, g_udev_device_get_property (device, ""));
+ udisks_drive_set_revision (iface, g_udev_device_get_property (device, "ID_REVISION"));
+ udisks_drive_set_serial (iface, g_udev_device_get_property (device, "ID_SERIAL_SHORT"));
+ udisks_drive_set_wwn (iface, g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"));
}
- else if (g_udev_device_get_property_as_boolean (drive->device, "ID_SCSI"))
+ else if (g_udev_device_get_property_as_boolean (device, "ID_SCSI"))
{
const gchar *vendor;
const gchar *model;
- vendor = g_udev_device_get_property (drive->device, "ID_VENDOR_ENC");
+ vendor = g_udev_device_get_property (device, "ID_VENDOR_ENC");
if (vendor != NULL)
{
gchar *s;
g_free (s);
}
- model = g_udev_device_get_property (drive->device, "ID_MODEL_ENC");
+ model = g_udev_device_get_property (device, "ID_MODEL_ENC");
if (model != NULL)
{
gchar *s;
g_free (s);
}
- udisks_drive_set_revision (iface, g_udev_device_get_property (drive->device, "ID_REVISION"));
- udisks_drive_set_serial (iface, g_udev_device_get_property (drive->device, "ID_SCSI_SERIAL"));
- udisks_drive_set_wwn (iface, g_udev_device_get_property (drive->device, "ID_WWN_WITH_EXTENSION"));
+ udisks_drive_set_revision (iface, g_udev_device_get_property (device, "ID_REVISION"));
+ udisks_drive_set_serial (iface, g_udev_device_get_property (device, "ID_SCSI_SERIAL"));
+ udisks_drive_set_wwn (iface, g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"));
}
else
{
/* generic fallback... */
- udisks_drive_set_vendor (iface, g_udev_device_get_property (drive->device, "ID_VENDOR"));
- udisks_drive_set_model (iface, g_udev_device_get_property (drive->device, "ID_MODEL"));
- udisks_drive_set_revision (iface, g_udev_device_get_property (drive->device, "ID_REVISION"));
- udisks_drive_set_serial (iface, g_udev_device_get_property (drive->device, "ID_SERIAL_SHORT"));
- udisks_drive_set_wwn (iface, g_udev_device_get_property (drive->device, "ID_WWN_WITH_EXTENSION"));
+ udisks_drive_set_vendor (iface, g_udev_device_get_property (device, "ID_VENDOR"));
+ udisks_drive_set_model (iface, g_udev_device_get_property (device, "ID_MODEL"));
+ udisks_drive_set_revision (iface, g_udev_device_get_property (device, "ID_REVISION"));
+ udisks_drive_set_serial (iface, g_udev_device_get_property (device, "ID_SERIAL_SHORT"));
+ udisks_drive_set_wwn (iface, g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION"));
}
+
+ out:
+ ;
}
/* ---------------------------------------------------------------------------------------------------- */
+static GList *
+find_link_for_sysfs_path (UDisksLinuxDrive *drive,
+ const gchar *sysfs_path)
+{
+ GList *l;
+ GList *ret;
+ ret = NULL;
+ for (l = drive->devices; l != NULL; l = l->next)
+ {
+ GUdevDevice *device = G_UDEV_DEVICE (l->data);
+ if (g_strcmp0 (g_udev_device_get_sysfs_path (device), sysfs_path) == 0)
+ {
+ ret = l;
+ goto out;
+ }
+ }
+ out:
+ return ret;
+}
+
/**
* udisks_linux_drive_uevent:
* @drive: A #UDisksLinuxDrive.
const gchar *action,
GUdevDevice *device)
{
+ GList *link;
+
g_return_if_fail (UDISKS_IS_LINUX_DRIVE (drive));
- g_return_if_fail (device == NULL || G_UDEV_IS_DEVICE (device));
+ g_return_if_fail (G_UDEV_IS_DEVICE (device));
- if (device != NULL)
+ link = find_link_for_sysfs_path (drive, g_udev_device_get_sysfs_path (device));
+ if (g_strcmp0 (action, "remove") == 0)
+ {
+ if (link != NULL)
+ {
+ g_object_unref (G_UDEV_DEVICE (link->data));
+ drive->devices = g_list_delete_link (drive->devices, link);
+ }
+ else
+ {
+ udisks_daemon_log (drive->daemon,
+ UDISKS_LOG_LEVEL_WARNING,
+ "Drive doesn't have device with sysfs path %s on remove event",
+ g_udev_device_get_sysfs_path (device));
+ }
+ }
+ else
{
- g_object_unref (drive->device);
- drive->device = g_object_ref (device);
- g_object_notify (G_OBJECT (drive), "device");
+ if (link != NULL)
+ {
+ g_object_unref (G_UDEV_DEVICE (link->data));
+ link->data = g_object_ref (device);
+ }
+ else
+ {
+ drive->devices = g_list_append (drive->devices, g_object_ref (device));
+ }
}
update_iface (drive, action, drive_check, drive_update,
#define UDISKS_LINUX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), UDISKS_TYPE_LINUX_DRIVE, UDisksLinuxDrive))
#define UDISKS_IS_LINUX_DRIVE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), UDISKS_TYPE_LINUX_DRIVE))
-GType udisks_linux_drive_get_type (void) G_GNUC_CONST;
-UDisksLinuxDrive *udisks_linux_drive_new (UDisksDaemon *daemon,
- GUdevDevice *device);
-void udisks_linux_drive_uevent (UDisksLinuxDrive *drive,
- const gchar *action,
- GUdevDevice *device);
-UDisksDaemon *udisks_linux_drive_get_daemon (UDisksLinuxDrive *drive);
-GUdevDevice *udisks_linux_drive_get_device (UDisksLinuxDrive *drive);
+GType udisks_linux_drive_get_type (void) G_GNUC_CONST;
+UDisksLinuxDrive *udisks_linux_drive_new (UDisksDaemon *daemon,
+ GUdevDevice *device);
+void udisks_linux_drive_uevent (UDisksLinuxDrive *drive,
+ const gchar *action,
+ GUdevDevice *device);
+UDisksDaemon *udisks_linux_drive_get_daemon (UDisksLinuxDrive *drive);
+GList *udisks_linux_drive_get_devices (UDisksLinuxDrive *drive);
G_END_DECLS
#include "config.h"
+#include <string.h>
+
#include "udisksdaemon.h"
#include "udisksprovider.h"
#include "udiskslinuxprovider.h"
/* maps from sysfs path to UDisksLinuxBlock objects */
GHashTable *sysfs_to_block;
- /* maps from sysfs path to UDisksLinuxDrive objects */
- GHashTable *sysfs_to_drive;
+ /* maps from VPD (serial, wwn) to UDisksLinuxDrive objects */
+ GHashTable *vpd_to_drive;
/* maps from sysfs path to UDisksLinuxController objects */
GHashTable *sysfs_to_controller;
UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (object);
g_hash_table_unref (provider->sysfs_to_block);
- g_hash_table_unref (provider->sysfs_to_drive);
+ g_hash_table_unref (provider->vpd_to_drive);
g_hash_table_unref (provider->sysfs_to_controller);
g_object_unref (provider->gudev_client);
gpointer user_data)
{
UDisksLinuxProvider *provider = UDISKS_LINUX_PROVIDER (user_data);
- g_print ("%s:%s: entering\n", G_STRLOC, G_STRFUNC);
+ //g_print ("%s:%s: entering\n", G_STRLOC, G_STRFUNC);
udisks_linux_provider_handle_uevent (provider, action, device);
}
g_str_equal,
g_free,
(GDestroyNotify) g_object_unref);
- provider->sysfs_to_drive = g_hash_table_new_full (g_str_hash,
- g_str_equal,
- g_free,
- (GDestroyNotify) g_object_unref);
+ provider->vpd_to_drive = g_hash_table_new_full (g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify) g_object_unref);
provider->sysfs_to_controller = g_hash_table_new_full (g_str_hash,
g_str_equal,
g_free,
const gchar *action,
GUdevDevice *device)
{
- const gchar *sysfs_path;
UDisksLinuxDrive *drive;
UDisksDaemon *daemon;
+ const gchar *sysfs_path;
+ const gchar *serial;
+ const gchar *wwn;
+ const gchar *vpd;
daemon = udisks_provider_get_daemon (UDISKS_PROVIDER (provider));
sysfs_path = g_udev_device_get_sysfs_path (device);
+ /* prefer WWN to serial */
+ serial = g_udev_device_get_property (device, "ID_SERIAL");
+ wwn = g_udev_device_get_property (device, "ID_WWN_WITH_EXTENSION");
+ if (wwn != NULL && strlen (wwn) > 0)
+ {
+ vpd = wwn;
+ }
+ else if (serial != NULL && strlen (serial) > 0)
+ {
+ vpd = serial;
+ }
+ else
+ {
+ udisks_daemon_log (daemon,
+ UDISKS_LOG_LEVEL_WARNING,
+ "Ignoring scsi_device %s with no serial or WWN",
+ g_udev_device_get_sysfs_path (device));
+ goto out;
+ }
+
if (g_strcmp0 (action, "remove") == 0)
{
- drive = g_hash_table_lookup (provider->sysfs_to_drive, sysfs_path);
+ drive = g_hash_table_lookup (provider->vpd_to_drive, vpd);
if (drive != NULL)
{
- gchar *object_path;
- object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (drive));
- g_dbus_object_manager_unexport (udisks_daemon_get_object_manager (daemon),
- object_path);
- g_free (object_path);
- g_warn_if_fail (g_hash_table_remove (provider->sysfs_to_drive, sysfs_path));
+ GList *devices;
+
+ udisks_linux_drive_uevent (drive, action, device);
+
+ devices = udisks_linux_drive_get_devices (drive);
+ if (devices == NULL)
+ {
+ gchar *object_path;
+ object_path = g_dbus_object_get_object_path (G_DBUS_OBJECT (drive));
+ g_dbus_object_manager_unexport (udisks_daemon_get_object_manager (daemon),
+ object_path);
+ g_free (object_path);
+ g_warn_if_fail (g_hash_table_remove (provider->vpd_to_drive, vpd));
+ }
+ g_list_foreach (devices, (GFunc) g_object_unref, NULL);
+ g_list_free (devices);
}
}
else
{
- drive = g_hash_table_lookup (provider->sysfs_to_drive, sysfs_path);
+ drive = g_hash_table_lookup (provider->vpd_to_drive, vpd);
if (drive != NULL)
{
udisks_linux_drive_uevent (drive, action, device);
{
g_dbus_object_manager_export_and_uniquify (udisks_daemon_get_object_manager (daemon),
G_DBUS_OBJECT (drive));
- g_hash_table_insert (provider->sysfs_to_drive, g_strdup (sysfs_path), drive);
+ g_hash_table_insert (provider->vpd_to_drive, g_strdup (vpd), drive);
}
}
}
+
+ out:
+ ;
}
static void
/* ---------------------------------------------------------------------------------------------------- */
-/* built-in assumption: there is only one block device per drive */
-static UDisksBlockDevice *
-find_block_for_drive (GList *object_proxies,
- const gchar *drive_object_path)
+static GList *
+find_block_devices_for_drive (GList *object_proxies,
+ const gchar *drive_object_path)
{
- UDisksBlockDevice *ret;
+ GList *ret;
GList *l;
ret = NULL;
if (g_strcmp0 (udisks_block_device_get_drive (block), drive_object_path) == 0)
{
- ret = block;
- goto out;
+ ret = g_list_append (ret, g_object_ref (block));
}
g_object_unref (block);
}
- out:
return ret;
}
* - revision <= 8 (SCSI: 6, ATA: 8)
* - serial <= 20 (SCSI: 16, ATA: 20)
*/
- g_print ("LOCATION MODEL REVISION SERIAL BLOCK\n"
+ g_print ("PORT MODEL REVISION SERIAL BLOCK\n"
"--------------------------------------------------------------------------------\n");
- /* SEAGATE ST3300657SS 0006 3SJ1QNMQ00009052NECM sdaa */
+ /* SEAGATE ST3300657SS 0006 3SJ1QNMQ00009052NECM sdaa sdab dm-32 */
/* 01234567890123456789012345678901234567890123456789012345678901234567890123456789 */
/* TODO: sort */
- //object_proxies = g_list_sort (object_proxies, (GCompareFunc) obj_proxy_cmp_ctds);
+ object_proxies = g_list_sort (object_proxies, (GCompareFunc) obj_proxy_cmp);
for (l = object_proxies; l != NULL; l = l->next)
{
GDBusObjectProxy *object_proxy = G_DBUS_OBJECT_PROXY (l->data);
UDisksDrive *drive;
- UDisksBlockDevice *block;
- const gchar *block_device;
+ GList *block_devices;
const gchar *vendor;
const gchar *model;
const gchar *revision;
const gchar *serial;
gchar *vendor_model;
+ GString *str;
+ gchar *block_device;
+ GList *j;
drive = UDISKS_PEEK_DRIVE (object_proxy);
if (drive == NULL)
continue;
- block = find_block_for_drive (object_proxies, g_dbus_object_proxy_get_object_path (object_proxy));
- if (block != NULL)
- {
- block_device = udisks_block_device_get_device (block);
- g_object_unref (block);
- }
- else
+ str = g_string_new (NULL);
+ block_devices = find_block_devices_for_drive (object_proxies, g_dbus_object_proxy_get_object_path (object_proxy));
+ for (j = block_devices; j != NULL; j = j->next)
{
- block_device = "-";
+ UDisksBlockDevice *block = UDISKS_BLOCK_DEVICE (j->data);
+ const gchar *device_file;
+ if (str->len > 0)
+ g_string_append (str, " ");
+ device_file = udisks_block_device_get_device (block);
+ if (g_str_has_prefix (device_file, "/dev/"))
+ g_string_append (str, device_file + 5);
+ else
+ g_string_append (str, device_file);
}
+ if (str->len == 0)
+ g_string_append (str, "-");
+ block_device = g_string_free (str, FALSE);
+ g_list_foreach (block_devices, (GFunc) g_object_unref, NULL);
+ g_list_free (block_devices);
vendor = udisks_drive_get_vendor (drive);
model = udisks_drive_get_model (drive);
vendor_model = g_strdup ("-");
/* TODO: need to figure out LOCATION */
- g_print ("%-13s %-25s %-9s %-20s %-8s\n",
+ g_print ("%-5s %-25s %-9s %-20s %-8s\n",
"",
vendor_model,
revision,
serial,
block_device);
+ g_free (block_device);
}