diff options
author | jmcneill <jmcneill@pkgsrc.org> | 2008-11-25 23:10:23 +0000 |
---|---|---|
committer | jmcneill <jmcneill@pkgsrc.org> | 2008-11-25 23:10:23 +0000 |
commit | 063813da32605a8e1ac653c88439961286754e01 (patch) | |
tree | 0447589fba1775964f334dbc860bd4935aadffca /sysutils/hal/files | |
parent | e8093bf042ef4264b1ad63191042b4afe78c58dd (diff) | |
download | pkgsrc-063813da32605a8e1ac653c88439961286754e01.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/files')
29 files changed, 6483 insertions, 0 deletions
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; + +} |