hal/hald/linux2/addons addon-storage.c,1.1,1.2
David Zeuthen
david at freedesktop.org
Fri Feb 11 14:01:10 PST 2005
Update of /cvs/hal/hal/hald/linux2/addons
In directory gabe:/tmp/cvs-serv4717/hald/linux2/addons
Modified Files:
addon-storage.c
Log Message:
2005-02-11 David Zeuthen <davidz at redhat.com>
With this path, all storage devices should be working just as
well as on the 0.4.x branch.
In fact, since we're doing things in separate processes hald now
nicely handles my very troublesome USB 6in1 card reader. There's
other improvements too; we handle media with non-partitioned file
systems _a lot nicer_, especially those on PCMCIA card
readers (driven by ide-cs) since we now have logic to discard
hotplug rem/add for those partitions.
Rock on.
* libhal/libhal.h: Add prototypes for libhal_device_rescan()
and libhal_device_reprobe()
* libhal/libhal.c (libhal_device_rescan): New function
(libhal_device_reprobe): New function
* hald/linux2/probing/probe-volume.c (main): Be able to probe for
volumes on main block devices. Retrieve optical disc properties
if applicable.
* hald/linux2/probing/probe-storage.c (is_mounted): New function
(main): Add a new option --only-check-for-media which is used on
Rescan() of a storage device. Check for fs on main block device or
a disc in the optical drive. Return code 2 if that is the case.
* hald/linux2/addons/addon-storage.c (force_unmount): New function
(unmount_childs): New function
(is_mounted): New function
(main): Do lazy unmount, if necessary, when media goes away. Handle
polling on optical drives.
* hald/linux2/hotplug.h: Add prototype for hotplug_event_reposted()
and hotplug_event_enqueue_at_front().
* hald/linux2/hotplug.c (hotplug_event_reposted): New function;
like event_end but without deleting the hotplug event (useful
for reordering events)
(hotplug_event_enqueue_at_front): New function; to insert events
at the front of the queue
* hald/linux2/blockdev.c:
(generate_fakevolume_hotplug_event_add_for_storage_device): New
function (and what a nice long name :-/)
(add_blockdev_probing_helper_done): Check result from hald-probe-
storage and add a new fakevolume add event if one was detected.
(hotplug_event_begin_add_blockdev): Handle fakevolume add events.
Add some more debug spewage when things fail.
(force_unmount): New function
(hotplug_event_begin_remove_blockdev): Handle fakevolume remove
events; reorder queue to process non-handled volume before
the storage device. Nice.
(block_rescan_storage_done): New function
(blockdev_rescan_device): Actually do something here; a Rescan()
method call on a storage device will induce searching a filesystem
on the main block device
* hald/hald.c (main): Add new master_slave code but comment it out
for now
* fdi/20freedesktop/lexar-media-cf-reader.fdi: Fix up
* fdi/20freedesktop/6in1-card-reader.fdi: Fix up to use new way
of figuring vendor_id/product_id etc.
Index: addon-storage.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/addons/addon-storage.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- addon-storage.c 10 Feb 2005 17:03:57 -0000 1.1
+++ addon-storage.c 11 Feb 2005 22:01:08 -0000 1.2
@@ -34,7 +34,8 @@
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/wait.h>
#include <fcntl.h>
#include <unistd.h>
#include <linux/kdev_t.h>
@@ -46,6 +47,97 @@
#include "../probing/shared.h"
+static void
+force_unmount (const char *device_file)
+{
+ pid_t pid;
+
+ switch (pid = fork ()) {
+ case -1:
+ break;
+ case 0:
+ execl ("/bin/umount", "-l", device_file);
+ break;
+ default:
+ waitpid (pid, NULL, 0);
+ break;
+ }
+}
+
+static void
+unmount_childs(LibHalContext *ctx, const char *udi)
+{
+ int num_volumes;
+ char **volumes;
+ DBusError error;
+
+ /* need to force unmount all partitions */
+ dbus_error_init (&error);
+ if ((volumes = libhal_manager_find_device_string_match (
+ ctx, "block.storage_device", udi, &num_volumes, &error)) != NULL) {
+ int i;
+
+ for (i = 0; i < num_volumes; i++) {
+ char *vol_udi;
+
+ vol_udi = volumes[i];
+ dbus_error_init (&error);
+ if (libhal_device_get_property_bool (ctx, vol_udi, "block.is_volume", &error)) {
+ dbus_error_init (&error);
+ if (libhal_device_get_property_bool (ctx, vol_udi, "volume.is_mounted", &error)) {
+ char *vol_device_file;
+
+ dbus_error_init (&error);
+ vol_device_file = libhal_device_get_property_string (ctx, vol_udi,
+ "block.device", &error);
+ if (vol_device_file != NULL) {
+ HAL_INFO (("Forcing unmount for %s", vol_device_file));
+
+ /* TODO: emit DeviceCondition */
+ force_unmount (vol_device_file);
+ libhal_free_string (vol_device_file);
+ }
+ }
+ }
+ }
+ libhal_free_string_array (volumes);
+ }
+}
+
+/** Check if a filesystem on a special device file is mounted
+ *
+ * @param device_file Special device file, e.g. /dev/cdrom
+ * @return TRUE iff there is a filesystem system mounted
+ * on the special device file
+ */
+static dbus_bool_t
+is_mounted (const char *device_file)
+{
+ FILE *f;
+ dbus_bool_t rc;
+ struct mntent mnt;
+ struct mntent *mnte;
+ char buf[512];
+
+ rc = FALSE;
+
+ if ((f = setmntent ("/etc/mtab", "r")) == NULL)
+ goto out;
+
+ while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
+ if (strcmp (device_file, mnt.mnt_fsname) == 0) {
+ rc = TRUE;
+ goto out1;
+ }
+ }
+
+out1:
+ endmntent (f);
+out:
+ return rc;
+}
+
+
enum {
MEDIA_STATUS_UNKNOWN = 0,
MEDIA_STATUS_GOT_MEDIA = 1,
@@ -64,6 +156,10 @@
char *drive_type;
int is_cdrom;
int media_status;
+ int storage_policy_should_mount;
+ char *storage_policy_should_mount_str;
+ char *support_media_changed_str;
+ int support_media_changed;
if ((udi = getenv ("UDI")) == NULL)
goto out;
@@ -73,6 +169,13 @@
goto out;
if ((drive_type = getenv ("HAL_PROP_STORAGE_DRIVE_TYPE")) == NULL)
goto out;
+ storage_policy_should_mount_str = getenv ("HAL_PROP_STORAGE_POLICY_SHOULD_MOUNT");
+
+ 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 ((conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error)) == NULL)
@@ -87,7 +190,7 @@
printf ("**************************************************\n");
printf ("**************************************************\n");
- printf ("Doing addon-storage for %s (bus %s) (drive_type %s)\n", device_file, bus, drive_type);
+ printf ("Doing addon-storage for %s (bus %s) (drive_type %s) (udi %s)\n", device_file, bus, drive_type, udi);
printf ("**************************************************\n");
printf ("**************************************************\n");
@@ -96,63 +199,151 @@
else
is_cdrom = 0;
+ if (storage_policy_should_mount_str != NULL && strcmp (storage_policy_should_mount_str, "true") == 0)
+ storage_policy_should_mount = 1;
+ else
+ storage_policy_should_mount = 0;
media_status = MEDIA_STATUS_UNKNOWN;
- while (1) {
+ while (TRUE) {
int fd;
+ int got_media;
+
+ got_media = FALSE;
if (is_cdrom) {
-
- /* TODO */
- } else {
- int got_media;
+ int drive;
- fd = open (device_file, O_RDONLY);
- if (fd < 0 && errno == ENOMEDIUM) {
- got_media = FALSE;
- } else {
- got_media = TRUE;
+ 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))
+ goto skip_check;
+
+ fd = open (device_file, O_RDONLY | O_NONBLOCK);
}
- close (fd);
- switch (media_status)
- {
- case MEDIA_STATUS_GOT_MEDIA:
- if (!got_media) {
- /* signal that parent should force unmount all partitions */
- HAL_INFO (("Media removal detected on %s", device_file));
- }
- break;
+ if (fd < 0) {
+ HAL_INFO (("open failed for %s: %s", device_file, strerror (errno)));
+ goto skip_check;
+ }
- case MEDIA_STATUS_NO_MEDIA:
- if (got_media) {
- HAL_INFO (("Media insertion detected on %s", device_file));
- /* will trigger appropriate hotplug events */
- fd = open (device_file, O_RDONLY | O_NONBLOCK);
- if (fd >= 0)
- ioctl (fd, BLKRRPART);
- close (fd);
+
+ /* 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 (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:
- case MEDIA_STATUS_UNKNOWN:
break;
}
+ close (fd);
+ } else {
- /* update our current status */
- if (got_media)
- media_status = MEDIA_STATUS_GOT_MEDIA;
- else
- media_status = MEDIA_STATUS_NO_MEDIA;
-
+ fd = open (device_file, O_RDONLY);
+ if (fd < 0 && errno == ENOMEDIUM) {
+ got_media = FALSE;
+ close (fd);
+ } else if (fd >= 0) {
+ got_media = TRUE;
+ close (fd);
+ } else {
+ HAL_INFO (("open failed for %s: %s", device_file, strerror (errno)));
+ close (fd);
+ goto skip_check;
+ }
+ }
- HAL_INFO (("polling %s; got media=%d", device_file, got_media));
+ switch (media_status)
+ {
+ case MEDIA_STATUS_GOT_MEDIA:
+ if (!got_media) {
+ DBusError error;
+
+ HAL_INFO (("Media removal detected on %s", device_file));
+
+ /* have to unmount all childs, but only if we're doing policy on the device */
+ if (storage_policy_should_mount)
+ 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);
+
+ /* 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_INFO (("Media insertion detected on %s", device_file));
+ /* our probe will trigger the appropriate hotplug events */
+
+ /* 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);
+
+ }
+ break;
+
+ default:
+ case MEDIA_STATUS_UNKNOWN:
+ break;
}
+
+ /* update our current status */
+ if (got_media)
+ media_status = MEDIA_STATUS_GOT_MEDIA;
+ else
+ media_status = MEDIA_STATUS_NO_MEDIA;
+
+
+ HAL_INFO (("polling %s; got media=%d", device_file, got_media));
+
+ skip_check:
sleep (2);
+
}
out:
More information about the hal-commit
mailing list