/***************************************************************************
*
* devinfo_storage.c : storage devices
*
* Copyright 2013 Garrett D'Amore <garrett@damore.org>
*
* Licensed under the Academic Free License version 2.1
*
**************************************************************************/
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <libdevinfo.h>
#include "../osspec.h"
#include "../logger.h"
#include "../hald.h"
#include "../hald_dbus.h"
#include "../device_info.h"
#include "../util.h"
#include "../hald_runner.h"
#include "hotplug.h"
#include "devinfo.h"
#include "devinfo_misc.h"
#include "devinfo_storage.h"
#include "osspec_solaris.h"
#ifdef sparc
#else
#endif
/* some devices,especially CDROMs, may take a while to be probed (values in ms) */
typedef struct devinfo_storage_minor {
char *devpath;
char *devlink;
char *slice;
HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
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 void devinfo_storage_free_minor(struct devinfo_storage_minor *m);
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);
static char *devinfo_scsi_dtype2str(int dtype);
static char *devinfo_volume_get_slice_name (char *devlink);
static void devinfo_storage_set_nicknames (HalDevice *d);
NULL,
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
};
NULL,
NULL,
NULL,
NULL,
};
/* IDE */
{
char *s;
}
(strcmp (s, "dada") == 0)) {
}
return (NULL);
}
static HalDevice *
{
HalDevice *d;
d = hal_device_new ();
return (d);
}
static HalDevice *
{
HalDevice *d;
d = hal_device_new();
}
static HalDevice *
{
HalDevice *d;
char *s;
int *i;
char *driver_name;
return (NULL);
}
d = hal_device_new ();
hal_device_set_udi (d, udi);
hal_device_add_capability (d, "storage");
hal_device_property_set_int (d, "storage.lun", 0);
/* XXX */
hal_device_add_capability (d, "block");
return (d);
}
/* SCSI */
{
int *i;
char *driver_name;
HalDevice *d;
return (NULL);
}
d = hal_device_new ();
hal_device_set_udi (d, udi);
hal_device_property_set_int (d, "scsi.host",
hal_device_property_set_int (d, "scsi.bus", 0);
}
static HalDevice *
{
HalDevice *d;
int *i;
char *s;
d = hal_device_new ();
hal_device_set_udi (d, udi);
hal_device_add_capability (d, "storage");
hal_device_property_set_int (d, "storage.lun",
/*
* We have to enable polling not only for drives with removable media,
* but also for hotpluggable devices, because when a disk is
* 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",
&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_add_capability (d, "block");
return (d);
}
static char *
{
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 */
};
} else {
return ("scsi");
}
}
/* blkdev */
{
int *i;
char *driver_name;
HalDevice *d;
return (NULL);
}
d = hal_device_new ();
hal_device_set_udi (d, udi);
}
static HalDevice *
{
HalDevice *d;
char *driver_name;
int *i;
char *s;
d = hal_device_new ();
hal_device_set_udi (d, udi);
hal_device_add_capability (d, "storage");
hal_device_property_set_int (d, "storage.lun", 0);
hal_device_add_capability (d, "block");
return (d);
}
/* floppy */
{
char *driver_name;
char *raw;
int major;
return (NULL);
}
/*
*/
return (NULL);
}
continue;
}
break;
}
minor_path = NULL;
}
goto out;
}
d = hal_device_new ();
hal_device_add_capability (d, "storage");
hal_device_add_capability (d, "block");
/* trigger initial probe-volume */
out:
return (d);
}
static void
{
char *devlink;
char *devfs_path;
struct devinfo_storage_minor *m;
}
/*
* After reprobing storage, reprobe its volumes.
*/
static void
{
const char *devfs_path;
HalDevice *v;
if (!hal_device_property_get_bool (d, "storage.removable.media_available")) {
/* remove child (can only be single volume) */
if (((v = hal_device_store_match_key_value_string (hald_get_gdl(),
"solaris.devfs_path")) != NULL)) {
}
} else {
return;
}
return;
}
}
}
/* lofi */
{
}
{
char *driver_name;
int major;
return (NULL);
}
if (!rescan) {
d = hal_device_new ();
hal_device_set_udi (d, udi);
} 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
*/
return (d);
}
continue;
}
continue;
}
if (!rescan ||
}
}
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;
struct devinfo_storage_minor *m;
int i;
/* add storage */
d = hal_device_new ();
hal_device_add_capability (d, "storage");
hal_device_add_capability (d, "block");
/* add volumes: one on main device and a few pcfs candidates */
devinfo_volume_add (d, node, m);
for (i = 1; i < 16; i++) {
devinfo_volume_add (d, node, m);
}
}
}
void
{
GSList *i;
const char *devfs_path;
d = HAL_DEVICE (i->data);
break;
}
}
if (d == NULL) {
return;
}
if ((devfs_path = hal_device_property_get_string (d,
"solaris.devfs_path")) == NULL) {
return;
}
if (d != NULL) {
devinfo_remove_branch ((char *)devfs_path, d);
}
}
/* common storage */
static void
{
if (m != NULL) {
free (m);
}
}
static struct devinfo_storage_minor *
{
struct devinfo_storage_minor *m;
int pathlen;
char *devpath;
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.
*/
m = NULL;
}
}
return (m);
}
/*
* Storage minor nodes are potential "volume" objects.
* This function also completes building the parent object (main storage device).
*/
static void
{
const char *whole_disk;
int major;
int doslink_len;
char *doslink;
char *slice;
int pathlen;
int i;
char *raw;
struct devinfo_storage_minor *m;
/* for cdroms whole disk is always s2 */
* so we put other minor nodes on the local queue and move to the
* hotplug queue up in the end
*/
goto err;
}
g_queue_free (mq);
goto err;
}
continue;
}
continue;
}
continue;
}
/* ignore p1..N - we'll use p0:N instead */
continue;
}
if (m == NULL) {
continue;
}
if (maindev_path != NULL) {
}
maindev = m;
} else {
g_queue_push_tail (mq, m);
}
}
/* shouldn't typically happen */
while (!g_queue_is_empty (mq)) {
}
goto err;
}
/* first enqueue main storage device */
if (!rescan) {
}
/* add virtual dos volumes to enable pcfs probing */
if (!is_cdrom) {
for (i = 1; i < 16; i++) {
g_queue_push_tail (mq, m);
}
}
}
/* enqueue all volumes */
while (!g_queue_is_empty (mq)) {
m = g_queue_pop_head (mq);
continue;
}
/* don't do p0 on cdrom */
continue;
}
if (rescan) {
/* in rescan mode, don't reprobe existing volumes */
/* XXX detect volume removal? */
"solaris.devfs_path", m->devpath);
} else {
}
} else {
}
}
if (maindev_path != NULL) {
}
return;
err:
if (maindev_path != NULL) {
}
if (!rescan) {
}
}
{
HalDevice *d;
char *raw;
d = hal_device_new ();
hal_device_set_udi (d, udi);
hal_device_add_capability (d, "volume");
hal_device_add_capability (d, "block");
/* set volume defaults */
hal_device_add_capability (d, "volume.disc");
} else {
}
if (dosnum > 0) {
} else {
}
/* prober may override these */
return (d);
}
static void
{
char *whole_disk;
char *block_device;
const char *storage_udi;
const char *slice;
int dos_num;
if (hal_device_property_get_bool (d, "info.ignore")) {
goto skip;
}
/*
* Optimizations: only probe if there's a chance to find something
*/
goto skip;
}
goto skip;
}
/* don't probe more dos volumes than probe-storage found */
goto skip;
}
} else {
/* if no VTOC slices found, don't probe slices except s2 */
goto skip;
}
}
hald_runner_run (d,
"hald-probe-volume", NULL,
return;
skip:
hal_device_store_remove (hald_get_tdl (), d);
g_object_unref (d);
}
static void
devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
{
goto skip;
}
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 */
/* Run preprobe callouts */
return;
skip:
g_object_unref (d);
}
void
devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
{
const char *drive_type;
const char *p_udi;
const char *phys_bus;
const char *bus;
"pseudo" };
int i;
goto error;
}
/*
* figure out physical device and bus, except for floppy
*/
goto skip_bus;
}
for (;;) {
break;
}
}
}
/* up the tree */
break;
}
}
} else {
}
/* add to TDL so preprobing callouts and prober can access it */
hal_device_store_add (hald_get_tdl (), d);
/* Process preprobe fdi files */
/* Run preprobe callouts */
return;
g_object_unref (d);
}
static void
devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
{
/* Discard device if probing reports failure */
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);
return;
}
/* Merge properties from .fdi files */
}
const gchar *
{
return "hald-probe-storage";
}
const gchar *
{
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)
{
char *p;
if (devfs_path_orig == NULL) {
HAL_INFO (("device has no solaris.devfs_path"));
return;
}
/* strip trailing minor part if any */
*p = '\0';
}
} else {
devfs_path = (char *)devfs_path_orig;
}
return;
} else {
}
if (devfs_path != devfs_path_orig) {
free (devfs_path);
}
}
/*
* 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).
*/
{
GSList *i;
HalDevice *v;
const char *drive_type;
if (hal_device_property_get_bool (d, "block.is_volume")) {
HAL_INFO (("nothing to do for volume"));
return (FALSE);
}
hal_device_property_get_bool (d, "storage.removable.media_available");
if (!media_available && !is_floppy) {
"block.storage_device", hal_device_get_udi (d));
v = HAL_DEVICE (i->data);
} else {
}
}
} else if (is_floppy) {
hald_runner_run (d,
"hald-probe-storage --only-check-for-media", NULL,
} else {
hald_runner_run (d,
"hald-probe-storage --only-check-for-media", NULL,
}
return TRUE;
}
static char *
{
char *s = NULL;
char *p;
return (p + sizeof ("/lofi/") - 1);
}
s = part;
s = slice;
} else {
s = disk;
}
return (s);
} else {
return ("");
}
}
static gboolean
{
char *p;
return (FALSE);
}
}
static gboolean
{
char *p;
return (FALSE);
}
return (FALSE);
}
p[0] = '\0';
p[0] = ':';
}
static void
{
}
void
{
struct extmnttab m;
HalDevice *d;
unsigned int major;
unsigned int minor;
GSList *v;
char *mount_point;
const char *fstype;
int partition_number;
if (hal_volume != NULL) {
} else {
volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
}
return;
}
return;
}
d = HAL_DEVICE (v->data);
/*
* special handling for pcfs, which encodes logical
* drive number into the 6 upper bits of the minor
*/
}
continue;
}
/* this volume matches the mnttab entry */
hal_device_property_set_bool (d, "volume.is_mounted_read_only",
HAL_INFO (("set %s to be mounted at %s",
hal_device_get_udi (d), m.mnt_mountp));
}
}
/* all remaining volumes are not mounted */
d = HAL_DEVICE (v->data);
continue;
}
/* cleanup if was mounted by us */
if (hal_util_is_mounted_by_hald (mount_point)) {
char *cleanup_stdin;
cleanup_stdin = "\n";
"hal-storage-cleanup-mountpoint",
0,
}
}
}
static void
{
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));
}
}
}
static void
{
const char *device_file;
const char *mount_point;
char *unmount_stdin;
extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) {
return;
}
unmount_stdin = "\n";
"hal-storage-unmount",
0,
}
void
{
if (hal_device_property_get_bool (d, "volume.is_mounted")) {
} else {
}
}
enum {
};
static const char *legacy_media_str[] = {
"cdrom",
"floppy",
"rmdisk"
};
struct enum_nick {
const char *type;
};
static int
{
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,
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
{
const char *media_type;
int media_num;
(media_num >= 0)) {
}
return TRUE;
}
static void
{
if (media_num == 0) {
}
}
static void
{
int media;
const char *media_type;
int media_num;
GSList *i;
if ((media = devinfo_storage_get_legacy_media (d)) < 0) {
return;
}
/* enumerate all storage devices of this media type */
/* find a free number */
break;
}
}
if (i == NULL) {
break;
}
}
/* primary nickname, and also vold-style symdev */
/* additional nicknames */
if (media == LEGACY_CDROM) {
} else if (media == LEGACY_FLOPPY) {
}
}