summaryrefslogtreecommitdiff
path: root/sysutils/hal
diff options
context:
space:
mode:
authorjmcneill <jmcneill>2008-11-25 23:10:23 +0000
committerjmcneill <jmcneill>2008-11-25 23:10:23 +0000
commit5dc3730f6d7f8520c8822662ef67a27d493d61f4 (patch)
tree0447589fba1775964f334dbc860bd4935aadffca /sysutils/hal
parent946ed47bd97702f0945e8711d66df55caf4d1fad (diff)
downloadpkgsrc-5dc3730f6d7f8520c8822662ef67a27d493d61f4.tar.gz
Initial import of NetBSD HAL backend. It doesn't do much useful yet, but
keeping things here makes development easier. Bump PKGREVISION.
Diffstat (limited to 'sysutils/hal')
-rw-r--r--sysutils/hal/Makefile25
-rw-r--r--sysutils/hal/PLIST.NetBSD4
-rw-r--r--sysutils/hal/distinfo6
-rw-r--r--sysutils/hal/files/hald-netbsd/Makefile.am23
-rw-r--r--sysutils/hal/files/hald-netbsd/addons/Makefile.am17
-rw-r--r--sysutils/hal/files/hald-netbsd/addons/addon-storage.c332
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo.c406
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo.h72
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_acpi.h44
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_cpu.h19
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_misc.c134
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_misc.h21
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_pci.c122
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_pci.h21
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_storage.c1671
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_storage.h30
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_usb.c229
-rw-r--r--sysutils/hal/files/hald-netbsd/devinfo_usb.h23
-rw-r--r--sysutils/hal/files/hald-netbsd/drvctl.c265
-rw-r--r--sysutils/hal/files/hald-netbsd/drvctl.h23
-rw-r--r--sysutils/hal/files/hald-netbsd/hal-file-monitor.c821
-rw-r--r--sysutils/hal/files/hald-netbsd/hotplug.c204
-rw-r--r--sysutils/hal/files/hald-netbsd/hotplug.h58
-rw-r--r--sysutils/hal/files/hald-netbsd/osspec.c193
-rw-r--r--sysutils/hal/files/hald-netbsd/osspec_netbsd.h21
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/Makefile.am20
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/cdutils.c379
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/cdutils.h61
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/fsutils.c217
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/fsutils.h25
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/probe-storage.c403
-rw-r--r--sysutils/hal/files/hald-netbsd/probing/probe-volume.c629
-rw-r--r--sysutils/hal/patches/patch-ag14
-rw-r--r--sysutils/hal/patches/patch-na41
-rw-r--r--sysutils/hal/patches/patch-nb12
35 files changed, 6570 insertions, 15 deletions
diff --git a/sysutils/hal/Makefile b/sysutils/hal/Makefile
index 920e04c449e..49304e8325f 100644
--- a/sysutils/hal/Makefile
+++ b/sysutils/hal/Makefile
@@ -1,8 +1,8 @@
-# $NetBSD: Makefile,v 1.4 2008/11/24 21:13:19 hasso Exp $
+# $NetBSD: Makefile,v 1.5 2008/11/25 23:10:23 jmcneill Exp $
#
DISTNAME= hal-0.5.11
-PKGREVISION= 3
+PKGREVISION= 4
CATEGORIES= sysutils
MASTER_SITES= http://hal.freedesktop.org/releases/
EXTRACT_SUFX= .tar.bz2
@@ -20,6 +20,7 @@ GNU_CONFIGURE= YES
USE_DIRS+= xdg-1.4
USE_PKGLOCALEDIR= YES
USE_TOOLS+= gmake intltool msgfmt perl pkg-config
+USE_TOOLS+= autoconf automake autoreconf
USE_LIBTOOL= YES
MAKE_DIRS= ${VARBASE}/cache/hald
@@ -43,6 +44,17 @@ CONFIGURE_ARGS+= --with-backend=freebsd
PLIST_SRC= PLIST.FreeBSD PLIST
.endif
+.if !empty(MACHINE_PLATFORM:MNetBSD-[5-9]*)
+CONFIGURE_ARGS+= --with-backend=netbsd
+PLIST_SRC= PLIST.NetBSD PLIST
+.endif
+
+.if ${OPSYS} == "Linux"
+.include "../../devel/libusb/buildlink3.mk"
+.include "../../sysutils/pciutils/buildlink3.mk"
+CONFIGURE_ARGS+= --with-backend=linux
+.endif
+
REPLACE_INTERPRETER+= bash
REPLACE.bash.old= /bin/bash
REPLACE.bash.new= ${SH}
@@ -59,10 +71,11 @@ PKG_HOME.haldaemon= ${VARBASE}/run/hal
FILES_SUBST+= HAL_USER=${HAL_USER}
FILES_SUBST+= HAL_GROUP=${HAL_GROUP}
-.if ${OPSYS} == "Linux"
-.include "../../devel/libusb/buildlink3.mk"
-.include "../../sysutils/pciutils/buildlink3.mk"
-.endif
+post-extract:
+ ${CP} -r ${FILESDIR}/hald-netbsd ${WRKSRC}/hald/netbsd
+
+pre-configure:
+ cd ${WRKSRC} && autoreconf -vi
.include "../../devel/GConf/schemas.mk"
.include "../../devel/glib2/buildlink3.mk"
diff --git a/sysutils/hal/PLIST.NetBSD b/sysutils/hal/PLIST.NetBSD
new file mode 100644
index 00000000000..1d36895b767
--- /dev/null
+++ b/sysutils/hal/PLIST.NetBSD
@@ -0,0 +1,4 @@
+@comment $NetBSD: PLIST.NetBSD,v 1.1 2008/11/25 23:10:23 jmcneill Exp $
+libexec/hald-addon-storage
+libexec/hald-probe-storage
+libexec/hald-probe-volume
diff --git a/sysutils/hal/distinfo b/sysutils/hal/distinfo
index dfe25c57ea2..c9944ae47d4 100644
--- a/sysutils/hal/distinfo
+++ b/sysutils/hal/distinfo
@@ -1,4 +1,4 @@
-$NetBSD: distinfo,v 1.4 2008/11/24 21:13:19 hasso Exp $
+$NetBSD: distinfo,v 1.5 2008/11/25 23:10:23 jmcneill Exp $
SHA1 (hal-0.5.11.tar.bz2) = 1ddb7895d2ddc2464b553ad11f7ba38860478ae9
RMD160 (hal-0.5.11.tar.bz2) = 741cfe82f0bc2d67106b24cfe526a754ab36e45f
@@ -9,7 +9,7 @@ SHA1 (patch-ac) = cffdb9caa947366ff88310a750ab502bd2d98db8
SHA1 (patch-ad) = 2a2732f82a4fd8d7ffa311b4a0e747208dc9ad1c
SHA1 (patch-ae) = ebc98ede0b6e9535825434f2dc6185193d837f36
SHA1 (patch-af) = 161b59ee30d59dbc9e0c79f7f3162bcec5480d99
-SHA1 (patch-ag) = 39b79fbcd99f9172afd492772c120161bb63a378
+SHA1 (patch-ag) = 3fd8b7d10b1a43311541d2c6ad67a944e286c5ec
SHA1 (patch-ah) = 6d801a2c30cee6199b25acf46d7e9866f6004182
SHA1 (patch-ai) = 2e11ee437e778f540f401335b4f022fe6e8e8fee
SHA1 (patch-aj) = 533289d4e1328a89ad9e4ce6c1b28e32139b70db
@@ -18,3 +18,5 @@ SHA1 (patch-al) = 8279947ecb720f3e99777dae8c20d4afe0e19039
SHA1 (patch-am) = 6a4940006e583300d9a983511bdcb05268f74b1a
SHA1 (patch-an) = 0307b2f0f6bb5e4a6d7bf837163e74749b7d24b2
SHA1 (patch-ao) = 9099fa4783921a0389b874b8f6d3f7b890810b34
+SHA1 (patch-na) = bbeb48b6fa909c8fcf7cbaf609019a0d4d4b8082
+SHA1 (patch-nb) = 1693b7a2faa5bee20a594f0b60b8ff6caea0efdc
diff --git a/sysutils/hal/files/hald-netbsd/Makefile.am b/sysutils/hal/files/hald-netbsd/Makefile.am
new file mode 100644
index 00000000000..fd46e3aca25
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/Makefile.am
@@ -0,0 +1,23 @@
+
+SUBDIRS = probing addons .
+
+AM_CPPFLAGS = \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
+ -DPACKAGE_LOCALSTATEDIR=\""$(localstatedir)"\" \
+ -I$(top_srcdir) -I.. \
+ @GLIB_CFLAGS@ @DBUS_CFLAGS@ @POLKIT_CFLAGS@
+
+if HALD_COMPILE_NETBSD
+noinst_LTLIBRARIES = libhald_netbsd.la
+endif
+
+libhald_netbsd_la_SOURCES = \
+ osspec.c drvctl.c \
+ devinfo.c devinfo_misc.c \
+ hotplug.c hal-file-monitor.c
+# devinfo_pci.c devinfo_storage.c devinfo_usb.c
+
+libhald_netbsd_la_LDFLAGS = -lprop
diff --git a/sysutils/hal/files/hald-netbsd/addons/Makefile.am b/sysutils/hal/files/hald-netbsd/addons/Makefile.am
new file mode 100644
index 00000000000..8434fb03347
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/addons/Makefile.am
@@ -0,0 +1,17 @@
+
+AM_CPPFLAGS = \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
+ -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_NETBSD
+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/sysutils/hal/files/hald-netbsd/addons/addon-storage.c b/sysutils/hal/files/hald-netbsd/addons/addon-storage.c
new file mode 100644
index 00000000000..493430c086c
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/addons/addon-storage.c
@@ -0,0 +1,332 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#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/statvfs.h>
+#include <sys/dkio.h>
+#include <dev/scsipi/scsi_spc.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsipi_cd.h>
+#include <sys/scsiio.h>
+
+#include <libhal.h>
+
+#include <logger.h>
+
+#define SLEEP_PERIOD 5
+
+enum discstate {
+ DISC_INSERTED,
+ DISC_EJECTED,
+ DISC_NONE,
+ DISC_UNKNOWN
+};
+
+static enum discstate
+scsi_test_unit_ready (int fd)
+{
+ struct scsi_test_unit_ready tur;
+ scsireq_t req;
+
+ memset(&tur, 0, sizeof(tur));
+ tur.opcode = SCSI_TEST_UNIT_READY;
+
+ memset(&req, 0, sizeof(req));
+ memcpy(req.cmd, &tur, sizeof(tur));
+ req.cmdlen = sizeof(tur);
+ req.databuf = NULL;
+ req.datalen = 0;
+ req.timeout = 10000;
+ req.flags = 0;
+ req.senselen = SENSEBUFLEN;
+
+ if (ioctl(fd, SCIOCCOMMAND, &req) == -1)
+ return DISC_UNKNOWN;
+ if (req.retsts == SCCMD_OK)
+ return DISC_INSERTED;
+ return DISC_EJECTED;
+}
+
+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)
+{
+ int count;
+ struct statvfs *statvfs;
+
+ count = getmntinfo(&statvfs, ST_WAIT);
+ while (count-- > 0) {
+ if (strcmp(statvfs->f_mntfromname, device_file) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+close_device (int *fd)
+{
+ if (*fd > 0) {
+ close (*fd);
+ *fd = -1;
+ }
+}
+
+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;
+
+ 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 = DISC_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 */
+ state = scsi_test_unit_ready (fd);
+
+ 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 DISC_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 DISC_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 DISC_UNKNOWN:
+ default:
+ HAL_DEBUG (("Device gone detected on %s", device_file));
+ last_state = state;
+
+ unmount_childs (ctx, udi);
+ close_device (&fd);
+ goto out;
+
+ }
+ }
+ }
+
+out:
+ if (ctx != NULL) {
+ my_dbus_error_free (&error);
+ libhal_ctx_shutdown (ctx, &error);
+ libhal_ctx_free (ctx);
+ }
+
+ return 0;
+}
diff --git a/sysutils/hal/files/hald-netbsd/devinfo.c b/sysutils/hal/files/hald-netbsd/devinfo.c
new file mode 100644
index 00000000000..4977dc53a98
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo.c
@@ -0,0 +1,406 @@
+/***************************************************************************
+ *
+ * devinfo.c : main file for drvctl-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
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include <sys/drvctlio.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_netbsd.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_pci.h"
+#include "devinfo_storage.h"
+#include "devinfo_usb.h"
+#include "devinfo_misc.h"
+#include "devinfo_cpu.h"
+#include "drvctl.h"
+
+void devinfo_add_subtree(HalDevice *parent, const char *devnode, gboolean is_root);
+
+void
+devinfo_add(HalDevice *parent, gchar *name)
+{
+ devinfo_add_subtree (parent, name, TRUE);
+}
+
+void
+devinfo_add_subtree(HalDevice *parent, const char *devnode, gboolean is_root)
+{
+ HalDevice *d;
+ struct devlistargs laa;
+ int i;
+
+ HAL_INFO (("add_subtree: %s", devnode));
+
+ if (parent == NULL) {
+ parent = devinfo_add_node (NULL, devnode);
+ }
+
+ if (drvctl_list (devnode, &laa) == -1) {
+ HAL_INFO (("devinfo_add_subtree: drvctl_list failed"));
+ return;
+ }
+
+ for (i = 0; i < laa.l_children; i++) {
+ d = devinfo_add_node (parent, laa.l_childname[i]);
+ if (d)
+ devinfo_add_subtree (d, laa.l_childname[i], FALSE);
+ }
+
+ if (laa.l_childname)
+ free(laa.l_childname);
+}
+
+void
+devinfo_set_default_properties (HalDevice *d, HalDevice *parent, const char *devnode, char *devfs_path)
+{
+ char *driver_name, *s;
+ const char *s1;
+ char udi[HAL_PATH_MAX];
+
+ if (parent != NULL) {
+ char *pdevice = hal_device_property_get_string (parent, "netbsd.device");
+ if (pdevice) {
+ gchar *path;
+ if (strcmp (pdevice, "mainbus0") == 0)
+ pdevice = "computer";
+ path = g_strdup_printf ("/org/freedesktop/Hal/devices/%s", pdevice);
+ hal_device_property_set_string (d, "info.parent", path);
+ g_free (path);
+ }
+ } else {
+ gchar pdevnode[512];
+ char *pdevice = pdevnode;
+ if (drvctl_find_parent (devnode, pdevnode) == TRUE) {
+ gchar *path;
+ if (strcmp (pdevnode, "mainbus0") == 0)
+ pdevice = "computer";
+ path = g_strdup_printf ("/org/freedesktop/Hal/devices/%s", pdevice);
+ hal_device_property_set_string (d, "info.parent", path);
+ g_free (path);
+ } else
+ hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local");
+ }
+
+ hald_compute_udi (udi, sizeof (udi),
+ "/org/freedesktop/Hal/devices/%s", devnode);
+ hal_device_set_udi (d, udi);
+
+#if notyet
+ 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));
+ }
+#else
+ hal_device_property_set_string (d, "info.product", devnode);
+#endif
+
+ hal_device_property_set_string (d, "netbsd.device", devnode);
+
+#if notyet
+ 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);
+ }
+ }
+#endif
+}
+
+/* device handlers, ordered specific to generic */
+static DevinfoDevHandler *devinfo_handlers[] = {
+ &devinfo_computer_handler,
+ &devinfo_cpu_handler,
+#if notyet
+ &devinfo_ide_handler,
+ &devinfo_scsi_handler,
+ &devinfo_floppy_handler,
+ &devinfo_usb_handler,
+ &devinfo_pci_handler,
+ &devinfo_lofi_handler,
+#endif
+ &devinfo_default_handler,
+ NULL
+};
+
+HalDevice *
+devinfo_add_node(HalDevice *parent, const char *devnode)
+{
+ HalDevice *d = NULL;
+ char *devfs_path;
+ char *device_type = NULL;
+ DevinfoDevHandler *handler;
+ int i;
+
+ devfs_path = g_strdup_printf ("%s", devnode);
+
+#if notyet
+ (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
+ &device_type);
+#else
+ device_type = "unknown";
+#endif
+
+ for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) {
+ handler = devinfo_handlers[i];
+ d = handler->add (parent, devnode, devfs_path, device_type);
+ }
+
+ g_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);
+
+#if 0
+ /* Process preprobe fdi files */
+ di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
+#endif
+
+ /* 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 *devnode, 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 (),
+ "netbsd.device", devnode);
+ if (d == NULL)
+ return;
+ }
+
+ HAL_INFO (("remove_branch: %s %s\n", devnode, 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, "netbsd.device"), child);
+ }
+ g_slist_free (children);
+ HAL_INFO (("remove_branch: done with children"));
+
+ /* then remove self */
+ HAL_INFO (("remove_branch: queueing %s", devnode));
+ devinfo_remove_enqueue (devnode, 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 notyet
+ 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);
+ }
+#else
+#warning hotplug_event_begin_remove_devinfo TODO
+ hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
+#endif
+}
+
+gboolean
+devinfo_device_rescan (HalDevice *d)
+{
+#if notyet
+ if (hal_device_has_capability (d, "block")) {
+ return (devinfo_storage_device_rescan (d));
+ } else {
+ return (FALSE);
+ }
+#else
+#warning devinfo_device_rescan TODO
+ return FALSE;
+#endif
+}
diff --git a/sysutils/hal/files/hald-netbsd/devinfo.h b/sysutils/hal/files/hald-netbsd/devinfo.h
new file mode 100644
index 00000000000..6ed0dd0f5ef
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ *
+ * devinfo.h : definitions for libdevinfo-based device enumeration
+ *
+ * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_H
+#define DEVINFO_H
+
+#include <glib.h>
+
+#include <prop/proplib.h>
+
+#include "../hald.h"
+#include "../device_info.h"
+
+typedef struct DevinfoDevHandler_s
+{
+ HalDevice *(*add) (HalDevice *parent, const char *devnode, 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);
+HalDevice *devinfo_add_node(HalDevice *parent, const char *devnode);
+void devinfo_set_default_properties (HalDevice *d, HalDevice *parent, const char *devnode, 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/sysutils/hal/files/hald-netbsd/devinfo_acpi.h b/sysutils/hal/files/hald-netbsd/devinfo_acpi.h
new file mode 100644
index 00000000000..6e841cc48ec
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_acpi.h
@@ -0,0 +1,44 @@
+/***************************************************************************
+ *
+ * devinfo_acpi.h : definitions for acpi devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_ACPI_H
+#define DEVINFO_ACPI_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_acpi_handler;
+extern DevinfoDevHandler devinfo_power_button_handler;
+
+#define MINOR_SHIFT 8
+#define MINOR2TYPE(minor) ((minor) >> MINOR_SHIFT)
+
+/* Battery device types */
+enum batt_type {
+ BATT_TYPE_UNKNOWN = -1,
+ BATT_TYPE_CBAT,
+ BATT_TYPE_AC,
+ BATT_TYPE_SBAT
+};
+
+HalDevice *devinfo_battery_add_major(HalDevice *parent, const char *devnode,
+ char *devfs_path, char *device_type, gboolean rescan, HalDevice *battery_d);
+void devinfo_acpi_add_minor(HalDevice *parent, const char *devnode,
+ char *minor_path, dev_t dev);
+void devinfo_battery_remove_minor(char *parent_devfs_path, gchar *udi);
+void devinfo_battery_rescan(char *parent_devfs_path, gchar *udi);
+const gchar *devinfo_acpi_get_prober(HalDevice *d, int *timeout);
+void devinfo_power_button_event(void);
+void devinfo_brightness_hotkeys_event(char *subclass);
+
+void devinfo_lid_event(char *subclass, gchar *udi);
+gboolean devinfo_lid_rescan(HalDevice *d);
+
+#endif /* DEVINFO_ACPI_H */
diff --git a/sysutils/hal/files/hald-netbsd/devinfo_cpu.h b/sysutils/hal/files/hald-netbsd/devinfo_cpu.h
new file mode 100644
index 00000000000..441acdf10e6
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_cpu.h
@@ -0,0 +1,19 @@
+/***************************************************************************
+ *
+ * devinfo_cpu.h : definition for cpu devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_CPU_H
+#define DEVINFO_CPU_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_cpu_handler;
+
+#endif /* DEVINFO_CPU_H */
diff --git a/sysutils/hal/files/hald-netbsd/devinfo_misc.c b/sysutils/hal/files/hald-netbsd/devinfo_misc.c
new file mode 100644
index 00000000000..e2a0f09d8b6
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_misc.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/utsname.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 *, const char *, char *, char *);
+static HalDevice *devinfo_cpu_add(HalDevice *, const char *, char *,char *);
+static HalDevice *devinfo_default_add(HalDevice *, const char *, 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, const char *devnode, char *devfs_path, char *device_type)
+{
+ HalDevice *d, *local_d;
+ struct utsname un;
+
+ if (strcmp (devnode, "mainbus0") != 0) {
+ return (NULL);
+ }
+
+ HAL_INFO (("devinfo_computer_add parent=%p devnode=%s devfs_path=%s device_type=%s",
+ parent, devnode, devfs_path, device_type));
+
+ d = hal_device_new ();
+
+ hal_device_property_set_string (d, "info.subsystem", "unknown");
+ hal_device_property_set_string (d, "info.product", "Computer");
+ hal_device_set_udi (d, "/org/freedesktop/Hal/devices/computer");
+ hal_device_property_set_string (d, "netbsd.device", devnode);
+
+ 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.subsystem", "unknown");
+ hal_device_property_set_string (local_d, "info.product", "Local devices");
+ hal_device_property_set_string (local_d, "netbsd.device", devnode);
+
+ devinfo_add_enqueue (local_d, devnode, &devinfo_default_handler);
+
+ return (local_d);
+}
+
+static HalDevice *
+devinfo_cpu_add(HalDevice *parent, const char *devnode, char *devfs_path, char *device_type)
+{
+ HalDevice *d;
+
+ if (strncmp(devnode, "cpu", 3) != 0) {
+ return (NULL);
+ }
+
+ HAL_INFO (("devinfo_cpu_add: parent=%p devnode=%s devfs_path=%s device_type=%s",
+ parent, devnode, devfs_path, device_type));
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, devnode, devnode);
+ hal_device_add_capability (d, "processor");
+
+ devinfo_add_enqueue (d, devnode, &devinfo_cpu_handler);
+
+ return (d);
+}
+
+static HalDevice *
+devinfo_default_add(HalDevice *parent, const char *devnode, char *devfs_path, char *device_type)
+{
+ char *driver_name;
+ const char *parent_path;
+ HalDevice *d;
+
+ d = hal_device_new ();
+
+ devinfo_set_default_properties (d, parent, devnode, devnode);
+
+ devinfo_add_enqueue (d, devnode, &devinfo_default_handler);
+
+ return (d);
+}
diff --git a/sysutils/hal/files/hald-netbsd/devinfo_misc.h b/sysutils/hal/files/hald-netbsd/devinfo_misc.h
new file mode 100644
index 00000000000..ef666ff38c9
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_misc.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * devinfo_misc.h : definitions for misc devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_MISC_H
+#define DEVINFO_MISC_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_computer_handler;
+extern DevinfoDevHandler devinfo_keyboard_handler;
+extern DevinfoDevHandler devinfo_default_handler;
+
+#endif /* DEVINFO_MISC_H */
diff --git a/sysutils/hal/files/hald-netbsd/devinfo_pci.c b/sysutils/hal/files/hald-netbsd/devinfo_pci.c
new file mode 100644
index 00000000000..415d2f6dc9f
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/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.subsystem");
+ 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.subsystem", "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/sysutils/hal/files/hald-netbsd/devinfo_pci.h b/sysutils/hal/files/hald-netbsd/devinfo_pci.h
new file mode 100644
index 00000000000..dbeb4f6e474
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/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 "%Z%%M% %I% %E% SMI"
+
+#ifndef DEVINFO_PCI_H
+#define DEVINFO_PCI_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_pci_handler;
+
+#endif /* DEVINFO_PCI_H */
diff --git a/sysutils/hal/files/hald-netbsd/devinfo_storage.c b/sysutils/hal/files/hald-netbsd/devinfo_storage.c
new file mode 100644
index 00000000000..ca711bb9dbf
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_storage.c
@@ -0,0 +1,1671 @@
+/***************************************************************************
+ *
+ * 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_netbsd.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.subsystem", "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.subsystem", "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");
+
+ hald_compute_udi (udi, sizeof (udi),
+ "%s/%s%d", hal_device_get_udi (parent),
+ driver_name, di_instance (node));
+ hal_device_set_udi (d, 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.subsystem", "scsi");
+
+ hald_compute_udi (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_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");
+
+ hald_compute_udi (udi, sizeof (udi),
+ "%s/sd%d", hal_device_get_udi (parent),
+ di_instance (node));
+ hal_device_set_udi (d, 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.subsystem", "pseudo");
+
+ hald_compute_udi (udi, sizeof (udi),
+ "%s/%s%d", hal_device_get_udi (parent),
+ di_node_name(node), di_instance (node));
+ hal_device_set_udi (d, 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");
+
+ hald_compute_udi (udi, sizeof (udi),
+ "%s/%s", hal_device_get_udi (parent), slice);
+ hal_device_set_udi (d, 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", "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.subsystem");
+ 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.originating_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, FALSE);
+ }
+ snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
+ hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf, FALSE);
+}
+
+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/sysutils/hal/files/hald-netbsd/devinfo_storage.h b/sysutils/hal/files/hald-netbsd/devinfo_storage.h
new file mode 100644
index 00000000000..9238fe539c6
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_storage.h
@@ -0,0 +1,30 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_STORAGE_H
+#define DEVINFO_STORAGE_H
+
+#include "devinfo.h"
+
+extern DevinfoDevHandler devinfo_ide_handler;
+extern DevinfoDevHandler devinfo_scsi_handler;
+extern DevinfoDevHandler devinfo_pcata_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, const char *devinfo, 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/sysutils/hal/files/hald-netbsd/devinfo_usb.c b/sysutils/hal/files/hald-netbsd/devinfo_usb.c
new file mode 100644
index 00000000000..a93327296c5
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_usb.c
@@ -0,0 +1,229 @@
+/***************************************************************************
+ *
+ * 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.subsystem", "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.subsystem", "usb");
+
+ hald_compute_udi (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.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);
+
+ hald_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.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/sysutils/hal/files/hald-netbsd/devinfo_usb.h b/sysutils/hal/files/hald-netbsd/devinfo_usb.h
new file mode 100644
index 00000000000..01864c20111
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/devinfo_usb.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ *
+ * devinfo_usb.h : definitions for USB devices
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DEVINFO_USB_H
+#define DEVINFO_USB_H
+
+#include "devinfo.h"
+
+#define bcd(a) ((((a) & 0xf000) >> 12) * 1000 + (((a) & 0xf00) >> 8) * 100 + (((a) & 0xf0) >> 4) * 10 + ((a) & 0xf))
+
+extern DevinfoDevHandler devinfo_usb_handler;
+
+HalDevice *devinfo_usb_add(HalDevice *parent, const char *devnode, char *devfs_path, char *device_type);
+
+#endif /* DEVINFO_USB_H */
diff --git a/sysutils/hal/files/hald-netbsd/drvctl.c b/sysutils/hal/files/hald-netbsd/drvctl.c
new file mode 100644
index 00000000000..a1b697bbc50
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/drvctl.c
@@ -0,0 +1,265 @@
+/***************************************************************************
+ *
+ * drvctl.c : NetBSD drvctl events
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#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/ioctl.h>
+#include <sys/drvctlio.h>
+#include <sys/dkio.h>
+#include <sys/stat.h>
+#include <sys/drvctlio.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_netbsd.h"
+#include "hotplug.h"
+#include "devinfo.h"
+#include "devinfo_storage.h"
+#include "drvctl.h"
+
+static gboolean drvctl_iochannel_data(GIOChannel *, GIOCondition, gpointer);
+static void drvctl_dev_add(gchar *);
+static void drvctl_dev_remove(gchar *);
+static void drvctl_dev_branch(gchar *);
+
+static int drvctl_fd;
+static GIOChannel *drvctl_iochannel;
+
+gboolean
+drvctl_init(void)
+{
+ drvctl_fd = open (DRVCTLDEV, O_RDWR);
+ if (drvctl_fd == -1) {
+ HAL_INFO (("open(%s, O_RDWR) failed: %s", DRVCTLDEV, strerror(errno)));
+ return FALSE;
+ }
+
+ drvctl_iochannel = g_io_channel_unix_new (drvctl_fd);
+ if (drvctl_iochannel == NULL) {
+ HAL_INFO (("g_io_channel_unix_new failed"));
+ return FALSE;
+ }
+ g_io_add_watch (drvctl_iochannel, G_IO_IN, drvctl_iochannel_data, NULL);
+
+ return TRUE;
+}
+
+void
+drvctl_fini(void)
+{
+ HAL_INFO (("drvctl_fini"));
+}
+
+static gboolean
+drvctl_iochannel_data (GIOChannel *source,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ prop_dictionary_t ev;
+ const char *event, *device;
+ int res;
+
+ HAL_INFO (("drvctl_iochannel_data"));
+
+ res = prop_dictionary_recv_ioctl (drvctl_fd, DRVGETEVENT, &ev);
+ if (res) {
+ HAL_WARNING (("DRVGETEVENT failed: %s", strerror(errno)));
+ return FALSE;
+ }
+
+ if (!prop_dictionary_get_cstring_nocopy (ev, "event", &event)) {
+ HAL_WARNING (("DRVGETEVENT missing \"event\" parameter"));
+ goto done;
+ }
+ if (!prop_dictionary_get_cstring_nocopy (ev, "device", &device)) {
+ HAL_WARNING (("DRVGETEVENT missing \"device\" parameter"));
+ goto done;
+ }
+
+ HAL_INFO (("DRVGETEVENT event=%s device=%s", event, device));
+
+
+ if (strcmp (event, "device-attach") == 0) {
+ drvctl_dev_add (device);
+ } else {
+ drvctl_dev_remove (device);
+ }
+
+done:
+ prop_object_release(ev);
+ return TRUE;
+}
+
+static void
+drvctl_dev_add(gchar *name)
+{
+ HalDevice *parent, *d;
+ gchar pdevnode[512];
+
+ if (drvctl_find_parent (name, pdevnode) == FALSE) {
+ HAL_INFO (("dev_add: name=%s orphan", name));
+ parent = NULL;
+ } else {
+ parent = hal_device_store_match_key_value_string (
+ hald_get_gdl(), "netbsd.device", pdevnode);
+ if (parent == NULL)
+ HAL_INFO (("dev_add: name=%s but netbsd.device=%s not found", pdevnode));
+ }
+
+ d = devinfo_add_node (parent, name);
+ if (d == NULL)
+ HAL_WARNING (("dev_add: couldn't add %s node (parent=%p)", name, parent));
+
+ hotplug_event_process_queue ();
+}
+
+static void
+drvctl_dev_remove(gchar *name)
+{
+ HAL_INFO (("dev_remove: %s", name));
+
+ devinfo_remove_branch (name, NULL);
+ hotplug_event_process_queue ();
+}
+
+static void
+drvctl_dev_branch(gchar *name)
+{
+ HAL_INFO (("branch_remove: %s", name));
+
+ devinfo_remove_branch (name, NULL);
+ hotplug_event_process_queue ();
+}
+
+int
+drvctl_list(const gchar *name, struct devlistargs *laa)
+{
+ size_t children;
+
+ /* HAL_INFO (("drvctl_list: %s", name)); */
+
+ memset (laa, 0, sizeof (*laa));
+ strlcpy (laa->l_devname, name, sizeof (laa->l_devname));
+ if (ioctl (drvctl_fd, DRVLISTDEV, laa) == -1) {
+ HAL_INFO (("DRVLISTDEV/1 failed: %s", strerror(errno)));
+ return -1;
+ }
+ children = laa->l_children;
+ /* HAL_INFO (("%s: found %d children", name, children)); */
+ if (children == 0)
+ return -1;
+ laa->l_childname = malloc (children * sizeof (laa->l_childname[0]));
+ if (laa->l_childname == NULL) {
+ HAL_INFO (("drvctl_list couldn't allocate %d children: %s\n", children, strerror(errno)));
+ return -1;
+ }
+ if (ioctl (drvctl_fd, DRVLISTDEV, laa) == -1) {
+ HAL_INFO (("DRVLISTDEV/2 failed: %s", strerror(errno)));
+ return -1;
+ }
+ if (children != laa->l_children)
+ HAL_WARNING (("DRVLISTDEV/3 expected %d children, got %d", children, laa->l_childname));
+}
+
+static gboolean
+drvctl_find_device_with_child(const gchar *curnode, const gchar *devnode,
+ char *parent)
+{
+ struct devlistargs laa;
+ u_int i;
+
+ if (drvctl_list (curnode, &laa) == -1)
+ return FALSE;
+
+ for (i = 0; i < laa.l_children; i++) {
+ if (strcmp (laa.l_childname[i], devnode) == 0) {
+ strlcpy(parent, curnode, 16);
+ free(laa.l_childname);
+ return TRUE;
+ }
+ if (drvctl_find_device_with_child (laa.l_childname[i], devnode, parent) == TRUE) {
+ free(laa.l_childname);
+ return TRUE;
+ }
+ }
+
+ if (laa.l_childname)
+ free(laa.l_childname);
+
+ /* HAL_INFO (("%s: couldn't find device with child %s", curnode, devnode)); */
+ return FALSE;
+}
+
+gboolean
+drvctl_find_parent(const gchar *devnode, char *parent)
+{
+ return drvctl_find_device_with_child("mainbus0", devnode, parent);
+}
+
+#if 0
+static void
+drvctl_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
+drvctl_lofi_remove(gchar *parent_devfs_path, gchar *name)
+{
+ devinfo_lofi_remove_minor(parent_devfs_path, name);
+ hotplug_event_process_queue ();
+}
+#endif
diff --git a/sysutils/hal/files/hald-netbsd/drvctl.h b/sysutils/hal/files/hald-netbsd/drvctl.h
new file mode 100644
index 00000000000..b70e7200d79
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/drvctl.h
@@ -0,0 +1,23 @@
+/***************************************************************************
+ *
+ * drvctl.h : definitions for NetBSD drvctl events
+ *
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifndef DRVCTL_H
+#define DRVCTL_H
+
+#include <glib.h>
+#include <sys/drvctlio.h>
+
+gboolean drvctl_init(void);
+void drvctl_fini(void);
+int drvctl_list(const gchar *devnode, struct devlistargs *laa);
+gboolean drvctl_find_parent(const gchar *devnode, char *parent);
+
+#endif /* DRVCTL_H */
diff --git a/sysutils/hal/files/hald-netbsd/hal-file-monitor.c b/sysutils/hal/files/hald-netbsd/hal-file-monitor.c
new file mode 100644
index 00000000000..6eea97f1f78
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/hal-file-monitor.c
@@ -0,0 +1,821 @@
+/***************************************************************************
+ * CVSID: $Id: hal-file-monitor.c,v 1.1 2008/11/25 23:10:23 jmcneill Exp $
+ *
+ * hal-file-monitor.c: Kqueue-based file monitor
+ *
+ * Copyright (C) 2007 Joe Marcus Clarke <marcus@FreeBSD.org>
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <time.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/event.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <glib-object.h>
+
+#include "../hal-file-monitor.h"
+
+#define HAL_FILE_MONITOR_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), HAL_TYPE_FILE_MONITOR, HalFileMonitorPrivate))
+
+#define VN_NOTE_CHANGED (NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_LINK)
+#define VN_NOTE_DELETED (NOTE_DELETE | NOTE_REVOKE)
+#define VN_NOTE_ALL (VN_NOTE_CHANGED | VN_NOTE_DELETED | NOTE_RENAME)
+
+typedef struct
+{
+ char *path;
+ int omask;
+ gboolean isdir;
+ HalFileMonitorNotifyFunc func;
+ gpointer udata;
+ GHashTable *dir_contents;
+} FileKqueueData;
+
+typedef struct
+{
+ char *path;
+ time_t atime;
+ gboolean owner;
+ HalFileMonitorNotifyFunc func;
+ gpointer udata;
+} FileAccessData;
+
+struct HalFileMonitorPrivate
+{
+ int kqueue_fd;
+ guint io_watch;
+ guint access_source;
+
+ gboolean initialized_kqueue;
+
+ GHashTable *fd_to_kdata;
+ GHashTable *fd_to_adata;
+};
+
+G_DEFINE_TYPE (HalFileMonitor, hal_file_monitor, G_TYPE_OBJECT)
+
+static gpointer monitor_object = NULL;
+
+static void hal_file_monitor_finalize (GObject *object);
+static GHashTable *get_dir_contents (const char *path);
+static GHashTable *diff_dir_contents (FileKqueueData *data, GSList **added, GSList **removed);
+static int hal_mask_to_kmask (int mask);
+static void monitor_release_kdata (HalFileMonitor *monitor, int fd, FileKqueueData *data);
+static void monitor_release_adata (HalFileMonitor *monitor, int fd, FileAccessData *data);
+static gboolean remove_kdata_foreach (gpointer fd, FileKqueueData *data, HalFileMonitor *monitor);
+static gboolean remove_adata_foreach (gpointer fd, FileAccessData *data, HalFileMonitor *monitor);
+static void hal_file_monitor_remove_kdata (HalFileMonitor *monitor, guint id);
+static void hal_file_monitor_remove_adata (HalFileMonitor *monitor, guint id);
+static void setup_monitor (HalFileMonitor *monitor);
+static void close_monitor (HalFileMonitor *monitor);
+static gboolean hal_file_access_monitor (gpointer data);
+/*static char *fflags_to_str (int fflags);*/
+static void emit_monitor_event (HalFileMonitor *monitor, HalFileMonitorEvent event, const char *path, HalFileMonitorNotifyFunc func, gpointer udata);
+static gboolean handle_kqueue_event (GIOChannel *source, GIOCondition condition, gpointer udata);
+
+GQuark
+hal_file_monitor_error_quark (void)
+{
+ static GQuark ret = 0;
+ if (ret == 0)
+ {
+ ret = g_quark_from_static_string ("hal_file_monitor_error");
+ }
+
+ return ret;
+}
+
+static int
+hal_mask_to_kmask (int mask)
+{
+ int kmask = 0;
+
+ if (mask & HAL_FILE_MONITOR_EVENT_CREATE)
+ {
+ kmask |= NOTE_WRITE | NOTE_LINK;
+ }
+
+ if (mask & HAL_FILE_MONITOR_EVENT_DELETE)
+ {
+ kmask |= NOTE_WRITE | NOTE_LINK | VN_NOTE_DELETED;
+ }
+
+ if (mask & HAL_FILE_MONITOR_EVENT_CHANGE)
+ {
+ kmask |= VN_NOTE_CHANGED;
+ }
+
+ return kmask;
+}
+
+guint
+hal_file_monitor_add_notify (HalFileMonitor *monitor,
+ const char *path,
+ int mask,
+ HalFileMonitorNotifyFunc notify_func,
+ gpointer data)
+{
+ struct kevent ev;
+ struct stat sb;
+ int fd;
+ int id = 0;
+
+ if (! monitor->priv->initialized_kqueue)
+ {
+ return id;
+ }
+
+ fd = open (path, O_RDONLY);
+ if (fd < 0)
+ {
+ return id;
+ }
+
+ if (fstat (fd, &sb) == -1)
+ {
+ close (fd);
+ return id;
+ }
+
+ if (mask & HAL_FILE_MONITOR_EVENT_ACCESS)
+ {
+ FileAccessData *adata;
+
+ adata = g_new0 (FileAccessData, 1);
+ adata->path = g_strdup (path);
+ adata->atime = sb.st_atime;
+ adata->func = notify_func;
+ adata->udata = data;
+ if (mask == HAL_FILE_MONITOR_EVENT_ACCESS)
+ {
+ /* We will close the file descriptor when we release the adata. */
+ adata->owner = TRUE;
+ }
+ g_hash_table_insert (monitor->priv->fd_to_adata,
+ GINT_TO_POINTER (fd),
+ adata);
+ id = fd;
+ }
+
+ if ((mask & HAL_FILE_MONITOR_EVENT_CREATE) ||
+ (mask & HAL_FILE_MONITOR_EVENT_DELETE) ||
+ (mask & HAL_FILE_MONITOR_EVENT_CHANGE))
+ {
+ FileKqueueData *kdata;
+ int kmask;
+ gboolean isdir;
+
+ kmask = hal_mask_to_kmask (mask);
+
+ isdir = (sb.st_mode & S_IFDIR) != 0;
+ if (! isdir && mask == HAL_FILE_MONITOR_EVENT_CREATE)
+ {
+ /* We can't monitor creation on a file. */
+ goto done;
+ }
+
+ kdata = g_new0 (FileKqueueData, 1);
+ kdata->path = g_strdup (path);
+ kdata->omask = mask;
+ kdata->isdir = isdir;
+ kdata->func = notify_func;
+ kdata->udata = data;
+ if (isdir)
+ {
+ kdata->dir_contents = get_dir_contents (path);
+ }
+
+ /*g_warning ("XXX: Adding event with mask %s", fflags_to_str (kmask));*/
+ EV_SET (&ev, fd, EVFILT_VNODE, EV_ADD | EV_ENABLE | EV_CLEAR,
+ kmask, 0, monitor);
+ if (kevent (monitor->priv->kqueue_fd, &ev, 1, NULL, 0, NULL) < 0)
+ {
+ monitor_release_kdata (monitor, fd, kdata);
+ goto done;
+ }
+ g_hash_table_insert (monitor->priv->fd_to_kdata,
+ GINT_TO_POINTER (fd),
+ kdata);
+ id = fd;
+ }
+
+done:
+ return id;
+}
+
+static void
+hal_file_monitor_remove_kdata (HalFileMonitor *monitor,
+ guint id)
+{
+ FileKqueueData *kdata;
+
+ kdata = (FileKqueueData *) g_hash_table_lookup (monitor->priv->fd_to_kdata, GINT_TO_POINTER (id));
+
+ if (kdata)
+ {
+ g_hash_table_remove (monitor->priv->fd_to_kdata, GINT_TO_POINTER (id));
+ monitor_release_kdata (monitor, id, kdata);
+ }
+}
+
+static void
+hal_file_monitor_remove_adata (HalFileMonitor *monitor,
+ guint id)
+{
+ FileAccessData *adata;
+
+ adata = (FileAccessData *) g_hash_table_lookup (monitor->priv->fd_to_adata, GINT_TO_POINTER (id));
+
+ if (adata)
+ {
+ g_hash_table_remove (monitor->priv->fd_to_adata, GINT_TO_POINTER (id));
+ monitor_release_adata (monitor, id, adata);
+ }
+}
+
+void
+hal_file_monitor_remove_notify (HalFileMonitor *monitor,
+ guint id)
+{
+ if (! monitor->priv->initialized_kqueue)
+ return;
+
+ hal_file_monitor_remove_kdata (monitor, id);
+ hal_file_monitor_remove_adata (monitor, id);
+
+}
+
+static void
+monitor_release_kdata (HalFileMonitor *monitor,
+ int fd,
+ FileKqueueData *data)
+{
+ g_free (data->path);
+ data->path = NULL;
+
+ if (data->dir_contents)
+ {
+ g_hash_table_remove_all (data->dir_contents);
+ g_hash_table_destroy (data->dir_contents);
+ }
+ data->dir_contents = NULL;
+
+ close (fd);
+
+ g_free (data);
+}
+
+static void
+monitor_release_adata (HalFileMonitor *monitor,
+ int fd,
+ FileAccessData *data)
+{
+ g_free (data->path);
+ data->path = NULL;
+
+ if (data->owner)
+ {
+ close (fd);
+ }
+
+ g_free (data);
+}
+
+static gboolean
+remove_kdata_foreach (gpointer fd,
+ FileKqueueData *data,
+ HalFileMonitor *monitor)
+{
+ monitor_release_kdata (monitor, GPOINTER_TO_INT (fd), data);
+ return TRUE;
+}
+
+static gboolean
+remove_adata_foreach (gpointer fd,
+ FileAccessData *data,
+ HalFileMonitor *monitor)
+{
+ monitor_release_adata (monitor, GPOINTER_TO_INT (fd), data);
+ return TRUE;
+}
+
+static void
+close_monitor (HalFileMonitor *monitor)
+{
+ if (! monitor->priv->initialized_kqueue)
+ {
+ return;
+ }
+
+ monitor->priv->initialized_kqueue = FALSE;
+
+ g_hash_table_foreach_remove (monitor->priv->fd_to_kdata,
+ (GHRFunc) remove_kdata_foreach,
+ monitor);
+
+ g_hash_table_foreach_remove (monitor->priv->fd_to_adata,
+ (GHRFunc) remove_adata_foreach,
+ monitor);
+
+ if (monitor->priv->io_watch)
+ {
+ g_source_remove (monitor->priv->io_watch);
+ }
+ monitor->priv->io_watch = 0;
+
+ if (monitor->priv->access_source)
+ {
+ g_source_remove (monitor->priv->access_source);
+ }
+ monitor->priv->access_source = 0;
+
+ if (monitor->priv->kqueue_fd > -1)
+ {
+ close (monitor->priv->kqueue_fd);
+ }
+ monitor->priv->kqueue_fd = -1;
+}
+
+static gboolean
+hal_file_access_monitor (gpointer data)
+{
+ HalFileMonitor *monitor;
+ GList *keys, *l;
+
+ g_return_val_if_fail (HAL_IS_FILE_MONITOR (data), FALSE);
+
+ monitor = HAL_FILE_MONITOR (data);
+
+ g_return_val_if_fail (monitor->priv != NULL, FALSE);
+
+ keys = g_hash_table_get_keys (monitor->priv->fd_to_adata);
+
+ for (l = keys; l != NULL; l = l->next)
+ {
+ FileAccessData *adata;
+ struct stat sb;
+ int fd;
+
+ fd = GPOINTER_TO_INT (l->data);
+ adata = g_hash_table_lookup (monitor->priv->fd_to_adata,
+ l->data);
+
+ if (! adata)
+ {
+ continue;
+ }
+
+ if (fstat (fd, &sb) == -1)
+ {
+ g_warning ("Failed to stat %s: %s", adata->path, g_strerror (errno));
+ hal_file_monitor_remove_adata (monitor, fd);
+ continue;
+ }
+
+ if (sb.st_atime != adata->atime)
+ {
+ adata->atime = sb.st_atime;
+ emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_ACCESS, adata->path, adata->func, adata->udata);
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+setup_monitor (HalFileMonitor *monitor)
+{
+ GIOChannel *io_channel;
+ int fd;
+
+ if (monitor->priv->initialized_kqueue)
+ {
+ return;
+ }
+
+ if ((fd = kqueue ()) < 0)
+ {
+ g_warning ("Failed to initialize kqueue: %s",
+ g_strerror (errno));
+ return;
+ }
+
+ monitor->priv->kqueue_fd = fd;
+
+ monitor->priv->fd_to_kdata = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+ monitor->priv->fd_to_adata = g_hash_table_new (g_direct_hash,
+ g_direct_equal);
+
+ io_channel = g_io_channel_unix_new (fd);
+ monitor->priv->io_watch = g_io_add_watch (io_channel,
+ G_IO_IN|G_IO_PRI,
+ (GIOFunc) handle_kqueue_event,
+ monitor);
+ g_io_channel_unref (io_channel);
+
+ monitor->priv->access_source = g_timeout_add (1000, (GSourceFunc) hal_file_access_monitor, monitor);
+
+ monitor->priv->initialized_kqueue = TRUE;
+}
+
+static void
+hal_file_monitor_init (HalFileMonitor *monitor)
+{
+ monitor->priv = HAL_FILE_MONITOR_GET_PRIVATE (monitor);
+
+ setup_monitor (monitor);
+}
+
+static void
+hal_file_monitor_class_init (HalFileMonitorClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = hal_file_monitor_finalize;
+
+ g_type_class_add_private (klass, sizeof (HalFileMonitorPrivate));
+}
+
+static void
+hal_file_monitor_finalize (GObject *object)
+{
+ HalFileMonitor *monitor;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (HAL_IS_FILE_MONITOR (object));
+
+ monitor = HAL_FILE_MONITOR (object);
+
+ g_return_if_fail (monitor->priv != NULL);
+
+ close_monitor (monitor);
+
+ g_hash_table_destroy (monitor->priv->fd_to_kdata);
+ g_hash_table_destroy (monitor->priv->fd_to_adata);
+
+ G_OBJECT_CLASS (hal_file_monitor_parent_class)->finalize (object);
+}
+
+HalFileMonitor *
+hal_file_monitor_new (void)
+{
+ if (monitor_object != NULL)
+ {
+ g_object_ref (monitor_object);
+ }
+ else
+ {
+ monitor_object = g_object_new (HAL_TYPE_FILE_MONITOR, NULL);
+
+ g_object_add_weak_pointer (monitor_object,
+ (gpointer *) &monitor_object);
+ }
+
+ return HAL_FILE_MONITOR (monitor_object);
+}
+
+/*
+static char *
+fflags_to_str (int fflags)
+{
+
+ GString *out;
+
+ out = g_string_new (NULL);
+
+ if (fflags & NOTE_WRITE)
+ {
+ g_string_append (out, " WRITE ");
+ }
+ if (fflags & NOTE_EXTEND)
+ {
+ g_string_append (out, " EXTEND ");
+ }
+ if (fflags & NOTE_ATTRIB)
+ {
+ g_string_append (out, " ATTRIB ");
+ }
+ if (fflags & NOTE_LINK)
+ {
+ g_string_append (out, " LINK ");
+ }
+ if (fflags & NOTE_DELETE)
+ {
+ g_string_append (out, " DELETE ");
+ }
+ if (fflags & NOTE_REVOKE)
+ {
+ g_string_append (out, " REVOKE ");
+ }
+ if (fflags & NOTE_RENAME)
+ {
+ g_string_append (out, " RENAME ");
+ }
+
+ return g_string_free (out, FALSE);
+}
+*/
+
+static void
+emit_monitor_event (HalFileMonitor *monitor,
+ HalFileMonitorEvent event,
+ const char *path,
+ HalFileMonitorNotifyFunc func,
+ gpointer udata)
+{
+ if (func)
+ {
+ func (monitor, event, path, udata);
+ }
+}
+
+static gboolean
+handle_kqueue_event (GIOChannel *source,
+ GIOCondition condition,
+ gpointer udata)
+{
+ struct kevent ev;
+ struct timespec timeout = { 0, 0 };
+ int nevents;
+ HalFileMonitor *monitor;
+
+ g_return_val_if_fail (HAL_IS_FILE_MONITOR (udata), FALSE);
+
+ monitor = HAL_FILE_MONITOR (udata);
+
+ g_return_val_if_fail (monitor->priv != NULL, FALSE);
+
+ g_return_val_if_fail (monitor->priv->kqueue_fd > -1, FALSE);
+
+ nevents = kevent (monitor->priv->kqueue_fd, NULL, 0, &ev, 1, &timeout);
+ if (nevents == 1)
+ {
+ int fd;
+ FileKqueueData *data;
+
+ fd = ev.ident;
+ data = g_hash_table_lookup (monitor->priv->fd_to_kdata,
+ GINT_TO_POINTER (fd));
+ if (! data)
+ {
+ /* The monitor may have been deleted. */
+ return TRUE;
+ }
+
+ if ((data->omask & HAL_FILE_MONITOR_EVENT_DELETE) &&
+ (ev.fflags & VN_NOTE_DELETED))
+ {
+ emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_DELETE, data->path, data->func, data->udata);
+ hal_file_monitor_remove_kdata (monitor, fd);
+ return TRUE;
+ }
+
+ if ((data->omask & HAL_FILE_MONITOR_EVENT_CREATE) ||
+ (data->omask & HAL_FILE_MONITOR_EVENT_DELETE))
+ {
+ if (data->isdir)
+ {
+ GSList *added = NULL;
+ GSList *removed = NULL;
+ GSList *l;
+ GHashTable *table;
+ gboolean found_change = FALSE;
+
+ table = diff_dir_contents (data, &added, &removed);
+ if (data->omask & HAL_FILE_MONITOR_EVENT_CREATE)
+ {
+ for (l = added; l != NULL; l = l->next)
+ {
+ char *path;
+
+ path = g_build_filename (data->path, l->data, NULL);
+ emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_CREATE, path, data->func, data->udata);
+ g_free (path);
+ }
+ }
+
+ if (data->omask & HAL_FILE_MONITOR_EVENT_DELETE)
+ {
+ for (l = removed; l != NULL; l = l->next)
+ {
+ char *path;
+
+ path = g_build_filename (data->path, l->data, NULL);
+ emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_DELETE, path, data->func, data->udata);
+ g_free (path);
+ }
+ }
+
+ if (added || removed)
+ {
+ g_hash_table_remove_all (data->dir_contents);
+ g_hash_table_destroy (data->dir_contents);
+ data->dir_contents = table;
+ found_change = TRUE;
+ }
+ else if (table)
+ {
+ g_hash_table_remove_all (table);
+ g_hash_table_destroy (table);
+ }
+ else
+ {
+ hal_file_monitor_remove_kdata (monitor, fd);
+ }
+
+ if (added)
+ {
+ g_slist_foreach (added, (GFunc) g_free, NULL);
+ g_slist_free (added);
+ }
+ if (removed)
+ {
+ g_slist_foreach (removed, (GFunc) g_free, NULL);
+ g_slist_free (removed);
+ }
+
+ if (found_change)
+ {
+ return TRUE;
+ }
+ }
+ }
+
+ if (data->omask & HAL_FILE_MONITOR_EVENT_CHANGE)
+ {
+ emit_monitor_event (monitor, HAL_FILE_MONITOR_EVENT_CHANGE, data->path, data->func, data->udata);
+ }
+ }
+ else
+ {
+ g_warning ("Failed to read from kqueue: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static GHashTable *
+diff_dir_contents (FileKqueueData *data,
+ GSList **added,
+ GSList **removed)
+{
+ GDir *dir;
+ GError *err = NULL;
+ GHashTable *table = NULL;
+
+ dir = g_dir_open (data->path, 0, &err);
+ if (dir)
+ {
+ const char *fname;
+
+ table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ while ((fname = g_dir_read_name (dir)))
+ {
+ if (added)
+ {
+ if (! g_hash_table_lookup (data->dir_contents, fname))
+ {
+ *added = g_slist_prepend (*added, g_strdup (fname));
+ }
+ }
+
+ g_hash_table_insert (table, g_strdup (fname), GINT_TO_POINTER (TRUE));
+ }
+
+ g_dir_close (dir);
+
+ if (removed)
+ {
+ GList *keys;
+ GList *l;
+
+ keys = g_hash_table_get_keys (data->dir_contents);
+
+ for (l = keys; l != NULL; l = l->next)
+ {
+ if (! g_hash_table_lookup (table, l->data))
+ {
+ *removed = g_slist_prepend (*removed, g_strdup (l->data));
+ }
+ }
+ }
+
+ }
+ else
+ {
+ g_warning ("Failed to open directory: %s", err->message);
+ g_error_free (err);
+ }
+
+ return table;
+}
+
+static GHashTable *
+get_dir_contents (const char *path)
+{
+ GDir *dir;
+ GError *err = NULL;
+ GHashTable *table = NULL;
+
+ dir = g_dir_open (path, 0, &err);
+ if (dir)
+ {
+ const char *fname;
+
+ table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ while ((fname = g_dir_read_name (dir)))
+ {
+ g_hash_table_insert (table, g_strdup (fname), GINT_TO_POINTER (TRUE));
+ }
+ g_dir_close (dir);
+ }
+ else
+ {
+ g_warning ("Failed to open directory %s: %s\n", path, err->message);
+ g_error_free (err);
+ }
+
+ return table;
+}
+
+/*
+static void
+print_event (HalFileMonitor *monitor,
+ HalFileMonitorEvent event,
+ const char *path,
+ gpointer udata)
+{
+ GString *ename;
+
+ ename = g_string_new (NULL);
+
+ if (event & HAL_FILE_MONITOR_EVENT_ACCESS)
+ {
+ g_string_append (ename, "ACCESS ");
+ }
+ if (event & HAL_FILE_MONITOR_EVENT_CREATE)
+ {
+ g_string_append (ename, "CREATE ");
+ }
+ if (event & HAL_FILE_MONITOR_EVENT_DELETE)
+ {
+ g_string_append (ename, "DELETE ");
+ }
+ if (event & HAL_FILE_MONITOR_EVENT_CHANGE)
+ {
+ g_string_append (ename, "CHANGE ");
+ }
+
+ printf("Received event for %s: %s\n", path, g_string_free (ename, FALSE));
+}
+
+int
+main(void)
+{
+ const char *path = "/tmp/kqueue.d";
+ guint watch;
+ GMainLoop *loop;
+ HalFileMonitor *monitor;
+
+ g_type_init ();
+
+ monitor = hal_file_monitor_new ();
+ hal_file_monitor_add_notify (monitor, path, HAL_FILE_MONITOR_EVENT_CREATE|HAL_FILE_MONITOR_EVENT_DELETE|HAL_FILE_MONITOR_EVENT_CHANGE,print_event, NULL);
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ g_main_loop_run (loop);
+
+ return 0;
+}
+*/
diff --git a/sysutils/hal/files/hald-netbsd/hotplug.c b/sysutils/hal/files/hald-netbsd/hotplug.c
new file mode 100644
index 00000000000..ce96f84f5e7
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/hotplug.c
@@ -0,0 +1,204 @@
+/***************************************************************************
+ *
+ * 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_netbsd.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;
+ HAL_INFO (("no info.parent parameter found"));
+ } else {
+ parent = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", parent_udi);
+ if (parent == NULL)
+ HAL_INFO (("no info.udi=%s parameter found", parent_udi));
+ }
+
+ if (parent == NULL) {
+ gchar pdevnode[512];
+ HAL_INFO (("couldn't look up %s parent by udi, trying netbsd.device", hotplug_event->un.devfs.devfs_path));
+ if (drvctl_find_parent (hotplug_event->un.devfs.devfs_path, pdevnode) == TRUE)
+ parent = hal_device_store_match_key_value_string (hald_get_gdl (), "netbsd.device", pdevnode);
+ }
+
+ /* only root node is allowed to be orphan */
+ if (parent == NULL) {
+ if (strcmp(hotplug_event->un.devfs.devfs_path, "mainbus0") != 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 (),
+ "netbsd.device",
+ 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/sysutils/hal/files/hald-netbsd/hotplug.h b/sysutils/hal/files/hald-netbsd/hotplug.h
new file mode 100644
index 00000000000..fc9f92ec1c5
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/hotplug.h
@@ -0,0 +1,58 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#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/sysutils/hal/files/hald-netbsd/osspec.c b/sysutils/hal/files/hald-netbsd/osspec.c
new file mode 100644
index 00000000000..3c88dbdad37
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/osspec.c
@@ -0,0 +1,193 @@
+/***************************************************************************
+ *
+ * osspec.c : NetBSD HAL backend entry points
+ *
+ * Copyright 2008 Jared D. McNeill <jmcneill@NetBSD.org>
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <strings.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/statvfs.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_netbsd.h"
+#include "hotplug.h"
+#include "drvctl.h"
+#include "devinfo.h"
+#include "devinfo_storage.h"
+
+static void mntinfo_event_init ();
+static gboolean mntinfo_timeout (gpointer user_data);
+
+HalFileMonitor *
+osspec_get_file_monitor (void)
+{
+#warning Please implement
+ return NULL;
+}
+
+void
+osspec_init (void)
+{
+ ids_init ();
+ mntinfo_event_init ();
+}
+
+void
+osspec_privileged_init (void)
+{
+ drvctl_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, "mainbus0");
+
+ /* start processing events */
+ hotplug_event_process_queue ();
+}
+
+gboolean
+osspec_device_rescan (HalDevice *d)
+{
+ return (devinfo_device_rescan (d));
+}
+
+gboolean
+osspec_device_reprobe (HalDevice *d)
+{
+ return FALSE;
+}
+
+DBusHandlerResult
+osspec_filter_function (DBusConnection *connection, DBusMessage *message, void *user_data)
+{
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+/**
+ * hal_util_find_closest_ancestor:
+ * @devfs_path: Path into devfs, e.g. /pci@0,0/pci1025,57@10,2/storage@1
+ *
+ * Returns: Parent Hal Device Object or #NULL if there is none
+ *
+ * Find the closest ancestor by looking at devfs paths
+ */
+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;
+
+ if (drvctl_find_parent (devfs_path, buf) == FALSE)
+ return NULL;
+
+ HAL_INFO (("hal_util_find_closest_ancestor: devnode=%s parent=%s\n", devfs_path, buf));
+
+ parent = hal_device_store_match_key_value_string (hald_get_gdl (),
+ "netbsd.device",
+ buf);
+ if (parent != NULL) {
+ if (ancestor_devfs_path != NULL) {
+ *ancestor_devfs_path = g_strdup (buf);
+ }
+ if (hotplug_devfs_path != NULL) {
+ *hotplug_devfs_path = g_strdup (buf);
+ }
+ }
+
+ return parent;
+}
+
+char *
+dsk_to_rdsk(char *dsk)
+{
+ int len, pos;
+ char *p;
+ char *rdsk;
+
+ if ((len = strlen (dsk)) < sizeof ("/dev/AANA") - 1) {
+ return (strdup(""));
+ }
+ p = strstr (dsk, "/dev/");
+ 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 mntinfo changes
+ */
+static void
+mntinfo_event_init ()
+{
+#if notyet
+ g_timeout_add(1000, mntinfo_timeout, NULL);
+#endif
+}
+
+static gboolean
+mntinfo_timeout (gpointer user_data)
+{
+#if notyet
+ struct statvfs *statvfs;
+
+ HAL_INFO (("mntinfo timeout"));
+
+ if (!hald_is_initialising) {
+ devinfo_storage_mnttab_event (NULL);
+ }
+#endif
+
+ return TRUE;
+}
+
+void
+osspec_refresh_mount_state_for_block_device (HalDevice *d)
+{
+#warning osspec_refresh_mount_state_for_block_device TODO
+#if notyet
+ devinfo_storage_mnttab_event (d);
+#endif
+}
diff --git a/sysutils/hal/files/hald-netbsd/osspec_netbsd.h b/sysutils/hal/files/hald-netbsd/osspec_netbsd.h
new file mode 100644
index 00000000000..5a1bed810f3
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/osspec_netbsd.h
@@ -0,0 +1,21 @@
+/***************************************************************************
+ *
+ * osspec_netbsd.h : definitions for NetBSD 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
+ *
+ **************************************************************************/
+
+#ifndef OSSPEC_NETBSD_H
+#define OSSPEC_NETBSD_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/sysutils/hal/files/hald-netbsd/probing/Makefile.am b/sysutils/hal/files/hald-netbsd/probing/Makefile.am
new file mode 100644
index 00000000000..c9a58549ee1
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/Makefile.am
@@ -0,0 +1,20 @@
+
+AM_CPPFLAGS = \
+ -DPACKAGE_SYSCONF_DIR=\""$(sysconfdir)"\" \
+ -DPACKAGE_DATA_DIR=\""$(datadir)"\" \
+ -DPACKAGE_BIN_DIR=\""$(bindir)"\" \
+ -DPACKAGE_LOCALE_DIR=\""$(localedir)"\" \
+ -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_NETBSD
+libexec_PROGRAMS = hald-probe-storage hald-probe-volume
+endif
+
+hald_probe_storage_SOURCES = probe-storage.c cdutils.c fsutils.c ../../logger.c
+hald_probe_storage_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ -lprop
+
+hald_probe_volume_SOURCES = probe-volume.c cdutils.c fsutils.c ../../logger.c
+hald_probe_volume_LDADD = $(top_builddir)/libhal/libhal.la @GLIB_LIBS@ -lprop
+
diff --git a/sysutils/hal/files/hald-netbsd/probing/cdutils.c b/sysutils/hal/files/hald-netbsd/probing/cdutils.c
new file mode 100644
index 00000000000..0d524eb92e1
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/cdutils.c
@@ -0,0 +1,379 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/scsiio.h>
+#include <sys/disklabel.h>
+#include <dev/scsipi/scsi_spc.h>
+#include <dev/scsipi/scsipi_all.h>
+#include <dev/scsipi/scsipi_cd.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])
+
+bool
+scsi_command (int fd, void *cmd, size_t cmdlen, void *data, size_t datalen,
+ int timeout, int flags)
+{
+ scsireq_t req;
+
+ memset(&req, 0, sizeof(req));
+ memcpy(req.cmd, cmd, cmdlen);
+ req.cmdlen = cmdlen;
+ req.databuf = data;
+ req.datalen = datalen;
+ req.timeout = timeout;
+ req.flags = flags;
+ req.senselen = SENSEBUFLEN;
+
+ if (ioctl(fd, SCIOCCOMMAND, &req) == -1)
+ return false;
+ if (req.retsts == SCCMD_OK)
+ return true;
+ return false;
+}
+
+int
+mode_sense(int fd, u_char pc, int dbd, int page_len, u_char *buffer)
+{
+ struct scsi_mode_sense_10 sms10;
+
+ memset(&sms10, 0, sizeof(sms10));
+ sms10.opcode = SCSI_MODE_SENSE_10;
+ if (dbd)
+ sms10.byte2 = SMS_DBD; /* no block descriptors */
+ sms10.page = pc;
+ sms10.length[0] = (page_len >> 8) & 0xff;
+ sms10.length[1] = page_len & 0xff;
+
+ return (scsi_command(fd, &sms10, sizeof(sms10), buffer, page_len, 10000, SCCMD_READ) == true);
+}
+
+/*
+ * 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, u_char *buffer, int *plen)
+{
+ int ret;
+ u_char byte2;
+ u_char buf[256];
+ u_int header_len, page_len, copy_cnt;
+
+ byte2 = (u_char)(((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 = ((int)page_len > buf_len) ? (u_int)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, u_char *buf)
+{
+ struct scsipi_get_configuration conf;
+
+ memset(&conf, 0, sizeof(conf));
+ conf.opcode = GET_CONFIGURATION;
+ conf.request_type = 0x2;
+ conf.start_at_feature[0] = (feature >> 8) & 0xff;
+ conf.start_at_feature[1] = feature & 0xff;
+ conf.data_len[0] = (bufsize >> 8) & 0xff;
+ conf.data_len[1] = bufsize & 0xff;
+
+ return (scsi_command(fd, &conf, sizeof(conf), buf, bufsize, 10000, SCCMD_READ) == true);
+}
+
+bool
+get_current_profile(int fd, int *profile)
+{
+ u_char smallbuf[4];
+ size_t buflen;
+ u_char *bufp;
+ int ret = false;
+
+ /* first determine amount of memory needed to hold all profiles */
+ if (get_configuration(fd, 0, 4, &smallbuf[0])) {
+ buflen = GET32(smallbuf) + 4;
+ bufp = (u_char *)malloc(buflen);
+
+ /* now get all profiles */
+ if (get_configuration(fd, 0, buflen, bufp)) {
+ *profile = GET16(&bufp[6]);
+ ret = true;
+ }
+ free(bufp);
+ }
+
+ return (ret);
+}
+
+void
+walk_profiles(int fd, int (*f)(void *, int, bool), void *arg)
+{
+ size_t i;
+ uint16_t profile, current_profile;
+ u_char smallbuf[4];
+ size_t buflen;
+ u_char *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 = (u_char *)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
+ */
+static void
+get_write_speeds(u_char *page, int n, intlist_t **speeds, int *n_speeds, intlist_t **speeds_mem)
+{
+ u_char *p = page + 2;
+ int i;
+ intlist_t **nextp;
+ intlist_t *current;
+ bool 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 = false;
+ for (nextp = speeds; *nextp != NULL; nextp = &((*nextp)->next)) {
+ if (current->val == (*nextp)->val) {
+ skip = 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;
+ u_char 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);
+ }
+}
+
+bool
+get_disc_info(int fd, disc_info_t *di)
+{
+ struct scsipi_read_discinfo discinfo;
+ uint8_t buf[32];
+ int bufsize = sizeof (buf);
+
+ bzero(buf, bufsize);
+ memset(&discinfo, 0, sizeof(discinfo));
+ discinfo.opcode = READ_DISCINFO;
+ discinfo.data_len[0] = (bufsize >> 8) & 0xff;
+ discinfo.data_len[1] = bufsize & 0xff;
+
+ if (scsi_command(fd, &discinfo, sizeof(discinfo), buf, bufsize, 10000, SCCMD_READ) == false)
+ return 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 true;
+}
+
+/*
+ * returns current/maximum format capacity in bytes
+ */
+bool
+read_format_capacity(int fd, uint64_t *capacity)
+{
+ char cdb[12];
+ uint8_t buf[32];
+ int bufsize = sizeof (buf);
+ uint32_t num_blocks;
+ uint32_t block_len;
+
+ memset(buf, 0, bufsize);
+ memset(cdb, 0, sizeof(cdb));
+ cdb[0] = 0x23; /* READ FORMAT CAPACITIES */
+ cdb[7] = (bufsize >> 8) & 0xff; /* allocation length */
+ cdb[8] = bufsize & 0xff;
+
+ if (scsi_command(fd, &cdb, sizeof(cdb), buf, bufsize, 10000, SCCMD_READ) == false)
+ return 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 (true);
+}
+
+bool
+get_media_info(int fd, uint64_t *capacity)
+{
+ struct disklabel d;
+ int ret;
+
+ ret = ioctl(fd, DIOCGDINFO, &d);
+ if (ret == -1)
+ return false;
+ *capacity = d.d_secsize * d.d_secperunit;
+ return true;
+}
+
+/*
+ * given current profile, use the best method for determining
+ * disc capacity (in bytes)
+ */
+bool
+get_disc_capacity_for_profile(int fd, int profile, uint64_t *capacity)
+{
+ disc_info_t di;
+ bool ret = false;
+
+ switch (profile) {
+ case 0x08: /* CD-ROM */
+ case 0x10: /* DVD-ROM */
+ if (get_media_info(fd, capacity))
+ ret = true;
+ break;
+ default:
+ if (read_format_capacity(fd, capacity) && (*capacity > 0)) {
+ ret = true;
+ } else if (get_disc_info(fd, &di) && (di.capacity > 0)) {
+ if (get_media_info(fd, capacity))
+ ret = true;
+ }
+ }
+
+ return (ret);
+}
+
+bool
+read_toc(int fd, int format, int trackno, int buflen, u_char *buf)
+{
+ struct scsipi_read_toc toc;
+
+ memset(buf, 0, buflen);
+ toc.opcode = READ_TOC;
+ toc.resp_format = format & 0xf;
+ toc.from_track = trackno;
+ toc.data_len[0] = (buflen >> 8) & 0xff;
+ toc.data_len[1] = buflen & 0xff;
+
+ return scsi_command(fd, &toc, sizeof(toc), buf, buflen, 10000, SCCMD_READ);
+}
diff --git a/sysutils/hal/files/hald-netbsd/probing/cdutils.h b/sysutils/hal/files/hald-netbsd/probing/cdutils.h
new file mode 100644
index 00000000000..f79a4a2bdd8
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/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
+ *
+ **************************************************************************/
+
+#ifndef CDUTILS_H
+#define CDUTILS_H
+
+#include <sys/types.h>
+#include <sys/dkio.h>
+#include <sys/cdio.h>
+#include <sys/scsiio.h>
+#include <stdbool.h>
+#include <stdint.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;
+ uint64_t capacity;
+} disc_info_t;
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+bool scsi_command(int fd, void *cmd, size_t cmdlen, void *data,
+ size_t datalen, int timeout, int flags);
+int mode_sense(int fd, u_char pc, int dbd, int page_len,
+ u_char *buffer);
+int get_mode_page(int fd, int page_no, int pc, int buf_len,
+ u_char *buffer, int *plen);
+int get_configuration(int fd, uint16_t feature, int bufsize,
+ u_char *buf);
+bool get_current_profile(int fd, int *profile);
+void walk_profiles(int fd, int (*f)(void *, int, bool), void *);
+void get_read_write_speeds(int fd, int *read_speed, int *write_speed,
+ intlist_t **wspeeds, int *n_wspeeds, intlist_t **wspeeds_mem);
+bool get_disc_info(int fd, disc_info_t *);
+bool read_format_capacity(int fd, uint64_t *capacity);
+bool get_media_info(int fd, uint64_t *capacity);
+bool get_disc_capacity_for_profile(int fd, int profile,
+ uint64_t *capacity);
+bool read_toc(int fd, int format, int trackno, int buflen,
+ u_char *buf);
+
+#endif /* CDUTILS_H */
diff --git a/sysutils/hal/files/hald-netbsd/probing/fsutils.c b/sysutils/hal/files/hald-netbsd/probing/fsutils.c
new file mode 100644
index 00000000000..fa0a16c2a35
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/fsutils.c
@@ -0,0 +1,217 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/scsiio.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/disklabel.h>
+#include <sys/bootblock.h>
+
+#include <libhal.h>
+#include "fsutils.h"
+
+/*
+ * Separates dos notation device spec into device and drive number
+ */
+bool
+dos_to_dev(char *path, char **devpath, int *num)
+{
+ char *p;
+
+ if ((p = strrchr(path, ':')) == NULL) {
+ return (false);
+ }
+ if ((*num = atoi(p + 1)) == 0) {
+ return (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 ("");
+ }
+}
+
+bool
+is_dos_drive(u_char type)
+{
+ return ((type == 1) || (type == 4) || (type == 5) || (type == 6) ||
+ ((type >= 8) && (type <= 0xf)));
+}
+
+bool
+is_dos_extended(u_char id)
+{
+ return MBR_IS_EXTENDED(id);
+}
+
+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 mbr_sector *msect = (struct mbr_sector *)&buf[0];
+ struct mbr_partition mpart[MBR_PART_COUNT];
+ int sec = startsec;
+ int lastsec = sec + 1;
+ int relsect;
+ int ext = 0;
+ int systid;
+ bool valid;
+ int i;
+
+ while (sec != lastsec) {
+ if (pread(fd, buf, bufsize, (off_t)sec * 512) != bufsize) {
+ break;
+ }
+ lastsec = sec;
+ if (le16toh(msect->mbr_magic) != MBR_MAGIC) {
+ break;
+ }
+ memcpy(mpart, msect->mbr_parts, MBR_PART_COUNT * sizeof (struct mbr_partition));
+
+ for (i = 0; i < MBR_PART_COUNT; i++) {
+ systid = mpart[i].mbrp_type;
+ relsect = sec + le32toh(mpart[i].mbrp_start);
+ if (systid == 0) {
+ continue;
+ }
+ valid = true;
+ if (is_dos_extended(systid) && (sec == lastsec)) {
+ sec = startsec + le32toh(mpart[i].mbrp_start);
+ if (ext++ == 0) {
+ relsect = startsec = sec;
+ } else {
+ valid = false;
+ }
+ }
+ if (valid && f(arg, mpart[i].mbrp_type, relsect,
+ le32toh(mpart[i].mbrp_size)) == 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.
+ */
+bool
+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 (true);
+ }
+ }
+
+ return (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);
+}
diff --git a/sysutils/hal/files/hald-netbsd/probing/fsutils.h b/sysutils/hal/files/hald-netbsd/probing/fsutils.h
new file mode 100644
index 00000000000..8f4558d7d6f
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/fsutils.h
@@ -0,0 +1,25 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#ifndef FSUTILS_H
+#define FSUTILS_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+bool dos_to_dev(char *path, char **devpath, int *num);
+char *get_slice_name (char *devlink);
+bool is_dos_drive(u_char id);
+bool is_dos_extended(u_char id);
+bool find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid);
+
+#endif /* FSUTILS_H */
diff --git a/sysutils/hal/files/hald-netbsd/probing/probe-storage.c b/sysutils/hal/files/hald-netbsd/probing/probe-storage.c
new file mode 100644
index 00000000000..f27ca6782fa
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/probe-storage.c
@@ -0,0 +1,403 @@
+/***************************************************************************
+ *
+ * probe-storage.c : Probe for storage devices
+ *
+ * Copyright 2008 Jared D. McNeill <jmcneill@NetBSD.org>
+ * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * Licensed under the Academic Free License version 2.1
+ *
+ **************************************************************************/
+
+#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/fdio.h>
+#include <sys/statvfs.h>
+
+#include <sys/scsiio.h>
+#include <dev/scsipi/scsi_spc.h>
+#include <dev/scsipi/scsipi_all.h>
+
+#include <libhal.h>
+#include <cdutils.h>
+#include <fsutils.h>
+#include <logger.h>
+
+#if notyet
+/** Check if a filesystem on a special device file is mounted
+ *
+ * @param device_file Special device file, e.g. /dev/cd0a
+ * @return TRUE iff there is a filesystem system mounted
+ * on the special device file
+ */
+static dbus_bool_t
+is_mounted (const char *device_file)
+{
+ int count;
+ struct statvfs *statvfs;
+
+ count = getmntinfo(&statvfs, ST_WAIT);
+ while (count-- > 0) {
+ if (strcmp(statvfs->f_mntfromname, device_file) == 0)
+ return TRUE;
+ }
+
+ return FALSE;
+}
+#endif
+
+static int
+get_cdrom_properties_walker (void *arg, int profile, bool 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)
+{
+ 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.
+ */
+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((int)*p))) {
+ *p-- = '\0';
+ }
+ }
+ return (dst);
+}
+
+static void
+get_disk_properties (int fd, LibHalChangeSet *cs)
+{
+ struct scsipi_inquiry_data inqbuf;
+ struct scsipi_inquiry cmd;
+ dbus_bool_t status;
+ char *s;
+
+ /* INQUIRY */
+ memset(&cmd, 0, sizeof(cmd));
+ memset(&inqbuf, 0, sizeof(inqbuf));
+ cmd.opcode = INQUIRY;
+ cmd.length = sizeof(inqbuf);
+ status = scsi_command(fd, &cmd, sizeof(cmd), &inqbuf, sizeof(inqbuf), 10000, SCCMD_READ);
+ if (status == false)
+ return;
+
+ if ((s = rtrim_copy(inqbuf.vendor, sizeof (inqbuf.vendor))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.vendor", s);
+ free(s);
+ }
+ if ((s = rtrim_copy(inqbuf.product, sizeof (inqbuf.product))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.model", s);
+ free(s);
+ }
+ if ((s = rtrim_copy(inqbuf.revision, sizeof (inqbuf.revision))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.firmware_revision", s);
+ free(s);
+ }
+ if ((s = rtrim_copy((char *)inqbuf.vendor_specific, sizeof (inqbuf.vendor_specific))) != NULL) {
+ libhal_changeset_set_property_string (cs, "storage.serial", s);
+ free(s);
+ }
+}
+
+#if notyet
+/*
+ * 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);
+ }
+}
+#endif
+
+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;
+ 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;
+ int dos_cnt = 0;
+ const char *scheme = "";
+ 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;
+
+ 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) {
+ uint64_t capacity;
+
+ HAL_DEBUG (("Checking for optical disc on %s", raw_device_file));
+ got_media = get_media_info(rfd, &capacity);
+ if (!got_media) {
+ goto out_cs;
+ }
+ /* XXX */
+ is_write_protected = TRUE;
+ } else if (is_floppy) {
+#if 0
+ HAL_DEBUG (("Checking for floppy on %s", raw_device_file));
+ if (check_floppy(rfd, &is_write_protected)) {
+ got_media = TRUE;
+ }
+#endif
+ /* 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;
+ }
+
+ scheme = "mbr";
+ dos_cnt = 1;
+
+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_int (cs, "storage.netbsd.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.netbsd.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/sysutils/hal/files/hald-netbsd/probing/probe-volume.c b/sysutils/hal/files/hald-netbsd/probing/probe-volume.c
new file mode 100644
index 00000000000..9b9c66a19d2
--- /dev/null
+++ b/sysutils/hal/files/hald-netbsd/probing/probe-volume.c
@@ -0,0 +1,629 @@
+/***************************************************************************
+ *
+ * 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
+ *
+ **************************************************************************/
+
+#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 <sys/disklabel.h>
+#include <isofs/cd9660/iso.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)
+{
+ 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);
+
+#if notyet
+ /* label */
+ (void) nvlist_lookup_string(fsattr, "gen_volume_label", &label_orig);
+#endif
+ 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);
+ }
+ if (label)
+ free(label);
+
+#if notyet
+ /* 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", "");
+ }
+#else
+ libhal_changeset_set_property_string (cs, "volume.uuid", "");
+#endif
+
+ libhal_device_commit_changeset (ctx, cs, &error);
+ libhal_device_free_changeset (cs);
+
+ my_dbus_error_free (&error);
+}
+
+#define ISO_VOLDESC_SEC 16
+#define IPE_FPESIZE 8
+#define IDE_MAX_NAME_LEN (255 - ISO_DIRECTORY_RECORD_SIZE)
+
+/*
+ * isofs/cd9660 contents detection: Video DVD, Video CD, etc.
+ */
+static void
+isofs_contents(int fd, off_t probe_offset, LibHalContext *ctx, const char *udi)
+{
+ size_t secsz = sizeof(struct iso_primary_descriptor);
+ struct iso_primary_descriptor ipdesc;
+ uint8_t buf[sizeof(struct iso_volume_descriptor)];
+ int ptbl_lbn, ptbl_size;
+ int off, reloff, readoff;
+ 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, &ipdesc, secsz, readoff) != secsz) {
+ return;
+ }
+ while (isonum_711 (ipdesc.type) != ISO_VD_PRIMARY) {
+ if (isonum_711 (ipdesc.type) == ISO_VD_END) {
+ return;
+ }
+ readoff += secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ return;
+ }
+ }
+
+ /*
+ * PVD contains size and offset of the LSB/MSB path table
+ */
+ ptbl_size = isonum_733 (ipdesc.path_table_size);
+ ptbl_lbn = isonum_732 (ipdesc.type_m_path_table);
+
+ /*
+ * 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) {
+ uint8_t *p;
+
+ /* load sectors on demand */
+ if (reloff >= secsz) {
+ readoff += secsz;
+ if (pread (fd, buf, secsz, readoff) != secsz) {
+ break;
+ }
+ reloff -= secsz;
+ }
+
+ p = buf + reloff;
+ name_len = isonum_711 (p[0]);
+ ipe_len = IPE_FPESIZE + name_len + (name_len % 2);
+
+ /* only interested in root directories */
+ if (isonum_711 (p[6]) != 1) {
+ continue;
+ }
+ if ((name_len < 2) || (name_len > IDE_MAX_NAME_LEN)) {
+ continue;
+ }
+
+ name = (char *)&p[8];
+ 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 */
+ 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) {
+ u_char smalltoc[12];
+ size_t toc_size;
+ u_char *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 = TRUE; /* probe for fs anyway */
+ } else {
+ toc_size = smalltoc[0] * 256 + smalltoc[1] + 2;
+ toc = (u_char *)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 = TRUE;
+ } else {
+ has_audio = 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);
+}
+
+int
+main (int argc, char *argv[])
+{
+ int fd, rfd;
+ int ret;
+ char *udi;
+ char *device_file, *raw_device_file;
+ char *devpath, *rdevpath;
+ bool 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;
+ struct disklabel d;
+ dbus_uint64_t partition_start = 0;
+ int partition_number = 0;
+ int i, dos_cnt;
+ int systid, relsect, numsect;
+ off_t probe_offset = 0;
+ int num_volumes;
+ char **volumes;
+ dbus_uint64_t v_start;
+ const char *fstype;
+
+ 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;
+ }
+
+ 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 notyet
+ /* 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;
+ }
+ }
+#endif
+
+ /* block size and total size */
+ if (ioctl(rfd, DIOCGDINFO, &d) != -1) {
+ block_size = d.d_secsize;
+ vol_size = d.d_secsize * d.d_secperunit;
+ } 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 notyet
+ 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);
+ }
+#endif
+ 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:
+
+#if notyet
+ /*
+ * 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;
+ }
+ }
+#else
+ fstype = "cd9660";
+#endif
+ set_fstyp_properties (ctx, udi, fstype);
+
+ if (strcmp (fstype, "cd9660") == 0) {
+ isofs_contents (fd, probe_offset, ctx, udi);
+ }
+
+#if notyet
+ fstyp_fini(fstyp_handle);
+#endif
+
+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/sysutils/hal/patches/patch-ag b/sysutils/hal/patches/patch-ag
index 8a6cca6e335..1d64cde7164 100644
--- a/sysutils/hal/patches/patch-ag
+++ b/sysutils/hal/patches/patch-ag
@@ -1,13 +1,13 @@
-$NetBSD: patch-ag,v 1.1.1.1 2008/11/22 15:20:51 jmcneill Exp $
+$NetBSD: patch-ag,v 1.2 2008/11/25 23:10:23 jmcneill Exp $
---- Makefile.in.orig 2008-11-22 09:25:09.000000000 -0500
-+++ Makefile.in
-@@ -239,7 +239,7 @@ SUBDIRS = libhal libhal-storage partutil
-
+--- Makefile.am.orig 2008-11-25 17:57:41.000000000 -0500
++++ Makefile.am 2008-11-25 17:57:56.000000000 -0500
+@@ -6,7 +6,7 @@
pkgconfigdir = $(libdir)/pkgconfig
pkgconfig_DATA = hal.pc hal-storage.pc
+
-dbusdir = $(DBUS_SYS_DIR)
+dbusdir = $(PREFIX)/share/examples/hal
dist_dbus_DATA = hal.conf
- MAINTAINERCLEANFILES = ChangeLog
- DISTCLEANFILES = hal.pc hal-storage.pc
+
+ # Creating ChangeLog from git log (taken from cairo/Makefile.am):
diff --git a/sysutils/hal/patches/patch-na b/sysutils/hal/patches/patch-na
new file mode 100644
index 00000000000..e56c3510034
--- /dev/null
+++ b/sysutils/hal/patches/patch-na
@@ -0,0 +1,41 @@
+$NetBSD: patch-na,v 1.1 2008/11/25 23:10:23 jmcneill Exp $
+
+--- configure.in.orig 2008-11-24 15:25:20.000000000 -0500
++++ configure.in
+@@ -448,7 +448,7 @@ AM_CONDITIONAL([HAVE_LIBPCI], [test "x$U
+
+ AC_ARG_WITH([backend],
+ AS_HELP_STRING([--with-backend=<name>],
+- [backend to use (linux/solaris/freebsd/dummy)]),
++ [backend to use (linux/solaris/netbsd/freebsd/dummy)]),
+ [backend=$withval])
+ if ! test -z "$with_backend" ; then
+ HALD_BACKEND="$with_backend"
+@@ -457,6 +457,9 @@ else
+ *-*-solaris*)
+ HALD_BACKEND="solaris"
+ ;;
++ *-*-netbsd*)
++ HALD_BACKEND="netbsd"
++ ;;
+ *-*-freebsd*)
+ HALD_BACKEND="freebsd"
+ ;;
+@@ -472,6 +475,7 @@ AM_CONDITIONAL(HALD_COMPILE_DUMMY, [test
+ AM_CONDITIONAL(HALD_COMPILE_LINUX, [test x$HALD_BACKEND = xlinux], [Compiling for Linux])
+ AM_CONDITIONAL(HALD_COMPILE_FREEBSD, [test x$HALD_BACKEND = xfreebsd], [Compiling for FreeBSD])
+ AM_CONDITIONAL(HALD_COMPILE_SOLARIS, [test x$HALD_BACKEND = xsolaris], [Compiling for Solaris])
++AM_CONDITIONAL(HALD_COMPILE_NETBSD, [test x$HALD_BACKEND = xnetbsd], [Compiling for NetBSD])
+ AC_SUBST(HALD_BACKEND)
+
+ dnl DBUS API is subject to changes
+@@ -1004,6 +1008,9 @@ hald/linux/addons/Makefile
+ hald/solaris/Makefile
+ hald/solaris/probing/Makefile
+ hald/solaris/addons/Makefile
++hald/netbsd/Makefile
++hald/netbsd/probing/Makefile
++hald/netbsd/addons/Makefile
+ hald/freebsd/Makefile
+ hald/freebsd/probing/Makefile
+ hald/freebsd/libprobe/Makefile
diff --git a/sysutils/hal/patches/patch-nb b/sysutils/hal/patches/patch-nb
new file mode 100644
index 00000000000..22f30195d76
--- /dev/null
+++ b/sysutils/hal/patches/patch-nb
@@ -0,0 +1,12 @@
+$NetBSD: patch-nb,v 1.1 2008/11/25 23:10:23 jmcneill Exp $
+
+--- hald/Makefile.am.orig 2008-11-24 15:24:58.000000000 -0500
++++ hald/Makefile.am
+@@ -1,6 +1,6 @@
+ ## Process this file with automake to produce Makefile.in
+
+-SUBDIRS = dummy freebsd linux solaris .
++SUBDIRS = dummy freebsd linux solaris netbsd .
+
+ AM_CPPFLAGS = \
+ -DPACKAGE_LIBEXEC_DIR=\""$(libexecdir)"\" \