Support PC-style floppy drives
authorDavid Zeuthen <davidz@redhat.com>
Mon, 10 Oct 2011 20:25:01 +0000 (16:25 -0400)
committerDavid Zeuthen <davidz@redhat.com>
Mon, 10 Oct 2011 20:25:01 +0000 (16:25 -0400)
This is achieved by introducing properties

 MediaAvailable
 MediaChangeDetected

on the Drive interface.

Signed-off-by: David Zeuthen <davidz@redhat.com>
data/org.freedesktop.UDisks2.xml
doc/udisks2-sections.txt
src/udisksdaemonutil.c
src/udisksdaemonutil.h
src/udiskslinuxblock.c
src/udiskslinuxblockobject.c
src/udiskslinuxdrive.c
src/udiskslinuxdriveobject.c

index fe7a606..305de42 100644 (file)
@@ -83,9 +83,6 @@
     -->
     <property name="WWN" type="s" access="read"/>
 
-    <!-- Size: The size of the drive. Is set to 0 if, and only if, no media is inserted. -->
-    <property name="Size" type="t" access="read"/>
-
     <!-- Media: The kind of media currently in the drive or blank if unknown.
          See the #org.freedesktop.UDisks2.Drive:MediaCompatibility property for known values.
     -->
     <!-- MediaRemovable: Whether the media can be removed from the drive. -->
     <property name="MediaRemovable" type="b" access="read"/>
 
+    <!-- MediaAvailable: Set to %FALSE if no medium is available.
+         This is always %TRUE if #org.freedesktop.UDisks2.Block.MediaChangeDetected is %FALSE.
+    -->
+    <property name="MediaAvailable" type="b" access="read"/>
+
+    <!-- MediaChangeDetected: Set to %TRUE only if media changes are detected.
+         Media changes are detected on all modern disk drives through
+         either polling or an asynchronous notification mechanism. The
+         only known disk drives that cannot report media changes are
+         PC floppy drives.
+    -->
+    <property name="MediaChangeDetected" type="b" access="read"/>
+
+    <!-- Size: The size of the drive (or the media currently in the drive).
+         This is always 0 if #org.freedesktop.UDisks2.Block.MediaChangeDetected is %FALSE.
+    -->
+    <property name="Size" type="t" access="read"/>
+
     <!-- Optical: %TRUE if the drive contains an optical disc. -->
     <property name="Optical" type="b" access="read"/>
 
index e456f37..e497d63 100644 (file)
@@ -498,6 +498,9 @@ udisks_drive_get_connection_bus
 udisks_drive_get_media
 udisks_drive_get_media_compatibility
 udisks_drive_get_media_removable
+udisks_drive_get_media_available
+udisks_drive_get_media_change_detected
+udisks_drive_get_size
 udisks_drive_get_optical
 udisks_drive_get_optical_blank
 udisks_drive_get_optical_num_tracks
@@ -508,7 +511,6 @@ udisks_drive_get_model
 udisks_drive_get_revision
 udisks_drive_get_rotation_rate
 udisks_drive_get_serial
-udisks_drive_get_size
 udisks_drive_get_vendor
 udisks_drive_get_wwn
 udisks_drive_get_sort_key
@@ -525,6 +527,9 @@ udisks_drive_set_connection_bus
 udisks_drive_set_media
 udisks_drive_set_media_compatibility
 udisks_drive_set_media_removable
+udisks_drive_set_media_available
+udisks_drive_set_media_change_detected
+udisks_drive_set_size
 udisks_drive_set_optical
 udisks_drive_set_optical_blank
 udisks_drive_set_optical_num_tracks
@@ -535,7 +540,6 @@ udisks_drive_set_model
 udisks_drive_set_revision
 udisks_drive_set_rotation_rate
 udisks_drive_set_serial
-udisks_drive_set_size
 udisks_drive_set_vendor
 udisks_drive_set_wwn
 udisks_drive_set_sort_key
