hal/hald/linux2 blockdev.c, 1.2, 1.3 blockdev.h, 1.1, 1.2 hotplug.c, 1.9, 1.10 osspec.c, 1.11, 1.12

David Zeuthen david at freedesktop.org
Thu Feb 10 09:04:00 PST 2005


Update of /cvs/hal/hal/hald/linux2
In directory gabe:/tmp/cvs-serv28549/hald/linux2

Modified Files:
	blockdev.c blockdev.h hotplug.c osspec.c 
Log Message:
2005-02-10  David Zeuthen  <davidz at redhat.com>

	* volume_id/fat.c (volume_id_probe_vfat): Must have been a typo by Kay,
	changed from VOLUME_ID_DISKLABEL to VOLUME_ID_FILESYSTEM.

	* tools/fstab-sync.c (remove_udi): Remember to init the DBusError since
	some operations may fail.
	(main): Look at $HALD_ACTION for add, remove instead of first 
	positional parameter $1.

	* hald/linux2/probing/probe-volume.c: New file

	* hald/linux2/probing/probe-storage.c: New file

	* hald/linux2/probing/linux_dvd_rw_utils.[ch]: New files (imported
	from hal-0.4.x)

	* hald/linux2/probing/Makefile.am: Add rules for hald-probe-storage
	and hald-probe-volume

	* hald/linux2/addons/addon-storage.c: New file

	* hald/linux2/addons/Makefile.am: Add rules for hald-addon-storage

	* hald/linux2/osspec.c (sigio_handler): New function
	(sigio_iochn_data): New function
	(osspec_init): Set up signal handler for SIGIO and the neccesary
	pipes to handle it safely. Set up directory watcher for /etc and
	invoke blockdev_mtab_changed whenever that happens

	* hald/linux2/hotplug.c (hotplug_rescan_device): Call blockdev_*
	if appropriate

	* hald/linux2/blockdev.h: Add some new prototype for interacting
	with hotplug.c (much like what physdev.h and classdev.h)
	exported. Also add the prototype for a new function
	blockdev_mtab_changed.

	* hald/linux2/blockdev.c: Actually put some code here (the previous
	code was just boiler plate).

	* hald/util.h (struct HalHelperData_s): Add boolean already_issued_
	callback

	* hald/util.c (hal_util_get_string_from_file): Truncate whitespace
	from string read
	(hal_util_terminate_helper): Don't remove the child watcher source,
	but set a flag that we already did the callback and helper_child_exited
	will reap the child (including removing sources). This helps reap the
	zombies I've been seeing.
	(helper_child_timeout): -do-
	(helper_child_exited): Only do callback if we haven't already done
	so.

	* hald/debug-hald.sh: Another nice script for running gdb on hald;
	just run this script and invoke the run command from the gdb console.

	* hald/run-hald.sh: Also export ../tools so we can get fstab-sync
	going. Set HAL_FDI_SOURCE

	* hald/device_info.c (di_search_and_merge): Respect the env
	var HAL_FDI_SOURCE which is useful for development as hald will
	read you local .fdi files

	* fdi/90defaultpolicy/storage-policy.fdi: Temporarily add
	fstab-sync add/rem callouts (mental note: move to other file
	soon); also add the media detection addon

	* fdi/90defaultpolicy/power-mgmt-policy.fdi: New file

	* fdi/90defaultpolicy/Makefile.am (fdi90defaultpolicydir): Add
	power-mgmt-policy.fdi



