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