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; }