Index: blockdev.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/blockdev.c,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- blockdev.c	8 Feb 2005 16:44:20 -0000	1.2
+++ blockdev.c	10 Feb 2005 17:03:57 -0000	1.3
@@ -1,9 +1,9 @@
 /***************************************************************************
  * CVSID: $Id$
  *
- * blockdev.c : Handling of block devices 
+ * blockdev.c : Handling of block devices
  *
- * Copyright (C) 2004 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2005 David Zeuthen, <david at fubar.dk>
  *
  * Licensed under the Academic Free License version 2.0
  *
@@ -28,6 +28,8 @@
 #endif
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
 #include <string.h>
 #include <mntent.h>
 #include <errno.h>
@@ -37,6 +39,15 @@
 #include <sys/un.h>
 #include <sys/utsname.h>
 #include <unistd.h>
+#include <ctype.h>
+#include <unistd.h>
+
+#include <limits.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
@@ -47,6 +58,9 @@
 #include "../hald.h"
 #include "../device_info.h"
 #include "../hald_conf.h"
+#include "../hald_dbus.h"
+
+#include "osspec_linux.h"
 
 #include "util.h"
 #include "coldplug.h"
@@ -55,53 +69,721 @@
 #include "hotplug.h"
 #include "blockdev.h"
 
+/*--------------------------------------------------------------------------------------------------------------*/
+
+static gboolean
+blockdev_compute_udi (HalDevice *d)
+{
+	gchar udi[256];
+
+	if (hal_device_property_get_bool (d, "block.is_volume")) {
+		const char *label;
+		const char *uuid;
+
+		label = hal_device_property_get_string (d, "volume.label");
+		uuid = hal_device_property_get_string (d, "volume.uuid");
+
+		if (uuid != NULL && strlen (uuid) > 0) {
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "/org/freedesktop/Hal/devices/volume_uuid_%s", uuid);
+		} else if (label != NULL && strlen (label) > 0) {
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "/org/freedesktop/Hal/devices/volume_label_%s", uuid);
+		} else {
+			/* fallback to partition number, size */
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "/org/freedesktop/Hal/devices/volume_part%d_size_%lld", 
+					      hal_device_property_get_int (d, "volume.partition.number"),
+					      hal_device_property_get_uint64 (d, "volume.size"));
+		}
+	} else {
+		const char *model;
+		const char *serial;
+
+		model = hal_device_property_get_string (d, "storage.model");
+		serial = hal_device_property_get_string (d, "storage.serial");
+
+		if (serial != NULL) {
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "/org/freedesktop/Hal/devices/storage_serial_%s", 
+					      serial);
+		} else if (model != NULL) {
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "/org/freedesktop/Hal/devices/storage_model_%s", 
+					      model);
+		} else {
+			hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+					      "%s_storage", 
+					      hal_device_property_get_string (d, "storage.physical_device"));
+		}
+	}
+
+	hal_device_set_udi (d, udi);
+	hal_device_property_set_string (d, "info.udi", udi);
+
+	return TRUE;
+}
+
+
+static void 
+blockdev_callouts_add_done (HalDevice *d, gpointer userdata)
+{
+	void *end_token = (void *) userdata;
+
+	HAL_INFO (("Add callouts completed udi=%s", d->udi));
+
+	/* Move from temporary to global device store */
+	hal_device_store_remove (hald_get_tdl (), d);
+	hal_device_store_add (hald_get_gdl (), d);
+
+	hotplug_event_end (end_token);
+}
+
+static void 
+blockdev_callouts_remove_done (HalDevice *d, gpointer userdata)
+{
+	void *end_token = (void *) userdata;
+
+	HAL_INFO (("Remove callouts completed udi=%s", d->udi));
+
+	if (!hal_device_store_remove (hald_get_gdl (), d)) {
+		HAL_WARNING (("Error removing device"));
+	}
+
+	hotplug_event_end (end_token);
+}
+
+static void 
+update_mount_point (HalDevice *d)
+{
+	FILE *f;
+	struct mntent mnt;
+	struct mntent *mnte;
+	const char *device_file;
+	char buf[512];
+
+	if ((device_file = hal_device_property_get_string (d, "block.device")) == NULL)
+		goto out;
+	
+	if ((f = setmntent ("/etc/mtab", "r")) == NULL) {
+		HAL_ERROR (("Could not open /etc/mtab"));
+		goto out;
+	}
+		
+	while ((mnte = getmntent_r (f, &mnt, buf, sizeof(buf))) != NULL) {
+		if (strcmp (mnt.mnt_fsname, device_file) == 0) {
+			device_property_atomic_update_begin ();
+			hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
+			hal_device_property_set_string (d, "volume.mount_point", mnt.mnt_dir);
+			device_property_atomic_update_end ();
+			goto found;
+		}
+	}
+
+	device_property_atomic_update_begin ();
+	hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
+	hal_device_property_set_string (d, "volume.mount_point", "");
+	device_property_atomic_update_end ();
+
+found:		
+	endmntent (f);
+out:
+	;
+}
+
+void 
+blockdev_mtab_changed (void)
+{
+	GSList *i;
+	GSList *volumes;
+
+	volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (),
+								    "volume.fsusage",
+								    "filesystem");
+	for (i = volumes; i != NULL; i = g_slist_next (i)) {
+		HalDevice *d;
+
+		d = HAL_DEVICE (i->data);
+		update_mount_point (d);
+	}
+}
+
+
+static void 
+add_blockdev_probing_helper_done (HalDevice *d, gboolean timed_out, gint return_code, 
+				  gpointer data1, gpointer data2, HalHelperData *helper_data)
+{
+	void *end_token = (void *) data1;
+
+	HAL_INFO (("entering; timed_out=%d, return_code=%d", timed_out, return_code));
+
+	/* Discard device if probing reports failure */
+	if (timed_out || return_code != 0) {
+		hal_device_store_remove (hald_get_tdl (), d);
+		hotplug_event_end (end_token);
+		goto out;
+	}
+
+	if (!blockdev_compute_udi (d)) {
+		hal_device_store_remove (hald_get_tdl (), d);
+		hotplug_event_end (end_token);
+		goto out;
+	}
+
+	/* set block.storage_device for storage devices since only now we know the UDI */
+	if (!hal_device_property_get_bool (d, "block.is_volume")) {
+		hal_device_copy_property (d, "info.udi", d, "block.storage_device");
+	} else {
+		/* check for mount point */
+		update_mount_point (d);
+	}
+
+	/* Merge properties from .fdi files */
+	di_search_and_merge (d);
+	
+	/* TODO: Merge persistent properties */
+
+	/* Run callouts */
+	hal_util_callout_device_add (d, blockdev_callouts_add_done, end_token);
+
+out:
+	;
+}
+
+
+
 void
