Logo Search packages:      
Sourcecode: hal version File versions

static dbus_bool_t detect_media ( HalDevice *  d,
dbus_bool_t  force_poll 
) [static]

Check for media on a block device that is not a volume

Parameters:
d Device to inspect; can be any device, but it will only have effect if the device is in the GDL and is of capability block and is not a volume
force_poll If TRUE, do polling even though storage.media_check_enabled==FALSE
Returns:
TRUE if the GDL was modified

Definition at line 794 of file block_class_device.c.

References class_device_move_from_tdl_to_gdl(), force_unmount(), force_unmount_of_all_childs(), get_first_valid_partition(), HAL_ERROR, HAL_INFO, is_mounted(), ClassDeviceHandler_s::merge_or_add, and rename_and_merge().

Referenced by foreach_detect_media().

{
      const char *device_file;
      HalDevice *child;
      int fd;
      struct volume_id *vid;
      gboolean no_partitions;
      dbus_bool_t is_cdrom;
      dbus_bool_t got_media;

      /* respect policy unless we force */
      if (!force_poll &&
          !hal_device_property_get_bool (d, "storage.media_check_enabled"))
            return FALSE;

      /* Refuse to poll on storage devices without removable media */
      if (!force_poll && !hal_device_property_get_bool (d, "storage.removable"))
            return FALSE;

      /* need to be in GDL */
      if (!hal_device_store_find (hald_get_gdl (), hal_device_get_udi (d)))
            return FALSE;

      /* need to be a drive and not a volume */
      if (!hal_device_has_property (d, "block.is_volume") ||
          !hal_device_has_property (d, "block.device") ||
          hal_device_property_get_bool (d, "block.is_volume"))
            return FALSE;

      /* we have to do special treatment for optical drives */
      is_cdrom = hal_device_has_property (d, "storage.drive_type") &&
            strcmp (hal_device_property_get_string (d, "storage.drive_type"), "cdrom") == 0 &&
            hal_device_property_get_bool (d, "storage.cdrom.support_media_changed");

      /* current state of media */
      no_partitions = hal_device_property_get_bool (d, "block.no_partitions");

      got_media = FALSE;

      device_file = hal_device_property_get_string (d, "block.device");

      if (device_file == NULL)
            return FALSE;

      if (force_poll) {
            HAL_INFO (("Forcing check for media check on device %s", device_file));
      }

      if (is_cdrom)
            fd = open (device_file, O_RDONLY | O_NONBLOCK | O_EXCL);
      else
            fd = open (device_file, O_RDONLY);

      if (is_cdrom) {
            int drive;

            if (fd < 0 && errno == EBUSY) {
                  /* this means the disc is mounted or some other app,
                   * like a cd burner, has already opened O_EXCL */
                  
                  /* HOWEVER, when starting hald, a disc may be
                   * mounted; so check /etc/mtab to see if it
                   * actually is mounted. If it is we retry to open
                   * without O_EXCL
                   */
                  if (!is_mounted (device_file))
                        return FALSE;
            
                  fd = open (device_file, O_RDONLY | O_NONBLOCK);
            }

            if (fd < 0)
                  return FALSE;

            /* Check if a disc is in the drive
             *
             * @todo Use MMC-2 API if applicable
             */
            drive = ioctl (fd, CDROM_DRIVE_STATUS, CDSL_CURRENT);
            switch (drive) {
                  /* explicit fallthrough */
            case CDS_NO_INFO:
            case CDS_NO_DISC:
            case CDS_TRAY_OPEN:
            case CDS_DRIVE_NOT_READY:
                  break;
                  
            case CDS_DISC_OK:
                  /* some CD-ROMs report CDS_DISK_OK even with an open
                   * tray; if media check has the same value two times in
                   * a row then this seems to be the case and we must not
                   * report that there is a media in it. */
                  if (hal_device_property_get_bool (d, "storage.cdrom.support_media_changed") &&
                      ioctl (fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT) && 
                      ioctl (fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT)) {
                        /*HAL_INFO (("CD-ROM drive %s: media checking is broken, assuming no CD is inside.", device_file));*/
                  } else {
                      got_media = TRUE;
                  }
                  break;
                  
            case -1:
                HAL_ERROR(("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno)));
                break;

            default:
                  break;
            }

      } else {
            if (fd < 0 && errno == ENOMEDIUM) {
                  got_media = FALSE;
            } else {
                  got_media = TRUE;
            }

      }

      if (!got_media) {
            /* No media in drive; if we had volumes for this drive,
             * now is a good time to remove them.. */
            
            if (no_partitions) {
                  child = hal_device_store_match_key_value_string (
                        hald_get_gdl (), "info.parent",
                        hal_device_get_udi (d));
                  
                  /* We can have only one child, simply remove it */
                  
                  if (child != NULL ) {
                        HAL_INFO (("Removing volume for "
                                 "no_partitions device %s",
                                 device_file));

                        force_unmount (child);
                        
                        g_signal_connect (child, "callouts_finished",
                                      G_CALLBACK (volume_remove_from_gdl), NULL);
                        hal_callout_device (child, FALSE);
                        
                        hal_device_property_set_bool (d, "block.no_partitions", 
                                                hal_device_property_get_bool (
                                                      d, "storage.no_partitions_hint"));
                        hal_device_property_set_bool (d, "block.have_scanned", FALSE);

                        if (fd >= 0)
                              close (fd);
                        return TRUE;
                  }
                  
            } else {
                  
                  /* Just unmount the childs already mounted (otherwise
                   * no hotplug will happen). This causes storm of hotplug
                   * remove events and The Right Stuff Happens(tm)
                   */
                  
                  force_unmount_of_all_childs (d);
                  
                  hal_device_property_set_bool (d, "block.no_partitions", 
                                          hal_device_property_get_bool (
                                                d, "storage.no_partitions_hint"));

                  hal_device_property_set_bool (d, "block.have_scanned", FALSE);
            }

            if (fd >= 0)
                  close (fd);
            return FALSE;
      }

      if (fd < 0)
            return FALSE;

      close (fd);

      /* Now got_media==TRUE and fd>0.. So, Yay!, we got media
       *
       * See if we already got children (or children underway :-),
       * if so, just exit this function as life is good as nothing
       * really changed
       */

      child = get_child_device_gdl (d);
      if (child == NULL) {
            child = get_child_device_tdl (d);
      }
      if (child != NULL) {
            return FALSE;
      }

      /* No children... So, this means that the media have just been
       * inserted. The poll we just did will make the kernel search
       * for partition tables. If there is indeed a known, to the
       * kernel, partition table then we'll get hotplug events and
       * life is good because these are handled elsewhere.
       *
       * In the event there is no partition table, then we get no
       * feedback whatsoever. Which is kind of rude of the kernel,
       * but hey...
       *
       * Therefore, we need to scan the media to see if if the
       * top-level block device is indeed a filesystem we know. If
       * yes, then there can't be any partition table. If we find
       * anything, we set the block.no_partitions to TRUE. And then
       * we add a child. This needs to be set to the value of
       * storage.no_partitions_hint when we detect that the media 
       * is removed.
       *
       * We also set block.have_scanned to TRUE so we won't do this
       * again (in the event that the kernel didn't find a partition
       * table and the top-level block device didn't contain an
       * known (to HAL) filesystem). Clearly, this must be set to
       * FALSE when media is removed.
       */

      if (!hal_device_property_get_bool (d, "block.have_scanned")) {
            ClassAsyncData *cad;

            hal_device_property_set_bool (d, "block.have_scanned", TRUE);

            child = hal_device_new ();

            /* copy block.* properties from parent */
            hal_device_merge_with_rewrite (child, d, "block", "block");
            /* in particular, set this to the value of storage.no_partitions_hint */
            hal_device_property_set_bool (child, "block.no_partitions", 
                                    hal_device_property_get_bool (d, "block.no_partitions"));

            /* modify some properties */
            hal_device_property_set_bool (child, "block.is_volume", TRUE);
            hal_device_property_set_bool (child, "block.have_scanned", FALSE);

            /* add info.* properties */
            hal_device_property_set_string (child, "info.bus", "block");
            hal_device_property_set_string (child, "info.capabilities", "block volume");
            hal_device_property_set_string (child, "info.category", "volume");
            hal_device_property_set_string (child, "info.parent", d->udi);
            hal_device_property_set_string (child, "info.product", "Volume");

            /* set defaults */
            hal_device_property_set_string (child, "volume.fstype", "");
            hal_device_property_set_string (child, "volume.fsusage", "");
            hal_device_property_set_string (child, "volume.fsversion", "");
            hal_device_property_set_string (child, "volume.uuid", "");
            hal_device_property_set_string (child, "volume.label", "");
            hal_device_property_set_string (child, "volume.mount_point", "");
            hal_device_property_set_bool (child, "volume.is_mounted", FALSE);
            hal_device_property_set_bool (child, "volume.is_disc", is_cdrom);
            hal_device_property_set_bool (d, "volume.is_partition", FALSE);

            /* set the size */
            volume_set_size (child, force_poll);

            if (is_cdrom )
                  detect_disc (child, device_file);

            vid = NULL;

            if (!is_cdrom || 
                (is_cdrom && hal_device_property_get_bool (child, "volume.disc.has_data"))) {

                  HAL_INFO (("Detecting if %s contains a fs", device_file));

                  vid = volume_id_open_node (device_file);
                  if (vid == NULL) {
                        g_object_unref (child);
                        return FALSE;
                  }
                  
                  if (volume_id_probe (vid, VOLUME_ID_ALL, 0, 0) != 0) {
                        if (is_cdrom) {
                              /* volume_id cannot probe blank/audio discs etc,
                               * so don't fail for them, just set vid to NULL */
                              volume_id_close (vid);
                              vid = NULL;
                        } else {
                              g_object_unref (child);
                              volume_id_close (vid);
                              return FALSE;
                        }
                  }

            }

            /* Unfortunally, linux doesn't scan optical discs for partition
             * tables. We only get the main device, the kernel doesn't
             * create childs for us.
             */
            no_partitions = is_cdrom || (vid != NULL && vid->usage_id == VOLUME_ID_FILESYSTEM);
            hal_device_property_set_bool (d, "block.no_partitions", no_partitions);

            if (!no_partitions) {
                  if (vid != NULL)
                        volume_id_close (vid);
                  g_object_unref (child);
                  return FALSE;
            }

            HAL_INFO (("Media in no_partitions device %s", device_file));

            hal_device_store_add (hald_get_tdl (), child);
            g_object_unref (child);

            /* If _we_ detect a partition table like a apple hfs cd, we just
             * stop at the first partiton with a valid filesystem
             */
            if (vid != NULL) {
                  if (vid->partition_count > 0) {
                        struct volume_id *p;
                        
                        p = get_first_valid_partition(vid);
                        if (p != NULL) {
                              set_volume_id_values(child, p);
                              volume_id_close(p);
                        }
                  } else {
                        set_volume_id_values(child, vid);
                  }
            }

            /* set UDI (will scan .fdi files and merge from unplugged) */
            rename_and_merge (child, block_class_compute_udi, "volume");

            cad = g_new0 (ClassAsyncData, 1);
            cad->device = child;
            cad->handler = &block_class_handler;
            cad->merge_or_add = block_class_handler.merge_or_add;

            /* add new device */
            g_signal_connect (child, "callouts_finished",
                  G_CALLBACK (class_device_move_from_tdl_to_gdl), cad);
            hal_callout_device (child, TRUE);

            if (vid != NULL)
                  volume_id_close (vid);
            return TRUE;
      }

      return FALSE;
}


Generated by  Doxygen 1.6.0   Back to index