index a00ae22..9667eb4 100644 (file)
@@ -149,28 +149,46 @@ udisks_safe_append_to_object_path (GString      *str,
 /**
  * udisks_daemon_util_block_get_size:
  * @device: A #GUdevDevice for a top-level block device.
+ * @out_media_available: (out): Return location for whether media is available or %NULL.
+ * @out_media_change_detected: (out): Return location for whether media change is detected or %NULL.
  *
  * Gets the size of the @device top-level block device, checking for media in the process
  *
- * Returns: The size of @device or 0 if no media is available.
+ * Returns: The size of @device or 0 if no media is available or if unknown.
  */
 guint64
-udisks_daemon_util_block_get_size (GUdevDevice *device)
+udisks_daemon_util_block_get_size (GUdevDevice *device,
+                                   gboolean    *out_media_available,
+                                   gboolean    *out_media_change_detected)
 {
-  gboolean media_available;
+  gboolean media_available = FALSE;
+  gboolean media_change_detected = TRUE;
+  guint64 size = 0;
 
   /* figuring out if media is available is a bit tricky */
-  media_available = FALSE;
   if (g_udev_device_get_sysfs_attr_as_boolean (device, "removable"))
     {
       /* never try to open optical drives (might cause the door to close) or
        * floppy drives (makes noise)
        */
-      media_available = FALSE;
-      if (!(g_udev_device_get_property_as_boolean (device, "ID_CDROM") ||
-            g_udev_device_get_property_as_boolean (device, "ID_DRIVE_FLOPPY")))
+      if (g_udev_device_get_property_as_boolean (device, "ID_DRIVE_FLOPPY"))
+        {
+          /* assume media available */
+          media_available = TRUE;
+          media_change_detected = FALSE;
+        }
+      else if (g_udev_device_get_property_as_boolean (device, "ID_CDROM"))
+        {
+          /* Rely on (careful) work already done by udev's cdrom_id prober */
+          if (g_udev_device_get_property_as_boolean (device, "ID_CDROM_MEDIA"))
+            media_available = TRUE;
+        }
+      else
         {
           gint fd;
+          /* For the general case, just rely on open(2) failing with
+           * ENOMEDIUM if no medium is inserted
+           */
           fd = open (g_udev_device_get_device_file (device), O_RDONLY);
           if (fd >= 0)
             {
@@ -178,23 +196,23 @@ udisks_daemon_util_block_get_size (GUdevDevice *device)
               close (fd);
             }
         }
-      else
-        {
-          if (g_udev_device_get_property_as_boolean (device, "ID_CDROM_MEDIA"))
-            media_available = TRUE;
-          else
-            media_available = FALSE;
-        }
     }
   else
     {
+      /* not removable, so media is implicitly available */
       media_available = TRUE;
     }
 
-  if (media_available)
-    return g_udev_device_get_sysfs_attr_as_uint64 (device, "size") * 512;
-  else
-    return 0;
+  if (media_available && size == 0 && media_change_detected)
+    size = g_udev_device_get_sysfs_attr_as_uint64 (device, "size") * 512;
+
+  if (out_media_available != NULL)
+    *out_media_available = media_available;
+
+  if (out_media_change_detected != NULL)
+    *out_media_change_detected = media_change_detected;
+
+  return size;
 }
 
 
index 6bc7eee..e0c63bd 100644 (file)
@@ -30,7 +30,9 @@ gchar *udisks_decode_udev_string (const gchar *str);
 void udisks_safe_append_to_object_path (GString      *str,
                                         const gchar  *s);
 
-guint64 udisks_daemon_util_block_get_size (GUdevDevice *device);
+guint64 udisks_daemon_util_block_get_size (GUdevDevice *device,
+                                           gboolean    *out_media_available,
+                                           gboolean    *out_media_change_detected);
 
 gchar *udisks_daemon_util_resolve_link (const gchar *path,
                                         const gchar *name);
index 6b0c3e4..e3f3128 100644 (file)
@@ -270,6 +270,11 @@ update_hints (UDisksLinuxBlock  *block,
           hint_auto = TRUE;
         }
     }
+  else
+    {
+      if (g_str_has_prefix (device_file, "/dev/fd"))
+        hint_system = FALSE;
+    }
 
   /* TODO: set ignore to TRUE for physical paths belonging to a drive with multiple paths */
 
@@ -590,6 +595,9 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
   const gchar *device_file;
   const gchar *const *symlinks;
   const gchar *preferred_device_file;
+  guint64 size;
+  gboolean media_available;
+  gboolean media_change_detected;
 
   drive = NULL;
 