-hotplug_event_begin_add_blockdev (const gchar *sysfs_path, const char *device_file, gboolean is_partition, 
+hotplug_event_begin_add_blockdev (const gchar *sysfs_path, const gchar *device_file, gboolean is_partition,
 				  HalDevice *parent, void *end_token)
 {
-#if 0
+	gchar *major_minor;
 	HalDevice *d;
+	unsigned int major, minor;
 
-	HAL_INFO (("block_add: sysfs_path=%s dev=%s is_part=%d parent=0x%08x", 
-		 sysfs_path, device_file, is_partition, parent));
+	HAL_INFO (("block_add: sysfs_path=%s dev=%s is_part=%d, parent=0x%08x", 
+		   sysfs_path, device_file, is_partition, parent));
+	
+	/* See if we already have device (which we may have as we're ignoring rem/add
+	 * for certain classes of devices - see hotplug_event_begin_remove_blockdev)
+	 */
+	d = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.sysfs_path", sysfs_path);
+	if (d != NULL) {
+		HAL_INFO (("Ignoring hotplug event"));
+		goto out;
+	}
+
+	if (parent == NULL)
+		goto error;
 
 	d = hal_device_new ();
+	hal_device_property_set_string (d, "linux.sysfs_path", sysfs_path);
 	hal_device_property_set_string (d, "linux.sysfs_path_device", sysfs_path);
-	hal_device_property_set_string (d, "info.udi", sysfs_path);
-	hal_device_property_set_string (d, "info.bus", "block");
-	hal_device_set_udi (d, sysfs_path);
-	
-	if (parent != NULL) {
-		hal_device_property_set_string (d, "info.parent", parent->udi);
+	hal_device_property_set_string (d, "info.parent", parent->udi);
+
+	hal_device_property_set_string (d, "block.device", device_file);
+	if ((major_minor = hal_util_get_string_from_file (sysfs_path, "dev")) == NULL || 
+	    sscanf (major_minor, "%d:%d", &major, &minor) != 2)
+		goto error;
+
+	hal_device_property_set_int (d, "block.major", major);
+	hal_device_property_set_int (d, "block.minor", minor);
+	hal_device_property_set_bool (d, "block.is_volume", is_partition);
+
+	if (!is_partition) {
+		const char *udi_it;
+		const char *physdev_udi;
+		HalDevice *scsidev;
+		HalDevice *physdev;
+		gboolean is_hotpluggable;
+		gboolean is_removable;
+		gboolean requires_eject;
+		gboolean no_partitions_hint;
+		const gchar *bus;
+		const gchar *parent_bus;
+
+		/********************************
+		 * storage devices
+		 *******************************/
+
+		scsidev = NULL;
+		physdev = NULL;
+		physdev_udi = NULL;		
+
+		is_removable = FALSE;
+		is_hotpluggable = FALSE;
+		requires_eject = FALSE;
+		no_partitions_hint = FALSE;
+
+		/* defaults */
+		hal_device_property_set_string (d, "storage.bus", "unknown");
+		hal_device_property_set_bool (d, "storage.no_partitions_hint", TRUE);
+		hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
+		hal_device_property_set_bool (d, "storage.automount_enabled_hint", TRUE);
+		hal_device_property_set_string (d, "storage.model", "");
+		hal_device_property_set_string (d, "storage.vendor", "");
+		hal_device_property_set_string (d, "storage.drive_type", "disk");
+
+		/* walk up the device chain to find the physical device, 
+		 * start with our parent. On the way, optionally pick up
+		 * the scsi if it exists */
+		udi_it = parent->udi;
+		while (udi_it != NULL) {
+			HalDevice *d_it;
+
+			/* Find device */
+			d_it = hal_device_store_find (hald_get_gdl (), udi_it);
+			g_assert (d_it != NULL);
+
+			/* Check info.bus */
+			if ((bus = hal_device_property_get_string (d_it, "info.bus")) != NULL) {
+				if (strcmp (bus, "scsi") == 0) {
+					scsidev = d_it;
+					physdev = d_it;
+					physdev_udi = udi_it;
+					hal_device_property_set_string (d, "storage.bus", "scsi");
+					hal_device_property_set_string (d, "storage.scsi_device", udi_it);
+					/* want to continue here, because it may be USB or IEEE1394 */
+				}
+
+				if (strcmp (bus, "usb") == 0) {
+					physdev = d_it;
+					physdev_udi = udi_it;
+					is_hotpluggable = TRUE;
+					hal_device_property_set_string (d, "storage.bus", "usb");
+					break;
+				} else if (strcmp (bus, "ieee1394") == 0) {
+					physdev = d_it;
+					physdev_udi = udi_it;
+					is_hotpluggable = TRUE;
+					hal_device_property_set_string (d, "storage.bus", "ieee1394");
+					break;
+				} else if (strcmp (bus, "ide") == 0) {
+					physdev = d_it;
+					physdev_udi = udi_it;
+					hal_device_property_set_string (d, "storage.bus", "ide");
+					break;
+				} else if (strcmp (bus, "mmc") == 0) {
+					physdev = d_it;
+					physdev_udi = udi_it;
+					hal_device_property_set_string (d, "storage.bus", "mmc");
+					break;
+				}
+			}
+
+			/* Go to parent */
+			udi_it = hal_device_property_get_string (d_it, "info.parent");
+		}
+
+		/* needs physical device */
+		if (physdev_udi == NULL)
+			goto error;
+
+		hal_device_property_set_string (d, "storage.physical_device", physdev_udi);
+
+		if (!hal_util_get_int_from_file (sysfs_path, "removable", (gint *) &is_removable, 10))
+			goto error;
+
+		hal_device_property_set_bool (d, "storage.removable", is_removable);
+
+		/* by default, do checks for media if, and only if, the removable file is set to 1
+		 *
+		 * Problematic buses, like IDE, may override this.
+		 */
+		hal_device_property_set_bool (d, "storage.media_check_enabled", is_removable);
+
+		parent_bus = hal_device_property_get_string (parent, "info.bus");
+		HAL_INFO (("parent_bus is %s", parent_bus));
+
+		/* per-bus specific properties */
+		if (strcmp (parent_bus, "ide") == 0) {
+			char buf[256];
+			gchar *media;
+			gchar *model;
+
+			/* Be conservative and don't poll IDE drives at all (except CD-ROM's, see below) */
+			hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
+
+			/* according to kernel source, media can assume the following values:
+			 *
+			 * "disk", "cdrom", "tape", "floppy", "UNKNOWN"
+			 */
+			snprintf (buf, sizeof (buf), "%s/ide/%s", get_hal_proc_path (), hal_util_get_last_element (sysfs_path));
+			if ((media = hal_util_get_string_from_file (buf, "media")) != NULL) {
+				if (strcmp (media, "disk") == 0 ||
+				    strcmp (media, "cdrom") == 0 ||
+				    strcmp (media, "floppy")) {
+					hal_device_property_set_string (d, "storage.drive_type", media);
+				} else {
+					goto error;
+				}
+
+				if (strcmp (media, "cdrom") == 0) {
+					/* only optical drives are the only IDE devices that can safely be polled */
+					hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
+				}
+			}
+
+			if ((model = hal_util_get_string_from_file (buf, "model")) != NULL) {
+				hal_device_property_set_string (d, "storage.model", model);
+				hal_device_property_set_string (d, "info.product", model);
+			}
+
+		} else if (strcmp (parent_bus, "scsi") == 0) {
+			gint type;
+
+			if (hal_util_set_string_from_file (d, "storage.vendor", sysfs_path, "device/vendor"))
+				hal_device_copy_property (d, "storage.vendor", d, "info.vendor");
+			if (hal_util_set_string_from_file (d, "storage.model", sysfs_path, "device/model"))
+				hal_device_copy_property (d, "storage.model", d, "info.product");
+
+			if (!hal_util_get_int_from_file (sysfs_path, "device/type", &type, 0))
+				goto error;
+
+			/* These magic values are documented in the kernel source */
+			switch (type) {
+			case 0:	/* Disk */
+				hal_device_property_set_string (d, "storage.drive_type", "disk");
+				break;
+
+			case 5:	/* CD-ROM */
+				hal_device_property_set_string (d, "storage.drive_type", "cdrom");
+				break;
+
+			default:
+				goto error;
+			}
+
+			/* Check for USB floppy drive by looking at USB Mass Storage interface class
+			 * instead of Protocol: Uniform Floppy Interface (UFI) in /proc as we did before.
+			 *
+			 * (should fix RH bug 133834)
+			 */
+			if (physdev != NULL) {
+				if (hal_device_property_get_int (physdev, "usb.interface.class") == 8 &&
+				    hal_device_property_get_int (physdev, "usb.interface.subclass") == 4 ) {
+					
+					hal_device_property_set_string (d, "storage.drive_type", "floppy");
+					
+					/* My experiments with my USB LaCie Floppy disk
+					 * drive is that polling indeed work (Yay!), so
+					 * we don't set storage.media_check_enabled to 
+					 * FALSE - for devices where this doesn't work,
+					 * we can override it with .fdi files
+					 */
+				}
+			}
+
+		}
+
+		hal_device_property_set_string (d, "info.category", "storage");
+		hal_device_add_capability (d, "storage");
+		hal_device_add_capability (d, "block");
+
+		if (strcmp (hal_device_property_get_string (d, "storage.drive_type"), "cdrom") == 0) {
+			hal_device_add_capability (d, "storage.cdrom");
+			no_partitions_hint = TRUE;
+			requires_eject = TRUE;
+		}
+
+
+		if (strcmp (hal_device_property_get_string (d, "storage.drive_type"), "floppy") == 0) {
+			no_partitions_hint = TRUE;
+		}
+
+		hal_device_property_set_bool (d, "storage.hotpluggable", is_hotpluggable);
+		hal_device_property_set_bool (d, "storage.requires_eject", requires_eject);
+		hal_device_property_set_bool (d, "storage.no_partitions_hint", no_partitions_hint);
+
+		/* add to TDL so prober can access it */
+		hal_device_store_add (hald_get_tdl (), d);
+
+		/* TODO: run prober for 
+		 *
+		 *  - drive_id
+		 *  - cdrom drive properties
+		 *  - non-partitioned filesystem on main block device
+		 */
+
+		/* probe the device */
+		if (hal_util_helper_invoke ("hald-probe-storage", NULL, d, (gpointer) end_token, 
+					    NULL, add_blockdev_probing_helper_done, 
+					    HAL_HELPER_TIMEOUT) == NULL) {
+			hal_device_store_remove (hald_get_tdl (), d);
+			goto error;
+		}
+
+	} else {
+		guint sysfs_path_len;
+
+		/* volumes */
+		hal_device_property_set_string (d, "block.storage_device", parent->udi);
+
+		/* set defaults */
+		hal_device_property_set_string (d, "volume.fstype", "");
+		hal_device_property_set_string (d, "volume.fsusage", "");
+		hal_device_property_set_string (d, "volume.fsversion", "");
+		hal_device_property_set_string (d, "volume.uuid", "");
+		hal_device_property_set_string (d, "volume.label", "");
+		hal_device_property_set_string (d, "volume.mount_point", "");
+		hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
+		hal_device_property_set_bool (
+			d, "volume.is_disc", 
+			strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0);
+		hal_device_property_set_bool (d, "volume.is_partition", TRUE);
+
+		hal_device_property_set_string (d, "info.category", "volume");
+		hal_device_add_capability (d, "volume");
+		hal_device_add_capability (d, "block");
+
+		/* determine partition number */
+		sysfs_path_len = strlen (sysfs_path);
+		if (sysfs_path_len > 0 && isdigit (sysfs_path[sysfs_path_len - 1])) {
+			guint i;
+			for (i = sysfs_path_len - 1; isdigit (sysfs_path[i]); --i)
+				;
+			if (isdigit (sysfs_path[i+1])) {
+				guint partition_number;
+				partition_number = atoi (&sysfs_path[i+1]);
+				hal_device_property_set_int (d, "volume.partition.number", partition_number);
+			} else {
+				goto error;
+			}
+		} else {
+			goto error;
+		}
+
+		/* first estimate - prober may override this...
+		 *
+		 * (block size requires opening the device file)
+		 */
+		hal_device_property_set_int (d, "volume.block_size", 512);
+		if (!hal_util_set_int_from_file (d, "volume.num_blocks", sysfs_path, "size", 0))
+			goto error;
+		hal_device_property_set_uint64 (
+			d, "volume.size", 
+			((dbus_uint64_t)(512)) * 
+			((dbus_uint64_t)(hal_device_property_set_int (d, "volume.block_size", 512))));
+
+		/* add to TDL so prober can access it */
+		hal_device_store_add (hald_get_tdl (), d);
+
+		/* probe the device */
+		if (hal_util_helper_invoke ("hald-probe-volume", NULL, d, (gpointer) end_token, 
+					    NULL, add_blockdev_probing_helper_done, 
+					    HAL_HELPER_TIMEOUT) == NULL) {
+			hal_device_store_remove (hald_get_tdl (), d);
+			goto error;
+		}
 	}
-	
-	hal_device_store_add (hald_get_gdl (), d);
-#endif
 
+	return;
+
+error:
+	if (d != NULL)
+		g_object_unref (d);
+out:
 	hotplug_event_end (end_token);
 }
 
+#if 0
+static void
+force_unmount (HalDevice * d)
+{
+	const char *storudi;
+	HalDevice *stordev;
+	const char *device_file;
+	const char *device_mount_point;
+	const char *umount_argv[4] = { "/bin/umount", "-l", NULL, NULL };
+	char *umount_stdout;
+	char *umount_stderr;
+	int umount_exitcode;
+
+	device_file = hal_device_property_get_string (d, "block.device");
+	device_mount_point = hal_device_property_get_string (d, "volume.mount_point");
+
+	/* Only attempt to 'umount -l' if some hal policy piece are performing policy on the device */
+	storudi = hal_device_property_get_string (d, "block.storage_device");
+	if (storudi == NULL)
+		return;
+	stordev = hal_device_store_find (hald_get_gdl (), storudi);
+	if (stordev == NULL)
+		return;
+	if ((!hal_device_has_property (stordev, "storage.policy.should_mount")) ||
+	    (!hal_device_property_get_bool (stordev, "storage.policy.should_mount")))
+		return;
+
+	umount_argv[2] = device_file;
+
+	if (hal_device_has_property (d, "block.is_volume") &&
+	    hal_device_property_get_bool (d, "block.is_volume") &&
+	    hal_device_property_get_bool (d, "volume.is_mounted") &&
+	    device_mount_point != NULL &&
+	    strlen (device_mount_point) > 0) {
+		HAL_INFO (("attempting /bin/umount -l %s", device_file));
+
+		/* invoke umount */
+		if (g_spawn_sync ("/",
+				  (char **) umount_argv,
+				  NULL,
+				  0,
+				  NULL,
+				  NULL,
+				  &umount_stdout,
+				  &umount_stderr,
+				  &umount_exitcode, NULL) != TRUE) {
+			HAL_ERROR (("Couldn't invoke /bin/umount"));
+		}
+
+		if (umount_exitcode != 0) {
+			HAL_ERROR (("/bin/umount returned %d",
+				    umount_exitcode));
+		} else {
+			/* Tell clients we are going to unmount so they close
+			 * can files - otherwise this unmount is going to stall
+			 *
+			 * One candidate for catching this would be FAM - the
+			 * File Alteration Monitor
+			 *
+			 * Lazy unmount been in Linux since 2.4.11, so we're
+			 * homefree (but other kernels might not support this)
+			 */
+			HAL_INFO (("Goint to emit VolumeUnmountForced('%s', '%s', TRUE)", device_file, device_mount_point));
+			device_send_signal_condition (d,
+						      "VolumeUnmountForced",
+						      DBUS_TYPE_STRING,
+						      device_file,
+						      DBUS_TYPE_STRING,
+						      device_mount_point,
+						      DBUS_TYPE_INVALID);
+		}
+	} else {
+		HAL_INFO (("didn't want to unmount"));
+	}
+}
+#endif
+
 void
 hotplug_event_begin_remove_blockdev (const gchar *sysfs_path, gboolean is_partition, void *end_token)
 {
-#if 0
 	HalDevice *d;
 
 	HAL_INFO (("block_rem: sysfs_path=%s is_part=%d", sysfs_path, is_partition));
 
-	d = hal_device_store_match_key_value_string (hald_get_gdl (), 
-						     "linux.sysfs_path_device", 
-						     sysfs_path);
+	d = hal_device_store_match_key_value_string (hald_get_gdl (), "linux.sysfs_path", sysfs_path);
 	if (d == NULL) {
-		HAL_WARNING (("Couldn't remove device with sysfs path %s - not found", sysfs_path));
-		goto out;
-	}
+		HAL_WARNING (("Error removing device"));
+		hotplug_event_end (end_token);
+	} else {
+		const char *stor_udi;
+		HalDevice *stor_dev;
 
-	if (!hal_device_store_remove (hald_get_gdl (), d)) {
-		HAL_WARNING (("Error removing device with sysfs path %s", sysfs_path));
-	}
+		/* ignore hotplug events on IDE partitions since ide-cs and others causes hotplug 
+		 * rem/add when the last closer (including mount) closes the device.
+		 *
+		 * This causes an infinite loop since we open the device to probe. How nice.
+		 *
+		 * Instead - we'll be removing the partition once the main block device
+		 * goes away
+		 */
+		stor_udi = hal_device_property_get_string (d, "block.storage_device");
+		if (is_partition && 
+		    stor_udi != NULL && 
+		    ((stor_dev = hal_device_store_find (hald_get_gdl (), stor_udi)) != NULL)) {
+			const char *stor_bus;
+			stor_bus = hal_device_property_get_string (stor_dev, "storage.bus");
+			if (strcmp (stor_bus, "ide") == 0) {
+				HAL_INFO (("Ignoring hotplug event"));
+				hotplug_event_end (end_token);
+				goto out;
+			}
+		} else if (!is_partition) {
+			GSList *i;
+			GSList *partitions;
+			/* see if there any partitions lying around that we refused to remove above */
 
-out:
+			partitions = hal_device_store_match_multiple_key_value_string (hald_get_gdl (),
+										       "block.storage_device",
+										       stor_udi);
+			for (i = partitions; i != NULL; i = g_slist_next (i)) {
+				HalDevice *child;
+				HotplugEvent *hotplug_event;
+
+				child = HAL_DEVICE (i->data);
+
+				/* ignore ourself */
+				if (child == d)
+					continue;
+
+				/* yah - generate hotplug event */
+				hotplug_event = blockdev_generate_remove_hotplug_event (child);
+				hotplug_event_enqueue (hotplug_event);
+
+				HAL_INFO (("Generating hotplug rem for ignored IDE partition with udi %s",
+					   child->udi));
+			}
+
+			g_slist_free (partitions);
+		}
+
+		/* if we're mounted, then do a lazy unmount so the system can gracefully recover */
+#if 0
+		if (hal_device_property_get_bool (d, "volume.is_mounted")) {
+			force_unmount (d);
+		}
 #endif
-	hotplug_event_end (end_token);
+
+		hal_util_callout_device_remove (d, blockdev_callouts_remove_done, end_token);
+	}
+out:
+	;
+}
+
+gboolean
+blockdev_rescan_device (HalDevice *d)
+{
+	return FALSE;
+}
+
+
+HotplugEvent *
+blockdev_generate_add_hotplug_event (HalDevice *d)
+{
+	const char *sysfs_path;
+	const char *device_file;
+	HotplugEvent *hotplug_event;
+
+	sysfs_path = hal_device_property_get_string (d, "linux.sysfs_path");
+	device_file = hal_device_property_get_string (d, "block.device");
+
+	hotplug_event = g_new0 (HotplugEvent, 1);
+	hotplug_event->is_add = TRUE;
+	hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+	g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
+	g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
+	if (device_file != NULL)
+		g_strlcpy (hotplug_event->sysfs.device_file, device_file, sizeof (hotplug_event->sysfs.device_file));
+	else
+		hotplug_event->sysfs.device_file[0] = '\0';
+	hotplug_event->sysfs.net_ifindex = -1;
+
+	return hotplug_event;
+}
+
+HotplugEvent *
+blockdev_generate_remove_hotplug_event (HalDevice *d)
+{
+	const char *sysfs_path;
+	HotplugEvent *hotplug_event;
+
+	sysfs_path = hal_device_property_get_string (d, "linux.sysfs_path");
+
+	hotplug_event = g_new0 (HotplugEvent, 1);
+	hotplug_event->is_add = FALSE;
+	hotplug_event->type = HOTPLUG_EVENT_SYSFS;
+	g_strlcpy (hotplug_event->sysfs.subsystem, "block", sizeof (hotplug_event->sysfs.subsystem));
+	g_strlcpy (hotplug_event->sysfs.sysfs_path, sysfs_path, sizeof (hotplug_event->sysfs.sysfs_path));
+	hotplug_event->sysfs.device_file[0] = '\0';
+	hotplug_event->sysfs.net_ifindex = -1;
+
+	return hotplug_event;
 }

Index: blockdev.h
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/blockdev.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- blockdev.h	18 Jan 2005 19:48:13 -0000	1.1
+++ blockdev.h	10 Feb 2005 17:03:57 -0000	1.2
@@ -32,4 +32,12 @@
 
 void hotplug_event_begin_remove_blockdev (const gchar *sysfs_path, gboolean is_partition, void *end_token);
 
+gboolean blockdev_rescan_device (HalDevice *d);
+
+HotplugEvent *blockdev_generate_add_hotplug_event (HalDevice *d);
+
+HotplugEvent *blockdev_generate_remove_hotplug_event (HalDevice *d);
+
+void blockdev_mtab_changed (void);
+
 #endif /* BLOCKDEV_H */

Index: hotplug.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/hotplug.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- hotplug.c	8 Feb 2005 22:36:58 -0000	1.9
+++ hotplug.c	10 Feb 2005 17:03:57 -0000	1.10
@@ -386,7 +386,7 @@
 		break;
 
 	case HOTPLUG_EVENT_SYSFS_BLOCK:
-		ret = FALSE; /* TODO */
+		ret = blockdev_rescan_device (d);
 		break;
 
 	case HOTPLUG_EVENT_ACPI:
@@ -438,7 +438,7 @@
 		break;
 
 	case HOTPLUG_EVENT_SYSFS_BLOCK:
-		e = NULL; /* TODO */
+		e = blockdev_generate_remove_hotplug_event (d);
 		break;
 
 	case HOTPLUG_EVENT_ACPI:
@@ -483,7 +483,7 @@
 		break;
 
 	case HOTPLUG_EVENT_SYSFS_BLOCK:
-		e = NULL; /* TODO */
+		e = blockdev_generate_add_hotplug_event (d);
 		break;
 
 	case HOTPLUG_EVENT_ACPI:

Index: osspec.c
===================================================================
RCS file: /cvs/hal/hal/hald/linux2/osspec.c,v
retrieving revision 1.11
retrieving revision 1.12
diff -u -d -r1.11 -r1.12
--- osspec.c	9 Feb 2005 00:56:38 -0000	1.11
+++ osspec.c	10 Feb 2005 17:03:57 -0000	1.12
@@ -27,6 +27,8 @@
 #  include <config.h>
 #endif
 
+#define _GNU_SOURCE 1
+
 #include <ctype.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -38,6 +40,7 @@
 #include <limits.h>
 #include <errno.h>
 #include <mntent.h>
+#include <signal.h>
 #include <sys/un.h>
 #include <sys/utsname.h>
 #include <unistd.h>
@@ -81,6 +84,7 @@
 #include "acpi.h"
 #include "apm.h"
 #include "pmu.h"
+#include "blockdev.h"
 
 #include "osspec_linux.h"
 
@@ -190,14 +194,55 @@
 	return TRUE;
 }
 
