Exemple #1
0
int 
main (int argc, char *argv[])
{
	char *udi;
	char *device_file, *raw_device_file;
	LibHalContext *ctx = NULL;
	DBusError error;
	char *bus;
	char *drive_type;
	int state, last_state;
	char *support_media_changed_str;
	int support_media_changed;
	int fd = -1;

	if ((udi = getenv ("UDI")) == NULL)
		goto out;
	if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL)
		goto out;
	if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL)
		goto out;
	if ((bus = getenv ("HAL_PROP_STORAGE_BUS")) == NULL)
		goto out;
	if ((drive_type = getenv ("HAL_PROP_STORAGE_DRIVE_TYPE")) == NULL)
		goto out;

	drop_privileges ();

	setup_logger ();

	support_media_changed_str = getenv ("HAL_PROP_STORAGE_CDROM_SUPPORT_MEDIA_CHANGED");
	if (support_media_changed_str != NULL && strcmp (support_media_changed_str, "true") == 0)
		support_media_changed = TRUE;
	else
		support_media_changed = FALSE;

	dbus_error_init (&error);

	if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
		goto out;
	}
	my_dbus_error_free (&error);

	if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
		goto out;
	}
	my_dbus_error_free (&error);

	printf ("Doing addon-storage for %s (bus %s) (drive_type %s) (udi %s)\n", device_file, bus, drive_type, udi);

	last_state = state = DKIO_NONE;

	/* Linux version of this addon attempts to re-open the device O_EXCL
	 * every 2 seconds, trying to figure out if some other app,
	 * like a cd burner, is using the device. Aside from questionable
	 * value of this (apps should use HAL's locked property or/and
	 * Solaris in_use facility), but also frequent opens/closes
	 * keeps media constantly spun up. All this needs more thought.
	 */
	for (;;) {
		if (is_mounted (device_file)) {
			close_device (&fd);
			sleep (SLEEP_PERIOD);
		} else if ((fd < 0) && ((fd = open (raw_device_file, O_RDONLY | O_NONBLOCK)) < 0)) {
			HAL_DEBUG (("open failed for %s: %s", raw_device_file, strerror (errno)));
			sleep (SLEEP_PERIOD);
		} else {
			/* Check if a disc is in the drive */
			/* XXX initial call always returns inserted
			 * causing unnecessary rescan - optimize?
			 */
			if (ioctl (fd, DKIOCSTATE, &state) == 0) {
				if (state == last_state) {
					HAL_DEBUG (("state has not changed %d %s", state, device_file));
					continue;
				} else {
					HAL_DEBUG (("new state %d %s", state, device_file));
				}

				switch (state) {
				case DKIO_EJECTED:
					HAL_DEBUG (("Media removal detected on %s", device_file));
					last_state = state;

					libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
					my_dbus_error_free (&error);

					/* attempt to unmount all childs */
					unmount_childs (ctx, udi);

					/* could have a fs on the main block device; do a rescan to remove it */
					libhal_device_rescan (ctx, udi, &error);
					my_dbus_error_free (&error);
					break;

				case DKIO_INSERTED:
					HAL_DEBUG (("Media insertion detected on %s", device_file));
					last_state = state;

					libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);
					my_dbus_error_free (&error);

					/* could have a fs on the main block device; do a rescan to add it */
					libhal_device_rescan (ctx, udi, &error);
					my_dbus_error_free (&error);
					break;

				case DKIO_DEV_GONE:
					HAL_DEBUG (("Device gone detected on %s", device_file));
					last_state = state;

					unmount_childs (ctx, udi);
					close_device (&fd);
					goto out;

				case DKIO_NONE:
				default:
					break;
				}
			} else {
				HAL_DEBUG (("DKIOCSTATE failed: %s\n", strerror(errno)));
				sleep (SLEEP_PERIOD);
			}
		}
	}

