hal: Branch 'master'
Artem Kachitchkine
artem at kemper.freedesktop.org
Mon Nov 6 11:55:42 PST 2006
configure.in | 12
hald-runner/main.c | 4
hald/Makefile.am | 2
hald/hald_dbus.c | 8
hald/solaris/Makefile.am | 6
hald/solaris/addons/Makefile.am | 17
hald/solaris/addons/addon-storage.c | 357 +++++++
hald/solaris/devinfo.c | 380 +++++++
hald/solaris/devinfo.h | 72 +
hald/solaris/devinfo_ieee1394.c | 90 +
hald/solaris/devinfo_ieee1394.h | 21
hald/solaris/devinfo_misc.c | 147 +++
hald/solaris/devinfo_misc.h | 23
hald/solaris/devinfo_pci.c | 122 ++
hald/solaris/devinfo_pci.h | 21
hald/solaris/devinfo_storage.c | 1673 +++++++++++++++++++++++++++++++++++
hald/solaris/devinfo_storage.h | 31
hald/solaris/devinfo_usb.c | 231 ++++
hald/solaris/devinfo_usb.h | 21
hald/solaris/hal.xml | 89 +
hald/solaris/hotplug.c | 193 ++++
hald/solaris/hotplug.h | 60 +
hald/solaris/osspec.c | 207 +++-
hald/solaris/osspec_solaris.h | 23
hald/solaris/probing/Makefile.am | 22
hald/solaris/probing/cdutils.c | 484 ++++++++++
hald/solaris/probing/cdutils.h | 61 +
hald/solaris/probing/fsutils.c | 250 +++++
hald/solaris/probing/fsutils.h | 28
hald/solaris/probing/probe-storage.c | 488 ++++++++++
hald/solaris/probing/probe-volume.c | 673 ++++++++++++++
hald/solaris/svc-hal | 39
hald/solaris/sysevent.c | 295 ++++++
hald/solaris/sysevent.h | 22
hald/util_helper.c | 45
partutil/Makefile.am | 3
tools/hal-storage-shared.c | 2
37 files changed, 6196 insertions(+), 26 deletions(-)
New commits:
diff-tree 49abf2145106009fe92a4efd82ff510a5c945d45 (from a56a15b90177734c70a8b03d961a7bcabdea2af8)
Author: Artem Kachitchkine <artem.kachitchkin at sun.com>
Date: Mon Nov 6 11:55:58 2006 -0800
solaris backend
Initial commit of the Solaris backend.
diff --git a/configure.in b/configure.in
index c123c21..f4eb57b 100644
--- a/configure.in
+++ b/configure.in
@@ -12,7 +12,7 @@ AM_INIT_AUTOMAKE(hal, 0.5.9)
AM_CONFIG_HEADER(config.h)
AM_MAINTAINER_MODE
-glib_module="glib-2.0 >= 2.6.0 dbus-glib-1 >= 0.61"
+glib_module="glib-2.0 >= 2.6.0 gobject-2.0 > 2.6.0 dbus-glib-1 >= 0.61"
dbus_module="dbus-1 >= 0.61"
volume_id_module="libvolume_id >= 0.61"
polkit_module="polkit >= 0.2"
@@ -316,6 +316,14 @@ case "$host" in
AC_SUBST(VOLUME_ID_LIBS)
esac
+# OS specific libs
+case "$host" in
+*-*-solaris*)
+ HALD_OS_LIBS="-lsysevent -lnvpair -ldevinfo"
+ AC_SUBST(HALD_OS_LIBS)
+ ;;
+esac
+
# Check for BLKGETSIZE64
AC_CHECK_TYPE(pgoff_t, ,
[AC_DEFINE(pgoff_t, unsigned long, [Index into the pagecache])],
@@ -549,6 +557,8 @@ hald/linux/Makefile
hald/linux/probing/Makefile
hald/linux/addons/Makefile
hald/solaris/Makefile
+hald/solaris/probing/Makefile
+hald/solaris/addons/Makefile
hald/haldaemon
hald-runner/Makefile
libhal/Makefile
diff --git a/hald-runner/main.c b/hald-runner/main.c
index a9f366d..b509ad7 100644
--- a/hald-runner/main.c
+++ b/hald-runner/main.c
@@ -31,6 +31,10 @@
#include "utils.h"
#include "runner.h"
+#ifndef __GNUC__
+#define __attribute__(x)
+#endif
+
static gboolean
parse_first_part(run_request *r, DBusMessage *msg, DBusMessageIter *iter)
{
diff --git a/hald/Makefile.am b/hald/Makefile.am
index 7201b1a..248f27e 100644
--- a/hald/Makefile.am
+++ b/hald/Makefile.am
@@ -51,7 +51,7 @@ hald_SOURCES =
osspec.h \
ids.h ids.c
-hald_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
+hald_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ -lm @EXPAT_LIB@ @HALD_OS_LIBS@ $(top_builddir)/hald/$(HALD_BACKEND)/libhald_$(HALD_BACKEND).la
#### Init scripts fun
SCRIPT_IN_FILES=haldaemon.in
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index 7b40903..7434230 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -3941,10 +3941,10 @@ local_server_message_handler (DBusConnec
void *user_data)
{
HAL_INFO (("local_server_message_handler: destination=%s obj_path=%s interface=%s method=%s",
- dbus_message_get_destination (message),
- dbus_message_get_path (message),
- dbus_message_get_interface (message),
- dbus_message_get_member (message)));
+ dbus_message_get_destination (message) ? dbus_message_get_destination (message) : "",
+ dbus_message_get_path (message) ? dbus_message_get_path (message) : "" ,
+ dbus_message_get_interface (message) ? dbus_message_get_interface (message) : "",
+ dbus_message_get_member (message) ? dbus_message_get_member (message) : ""));
if (dbus_message_is_method_call (message, "org.freedesktop.DBus", "AddMatch")) {
DBusMessage *reply;
diff --git a/hald/solaris/Makefile.am b/hald/solaris/Makefile.am
index 81266f7..d90beb7 100644
--- a/hald/solaris/Makefile.am
+++ b/hald/solaris/Makefile.am
@@ -1,3 +1,6 @@
+
+SUBDIRS = probing addons .
+
INCLUDES = \
-DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
-DPACKAGE_DATA_DIR=\""$(datadir)"\" \
@@ -12,5 +15,6 @@ noinst_LTLIBRARIES = libhald_solaris.la
endif
libhald_solaris_la_SOURCES = \
-osspec.c
+ devinfo.c devinfo_ieee1394.c devinfo_misc.c devinfo_pci.c devinfo_storage.c devinfo_usb.c \
+ hotplug.c osspec.c sysevent.c
diff --git a/hald/solaris/addons/Makefile.am b/hald/solaris/addons/Makefile.am
new file mode 100644
index 0000000..87ce550
--- /dev/null
+++ b/hald/solaris/addons/Makefile.am
@@ -0,0 +1,17 @@
+
+INCLUDES = \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
+ -I$(top_srcdir) -I$(top_srcdir)/hald -I$(top_srcdir)/libhal -I$(top_srcdir)/libhal-storage \
+ @GLIB_CFLAGS@ @DBUS_CFLAGS@
+
+if HALD_COMPILE_SOLARIS
+libexec_PROGRAMS = hald-addon-storage
+endif
+
+hald_addon_storage_SOURCES = addon-storage.c ../../logger.c
+hald_addon_storage_LDADD = $(top_builddir)/libhal/libhal.la
+
diff --git a/hald/solaris/addons/addon-storage.c b/hald/solaris/addons/addon-storage.c
new file mode 100644
index 0000000..1429a27
--- /dev/null
+++ b/hald/solaris/addons/addon-storage.c
@@ -0,0 +1,357 @@
+/***************************************************************************
+ *
+ * addon-storage.c : watch removable media state changes
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)addon-storage.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mnttab.h>
+#include <sys/dkio.h>
+#include <priv.h>
+
+#include <libhal.h>
+
+#include <logger.h>
+
+#define SLEEP_PERIOD 5
+
+static void
+my_dbus_error_free(DBusError *error)
+{
+ if (dbus_error_is_set(error)) {
+ dbus_error_free(error);
+ }
+}
+
+static void
+force_unmount (LibHalContext *ctx, const char *udi)
+{
+ DBusError error;
+ DBusMessage *msg = NULL;
+ DBusMessage *reply = NULL;
+ char **options = NULL;
+ unsigned int num_options = 0;
+ DBusConnection *dbus_connection;
+ char *device_file;
+
+ dbus_error_init (&error);
+
+ dbus_connection = libhal_ctx_get_dbus_connection (ctx);
+
+ msg = dbus_message_new_method_call ("org.freedesktop.Hal", udi,
+ "org.freedesktop.Hal.Device.Volume",
+ "Unmount");
+ if (msg == NULL) {
+ HAL_DEBUG (("Could not create dbus message for %s", udi));
+ goto out;
+ }
+
+
+ options = calloc (1, sizeof (char *));
+ if (options == NULL) {
+ HAL_DEBUG (("Could not allocate options array"));
+ goto out;
+ }
+
+ device_file = libhal_device_get_property_string (ctx, udi, "block.device", &error);
+ if (device_file != NULL) {
+ libhal_free_string (device_file);
+ }
+ dbus_error_free (&error);
+
+ if (!dbus_message_append_args (msg,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &options, num_options,
+ DBUS_TYPE_INVALID)) {
+ HAL_DEBUG (("Could not append args to dbus message for %s", udi));
+ goto out;
+ }
+
+ if (!(reply = dbus_connection_send_with_reply_and_block (dbus_connection, msg, -1, &error))) {
+ HAL_DEBUG (("Unmount failed for %s: %s : %s\n", udi, error.name, error.message));
+ goto out;
+ }
+
+ if (dbus_error_is_set (&error)) {
+ HAL_DEBUG (("Unmount failed for %s\n%s : %s\n", udi, error.name, error.message));
+ goto out;
+ }
+
+ HAL_DEBUG (("Succesfully unmounted udi '%s'", udi));
+
+out:
+ dbus_error_free (&error);
+ if (options != NULL)
+ free (options);
+ if (msg != NULL)
+ dbus_message_unref (msg);
+ if (reply != NULL)
+ dbus_message_unref (reply);
+}
+
+static void
+unmount_childs (LibHalContext *ctx, const char *udi)
+{
+ DBusError error;
+ int num_volumes;
+ char **volumes;
+
+ dbus_error_init (&error);
+
+ /* need to force unmount all partitions */
+ if ((volumes = libhal_manager_find_device_string_match (
+ ctx, "block.storage_device", udi, &num_volumes, &error)) != NULL) {
+ dbus_error_free (&error);
+ int i;
+
+ for (i = 0; i < num_volumes; i++) {
+ char *vol_udi;
+
+ vol_udi = volumes[i];
+ if (libhal_device_get_property_bool (ctx, vol_udi, "block.is_volume", &error)) {
+ dbus_error_free (&error);
+ if (libhal_device_get_property_bool (ctx, vol_udi, "volume.is_mounted", &error)) {
+ dbus_error_free (&error);
+ HAL_DEBUG (("Forcing unmount of child '%s'", vol_udi));
+ force_unmount (ctx, vol_udi);
+ }
+ }
+ }
+ libhal_free_string_array (volumes);
+ }
+ my_dbus_error_free (&error);
+}
+
+/** Check if a filesystem on a special device file is mounted
+ *
+ * @param device_file Special device file, e.g. /dev/cdrom
+ * @return TRUE iff there is a filesystem system mounted
+ * on the special device file
+ */
+static dbus_bool_t
+is_mounted (const char *device_file)
+{
+ FILE *f;
+ dbus_bool_t rc = FALSE;
+ struct mnttab mp;
+ struct mnttab mpref;
+
+ if ((f = fopen ("/etc/mnttab", "r")) == NULL)
+ return rc;
+
+ bzero(&mp, sizeof (mp));
+ bzero(&mpref, sizeof (mpref));
+ mpref.mnt_special = (char *)device_file;
+ if (getmntany(f, &mp, &mpref) == 0) {
+ rc = TRUE;
+ }
+
+ fclose (f);
+ return rc;
+}
+
+void
+close_device (int *fd)
+{
+ if (*fd > 0) {
+ close (*fd);
+ *fd = -1;
+ }
+}
+
+void
+drop_privileges ()
+{
+ priv_set_t *pPrivSet = NULL;
+ priv_set_t *lPrivSet = NULL;
+
+ /*
+ * Start with the 'basic' privilege set and then remove any
+ * of the 'basic' privileges that will not be needed.
+ */
+ if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ return;
+ }
+
+ /* Clear privileges we will not need from the 'basic' set */
+ (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
+ (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
+ (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
+
+ /* to open logindevperm'd devices */
+ (void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
+
+ /* Set the permitted privilege set. */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
+ return;
+ }
+
+ /* Clear the limit set. */
+ if ((lPrivSet = priv_allocset()) == NULL) {
+ return;
+ }
+
+ priv_emptyset(lPrivSet);
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
+ return;
+ }
+
+ priv_freeset(lPrivSet);
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *udi;
+ char *device_file, *raw_device_file;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ char *bus;
+ char *drive_type;
+ int state, last_state;
+ char *support_media_changed_str;
+ int support_media_changed;
+ int fd = -1;
+
+ if ((udi = getenv ("UDI")) == NULL)
+ goto out;
+ if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL)
+ goto out;
+ if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_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;
+
+ drop_privileges ();
+
+ setup_logger ();
+
+ support_media_changed_str = getenv ("HAL_PROP_STORAGE_CDROM_SUPPORT_MEDIA_CHANGED");
+ if (support_media_changed_str != NULL && strcmp (support_media_changed_str, "true") == 0)
+ support_media_changed = TRUE;
+ else
+ support_media_changed = FALSE;
+
+ dbus_error_init (&error);
+
+ if ((ctx = libhal_ctx_init_direct (&error)) == NULL) {
+ goto out;
+ }
+ my_dbus_error_free (&error);
+
+ if (!libhal_device_addon_is_ready (ctx, udi, &error)) {
+ goto out;
+ }
+ my_dbus_error_free (&error);
+
+ printf ("Doing addon-storage for %s (bus %s) (drive_type %s) (udi %s)\n", device_file, bus, drive_type, udi);
+
+ last_state = state = DKIO_NONE;
+
+ /* Linux version of this addon attempts to re-open the device O_EXCL
+ * every 2 seconds, trying to figure out if some other app,
+ * like a cd burner, is using the device. Aside from questionable
+ * value of this (apps should use HAL's locked property or/and
+ * Solaris in_use facility), but also frequent opens/closes
+ * keeps media constantly spun up. All this needs more thought.
+ */
+ for (;;) {
+ if (is_mounted (device_file)) {
+ close_device (&fd);
+ sleep (SLEEP_PERIOD);
+ } else if ((fd < 0) && ((fd = open (raw_device_file, O_RDONLY | O_NONBLOCK)) < 0)) {
+ HAL_DEBUG (("open failed for %s: %s", raw_device_file, strerror (errno)));
+ sleep (SLEEP_PERIOD);
+ } else {
+ /* Check if a disc is in the drive */
+ /* XXX initial call always returns inserted
+ * causing unnecessary rescan - optimize?
+ */
+ if (ioctl (fd, DKIOCSTATE, &state) == 0) {
+ if (state == last_state) {
+ HAL_DEBUG (("state has not changed %d %s", state, device_file));
+ continue;
+ } else {
+ HAL_DEBUG (("new state %d %s", state, device_file));
+ }
+
+ switch (state) {
+ case DKIO_EJECTED:
+ HAL_DEBUG (("Media removal detected on %s", device_file));
+ last_state = state;
+
+ libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", FALSE, &error);
+ my_dbus_error_free (&error);
+
+ /* attempt to unmount all childs */
+ unmount_childs (ctx, udi);
+
+ /* could have a fs on the main block device; do a rescan to remove it */
+ libhal_device_rescan (ctx, udi, &error);
+ my_dbus_error_free (&error);
+ break;
+
+ case DKIO_INSERTED:
+ HAL_DEBUG (("Media insertion detected on %s", device_file));
+ last_state = state;
+
+ libhal_device_set_property_bool (ctx, udi, "storage.removable.media_available", TRUE, &error);
+ my_dbus_error_free (&error);
+
+ /* could have a fs on the main block device; do a rescan to add it */
+ libhal_device_rescan (ctx, udi, &error);
+ my_dbus_error_free (&error);
+ break;
+
+ case DKIO_DEV_GONE:
+ HAL_DEBUG (("Device gone detected on %s", device_file));
+ last_state = state;
+
+ unmount_childs (ctx, udi);
+ close_device (&fd);
+ goto out;
+
+ case DKIO_NONE:
+ default:
+ break;
+ }
+ } else {
+ HAL_DEBUG (("DKIOCSTATE failed: %s\n", strerror(errno)));
+ sleep (SLEEP_PERIOD);
+ }
+ }
+ }
+
+out:
+ if (ctx != NULL) {
+ my_dbus_error_free (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return 0;
+}
diff --git a/hald/solaris/devinfo.c b/hald/solaris/devinfo.c
new file mode 100644
index 0000000..e82317f
--- /dev/null
+++ b/hald/solaris/devinfo.c
@@ -0,0 +1,380 @@
+/***************************************************************************
+ *
+ * devinfo.c : main file for libdevinfo-based device enumeration
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libdevinfo.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "../hald_runner.h"
+#include "osspec_solaris.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_pci.h"
+#include "devinfo_storage.h"
+#include "devinfo_ieee1394.h"
+#include "devinfo_usb.h"
+#include "devinfo_misc.h"
+
+void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root);
+HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node);
+
+void
+devinfo_add(HalDevice *parent, gchar *path)
+{
+ di_node_t root;
+
+ if (strcmp (path, "/") == 0) {
+ if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) {
+ HAL_INFO (("di_init() failed %d", errno));
+ return;
+ }
+ } else {
+ if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) {
+ HAL_INFO (("di_init() failed %d", errno));
+ return;
+ }
+ }
+
+ devinfo_add_subtree(parent, root, TRUE);
+
+ di_fini (root);
+}
+
+void
+devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root)
+{
+ HalDevice *d;
+ di_node_t root_node, child_node;
+
+ HAL_INFO (("add_subtree: %s", di_node_name (node)));
+
+ root_node = node;
+ do {
+ d = devinfo_add_node (parent, node);
+
+ if ((d != NULL) &&
+ (child_node = di_child_node (node)) != DI_NODE_NIL) {
+ devinfo_add_subtree (d, child_node, FALSE);
+ }
+
+ node = di_sibling_node (node);
+ } while ((node != DI_NODE_NIL) &&
+ (!is_root || di_parent_node (node) == root_node));
+}
+
+void
+devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path)
+{
+ char *driver_name, *s;
+ const char *s1;
+ char udi[HAL_PATH_MAX];
+
+ if (parent != NULL) {
+ hal_device_property_set_string (d, "info.parent", hal_device_get_udi (parent));
+ } else {
+ hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local");
+ }
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "/org/freedesktop/Hal/devices%s_%d",
+ devfs_path,
+ di_instance (node));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+
+ if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
+ hal_device_property_set_string (d, "info.product", s);
+ } else {
+ hal_device_property_set_string (d, "info.product", di_node_name (node));
+ }
+
+ hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
+
+ if ((driver_name = di_driver_name (node)) != NULL) {
+ hal_device_property_set_string (d, "info.solaris.driver",
+ driver_name);
+ }
+
+
+ /* inherit parent's claim attributes */
+ if (hal_device_property_get_bool (parent, "info.claimed")) {
+ s1 = hal_device_property_get_string (parent, "info.claimed.service");
+ if (s1 != NULL) {
+ hal_device_property_set_bool (d, "info.claimed", TRUE);
+ hal_device_property_set_string (d, "info.claimed.service", s1);
+ }
+ }
+}
+
+/* device handlers, ordered specific to generic */
+static DevinfoDevHandler *devinfo_handlers[] = {
+ &devinfo_computer_handler,
+ &devinfo_cpu_handler,
+ &devinfo_ide_handler,
+ &devinfo_scsi_handler,
+ &devinfo_floppy_handler,
+ &devinfo_usb_handler,
+ &devinfo_ieee1394_handler,
+ &devinfo_pci_handler,
+ &devinfo_lofi_handler,
+ &devinfo_default_handler,
+ NULL
+};
+
+HalDevice *
+devinfo_add_node(HalDevice *parent, di_node_t node)
+{
+ HalDevice *d = NULL;
+ char *devfs_path;
+ char *device_type = NULL;
+ DevinfoDevHandler *handler;
+ int i;
+
+ devfs_path = di_devfs_path (node);
+
+ (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
+ &device_type);
+
+ for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) {
+ handler = devinfo_handlers[i];
+ d = handler->add (parent, node, devfs_path, device_type);
+ }
+
+ di_devfs_path_free(devfs_path);
+
+ HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none"));
+ return (d);
+}
+
+void
+devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front)
+{
+ HotplugEvent *hotplug_event;
+
+ hotplug_event = g_new0 (HotplugEvent, 1);
+ hotplug_event->action = action;
+ hotplug_event->type = HOTPLUG_EVENT_DEVFS;
+ hotplug_event->d = d;
+ strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path,
+ sizeof (hotplug_event->un.devfs.devfs_path));
+ hotplug_event->un.devfs.handler = handler;
+
+ hotplug_event_enqueue (hotplug_event, front);
+}
+
+void
+devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
+{
+ devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0);
+}
+
+void
+devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
+{
+ devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1);
+}
+
+void
+devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler)
+{
+ devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0);
+}
+
+void
+devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+
+ /* 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);
+}
+
+void
+devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+
+ /* Discard device if probing reports failure */
+ if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) {
+ HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d), return_code));
+ hal_device_store_remove (hald_get_tdl (), d);
+ g_object_unref (d);
+ hotplug_event_end (end_token);
+ return;
+ }
+
+ /* Merge properties from .fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
+ di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
+
+ hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
+}
+
+void
+devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+ DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2;
+ void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer);
+ const gchar *prober;
+ int prober_timeout;
+
+ if (hal_device_property_get_bool (d, "info.ignore")) {
+ HAL_INFO (("Preprobing merged info.ignore==TRUE"));
+
+ /* Leave device with info.ignore==TRUE so we won't pick up children */
+ hal_device_property_remove (d, "info.category");
+ hal_device_property_remove (d, "info.capabilities");
+
+ hal_device_store_remove (hald_get_tdl (), d);
+ hal_device_store_add (hald_get_gdl (), d);
+
+ hotplug_event_end (end_token);
+ return;
+ }
+
+ if (handler != NULL && handler->get_prober != NULL) {
+ prober = handler->get_prober (d, &prober_timeout);
+ } else {
+ prober = NULL;
+ }
+
+ if (handler->probing_done != NULL) {
+ probing_done = handler->probing_done;
+ } else {
+ probing_done = devinfo_callouts_probing_done;
+ }
+
+ if (prober != NULL) {
+ /* probe the device */
+ HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
+ hald_runner_run (d,
+ prober, NULL,
+ prober_timeout,
+ probing_done,
+ (gpointer) end_token, (gpointer) handler);
+ } else {
+ probing_done (d, 0, 0, NULL, userdata1, userdata2);
+ }
+}
+
+/* This is the beginning of hotplug even handling */
+void
+hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
+{
+ HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d)));
+
+ if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) {
+ HAL_INFO (("Ignoring device since parent has info.ignore==TRUE"));
+
+ hotplug_event_end (end_token);
+ return;
+ }
+
+ /* add to TDL so preprobing callouts and prober can access it */
+ hal_device_store_add (hald_get_tdl (), d);
+
+ /* Process preprobe fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
+
+ /* Run preprobe callouts */
+ hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
+}
+
+void
+devinfo_remove (gchar *devfs_path)
+{
+ devinfo_remove_enqueue ((gchar *)devfs_path, NULL);
+}
+
+/* generate hotplug event for each device in this branch */
+void
+devinfo_remove_branch (gchar *devfs_path, HalDevice *d)
+{
+ GSList *i;
+ GSList *children;
+ HalDevice *child;
+ char *child_devfs_path;
+
+ if (d == NULL) {
+ d = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path", devfs_path);
+ if (d == NULL)
+ return;
+ }
+
+ HAL_INFO (("remove_branch: %s %s\n", devfs_path, hal_device_get_udi (d)));
+
+ /* first remove children */
+ children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
+ "info.parent", hal_device_get_udi (d));
+ for (i = children; i != NULL; i = g_slist_next (i)) {
+ child = HAL_DEVICE (i->data);
+ HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child)));
+ devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child);
+ }
+ g_slist_free (children);
+ HAL_INFO (("remove_branch: done with children"));
+
+ /* then remove self */
+ HAL_INFO (("remove_branch: queueing %s", devfs_path));
+ devinfo_remove_enqueue (devfs_path, NULL);
+}
+
+void
+devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+
+ HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d)));
+
+ if (!hal_device_store_remove (hald_get_gdl (), d)) {
+ HAL_WARNING (("Error removing device"));
+ }
+ g_object_unref (d);
+
+ hotplug_event_end (end_token);
+}
+
+void
+hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token)
+{
+ if (hal_device_has_capability (d, "volume")) {
+ devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token);
+ } else {
+ hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
+ }
+}
+
+gboolean
+devinfo_device_rescan (HalDevice *d)
+{
+ if (hal_device_has_capability (d, "block")) {
+ return (devinfo_storage_device_rescan (d));
+ } else {
+ return (FALSE);
+ }
+}
diff --git a/hald/solaris/devinfo.h b/hald/solaris/devinfo.h
new file mode 100644
index 0000000..27b9b48
--- /dev/null
+++ b/hald/solaris/devinfo.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *
+ * devinfo.h : definitions for libdevinfo-based device enumeration
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_H
+#define DEVINFO_H
+
+#include <glib.h>
+#include <libdevinfo.h>
+
+#include "../hald.h"
+#include "../device_info.h"
+
+typedef struct DevinfoDevHandler_s
+{
+ HalDevice *(*add) (HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+
+ /* yet unused */
+ void (*remove) (char *devfs_path);
+
+ void (*hotplug_begin_add) (HalDevice *d, HalDevice *parent, struct DevinfoDevHandler_s *handler, void *end_token);
+
+ void (*hotplug_begin_remove) (HalDevice *d, struct DevinfoDevHandler_s *handler, void *end_token);
+
+ void (*probing_done) (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2);
+
+ const gchar *(*get_prober) (HalDevice *d, int *timeout);
+} DevinfoDevHandler;
+
+#define PROP_INT(d, node, v, diprop, halprop) \
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, diprop, &(v)) > 0) { \
+ hal_device_property_set_int (d, halprop, *(v)); \
+ }
+
+#define PROP_STR(d, node, v, diprop, halprop) \
+ if (di_prop_lookup_strings(DDI_DEV_T_ANY, node, diprop, &(v)) > 0) { \
+ hal_device_property_set_string (d, halprop, v); \
+ }
+
+#define PROP_BOOL(d, node, v, diprop, halprop) \
+ hal_device_property_set_bool (d, halprop, \
+ (di_prop_lookup_ints(DDI_DEV_T_ANY, node, diprop, &(v)) >= 0));
+
+#define NELEM(a) (sizeof (a) / sizeof (*(a)))
+
+void devinfo_add (HalDevice *parent, gchar *path);
+void devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path);
+void devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2);
+void devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error,
+ gpointer userdata1, gpointer userdata2);
+void devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2);
+void devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2);
+void hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
+void devinfo_remove (gchar *path);
+void devinfo_remove_branch (gchar *path, HalDevice *d);
+void hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token);
+void devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front);
+void devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler);
+void devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler);
+void devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler);
+gboolean devinfo_device_rescan (HalDevice *d);
+
+#endif /* DEVINFO_H */
diff --git a/hald/solaris/devinfo_ieee1394.c b/hald/solaris/devinfo_ieee1394.c
new file mode 100644
index 0000000..240af8c
--- /dev/null
+++ b/hald/solaris/devinfo_ieee1394.c
@@ -0,0 +1,90 @@
+/***************************************************************************
+ *
+ * devinfo_ieee1394.c : IEEE 1394/FireWire devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_ieee1394.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libdevinfo.h>
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#include <sys/stat.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "../ids.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_ieee1394.h"
+
+HalDevice *devinfo_ieee1394_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static HalDevice *devinfo_scsa1394_add(HalDevice *d, di_node_t node, gchar *devfs_path);
+
+DevinfoDevHandler devinfo_ieee1394_handler = {
+ devinfo_ieee1394_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+HalDevice *
+devinfo_ieee1394_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ HalDevice *d = NULL;
+ char *compat;
+ char *driver_name;
+
+ /*
+ * we distinguish 1394 devices by compatible name
+ * starting with 'firewire'
+ */
+ if ((di_compatible_names (node, &compat) < 1) ||
+ (strncmp (compat, "firewire", sizeof ("firewire") - 1) != 0)) {
+ return (NULL);
+ }
+
+ if ((driver_name = di_driver_name (node)) == NULL) {
+ return (NULL);
+ }
+
+ if (strcmp (driver_name, "scsa1394") == 0) {
+ d = devinfo_scsa1394_add (parent, node, devfs_path);
+ }
+
+ return (d);
+}
+
+static HalDevice *
+devinfo_scsa1394_add(HalDevice *parent, di_node_t node, gchar *devfs_path)
+{
+ HalDevice *d = NULL;
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.bus", "ieee1394");
+ hal_device_property_set_string (d, "info.product", "FireWire SBP-2 device");
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_ieee1394_handler);
+
+ return (d);
+}
+
diff --git a/hald/solaris/devinfo_ieee1394.h b/hald/solaris/devinfo_ieee1394.h
new file mode 100644
index 0000000..5f82443
--- /dev/null
+++ b/hald/solaris/devinfo_ieee1394.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * devinfo_ieee1394.h : definitions for IEEE 1394 devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_ieee1394.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_IEEE1394_H
+#define DEVINFO_IEEE1394_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_ieee1394_handler;
+
+#endif /* DEVINFO_IEEE1394_H */
diff --git a/hald/solaris/devinfo_misc.c b/hald/solaris/devinfo_misc.c
new file mode 100644
index 0000000..2e1be2b
--- /dev/null
+++ b/hald/solaris/devinfo_misc.c
@@ -0,0 +1,147 @@
+/***************************************************************************
+ *
+ * devinfo_misc : misc devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_misc.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/utsname.h>
+#include <libdevinfo.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "devinfo_misc.h"
+
+static HalDevice *devinfo_computer_add(HalDevice *, di_node_t, char *, char *);
+static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *,char *);
+static HalDevice *devinfo_default_add(HalDevice *, di_node_t, char *, char *);
+
+DevinfoDevHandler devinfo_computer_handler = {
+ devinfo_computer_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_cpu_handler = {
+ devinfo_cpu_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_default_handler = {
+ devinfo_default_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+static HalDevice *
+devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ HalDevice *d, *local_d;
+ struct utsname un;
+
+ if (strcmp (devfs_path, "/") != 0) {
+ return (NULL);
+ }
+
+ d = hal_device_new ();
+
+ hal_device_property_set_string (d, "info.bus", "unknown");
+ hal_device_property_set_string (d, "info.product", "Computer");
+ hal_device_property_set_string (d, "info.udi", "/org/freedesktop/Hal/devices/computer");
+ hal_device_set_udi (d, "/org/freedesktop/Hal/devices/computer");
+ hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
+
+ if (uname (&un) >= 0) {
+ hal_device_property_set_string (d, "system.kernel.name", un.sysname);
+ hal_device_property_set_string (d, "system.kernel.version", un.release);
+ hal_device_property_set_string (d, "system.kernel.machine", un.machine);
+ }
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_computer_handler);
+
+ /* all devinfo devices belong to the 'local' branch */
+ local_d = hal_device_new ();
+
+ hal_device_property_set_string (local_d, "info.parent", hal_device_get_udi (d));
+ hal_device_property_set_string (local_d, "info.bus", "unknown");
+ hal_device_property_set_string (local_d, "info.product", "Local devices");
+ hal_device_property_set_string (local_d, "info.udi", "/org/freedesktop/Hal/devices/local");
+ hal_device_set_udi (local_d, "/org/freedesktop/Hal/devices/local");
+ hal_device_property_set_string (local_d, "solaris.devfs_path", "/local");
+
+ devinfo_add_enqueue (local_d, "/local", &devinfo_default_handler);
+
+ return (local_d);
+}
+
+static HalDevice *
+devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ HalDevice *d;
+
+ if ((device_type == NULL) || (strcmp(device_type, "cpu") != 0)) {
+ return (NULL);
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_add_capability (d, "processor");
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_cpu_handler);
+
+ return (d);
+}
+
+static HalDevice *
+devinfo_default_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ char *driver_name;
+ const char *parent_path;
+ HalDevice *d;
+
+ /* ignore all children of the 'pseudo' node except lofi */
+ if (parent != NULL) {
+ parent_path = hal_device_property_get_string(parent, "solaris.devfs_path");
+ if ((parent_path != NULL) &&
+ (strcmp (parent_path, "/pseudo") == 0)) {
+ driver_name = di_driver_name (node);
+ if ((driver_name != NULL) &&
+ (strcmp (driver_name, "lofi") != 0)) {
+ return (NULL);
+ }
+ }
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_default_handler);
+
+ return (d);
+}
diff --git a/hald/solaris/devinfo_misc.h b/hald/solaris/devinfo_misc.h
new file mode 100644
index 0000000..bc5f071
--- /dev/null
+++ b/hald/solaris/devinfo_misc.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ *
+ * devinfo_misc.h : definitions for misc devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_misc.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_MISC_H
+#define DEVINFO_MISC_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_cpu_handler;
+extern DevinfoDevHandler devinfo_computer_handler;
+extern DevinfoDevHandler devinfo_default_handler;
+
+#endif /* DEVINFO_MISC_H */
diff --git a/hald/solaris/devinfo_pci.c b/hald/solaris/devinfo_pci.c
new file mode 100644
index 0000000..8bd026b
--- /dev/null
+++ b/hald/solaris/devinfo_pci.c
@@ -0,0 +1,122 @@
+/***************************************************************************
+ *
+ * devinfo_pci.c : PCI devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_pci.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libdevinfo.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "../ids.h"
+#include "devinfo_pci.h"
+
+HalDevice *devinfo_pci_add (HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+
+DevinfoDevHandler devinfo_pci_handler = {
+ devinfo_pci_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+HalDevice *devinfo_pci_add (HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ HalDevice *d;
+ char *s;
+ int *i;
+ int vid, pid, svid, spid;
+
+ if ((device_type == NULL) ||
+ ((strcmp (device_type, "pci") != 0) &&
+ (strcmp (device_type, "pci-ide") != 0))) {
+ if (parent == NULL) {
+ return (NULL);
+ } else {
+ s = (char *)hal_device_property_get_string (parent, "info.bus");
+ if ((s == NULL) || (strcmp (s, "pci") != 0)) {
+ return (NULL);
+ }
+ }
+ }
+
+ d = hal_device_new ();
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+
+ hal_device_property_set_string (d, "info.bus", "pci");
+
+ vid = pid = svid = spid = 0;
+ if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "vendor-id", &i) > 0) {
+ vid = i[0];
+ }
+ if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "device-id", &i) > 0) {
+ pid = i[0];
+ }
+ if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "subsystem-vendor-id", &i) > 0) {
+ svid = i[0];
+ }
+ if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "subsystem-id", &i) > 0) {
+ spid = i[0];
+ }
+ hal_device_property_set_int (d, "pci.vendor_id", vid);
+ hal_device_property_set_int (d, "pci.product_id", pid);
+ hal_device_property_set_int (d, "pci.subsys_vendor_id", svid);
+ hal_device_property_set_int (d, "pci.subsys_product_id", spid);
+
+ {
+ char *vendor_name;
+ char *product_name;
+ char *subsys_vendor_name;
+ char *subsys_product_name;
+
+ ids_find_pci (hal_device_property_get_int (d, "pci.vendor_id"),
+ hal_device_property_get_int (d, "pci.product_id"),
+ hal_device_property_get_int (d, "pci.subsys_vendor_id"),
+ hal_device_property_get_int (d, "pci.subsys_product_id"),
+ &vendor_name, &product_name, &subsys_vendor_name,
+&subsys_product_name);
+
+ if (vendor_name != NULL) {
+ hal_device_property_set_string (d, "pci.vendor", vendor_name);
+ hal_device_property_set_string (d, "info.vendor", vendor_name);
+ }
+
+ if (product_name != NULL) {
+ hal_device_property_set_string (d, "pci.product", product_name);
+ hal_device_property_set_string (d, "info.product", product_name);
+ }
+
+ if (subsys_vendor_name != NULL) {
+ hal_device_property_set_string (d, "pci.subsys_vendor",
+subsys_vendor_name);
+ }
+
+ if (subsys_product_name != NULL) {
+ hal_device_property_set_string (d, "pci.subsys_product", subsys_product_name);
+ }
+ }
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_pci_handler);
+
+ return (d);
+}
+
diff --git a/hald/solaris/devinfo_pci.h b/hald/solaris/devinfo_pci.h
new file mode 100644
index 0000000..d0d0d8a
--- /dev/null
+++ b/hald/solaris/devinfo_pci.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * devinfo_pci.h : definitions for PCI devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_pci.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_PCI_H
+#define DEVINFO_PCI_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_pci_handler;
+
+#endif /* DEVINFO_PCI_H */
diff --git a/hald/solaris/devinfo_storage.c b/hald/solaris/devinfo_storage.c
new file mode 100644
index 0000000..0026b70
--- /dev/null
+++ b/hald/solaris/devinfo_storage.c
@@ -0,0 +1,1673 @@
+/***************************************************************************
+ *
+ * devinfo_storage.c : storage devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_storage.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <libdevinfo.h>
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#include <sys/stat.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "../hald_runner.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_misc.h"
+#include "devinfo_storage.h"
+#include "osspec_solaris.h"
+
+#ifdef sparc
+#define WHOLE_DISK "s2"
+#else
+#define WHOLE_DISK "p0"
+#endif
+
+/* some devices,especially CDROMs, may take a while to be probed (values in ms) */
+#define DEVINFO_PROBE_STORAGE_TIMEOUT 60000
+#define DEVINFO_PROBE_VOLUME_TIMEOUT 60000
+
+typedef struct devinfo_storage_minor {
+ char *devpath;
+ char *devlink;
+ char *slice;
+ dev_t dev;
+ int dosnum; /* dos disk number or -1 */
+} devinfo_storage_minor_t;
+
+HalDevice *devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static HalDevice *devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path);
+static HalDevice *devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path);
+static HalDevice *devinfo_ide_storage_add(HalDevice *grampa, HalDevice *parent, di_node_t node, char *devfs_path);
+HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static HalDevice *devinfo_scsi_storage_add(HalDevice *grampa, HalDevice *parent, di_node_t node, char *devfs_path);
+HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node);
+static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev);
+static int walk_devlinks(di_devlink_t devlink, void *arg);
+static char *get_devlink(di_devlink_handle_t devlink_hdl, char *path);
+static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean);
+static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice,
+ char *devlink, dev_t dev, int dosnum);
+static void devinfo_storage_free_minor(struct devinfo_storage_minor *m);
+HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m);
+static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2);
+static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
+static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
+static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2);
+const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout);
+const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout);
+
+static char *devinfo_scsi_dtype2str(int dtype);
+static char *devinfo_volume_get_slice_name (char *devlink);
+static gboolean dos_to_dev(char *path, char **devpath, int *partnum);
+static gboolean is_dos_path(char *path, int *partnum);
+
+static void devinfo_storage_set_nicknames (HalDevice *d);
+
+DevinfoDevHandler devinfo_ide_handler = {
+ devinfo_ide_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_scsi_handler = {
+ devinfo_scsi_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_floppy_handler = {
+ devinfo_floppy_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_lofi_handler = {
+ devinfo_lofi_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+DevinfoDevHandler devinfo_storage_handler = {
+ NULL,
+ NULL,
+ devinfo_storage_hotplug_begin_add,
+ NULL,
+ devinfo_storage_probing_done,
+ devinfo_storage_get_prober
+};
+DevinfoDevHandler devinfo_volume_handler = {
+ NULL,
+ NULL,
+ devinfo_volume_hotplug_begin_add,
+ NULL,
+ NULL,
+ devinfo_volume_get_prober
+};
+
+/* IDE */
+
+HalDevice *
+devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ char *s;
+
+ if ((device_type != NULL) && (strcmp(device_type, "ide") == 0)) {
+ return (devinfo_ide_host_add(parent, node, devfs_path));
+ }
+
+ if ((di_prop_lookup_strings (DDI_DEV_T_ANY, node, "class", &s) > 0) &&
+ (strcmp (s, "dada") == 0)) {
+ return (devinfo_ide_device_add(parent, node, devfs_path));
+ }
+
+ return (NULL);
+}
+
+static HalDevice *
+devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path)
+{
+ HalDevice *d;
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.product", "IDE host controller");
+ hal_device_property_set_string (d, "info.bus", "ide_host");
+ hal_device_property_set_int (d, "ide_host.number", 0); /* XXX */
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
+
+ return (d);
+}
+
+static HalDevice *
+devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path)
+{
+ HalDevice *d;
+
+ d = hal_device_new();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (parent, "info.product", "IDE device");
+ hal_device_property_set_string (parent, "info.bus", "ide");
+ hal_device_property_set_int (parent, "ide.host", 0); /* XXX */
+ hal_device_property_set_int (parent, "ide.channel", 0);
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
+
+ return (devinfo_ide_storage_add (parent, d, node, devfs_path));
+}
+
+static HalDevice *
+devinfo_ide_storage_add(HalDevice *grampa, HalDevice *parent, di_node_t node, char *devfs_path)
+{
+ HalDevice *d;
+ char *s;
+ int *i;
+ char *driver_name;
+ char udi[HAL_PATH_MAX];
+
+ if ((driver_name = di_driver_name (node)) == NULL) {
+ return (NULL);
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.category", "storage");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/%s%d", hal_device_get_udi (parent), driver_name, di_instance (node));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ PROP_STR(d, node, s, "devid", "info.product");
+
+ hal_device_add_capability (d, "storage");
+ hal_device_property_set_string (d, "storage.bus", "ide");
+ hal_device_property_set_int (d, "storage.lun", 0);
+ hal_device_property_set_string (d, "storage.drive_type", "disk");
+
+ PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
+ PROP_BOOL(d, node, i, "removable-media", "storage.removable");
+
+ hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
+
+ /* XXX */
+ hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
+
+ hal_device_add_capability (d, "block");
+
+ devinfo_storage_minors (d, node, (char *)devfs_path, FALSE);
+
+ return (d);
+}
+
+/* SCSI */
+
+HalDevice *
+devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ int *i;
+ char *driver_name;
+ HalDevice *d;
+ char udi[HAL_PATH_MAX];
+
+ driver_name = di_driver_name (node);
+ if ((driver_name == NULL) || (strcmp (driver_name, "sd") != 0)) {
+ return (NULL);
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.bus", "scsi");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+
+ hal_device_property_set_int (d, "scsi.host",
+ hal_device_property_get_int (parent, "scsi_host.host"));
+ hal_device_property_set_int (d, "scsi.bus", 0);
+ PROP_INT(d, node, i, "target", "scsi.target");
+ PROP_INT(d, node, i, "lun", "scsi.lun");
+ hal_device_property_set_string (d, "info.product", "SCSI Device");
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_scsi_handler);
+
+ return (devinfo_scsi_storage_add (parent, d, node, devfs_path));
+}
+
+static HalDevice *
+devinfo_scsi_storage_add(HalDevice *grampa, HalDevice *parent, di_node_t node, char *devfs_path)
+{
+ HalDevice *d;
+ int *i;
+ char *s;
+ char udi[HAL_PATH_MAX];
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.category", "storage");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/sd%d", hal_device_get_udi (parent), di_instance (node));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ PROP_STR(d, node, s, "inquiry-product-id", "info.product");
+
+ hal_device_add_capability (d, "storage");
+
+ hal_device_property_set_int (d, "storage.lun",
+ hal_device_property_get_int (parent, "scsi.lun"));
+ PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
+ PROP_BOOL(d, node, i, "removable-media", "storage.removable");
+ hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
+
+ /*
+ * We have to enable polling not only for drives with removable media,
+ * but also for hotpluggable devices, because when a disk is
+ * unplugged while busy/mounted, there is not sysevent generated.
+ * Instead, the HBA driver (scsa2usb, scsa1394) will notify sd driver
+ * and the latter will report DKIO_DEV_GONE via DKIOCSTATE ioctl.
+ * So we have to enable media check so that hald-addon-storage notices
+ * the "device gone" condition and unmounts all associated volumes.
+ */
+ hal_device_property_set_bool (d, "storage.media_check_enabled",
+ ((di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", &i) >= 0) ||
+ (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", &i) >= 0)));
+
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
+ &i) > 0) {
+ s = devinfo_scsi_dtype2str (*i);
+ hal_device_property_set_string (d, "storage.drive_type", s);
+
+ if (strcmp (s, "cdrom") == 0) {
+ hal_device_add_capability (d, "storage.cdrom");
+ hal_device_property_set_bool (d, "storage.no_partitions_hint", TRUE);
+ hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
+ }
+ }
+
+ hal_device_add_capability (d, "block");
+
+ devinfo_storage_minors (d, node, devfs_path, FALSE);
+
+ return (d);
+}
+
+static char *devinfo_scsi_dtype2str(int dtype)
+{
+ char *dtype2str[] = {
+ "disk" , /* DTYPE_DIRECT 0x00 */
+ "tape" , /* DTYPE_SEQUENTIAL 0x01 */
+ "printer", /* DTYPE_PRINTER 0x02 */
+ "processor", /* DTYPE_PROCESSOR 0x03 */
+ "worm" , /* DTYPE_WORM 0x04 */
+ "cdrom" , /* DTYPE_RODIRECT 0x05 */
+ "scanner", /* DTYPE_SCANNER 0x06 */
+ "cdrom" , /* DTYPE_OPTICAL 0x07 */
+ "changer", /* DTYPE_CHANGER 0x08 */
+ "comm" , /* DTYPE_COMM 0x09 */
+ "scsi" , /* DTYPE_??? 0x0A */
+ "scsi" , /* DTYPE_??? 0x0B */
+ "array_ctrl", /* DTYPE_ARRAY_CTRL 0x0C */
+ "esi" , /* DTYPE_ESI 0x0D */
+ "disk" /* DTYPE_RBC 0x0E */
+ };
+
+ if (dtype < NELEM(dtype2str)) {
+ return (dtype2str[dtype]);
+ } else {
+ return ("scsi");
+ }
+
+}
+
+/* floppy */
+
+HalDevice *
+devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ char *driver_name;
+ char *raw;
+ char udi[HAL_PATH_MAX];
+ di_devlink_handle_t devlink_hdl;
+ int major;
+ di_minor_t minor;
+ dev_t dev;
+ HalDevice *d = NULL;
+ char *minor_path = NULL;
+ char *devlink = NULL;
+
+ driver_name = di_driver_name (node);
+ if ((driver_name == NULL) || (strcmp (driver_name, "fd") != 0)) {
+ return (NULL);
+ }
+
+ /*
+ * The only minor node we're interested in is /dev/diskette*
+ */
+ major = di_driver_major(node);
+ if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
+ return (NULL);
+ }
+ minor = DI_MINOR_NIL;
+ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
+ dev = di_minor_devt(minor);
+ if ((major != major(dev)) ||
+ (di_minor_type(minor) != DDM_MINOR) ||
+ (di_minor_spectype(minor) != S_IFBLK) ||
+ ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
+ continue;
+ }
+ if (((devlink = get_devlink(devlink_hdl, minor_path)) != NULL) &&
+ (strncmp (devlink, "/dev/diskette", sizeof ("/dev/diskette") - 1) == 0)) {
+ break;
+ }
+ di_devfs_path_free (minor_path);
+ minor_path = NULL;
+ free(devlink);
+ devlink = NULL;
+ }
+ di_devlink_fini (&devlink_hdl);
+
+ if ((devlink == NULL) || (minor_path == NULL)) {
+ HAL_INFO (("floppy devlink not found %s", devfs_path));
+ goto out;
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.category", "storage");
+ hal_device_add_capability (d, "storage");
+ hal_device_property_set_string (d, "storage.bus", "platform");
+ hal_device_property_set_bool (d, "storage.hotpluggable", FALSE);
+ hal_device_property_set_bool (d, "storage.removable", TRUE);
+ hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
+ hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
+ hal_device_property_set_string (d, "storage.drive_type", "floppy");
+
+ hal_device_add_capability (d, "block");
+ hal_device_property_set_bool (d, "block.is_volume", FALSE);
+ hal_device_property_set_int (d, "block.major", major(dev));
+ hal_device_property_set_int (d, "block.minor", minor(dev));
+ hal_device_property_set_string (d, "block.device", devlink);
+ raw = dsk_to_rdsk (devlink);
+ hal_device_property_set_string (d, "block.solaris.raw_device", raw);
+ free (raw);
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_storage_handler);
+
+ /* trigger initial probe-volume */
+ devinfo_floppy_add_volume(d, node);
+
+out:
+ di_devfs_path_free (minor_path);
+ free(devlink);
+
+ return (d);
+}
+
+static void
+devinfo_floppy_add_volume(HalDevice *parent, di_node_t node)
+{
+ char *devlink;
+ char *devfs_path;
+ int minor, major;
+ dev_t dev;
+ struct devinfo_storage_minor *m;
+
+ devfs_path = (char *)hal_device_property_get_string (parent, "solaris.devfs_path");
+ devlink = (char *)hal_device_property_get_string (parent, "block.device");
+ major = hal_device_property_get_int (parent, "block.major");
+ minor = hal_device_property_get_int (parent, "block.minor");
+ dev = makedev (major, minor);
+
+ m = devinfo_storage_new_minor (devfs_path, WHOLE_DISK, devlink, dev, -1);
+ devinfo_volume_add (parent, node, m);
+ devinfo_storage_free_minor (m);
+}
+
+/*
+ * After reprobing storage, reprobe its volumes.
+ */
+static void
+devinfo_floppy_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code,
+ char **error, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+ const char *devfs_path;
+ di_node_t node;
+ HalDevice *v;
+
+ if (!hal_device_property_get_bool (d, "storage.removable.media_available")) {
+ HAL_INFO (("no floppy media", hal_device_get_udi (d)));
+
+ /* remove child (can only be single volume) */
+ if (((v = hal_device_store_match_key_value_string (hald_get_gdl(),
+ "info.parent", hal_device_get_udi (d))) != NULL) &&
+ ((devfs_path = hal_device_property_get_string (v,
+ "solaris.devfs_path")) != NULL)) {
+ devinfo_remove_enqueue ((char *)devfs_path, NULL);
+ }
+ } else {
+ HAL_INFO (("floppy media found", hal_device_get_udi (d)));
+
+ if ((devfs_path = hal_device_property_get_string(d, "solaris.devfs_path")) == NULL) {
+ HAL_INFO (("no devfs_path", hal_device_get_udi (d)));
+ hotplug_event_process_queue ();
+ return;
+ }
+ if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
+ HAL_INFO (("di_init %s failed %d", devfs_path, errno));
+ hotplug_event_process_queue ();
+ return;
+ }
+
+ devinfo_floppy_add_volume (d, node);
+
+ di_fini (node);
+ }
+
+ hotplug_event_process_queue ();
+}
+
+/* lofi */
+
+HalDevice *
+devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ return (devinfo_lofi_add_major(parent,node, devfs_path, device_type, FALSE, NULL));
+}
+
+HalDevice *
+devinfo_lofi_add_major(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type,
+ gboolean rescan, HalDevice *lofi_d)
+{
+ char *driver_name;
+ HalDevice *d = NULL;
+ char udi[HAL_PATH_MAX];
+ di_devlink_handle_t devlink_hdl;
+ int major;
+ di_minor_t minor;
+ dev_t dev;
+ char *minor_path = NULL;
+ char *devpath, *devlink;
+
+ driver_name = di_driver_name (node);
+ if ((driver_name == NULL) || (strcmp (driver_name, "lofi") != 0)) {
+ return (NULL);
+ }
+
+ if (!rescan) {
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.bus", "pseudo");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_lofi_handler);
+ } else {
+ d = lofi_d;
+ }
+
+ /*
+ * Unlike normal storage, as in devinfo_storage_minors(), where
+ * sd instance -> HAL storage, sd minor node -> HAL volume,
+ * lofi always has one instance, lofi minor -> HAL storage.
+ * lofi storage never has slices, but it can have
+ * embedded pcfs partitions that fstyp would recognize
+ */
+ major = di_driver_major(node);
+ if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
+ return (d);
+ }
+ minor = DI_MINOR_NIL;
+ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
+ dev = di_minor_devt(minor);
+ if ((major != major(dev)) ||
+ (di_minor_type(minor) != DDM_MINOR) ||
+ (di_minor_spectype(minor) != S_IFBLK) ||
+ ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
+ continue;
+ }
+ if ((devlink = get_devlink(devlink_hdl, minor_path)) == NULL) {
+ di_devfs_path_free (minor_path);
+ continue;
+ }
+
+ if (!rescan ||
+ (hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path", minor_path) == NULL)) {
+ devinfo_lofi_add_minor(d, node, minor_path, devlink, dev);
+ }
+
+ di_devfs_path_free (minor_path);
+ free(devlink);
+ }
+ di_devlink_fini (&devlink_hdl);
+
+ return (d);
+}
+
+static void
+devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev)
+{
+ HalDevice *d;
+ char *raw;
+ char *doslink;
+ char dospath[64];
+ struct devinfo_storage_minor *m;
+ int i;
+
+ /* add storage */
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, minor_path);
+ hal_device_property_set_string (d, "info.category", "storage");
+ hal_device_add_capability (d, "storage");
+ hal_device_property_set_string (d, "storage.bus", "lofi");
+ hal_device_property_set_bool (d, "storage.hotpluggable", TRUE);
+ hal_device_property_set_bool (d, "storage.removable", FALSE);
+ hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
+ hal_device_property_set_string (d, "storage.drive_type", "disk");
+ hal_device_add_capability (d, "block");
+ hal_device_property_set_int (d, "block.major", major(dev));
+ hal_device_property_set_int (d, "block.minor", minor(dev));
+ hal_device_property_set_string (d, "block.device", devlink);
+ raw = dsk_to_rdsk (devlink);
+ hal_device_property_set_string (d, "block.solaris.raw_device", raw);
+ free (raw);
+ hal_device_property_set_bool (d, "block.is_volume", FALSE);
+
+ devinfo_add_enqueue (d, minor_path, &devinfo_storage_handler);
+
+ /* add volumes: one on main device and a few pcfs candidates */
+ m = devinfo_storage_new_minor(minor_path, WHOLE_DISK, devlink, dev, -1);
+ devinfo_volume_add (d, node, m);
+ devinfo_storage_free_minor (m);
+
+ doslink = (char *)calloc (1, strlen (devlink) + sizeof (":NNN") + 1);
+ if (doslink != NULL) {
+ for (i = 1; i < 16; i++) {
+ snprintf(dospath, sizeof (dospath), WHOLE_DISK":%d", i);
+ sprintf(doslink, "%s:%d", devlink, i);
+ m = devinfo_storage_new_minor(minor_path, dospath, doslink, dev, i);
+ devinfo_volume_add (d, node, m);
+ devinfo_storage_free_minor (m);
+ }
+ free (doslink);
+ }
+}
+
+void
+devinfo_lofi_remove_minor(char *parent_devfs_path, char *name)
+{
+ GSList *i;
+ GSList *devices;
+ HalDevice *d = NULL;
+ const char *devfs_path;
+
+ devices = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
+ "block.solaris.raw_device", name);
+ for (i = devices; i != NULL; i = g_slist_next (i)) {
+ if (hal_device_has_capability (HAL_DEVICE (i->data), "storage")) {
+ d = HAL_DEVICE (i->data);
+ break;
+ }
+ }
+ g_slist_free (devices);
+
+ if (d == NULL) {
+ HAL_INFO (("device not found %s", name));
+ return;
+ }
+
+ if ((devfs_path = hal_device_property_get_string (d,
+ "solaris.devfs_path")) == NULL) {
+ HAL_INFO (("devfs_path not found %s", hal_device_get_udi (d)));
+ return;
+ }
+
+ if (d != NULL) {
+ devinfo_remove_branch ((char *)devfs_path, d);
+ }
+}
+
+/* common storage */
+
+static int
+walk_devlinks(di_devlink_t devlink, void *arg)
+{
+ char **path= (char **)arg;
+
+ *path = strdup(di_devlink_path(devlink));
+
+ return (DI_WALK_TERMINATE);
+}
+
+static char *
+get_devlink(di_devlink_handle_t devlink_hdl, char *path)
+{
+ char *devlink_path = NULL;
+
+ (void) di_devlink_walk(devlink_hdl, NULL, path,
+ DI_PRIMARY_LINK, &devlink_path, walk_devlinks);
+
+ return (devlink_path);
+}
+
+static void
+devinfo_storage_free_minor(struct devinfo_storage_minor *m)
+{
+ if (m != NULL) {
+ free (m->slice);
+ free (m->devlink);
+ free (m->devpath);
+ free (m);
+ }
+}
+
+static struct devinfo_storage_minor *
+devinfo_storage_new_minor(char *maindev_path, char *slice, char *devlink, dev_t dev, int dosnum)
+{
+ struct devinfo_storage_minor *m;
+ int pathlen;
+ char *devpath;
+
+ m = (struct devinfo_storage_minor *)calloc (sizeof (struct devinfo_storage_minor), 1);
+ if (m != NULL) {
+ /*
+ * For volume's devfs_path we'll use minor_path/slice instead of
+ * minor_path which we use for parent storage device.
+ */
+ pathlen = strlen (maindev_path) + strlen (slice) + 2;
+ devpath = (char *)calloc (1, pathlen);
+ snprintf(devpath, pathlen, "%s/%s", maindev_path, slice);
+
+ m->devpath = devpath;
+ m->devlink = strdup (devlink);
+ m->slice = strdup (slice);
+ m->dev = dev;
+ m->dosnum = dosnum;
+ if ((m->devpath == NULL) || (m->devlink == NULL)) {
+ devinfo_storage_free_minor (m);
+ m = NULL;
+ }
+ }
+ return (m);
+}
+
+/*
+ * Storage minor nodes are potential "volume" objects.
+ * This function also completes building the parent object (main storage device).
+ */
+static void
+devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean rescan)
+{
+ di_devlink_handle_t devlink_hdl;
+ gboolean is_cdrom;
+ const char *whole_disk;
+ int major;
+ di_minor_t minor;
+ dev_t dev;
+ char *minor_path = NULL;
+ char *maindev_path = NULL;
+ char *devpath, *devlink;
+ int doslink_len;
+ char *doslink;
+ char dospath[64];
+ char *slice;
+ int pathlen;
+ int i;
+ char *raw;
+ boolean_t maindev_is_d0;
+ GQueue *mq;
+ HalDevice *volume;
+ struct devinfo_storage_minor *m;
+ struct devinfo_storage_minor *maindev = NULL;
+
+ /* for cdroms whole disk is always s2 */
+ is_cdrom = hal_device_has_capability (parent, "storage.cdrom");
+ whole_disk = is_cdrom ? "s2" : WHOLE_DISK;
+
+ major = di_driver_major(node);
+
+ /* the "whole disk" p0/s2/d0 node must come first in the hotplug queue
+ * so we put other minor nodes on the local queue and move to the
+ * hotplug queue up in the end
+ */
+ if ((mq = g_queue_new()) == NULL) {
+ goto err;
+ }
+ if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
+ g_queue_free (mq);
+ goto err;
+ }
+ minor = DI_MINOR_NIL;
+ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
+ dev = di_minor_devt(minor);
+ if ((major != major(dev)) ||
+ (di_minor_type(minor) != DDM_MINOR) ||
+ (di_minor_spectype(minor) != S_IFBLK) ||
+ ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
+ continue;
+ }
+ if ((devlink = get_devlink(devlink_hdl, minor_path)) == NULL) {
+ di_devfs_path_free (minor_path);
+ continue;
+ }
+
+ slice = devinfo_volume_get_slice_name (devlink);
+ if (strlen (slice) < 2) {
+ free (devlink);
+ di_devfs_path_free (minor_path);
+ continue;
+ }
+
+ /* ignore p1..N - we'll use p0:N instead */
+ if ((strlen (slice) > 1) && (slice[0] == 'p') && isdigit(slice[1]) &&
+ ((atol(&slice[1])) > 0)) {
+ free (devlink);
+ di_devfs_path_free (minor_path);
+ continue;
+ }
+
+ m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1);
+ if (m == NULL) {
+ free (devlink);
+ di_devfs_path_free (minor_path);
+ continue;
+ }
+
+ /* main device is either s2/p0 or d0, the latter taking precedence */
+ if ((strcmp (slice, "d0") == 0) ||
+ (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) {
+ if (maindev_path != NULL) {
+ di_devfs_path_free (maindev_path);
+ }
+ maindev_path = minor_path;
+ maindev = m;
+ g_queue_push_head (mq, maindev);
+ } else {
+ di_devfs_path_free (minor_path);
+ g_queue_push_tail (mq, m);
+ }
+
+ free (devlink);
+ }
+ di_devlink_fini (&devlink_hdl);
+
+ if (maindev == NULL) {
+ /* shouldn't typically happen */
+ while (!g_queue_is_empty (mq)) {
+ devinfo_storage_free_minor (g_queue_pop_head (mq));
+ }
+ goto err;
+ }
+
+ /* first enqueue main storage device */
+ if (!rescan) {
+ hal_device_property_set_int (parent, "block.major", major);
+ hal_device_property_set_int (parent, "block.minor", minor(maindev->dev));
+ hal_device_property_set_string (parent, "block.device", maindev->devlink);
+ raw = dsk_to_rdsk (maindev->devlink);
+ hal_device_property_set_string (parent, "block.solaris.raw_device", raw);
+ free (raw);
+ hal_device_property_set_bool (parent, "block.is_volume", FALSE);
+ hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path);
+ devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler);
+ }
+
+ /* add virtual dos volumes to enable pcfs probing */
+ if (!is_cdrom) {
+ doslink_len = strlen (maindev->devlink) + sizeof (":NNN") + 1;
+ if ((doslink = (char *)calloc (1, doslink_len)) != NULL) {
+ for (i = 1; i < 16; i++) {
+ snprintf(dospath, sizeof (dospath), "%s:%d", maindev->slice, i);
+ snprintf(doslink, doslink_len, "%s:%d", maindev->devlink, i);
+ m = devinfo_storage_new_minor(maindev_path, dospath, doslink, maindev->dev, i);
+ g_queue_push_tail (mq, m);
+ }
+ free (doslink);
+ }
+ }
+
+ maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0);
+
+ /* enqueue all volumes */
+ while (!g_queue_is_empty (mq)) {
+ m = g_queue_pop_head (mq);
+
+ /* if main device is d0, we'll throw away s2/p0 */
+ if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) {
+ devinfo_storage_free_minor (m);
+ continue;
+ }
+ /* don't do p0 on cdrom */
+ if (is_cdrom && (strcmp (m->slice, "p0") == 0)) {
+ devinfo_storage_free_minor (m);
+ continue;
+ }
+ if (rescan) {
+ /* in rescan mode, don't reprobe existing volumes */
+ /* XXX detect volume removal? */
+ volume = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path", m->devpath);
+ if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) {
+ devinfo_volume_add (parent, node, m);
+ } else {
+ HAL_INFO(("rescan volume exists %s", m->devpath));
+ }
+ } else {
+ devinfo_volume_add (parent, node, m);
+ }
+ devinfo_storage_free_minor (m);
+ }
+
+ if (maindev_path != NULL) {
+ di_devfs_path_free (maindev_path);
+ }
+
+ return;
+
+err:
+ if (maindev_path != NULL) {
+ di_devfs_path_free (maindev_path);
+ }
+ if (!rescan) {
+ devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler);
+ }
+}
+
+HalDevice *
+devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m)
+{
+ HalDevice *d;
+ char *raw;
+ char udi[HAL_PATH_MAX];
+ char *devfs_path = m->devpath;
+ char *devlink = m->devlink;
+ dev_t dev = m->dev;
+ int dosnum = m->dosnum;
+ char *slice = m->slice;
+
+ HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink));
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.category", "volume");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/%s", hal_device_get_udi (parent), slice);
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ hal_device_property_set_string (d, "info.product", slice);
+
+ hal_device_add_capability (d, "volume");
+ hal_device_add_capability (d, "block");
+ hal_device_property_set_int (d, "block.major", major (dev));
+ hal_device_property_set_int (d, "block.minor", minor (dev));
+ hal_device_property_set_string (d, "block.device", devlink);
+ raw = dsk_to_rdsk (devlink);
+ hal_device_property_set_string (d, "block.solaris.raw_device", raw);
+ free (raw);
+ hal_device_property_set_string (d, "block.solaris.slice", slice);
+ hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */
+
+ hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent));
+
+ /* set volume 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);
+ if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) {
+ hal_device_property_set_bool (d, "volume.is_disc", TRUE);
+ hal_device_add_capability (d, "volume.disc");
+ } else {
+ hal_device_property_set_bool (d, "volume.is_disc", FALSE);
+ }
+
+ if (dosnum > 0) {
+ hal_device_property_set_bool (d, "volume.is_partition", TRUE);
+ hal_device_property_set_int (d, "volume.partition.number", dosnum);
+ } else {
+ hal_device_property_set_bool (d, "volume.is_partition", FALSE);
+ }
+
+ /* prober may override these */
+ hal_device_property_set_int (d, "volume.block_size", 512);
+
+ devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler);
+
+ return (d);
+}
+
+static void
+devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+ char *whole_disk;
+ char *block_device;
+ const char *storage_udi;
+ HalDevice *storage_d;
+ const char *slice;
+ int dos_num;
+
+ if (hal_device_property_get_bool (d, "info.ignore")) {
+ HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d)));
+ goto skip;
+ }
+
+ /*
+ * Optimizations: only probe if there's a chance to find something
+ */
+ block_device = (char *)hal_device_property_get_string (d, "block.device");
+ storage_udi = hal_device_property_get_string (d, "block.storage_device");
+ slice = hal_device_property_get_string(d, "block.solaris.slice");
+ if ((block_device == NULL) || (storage_udi == NULL) ||
+ (slice == NULL) || (strlen (slice) < 2)) {
+ HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d)));
+ goto skip;
+ }
+ storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi);
+ if (storage_d == NULL) {
+ HAL_INFO (("Storage device not found %s", hal_device_get_udi (d)));
+ goto skip;
+ }
+
+ whole_disk = hal_device_has_capability (storage_d,
+ "storage.cdrom") ? "s2" : WHOLE_DISK;
+
+ if (is_dos_path(block_device, &dos_num)) {
+ /* don't probe more dos volumes than probe-storage found */
+ if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") ||
+ (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) {
+ HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d,
+ "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d)));
+ goto skip;
+ }
+ } else {
+ /* if no VTOC slices found, don't probe slices except s2 */
+ if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) &&
+ !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) {
+ HAL_INFO (("Not probing slice %s", hal_device_get_udi (d)));
+ goto skip;
+ }
+ }
+
+ HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
+ hald_runner_run (d,
+ "hald-probe-volume", NULL,
+ DEVINFO_PROBE_VOLUME_TIMEOUT,
+ devinfo_callouts_probing_done,
+ (gpointer) end_token, userdata2);
+
+ return;
+
+skip:
+ hal_device_store_remove (hald_get_tdl (), d);
+ g_object_unref (d);
+ hotplug_event_end (end_token);
+}
+
+static void
+devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
+{
+ HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d)));
+
+ if (hal_device_property_get_bool (parent, "info.ignore")) {
+ HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE"));
+ goto skip;
+ }
+
+ /* add to TDL so preprobing callouts and prober can access it */
+ hal_device_store_add (hald_get_tdl (), d);
+
+ /* Process preprobe fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
+
+ /* Run preprobe callouts */
+ hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler);
+
+ return;
+
+skip:
+ g_object_unref (d);
+ hotplug_event_end (end_token);
+}
+
+void
+devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
+{
+ const char *drive_type;
+ const char *p_udi;
+ HalDevice *p_d;
+ HalDevice *phys_d = NULL;
+ const char *phys_bus;
+ const char *bus;
+ static const char *busses[] = { "usb", "ide", "scsi", "ieee1394",
+ "pseudo" };
+ int i;
+
+ HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d)));
+
+ if (parent == NULL) {
+ HAL_INFO (("no parent %s", hal_device_get_udi (d)));
+ goto error;
+ }
+
+ /*
+ * figure out physical device and bus, except for floppy
+ */
+ drive_type = hal_device_property_get_string (d, "storage.drive_type");
+ if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) {
+ goto skip_bus;
+ }
+
+ p_d = parent;
+ for (;;) {
+ bus = hal_device_property_get_string (p_d, "info.bus");
+ if (bus != NULL) {
+ for (i = 0; i < NELEM(busses); i++) {
+ if (strcmp(bus, busses[i]) == 0) {
+ phys_d = p_d;
+ phys_bus = busses[i];
+ break;
+ }
+ }
+ }
+ /* up the tree */
+ p_udi = hal_device_property_get_string (p_d, "info.parent");
+ if (p_udi == NULL) {
+ break;
+ }
+ p_d = hal_device_store_find (hald_get_gdl (), p_udi);
+ }
+ if (phys_d == NULL) {
+ HAL_INFO (("no physical device %s", hal_device_get_udi (d)));
+ goto error;
+ }
+ hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d));
+ hal_device_property_set_string (d, "storage.bus", phys_bus);
+
+skip_bus:
+
+ /* add to TDL so preprobing callouts and prober can access it */
+ hal_device_store_add (hald_get_tdl (), d);
+
+ /* Process preprobe fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
+
+ /* Run preprobe callouts */
+ hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
+
+ return;
+
+error:
+ g_object_unref (d);
+ hotplug_event_end (end_token);
+}
+
+static void
+devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+
+ HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d)));
+
+ /* Discard device if probing reports failure */
+ if (exit_type != HALD_RUN_SUCCESS || return_code != 0) {
+ HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code));
+ hal_device_store_remove (hald_get_tdl (), d);
+ g_object_unref (d);
+ hotplug_event_end (end_token);
+ return;
+ }
+
+ devinfo_storage_set_nicknames (d);
+
+ /* Merge properties from .fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
+ di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
+
+ hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
+}
+
+const gchar *
+devinfo_storage_get_prober (HalDevice *d, int *timeout)
+{
+ *timeout = DEVINFO_PROBE_STORAGE_TIMEOUT;
+ return "hald-probe-storage";
+}
+
+const gchar *
+devinfo_volume_get_prober (HalDevice *d, int *timeout)
+{
+ *timeout = DEVINFO_PROBE_VOLUME_TIMEOUT;
+ return "hald-probe-volume";
+}
+
+/*
+ * After reprobing storage, reprobe its volumes.
+ */
+static void
+devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
+{
+ void *end_token = (void *) userdata1;
+ const char *devfs_path_orig = NULL;
+ char *devfs_path = NULL;
+ char *p;
+ di_node_t node;
+
+ HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d)));
+
+ devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path");
+ if (devfs_path_orig == NULL) {
+ HAL_INFO (("device has no solaris.devfs_path"));
+ hotplug_event_process_queue ();
+ return;
+ }
+
+ /* strip trailing minor part if any */
+ if (strrchr(devfs_path_orig, ':') != NULL) {
+ if ((devfs_path = strdup (devfs_path_orig)) != NULL) {
+ p = strrchr(devfs_path, ':');
+ *p = '\0';
+ }
+ } else {
+ devfs_path = (char *)devfs_path_orig;
+ }
+
+ if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
+ HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d)));
+ hotplug_event_process_queue ();
+ return;
+ } else {
+ devinfo_storage_minors (d, node, (char *)devfs_path, TRUE);
+ di_fini (node);
+ }
+
+ if (devfs_path != devfs_path_orig) {
+ free (devfs_path);
+ }
+
+ hotplug_event_process_queue ();
+}
+
+/*
+ * For removable media devices, check for "storage.removable.media_available".
+ * For non-removable media devices, assume media is always there.
+ *
+ * If media is gone, enqueue remove events for all children volumes.
+ * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone).
+ */
+gboolean
+devinfo_storage_device_rescan (HalDevice *d)
+{
+ GSList *i;
+ GSList *volumes;
+ HalDevice *v;
+ gchar *v_devfs_path;
+ const char *drive_type;
+ gboolean is_floppy;
+ gboolean media_available;
+
+ HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d)));
+
+ if (hal_device_property_get_bool (d, "block.is_volume")) {
+ HAL_INFO (("nothing to do for volume"));
+ return (FALSE);
+ }
+
+ drive_type = hal_device_property_get_string (d, "storage.drive_type");
+ is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0);
+
+ media_available = !hal_device_property_get_bool (d, "storage.removable") ||
+ hal_device_property_get_bool (d, "storage.removable.media_available");
+
+ if (!media_available && !is_floppy) {
+ HAL_INFO (("media gone %s", hal_device_get_udi (d)));
+
+ volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
+ "block.storage_device", hal_device_get_udi (d));
+ for (i = volumes; i != NULL; i = g_slist_next (i)) {
+ v = HAL_DEVICE (i->data);
+ v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path");
+ HAL_INFO (("child volume %s", hal_device_get_udi (v)));
+ if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) {
+ HAL_INFO (("removing volume %s", hal_device_get_udi (v)));
+ devinfo_remove_enqueue (v_devfs_path, NULL);
+ } else {
+ HAL_INFO (("not a volume %s", hal_device_get_udi (v)));
+ }
+ }
+ g_slist_free (volumes);
+
+ hotplug_event_process_queue ();
+ } else if (is_floppy) {
+ HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d)));
+
+ hald_runner_run (d,
+ "hald-probe-storage --only-check-for-media", NULL,
+ DEVINFO_PROBE_STORAGE_TIMEOUT,
+ devinfo_floppy_rescan_probing_done,
+ NULL, NULL);
+ } else {
+ HAL_INFO (("media available %s", hal_device_get_udi (d)));
+
+ hald_runner_run (d,
+ "hald-probe-storage --only-check-for-media", NULL,
+ DEVINFO_PROBE_STORAGE_TIMEOUT,
+ devinfo_storage_rescan_probing_done,
+ NULL, NULL);
+ }
+
+ return TRUE;
+}
+
+static char *
+devinfo_volume_get_slice_name (char *devlink)
+{
+ char *part, *slice, *disk;
+ char *s = NULL;
+ char *p;
+
+ if ((p = strstr(devlink, "/lofi/")) != 0) {
+ return (p + sizeof ("/lofi/") - 1);
+ }
+
+ part = strrchr(devlink, 'p');
+ slice = strrchr(devlink, 's');
+ disk = strrchr(devlink, 'd');
+
+ if ((part != NULL) && (part > slice) && (part > disk)) {
+ s = part;
+ } else if ((slice != NULL) && (slice > disk)) {
+ s = slice;
+ } else {
+ s = disk;
+ }
+ if ((s != NULL) && isdigit(s[1])) {
+ return (s);
+ } else {
+ return ("");
+ }
+}
+
+static gboolean
+is_dos_path(char *path, int *partnum)
+{
+ char *p;
+
+ if ((p = strrchr (path, ':')) == NULL) {
+ return (FALSE);
+ }
+ return ((*partnum = atoi(p + 1)) != 0);
+}
+
+static gboolean
+dos_to_dev(char *path, char **devpath, int *partnum)
+{
+ char *p;
+
+ if ((p = strrchr (path, ':')) == NULL) {
+ return (FALSE);
+ }
+ if ((*partnum = atoi(p + 1)) == 0) {
+ return (FALSE);
+ }
+ p[0] = '\0';
+ *devpath = strdup(path);
+ p[0] = ':';
+ return (*devpath != NULL);
+}
+
+static void
+devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type,
+ gint return_code, gchar **error,
+ gpointer data1, gpointer data2)
+{
+ char *mount_point = (char *) data1;
+
+ HAL_INFO (("Cleaned up mount point '%s'", mount_point));
+ g_free (mount_point);
+}
+
+
+void
+devinfo_storage_mnttab_event (HalDevice *hal_volume)
+{
+ FILE *fp = NULL;
+ struct extmnttab m;
+ HalDevice *d;
+ unsigned int major;
+ unsigned int minor;
+ GSList *volumes = NULL;
+ GSList *v;
+ char *mount_point;
+ dbus_bool_t is_partition;
+ const char *fstype;
+ int partition_number;
+
+ if (hal_volume != NULL) {
+ volumes = g_slist_append (NULL, hal_volume);
+ } else {
+ volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
+ }
+ if (volumes == NULL) {
+ return;
+ }
+
+ if ((fp = fopen(MNTTAB, "r")) == NULL) {
+ HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno));
+ return;
+ }
+
+ while (getextmntent(fp, &m, 1) == 0) {
+ for (v = volumes; v != NULL; v = g_slist_next (v)) {
+ d = HAL_DEVICE (v->data);
+ major = hal_device_property_get_int (d, "block.major");
+ minor = hal_device_property_get_int (d, "block.minor");
+
+ /*
+ * special handling for pcfs, which encodes logical
+ * drive number into the 6 upper bits of the minor
+ */
+ is_partition = hal_device_property_get_bool (d, "volume.is_partition");
+ partition_number = hal_device_property_get_int (d, "volume.partition.number");
+ fstype = hal_device_property_get_string (d, "volume.fstype");
+
+ if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) {
+ minor |= partition_number << 12;
+ }
+
+ if (m.mnt_major != major || m.mnt_minor != minor) {
+ continue;
+ }
+
+ /* this volume matches the mnttab entry */
+ device_property_atomic_update_begin ();
+ hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
+ hal_device_property_set_bool (d, "volume.is_mounted_read_only",
+ hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE);
+ hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp);
+ device_property_atomic_update_end ();
+
+ HAL_INFO (("set %s to be mounted at %s",
+ hal_device_get_udi (d), m.mnt_mountp));
+ volumes = g_slist_delete_link (volumes, v);
+ }
+ }
+
+ /* all remaining volumes are not mounted */
+ for (v = volumes; v != NULL; v = g_slist_next (v)) {
+ d = HAL_DEVICE (v->data);
+ mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point"));
+ if (mount_point == NULL || strlen (mount_point) == 0) {
+ g_free (mount_point);
+ continue;
+ }
+
+ device_property_atomic_update_begin ();
+ hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
+ hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE);
+ hal_device_property_set_string (d, "volume.mount_point", "");
+ device_property_atomic_update_end ();
+
+ HAL_INFO (("set %s to unmounted", hal_device_get_udi (d)));
+
+ /* cleanup if was mounted by us */
+ if (hal_util_is_mounted_by_hald (mount_point)) {
+ char *cleanup_stdin;
+ char *extra_env[2];
+
+ HAL_INFO (("Cleaning up '%s'", mount_point));
+
+ extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point);
+ extra_env[1] = NULL;
+ cleanup_stdin = "\n";
+
+ hald_runner_run_method (d,
+ "hal-storage-cleanup-mountpoint",
+ extra_env,
+ cleanup_stdin, TRUE,
+ 0,
+ devinfo_storage_cleanup_mountpoint_cb,
+ g_strdup (mount_point), NULL);
+
+ g_free (extra_env[0]);
+ }
+
+ g_free (mount_point);
+ }
+ g_slist_free (volumes);
+
+ (void) fclose (fp);
+}
+
+static void
+devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type,
+ gint return_code, gchar **error,
+ gpointer data1, gpointer data2)
+{
+ void *end_token = (void *) data1;
+
+ HAL_INFO (("devinfo_volume_force_unmount_cb for udi='%s', exit_type=%d, return_code=%d", hal_device_get_udi (d), exit_type, return_code));
+
+ if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
+ error[0] != NULL && error[1] != NULL) {
+ char *exp_name = NULL;
+ char *exp_detail = NULL;
+
+ exp_name = error[0];
+ if (error[0] != NULL) {
+ exp_detail = error[1];
+ }
+ HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
+ }
+
+ hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
+}
+
+static void
+devinfo_volume_force_unmount (HalDevice *d, void *end_token)
+{
+ const char *device_file;
+ const char *mount_point;
+ char *unmount_stdin;
+ char *extra_env[2];
+ extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
+ extra_env[1] = NULL;
+
+ device_file = hal_device_property_get_string (d, "block.device");
+ mount_point = hal_device_property_get_string (d, "volume.mount_point");
+
+ if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) {
+ hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
+ return;
+ }
+
+ HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d)));
+
+ unmount_stdin = "\n";
+
+ hald_runner_run_method (d,
+ "hal-storage-unmount",
+ extra_env,
+ unmount_stdin, TRUE,
+ 0,
+ devinfo_volume_force_unmount_cb,
+ end_token, NULL);
+}
+
+void
+devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token)
+{
+ if (hal_device_property_get_bool (d, "volume.is_mounted")) {
+ devinfo_volume_force_unmount (d, end_token);
+ } else {
+ hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
+ }
+}
+
+
+enum {
+ LEGACY_CDROM,
+ LEGACY_FLOPPY,
+ LEGACY_RMDISK
+};
+
+static const char *legacy_media_str[] = {
+ "cdrom",
+ "floppy",
+ "rmdisk"
+};
+
+struct enum_nick {
+ const char *type;
+ GSList *nums;
+};
+
+static int
+devinfo_storage_get_legacy_media(HalDevice *d)
+{
+ const char *drive_type;
+
+ if (hal_device_has_capability (d, "storage.cdrom")) {
+ return (LEGACY_CDROM);
+ } else if (((drive_type = hal_device_property_get_string (d,
+ "storage.drive_type")) != NULL) && (strcmp (drive_type, "floppy") == 0)) {
+ return (LEGACY_FLOPPY);
+ } else if (hal_device_property_get_bool (d, "storage.removable") ||
+ hal_device_property_get_bool (d, "storage.hotpluggable")) {
+ return (LEGACY_RMDISK);
+ } else {
+ return (-1);
+ }
+}
+
+static gboolean
+devinfo_storage_foreach_nick (HalDeviceStore *store, HalDevice *d, gpointer user_data)
+{
+ struct enum_nick *en = (struct enum_nick *) user_data;
+ const char *media_type;
+ int media_num;
+
+ media_type = hal_device_property_get_string (d, "storage.solaris.legacy.media_type");
+ media_num = hal_device_property_get_int (d, "storage.solaris.legacy.media_num");
+ if ((media_type != NULL) && (strcmp (media_type, en->type) == 0) &&
+ (media_num >= 0)) {
+ en->nums = g_slist_prepend (en->nums, GINT_TO_POINTER(media_num));
+ }
+ return TRUE;
+}
+
+static void
+devinfo_storage_append_nickname (HalDevice *d, const char *media_type, int media_num)
+{
+ char buf[64];
+
+ if (media_num == 0) {
+ hal_device_property_strlist_append (d, "storage.solaris.nicknames", media_type);
+ }
+ snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
+ hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf);
+}
+
+static void
+devinfo_storage_set_nicknames (HalDevice *d)
+{
+ int media;
+ const char *media_type;
+ int media_num;
+ GSList *i;
+ struct enum_nick en;
+ char buf[64];
+
+ if ((media = devinfo_storage_get_legacy_media (d)) < 0) {
+ return;
+ }
+ media_type = legacy_media_str[media];
+
+ /* enumerate all storage devices of this media type */
+ en.type = media_type;
+ en.nums = NULL;
+ hal_device_store_foreach (hald_get_gdl (), devinfo_storage_foreach_nick, &en);
+
+ /* find a free number */
+ for (media_num = 0; ; media_num++) {
+ for (i = en.nums; i != NULL; i = g_slist_next (i)) {
+ if (GPOINTER_TO_INT (i->data) == media_num) {
+ break;
+ }
+ }
+ if (i == NULL) {
+ break;
+ }
+ }
+ g_slist_free (en.nums);
+
+ hal_device_property_set_string (d, "storage.solaris.legacy.media_type", media_type);
+ hal_device_property_set_int (d, "storage.solaris.legacy.media_num", media_num);
+
+ /* primary nickname, and also vold-style symdev */
+ snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
+ hal_device_property_set_string (d, "storage.solaris.legacy.symdev", buf);
+ devinfo_storage_append_nickname(d, media_type, media_num);
+
+ /* additional nicknames */
+ if (media == LEGACY_CDROM) {
+ devinfo_storage_append_nickname(d, "cd", media_num);
+ devinfo_storage_append_nickname(d, "sr", media_num);
+ } else if (media == LEGACY_FLOPPY) {
+ devinfo_storage_append_nickname(d, "fd", media_num);
+ devinfo_storage_append_nickname(d, "diskette", media_num);
+ devinfo_storage_append_nickname(d, "rdiskette", media_num);
+ }
+}
diff --git a/hald/solaris/devinfo_storage.h b/hald/solaris/devinfo_storage.h
new file mode 100644
index 0000000..ad6bb6d
--- /dev/null
+++ b/hald/solaris/devinfo_storage.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ *
+ * devinfo_storage.h : definitions for storage devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_storage.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_STORAGE_H
+#define DEVINFO_STORAGE_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_ide_handler;
+extern DevinfoDevHandler devinfo_scsi_handler;
+extern DevinfoDevHandler devinfo_floppy_handler;
+extern DevinfoDevHandler devinfo_lofi_handler;
+
+gboolean devinfo_storage_device_rescan (HalDevice *d);
+HalDevice *devinfo_lofi_add_major(HalDevice *parent, di_node_t node, char *devfs_path,
+ char *device_type, gboolean rescan, HalDevice *lofi_d);
+void devinfo_lofi_remove_minor(char *parent_devfs_path, char *name);
+void devinfo_storage_mnttab_event (HalDevice *hal_volume);
+void devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token);
+
+#endif /* DEVINFO_STORAGE_H */
diff --git a/hald/solaris/devinfo_usb.c b/hald/solaris/devinfo_usb.c
new file mode 100644
index 0000000..b3359a2
--- /dev/null
+++ b/hald/solaris/devinfo_usb.c
@@ -0,0 +1,231 @@
+/***************************************************************************
+ *
+ * devinfo_usb.h : USB devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_usb.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <libdevinfo.h>
+#include <sys/types.h>
+#include <sys/mkdev.h>
+#include <sys/stat.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "../ids.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_usb.h"
+
+HalDevice *devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
+static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, int ifnum);
+static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node, gchar *devfs_path);
+
+DevinfoDevHandler devinfo_usb_handler = {
+ devinfo_usb_add,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+};
+
+HalDevice *
+devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
+{
+ HalDevice *d, *nd = NULL;
+ char *s;
+ int *i, *vid;
+ char *driver_name, *binding_name;
+ char if_devfs_path[HAL_PATH_MAX];
+
+ /*
+ * we distinguish USB devices by presence of "usb-vendor-id"
+ * property. should USB devices have "device_type"?
+ */
+ if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", &vid) <= 0) {
+ return (NULL);
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.bus", "usb_device");
+ PROP_STR(d, node, s, "usb-product-name", "info.product");
+ PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
+ PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
+ PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
+ PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
+ PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
+ PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
+ PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
+
+ /* class, subclass */
+ /* hal_device_property_set_int (d, "usb_device.device_class", 8); */
+
+ /* binding name tells us if driver is bound to interface or device */
+ if (((binding_name = di_binding_name(node)) != NULL) &&
+ (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
+ snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
+ if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
+ d = nd;
+ nd = NULL;
+ devfs_path = if_devfs_path;
+ }
+ }
+
+ /* driver specific */
+ driver_name = di_driver_name (node);
+ if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
+ nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
+ } else {
+ devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
+ }
+
+out:
+ if (nd != NULL) {
+ return (nd);
+ } else {
+ return (d);
+ }
+}
+
+static HalDevice *
+devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
+{
+ HalDevice *d = NULL;
+ char udi[HAL_PATH_MAX];
+
+ devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, node, devfs_path);
+ hal_device_property_set_string (d, "info.bus", "usb");
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s_if%d", hal_device_get_udi (parent), ifnum);
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ hal_device_property_set_string (d, "info.product", "USB Device Interface");
+
+ /* copy parent's usb_device.* properties */
+ hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
+
+ return (d);
+}
+
+static int
+walk_devlinks(di_devlink_t devlink, void *arg)
+{
+ char **path = (char **)arg;
+
+ *path = strdup(di_devlink_path(devlink));
+
+ return (DI_WALK_TERMINATE);
+}
+
+static char *
+get_devlink(di_devlink_handle_t devlink_hdl, char *path)
+{
+ char *devlink = NULL;
+
+ (void) di_devlink_walk(devlink_hdl, NULL, path,
+ DI_PRIMARY_LINK, &devlink, walk_devlinks);
+
+ return (devlink);
+}
+
+static HalDevice *
+devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
+{
+ HalDevice *d = NULL;
+ di_devlink_handle_t devlink_hdl;
+ int major;
+ di_minor_t minor;
+ dev_t devt;
+ char *minor_path = NULL;
+ char *devlink = NULL;
+ char udi[HAL_PATH_MAX];
+
+ devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
+
+ if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
+ printf("di_devlink_init() failed\n");
+ return (NULL);
+ }
+
+ major = di_driver_major(node);
+ minor = DI_MINOR_NIL;
+ while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
+ devt = di_minor_devt(minor);
+ if (major != major(devt)) {
+ continue;
+ }
+ if ((minor_path = di_devfs_minor_path(minor)) == NULL) {
+ continue;
+ }
+ if (di_minor_type(minor) != DDM_MINOR) {
+ continue;
+ }
+ if (strcmp (di_minor_nodetype(minor),
+ "ddi_ctl:devctl:scsi") == 0) {
+ devlink = get_devlink(devlink_hdl, minor_path);
+ if (devlink == NULL) {
+ devlink = strdup("");
+ }
+ break;
+ }
+ di_devfs_path_free (minor_path);
+ minor_path = NULL;
+ }
+
+ di_devlink_fini (&devlink_hdl);
+
+ if (devlink == NULL) {
+ goto out;
+ }
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, usbd, node, minor_path);
+ hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
+ hal_device_property_set_string (d, "info.category", "scsi_host");
+ hal_device_property_set_int (d, "scsi_host.host", 0);
+
+ hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
+ "%s/scsi_host%d", hal_device_get_udi (usbd),
+ hal_device_property_get_int (d, "scsi_host.host"));
+ hal_device_set_udi (d, udi);
+ hal_device_property_set_string (d, "info.udi", udi);
+ hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
+
+ devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
+
+out:
+ if (devlink) {
+ free(devlink);
+ }
+ if (minor_path) {
+ di_devfs_path_free (minor_path);
+ }
+
+ return (d);
+}
+
diff --git a/hald/solaris/devinfo_usb.h b/hald/solaris/devinfo_usb.h
new file mode 100644
index 0000000..8eed9f1
--- /dev/null
+++ b/hald/solaris/devinfo_usb.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * devinfo_usb.h : definitions for USB devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)devinfo_usb.h 1.2 06/10/13 SMI"
+
+#ifndef DEVINFO_USB_H
+#define DEVINFO_USB_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_usb_handler;
+
+#endif /* DEVINFO_USB_H */
diff --git a/hald/solaris/hal.xml b/hald/solaris/hal.xml
new file mode 100644
index 0000000..4221eb5
--- /dev/null
+++ b/hald/solaris/hal.xml
@@ -0,0 +1,89 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+ Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ Use is subject to license terms.
+
+ Licensed under the Academic Free License version 2.1
+
+ ident "@(#)hal.xml 1.1 06/10/10 SMI"
+
+ NOTE: This service manifest is not editable; its contents will
+ be overwritten by package or patch operations, including
+ operating system upgrade. Make customizations in a different
+ file.
+
+ Service manifest for HAL.
+-->
+
+<service_bundle type='manifest' name='SUNWhalr:hal'>
+
+<service
+ name='system/hal'
+ type='service'
+ version='1'>
+
+ <create_default_instance enabled='false' />
+
+ <single_instance />
+
+ <dependency name='usr'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/filesystem/local' />
+ </dependency>
+
+ <dependency
+ name='devices'
+ grouping='require_all'
+ restart_on='none'
+ type='service'>
+ <service_fmri value='svc:/system/device/local' />
+ </dependency>
+
+ <dependency name='dbus'
+ type='service'
+ grouping='require_all'
+ restart_on='none'>
+ <service_fmri value='svc:/system/dbus' />
+ </dependency>
+
+ <exec_method
+ type='method'
+ name='start'
+ exec='/lib/svc/method/svc-hal start'
+ timeout_seconds='600'>
+ <method_context>
+ <method_credential user='root' group='root' />
+ </method_context>
+ </exec_method>
+
+ <exec_method
+ type='method'
+ name='stop'
+ exec=':kill'
+ timeout_seconds='30' />
+
+ <property_group name='startd' type='framework'>
+ <!-- sub-process core dumps shouldn't restart session -->
+ <propval name='ignore_error' type='astring'
+ value='core,signal' />
+ </property_group>
+
+ <stability value='Unstable' />
+
+ <template>
+ <common_name>
+ <loctext xml:lang='C'>
+ Hardware Abstraction Layer daemon
+ </loctext>
+ </common_name>
+ <documentation>
+ <manpage title='hal' section='1M' manpath='/usr/man' />
+ </documentation>
+ </template>
+
+</service>
+
+</service_bundle>
diff --git a/hald/solaris/hotplug.c b/hald/solaris/hotplug.c
new file mode 100644
index 0000000..edb1e18
--- /dev/null
+++ b/hald/solaris/hotplug.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+ *
+ * hotplug.c : HAL-internal hotplug events
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)hotplug.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/un.h>
+#include <sys/utsname.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../device_info.h"
+
+#include "osspec_solaris.h"
+#include "hotplug.h"
+#include "devinfo.h"
+
+/** Queue of ordered hotplug events */
+GQueue *hotplug_event_queue;
+
+/** List of HotplugEvent objects we are currently processing */
+GSList *hotplug_events_in_progress = NULL;
+
+static void hotplug_event_begin (HotplugEvent *hotplug_event);
+
+void
+hotplug_event_end (void *end_token)
+{
+ HotplugEvent *hotplug_event = (HotplugEvent *) end_token;
+
+ hotplug_events_in_progress = g_slist_remove (hotplug_events_in_progress, hotplug_event);
+ g_free (hotplug_event);
+ hotplug_event_process_queue ();
+}
+
+static void
+hotplug_event_begin_devfs_add (HotplugEvent *hotplug_event, HalDevice *d)
+{
+ HalDevice *parent;
+ const gchar *parent_udi;
+ void (*begin_add_func) (HalDevice *, HalDevice *, DevinfoDevHandler *, void *);
+
+ if (d != NULL) {
+ /* XXX */
+ HAL_ERROR (("devpath %s already present in store, ignore event", hotplug_event->un.devfs.devfs_path));
+ hotplug_event_end ((void *) hotplug_event);
+ return;
+ }
+
+ /* find parent */
+ parent_udi = hal_device_property_get_string (hotplug_event->d, "info.parent");
+ if (parent_udi == NULL || strlen(parent_udi) == 0) {
+ parent = NULL;
+ } else {
+ parent = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", parent_udi);
+ }
+ /* only root node is allowed to be orphan */
+ if (parent == NULL) {
+ if (strcmp(hotplug_event->un.devfs.devfs_path, "/") != 0) {
+ HAL_ERROR (("Parent is NULL devfs_path=%s parent_udi=%s", hotplug_event->un.devfs.devfs_path, parent_udi ? parent_udi : "<null>"));
+ hotplug_event_end ((void *) hotplug_event);
+ return;
+ }
+ }
+
+ /* children of ignored parent should be ignored */
+ if (hal_device_property_get_bool (parent, "info.ignore")) {
+ HAL_INFO (("parent ignored %s", parent_udi));
+ hotplug_event_end ((void *) hotplug_event);
+ return;
+ }
+
+ /* custom or generic add function */
+ begin_add_func = hotplug_event->un.devfs.handler->hotplug_begin_add;
+ if (begin_add_func == NULL) {
+ begin_add_func = hotplug_event_begin_add_devinfo;
+ }
+ begin_add_func (hotplug_event->d,
+ parent,
+ hotplug_event->un.devfs.handler,
+ (void *) hotplug_event);
+}
+
+static void
+hotplug_event_begin_devfs_remove (HotplugEvent *hotplug_event, HalDevice *d)
+{
+ if (d == NULL) {
+ HAL_ERROR (("devpath %s not present in store, ignore event", hotplug_event->un.devfs.devfs_path));
+ hotplug_event_end ((void *) hotplug_event);
+ return;
+ }
+ HAL_INFO (("hotplug_event_begin_devfs_remove %s", hal_device_get_udi (d)));
+
+ hotplug_event_begin_remove_devinfo(d,
+ hotplug_event->un.devfs.devfs_path,
+ (void *) hotplug_event);
+}
+
+static void
+hotplug_event_begin_devfs (HotplugEvent *hotplug_event)
+{
+ HalDevice *d;
+
+ HAL_INFO (("hotplug_event_begin_devfs: %s", hotplug_event->un.devfs.devfs_path));
+ d = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path",
+ hotplug_event->un.devfs.devfs_path);
+
+ if (hotplug_event->action == HOTPLUG_ACTION_ADD) {
+ hotplug_event_begin_devfs_add (hotplug_event, d);
+ } else if (hotplug_event->action == HOTPLUG_ACTION_REMOVE) {
+ hotplug_event_begin_devfs_remove (hotplug_event, d);
+ } else {
+ hotplug_event_end ((void *) hotplug_event);
+ }
+}
+
+static void
+hotplug_event_begin (HotplugEvent *hotplug_event)
+{
+ switch (hotplug_event->type) {
+
+ case HOTPLUG_EVENT_DEVFS:
+ hotplug_event_begin_devfs (hotplug_event);
+ break;
+
+ default:
+ HAL_ERROR (("Unknown hotplug event type %d", hotplug_event->type));
+ hotplug_event_end ((void *) hotplug_event);
+ break;
+ }
+}
+
+void
+hotplug_event_enqueue (HotplugEvent *hotplug_event, int front)
+{
+ if (hotplug_event_queue == NULL)
+ hotplug_event_queue = g_queue_new ();
+
+ if (front) {
+ g_queue_push_head (hotplug_event_queue, hotplug_event);
+ } else {
+ g_queue_push_tail (hotplug_event_queue, hotplug_event);
+ }
+}
+
+void
+hotplug_event_process_queue (void)
+{
+ HotplugEvent *hotplug_event;
+
+ if (hotplug_events_in_progress == NULL &&
+ (hotplug_event_queue == NULL || g_queue_is_empty (hotplug_event_queue))) {
+ hotplug_queue_now_empty ();
+ goto out;
+ }
+
+ /* do not process events if some other event is in progress */
+ if (hotplug_events_in_progress != NULL && g_slist_length (hotplug_events_in_progress) > 0)
+ goto out;
+
+ hotplug_event = g_queue_pop_head (hotplug_event_queue);
+ if (hotplug_event == NULL)
+ goto out;
+
+ hotplug_events_in_progress = g_slist_append (hotplug_events_in_progress, hotplug_event);
+ hotplug_event_begin (hotplug_event);
+
+out:
+ ;
+}
diff --git a/hald/solaris/hotplug.h b/hald/solaris/hotplug.h
new file mode 100644
index 0000000..724735e
--- /dev/null
+++ b/hald/solaris/hotplug.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+ *
+ * hotplug.h : definitions for HAL-internal hotplug events
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)hotplug.h 1.2 06/10/13 SMI"
+
+#ifndef HOTPLUG_H
+#define HOTPLUG_H
+
+#include <glib.h>
+
+#include "../device.h"
+#include "../util.h"
+
+#include "devinfo.h"
+
+typedef enum {
+ HOTPLUG_ACTION_ADD,
+ HOTPLUG_ACTION_REMOVE,
+} HotplugActionType;
+
+typedef enum {
+ HOTPLUG_EVENT_DEVFS = 0,
+} HotplugEventType;
+
+/** Data structure representing a hotplug event; also used for
+ * coldplugging.
+ */
+typedef struct
+{
+ HotplugActionType action; /**< Whether the event is add or remove */
+ HotplugEventType type; /**< Type of hotplug event */
+
+ HalDevice *d;
+
+ union {
+ struct {
+ char devfs_path[HAL_PATH_MAX];
+ DevinfoDevHandler *handler;
+ } devfs;
+ } un;
+
+} HotplugEvent;
+
+void hotplug_event_enqueue (HotplugEvent *event, int front);
+
+void hotplug_event_process_queue (void);
+
+void hotplug_event_end (void *end_token);
+
+void hotplug_queue_now_empty (void);
+
+#endif /* HOTPLUG_H */
diff --git a/hald/solaris/osspec.c b/hald/solaris/osspec.c
index d694667..f5903f3 100644
--- a/hald/solaris/osspec.c
+++ b/hald/solaris/osspec.c
@@ -1,53 +1,76 @@
/***************************************************************************
- * CVSID: $Id$
*
- * osspec.c : HAL backend for Solaris
+ * osspec.c : Solaris HAL backend entry points
*
- * Copyright (C) 2005 Sun Microsystems
- * Author: Alvaro Lopez Ortega <alvaro at sun.com>
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
*
- * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ * Licensed under the Academic Free License version 2.1
*
**************************************************************************/
+#pragma ident "@(#)osspec.c 1.2 06/10/13 SMI"
+
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <port.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mntent.h>
+#include <sys/mnttab.h>
+
#include "../osspec.h"
#include "../logger.h"
#include "../hald.h"
#include "../hald_dbus.h"
#include "../device_info.h"
#include "../util.h"
+#include "../ids.h"
+#include "osspec_solaris.h"
+#include "hotplug.h"
+#include "sysevent.h"
+#include "devinfo.h"
+#include "devinfo_storage.h"
+static void mnttab_event_init ();
+static gboolean mnttab_event (GIOChannel *channel, GIOCondition cond, gpointer user_data);
void
osspec_init (void)
{
+ ids_init ();
+ sysevent_init ();
+ mnttab_event_init ();
+}
+
+void
+hotplug_queue_now_empty (void)
+{
+ if (hald_is_initialising) {
+ osspec_probe_done ();
+ }
}
void
osspec_probe (void)
{
+ /* add entire device tree */
+ devinfo_add (NULL, "/");
+
+ /* start processing events */
+ hotplug_event_process_queue ();
}
gboolean
osspec_device_rescan (HalDevice *d)
{
- return FALSE;
+ return (devinfo_device_rescan (d));
}
gboolean
@@ -62,3 +85,151 @@ osspec_filter_function (DBusConnection *
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
}
+/** Find the closest ancestor by looking at devfs paths
+ *
+ * @param devfs_path Path into devfs, e.g. /pci at 0,0/pci1025,57 at 10,2/storage at 1
+ * @return Parent Hal Device Object or #NULL if there is none
+ */
+HalDevice *
+hal_util_find_closest_ancestor (const gchar *devfs_path, gchar **ancestor_devfs_path, gchar **hotplug_devfs_path)
+{
+ gchar buf[512];
+ gchar c;
+ HalDevice *parent;
+
+ parent = NULL;
+
+ strncpy (buf, devfs_path, sizeof (buf));
+ do {
+ char *p;
+
+ p = strrchr (buf, '/');
+ if (p == NULL)
+ break;
+ c = *p;
+ *p = '\0';
+
+ parent = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path",
+ buf);
+ if (parent != NULL) {
+ if (ancestor_devfs_path != NULL) {
+ *ancestor_devfs_path = g_strdup (buf);
+ }
+ if (hotplug_devfs_path != NULL) {
+ *p = c;
+ *hotplug_devfs_path = g_strdup (buf);
+ }
+ break;
+ }
+
+ } while (TRUE);
+
+ return parent;
+}
+
+char *
+dsk_to_rdsk(char *dsk)
+{
+ int len, pos;
+ char *p;
+ char *rdsk;
+
+ if ((len = strlen (dsk)) < sizeof ("/dev/dsk/cN") - 1) {
+ return (strdup(""));
+ }
+ if ((p = strstr (dsk, "/dsk/")) == NULL) {
+ if ((p = strstr (dsk, "/lofi/")) == NULL) {
+ p = strstr (dsk, "/diskette");
+ }
+ }
+ if (p == NULL) {
+ return (strdup(""));
+ }
+
+ pos = (uintptr_t)p - (uintptr_t)dsk;
+ if ((rdsk = (char *)calloc (len + 2, 1)) != NULL) {
+ strncpy (rdsk, dsk, pos + 1);
+ rdsk[pos + 1] = 'r';
+ strcpy (rdsk + pos + 2, dsk + pos + 1);
+ }
+
+ return (rdsk);
+}
+
+/*
+ * Setup to watch mnttab changes
+ *
+ * When mnttab changes, POLLRDBAND is set. However, glib does not
+ * support POLLRDBAND, so we use Solaris ports (see port_create(3C))
+ * to "map" POLLRDBAND to POLLIN:
+ *
+ * - create a port
+ * - associate the port with mnttab file descriptor and POLLRDBAND
+ * - now polling for POLLIN on the port descriptor will unblock when
+ * the associated file descriptor receives POLLRDBAND
+ */
+static int mnttab_fd;
+static int mnttab_port;
+static GIOChannel *mnttab_channel;
+
+static void
+mnttab_event_init ()
+{
+ char buf[81];
+
+ if ((mnttab_fd = open (MNTTAB, O_RDONLY)) < 0) {
+ return;
+ }
+ if ((mnttab_port = port_create ()) < 0) {
+ (void) close (mnttab_fd);
+ return;
+ }
+ if (port_associate (mnttab_port, PORT_SOURCE_FD, mnttab_fd, POLLRDBAND,
+ NULL) != 0) {
+ (void) close (mnttab_port);
+ (void) close (mnttab_fd);
+ return;
+ }
+
+ /* suppress initial event */
+ (void) read(mnttab_fd, buf, (size_t)(sizeof (buf) - 1));
+ (void) lseek(mnttab_fd, 0, SEEK_SET);
+
+ mnttab_channel = g_io_channel_unix_new (mnttab_port);
+ g_io_add_watch (mnttab_channel, G_IO_IN, mnttab_event, NULL);
+}
+
+static gboolean
+mnttab_event (GIOChannel *channel, GIOCondition cond, gpointer user_data)
+{
+ port_event_t pe;
+ timespec_t timeout;
+ char buf[81];
+
+ /* if (cond & ~G_IO_ERR)
+ return TRUE;
+ */
+ HAL_INFO (("mnttab event"));
+
+ /* we have to re-associate port with fd every time */
+ timeout.tv_sec = timeout.tv_nsec = 0;
+ (void) port_get(mnttab_port, &pe, &timeout);
+ (void) port_associate(mnttab_port, PORT_SOURCE_FD,
+ mnttab_fd, POLLRDBAND, NULL);
+
+ if (!hald_is_initialising) {
+ devinfo_storage_mnttab_event (NULL);
+ }
+
+ (void) lseek(mnttab_fd, 0, SEEK_SET);
+ (void) read(mnttab_fd, buf, (size_t)(sizeof (buf) - 1));
+
+ return TRUE;
+}
+
+void
+osspec_refresh_mount_state_for_block_device (HalDevice *d)
+{
+ devinfo_storage_mnttab_event (d);
+}
diff --git a/hald/solaris/osspec_solaris.h b/hald/solaris/osspec_solaris.h
new file mode 100644
index 0000000..ce7436c
--- /dev/null
+++ b/hald/solaris/osspec_solaris.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ *
+ * osspec_solaris.h : definitions for Solaris HAL backend
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)osspec_solaris.h 1.2 06/10/13 SMI"
+
+#ifndef OSSPEC_SOLARIS_H
+#define OSSPEC_SOLARIS_H
+
+#include <glib.h>
+
+void hotplug_queue_now_empty (void);
+HalDevice *hal_util_find_closest_ancestor (const gchar *devfs_path, gchar **ancestor_devfs_path, gchar **hotplug_devfs_path);
+char *dsk_to_rdsk(char *);
+
+#endif /* OSSPEC_SOLARIS_H */
diff --git a/hald/solaris/probing/Makefile.am b/hald/solaris/probing/Makefile.am
new file mode 100644
index 0000000..b3c94ff
--- /dev/null
+++ b/hald/solaris/probing/Makefile.am
@@ -0,0 +1,22 @@
+
+INCLUDES = \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(prefix)/$(DATADIRNAME)/locale"\" \
+ -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
+ -I$(top_srcdir) -I$(top_srcdir)/hald -I$(top_srcdir)/libhal -I$(top_srcdir)/libhal-storage \
+ @GLIB_CFLAGS@ @DBUS_CFLAGS@
+
+if HALD_COMPILE_SOLARIS
+libexec_PROGRAMS = hald-probe-storage hald-probe-volume
+endif
+
+hald_probe_storage_SOURCES = probe-storage.c cdutils.c cdutils.h fsutils.c fsutils.h ../../logger.c
+hald_probe_storage_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ -ladm -lefi
+hald_probe_storage_CFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
+hald_probe_volume_SOURCES = probe-volume.c cdutils.c cdutils.h fsutils.c fsutils.h ../../logger.c
+hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ -lfstyp -lnvpair -ladm -lefi
+hald_probe_volume_CFLAGS = -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64
+
diff --git a/hald/solaris/probing/cdutils.c b/hald/solaris/probing/cdutils.c
new file mode 100644
index 0000000..8ea0c45
--- /dev/null
+++ b/hald/solaris/probing/cdutils.c
@@ -0,0 +1,484 @@
+/***************************************************************************
+ *
+ * cdutils.h : CD/DVD utilities
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)cdutils.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <string.h>
+#include <strings.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/dkio.h>
+#include <libintl.h>
+
+#include <logger.h>
+
+#include "cdutils.h"
+
+#define RQLEN 32
+#define SENSE_KEY(rqbuf) (rqbuf[2]) /* scsi error category */
+#define ASC(rqbuf) (rqbuf[12]) /* additional sense code */
+#define ASCQ(rqbuf) (rqbuf[13]) /* ASC qualifier */
+
+#define GET16(a) (((a)[0] << 8) | (a)[1])
+#define GET32(a) (((a)[0] << 24) | ((a)[1] << 16) | ((a)[2] << 8) | (a)[3])
+
+#define CD_USCSI_TIMEOUT 60
+
+void
+uscsi_cmd_init(struct uscsi_cmd *scmd, char *cdb, int cdblen)
+{
+ bzero(scmd, sizeof (*scmd));
+ bzero(cdb, cdblen);
+ scmd->uscsi_cdb = cdb;
+}
+
+int
+uscsi(int fd, struct uscsi_cmd *scmd)
+{
+ char rqbuf[RQLEN];
+ int ret;
+ int i, retries, total_retries;
+ int max_retries = 20;
+
+ scmd->uscsi_flags |= USCSI_RQENABLE;
+ scmd->uscsi_rqlen = RQLEN;
+ scmd->uscsi_rqbuf = rqbuf;
+
+ for (retries = 0; retries < max_retries; retries++) {
+ scmd->uscsi_status = 0;
+ memset(rqbuf, 0, RQLEN);
+
+ ret = ioctl(fd, USCSICMD, scmd);
+
+ if ((ret == 0) && (scmd->uscsi_status == 2)) {
+ ret = -1;
+ errno = EIO;
+ }
+ if ((ret < 0) && (scmd->uscsi_status == 2)) {
+ /*
+ * The drive is not ready to recieve commands but
+ * may be in the process of becoming ready.
+ * sleep for a short time then retry command.
+ * SENSE/ASC = 2/4 : not ready
+ * ASCQ = 0 Not Reportable.
+ * ASCQ = 1 Becoming ready.
+ * ASCQ = 4 FORMAT in progress.
+ * ASCQ = 7 Operation in progress.
+ */
+ if ((SENSE_KEY(rqbuf) == 2) && (ASC(rqbuf) == 4) &&
+ ((ASCQ(rqbuf) == 0) || (ASCQ(rqbuf) == 1) ||
+ (ASCQ(rqbuf) == 4)) || (ASCQ(rqbuf) == 7)) {
+ total_retries++;
+ sleep(1);
+ continue;
+ }
+
+ /*
+ * Device is not ready to transmit or a device reset
+ * has occurred. wait for a short period of time then
+ * retry the command.
+ */
+ if ((SENSE_KEY(rqbuf) == 6) && ((ASC(rqbuf) == 0x28) ||
+ (ASC(rqbuf) == 0x29))) {
+ sleep(1);
+ total_retries++;
+ continue;
+ }
+ /*
+ * Blank Sense, we don't know what the error is or if
+ * the command succeeded, Hope for the best. Some
+ * drives return blank sense periodically and will
+ * fail if this is removed.
+ */
+ if ((SENSE_KEY(rqbuf) == 0) && (ASC(rqbuf) == 0) &&
+ (ASCQ(rqbuf) == 0)) {
+ ret = 0;
+ break;
+ }
+
+ HAL_DEBUG (("cmd: 0x%02x ret:%i status:%02x "
+ " sense: %02x ASC: %02x ASCQ:%02x\n",
+ (uchar_t)scmd->uscsi_cdb[0], ret,
+ scmd->uscsi_status,
+ (uchar_t)SENSE_KEY(rqbuf),
+ (uchar_t)ASC(rqbuf), (uchar_t)ASCQ(rqbuf)));
+ }
+
+ break;
+ }
+
+ if (retries) {
+ HAL_DEBUG (("total retries: %d\n", total_retries));
+ }
+
+ return (ret);
+}
+
+int
+mode_sense(int fd, uchar_t pc, int dbd, int page_len, uchar_t *buffer)
+{
+ struct uscsi_cmd scmd;
+ char cdb[16];
+
+ uscsi_cmd_init(&scmd, cdb, sizeof (cdb));
+ scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd.uscsi_buflen = page_len;
+ scmd.uscsi_bufaddr = (char *)buffer;
+ scmd.uscsi_timeout = CD_USCSI_TIMEOUT;
+ scmd.uscsi_cdblen = 0xa;
+ scmd.uscsi_cdb[0] = 0x5a; /* MODE SENSE 10 */
+ if (dbd) {
+ scmd.uscsi_cdb[1] = 0x8; /* no block descriptors */
+ }
+ scmd.uscsi_cdb[2] = pc;
+ scmd.uscsi_cdb[7] = (page_len >> 8) & 0xff;
+ scmd.uscsi_cdb[8] = page_len & 0xff;
+
+ return (uscsi(fd, &scmd) == 0);
+}
+
+/*
+ * will get the mode page only i.e. will strip off the header.
+ */
+int
+get_mode_page(int fd, int page_no, int pc, int buf_len, uchar_t *buffer, int *plen)
+{
+ int ret;
+ uchar_t byte2;
+ uchar_t buf[256];
+ uint_t header_len, page_len, copy_cnt;
+
+ byte2 = (uchar_t)(((pc << 6) & 0xC0) | (page_no & 0x3f));
+
+ /* Ask 254 bytes only to make our IDE driver happy */
+ if ((ret = mode_sense(fd, byte2, 1, 254, buf)) == 0) {
+ return (0);
+ }
+
+ header_len = 8 + GET16(&buf[6]);
+ page_len = buf[header_len + 1] + 2;
+
+ copy_cnt = (page_len > buf_len) ? buf_len : page_len;
+ (void) memcpy(buffer, &buf[header_len], copy_cnt);
+
+ if (plen) {
+ *plen = page_len;
+ }
+
+ return (1);
+}
+
+/* Get information about the Logical Unit's capabilities */
+int
+get_configuration(int fd, uint16_t feature, int bufsize, uchar_t *buf)
+{
+ struct uscsi_cmd scmd;
+ char cdb[16];
+
+ uscsi_cmd_init(&scmd, cdb, sizeof (cdb));
+ scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd.uscsi_timeout = CD_USCSI_TIMEOUT;
+ scmd.uscsi_cdb[0] = 0x46; /* GET CONFIGURATION */
+ scmd.uscsi_cdb[1] = 0x2; /* request type */
+ scmd.uscsi_cdb[2] = (feature >> 8) & 0xff; /* starting feature # */
+ scmd.uscsi_cdb[3] = feature & 0xff;
+ scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
+ scmd.uscsi_cdb[8] = bufsize & 0xff;
+ scmd.uscsi_cdblen = 10;
+ scmd.uscsi_bufaddr = (char *)buf;
+ scmd.uscsi_buflen = bufsize;
+
+ return (uscsi(fd, &scmd) == 0);
+}
+
+boolean_t
+get_current_profile(int fd, int *profile)
+{
+ size_t i;
+ uchar_t smallbuf[4];
+ size_t buflen;
+ uchar_t *bufp;
+ int ret = B_FALSE;
+
+ /* first determine amount of memory needed to hold all profiles */
+ if (get_configuration(fd, 0, 4, &smallbuf[0])) {
+ buflen = GET32(smallbuf) + 4;
+ bufp = (uchar_t *)malloc(buflen);
+
+ /* now get all profiles */
+ if (get_configuration(fd, 0, buflen, bufp)) {
+ *profile = GET16(&bufp[6]);
+ ret = B_TRUE;
+ }
+ free(bufp);
+ }
+
+ return (ret);
+}
+
+void
+walk_profiles(int fd, int (*f)(void *, int, boolean_t), void *arg)
+{
+ size_t i;
+ uint16_t profile, current_profile;
+ uchar_t smallbuf[4];
+ size_t buflen;
+ uchar_t *bufp;
+ int ret;
+
+ /* first determine amount of memory needed to hold all profiles */
+ if (get_configuration(fd, 0, 4, &smallbuf[0])) {
+ buflen = GET32(smallbuf) + 4;
+ bufp = (uchar_t *)malloc(buflen);
+
+ /* now get all profiles */
+ if (get_configuration(fd, 0, buflen, bufp)) {
+ current_profile = GET16(&bufp[6]);
+ for (i = 8 + 4; i < buflen; i += 4) {
+ profile = GET16(&bufp[i]);
+ ret = f(arg, profile, (profile == current_profile));
+ if (ret == CDUTIL_WALK_STOP) {
+ break;
+ }
+ }
+ }
+
+ free(bufp);
+ }
+}
+
+/* retrieve speed list from the Write Speed Performance Descriptor Blocks
+ */
+void
+get_write_speeds(uchar_t *page, int n, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
+{
+ uchar_t *p = page + 2;
+ int i;
+ intlist_t **nextp;
+ intlist_t *current;
+ boolean_t skip;
+
+ *n_speeds = 0;
+ *speeds = NULL;
+ *speeds_mem = (intlist_t *)calloc(n, sizeof (intlist_t));
+ if (*speeds_mem == NULL) {
+ return;
+ }
+
+ for (i = 0; i < n; i++, p += 4) {
+ current = &(*speeds_mem)[i];
+ current->val = GET16(p);
+
+ /* keep the list sorted */
+ skip = B_FALSE;
+ for (nextp = speeds; *nextp != NULL; nextp = &((*nextp)->next)) {
+ if (current->val == (*nextp)->val) {
+ skip = B_TRUE; /* skip duplicates */
+ break;
+ } else if (current->val > (*nextp)->val) {
+ break;
+ }
+ }
+ if (!skip) {
+ current->next = *nextp;
+ *nextp = current;
+ *n_speeds++;
+ }
+ }
+}
+
+void
+get_read_write_speeds(int fd, int *read_speed, int *write_speed,
+ intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
+{
+ int page_len;
+ uchar_t p[254];
+ int n; /* number of write speed performance descriptor blocks */
+
+ *read_speed = *write_speed = 0;
+ *speeds = *speeds_mem = NULL;
+
+ if (!get_mode_page(fd, 0x2A, 0, sizeof (p), p, &page_len)) {
+ return;
+ }
+
+ if (page_len > 8) {
+ *read_speed = GET16(&p[8]);
+ }
+ if (page_len > 18) {
+ *write_speed = GET16(&p[18]);
+ }
+ if (page_len < 28) {
+ printf("MMC-2\n");
+ return;
+ } else {
+ printf("MMC-3\n");
+ }
+
+ *write_speed = GET16(&p[28]);
+
+ if (page_len < 30) {
+ return;
+ }
+
+ /* retrieve speed list */
+ n = GET16(&p[30]);
+ n = min(n, (sizeof (p) - 32) / 4);
+
+ get_write_speeds(&p[32], n, speeds, n_speeds, speeds_mem);
+
+ if (*speeds != NULL) {
+ *write_speed = max(*write_speed, (*speeds)[0].val);
+ }
+}
+
+boolean_t
+get_disc_info(int fd, disc_info_t *di)
+{
+ struct uscsi_cmd scmd;
+ char cdb[16];
+ uint8_t buf[32];
+ int bufsize = sizeof (buf);
+
+ bzero(buf, bufsize);
+ uscsi_cmd_init(&scmd, cdb, sizeof (cdb));
+ scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd.uscsi_timeout = CD_USCSI_TIMEOUT;
+ scmd.uscsi_cdb[0] = 0x51; /* READ DISC INFORMATION */
+ scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
+ scmd.uscsi_cdb[8] = bufsize & 0xff;
+ scmd.uscsi_cdblen = 10;
+ scmd.uscsi_bufaddr = (char *)buf;
+ scmd.uscsi_buflen = bufsize;
+
+ if ((uscsi(fd, &scmd)) != 0) {
+ return (B_FALSE);
+ }
+
+ di->disc_status = buf[2] & 0x03;
+ di->erasable = buf[2] & 0x10;
+ if ((buf[21] != 0) && (buf[21] != 0xff)) {
+ di->capacity = ((buf[21] * 60) + buf[22]) * 75;
+ } else {
+ di->capacity = 0;
+ }
+
+ return (B_TRUE);
+}
+
+/*
+ * returns current/maximum format capacity in bytes
+ */
+boolean_t
+read_format_capacity(int fd, uint64_t *capacity)
+{
+ struct uscsi_cmd scmd;
+ char cdb[16];
+ uint8_t buf[32];
+ int bufsize = sizeof (buf);
+ uint32_t num_blocks;
+ uint32_t block_len;
+
+ bzero(buf, bufsize);
+ uscsi_cmd_init(&scmd, cdb, sizeof (cdb));
+ scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd.uscsi_timeout = CD_USCSI_TIMEOUT;
+ scmd.uscsi_cdb[0] = 0x23; /* READ FORMAT CAPACITIRES */
+ scmd.uscsi_cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
+ scmd.uscsi_cdb[8] = bufsize & 0xff;
+ scmd.uscsi_cdblen = 12;
+ scmd.uscsi_bufaddr = (char *)buf;
+ scmd.uscsi_buflen = bufsize;
+
+ if ((uscsi(fd, &scmd)) != 0) {
+ return (B_FALSE);
+ }
+
+ num_blocks = (uint32_t)(buf[4] << 24) + (buf[5] << 16) + (buf[6] << 8) + buf[7];
+ block_len = (uint32_t)(buf[9] << 16) + (buf[10] << 8) + buf[11];
+ *capacity = (uint64_t)num_blocks * block_len;
+
+ return (B_TRUE);
+}
+
+boolean_t
+get_media_info(int fd, struct dk_minfo *minfop)
+{
+ return (ioctl(fd, DKIOCGMEDIAINFO, minfop) != -1);
+}
+
+/*
+ * given current profile, use the best method for determining
+ * disc capacity (in bytes)
+ */
+boolean_t
+get_disc_capacity_for_profile(int fd, int profile, uint64_t *capacity)
+{
+ struct dk_minfo mi;
+ disc_info_t di;
+ boolean_t ret = B_FALSE;
+
+ switch (profile) {
+ case 0x08: /* CD-ROM */
+ case 0x10: /* DVD-ROM */
+ if (get_media_info(fd, &mi) && (mi.dki_capacity > 1)) {
+ *capacity = mi.dki_capacity * mi.dki_lbsize;
+ ret = B_TRUE;
+ }
+ break;
+ default:
+ if (read_format_capacity(fd, capacity) && (*capacity > 0)) {
+ ret = B_TRUE;
+ } else if (get_disc_info(fd, &di) && (di.capacity > 0)) {
+ if (get_media_info(fd, &mi)) {
+ *capacity = di.capacity * mi.dki_lbsize;
+ ret = B_TRUE;
+ }
+ }
+ }
+
+ return (ret);
+}
+
+boolean_t
+read_toc(int fd, int format, int trackno, int buflen, uchar_t *buf)
+{
+ struct uscsi_cmd scmd;
+ char cdb[16];
+
+ bzero(buf, buflen);
+ uscsi_cmd_init(&scmd, cdb, sizeof (cdb));
+ scmd.uscsi_flags = USCSI_READ|USCSI_SILENT;
+ scmd.uscsi_timeout = CD_USCSI_TIMEOUT;
+ scmd.uscsi_cdb[0] = 0x43 /* READ_TOC_CMD */;
+ scmd.uscsi_cdb[2] = format & 0xf;
+ scmd.uscsi_cdb[6] = trackno;
+ scmd.uscsi_cdb[8] = buflen & 0xff;
+ scmd.uscsi_cdb[7] = (buflen >> 8) & 0xff;
+ scmd.uscsi_cdblen = 10;
+ scmd.uscsi_bufaddr = (char *)buf;
+ scmd.uscsi_buflen = buflen;
+
+ if ((uscsi(fd, &scmd)) != 0) {
+ return (B_FALSE);
+ }
+
+ return (B_TRUE);
+}
diff --git a/hald/solaris/probing/cdutils.h b/hald/solaris/probing/cdutils.h
new file mode 100644
index 0000000..678e26d
--- /dev/null
+++ b/hald/solaris/probing/cdutils.h
@@ -0,0 +1,61 @@
+/***************************************************************************
+ *
+ * cdutils.h : definitions for CD/DVD utilities
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)cdutils.h 1.2 06/10/13 SMI"
+
+#ifndef CDUTILS_H
+#define CDUTILS_H
+
+#include <sys/types.h>
+#include <sys/dkio.h>
+#include <sys/cdio.h>
+#include <sys/scsi/impl/uscsi.h>
+
+enum {
+ CDUTIL_WALK_CONTINUE,
+ CDUTIL_WALK_STOP
+};
+
+typedef struct intlist {
+ int val;
+ struct intlist *next;
+} intlist_t;
+
+typedef struct disc_info {
+ int disc_status;
+ int erasable;
+ uint_t capacity;
+} disc_info_t;
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+void uscsi_cmd_init(struct uscsi_cmd *scmd, char *cdb, int cdblen);
+int uscsi(int fd, struct uscsi_cmd *scmd);
+int mode_sense(int fd, uchar_t pc, int dbd, int page_len,
+ uchar_t *buffer);
+int get_mode_page(int fd, int page_no, int pc, int buf_len,
+ uchar_t *buffer, int *plen);
+int get_configuration(int fd, uint16_t feature, int bufsize,
+ uchar_t *buf);
+boolean_t get_current_profile(int fd, int *profile);
+void walk_profiles(int fd, int (*f)(void *, int, boolean_t), void *);
+void get_read_write_speeds(int fd, int *read_speed, int *write_speed,
+ intlist_t **wspeeds, int *n_wspeeds, intlist_t **wspeeds_mem);
+boolean_t get_disc_info(int fd, disc_info_t *);
+boolean_t read_format_capacity(int fd, uint64_t *capacity);
+boolean_t get_media_info(int fd, struct dk_minfo *minfop);
+boolean_t get_disc_capacity_for_profile(int fd, int profile,
+ uint64_t *capacity);
+boolean_t read_toc(int fd, int format, int trackno, int buflen,
+ uchar_t *buf);
+
+#endif /* CDUTILS_H */
diff --git a/hald/solaris/probing/fsutils.c b/hald/solaris/probing/fsutils.c
new file mode 100644
index 0000000..45386d3
--- /dev/null
+++ b/hald/solaris/probing/fsutils.c
@@ -0,0 +1,250 @@
+/***************************************************************************
+ *
+ * fsutils.c : filesystem utilities
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)fsutils.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/scsi/impl/uscsi.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/dkio.h>
+#include <libintl.h>
+#include <sys/dktp/fdisk.h>
+#include <sys/fs/pc_label.h>
+
+#include <libhal.h>
+#include "fsutils.h"
+
+/*
+ * Separates dos notation device spec into device and drive number
+ */
+boolean_t
+dos_to_dev(char *path, char **devpath, int *num)
+{
+ char *p;
+
+ if ((p = strrchr(path, ':')) == NULL) {
+ return (B_FALSE);
+ }
+ if ((*num = atoi(p + 1)) == 0) {
+ return (B_FALSE);
+ }
+ p[0] = '\0';
+ *devpath = strdup(path);
+ p[0] = ':';
+ return (*devpath != NULL);
+}
+
+char *
+get_slice_name (char *devlink)
+{
+ char *part, *slice, *disk;
+ char *s = NULL;
+ char *p;
+
+ if ((p = strstr(devlink, "/lofi/")) != 0) {
+ return (p + sizeof ("/lofi/") - 1);
+ }
+
+ part = strrchr(devlink, 'p');
+ slice = strrchr(devlink, 's');
+ disk = strrchr(devlink, 'd');
+
+ if ((part != NULL) && (part > slice) && (part > disk)) {
+ s = part;
+ } else if ((slice != NULL) && (slice > disk)) {
+ s = slice;
+ } else {
+ s = disk;
+ }
+ if ((s != NULL) && isdigit(s[1])) {
+ return (s);
+ } else {
+ return ("");
+ }
+}
+
+boolean_t
+is_dos_drive(uchar_t type)
+{
+ return ((type == 1) || (type == 4) || (type == 5) || (type == 6) ||
+ ((type >= 8) && (type <= 0xf)));
+}
+
+boolean_t
+is_dos_extended(uchar_t id)
+{
+ return ((id == EXTDOS) || (id == FDISK_EXTLBA));
+}
+
+struct part_find_s {
+ int num;
+ int count;
+ int systid;
+ int r_systid;
+ int r_relsect;
+ int r_numsect;
+};
+
+enum { WALK_CONTINUE, WALK_TERMINATE };
+
+/*
+ * Walk partition tables and invoke a callback for each.
+ */
+static void
+walk_partitions(int fd, int startsec, int (*f)(void *, int, int, int),
+ void *arg)
+{
+ uint32_t buf[1024/4];
+ int bufsize = 1024;
+ struct mboot *mboot = (struct mboot *)&buf[0];
+ struct ipart ipart[FD_NUMPART];
+ int sec = startsec;
+ int lastsec = sec + 1;
+ int relsect;
+ int ext = 0;
+ int systid;
+ boolean_t valid;
+ int i;
+
+ while (sec != lastsec) {
+ if (pread(fd, buf, bufsize, (off_t)sec * 512) != bufsize) {
+ break;
+ }
+ lastsec = sec;
+ if (ltohs(mboot->signature) != MBB_MAGIC) {
+ break;
+ }
+ bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ systid = ipart[i].systid;
+ relsect = sec + ltohi(ipart[i].relsect);
+ if (systid == 0) {
+ continue;
+ }
+ valid = B_TRUE;
+ if (is_dos_extended(systid) && (sec == lastsec)) {
+ sec = startsec + ltohi(ipart[i].relsect);
+ if (ext++ == 0) {
+ relsect = startsec = sec;
+ } else {
+ valid = B_FALSE;
+ }
+ }
+ if (valid && f(arg, ipart[i].systid, relsect,
+ ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
+ return;
+ }
+ }
+ }
+}
+
+static int
+find_dos_drive_cb(void *arg, int systid, int relsect, int numsect)
+{
+ struct part_find_s *p = arg;
+
+ if (is_dos_drive(systid)) {
+ if (++p->count == p->num) {
+ p->r_relsect = relsect;
+ p->r_numsect = numsect;
+ p->r_systid = systid;
+ return (WALK_TERMINATE);
+ }
+ }
+
+ return (WALK_CONTINUE);
+}
+
+/*
+ * Given a dos drive number, return its relative sector number,
+ * number of sectors in partition and the system id.
+ */
+boolean_t
+find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid)
+{
+ struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
+
+ p.num = num;
+
+ if (num > 0) {
+ walk_partitions(fd, 0, find_dos_drive_cb, &p);
+ if (p.count == num) {
+ *relsect = p.r_relsect;
+ *numsect = p.r_numsect;
+ *systid = p.r_systid;
+ return (B_TRUE);
+ }
+ }
+
+ return (B_FALSE);
+}
+
+static int
+get_num_dos_drives_cb(void *arg, int systid, int relsect, int numsect)
+{
+ if (is_dos_drive(systid)) {
+ (*(int *)arg)++;
+ }
+ return (WALK_CONTINUE);
+}
+
+int
+get_num_dos_drives(int fd)
+{
+ int count = 0;
+
+ walk_partitions(fd, 0, get_num_dos_drives_cb, &count);
+
+ return (count);
+}
+
+/*
+ * Return true if all non-empty slices in vtoc have identical start/size and
+ * are tagged backup/entire disk.
+ */
+boolean_t
+vtoc_one_slice_entire_disk(struct vtoc *vtoc)
+{
+ int i;
+ struct partition *p;
+ daddr_t prev_start;
+ long prev_size;
+
+ for (i = 0; i < vtoc->v_nparts; i++) {
+ p = &vtoc->v_part[i];
+ if (p->p_size == 0) {
+ continue;
+ }
+ if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) {
+ return (B_FALSE);
+ }
+ if ((i > 0) &&
+ ((p->p_start != prev_start) || (p->p_size != prev_size))) {
+ return (B_FALSE);
+ }
+ prev_start = p->p_start;
+ prev_size = p->p_size;
+ }
+
+ return (B_TRUE);
+}
diff --git a/hald/solaris/probing/fsutils.h b/hald/solaris/probing/fsutils.h
new file mode 100644
index 0000000..73fa823
--- /dev/null
+++ b/hald/solaris/probing/fsutils.h
@@ -0,0 +1,28 @@
+/***************************************************************************
+ *
+ * fsutils.h : definitions for filesystem utilities
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)fsutils.h 1.2 06/10/13 SMI"
+
+#ifndef FSUTILS_H
+#define FSUTILS_H
+
+#include <sys/types.h>
+#include <sys/vtoc.h>
+
+boolean_t dos_to_dev(char *path, char **devpath, int *num);
+char *get_slice_name (char *devlink);
+boolean_t is_dos_drive(uchar_t id);
+boolean_t is_dos_extended(uchar_t id);
+boolean_t find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid);
+int get_num_dos_drives(int fd);
+boolean_t vtoc_one_slice_entire_disk(struct vtoc *vtoc);
+
+#endif /* FSUTILS_H */
diff --git a/hald/solaris/probing/probe-storage.c b/hald/solaris/probing/probe-storage.c
new file mode 100644
index 0000000..61ec991
--- /dev/null
+++ b/hald/solaris/probing/probe-storage.c
@@ -0,0 +1,488 @@
+/***************************************************************************
+ *
+ * probe-storage.c : Probe for storage devices
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)probe-storage.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mnttab.h>
+#include <sys/fdio.h>
+#include <sys/scsi/scsi.h>
+#include <sys/vtoc.h>
+#include <sys/efi_partition.h>
+#include <priv.h>
+
+#include <libhal.h>
+#include <cdutils.h>
+#include <fsutils.h>
+#include <logger.h>
+
+/** Check if a filesystem on a special device file is mounted
+ *
+ * @param device_file Special device file, e.g. /dev/cdrom
+ * @return TRUE iff there is a filesystem system mounted
+ * on the special device file
+ */
+static dbus_bool_t
+is_mounted (const char *device_file)
+{
+ FILE *f;
+ dbus_bool_t rc = FALSE;
+ struct mnttab mp;
+ struct mnttab mpref;
+
+ if ((f = fopen ("/etc/mnttab", "r")) == NULL)
+ return rc;
+
+ bzero(&mp, sizeof (mp));
+ bzero(&mpref, sizeof (mpref));
+ mpref.mnt_special = (char *)device_file;
+ if (getmntany(f, &mp, &mpref) == 0) {
+ rc = TRUE;
+ }
+
+ fclose (f);
+ return rc;
+}
+
+static int
+get_cdrom_properties_walker (void *arg, int profile, boolean_t is_current)
+{
+ LibHalChangeSet *cs = (LibHalChangeSet *)arg;
+
+ switch (profile) {
+ case 0x09:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.cdr", TRUE);
+ break;
+ case 0x0a:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.cdrw", TRUE);
+ break;
+ case 0x10:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvd", TRUE);
+ break;
+ case 0x11:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdr", TRUE);
+ break;
+ case 0x12:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdram", TRUE);
+ break;
+ case 0x13:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdrw", TRUE);
+ break;
+ case 0x14:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdrw", TRUE);
+ break;
+ case 0x1a:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrw", TRUE);
+ break;
+ case 0x1b:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusr", TRUE);
+ break;
+ case 0x2b:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrdl", TRUE);
+ break;
+ case 0x40:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bd", TRUE);
+ break;
+ case 0x41:
+ case 0x42:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bdr", TRUE);
+ break;
+ case 0x43:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bdre", TRUE);
+ break;
+ case 0x50:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvd", TRUE);
+ break;
+ case 0x51:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdr", TRUE);
+ break;
+ case 0x52:
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdrw", TRUE);
+ break;
+ }
+
+ return CDUTIL_WALK_CONTINUE;
+}
+
+#define WSPLEN 64
+
+static void
+get_cdrom_properties (int fd, LibHalChangeSet *cs)
+{
+ DBusError error;
+ int capabilities;
+ int read_speed, write_speed;
+ intlist_t *write_speeds, *write_speeds_mem, *sp;
+ int n_wspeeds;
+ char **wspeeds;
+ char *wspeeds_mem;
+ int i;
+
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.cdr", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.cdrw", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvd", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdr", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdrw", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdram", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusr", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrw", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.dvdplusrdl", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bd", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bdr", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.bdre", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvd", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdr", FALSE);
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.hddvdrw", FALSE);
+
+ walk_profiles(fd, get_cdrom_properties_walker, cs);
+
+ /* XXX */
+ libhal_changeset_set_property_bool (cs, "storage.cdrom.support_media_changed", TRUE);
+
+ get_read_write_speeds(fd, &read_speed, &write_speed, &write_speeds, &n_wspeeds, &write_speeds_mem);
+
+ libhal_changeset_set_property_int (cs, "storage.cdrom.read_speed", read_speed);
+ libhal_changeset_set_property_int (cs, "storage.cdrom.write_speed", write_speed);
+
+ if (n_wspeeds <= 0) {
+ wspeeds_mem = NULL;
+ libhal_changeset_set_property_strlist (cs, "storage.cdrom.write_speeds", (const char **)&wspeeds_mem);
+ return;
+ }
+ if ((wspeeds = (char **)calloc(n_wspeeds + 1, sizeof (char *))) == NULL) {
+ free (write_speeds_mem);
+ return;
+ }
+ if ((wspeeds_mem = (char *)calloc(n_wspeeds, WSPLEN)) == NULL) {
+ free (wspeeds);
+ free (write_speeds_mem);
+ return;
+ }
+ for (i = 0; i < n_wspeeds; i++) {
+ wspeeds[i] = &wspeeds_mem[i * WSPLEN];
+ }
+
+ for (sp = write_speeds, i = 0; sp != NULL; sp = sp->next, i++) {
+ snprintf (wspeeds[i], WSPLEN, "%d", sp->val);
+ }
+ libhal_changeset_set_property_strlist (cs, "storage.cdrom.write_speeds", (const char **)wspeeds);
+
+ free (wspeeds);
+ free (wspeeds_mem);
+ free (write_speeds_mem);
+}
+
+/*
+ * Return a copy of a string without trailing spaces. If 'len' is non-zero,
+ * it specifies max length, otherwise the string must be null-terminated.
+ */
+char *
+rtrim_copy(char *src, int len)
+{
+ char *dst, *p;
+
+ if (len == 0) {
+ len = strlen(src);
+ }
+ if ((dst = calloc(1, len + 1)) != NULL) {
+ strncpy(dst, src, len);
+ p = dst + len - 1;
+ while ((p >= dst) && (isspace(*p))) {
+ *p-- = '\0';
+ }
+ }
+ return (dst);
+}
+
+static void
+get_disk_properties (int fd, LibHalChangeSet *cs)
+{
+ struct scsi_inquiry inq;
+ struct uscsi_cmd ucmd;
+ union scsi_cdb cdb;
+ int status;
+ char *s;
+
+ /* INQUIRY */
+ (void) memset((void *) &inq, 0, sizeof (inq));
+ (void) memset((void *) &ucmd, 0, sizeof (ucmd));
+ (void) memset((void *) &cdb, 0, sizeof (union scsi_cdb));
+ cdb.scc_cmd = SCMD_INQUIRY;
+ FORMG0COUNT(&cdb, sizeof (inq));
+ ucmd.uscsi_cdb = (caddr_t) & cdb;
+ ucmd.uscsi_cdblen = CDB_GROUP0;
+ ucmd.uscsi_bufaddr = (caddr_t) & inq;
+ ucmd.uscsi_buflen = sizeof (inq);
+ ucmd.uscsi_timeout = 30;
+ ucmd.uscsi_flags = USCSI_READ;
+ status = ioctl(fd, USCSICMD, &ucmd);
+ if (status || ucmd.uscsi_status) {
+ return;
+ }
+
+ if ((s = rtrim_copy(inq.inq_vid, sizeof (inq.inq_vid))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.vendor", s);
+ free(s);
+ }
+ if ((s = rtrim_copy(inq.inq_pid, sizeof (inq.inq_pid))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.model", s);
+ free(s);
+ }
+ if ((s = rtrim_copy(inq.inq_revision, sizeof (inq.inq_revision))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.firmware_revision", s);
+ free(s);
+ }
+ if ((s = rtrim_copy(inq.inq_serial, sizeof (inq.inq_serial))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.serial", s);
+ free(s);
+ }
+}
+
+/*
+ * returns TRUE if diskette is inserted.
+ * also returns write protection status.
+ */
+static dbus_bool_t
+check_floppy(int fd, dbus_bool_t *wprot)
+{
+ int chg;
+
+ if ((ioctl(fd, FDGETCHANGE, &chg) == 0) && !(chg & FDGC_CURRENT)) {
+ *wprot = ((chg & FDGC_CURWPROT) != NULL);
+ return (TRUE);
+ } else {
+ return (FALSE);
+ }
+}
+
+void
+drop_privileges ()
+{
+ priv_set_t *pPrivSet = NULL;
+ priv_set_t *lPrivSet = NULL;
+
+ /*
+ * Start with the 'basic' privilege set and then remove any
+ * of the 'basic' privileges that will not be needed.
+ */
+ if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ return;
+ }
+
+ /* Clear privileges we will not need from the 'basic' set */
+ (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
+ (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
+ (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
+ (void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
+ (void) priv_delset(pPrivSet, PRIV_PROC_FORK);
+
+ /* for uscsi */
+ (void) priv_addset(pPrivSet, PRIV_SYS_DEVICES);
+
+ /* to open logindevperm'd devices */
+ (void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
+
+ /* Set the permitted privilege set. */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
+ return;
+ }
+
+ /* Clear the limit set. */
+ if ((lPrivSet = priv_allocset()) == NULL) {
+ return;
+ }
+
+ priv_emptyset(lPrivSet);
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
+ return;
+ }
+
+ priv_freeset(lPrivSet);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret = 1;
+ int fd = -1;
+ int rfd = -1;
+ char *udi;
+ char *device_file;
+ char *raw_device_file;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ char *bus;
+ char *drive_type;
+ dbus_bool_t is_cdrom;
+ dbus_bool_t is_floppy;
+ struct dk_minfo minfo;
+ dbus_bool_t only_check_for_media;
+ int got_media = FALSE;
+ dbus_bool_t is_write_protected = FALSE;
+ dbus_bool_t is_mbr = FALSE;
+ dbus_bool_t is_smi = FALSE;
+ dbus_bool_t is_gpt = FALSE;
+ dbus_bool_t is_partitioned = FALSE;
+ dbus_bool_t vtoc_slices = FALSE;
+ int dos_cnt = 0;
+ const char *scheme = "";
+ struct vtoc vtoc;
+ dk_gpt_t *gpt;
+ LibHalChangeSet *cs = NULL;
+
+ if ((udi = getenv ("UDI")) == NULL)
+ goto out;
+ if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL)
+ goto out;
+ if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_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;
+
+ drop_privileges ();
+
+ setup_logger ();
+
+ if (argc == 2 && strcmp (argv[1], "--only-check-for-media") == 0)
+ only_check_for_media = TRUE;
+ else
+ only_check_for_media = FALSE;
+
+ is_cdrom = (strcmp (drive_type, "cdrom") == 0);
+ is_floppy = (strcmp (drive_type, "floppy") == 0);
+
+ dbus_error_init (&error);
+ if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
+ goto out;
+
+ if ((cs = libhal_device_new_changeset (udi)) == NULL) {
+ HAL_DEBUG (("Cannot allocate changeset"));
+ goto out;
+ }
+
+ HAL_DEBUG (("Doing probe-storage for %s (bus %s) (drive_type %s) (udi=%s) (--only-check-for-media==%d)",
+ device_file, bus, drive_type, udi, only_check_for_media));
+
+ if ((rfd = open (raw_device_file, O_RDONLY | O_NONBLOCK)) < 0) {
+ HAL_DEBUG (("Cannot open %s: %s", raw_device_file, strerror (errno)));
+ goto out;
+ }
+
+ if (!only_check_for_media) {
+ if (strcmp (drive_type, "cdrom") == 0) {
+ get_cdrom_properties (rfd, cs);
+ } else if (strcmp (drive_type, "disk") == 0) {
+ get_disk_properties (rfd, cs);
+ }
+ }
+
+ ret = 0;
+
+ if (is_cdrom) {
+ HAL_DEBUG (("Checking for optical disc on %s", raw_device_file));
+ got_media = get_media_info(rfd, &minfo);
+ if (!got_media) {
+ goto out_cs;
+ }
+ /* XXX */
+ is_write_protected = TRUE;
+ } else if (is_floppy) {
+ HAL_DEBUG (("Checking for floppy on %s", raw_device_file));
+ if (check_floppy(rfd, &is_write_protected)) {
+ got_media = TRUE;
+ }
+ /* don't look for partitions on floppy */
+ goto out_cs;
+ } else {
+ got_media = TRUE;
+ }
+
+ HAL_DEBUG (("Checking for partitions on %s", device_file));
+
+ if ((fd = open (device_file, O_RDONLY | O_NONBLOCK)) < 0) {
+ HAL_DEBUG (("Cannot open %s: %s", device_file, strerror (errno)));
+ goto out_cs;
+ }
+
+ dos_cnt = get_num_dos_drives(fd);
+ is_mbr = (dos_cnt > 0);
+ if (is_mbr) {
+ scheme = "mbr";
+ }
+ if (read_vtoc(rfd, &vtoc) >= 0) {
+ if (!vtoc_one_slice_entire_disk(&vtoc)) {
+ is_smi = TRUE;
+ if (!is_mbr) {
+ /* smi within mbr partition is okay */
+ scheme = "smi";
+ }
+ vtoc_slices = TRUE;
+ }
+ } else if (!is_cdrom && (efi_alloc_and_read(rfd, &gpt) >= 0)) {
+ /*
+ * Note: for some reason efi_read takes very long on cdroms.
+ * Needs more investigation, skip gpt on cdrom for now.
+ */
+ is_gpt = TRUE;
+ scheme = "gpt";
+ efi_free(gpt);
+ }
+
+out_cs:
+ is_partitioned = is_mbr || is_smi || is_gpt;
+ libhal_changeset_set_property_bool (cs, "storage.no_partitions_hint", !is_partitioned);
+ libhal_changeset_set_property_bool (cs, "block.no_partitions", !is_partitioned);
+ libhal_changeset_set_property_string (cs, "storage.partitioning_scheme", scheme);
+ libhal_changeset_set_property_bool (cs, "storage.solaris.vtoc_slices", vtoc_slices);
+ libhal_changeset_set_property_int (cs, "storage.solaris.num_dos_partitions", dos_cnt);
+ /* XXX should only set for removable drives */
+ libhal_changeset_set_property_bool (cs, "storage.removable.media_available", got_media);
+ libhal_changeset_set_property_bool (cs, "storage.removable.solaris.read_only", is_write_protected);
+
+ libhal_device_commit_changeset (ctx, cs, &error);
+
+out:
+ if (cs != NULL) {
+ libhal_device_free_changeset (cs);
+ }
+ if (fd >= 0) {
+ close (fd);
+ }
+ if (rfd >= 0) {
+ close (rfd);
+ }
+ if (ctx != NULL) {
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free (&error);
+ }
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return ret;
+}
diff --git a/hald/solaris/probing/probe-volume.c b/hald/solaris/probing/probe-volume.c
new file mode 100644
index 0000000..621022e
--- /dev/null
+++ b/hald/solaris/probing/probe-volume.c
@@ -0,0 +1,673 @@
+/***************************************************************************
+ *
+ * probe-volume.c : probe volumes
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)probe-volume.c 1.4 06/10/27 SMI"
+
+#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 <fcntl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/dkio.h>
+#include <sys/cdio.h>
+#include <sys/fdio.h>
+#include <libnvpair.h>
+#include <libfstyp.h>
+#include <sys/vtoc.h>
+#include <sys/efi_partition.h>
+#include <sys/fs/hsfs_spec.h>
+#include <sys/fs/hsfs_isospec.h>
+#include <priv.h>
+
+#include <libhal.h>
+#include <cdutils.h>
+#include <fsutils.h>
+#include <logger.h>
+
+static void
+my_dbus_error_free(DBusError *error)
+{
+ if (dbus_error_is_set(error)) {
+ dbus_error_free(error);
+ }
+}
+
+/*
+ * Return a copy of a string without trailing spaces. If 'len' is non-zero,
+ * it specifies max length, otherwise the string must be null-terminated.
+ */
+static char *
+rtrim_copy(char *src, int len)
+{
+ char *dst, *p;
+
+ if (len == 0) {
+ len = strlen(src);
+ }
+ if ((dst = calloc(1, len + 1)) != NULL) {
+ strncpy(dst, src, len);
+ p = dst + len - 1;
+ while ((p >= dst) && (isspace(*p))) {
+ *p-- = '\0';
+ }
+ }
+ return (dst);
+}
+
+static void
+set_fstyp_properties (LibHalContext *ctx, const char *udi, const char *fstype, nvlist_t *fsattr)
+{
+ char buf[256];
+ DBusError error;
+ char *uuid = NULL;
+ char *label_orig = NULL;
+ char *label = NULL;
+ LibHalChangeSet *cs;
+
+ dbus_error_init (&error);
+
+ if ((cs = libhal_device_new_changeset (udi)) == NULL) {
+ return;
+ }
+
+ libhal_changeset_set_property_string (cs, "volume.fsusage", "filesystem");
+ libhal_changeset_set_property_string (cs, "volume.fstype", fstype);
+
+ /* label */
+ (void) nvlist_lookup_string(fsattr, "gen_volume_label", &label_orig);
+ if (label_orig != NULL) {
+ label = rtrim_copy(label_orig, 0);
+ }
+ if ((label != NULL) && (label[0] != '\0')) {
+ libhal_changeset_set_property_string (cs, "volume.label", label);
+ libhal_changeset_set_property_string (cs, "info.product", label);
+ } else {
+ libhal_changeset_set_property_string (cs, "volume.label", "");
+ snprintf (buf, sizeof (buf), "Volume (%s)", fstype);
+ libhal_changeset_set_property_string (cs, "info.product", buf);
+ }
+ free(label);
+
+ /* uuid */
+ if (nvlist_lookup_string(fsattr, "gen_uuid", &uuid) == 0) {
+ libhal_changeset_set_property_string (cs, "volume.uuid", uuid);
+ } else {
+ libhal_changeset_set_property_string (cs, "volume.uuid", "");
+ }
+
+ libhal_device_commit_changeset (ctx, cs, &error);
+ libhal_device_free_changeset (cs);
+
+ my_dbus_error_free (&error);
+}
+
+/*
+ * hsfs/iso9660 contents detection: Video DVD, Video CD, etc.
+ */
+static void
+hsfs_contents(int fd, off_t probe_offset, LibHalContext *ctx, const char *udi)
+{
+ size_t secsz = ISO_SECTOR_SIZE;
+ uchar_t buf[ISO_SECTOR_SIZE];
+ int ptbl_lbn, ptbl_size;
+ int off, reloff, readoff;
+ uchar_t *p;
+ char *name;
+ int name_len;
+ int ipe_len;
+ DBusError error;
+
+ /*
+ * find 1st Primary Volume Descriptor
+ */
+ readoff = probe_offset + ISO_VOLDESC_SEC * secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ return;
+ }
+ while (ISO_DESC_TYPE (buf) != ISO_VD_PVD) {
+ if (ISO_DESC_TYPE (buf) == ISO_VD_EOV) {
+ return;
+ }
+ readoff += secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ return;
+ }
+ }
+
+ /*
+ * PVD contains size and offset of the LSB/MSB path table
+ */
+ ptbl_size = ISO_PTBL_SIZE (buf);
+#if defined(_LITTLE_ENDIAN)
+ ptbl_lbn = ISO_PTBL_MAN_LS (buf);
+#else
+ ptbl_lbn = ISO_PTBL_MAN_MS (buf);
+#endif
+
+ /*
+ * Look through path table entries
+ */
+ readoff = probe_offset + ptbl_lbn * secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ return;
+ }
+ dbus_error_init (&error);
+
+ for (off = reloff = 0;
+ off < ptbl_size;
+ off += ipe_len, reloff += ipe_len) {
+
+ /* load sectors on demand */
+ if (reloff >= secsz) {
+ readoff += secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ break;
+ }
+ reloff -= secsz;
+ }
+
+ p = buf + reloff;
+ name_len = IPE_NAME_LEN(p);
+ ipe_len = IPE_FPESIZE + name_len + (name_len % 2);
+
+ /* only interested in root directories */
+ if (IPE_PARENT_NO (p) != 1) {
+ continue;
+ }
+ if ((name_len < 2) || (name_len > IDE_MAX_NAME_LEN)) {
+ continue;
+ }
+
+ name = (char *)IPE_NAME (p);
+ if (strncasecmp (name, "VIDEO_TS", min (8, name_len)) == 0) {
+ libhal_device_set_property_bool (ctx, udi,
+ "volume.disc.is_videodvd", TRUE, &error);
+ } else if (strncasecmp (name, "VCD", min (3, name_len)) == 0) {
+ libhal_device_set_property_bool (ctx, udi,
+ "volume.disc.is_vcd", TRUE, &error);
+ } else if (strncasecmp (name, "SVCD", min (4, name_len)) == 0) {
+ libhal_device_set_property_bool (ctx, udi,
+ "volume.disc.is_svcd", TRUE, &error);
+ }
+ }
+
+ my_dbus_error_free (&error);
+}
+
+static dbus_bool_t
+probe_disc (int fd, LibHalContext *ctx, const char *udi, dbus_bool_t *should_probe_for_fs)
+{
+ DBusError error;
+ disc_info_t di;
+ int profile;
+ dbus_bool_t has_audio, has_data, is_blank, is_appendable, is_rewritable;
+ char *disc_type = "cd_rom";
+ uint64_t capacity = 0;
+ int i;
+ LibHalChangeSet *cs;
+
+ dbus_error_init (&error);
+
+ if (get_disc_info (fd, &di)) {
+ is_blank = (di.disc_status == 0);
+ is_appendable = (di.disc_status == 1);
+ is_rewritable = (di.erasable != 0);
+ } else {
+ is_blank = is_appendable = is_rewritable = FALSE;
+ }
+
+ if (get_current_profile (fd, &profile)) {
+ switch (profile) {
+ case 0x08: /* CD-ROM */
+ disc_type = "cd_rom";
+ break;
+ case 0x09: /* CD-R */
+ disc_type = "cd_r";
+ break;
+ case 0x0A: /* CD-RW */
+ disc_type = "cd_rw";
+ is_rewritable = TRUE;
+ break;
+ case 0x10: /* DVD-ROM */
+ disc_type = "dvd_rom";
+ break;
+ case 0x11: /* DVD-R Sequential */
+ disc_type = "dvd_r";
+ break;
+ case 0x12: /* DVD-RAM */
+ disc_type = "dvd_ram";
+ is_rewritable = TRUE;
+ break;
+ case 0x13: /* DVD-RW Restricted Overwrite */
+ disc_type = "dvd_rw";
+ is_rewritable = TRUE;
+ break;
+ case 0x14: /* DVD-RW Sequential */
+ disc_type = "dvd_rw";
+ is_rewritable = TRUE;
+ break;
+ case 0x1A: /* DVD+RW */
+ disc_type = "dvd_plus_rw";
+ is_rewritable = TRUE;
+ break;
+ case 0x1B: /* DVD+R */
+ disc_type = "dvd_plus_r";
+ break;
+ case 0x2B: /* DVD+R Double Layer */
+ disc_type = "dvd_plus_r_dl";
+ break;
+ case 0x40: /* BD-ROM */
+ disc_type = "bd_rom";
+ break;
+ case 0x41: /* BD-R Sequential */
+ disc_type = "bd_r";
+ break;
+ case 0x42: /* BD-R Random */
+ disc_type = "bd_r";
+ break;
+ case 0x43: /* BD-RE */
+ disc_type = "bd_re";
+ is_rewritable = TRUE;
+ break;
+ case 0x50: /* HD DVD-ROM */
+ disc_type = "hddvd_rom";
+ break;
+ case 0x51: /* HD DVD-R */
+ disc_type = "hddvd_r";
+ break;
+ case 0x52: /* HD DVD-Rewritable */
+ disc_type = "hddvd_rw";
+ is_rewritable = TRUE;
+ break;
+ }
+
+ (void) get_disc_capacity_for_profile(fd, profile, &capacity);
+ }
+
+ has_audio = has_data = FALSE;
+ if (!is_blank) {
+ uchar_t smalltoc[12];
+ size_t toc_size;
+ uchar_t *toc, *p;
+
+ /*
+ * XXX for some reason CDROMREADTOCENTRY fails on video DVDs,
+ * but extracting the toc directly works okay.
+ */
+ if (!read_toc(fd, 0, 1, 4, smalltoc)) {
+ HAL_DEBUG(("read_toc failed"));
+ has_data = B_TRUE; /* probe for fs anyway */
+ } else {
+ toc_size = smalltoc[0] * 256 + smalltoc[1] + 2;
+ toc = (uchar_t *)calloc(1, toc_size);
+ if (toc == NULL || !read_toc(fd, 0, 1, toc_size, toc)) {
+ HAL_DEBUG (("read_toc again failed"));
+ } else {
+ for (p = &toc[4]; p < (toc + toc_size); p += 8) {
+ /* skip leadout */
+ if (p[2] == 0xAA) {
+ continue;
+ }
+ if (p[1] & 4) {
+ has_data = B_TRUE;
+ } else {
+ has_audio = B_TRUE;
+ }
+ }
+ }
+ free(toc);
+ }
+ }
+
+ if ((cs = libhal_device_new_changeset (udi)) == NULL) {
+ return (FALSE);
+ }
+ libhal_changeset_set_property_string (cs, "volume.disc.type", disc_type);
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_blank", is_blank);
+ libhal_changeset_set_property_bool (cs, "volume.disc.has_audio", has_audio);
+ libhal_changeset_set_property_bool (cs, "volume.disc.has_data", has_data);
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_appendable", is_appendable);
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_rewritable", is_rewritable);
+ libhal_changeset_set_property_uint64 (cs, "volume.disc.capacity", capacity);
+
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_videodvd", FALSE);
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_vcd", FALSE);
+ libhal_changeset_set_property_bool (cs, "volume.disc.is_svcd", FALSE);
+
+ libhal_device_commit_changeset (ctx, cs, &error);
+ libhal_device_free_changeset (cs);
+
+out:
+
+ *should_probe_for_fs = has_data;
+
+ my_dbus_error_free (&error);
+
+ return (TRUE);
+}
+
+static void
+drop_privileges ()
+{
+ priv_set_t *pPrivSet = NULL;
+ priv_set_t *lPrivSet = NULL;
+
+ /*
+ * Start with the 'basic' privilege set and then remove any
+ * of the 'basic' privileges that will not be needed.
+ */
+ if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ return;
+ }
+
+ /* Clear privileges we will not need from the 'basic' set */
+ (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
+ (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
+ (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
+ (void) priv_delset(pPrivSet, PRIV_PROC_EXEC);
+ (void) priv_delset(pPrivSet, PRIV_PROC_FORK);
+
+ /* for uscsi */
+ (void) priv_addset(pPrivSet, PRIV_SYS_DEVICES);
+
+
+ /* to open logindevperm'd devices */
+ (void) priv_addset(pPrivSet, PRIV_FILE_DAC_READ);
+
+ /* Set the permitted privilege set. */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
+ return;
+ }
+
+ /* Clear the limit set. */
+ if ((lPrivSet = priv_allocset()) == NULL) {
+ return;
+ }
+
+ priv_emptyset(lPrivSet);
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
+ return;
+ }
+
+ priv_freeset(lPrivSet);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int fd, rfd;
+ int ret;
+ char *udi;
+ char *device_file, *raw_device_file;
+ char *devpath, *rdevpath;
+ boolean_t is_dos;
+ int dos_num;
+ LibHalContext *ctx = NULL;
+ DBusError error;
+ DBusConnection *conn;
+ char *parent_udi;
+ char *storage_device;
+ char *is_disc_str;
+ int fdc;
+ dbus_bool_t is_disc = FALSE;
+ dbus_bool_t is_floppy = FALSE;
+ unsigned int block_size;
+ dbus_uint64_t vol_size;
+ dbus_bool_t should_probe_for_fs;
+ char *partition_scheme = NULL;
+ dbus_uint64_t partition_start = 0;
+ int partition_number = 0;
+ struct vtoc vtoc;
+ dk_gpt_t *gpt;
+ struct dk_minfo mi;
+ int i, dos_cnt;
+ fstyp_handle_t fstyp_handle;
+ int systid, relsect, numsect;
+ off_t probe_offset = 0;
+ int num_volumes;
+ char **volumes;
+ dbus_uint64_t v_start;
+ const char *fstype;
+ nvlist_t *fsattr;
+
+ fd = rfd = -1;
+
+ ret = 1;
+
+ if ((udi = getenv ("UDI")) == NULL) {
+ goto out;
+ }
+ if ((device_file = getenv ("HAL_PROP_BLOCK_DEVICE")) == NULL) {
+ goto out;
+ }
+ if ((raw_device_file = getenv ("HAL_PROP_BLOCK_SOLARIS_RAW_DEVICE")) == NULL) {
+ goto out;
+ }
+ if (!dos_to_dev(device_file, &rdevpath, &dos_num)) {
+ rdevpath = raw_device_file;
+ }
+ if (!(is_dos = dos_to_dev(device_file, &devpath, &dos_num))) {
+ devpath = device_file;
+ }
+ if ((parent_udi = getenv ("HAL_PROP_INFO_PARENT")) == NULL) {
+ goto out;
+ }
+ if ((storage_device = getenv ("HAL_PROP_BLOCK_STORAGE_DEVICE")) == NULL) {
+ goto out;
+ }
+
+ is_disc_str = getenv ("HAL_PROP_VOLUME_IS_DISC");
+ if (is_disc_str != NULL && strcmp (is_disc_str, "true") == 0) {
+ is_disc = TRUE;
+ } else {
+ is_disc = FALSE;
+ }
+
+ drop_privileges ();
+
+ setup_logger ();
+
+ dbus_error_init (&error);
+ if ((ctx = libhal_ctx_init_direct (&error)) == NULL)
+ goto out;
+
+ HAL_DEBUG (("Doing probe-volume for %s\n", device_file));
+
+ fd = open (devpath, O_RDONLY | O_NONBLOCK);
+ if (fd < 0) {
+ goto out;
+ }
+ rfd = open (rdevpath, O_RDONLY | O_NONBLOCK);
+ if (rfd < 0) {
+ goto out;
+ }
+
+ /* if it's a floppy with no media, bail out */
+ if (ioctl(rfd, FDGETCHANGE, &fdc) == 0) {
+ is_floppy = TRUE;
+ if (fdc & FDGC_CURRENT) {
+ goto out;
+ }
+ }
+
+ /* block size and total size */
+ if (ioctl(rfd, DKIOCGMEDIAINFO, &mi) != -1) {
+ block_size = mi.dki_lbsize;
+ vol_size = mi.dki_capacity * block_size;
+ } else {
+ block_size = 512;
+ vol_size = 0;
+ }
+ libhal_device_set_property_int (ctx, udi, "volume.block_size", block_size, &error);
+ my_dbus_error_free (&error);
+ libhal_device_set_property_uint64 (ctx, udi, "volume.size", vol_size, &error);
+ my_dbus_error_free (&error);
+
+ should_probe_for_fs = TRUE;
+
+ if (is_disc) {
+ if (!probe_disc (rfd, ctx, udi, &should_probe_for_fs)) {
+ HAL_DEBUG (("probe_disc failed, skipping fstyp"));
+ goto out;
+ }
+ /* XXX vol_probe_offset for multisession discs? */
+ }
+
+ if (!should_probe_for_fs) {
+ goto skip_fs;
+ }
+
+ /* don't support partitioned floppy */
+ if (is_floppy) {
+ goto skip_part;
+ }
+
+ /*
+ * first get partitioning info
+ */
+ if (is_dos) {
+ /* for a dos drive find partition offset */
+ if (!find_dos_drive(fd, dos_num, &relsect, &numsect, &systid)) {
+ goto out;
+ }
+ partition_scheme = "mbr";
+ partition_start = (dbus_uint64_t)relsect * 512;
+ partition_number = dos_num;
+ probe_offset = (off_t)relsect * 512;
+ } else {
+ if ((partition_number = read_vtoc(rfd, &vtoc)) >= 0) {
+ if (!vtoc_one_slice_entire_disk(&vtoc)) {
+ partition_scheme = "smi";
+ if (partition_number < vtoc.v_nparts) {
+ if (vtoc.v_part[partition_number].p_size == 0) {
+ HAL_DEBUG (("zero size partition"));
+ }
+ partition_start = vtoc.v_part[partition_number].p_start * block_size;
+ }
+ }
+ } else if ((partition_number = efi_alloc_and_read(rfd, &gpt)) >= 0) {
+ partition_scheme = "gpt";
+ if (partition_number < gpt->efi_nparts) {
+ if (gpt->efi_parts[partition_number].p_size == 0) {
+ HAL_DEBUG (("zero size partition"));
+ }
+ partition_start = gpt->efi_parts[partition_number].p_start * block_size;
+ }
+ efi_free(gpt);
+ }
+ probe_offset = 0;
+ }
+
+ if (partition_scheme != NULL) {
+ libhal_device_set_property_string (ctx, udi, "volume.partition.scheme", partition_scheme, &error);
+ my_dbus_error_free (&error);
+ libhal_device_set_property_int (ctx, udi, "volume.partition.number", partition_number, &error);
+ my_dbus_error_free (&error);
+ libhal_device_set_property_uint64 (ctx, udi, "volume.partition.start", partition_start, &error);
+ my_dbus_error_free (&error);
+ libhal_device_set_property_bool (ctx, udi, "volume.is_partition", TRUE, &error);
+ my_dbus_error_free (&error);
+ } else {
+ libhal_device_set_property_bool (ctx, udi, "volume.is_partition", FALSE, &error);
+ my_dbus_error_free (&error);
+ }
+
+ /*
+ * ignore duplicate partitions
+ */
+ if ((volumes = libhal_manager_find_device_string_match (
+ ctx, "block.storage_device", storage_device, &num_volumes, &error)) != NULL) {
+ my_dbus_error_free (&error);
+ for (i = 0; i < num_volumes; i++) {
+ if (strcmp (udi, volumes[i]) == 0) {
+ continue; /* skip self */
+ }
+ v_start = libhal_device_get_property_uint64 (ctx, volumes[i], "volume.partition.start", &error);
+ if (dbus_error_is_set(&error)) {
+ dbus_error_free(&error);
+ continue;
+ }
+ if (v_start == partition_start) {
+ HAL_DEBUG (("duplicate partition"));
+ goto out;
+ }
+ }
+ libhal_free_string_array (volumes);
+ }
+
+skip_part:
+
+ /*
+ * now determine fs type
+ */
+ if (fstyp_init(fd, probe_offset, NULL, &fstyp_handle) != 0) {
+ HAL_DEBUG (("fstyp_init failed"));
+ goto out;
+ }
+ if ((fstyp_ident(fstyp_handle, NULL, &fstype) != 0) ||
+ (fstyp_get_attr(fstyp_handle, &fsattr) != 0)) {
+ HAL_DEBUG (("fstyp ident or get_attr failed"));
+
+ /*
+ * XXX fstyp_udfs has a bug that it only works on raw,
+ * but we don't want to slow down the fast path above.
+ * Try raw for just udfs here until the bug is fixed.
+ */
+ HAL_DEBUG (("trying udfs workaround"));
+ fstyp_fini(fstyp_handle);
+ if (fstyp_init(rfd, probe_offset, NULL, &fstyp_handle) != 0) {
+ goto out;
+ }
+ if ((fstyp_ident(fstyp_handle, "udfs", &fstype) != 0) ||
+ (fstyp_get_attr(fstyp_handle, &fsattr) != 0)) {
+ fstyp_fini(fstyp_handle);
+ goto out;
+ }
+ }
+ set_fstyp_properties (ctx, udi, fstype, fsattr);
+
+ if (strcmp (fstype, "hsfs") == 0) {
+ hsfs_contents (fd, probe_offset, ctx, udi);
+ }
+
+ fstyp_fini(fstyp_handle);
+
+skip_fs:
+
+ ret = 0;
+
+out:
+ if (fd >= 0)
+ close (fd);
+ if (rfd >= 0)
+ close (rfd);
+
+ if (ctx != NULL) {
+ my_dbus_error_free (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return ret;
+
+}
diff --git a/hald/solaris/svc-hal b/hald/solaris/svc-hal
new file mode 100755
index 0000000..f8198d2
--- /dev/null
+++ b/hald/solaris/svc-hal
@@ -0,0 +1,39 @@
+#!/sbin/sh
+#
+# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+# Licensed under the Academic Free License version 2.1
+#
+# ident "@(#)svc-hal 1.1 06/10/10 SMI"
+
+. /lib/svc/share/smf_include.sh
+
+case "$1" in
+'start')
+ if smf_is_nonglobalzone; then
+ /usr/sbin/svcadm disable $SMF_FMRI
+ echo "$SMF_FMRI is not supported in a local zone"
+ sleep 5 &
+ exit $SMF_EXIT_OK
+ fi
+
+ [ ! -x /usr/lib/hal/hald ] && exit $SMF_EXIT_ERR_CONFIG
+
+ [ ! -d /var/run/hald ] && /usr/bin/mkdir -m 755 /var/run/hald
+ [ ! -d /media ] && /usr/bin/mkdir -m 755 /media
+
+ /usr/lib/hal/hald --daemon=yes
+ err=$?
+ if [ $err -ne 0 ]; then
+ echo "hal failed to start: error $err"
+ exit $SMF_EXIT_ERR_FATAL
+ fi
+ ;;
+*)
+ echo "Usage: $0 { start }"
+ exit $SMF_EXIT_ERR_FATAL
+ ;;
+esac
+
+exit $SMF_EXIT_OK
diff --git a/hald/solaris/sysevent.c b/hald/solaris/sysevent.c
new file mode 100644
index 0000000..9ae7c13
--- /dev/null
+++ b/hald/solaris/sysevent.c
@@ -0,0 +1,295 @@
+/***************************************************************************
+ *
+ * sysevent.c : Solaris sysevents
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)sysevent.c 1.2 06/10/13 SMI"
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/dkio.h>
+#include <sys/stat.h>
+#include <libdevinfo.h>
+#include <libsysevent.h>
+#include <sys/sysevent/dev.h>
+#include <glib.h>
+
+#include "../osspec.h"
+#include "../logger.h"
+#include "../hald.h"
+#include "../hald_dbus.h"
+#include "../device_info.h"
+#include "../util.h"
+#include "osspec_solaris.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_storage.h"
+#include "sysevent.h"
+
+#ifndef ESC_LOFI
+#define ESC_LOFI "lofi"
+#endif
+
+static void sysevent_dev_handler(sysevent_t *);
+static gboolean sysevent_iochannel_data(GIOChannel *, GIOCondition, gpointer);
+static void sysevent_dev_add(gchar *, gchar *);
+static void sysevent_dev_remove(gchar *, gchar *);
+static void sysevent_dev_branch(gchar *);
+static void sysevent_lofi_add(gchar *, gchar *);
+static void sysevent_lofi_remove(gchar *, gchar *);
+
+static sysevent_handle_t *shp;
+
+static int sysevent_pipe_fds[2];
+static GIOChannel *sysevent_iochannel;
+static guint sysevent_source_id;
+
+gboolean
+sysevent_init(void)
+{
+ GError *err = NULL;
+ const char *subcl[2];
+
+ /*
+ * pipe used to serialize sysevents through the main loop
+ */
+ if (pipe (sysevent_pipe_fds) != 0) {
+ HAL_INFO (("pipe() failed errno=%d", errno));
+ return (FALSE);
+ }
+ sysevent_iochannel = g_io_channel_unix_new (sysevent_pipe_fds[0]);
+ if (sysevent_iochannel == NULL) {
+ HAL_INFO (("g_io_channel_unix_new failed"));
+ return (FALSE);
+ }
+ g_io_channel_set_flags (sysevent_iochannel, G_IO_FLAG_NONBLOCK, &err);
+ sysevent_source_id = g_io_add_watch (
+ sysevent_iochannel, G_IO_IN, sysevent_iochannel_data, NULL);
+
+ shp = sysevent_bind_handle(sysevent_dev_handler);
+ if (shp == NULL) {
+ HAL_INFO (("sysevent_bind_handle failed %d", errno));
+ return (FALSE);
+ }
+
+ subcl[0] = ESC_DISK;
+ subcl[1] = ESC_LOFI;
+ if (sysevent_subscribe_event(shp, EC_DEV_ADD, subcl, 2) != 0) {
+ HAL_INFO (("subscribe(dev_add) failed %d", errno));
+ sysevent_unbind_handle(shp);
+ return (FALSE);
+ }
+ if (sysevent_subscribe_event(shp, EC_DEV_REMOVE, subcl, 2) != 0) {
+ HAL_INFO (("subscribe(dev_remove) failed %d", errno));
+ sysevent_unbind_handle(shp);
+ return (FALSE);
+ }
+
+ subcl[0] = ESC_DEV_BRANCH_REMOVE;
+ if (sysevent_subscribe_event(shp, EC_DEV_BRANCH, subcl, 1) != 0) {
+ HAL_INFO (("subscribe(dev_branch) failed %d", errno));
+ sysevent_unbind_handle(shp);
+ return (FALSE);
+ }
+
+ return (B_TRUE);
+}
+
+void
+sysevent_fini(void)
+{
+ sysevent_unbind_handle(shp);
+ shp = NULL;
+}
+
+static void
+sysevent_dev_handler(sysevent_t *ev)
+{
+ char *class;
+ char *subclass;
+ nvlist_t *attr_list;
+ char *phys_path;
+ char *dev_name;
+ char s[1024];
+ ssize_t nwritten;
+
+ if ((class = sysevent_get_class_name(ev)) == NULL)
+ return;
+
+ if ((subclass = sysevent_get_subclass_name(ev)) == NULL)
+ return;
+
+ if (sysevent_get_attr_list(ev, &attr_list) != 0)
+ return;
+
+ if (nvlist_lookup_string(attr_list, DEV_PHYS_PATH, &phys_path) != 0)
+ goto out;
+
+ if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0)
+ dev_name = "";
+
+ snprintf(s, sizeof (s), "%s %s %s %s\n",
+ class, subclass, phys_path, dev_name);
+ nwritten = write(sysevent_pipe_fds[1], s, strlen(s) + 1);
+
+ HAL_INFO (("sysevent_dev_handler: wrote %d bytes", nwritten));
+
+out:
+ nvlist_free(attr_list);
+}
+
+static gboolean
+sysevent_iochannel_data (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ GError *err = NULL;
+ gchar *s = NULL;
+ gsize len;
+ int matches;
+ gchar class[1024];
+ gchar subclass[1024];
+ gchar phys_path[1024];
+ gchar dev_name[1024];
+
+ HAL_INFO (("sysevent_iochannel_data"));
+
+ while (g_io_channel_read_line (sysevent_iochannel, &s, &len, NULL,
+ &err) == G_IO_STATUS_NORMAL) {
+ if (len == 0) {
+ break;
+ }
+
+ class[0] = subclass[0] = phys_path[0] = dev_name[0] = '\0';
+ matches = sscanf(s, "%s %s %s %s", class, subclass, phys_path, dev_name);
+ g_free (s);
+ s = NULL;
+ if (matches < 3) {
+ continue;
+ }
+ HAL_INFO (("sysevent: class=%s, sub=%s", class, subclass));
+
+ if (strcmp(class, EC_DEV_ADD) == 0) {
+ if (strcmp(subclass, ESC_DISK) == 0) {
+ sysevent_dev_add(phys_path, dev_name);
+ } else if (strcmp(subclass, ESC_LOFI) == 0) {
+ sysevent_lofi_add(phys_path, dev_name);
+ }
+ } else if (strcmp(class, EC_DEV_REMOVE) == 0) {
+ if (strcmp(subclass, ESC_DISK) == 0) {
+ sysevent_dev_remove(phys_path, dev_name);
+ } else if (strcmp(subclass, ESC_LOFI) == 0) {
+ sysevent_lofi_remove(phys_path, dev_name);
+ }
+ } else if (strcmp(class, EC_DEV_BRANCH) == 0) {
+ sysevent_dev_branch(phys_path);
+ }
+ }
+
+ if (err) {
+ g_error_free (err);
+ }
+
+ return (TRUE);
+}
+
+static void
+sysevent_dev_add(gchar *devfs_path, gchar *name)
+{
+ gchar *parent_devfs_path, *hotplug_devfs_path;
+ HalDevice *parent;
+
+ HAL_INFO (("dev_add: %s %s", name, devfs_path));
+
+ parent = hal_util_find_closest_ancestor (devfs_path, &parent_devfs_path, &hotplug_devfs_path);
+ if (parent == NULL) {
+ return;
+ }
+
+ HAL_INFO (("dev_add: parent=%s", parent_devfs_path));
+ HAL_INFO (("dev_add: real=%s", hotplug_devfs_path));
+
+ devinfo_add (parent, hotplug_devfs_path);
+
+ g_free (parent_devfs_path);
+ g_free (hotplug_devfs_path);
+
+ hotplug_event_process_queue ();
+}
+
+static void
+sysevent_dev_remove(gchar *devfs_path, gchar *name)
+{
+ HAL_INFO (("dev_remove: %s %s", name, devfs_path));
+
+ devinfo_remove_branch (devfs_path, NULL);
+ hotplug_event_process_queue ();
+}
+
+static void
+sysevent_dev_branch(gchar *devfs_path)
+{
+ HAL_INFO (("branch_remove: %s", devfs_path));
+
+ devinfo_remove_branch (devfs_path, NULL);
+ hotplug_event_process_queue ();
+}
+
+static void
+sysevent_lofi_add(gchar *devfs_path, gchar *name)
+{
+ di_node_t node;
+ const char *parent_udi;
+ HalDevice *d, *parent;
+
+ HAL_INFO (("lofi_add: %s %s", name, devfs_path));
+
+ if ((d = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "solaris.devfs_path", devfs_path)) == NULL) {
+ HAL_INFO (("device not found in GDL %s", devfs_path));
+ return;
+ }
+ parent_udi = hal_device_property_get_string (d, "info.parent");
+ if ((parent_udi == NULL) || (strlen(parent_udi) == 0)) {
+ HAL_INFO (("parent not found in GDL %s", parent_udi));
+ return;
+ }
+ if ((parent = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "info.udi", parent_udi)) == NULL) {
+ HAL_INFO (("parent not found in GDL %s", parent_udi));
+ return;
+ }
+
+ if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
+ HAL_INFO (("device not found in devinfo %s", devfs_path));
+ return;
+ }
+
+ HAL_INFO (("device %s parent %s", hal_device_get_udi (d), parent_udi));
+ devinfo_lofi_add_major (parent, node, devfs_path, NULL, TRUE, d);
+
+ di_fini (node);
+
+ hotplug_event_process_queue ();
+}
+
+static void
+sysevent_lofi_remove(gchar *parent_devfs_path, gchar *name)
+{
+ devinfo_lofi_remove_minor(parent_devfs_path, name);
+ hotplug_event_process_queue ();
+}
diff --git a/hald/solaris/sysevent.h b/hald/solaris/sysevent.h
new file mode 100644
index 0000000..4acfcbf
--- /dev/null
+++ b/hald/solaris/sysevent.h
@@ -0,0 +1,22 @@
+/***************************************************************************
+ *
+ * sysevent.h : definitions for Solaris sysevents
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#pragma ident "@(#)sysevent.h 1.2 06/10/13 SMI"
+
+#ifndef SYSEVENT_H
+#define SYSEVENT_H
+
+#include <glib.h>
+
+gboolean sysevent_init(void);
+void sysevent_fini(void);
+
+#endif /* SYSEVENT_H */
diff --git a/hald/util_helper.c b/hald/util_helper.c
index 5a83d8b..ee97026 100644
--- a/hald/util_helper.c
+++ b/hald/util_helper.c
@@ -46,6 +46,50 @@ extern char **environ;
static char **argv_buffer = NULL;
static size_t argv_size = 0;
+#ifdef sun
+#include <priv.h>
+void
+drop_privileges (int keep_auxgroups)
+{
+ priv_set_t *pPrivSet = NULL;
+ priv_set_t *lPrivSet = NULL;
+
+ /*
+ * Start with the 'basic' privilege set and then remove any
+ * of the 'basic' privileges that will not be needed.
+ */
+ if ((pPrivSet = priv_str_to_set("basic", ",", NULL)) == NULL) {
+ return;
+ }
+
+ /* Clear privileges we will not need from the 'basic' set */
+ (void) priv_delset(pPrivSet, PRIV_FILE_LINK_ANY);
+ (void) priv_delset(pPrivSet, PRIV_PROC_INFO);
+ (void) priv_delset(pPrivSet, PRIV_PROC_SESSION);
+
+ /* for sysevent need to be root and have this privilege */
+ (void) priv_addset(pPrivSet, PRIV_SYS_CONFIG);
+
+ /* Set the permitted privilege set. */
+ if (setppriv(PRIV_SET, PRIV_PERMITTED, pPrivSet) != 0) {
+ return;
+ }
+
+ /* Clear the limit set. */
+ if ((lPrivSet = priv_allocset()) == NULL) {
+ return;
+ }
+
+ priv_emptyset(lPrivSet);
+
+ if (setppriv(PRIV_SET, PRIV_LIMIT, lPrivSet) != 0) {
+ return;
+ }
+
+ priv_freeset(lPrivSet);
+}
+#else /* !sun */
+
/** Drop root privileges: Set the running user id to HAL_USER and
* group to HAL_GROUP, and optionally retain auxiliary groups of HAL_USER.
*/
@@ -86,6 +130,7 @@ drop_privileges (int keep_auxgroups)
exit (-1);
}
}
+#endif /* !sun */
void
hal_set_proc_title_init (int argc, char *argv[])
diff --git a/partutil/Makefile.am b/partutil/Makefile.am
index 5d409bb..67b369b 100644
--- a/partutil/Makefile.am
+++ b/partutil/Makefile.am
@@ -1,3 +1,4 @@
+if !HALD_COMPILE_SOLARIS
INCLUDES = @GLIB_CFLAGS@
@@ -9,3 +10,5 @@ libpartutil_la_LIBADD = @GLIB_LIBS@ @PAR
clean-local :
rm -f *~
+
+endif
diff --git a/tools/hal-storage-shared.c b/tools/hal-storage-shared.c
index 0b95a35..74bd89e 100644
--- a/tools/hal-storage-shared.c
+++ b/tools/hal-storage-shared.c
@@ -103,7 +103,7 @@ mtab_next (gpointer handle, char **mount
if (getmntent (handle, &mnt) == 0) {
if (mount_point != NULL) {
- *mount_point = g_strdup (mnt->mnt_mountp);
+ *mount_point = g_strdup (mnt.mnt_mountp);
}
return mnt.mnt_special;
} else {
More information about the hal-commit
mailing list