+static int sigio_unix_signal_pipe_fds[2];
+static GIOChannel *sigio_iochn;
+
+static void
+sigio_handler (int sig)
+{
+	static char marker[1] = {'S'};
+
+	/* write a 'S' character to the other end to tell about
+	 * the signal. Note that 'the other end' is a GIOChannel thingy
+	 * that is only called from the mainloop - thus this is how we
+	 * defer this since UNIX signal handlers are evil
+	 *
+	 * Oh, and write(2) is indeed reentrant */
+	write (sigio_unix_signal_pipe_fds[1], marker, 1);
+}
+
+static gboolean
+sigio_iochn_data (GIOChannel *source, GIOCondition condition, gpointer user_data)
+{
+	GError *err = NULL;
+	gchar data[1];
+	gsize bytes_read;
+
+	/* Empty the pipe */
+	if (G_IO_STATUS_NORMAL != g_io_channel_read_chars (source, data, 1, &bytes_read, &err)) {
+		HAL_ERROR (("Error emptying callout notify pipe: %s", err->message));
+		g_error_free (err);
+		goto out;
+	}
+
+	/* TODO: check mtime on /etc/mtab file */
+	HAL_INFO (("/etc/mtab changed"));
+	blockdev_mtab_changed ();
+	
+out:
+	return TRUE;
+}
+
 void
 osspec_init (void)
 {
+	int etcfd;
 	int socketfd;
 	struct sockaddr_un saddr;
 	socklen_t addrlen;
 	GIOChannel *channel;	
 	const int on = 1;
+	guint sigio_iochn_listener_source_id;
 
 	/* setup socket for listening from datagrams from the hal.hotplug helper */
 	memset(&saddr, 0x00, sizeof(saddr));
@@ -235,6 +280,21 @@
 	}
 	HAL_INFO (("proc mount point is '%s'", hal_proc_path));
 
+	/* start watching /etc so we know when mtab is updated */
+	etcfd = open ("/etc", O_RDONLY);
+	if (etcfd < 0)
+		DIE (("Could not open /etc"));
+	fcntl (etcfd, F_NOTIFY, DN_MODIFY | DN_MULTISHOT);
+
+	if (pipe (sigio_unix_signal_pipe_fds) != 0) {
+		DIE (("Could not setup pipe: %s", strerror (errno)));
+	}	
+	if ((sigio_iochn = g_io_channel_unix_new (sigio_unix_signal_pipe_fds[0])) == NULL)
+		DIE (("Could not create GIOChannel"));
+	sigio_iochn_listener_source_id = g_io_add_watch (sigio_iochn, G_IO_IN, sigio_iochn_data, NULL);
+	signal (SIGIO, sigio_handler);
+
+
 	/* Load various hardware id databases */
 	ids_init ();
 




More information about the hal-commit mailing list