summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog73
-rw-r--r--fdi/90defaultpolicy/Makefile.am3
-rw-r--r--fdi/90defaultpolicy/power-mgmt-policy.fdi17
-rw-r--r--fdi/90defaultpolicy/storage-policy.fdi19
-rwxr-xr-xhald/debug-hald.sh6
-rw-r--r--hald/device_info.c16
-rw-r--r--hald/linux2/addons/Makefile.am5
-rw-r--r--hald/linux2/addons/addon-storage.c166
-rw-r--r--hald/linux2/blockdev.c736
-rw-r--r--hald/linux2/blockdev.h8
-rw-r--r--hald/linux2/hotplug.c6
-rw-r--r--hald/linux2/osspec.c60
-rw-r--r--hald/linux2/probing/Makefile.am8
-rw-r--r--hald/linux2/probing/linux_dvd_rw_utils.c431
-rw-r--r--hald/linux2/probing/linux_dvd_rw_utils.h18
-rw-r--r--hald/linux2/probing/probe-storage.c232
-rw-r--r--hald/linux2/probing/probe-volume.c240
-rwxr-xr-xhald/run-hald.sh3
-rw-r--r--hald/util.c34
-rw-r--r--hald/util.h2
-rw-r--r--tools/fstab-sync.c14
-rw-r--r--volume_id/fat.c2
22 files changed, 2048 insertions, 51 deletions
diff --git a/ChangeLog b/ChangeLog
index 6e96e23b..03862835 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,76 @@
+2005-02-10 David Zeuthen <davidz@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
+
2005-02-08 David Zeuthen <davidz@redhat.com>
* hald/linux2/osspec.c (get_hal_proc_path): Return hal_proc_path,
diff --git a/fdi/90defaultpolicy/Makefile.am b/fdi/90defaultpolicy/Makefile.am
index 61b3a697..a91e917f 100644
--- a/fdi/90defaultpolicy/Makefile.am
+++ b/fdi/90defaultpolicy/Makefile.am
@@ -1,4 +1,5 @@
fdi90defaultpolicydir = $(datadir)/hal/fdi/90defaultpolicy
-dist_fdi90defaultpolicy_DATA = storage-policy.fdi
+dist_fdi90defaultpolicy_DATA = storage-policy.fdi power-mgmt-policy.fdi
+
diff --git a/fdi/90defaultpolicy/power-mgmt-policy.fdi b/fdi/90defaultpolicy/power-mgmt-policy.fdi
new file mode 100644
index 00000000..fba938c1
--- /dev/null
+++ b/fdi/90defaultpolicy/power-mgmt-policy.fdi
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="ISO-8859-1"?> <!-- -*- SGML -*- -->
+
+<deviceinfo version="0.2">
+
+ <device>
+ <match key="hiddev.application_pages" contains="Power Device Page">
+ <append key="info.addons" type="strlist">hald-addon-hid-ups</append>
+ </match>
+ </device>
+
+ <device>
+ <match key="power_management.type" string="acpi">
+ <append key="info.addons" type="strlist">hald-addon-acpi</append>
+ </match>
+ </device>
+
+</deviceinfo>
diff --git a/fdi/90defaultpolicy/storage-policy.fdi b/fdi/90defaultpolicy/storage-policy.fdi
index 2194d4dd..2859889e 100644
--- a/fdi/90defaultpolicy/storage-policy.fdi
+++ b/fdi/90defaultpolicy/storage-policy.fdi
@@ -218,4 +218,23 @@
</match>
</device>
+ <device>
+ <match key="info.udi" string="/org/freedesktop/Hal/devices/computer">
+ <append key="info.callouts.add" type="strlist">fstab-sync --clean</append>
+ </match>
+
+ <match key="volume.policy.should_mount" bool="true">
+ <append key="info.callouts.add" type="strlist">fstab-sync</append>
+ <append key="info.callouts.remove" type="strlist">fstab-sync</append>
+ </match>
+ <match key="storage.policy.should_mount" bool="true">
+ <append key="info.callouts.add" type="strlist">fstab-sync</append>
+ <append key="info.callouts.remove" type="strlist">fstab-sync</append>
+ </match>
+
+ <match key="storage.media_check_enabled" bool="true">
+ <append key="info.addons" type="strlist">hald-addon-storage</append>
+ </match>
+ </device>
+
</deviceinfo>
diff --git a/hald/debug-hald.sh b/hald/debug-hald.sh
new file mode 100755
index 00000000..f62e0748
--- /dev/null
+++ b/hald/debug-hald.sh
@@ -0,0 +1,6 @@
+#!/bin/sh
+
+export PATH=linux2:linux2/probing:linux2/addons:.:../tools:$PATH
+export HAL_FDI_SOURCE=../fdi
+gdb run --args ./hald --daemon=no --verbose=yes --retain-privileges
+
diff --git a/hald/device_info.c b/hald/device_info.c
index 730ced88..f1061bf9 100644
--- a/hald/device_info.c
+++ b/hald/device_info.c
@@ -1399,7 +1399,6 @@ scan_fdi_files (const char *dir, HalDevice * d)
return found_fdi_file;
}
-
/** Search the device info file repository for a .fdi file to merge
* more information into the device object.
*
@@ -1409,8 +1408,21 @@ scan_fdi_files (const char *dir, HalDevice * d)
dbus_bool_t
di_search_and_merge (HalDevice *d)
{
+ static gboolean have_checked_hal_fdi_source = FALSE;
+ static char *hal_fdi_source = NULL;
+ char *source;
+
+ if (!have_checked_hal_fdi_source) {
+ hal_fdi_source = getenv ("HAL_FDI_SOURCE");
+ have_checked_hal_fdi_source = TRUE;
+ }
+
+ if (hal_fdi_source != NULL)
+ source = hal_fdi_source;
+ else
+ source = PACKAGE_DATA_DIR "/hal/fdi";
- return scan_fdi_files (PACKAGE_DATA_DIR "/hal/fdi", d);
+ return scan_fdi_files (source, d);
}
/** @} */
diff --git a/hald/linux2/addons/Makefile.am b/hald/linux2/addons/Makefile.am
index c2f5192b..bec20219 100644
--- a/hald/linux2/addons/Makefile.am
+++ b/hald/linux2/addons/Makefile.am
@@ -8,7 +8,7 @@ INCLUDES = \
-I$(top_srcdir) \
@PACKAGE_CFLAGS@
-libexec_PROGRAMS = hald-addon-hid-ups hald-addon-acpi
+libexec_PROGRAMS = hald-addon-hid-ups hald-addon-acpi hald-addon-storage
hald_addon_hid_ups_SOURCES = addon-hid-ups.c
hald_addon_hid_ups_LDADD = $(top_builddir)/libhal/libhal.la
@@ -16,6 +16,9 @@ hald_addon_hid_ups_LDADD = $(top_builddir)/libhal/libhal.la
hald_addon_acpi_SOURCES = addon-acpi.c
hald_addon_acpi_LDADD = $(top_builddir)/libhal/libhal.la
+hald_addon_storage_SOURCES = addon-storage.c
+hald_addon_storage_LDADD = $(top_builddir)/libhal/libhal.la
+
diff --git a/hald/linux2/addons/addon-storage.c b/hald/linux2/addons/addon-storage.c
new file mode 100644
index 00000000..564d217b
--- /dev/null
+++ b/hald/linux2/addons/addon-storage.c
@@ -0,0 +1,166 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * addon-storage.c : Poll storage devices for media changes
+ *
+ * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/kdev_t.h>
+#include <linux/cdrom.h>
+#include <linux/fs.h>
+#include <mntent.h>
+
+#include "libhal/libhal.h"
+
+#include "../probing/shared.h"
+
+enum {
+ MEDIA_STATUS_UNKNOWN = 0,
+ MEDIA_STATUS_GOT_MEDIA = 1,
+ MEDIA_STATUS_NO_MEDIA = 2
+};
+
+int
+main (int argc, char *argv[])
+{
+ char *udi;
+ char *device_file;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ DBusConnection *conn;
+ char *bus;
+ char *drive_type;
+ int is_cdrom;
+ int media_status;
+
+ if ((udi = getenv ("UDI")) == NULL)
+ goto out;
+ if ((device_file = getenv ("HAL_PROP_BLOCK_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;
+
+ dbus_error_init (&error);
+ if ((conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error)) == NULL)
+ goto out;
+
+ if ((ctx = libhal_ctx_new ()) == NULL)
+ goto out;
+ if (!libhal_ctx_set_dbus_connection (ctx, conn))
+ goto out;
+ if (!libhal_ctx_init (ctx, &error))
+ goto out;
+
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+ printf ("Doing addon-storage for %s (bus %s) (drive_type %s)\n", device_file, bus, drive_type);
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+
+ if (strcmp (drive_type, "cdrom") == 0)
+ is_cdrom = 1;
+ else
+ is_cdrom = 0;
+
+
+ media_status = MEDIA_STATUS_UNKNOWN;
+
+ while (1) {
+ int fd;
+
+ if (is_cdrom) {
+
+ /* TODO */
+ } else {
+ int got_media;
+
+ fd = open (device_file, O_RDONLY);
+ if (fd < 0 && errno == ENOMEDIUM) {
+ got_media = FALSE;
+ } else {
+ got_media = TRUE;
+ }
+ 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;
+
+ 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);
+ }
+ 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));
+
+ }
+
+ sleep (2);
+ }
+
+out:
+ if (ctx != NULL) {
+ dbus_error_init (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return 0;
+}
diff --git a/hald/linux2/blockdev.c b/hald/linux2/blockdev.c
index 0159d368..6b9fe2f6 100644
--- a/hald/linux2/blockdev.c
+++ b/hald/linux2/blockdev.c
@@ -1,9 +1,9 @@
/***************************************************************************
* CVSID: $Id$
*
- * blockdev.c : Handling of block devices
+ * blockdev.c : Handling of block devices
*
- * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
+ * Copyright (C) 2005 David Zeuthen, <david@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));
+
+ /* 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;
+ }
- HAL_INFO (("block_add: sysfs_path=%s dev=%s is_part=%d parent=0x%08x",
- sysfs_path, device_file, is_partition, parent));
+ 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;
}
diff --git a/hald/linux2/blockdev.h b/hald/linux2/blockdev.h
index e10777e6..80244523 100644
--- a/hald/linux2/blockdev.h
+++ b/hald/linux2/blockdev.h
@@ -32,4 +32,12 @@ void hotplug_event_begin_add_blockdev (const gchar *sysfs_path, const char *devi
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 */
diff --git a/hald/linux2/hotplug.c b/hald/linux2/hotplug.c
index 989d3b0a..3bcb044b 100644
--- a/hald/linux2/hotplug.c
+++ b/hald/linux2/hotplug.c
@@ -386,7 +386,7 @@ hotplug_rescan_device (HalDevice *d)
break;
case HOTPLUG_EVENT_SYSFS_BLOCK:
- ret = FALSE; /* TODO */
+ ret = blockdev_rescan_device (d);
break;
case HOTPLUG_EVENT_ACPI:
@@ -438,7 +438,7 @@ hotplug_reprobe_generate_remove_events (HalDevice *d)
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 @@ hotplug_reprobe_generate_add_events (HalDevice *d)
break;
case HOTPLUG_EVENT_SYSFS_BLOCK:
- e = NULL; /* TODO */
+ e = blockdev_generate_add_hotplug_event (d);
break;
case HOTPLUG_EVENT_ACPI:
diff --git a/hald/linux2/osspec.c b/hald/linux2/osspec.c
index fab2545a..4a7b082a 100644
--- a/hald/linux2/osspec.c
+++ b/hald/linux2/osspec.c
@@ -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 @@ out:
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 @@ osspec_init (void)
}
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 ();
diff --git a/hald/linux2/probing/Makefile.am b/hald/linux2/probing/Makefile.am
index ee3365ee..200b8de5 100644
--- a/hald/linux2/probing/Makefile.am
+++ b/hald/linux2/probing/Makefile.am
@@ -8,7 +8,7 @@ INCLUDES = \
-I$(top_srcdir) \
@PACKAGE_CFLAGS@
-libexec_PROGRAMS = hald-probe-input hald-probe-hiddev
+libexec_PROGRAMS = hald-probe-input hald-probe-hiddev hald-probe-storage hald-probe-volume
hald_probe_input_SOURCES = probe-input.c
hald_probe_input_LDADD = $(top_builddir)/libhal/libhal.la
@@ -16,6 +16,12 @@ hald_probe_input_LDADD = $(top_builddir)/libhal/libhal.la
hald_probe_hiddev_SOURCES = probe-hiddev.c
hald_probe_hiddev_LDADD = $(top_builddir)/libhal/libhal.la
+hald_probe_storage_SOURCES = probe-storage.c linux_dvd_rw_utils.c linux_dvd_rw_utils.h
+hald_probe_storage_LDADD = $(top_builddir)/libhal/libhal.la $(top_builddir)/drive_id/libdrive_id.la $(top_builddir)/volume_id/libvolume_id.la
+
+hald_probe_volume_SOURCES = probe-volume.c linux_dvd_rw_utils.c linux_dvd_rw_utils.h
+hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la $(top_builddir)/drive_id/libdrive_id.la $(top_builddir)/volume_id/libvolume_id.la
+
diff --git a/hald/linux2/probing/linux_dvd_rw_utils.c b/hald/linux2/probing/linux_dvd_rw_utils.c
new file mode 100644
index 00000000..59188d49
--- /dev/null
+++ b/hald/linux2/probing/linux_dvd_rw_utils.c
@@ -0,0 +1,431 @@
+/*
+ * This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
+ *
+ * Use-it-on-your-own-risk, GPL bless...
+ *
+ * For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/
+*/
+
+#define CREAM_ON_ERRNO(s) do { \
+ switch ((s)[2]&0x0F) \
+ { case 2: if ((s)[12]==4) errno=EAGAIN; break; \
+ case 5: errno=EINVAL; \
+ if ((s)[13]==0) \
+ { if ((s)[12]==0x21) errno=ENOSPC; \
+ else if ((s)[12]==0x20) errno=ENODEV; \
+ } \
+ break; \
+ } \
+} while(0)
+#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))
+#define SK(errcode) (((errcode)>>16)&0xF)
+#define ASC(errcode) (((errcode)>>8)&0xFF)
+#define ASCQ(errcode) ((errcode)&0xFF)
+
+#ifndef _LARGEFILE_SOURCE
+#define _LARGEFILE_SOURCE
+#endif
+#ifndef _LARGEFILE64_SOURCE
+#define _LARGEFILE64_SOURCE
+#endif
+#ifndef _FILE_OFFSET_BITS
+#define _FILE_OFFSET_BITS 64
+#endif
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/cdrom.h>
+#include <errno.h>
+#include <string.h>
+#include <mntent.h>
+#include <sys/wait.h>
+#include <sys/utsname.h>
+#include <scsi/scsi.h>
+#include <scsi/sg.h>
+#include <poll.h>
+#include <sys/time.h>
+
+#include "linux_dvd_rw_utils.h"
+
+typedef enum {
+ NONE = CGC_DATA_NONE, // 3
+ READ = CGC_DATA_READ, // 2
+ WRITE = CGC_DATA_WRITE // 1
+} Direction;
+
+typedef struct ScsiCommand ScsiCommand;
+
+struct ScsiCommand {
+ int fd;
+ int autoclose;
+ char *filename;
+ struct cdrom_generic_command cgc;
+ union {
+ struct request_sense s;
+ unsigned char u[18];
+ } _sense;
+ struct sg_io_hdr sg_io;
+};
+
+#define DIRECTION(i) (Dir_xlate[i]);
+
+/* 1,CGC_DATA_WRITE
+ * 2,CGC_DATA_READ
+ * 3,CGC_DATA_NONE
+ */
+const int Dir_xlate[4] = {
+ 0, // implementation-dependent...
+ SG_DXFER_TO_DEV, // 1,CGC_DATA_WRITE
+ SG_DXFER_FROM_DEV, // 2,CGC_DATA_READ
+ SG_DXFER_NONE // 3,CGC_DATA_NONE
+};
+
+static ScsiCommand *
+scsi_command_new (void)
+{
+ ScsiCommand *cmd;
+
+ cmd = (ScsiCommand *) malloc (sizeof (ScsiCommand));
+ memset (cmd, 0, sizeof (ScsiCommand));
+ cmd->fd = -1;
+ cmd->filename = NULL;
+ cmd->autoclose = 1;
+
+ return cmd;
+}
+
+static ScsiCommand *
+scsi_command_new_from_fd (int f)
+{
+ ScsiCommand *cmd;
+
+ cmd = scsi_command_new ();
+ cmd->fd = f;
+ cmd->autoclose = 0;
+
+ return cmd;
+}
+
+static void
+scsi_command_free (ScsiCommand * cmd)
+{
+ if (cmd->fd >= 0 && cmd->autoclose) {
+ close (cmd->fd);
+ cmd->fd = -1;
+ }
+ if (cmd->filename) {
+ free (cmd->filename);
+ cmd->filename = NULL;
+ }
+
+ free (cmd);
+}
+
+static int
+scsi_command_transport (ScsiCommand * cmd, Direction dir, void *buf,
+ size_t sz)
+{
+ int ret = 0;
+
+ cmd->sg_io.dxferp = buf;
+ cmd->sg_io.dxfer_len = sz;
+ cmd->sg_io.dxfer_direction = DIRECTION (dir);
+
+ if (ioctl (cmd->fd, SG_IO, &cmd->sg_io))
+ return -1;
+
+ if ((cmd->sg_io.info & SG_INFO_OK_MASK) != SG_INFO_OK) {
+ errno = EIO;
+ ret = -1;
+ if (cmd->sg_io.masked_status & CHECK_CONDITION) {
+ CREAM_ON_ERRNO (cmd->sg_io.sbp);
+ ret = ERRCODE (cmd->sg_io.sbp);
+ if (ret == 0)
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+static void
+scsi_command_init (ScsiCommand * cmd, size_t i, int arg)
+{
+ if (i == 0) {
+ memset (&cmd->cgc, 0, sizeof (cmd->cgc));
+ memset (&cmd->_sense, 0, sizeof (cmd->_sense));
+ cmd->cgc.quiet = 1;
+ cmd->cgc.sense = &cmd->_sense.s;
+ memset (&cmd->sg_io, 0, sizeof (cmd->sg_io));
+ cmd->sg_io.interface_id = 'S';
+ cmd->sg_io.mx_sb_len = sizeof (cmd->_sense);
+ cmd->sg_io.cmdp = cmd->cgc.cmd;
+ cmd->sg_io.sbp = cmd->_sense.u;
+ cmd->sg_io.flags = SG_FLAG_LUN_INHIBIT | SG_FLAG_DIRECT_IO;
+ }
+ cmd->sg_io.cmd_len = i + 1;
+ cmd->cgc.cmd[i] = arg;
+}
+
+int
+get_dvd_r_rw_profile (int fd)
+{
+ ScsiCommand *cmd;
+ int retval = -1;
+ unsigned char page[20];
+ unsigned char *list;
+ int i, len;
+
+ cmd = scsi_command_new_from_fd (fd);
+
+ scsi_command_init (cmd, 0, 0x46);
+ scsi_command_init (cmd, 1, 2);
+ scsi_command_init (cmd, 8, 8);
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, page, 8)) {
+ /* GET CONFIGURATION failed */
+ scsi_command_free (cmd);
+ return -1;
+ }
+
+ /* See if it's 2 gen drive by checking if DVD+R profile is an option */
+ len = 4 + (page[0] << 24 | page[1] << 16 | page[2] << 8 | page[3]);
+ if (len > 264) {
+ scsi_command_free (cmd);
+ /* insane profile list length */
+ return -1;
+ }
+
+ list = (unsigned char *) malloc (len);
+
+ scsi_command_init (cmd, 0, 0x46);
+ scsi_command_init (cmd, 1, 2);
+ scsi_command_init (cmd, 7, len >> 8);
+ scsi_command_init (cmd, 8, len);
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, list, len)) {
+ /* GET CONFIGURATION failed */
+ scsi_command_free (cmd);
+ free (list);
+ return -1;
+ }
+
+ for (i = 12; i < list[11]; i += 4) {
+ int profile = (list[i] << 8 | list[i + 1]);
+ /* 0x1B: DVD+R
+ * 0x1A: DVD+RW */
+ if (profile == 0x1B) {
+ if (retval == 1)
+ retval = 2;
+ else
+ retval = 0;
+ } else if (profile == 0x1A) {
+ if (retval == 0)
+ retval = 2;
+ else
+ retval = 1;
+ }
+ }
+
+ scsi_command_free (cmd);
+ free (list);
+
+ return retval;
+}
+
+static unsigned char *
+pull_page2a_from_fd (int fd)
+{
+ ScsiCommand *cmd;
+ unsigned char header[12], *page2A;
+ unsigned int len, bdlen;
+
+ cmd = scsi_command_new_from_fd (fd);
+
+ scsi_command_init (cmd, 0, 0x5A); /* MODE SENSE */
+ scsi_command_init (cmd, 1, 0x08); /* Disable Block Descriptors */
+ scsi_command_init (cmd, 2, 0x2A); /* Capabilities and Mechanical Status */
+ scsi_command_init (cmd, 8, sizeof (header)); /* header only to start with */
+ scsi_command_init (cmd, 9, 0);
+
+ if (scsi_command_transport (cmd, READ, header, sizeof (header))) {
+ /* MODE SENSE failed */
+ scsi_command_free (cmd);
+ return NULL;
+ }
+
+ len = (header[0] << 8 | header[1]) + 2;
+ bdlen = header[6] << 8 | header[7];
+
+ /* should never happen as we set "DBD" above */
+ if (bdlen) {
+ if (len < (8 + bdlen + 30)) {
+ /* LUN impossible to bear with */
+ scsi_command_free (cmd);
+ return NULL;
+ }
+ } else if (len < (8 + 2 + (unsigned int) header[9])) {
+ /* SANYO does this. */
+ len = 8 + 2 + header[9];
+ }
+
+ page2A = (unsigned char *) malloc (len);
+ if (page2A == NULL) {
+ /* ENOMEM */
+ scsi_command_free (cmd);
+ return NULL;
+ }
+
+ scsi_command_init (cmd, 0, 0x5A); /* MODE SENSE */
+ scsi_command_init (cmd, 1, 0x08); /* Disable Block Descriptors */
+ scsi_command_init (cmd, 2, 0x2A); /* Capabilities and Mechanical Status */
+ scsi_command_init (cmd, 7, len >> 8);
+ scsi_command_init (cmd, 8, len); /* Real length */
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, page2A, len)) {
+ /* MODE SENSE failed */
+ scsi_command_free (cmd);
+ free (page2A);
+ return NULL;
+ }
+
+ scsi_command_free (cmd);
+
+ len -= 2;
+ /* paranoia */
+ if (len < ((unsigned int) page2A[0] << 8 | page2A[1])) {
+ page2A[0] = len >> 8;
+ page2A[1] = len;
+ }
+
+ return page2A;
+}
+
+int
+get_read_write_speed (int fd, int *read_speed, int *write_speed)
+{
+ unsigned char *page2A;
+ int len, hlen;
+ unsigned char *p;
+
+ *read_speed = 0;
+ *write_speed = 0;
+
+ page2A = pull_page2a_from_fd (fd);
+ if (page2A == NULL) {
+ printf ("Failed to get Page 2A\n");
+ /* Failed to get Page 2A */
+ return -1;
+ }
+
+ len = (page2A[0] << 8 | page2A[1]) + 2;
+ hlen = 8 + (page2A[6] << 8 | page2A[7]);
+ p = page2A + hlen;
+
+ /* Values guessed from the cd_mode_page_2A struct
+ * in cdrecord's libscg/scg/scsireg.h */
+ if (len < (hlen + 30) || p[1] < (30 - 2)) {
+ /* no MMC-3 "Current Write Speed" present,
+ * try to use the MMC-2 one */
+ if (len < (hlen + 20) || p[1] < (20 - 2))
+ *write_speed = 0;
+ else
+ *write_speed = p[18] << 8 | p[19];
+ } else {
+ *write_speed = p[28] << 8 | p[29];
+ }
+
+ if (len >= hlen+9)
+ *read_speed = p[8] << 8 | p[9];
+ else
+ *read_speed = 0;
+
+ free (page2A);
+
+ return 0;
+}
+
+int
+get_disc_type (int fd)
+{
+ ScsiCommand *cmd;
+ int retval = -1;
+ unsigned char header[8];
+
+ cmd = scsi_command_new_from_fd (fd);
+
+ scsi_command_init (cmd, 0, 0x46);
+ scsi_command_init (cmd, 1, 1);
+ scsi_command_init (cmd, 8, 8);
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, header, 8)) {
+ /* GET CONFIGURATION failed */
+ scsi_command_free (cmd);
+ return -1;
+ }
+
+ retval = (header[6]<<8)|(header[7]);
+
+
+ scsi_command_free (cmd);
+ return retval;
+}
+
+
+int
+disc_is_appendable (int fd)
+{
+ ScsiCommand *cmd;
+ int retval = -1;
+ unsigned char header[32];
+
+ cmd = scsi_command_new_from_fd (fd);
+
+ /* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
+ scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
+ scsi_command_init (cmd, 8, 32);
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, header, 32)) {
+ /* READ_DISC_INFORMATION failed */
+ scsi_command_free (cmd);
+ return 0;
+ }
+
+ retval = ((header[2]&0x03) == 0x01);
+
+ scsi_command_free (cmd);
+ return retval;
+}
+
+int
+disc_is_rewritable (int fd)
+{
+ ScsiCommand *cmd;
+ int retval = -1;
+ unsigned char header[32];
+
+ cmd = scsi_command_new_from_fd (fd);
+
+ /* see section 5.19 of MMC-3 from http://www.t10.org/drafts.htm#mmc3 */
+ scsi_command_init (cmd, 0, 0x51); /* READ_DISC_INFORMATION */
+ scsi_command_init (cmd, 8, 32);
+ scsi_command_init (cmd, 9, 0);
+ if (scsi_command_transport (cmd, READ, header, 32)) {
+ /* READ_DISC_INFORMATION failed */
+ scsi_command_free (cmd);
+ return 0;
+ }
+
+ retval = ((header[2]&0x10) != 0);
+
+ scsi_command_free (cmd);
+ return retval;
+}
diff --git a/hald/linux2/probing/linux_dvd_rw_utils.h b/hald/linux2/probing/linux_dvd_rw_utils.h
new file mode 100644
index 00000000..5fb015e5
--- /dev/null
+++ b/hald/linux2/probing/linux_dvd_rw_utils.h
@@ -0,0 +1,18 @@
+//
+// This is part of dvd+rw-tools by Andy Polyakov <appro@fy.chalmers.se>
+//
+// Use-it-on-your-own-risk, GPL bless...
+//
+// For further details see http://fy.chalmers.se/~appro/linux/DVD+RW/
+//
+
+#ifndef LINUX_DVD_RW_UTILS_H
+#define LINUX_DVD_RW_UTILS_H
+
+int get_dvd_r_rw_profile (int fd);
+int get_read_write_speed (int fd, int *read_speed, int *write_speed);
+int get_disc_type (int fd);
+int disc_is_appendable (int fd);
+int disc_is_rewritable (int fd);
+
+#endif /* LINUX_DVD_RW_UTILS_H */
diff --git a/hald/linux2/probing/probe-storage.c b/hald/linux2/probing/probe-storage.c
new file mode 100644
index 00000000..16bddfc4
--- /dev/null
+++ b/hald/linux2/probing/probe-storage.c
@@ -0,0 +1,232 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * probe-storage.c : Probe storage devices
+ *
+ * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/kdev_t.h>
+#include <linux/cdrom.h>
+#include <linux/fs.h>
+
+#include "libhal/libhal.h"
+
+#include "drive_id/drive_id.h"
+#include "volume_id/volume_id.h"
+
+#include "linux_dvd_rw_utils.h"
+
+#include "shared.h"
+
+int
+main (int argc, char *argv[])
+{
+ int fd;
+ int ret;
+ char *udi;
+ char *device_file;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ DBusConnection *conn;
+ char *bus;
+ char *drive_type;
+
+ fd = -1;
+
+ /* assume failure */
+ ret = 1;
+
+ if ((udi = getenv ("UDI")) == NULL)
+ goto out;
+ if ((device_file = getenv ("HAL_PROP_BLOCK_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;
+
+ dbus_error_init (&error);
+ if ((conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error)) == NULL)
+ goto out;
+
+ if ((ctx = libhal_ctx_new ()) == NULL)
+ goto out;
+ if (!libhal_ctx_set_dbus_connection (ctx, conn))
+ goto out;
+ if (!libhal_ctx_init (ctx, &error))
+ goto out;
+
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+ printf ("Doing probe-storage for %s (bus %s) (drive_type %s)\n", device_file, bus, drive_type);
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+
+ fd = open (device_file, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ printf ("Cannot open %s: %s\n", device_file, strerror (errno));
+ goto out;
+ }
+
+ /* Only do drive_id on IDE and real SCSI disks - specifically
+ * not on USB which uses emulated SCSI since an INQUIRY on
+ * most USB devices may crash the storage device if the
+ * transfer length isn't exactly 36 bytes. See Red Hat bug
+ * #145256 for details.
+ */
+ if (strcmp (bus, "ide") == 0 ||
+ strcmp (bus, "scsi") == 0) {
+ struct drive_id *did;
+
+ did = drive_id_open_fd (fd);
+ if (drive_id_probe_all (did) == 0) {
+ if (did->serial[0] != '\0')
+ if (!libhal_device_set_property_string (ctx, udi, "storage.serial",
+ did->serial, &error))
+ goto out;
+
+ if (did->firmware[0] != '\0')
+ if (!libhal_device_set_property_string (ctx, udi, "storage.firmware_version",
+ did->firmware, &error))
+ goto out;
+ }
+ drive_id_close (did);
+ }
+
+#if 0
+ /* TODO: test for SATA drives once that gets exported to user space */
+ {
+ int fd;
+ unsigned char unused;
+
+ if ((fd = open (device_file, O_RDONLY|O_NDELAY)) != -1) {
+ if (ioctl (fd, ATA_IOC_GET_IO32, &unused) >= 0) {
+ hal_device_property_set_string (stordev, "storage.bus", "sata");
+ }
+ close (fd);
+ }
+ }
+#endif
+
+ /* Get properties for CD-ROM drive */
+ if (strcmp (drive_type, "cdrom") == 0) {
+ int capabilities;
+ int read_speed, write_speed;
+
+ if( ioctl (fd, CDROM_SET_OPTIONS, CDO_USE_FFLAGS) < 0 ) {
+ HAL_ERROR (("CDROM_SET_OPTIONS failed: %s\n", strerror(errno)));
+ goto out;
+ }
+
+ capabilities = ioctl (fd, CDROM_GET_CAPABILITY, 0);
+ if (capabilities < 0)
+ goto out;
+
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdr", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdrw", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvd", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdr", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdrw", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdram", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusr", FALSE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrw", FALSE, &error);
+
+ if (capabilities & CDC_CD_R) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdr", TRUE, &error);
+ }
+
+ if (capabilities & CDC_CD_RW) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.cdrw", TRUE, &error);
+ }
+ if (capabilities & CDC_DVD) {
+ int profile;
+
+ /** @todo FIXME BUG XXX: need to check for dvdrw (prolly need to rewrite much of
+ * the linux_dvdrw_utils.c file)
+ */
+
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvd", TRUE, &error);
+
+ profile = get_dvd_r_rw_profile (fd);
+ if (profile == 2) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusr", TRUE, &error);
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrw", TRUE, &error);
+ } else if (profile == 0) {
+ libhal_device_set_property_bool(ctx, udi, "storage.cdrom.dvdplusr", TRUE, &error);
+ } else if (profile == 1) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdplusrw", TRUE, &error);
+ }
+ }
+ if (capabilities & CDC_DVD_R) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.dvdr", TRUE, &error);
+ }
+ if (capabilities & CDC_DVD_RAM) {
+ libhal_device_set_property_bool (ctx, udi, "storage.dvdram", TRUE, &error);
+ }
+
+ /* while we're at it, check if we support media changed */
+ if (capabilities & CDC_MEDIA_CHANGED) {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.support_media_changed", TRUE, &error);
+ } else {
+ libhal_device_set_property_bool (ctx, udi, "storage.cdrom.support_media_changed", FALSE, &error);
+ }
+
+ if (get_read_write_speed(fd, &read_speed, &write_speed) >= 0) {
+ libhal_device_set_property_int (ctx, udi, "storage.cdrom.read_speed", read_speed, &error);
+ if (write_speed > 0)
+ libhal_device_set_property_int (ctx, udi, "storage.cdrom.write_speed", write_speed, &error);
+ else
+ libhal_device_set_property_int (ctx, udi, "storage.cdrom.write_speed", 0, &error);
+ }
+ }
+
+ /* TODO: see if we got a file system on the main block device */
+
+
+
+ ret = 0;
+
+out:
+ if (fd >= 0)
+ close (fd);
+
+ if (ctx != NULL) {
+ dbus_error_init (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return ret;
+}
diff --git a/hald/linux2/probing/probe-volume.c b/hald/linux2/probing/probe-volume.c
new file mode 100644
index 00000000..e1e774a8
--- /dev/null
+++ b/hald/linux2/probing/probe-volume.c
@@ -0,0 +1,240 @@
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * probe-volume.c : Probe for volume type (filesystems etc.)
+ *
+ * Copyright (C) 2004 David Zeuthen, <david@fubar.dk>
+ *
+ * Licensed under the Academic Free License version 2.0
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <asm/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <linux/kdev_t.h>
+#include <linux/cdrom.h>
+#include <linux/fs.h>
+
+#include "libhal/libhal.h"
+
+#include "drive_id/drive_id.h"
+#include "volume_id/volume_id.h"
+#include "volume_id/msdos.h"
+
+#include "linux_dvd_rw_utils.h"
+
+#include "shared.h"
+
+static void
+set_volume_id_values (LibHalContext *ctx, const char *udi, struct volume_id *vid)
+{
+ char buf[256];
+ const char *usage;
+ DBusError error;
+
+ dbus_error_init (&error);
+
+ switch (vid->usage_id) {
+ case VOLUME_ID_FILESYSTEM:
+ usage = "filesystem";
+ break;
+ case VOLUME_ID_PARTITIONTABLE:
+ usage = "partitiontable";
+ break;
+ case VOLUME_ID_OTHER:
+ usage = "other";
+ break;
+ case VOLUME_ID_RAID:
+ usage = "raid";
+ break;
+ case VOLUME_ID_UNUSED:
+ libhal_device_set_property_string (ctx, udi, "info.product", "Volume (unused)", &error);
+ usage = "unused";
+ return;
+ default:
+ usage = "";
+ }
+
+ libhal_device_set_property_string (ctx, udi, "volume.fsusage", usage, &error);
+ HAL_INFO (("volume.fsusage = '%s'", usage));
+
+ libhal_device_set_property_string (ctx, udi, "volume.fstype", vid->type, &error);
+ HAL_INFO (("volume.fstype = '%s'", vid->type));
+ if (vid->type_version[0] != '\0') {
+ libhal_device_set_property_string (ctx, udi, "volume.fsversion", vid->type_version, &error);
+ HAL_INFO (("volume.fsversion = '%s'", vid->type_version));
+ }
+ libhal_device_set_property_string (ctx, udi, "volume.uuid", vid->uuid, &error);
+ HAL_INFO (("volume.uuid = '%s'", vid->uuid));
+ libhal_device_set_property_string (ctx, udi, "volume.label", vid->label, &error);
+ HAL_INFO (("volume.label = '%s'", vid->label));
+
+ if (vid->label[0] != '\0') {
+ libhal_device_set_property_string (ctx, udi, "info.product", vid->label, &error);
+ } else {
+ snprintf (buf, sizeof (buf), "Volume (%s)", vid->type);
+ libhal_device_set_property_string (ctx, udi, "info.product", buf, &error);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ int fd;
+ int ret;
+ char *udi;
+ char *device_file;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ DBusConnection *conn;
+ char *parent_udi;
+ char *sysfs_path;
+ struct volume_id *vid;
+ char *stordev_dev_file;
+ char *partition_number_str;
+ unsigned int partition_number;
+ unsigned int block_size;
+ dbus_uint64_t vol_size;
+
+ fd = -1;
+
+ /* assume failure */
+ ret = 1;
+
+ if ((udi = getenv ("UDI")) == NULL)
+ goto out;
+ if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL)
+ goto out;
+ if ((parent_udi = getenv ("HAL_PROP_INFO_PARENT")) == NULL)
+ goto out;
+ if ((sysfs_path = getenv ("HAL_PROP_LINUX_SYSFS_PATH")) == NULL)
+ goto out;
+ if ((partition_number_str = getenv ("HAL_PROP_VOLUME_PARTITION_NUMBER")) == NULL)
+ goto out;
+ partition_number = (unsigned int) atoi (partition_number_str);
+
+ dbus_error_init (&error);
+ if ((conn = dbus_bus_get (DBUS_BUS_SYSTEM, &error)) == NULL)
+ goto out;
+
+ if ((ctx = libhal_ctx_new ()) == NULL)
+ goto out;
+ if (!libhal_ctx_set_dbus_connection (ctx, conn))
+ goto out;
+ if (!libhal_ctx_init (ctx, &error))
+ goto out;
+
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+ printf ("Doing probe-volume for %s\n", device_file);
+ printf ("**************************************************\n");
+ printf ("**************************************************\n");
+
+ fd = open (device_file, O_RDONLY);
+ if (fd < 0)
+ goto out;
+
+ /* probe for file system */
+ vid = volume_id_open_fd (fd);
+ if (vid != NULL) {
+ if (volume_id_probe_all (vid, 0, 0 /* size */) == 0) {
+ set_volume_id_values(ctx, udi, vid);
+ } else {
+ libhal_device_set_property_string (ctx, udi, "info.product", "Volume", &error);
+ }
+ volume_id_close(vid);
+ }
+
+ /* get partition type - presently we only support PC style partition tables */
+ if ((stordev_dev_file = libhal_device_get_property_string (ctx, parent_udi, "block.device", &error)) == NULL) {
+ goto out;
+ }
+ vid = volume_id_open_node (stordev_dev_file);
+ if (vid != NULL) {
+ if (volume_id_probe_msdos_part_table (vid, 0) == 0) {
+ HAL_INFO (("Number of partitions = %d", vid->partition_count));
+
+ if (partition_number > 0 && partition_number <= vid->partition_count) {
+ struct volume_id_partition *p;
+ p = &vid->partitions[partition_number-1];
+
+ libhal_device_set_property_int (ctx, udi,
+ "volume.partition.msdos_part_table_type",
+ p->partition_type_raw, &error);
+
+ /* NOTE: We trust the type from the partition table
+ * if it explicitly got correct entries for RAID and
+ * LVM partitions.
+ *
+ * Btw, in general it's not a good idea to trust the
+ * partition table type as many geek^Wexpert users use
+ * FAT filesystems on type 0x83 which is Linux.
+ *
+ * Linux RAID autodetect is 0xfd and Linux LVM is 0x8e
+ */
+ if (p->partition_type_raw == 0xfd ||
+ p->partition_type_raw == 0x8e ) {
+ libhal_device_set_property_string (ctx, udi, "volume.fsusage", "raid", &error);
+ }
+
+ } else {
+ HAL_WARNING (("partition_number=%d not in [0;%d[",
+ partition_number, vid->partition_count));
+ }
+ }
+ volume_id_close(vid);
+ }
+ libhal_free_string (stordev_dev_file);
+
+ /* block size and total size */
+ if (ioctl (fd, BLKSSZGET, &block_size) == 0) {
+ HAL_INFO (("volume.block_size = %d", block_size));
+ libhal_device_set_property_int (ctx, udi, "volume.block_size", block_size, &error);
+ }
+ if (ioctl (fd, BLKGETSIZE64, &vol_size) == 0) {
+ HAL_INFO (("volume.size = %llu", vol_size));
+ libhal_device_set_property_uint64 (ctx, udi, "volume.size", vol_size, &error);
+ }
+
+ ret = 0;
+
+out:
+ if (fd >= 0)
+ close (fd);
+
+ if (ctx != NULL) {
+ dbus_error_init (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return ret;
+
+}
diff --git a/hald/run-hald.sh b/hald/run-hald.sh
index 4075e320..51b5954e 100755
--- a/hald/run-hald.sh
+++ b/hald/run-hald.sh
@@ -1,5 +1,6 @@
#!/bin/sh
-export PATH=linux2:linux2/probing:linux2/addons:.:$PATH
+export PATH=linux2:linux2/probing:linux2/addons:.:../tools:$PATH
+export HAL_FDI_SOURCE=../fdi
./hald --daemon=no --verbose=yes --retain-privileges
diff --git a/hald/util.c b/hald/util.c
index 69b2e743..8f050e02 100644
--- a/hald/util.c
+++ b/hald/util.c
@@ -340,6 +340,7 @@ hal_util_get_string_from_file (const gchar *directory, const gchar *file)
gchar path[HAL_PATH_MAX];
gchar *result;
gsize len;
+ guint i;
f = NULL;
result = NULL;
@@ -356,11 +357,18 @@ hal_util_get_string_from_file (const gchar *directory, const gchar *file)
HAL_ERROR (("Cannot read from '%s'", path));
goto out;
}
-
+
len = strlen (buf);
if (len>0)
buf[len-1] = '\0';
+ /* Clear remaining whitespace */
+ for (i = len-2; i >= 0; --i) {
+ if (!g_ascii_isspace (buf[i]))
+ break;
+ buf[i] = '\0';
+ }
+
result = buf;
out:
@@ -418,14 +426,16 @@ hal_util_terminate_helper (HalHelperData *ed)
kill (ed->pid, SIGTERM);
/* TODO: yikes; what about removing the zombie? */
- if (ed->timeout_watch_id != (guint) -1)
+ if (ed->timeout_watch_id != (guint) -1) {
g_source_remove (ed->timeout_watch_id);
- g_source_remove (ed->child_watch_id);
- g_spawn_close_pid (ed->pid);
+ ed->timeout_watch_id = -1;
+ }
+
+ ed->already_issued_callback = TRUE;
ed->cb (ed->d, TRUE, -1, ed->data1, ed->data2, ed);
- g_free (ed);
+ /* ed will be cleaned up when helper_child_exited reaps the child */
return;
}
@@ -438,14 +448,13 @@ helper_child_timeout (gpointer data)
/* kill kenny! kill it!! */
kill (ed->pid, SIGTERM);
- /* TODO: yikes; what about removing the zombie? */
- g_source_remove (ed->child_watch_id);
- g_spawn_close_pid (ed->pid);
+ ed->timeout_watch_id = -1;
+ ed->already_issued_callback = TRUE;
ed->cb (ed->d, TRUE, -1, ed->data1, ed->data2, ed);
- g_free (ed);
+ /* ed will be cleaned up when helper_child_exited reaps the child */
return FALSE;
}
@@ -454,14 +463,15 @@ helper_child_exited (GPid pid, gint status, gpointer data)
{
HalHelperData *ed = (HalHelperData *) data;
- HAL_INFO (("child exited for pid %d", ed->pid));
+ HAL_INFO (("child exited for pid %d", pid));
if (ed->timeout_watch_id != (guint) -1)
g_source_remove (ed->timeout_watch_id);
g_spawn_close_pid (ed->pid);
- ed->cb (ed->d, FALSE, WEXITSTATUS (status), ed->data1, ed->data2, ed);
-
+ if (!ed->already_issued_callback)
+ ed->cb (ed->d, FALSE, WEXITSTATUS (status), ed->data1, ed->data2, ed);
+
g_free (ed);
}
diff --git a/hald/util.h b/hald/util.h
index 30476491..115cb27a 100644
--- a/hald/util.h
+++ b/hald/util.h
@@ -91,6 +91,8 @@ struct HalHelperData_s
gpointer data1;
gpointer data2;
HalDevice *d;
+
+ gboolean already_issued_callback;
};
HalHelperData *hal_util_helper_invoke (const gchar *command_line, gchar **extra_env, HalDevice *d,
diff --git a/tools/fstab-sync.c b/tools/fstab-sync.c
index 6c828185..7253d992 100644
--- a/tools/fstab-sync.c
+++ b/tools/fstab-sync.c
@@ -1414,7 +1414,6 @@ remove_udi (const char *udi)
DBusError error;
dbus_error_init (&error);
-
is_volume = libhal_device_query_capability (hal_context, udi, "volume", &error);
/* don't remove the fstab entry if we were spawned of a device with
@@ -1422,9 +1421,11 @@ remove_udi (const char *udi)
* exactly when block.no_partitions is TRUE on the volume. E.g.
* floppies and optical discs
*/
+ dbus_error_init (&error);
if (is_volume && libhal_device_get_property_bool (hal_context, udi, "block.no_partitions", &error))
return FALSE;
+ dbus_error_init (&error);
block_device = libhal_device_get_property_string (hal_context, udi, "block.device", &error);
dir = strdup (_PATH_FSTAB);
@@ -1702,7 +1703,9 @@ main (int argc, const char *argv[])
hal_device_udi = getenv ("UDI");
if (hal_device_udi != NULL) {
char *caps;
-
+ char *action;
+
+
/* when invoked for the /org/freedesktop/Hal/devices/computer UDI we clean the fstab */
if (getenv ("HALD_STARTUP") != NULL && strcmp (hal_device_udi, "/org/freedesktop/Hal/devices/computer") == 0) {
should_clean = TRUE;
@@ -1729,6 +1732,13 @@ main (int argc, const char *argv[])
}
}
+ if ((action = getenv ("HALD_ACTION")) != NULL) {
+ if (strcmp (action, "add") == 0)
+ udi_to_add = hal_device_udi;
+ else if (strcmp (action, "remove") == 0)
+ udi_to_remove = hal_device_udi;
+ }
+
/* we don't want to remove entries just because hald is shutting down */
if (getenv ("HALD_SHUTDOWN") != NULL)
goto out;
diff --git a/volume_id/fat.c b/volume_id/fat.c
index a2007355..5b4f8e27 100644
--- a/volume_id/fat.c
+++ b/volume_id/fat.c
@@ -343,7 +343,7 @@ fat32:
volume_id_set_uuid(id, vs->type.fat32.serno, UUID_DOS);
found:
- volume_id_set_usage(id, VOLUME_ID_DISKLABEL);
+ volume_id_set_usage(id, VOLUME_ID_FILESYSTEM);
id->type = "vfat";
return 0;