@@ -608,7 +616,10 @@ udisks_linux_block_update (UDisksLinuxBlock        *block,
   udisks_block_set_symlinks (iface, symlinks);
   udisks_block_set_major (iface, major (dev));
   udisks_block_set_minor (iface, minor (dev));
-  udisks_block_set_size (iface, udisks_daemon_util_block_get_size (device));
+  size = udisks_daemon_util_block_get_size (device,
+                                            &media_available,
+                                            &media_change_detected);
+  udisks_block_set_size (iface, size);
 
   /* dm-crypt
    *
index 576177a..b173045 100644 (file)
@@ -405,13 +405,34 @@ block_device_update (UDisksLinuxBlockObject *object,
 /* org.freedesktop.UDisks.Filesystem */
 
 static gboolean
+drive_does_not_detect_media_change (UDisksLinuxBlockObject *object)
+{
+  gboolean ret = FALSE;
+  UDisksObject *drive_object;
+
+  drive_object = udisks_daemon_find_object (object->daemon, udisks_block_get_drive (object->iface_block_device));
+  if (drive_object != NULL)
+    {
+      UDisksDrive *drive = udisks_object_get_drive (drive_object);
+      if (drive != NULL)
+        {
+          ret = ! udisks_drive_get_media_change_detected (drive);
+          g_object_unref (drive);
+        }
+      g_object_unref (drive_object);
+    }
+  return ret;
+}
+
+static gboolean
 filesystem_check (UDisksLinuxBlockObject *object)
 {
   gboolean ret;
   UDisksMountType mount_type;
 
   ret = FALSE;
-  if (g_strcmp0 (udisks_block_get_id_usage (object->iface_block_device), "filesystem") == 0 ||
+  if (drive_does_not_detect_media_change (object) ||
+      g_strcmp0 (udisks_block_get_id_usage (object->iface_block_device), "filesystem") == 0 ||
       (udisks_mount_monitor_is_dev_in_use (object->mount_monitor,
                                            g_udev_device_get_device_number (object->device),
                                            &mount_type) &&
index 8ca3080..0a77ae3 100644 (file)
@@ -214,7 +214,7 @@ set_media (UDisksDrive      *iface,
   g_ptr_array_add (media_compat_array, NULL);
 
   media_in_drive = "";
-  if (udisks_drive_get_size (iface) > 0)
+  if (udisks_drive_get_media_available (iface))
     {
       for (n = 0; media_mapping[n].udev_property != NULL; n++)
         {
@@ -320,6 +320,9 @@ udisks_linux_drive_update (UDisksLinuxDrive       *drive,
   UDisksDrive *iface = UDISKS_DRIVE (drive);
   GUdevDevice *device;
   gchar *sort_key;
+  guint64 size;
+  gboolean media_available;
+  gboolean media_change_detected;
 
   device = udisks_linux_drive_object_get_device (object, TRUE /* get_hw */);
   if (device == NULL)
@@ -415,6 +418,11 @@ udisks_linux_drive_update (UDisksLinuxDrive       *drive,
             {
               udisks_drive_set_vendor (iface, vendor);
             }
+          /* workaround for missing ID_VENDOR for floppy drives */
+          else if (g_str_has_prefix (name, "fd"))
+            {
+              udisks_drive_set_vendor (iface, "");
+            }
           /* workaround for missing ID_VENDOR on virtio-blk */
           else if (g_str_has_prefix (name, "vd"))
             {
@@ -439,6 +447,11 @@ udisks_linux_drive_update (UDisksLinuxDrive       *drive,
             {
               udisks_drive_set_model (iface, model);
             }
+          /* workaround for missing ID_MODEL for floppy drives */
+          else if (g_str_has_prefix (name, "fd"))
+            {
+              udisks_drive_set_model (iface, "Floppy Drive");
+            }
           /* workaround for missing ID_MODEL on virtio-blk */
           else if (g_str_has_prefix (name, "vd"))
             {
@@ -459,7 +472,12 @@ udisks_linux_drive_update (UDisksLinuxDrive       *drive,
 
   /* common bits go here */
   udisks_drive_set_media_removable (iface, g_udev_device_get_sysfs_attr_as_boolean (device, "removable"));
-  udisks_drive_set_size (iface, udisks_daemon_util_block_get_size (device));
+  size = udisks_daemon_util_block_get_size (device,
+                                            &media_available,
+                                            &media_change_detected);
+  udisks_drive_set_size (iface, size);
+  udisks_drive_set_media_available (iface, media_available);
+  udisks_drive_set_media_change_detected (iface, media_change_detected);
   set_media (iface, device);
   set_rotation_rate (iface, device);
   set_connection_bus (iface, device);
index 3cec14a..d67b9f1 100644 (file)
@@ -728,6 +728,13 @@ udisks_linux_drive_object_should_include_device (GUdevClient  *client,
 
       name = g_udev_device_get_name (device);
 
+      /* workaround for floppy devices */
+      if (g_str_has_prefix (name, "fd"))
+        {
+          vpd = g_strdup_printf ("pcfloppy_%s", name);
+          goto found;
+        }
+
       /* workaround for missing serial/wwn on virtio-blk */
       if (g_str_has_prefix (name, "vd"))
         {