diff options
-rw-r--r-- | ChangeLog | 73 | ||||
-rw-r--r-- | fdi/90defaultpolicy/Makefile.am | 3 | ||||
-rw-r--r-- | fdi/90defaultpolicy/power-mgmt-policy.fdi | 17 | ||||
-rw-r--r-- | fdi/90defaultpolicy/storage-policy.fdi | 19 | ||||
-rwxr-xr-x | hald/debug-hald.sh | 6 | ||||
-rw-r--r-- | hald/device_info.c | 16 | ||||
-rw-r--r-- | hald/linux2/addons/Makefile.am | 5 | ||||
-rw-r--r-- | hald/linux2/addons/addon-storage.c | 166 | ||||
-rw-r--r-- | hald/linux2/blockdev.c | 736 | ||||
-rw-r--r-- | hald/linux2/blockdev.h | 8 | ||||
-rw-r--r-- | hald/linux2/hotplug.c | 6 | ||||
-rw-r--r-- | hald/linux2/osspec.c | 60 | ||||
-rw-r--r-- | hald/linux2/probing/Makefile.am | 8 | ||||
-rw-r--r-- | hald/linux2/probing/linux_dvd_rw_utils.c | 431 | ||||
-rw-r--r-- | hald/linux2/probing/linux_dvd_rw_utils.h | 18 | ||||
-rw-r--r-- | hald/linux2/probing/probe-storage.c | 232 | ||||
-rw-r--r-- | hald/linux2/probing/probe-volume.c | 240 | ||||
-rwxr-xr-x | hald/run-hald.sh | 3 | ||||
-rw-r--r-- | hald/util.c | 34 | ||||
-rw-r--r-- | hald/util.h | 2 | ||||
-rw-r--r-- | tools/fstab-sync.c | 14 | ||||
-rw-r--r-- | volume_id/fat.c | 2 |
22 files changed, 2048 insertions, 51 deletions
@@ -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; |