out:
	if (ctx != NULL) {
		my_dbus_error_free (&error);
		libhal_ctx_shutdown (ctx, &error);
		libhal_ctx_free (ctx);
	}

	return 0;
}
/* returns: whether the state changed */
static gboolean
poll_for_media_force (void)
{
        int fd;
        int got_media;
        int old_media_status;

	got_media = FALSE;

        old_media_status = media_status;
	if (is_cdrom) {
		int drive;
		
		fd = open (device_file, O_RDONLY | O_NONBLOCK | O_EXCL);
		
		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)) {
                                if (!is_locked_via_o_excl) {
                                        is_locked_via_o_excl = TRUE;
                                        update_proc_title ();
                                } else {
                                        is_locked_via_o_excl = TRUE;
                                }
				goto skip_check;
                        }
			
			fd = open (device_file, O_RDONLY | O_NONBLOCK);
		}
		
		if (fd < 0) {
			HAL_ERROR (("open failed for %s: %s", device_file, strerror (errno))); 
			goto skip_check;
		}

                if (is_locked_via_o_excl) {
                        is_locked_via_o_excl = FALSE;
                        update_proc_title ();
                }
		
		
		/* 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) {
		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 (support_media_changed &&
			    ioctl (fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT) && 
			    ioctl (fd, CDROM_MEDIA_CHANGED, CDSL_CURRENT)) {
			} else {
				got_media = TRUE;
			}
			break;
			
		case -1:
			HAL_ERROR (("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno)));
			break;
			
		default:
			break;
		}
		
		/* check if eject button was pressed */
		if (got_media) {
			unsigned char cdb[10] = { 0x4a, 1, 0, 0, 16, 0, 0, 0, 8, 0};
			unsigned char buffer[8];
			struct sg_io_hdr sg_h;
			int retval;
			
			memset(buffer, 0, sizeof(buffer));
			memset(&sg_h, 0, sizeof(struct sg_io_hdr));
			sg_h.interface_id = 'S';
			sg_h.cmd_len = sizeof(cdb);
			sg_h.dxfer_direction = SG_DXFER_FROM_DEV;
			sg_h.dxfer_len = sizeof(buffer);
			sg_h.dxferp = buffer;
			sg_h.cmdp = cdb;
			sg_h.timeout = 5000;
			retval = ioctl(fd, SG_IO, &sg_h);
			if (retval == 0 && sg_h.status == 0 && (buffer[4] & 0x0f) == 0x01) {
				DBusError error;
				
				/* emit signal from drive device object */
				dbus_error_init (&error);
				libhal_device_emit_condition (ctx, udi, "EjectPressed", "", &error);
				LIBHAL_FREE_DBUS_ERROR (&error);
			}
		}
		close (fd);
	} else {
		fd = open (device_file, O_RDONLY);
		if (fd < 0 && errno == ENOMEDIUM) {
			got_media = FALSE;
		} else if (fd >= 0) {
			got_media = TRUE;
			close (fd);
		} else {
			HAL_ERROR (("open failed for %s: %s", device_file, strerror (errno))); 
			goto skip_check;
		}
	}
	
	/* set correct state on startup, this avoid endless loops if there was a media in the device on startup */
	if (media_status == MEDIA_STATUS_UNKNOWN) {
		if (got_media) 
			media_status = MEDIA_STATUS_NO_MEDIA;
		else 
			media_status = MEDIA_STATUS_GOT_MEDIA;	
	}

	switch (media_status) {
	case MEDIA_STATUS_GOT_MEDIA:
		if (!got_media) {
			DBusError error;
			
			HAL_DEBUG (("Media removal detected on %s", device_file));
			libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, NULL);
			libhal_device_set_property_string (ctx, udi, "storage.partitioning_scheme", "", NULL);
			
			
			/* attempt to unmount all childs */
			unmount_childs (ctx, udi);
			
			/* could have a fs on the main block device; do a rescan to remove it */
			dbus_error_init (&error);
			libhal_device_rescan (ctx, udi, &error);
			LIBHAL_FREE_DBUS_ERROR (&error);
			
			/* have to this to trigger appropriate hotplug events */
			fd = open (device_file, O_RDONLY | O_NONBLOCK);
			if (fd >= 0) {
				ioctl (fd, BLKRRPART);
				close (fd);
			}
		}
		break;
		
	case MEDIA_STATUS_NO_MEDIA:
		if (got_media) {
			DBusError error;
			
			HAL_DEBUG (("Media insertion detected on %s", device_file));
			
			/* our probe will trigger the appropriate hotplug events */
			libhal_device_set_property_bool (
				ctx, udi, "storage.removable.media_available", TRUE, NULL);
			
			/* could have a fs on the main block device; do a rescan to add it */
			dbus_error_init (&error);
			libhal_device_rescan (ctx, udi, &error);
			LIBHAL_FREE_DBUS_ERROR (&error);
		}
		break;
		
	case MEDIA_STATUS_UNKNOWN:
	default:
		break;
	}
	
	/* update our current status */
	if (got_media)
		media_status = MEDIA_STATUS_GOT_MEDIA;
	else
		media_status = MEDIA_STATUS_NO_MEDIA;
	
	/*HAL_DEBUG (("polling %s; got media=%d", device_file, got_media));*/
	
skip_check:
	return old_media_status != media_status;
}