Home | History | Annotate | Download | only in solaris
      1 /***************************************************************************
      2  *
      3  * devinfo_storage.c : storage devices
      4  *
      5  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      6  * Use is subject to license terms.
      7  *
      8  * Licensed under the Academic Free License version 2.1
      9  *
     10  **************************************************************************/
     11 
     12 #ifdef HAVE_CONFIG_H
     13 #  include <config.h>
     14 #endif
     15 
     16 #include <stdio.h>
     17 #include <string.h>
     18 #include <strings.h>
     19 #include <ctype.h>
     20 #include <libdevinfo.h>
     21 #include <sys/types.h>
     22 #include <sys/mkdev.h>
     23 #include <sys/stat.h>
     24 #include <sys/mntent.h>
     25 #include <sys/mnttab.h>
     26 
     27 #include "../osspec.h"
     28 #include "../logger.h"
     29 #include "../hald.h"
     30 #include "../hald_dbus.h"
     31 #include "../device_info.h"
     32 #include "../util.h"
     33 #include "../hald_runner.h"
     34 #include "hotplug.h"
     35 #include "devinfo.h"
     36 #include "devinfo_misc.h"
     37 #include "devinfo_storage.h"
     38 #include "osspec_solaris.h"
     39 
     40 #ifdef sparc
     41 #define	WHOLE_DISK	"s2"
     42 #else
     43 #define	WHOLE_DISK	"p0"
     44 #endif
     45 
     46 /* some devices,especially CDROMs, may take a while to be probed (values in ms) */
     47 #define	DEVINFO_PROBE_STORAGE_TIMEOUT	60000
     48 #define	DEVINFO_PROBE_VOLUME_TIMEOUT	60000
     49 
     50 typedef struct devinfo_storage_minor {
     51 	char	*devpath;
     52 	char	*devlink;
     53 	char	*slice;
     54 	dev_t	dev;
     55 	int	dosnum;	/* dos disk number or -1 */
     56 } devinfo_storage_minor_t;
     57 
     58 HalDevice *devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
     59 static HalDevice *devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path);
     60 static HalDevice *devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path);
     61 static HalDevice *devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
     62 HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
     63 static HalDevice *devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
     64 HalDevice *devinfo_pcata_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
     65 static HalDevice *devinfo_pcata_storage_add(HalDevice *parent, di_node_t node, char *devfs_path);
     66 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
     67 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node);
     68 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
     69 static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev);
     70 static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean);
     71 static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice,
     72     char *devlink, dev_t dev, int dosnum);
     73 static void devinfo_storage_free_minor(struct devinfo_storage_minor *m);
     74 HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m);
     75 static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2);
     76 static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
     77 static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token);
     78 static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2);
     79 const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout);
     80 const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout);
     81 
     82 static char *devinfo_scsi_dtype2str(int dtype);
     83 static char *devinfo_volume_get_slice_name (char *devlink);
     84 static gboolean dos_to_dev(char *path, char **devpath, int *partnum);
     85 static gboolean is_dos_path(char *path, int *partnum);
     86 
     87 static void devinfo_storage_set_nicknames (HalDevice *d);
     88 
     89 DevinfoDevHandler devinfo_ide_handler = {
     90         devinfo_ide_add,
     91 	NULL,
     92 	NULL,
     93 	NULL,
     94 	NULL,
     95         NULL
     96 };
     97 DevinfoDevHandler devinfo_scsi_handler = {
     98         devinfo_scsi_add,
     99 	NULL,
    100 	NULL,
    101 	NULL,
    102 	NULL,
    103         NULL
    104 };
    105 DevinfoDevHandler devinfo_pcata_handler = {
    106         devinfo_pcata_add,
    107 	NULL,
    108 	NULL,
    109 	NULL,
    110 	NULL,
    111         NULL
    112 };
    113 DevinfoDevHandler devinfo_floppy_handler = {
    114         devinfo_floppy_add,
    115 	NULL,
    116 	NULL,
    117 	NULL,
    118 	NULL,
    119         NULL
    120 };
    121 DevinfoDevHandler devinfo_lofi_handler = {
    122         devinfo_lofi_add,
    123 	NULL,
    124 	NULL,
    125 	NULL,
    126 	NULL,
    127         NULL
    128 };
    129 DevinfoDevHandler devinfo_storage_handler = {
    130 	NULL,
    131 	NULL,
    132 	devinfo_storage_hotplug_begin_add,
    133 	NULL,
    134 	devinfo_storage_probing_done,
    135 	devinfo_storage_get_prober
    136 };
    137 DevinfoDevHandler devinfo_volume_handler = {
    138 	NULL,
    139 	NULL,
    140 	devinfo_volume_hotplug_begin_add,
    141 	NULL,
    142 	NULL,
    143 	devinfo_volume_get_prober
    144 };
    145 
    146 /* IDE */
    147 
    148 HalDevice *
    149 devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
    150 {
    151 	char	*s;
    152 
    153 	if ((device_type != NULL) && (strcmp(device_type, "ide") == 0)) {
    154 		return (devinfo_ide_host_add(parent, node, devfs_path));
    155 	}
    156 
    157         if ((di_prop_lookup_strings (DDI_DEV_T_ANY, node, "class", &s) > 0) &&
    158 	    (strcmp (s, "dada") == 0)) {
    159 		return (devinfo_ide_device_add(parent, node, devfs_path));
    160 	}
    161 
    162 	return (NULL);
    163 }
    164 
    165 static HalDevice *
    166 devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path)
    167 {
    168 	HalDevice *d;
    169 
    170 	d = hal_device_new ();
    171 
    172 	devinfo_set_default_properties (d, parent, node, devfs_path);
    173 	hal_device_property_set_string (d, "info.product", "IDE host controller");
    174 	hal_device_property_set_string (d, "info.subsystem", "ide_host");
    175 	hal_device_property_set_int (d, "ide_host.number", 0); /* XXX */
    176 
    177 	devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
    178 
    179 	return (d);
    180 }
    181 
    182 static HalDevice *
    183 devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path)
    184 {
    185 	HalDevice *d;
    186 
    187 	d = hal_device_new();
    188 
    189 	devinfo_set_default_properties (d, parent, node, devfs_path);
    190         hal_device_property_set_string (parent, "info.product", "IDE device");
    191 	hal_device_property_set_string (parent, "info.subsystem", "ide");
    192 	hal_device_property_set_int (parent, "ide.host", 0); /* XXX */
    193 	hal_device_property_set_int (parent, "ide.channel", 0);
    194 
    195 	devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler);
    196 
    197 	return (devinfo_ide_storage_add (d, node, devfs_path));
    198 }
    199 
    200 static HalDevice *
    201 devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
    202 {
    203 	HalDevice *d;
    204 	char	*s;
    205 	int	*i;
    206 	char	*driver_name;
    207 	char	udi[HAL_PATH_MAX];
    208 
    209 	if ((driver_name = di_driver_name (node)) == NULL) {
    210 		return (NULL);
    211 	}
    212 
    213         d = hal_device_new ();
    214 
    215 	devinfo_set_default_properties (d, parent, node, devfs_path);
    216         hal_device_property_set_string (d, "info.category", "storage");
    217 
    218         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    219                 "%s/%s%d", hal_device_get_udi (parent), driver_name, di_instance (node));
    220         hal_device_set_udi (d, udi);
    221         hal_device_property_set_string (d, "info.udi", udi);
    222 	PROP_STR(d, node, s, "devid", "info.product");
    223 
    224         hal_device_add_capability (d, "storage");
    225         hal_device_property_set_string (d, "storage.bus", "ide");
    226         hal_device_property_set_int (d, "storage.lun", 0);
    227 	hal_device_property_set_string (d, "storage.drive_type", "disk");
    228 
    229 	PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
    230 	PROP_BOOL(d, node, i, "removable-media", "storage.removable");
    231 
    232         hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
    233 
    234 	/* XXX */
    235         hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
    236 
    237 	hal_device_add_capability (d, "block");
    238 
    239 	devinfo_storage_minors (d, node, (char *)devfs_path, FALSE);
    240 
    241 	return (d);
    242 }
    243 
    244 /* SCSI */
    245 
    246 HalDevice *
    247 devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
    248 {
    249 	int	*i;
    250 	char	*driver_name;
    251 	HalDevice *d;
    252 	char	udi[HAL_PATH_MAX];
    253 
    254 	driver_name = di_driver_name (node);
    255 	if ((driver_name == NULL) || (strcmp (driver_name, "sd") != 0)) {
    256 		return (NULL);
    257 	}
    258 
    259 	d = hal_device_new ();
    260 
    261 	devinfo_set_default_properties (d, parent, node, devfs_path);
    262 	hal_device_property_set_string (d, "info.subsystem", "scsi");
    263 
    264         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    265                 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
    266         hal_device_set_udi (d, udi);
    267         hal_device_property_set_string (d, "info.udi", udi);
    268 
    269 	hal_device_property_set_int (d, "scsi.host",
    270 		hal_device_property_get_int (parent, "scsi_host.host"));
    271 	hal_device_property_set_int (d, "scsi.bus", 0);
    272 	PROP_INT(d, node, i, "target", "scsi.target");
    273 	PROP_INT(d, node, i, "lun", "scsi.lun");
    274         hal_device_property_set_string (d, "info.product", "SCSI Device");
    275 
    276         devinfo_add_enqueue (d, devfs_path, &devinfo_scsi_handler);
    277 
    278         return (devinfo_scsi_storage_add (d, node, devfs_path));
    279 }
    280 
    281 static HalDevice *
    282 devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
    283 {
    284 	HalDevice *d;
    285 	int	*i;
    286 	char	*s;
    287 	char	udi[HAL_PATH_MAX];
    288 
    289 	d = hal_device_new ();
    290 
    291 	devinfo_set_default_properties (d, parent, node, devfs_path);
    292         hal_device_property_set_string (d, "info.category", "storage");
    293 
    294         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    295 		"%s/sd%d", hal_device_get_udi (parent), di_instance (node));
    296         hal_device_set_udi (d, udi);
    297         hal_device_property_set_string (d, "info.udi", udi);
    298 	PROP_STR(d, node, s, "inquiry-product-id", "info.product");
    299 
    300         hal_device_add_capability (d, "storage");
    301 
    302         hal_device_property_set_int (d, "storage.lun",
    303 		hal_device_property_get_int (parent, "scsi.lun"));
    304 	PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
    305 	PROP_BOOL(d, node, i, "removable-media", "storage.removable");
    306         hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
    307 
    308 	/*
    309 	 * We have to enable polling not only for drives with removable media,
    310 	 * but also for hotpluggable devices, because when a disk is
    311 	 * unplugged while busy/mounted, there is not sysevent generated.
    312 	 * Instead, the HBA driver (scsa2usb, scsa1394) will notify sd driver
    313 	 * and the latter will report DKIO_DEV_GONE via DKIOCSTATE ioctl.
    314 	 * So we have to enable media check so that hald-addon-storage notices
    315 	 * the "device gone" condition and unmounts all associated volumes.
    316 	 */
    317 	hal_device_property_set_bool (d, "storage.media_check_enabled",
    318 	    ((di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", &i) >= 0) ||
    319 	    (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", &i) >= 0)));
    320 
    321         if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type",
    322 	    &i) > 0) {
    323 		s = devinfo_scsi_dtype2str (*i);
    324         	hal_device_property_set_string (d, "storage.drive_type", s);
    325 
    326 		if (strcmp (s, "cdrom") == 0) {
    327 			hal_device_add_capability (d, "storage.cdrom");
    328 			hal_device_property_set_bool (d, "storage.no_partitions_hint", TRUE);
    329         		hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
    330 		}
    331 	}
    332 
    333         hal_device_add_capability (d, "block");
    334 
    335 	devinfo_storage_minors (d, node, devfs_path, FALSE);
    336 
    337 	return (d);
    338 }
    339 
    340 static char *
    341 devinfo_scsi_dtype2str(int dtype)
    342 {
    343         char *dtype2str[] = {
    344                 "disk"	,         /* DTYPE_DIRECT         0x00 */
    345                 "tape"	,         /* DTYPE_SEQUENTIAL     0x01 */
    346                 "printer",         /* DTYPE_PRINTER        0x02 */
    347                 "processor",         /* DTYPE_PROCESSOR      0x03 */
    348                 "worm"	,         /* DTYPE_WORM           0x04 */
    349                 "cdrom"	,         /* DTYPE_RODIRECT       0x05 */
    350                 "scanner",         /* DTYPE_SCANNER        0x06 */
    351                 "cdrom"	,         /* DTYPE_OPTICAL        0x07 */
    352                 "changer",         /* DTYPE_CHANGER        0x08 */
    353                 "comm"	,         /* DTYPE_COMM           0x09 */
    354                 "scsi"	,         /* DTYPE_???            0x0A */
    355                 "scsi"	,         /* DTYPE_???            0x0B */
    356                 "array_ctrl",         /* DTYPE_ARRAY_CTRL     0x0C */
    357                 "esi"	,         /* DTYPE_ESI            0x0D */
    358                 "disk"	          /* DTYPE_RBC            0x0E */
    359         };
    360 
    361         if (dtype < NELEM(dtype2str)) {
    362                 return (dtype2str[dtype]);
    363         } else {
    364 		return ("scsi");
    365         }
    366 
    367 }
    368 
    369 /* PCMCIA */
    370 
    371 HalDevice *
    372 devinfo_pcata_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
    373 {
    374 	int	*i;
    375 	char	*driver_name;
    376 	HalDevice *d;
    377 	char	udi[HAL_PATH_MAX];
    378 
    379 	driver_name = di_driver_name (node);
    380 	if ((driver_name == NULL) || (strcmp (driver_name, "pcata") != 0)) {
    381 		return (NULL);
    382 	}
    383 
    384 	d = hal_device_new ();
    385 
    386 	devinfo_set_default_properties (d, parent, node, devfs_path);
    387 	hal_device_property_set_string (d, "info.subsystem", "pcmcia");
    388 
    389         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    390                 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
    391         hal_device_set_udi (d, udi);
    392         hal_device_property_set_string (d, "info.udi", udi);
    393         hal_device_property_set_string (d, "info.product", "PCMCIA Disk");
    394 
    395         devinfo_add_enqueue (d, devfs_path, &devinfo_pcata_handler);
    396 
    397         return (devinfo_pcata_storage_add (d, node, devfs_path));
    398 }
    399 
    400 static HalDevice *
    401 devinfo_pcata_storage_add(HalDevice *parent, di_node_t node, char *devfs_path)
    402 {
    403 	HalDevice *d;
    404 	char	*driver_name;
    405 	int	*i;
    406 	char	*s;
    407 	char	udi[HAL_PATH_MAX];
    408 
    409 	d = hal_device_new ();
    410 
    411 	devinfo_set_default_properties (d, parent, node, devfs_path);
    412 	hal_device_property_set_string (d, "info.category", "storage");
    413 
    414 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    415 		"%s/sd%d", hal_device_get_udi (parent), di_instance (node));
    416 	hal_device_set_udi (d, udi);
    417 	hal_device_property_set_string (d, "info.udi", udi);
    418 
    419 	hal_device_add_capability (d, "storage");
    420 
    421 	hal_device_property_set_int (d, "storage.lun", 0);
    422 	hal_device_property_set_bool (d, "storage.hotpluggable", TRUE);
    423 	hal_device_property_set_bool (d, "storage.removable", FALSE);
    424 	hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
    425 	hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
    426        	hal_device_property_set_string (d, "storage.drive_type", "disk");
    427 	hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
    428 
    429 	hal_device_add_capability (d, "block");
    430 
    431 	devinfo_storage_minors (d, node, devfs_path, FALSE);
    432 
    433 	return (d);
    434 }
    435 
    436 /* floppy */
    437 
    438 HalDevice *
    439 devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
    440 {
    441 	char	*driver_name;
    442 	char	*raw;
    443 	char	udi[HAL_PATH_MAX];
    444 	di_devlink_handle_t devlink_hdl;
    445         int     major;
    446         di_minor_t minor;
    447         dev_t   dev;
    448 	HalDevice *d = NULL;
    449         char    *minor_path = NULL;
    450 	char	*devlink = NULL;
    451 
    452 	driver_name = di_driver_name (node);
    453 	if ((driver_name == NULL) || (strcmp (driver_name, "fd") != 0)) {
    454 		return (NULL);
    455 	}
    456 
    457 	/*
    458 	 * The only minor node we're interested in is /dev/diskette*
    459 	 */
    460 	major = di_driver_major(node);
    461 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
    462 		return (NULL);
    463 	}
    464 	minor = DI_MINOR_NIL;
    465 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
    466 		dev = di_minor_devt(minor);
    467 		if ((major != major(dev)) ||
    468 		    (di_minor_type(minor) != DDM_MINOR) ||
    469 		    (di_minor_spectype(minor) != S_IFBLK) ||
    470 		    ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
    471 			continue;
    472 		}
    473 		if ((devlink = get_devlink(devlink_hdl, "diskette.+" , minor_path)) != NULL) {
    474 			break;
    475 		}
    476 		di_devfs_path_free (minor_path);
    477 		minor_path = NULL;
    478 		free(devlink);
    479 		devlink = NULL;
    480 	}
    481 	di_devlink_fini (&devlink_hdl);
    482 
    483 	if ((devlink == NULL) || (minor_path == NULL)) {
    484 		HAL_INFO (("floppy devlink not found %s", devfs_path));
    485 		goto out;
    486 	}
    487 
    488 	d = hal_device_new ();
    489 
    490 	devinfo_set_default_properties (d, parent, node, devfs_path);
    491         hal_device_property_set_string (d, "info.category", "storage");
    492         hal_device_add_capability (d, "storage");
    493        	hal_device_property_set_string (d, "storage.bus", "platform");
    494         hal_device_property_set_bool (d, "storage.hotpluggable", FALSE);
    495         hal_device_property_set_bool (d, "storage.removable", TRUE);
    496         hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
    497         hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
    498        	hal_device_property_set_string (d, "storage.drive_type", "floppy");
    499 
    500         hal_device_add_capability (d, "block");
    501 	hal_device_property_set_bool (d, "block.is_volume", FALSE);
    502 	hal_device_property_set_int (d, "block.major", major(dev));
    503 	hal_device_property_set_int (d, "block.minor", minor(dev));
    504 	hal_device_property_set_string (d, "block.device", devlink);
    505 	raw = dsk_to_rdsk (devlink);
    506 	hal_device_property_set_string (d, "block.solaris.raw_device", raw);
    507 	free (raw);
    508 
    509 	devinfo_add_enqueue (d, devfs_path, &devinfo_storage_handler);
    510 
    511 	/* trigger initial probe-volume */
    512 	devinfo_floppy_add_volume(d, node);
    513 
    514 out:
    515 	di_devfs_path_free (minor_path);
    516 	free(devlink);
    517 
    518 	return (d);
    519 }
    520 
    521 static void
    522 devinfo_floppy_add_volume(HalDevice *parent, di_node_t node)
    523 {
    524 	char	*devlink;
    525 	char	*devfs_path;
    526 	int	minor, major;
    527 	dev_t	dev;
    528 	struct devinfo_storage_minor *m;
    529 
    530 	devfs_path = (char *)hal_device_property_get_string (parent, "solaris.devfs_path");
    531 	devlink = (char *)hal_device_property_get_string (parent, "block.device");
    532 	major = hal_device_property_get_int (parent, "block.major");
    533 	minor = hal_device_property_get_int (parent, "block.minor");
    534 	dev = makedev (major, minor);
    535 
    536 	m = devinfo_storage_new_minor (devfs_path, WHOLE_DISK, devlink, dev, -1);
    537 	devinfo_volume_add (parent, node, m);
    538 	devinfo_storage_free_minor (m);
    539 }
    540 
    541 /*
    542  * After reprobing storage, reprobe its volumes.
    543  */
    544 static void
    545 devinfo_floppy_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code,
    546     char **error, gpointer userdata1, gpointer userdata2)
    547 {
    548         void *end_token = (void *) userdata1;
    549 	const char *devfs_path;
    550 	di_node_t node;
    551 	HalDevice *v;
    552 
    553 	if (!hal_device_property_get_bool (d, "storage.removable.media_available")) {
    554 		HAL_INFO (("no floppy media", hal_device_get_udi (d)));
    555 
    556 		/* remove child (can only be single volume) */
    557 		if (((v = hal_device_store_match_key_value_string (hald_get_gdl(),
    558         	    "info.parent", hal_device_get_udi (d))) != NULL) &&
    559 		    ((devfs_path = hal_device_property_get_string (v,
    560 		    "solaris.devfs_path")) != NULL)) {
    561 			devinfo_remove_enqueue ((char *)devfs_path, NULL);
    562 		}
    563 	} else {
    564 		HAL_INFO (("floppy media found", hal_device_get_udi (d)));
    565 
    566 		if ((devfs_path = hal_device_property_get_string(d, "solaris.devfs_path")) == NULL) {
    567 			HAL_INFO (("no devfs_path", hal_device_get_udi (d)));
    568 			hotplug_event_process_queue ();
    569 			return;
    570 		}
    571 		if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
    572 			HAL_INFO (("di_init %s failed %d", devfs_path, errno));
    573 			hotplug_event_process_queue ();
    574 			return;
    575 		}
    576 
    577 		devinfo_floppy_add_volume (d, node);
    578 
    579 		di_fini (node);
    580 	}
    581 
    582 	hotplug_event_process_queue ();
    583 }
    584 
    585 /* lofi */
    586 
    587 HalDevice *
    588 devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
    589 {
    590 	return (devinfo_lofi_add_major(parent,node, devfs_path, device_type, FALSE, NULL));
    591 }
    592 
    593 HalDevice *
    594 devinfo_lofi_add_major(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type,
    595     gboolean rescan, HalDevice *lofi_d)
    596 {
    597 	char	*driver_name;
    598 	HalDevice *d = NULL;
    599 	char	udi[HAL_PATH_MAX];
    600 	di_devlink_handle_t devlink_hdl;
    601         int     major;
    602         di_minor_t minor;
    603         dev_t   dev;
    604         char    *minor_path = NULL;
    605         char    *devlink = NULL;
    606 
    607 	driver_name = di_driver_name (node);
    608 	if ((driver_name == NULL) || (strcmp (driver_name, "lofi") != 0)) {
    609 		return (NULL);
    610 	}
    611 
    612 	if (!rescan) {
    613 		d = hal_device_new ();
    614 
    615 		devinfo_set_default_properties (d, parent, node, devfs_path);
    616 		hal_device_property_set_string (d, "info.subsystem", "pseudo");
    617 
    618         	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    619                 	"%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
    620         	hal_device_set_udi (d, udi);
    621         	hal_device_property_set_string (d, "info.udi", udi);
    622 
    623         	devinfo_add_enqueue (d, devfs_path, &devinfo_lofi_handler);
    624 	} else {
    625 		d = lofi_d;
    626 	}
    627 
    628 	/*
    629 	 * Unlike normal storage, as in devinfo_storage_minors(), where
    630 	 * sd instance -> HAL storage, sd minor node -> HAL volume,
    631 	 * lofi always has one instance, lofi minor -> HAL storage.
    632 	 * lofi storage never has slices, but it can have
    633 	 * embedded pcfs partitions that fstyp would recognize
    634 	 */
    635 	major = di_driver_major(node);
    636 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
    637 		return (d);
    638 	}
    639 	minor = DI_MINOR_NIL;
    640 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
    641 		dev = di_minor_devt(minor);
    642 		if ((major != major(dev)) ||
    643 		    (di_minor_type(minor) != DDM_MINOR) ||
    644 		    (di_minor_spectype(minor) != S_IFBLK) ||
    645 		    ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
    646 			continue;
    647 		}
    648 		if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
    649 			di_devfs_path_free (minor_path);
    650         		continue;
    651 		}
    652 
    653 		if (!rescan ||
    654 		    (hal_device_store_match_key_value_string (hald_get_gdl (),
    655 		    "solaris.devfs_path", minor_path) == NULL)) {
    656 			devinfo_lofi_add_minor(d, node, minor_path, devlink, dev);
    657 		}
    658 
    659 		di_devfs_path_free (minor_path);
    660 		free(devlink);
    661 	}
    662 	di_devlink_fini (&devlink_hdl);
    663 
    664 	return (d);
    665 }
    666 
    667 static void
    668 devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev)
    669 {
    670 	HalDevice *d;
    671 	char	*raw;
    672 	char	*doslink;
    673 	char	dospath[64];
    674 	struct devinfo_storage_minor *m;
    675 	int	i;
    676 
    677 	/* add storage */
    678 	d = hal_device_new ();
    679 
    680 	devinfo_set_default_properties (d, parent, node, minor_path);
    681         hal_device_property_set_string (d, "info.category", "storage");
    682         hal_device_add_capability (d, "storage");
    683        	hal_device_property_set_string (d, "storage.bus", "lofi");
    684         hal_device_property_set_bool (d, "storage.hotpluggable", TRUE);
    685         hal_device_property_set_bool (d, "storage.removable", FALSE);
    686         hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
    687        	hal_device_property_set_string (d, "storage.drive_type", "disk");
    688         hal_device_add_capability (d, "block");
    689 	hal_device_property_set_int (d, "block.major", major(dev));
    690 	hal_device_property_set_int (d, "block.minor", minor(dev));
    691 	hal_device_property_set_string (d, "block.device", devlink);
    692 	raw = dsk_to_rdsk (devlink);
    693 	hal_device_property_set_string (d, "block.solaris.raw_device", raw);
    694 	free (raw);
    695 	hal_device_property_set_bool (d, "block.is_volume", FALSE);
    696 
    697 	devinfo_add_enqueue (d, minor_path, &devinfo_storage_handler);
    698 
    699 	/* add volumes: one on main device and a few pcfs candidates */
    700 	m = devinfo_storage_new_minor(minor_path, WHOLE_DISK, devlink, dev, -1);
    701 	devinfo_volume_add (d, node, m);
    702 	devinfo_storage_free_minor (m);
    703 
    704 	doslink = (char *)calloc (1, strlen (devlink) + sizeof (":NNN") + 1);
    705 	if (doslink != NULL) {
    706 		for (i = 1; i < 16; i++) {
    707 			snprintf(dospath, sizeof (dospath), WHOLE_DISK":%d", i);
    708 			sprintf(doslink, "%s:%d", devlink, i);
    709 			m = devinfo_storage_new_minor(minor_path, dospath, doslink, dev, i);
    710 			devinfo_volume_add (d, node, m);
    711 			devinfo_storage_free_minor (m);
    712 		}
    713 		free (doslink);
    714 	}
    715 }
    716 
    717 void
    718 devinfo_lofi_remove_minor(char *parent_devfs_path, char *name)
    719 {
    720 	GSList *i;
    721 	GSList *devices;
    722 	HalDevice *d = NULL;
    723 	const char *devfs_path;
    724 
    725 	devices = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
    726 		"block.solaris.raw_device", name);
    727         for (i = devices; i != NULL; i = g_slist_next (i)) {
    728 		if (hal_device_has_capability (HAL_DEVICE (i->data), "storage")) {
    729 			d = HAL_DEVICE (i->data);
    730 			break;
    731 		}
    732 	}
    733 	g_slist_free (devices);
    734 
    735 	if (d == NULL) {
    736 		HAL_INFO (("device not found %s", name));
    737 		return;
    738 	}
    739 
    740 	if ((devfs_path = hal_device_property_get_string (d,
    741 	    "solaris.devfs_path")) == NULL) {
    742 		HAL_INFO (("devfs_path not found %s", hal_device_get_udi (d)));
    743 		return;
    744 	}
    745 
    746 	if (d != NULL) {
    747 		devinfo_remove_branch ((char *)devfs_path, d);
    748 	}
    749 }
    750 
    751 /* common storage */
    752 
    753 static void
    754 devinfo_storage_free_minor(struct devinfo_storage_minor *m)
    755 {
    756 	if (m != NULL) {
    757 		free (m->slice);
    758 		free (m->devlink);
    759 		free (m->devpath);
    760 		free (m);
    761 	}
    762 }
    763 
    764 static struct devinfo_storage_minor *
    765 devinfo_storage_new_minor(char *maindev_path, char *slice, char *devlink, dev_t dev, int dosnum)
    766 {
    767 	struct devinfo_storage_minor *m;
    768 	int pathlen;
    769 	char *devpath;
    770 
    771 	m = (struct devinfo_storage_minor *)calloc (sizeof (struct devinfo_storage_minor), 1);
    772 	if (m != NULL) {
    773 		/*
    774 		 * For volume's devfs_path we'll use minor_path/slice instead of
    775 		 * minor_path which we use for parent storage device.
    776 		 */
    777 		pathlen = strlen (maindev_path) + strlen (slice) + 2;
    778 		devpath = (char *)calloc (1, pathlen);
    779 		snprintf(devpath, pathlen, "%s/%s", maindev_path, slice);
    780 
    781 		m->devpath = devpath;
    782 		m->devlink = strdup (devlink);
    783 		m->slice = strdup (slice);
    784 		m->dev = dev;
    785 		m->dosnum = dosnum;
    786 		if ((m->devpath == NULL) || (m->devlink == NULL)) {
    787 			devinfo_storage_free_minor (m);
    788 			m = NULL;
    789 		}
    790 	}
    791 	return (m);
    792 }
    793 
    794 /*
    795  * Storage minor nodes are potential "volume" objects.
    796  * This function also completes building the parent object (main storage device).
    797  */
    798 static void
    799 devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean rescan)
    800 {
    801 	di_devlink_handle_t devlink_hdl;
    802 	gboolean is_cdrom;
    803 	const char *whole_disk;
    804 	int     major;
    805 	di_minor_t minor;
    806 	dev_t   dev;
    807 	char    *minor_path = NULL;
    808 	char    *maindev_path = NULL;
    809 	char    *devpath, *devlink;
    810 	int	doslink_len;
    811 	char	*doslink;
    812 	char	dospath[64];
    813 	char    *slice;
    814 	int	pathlen;
    815 	int	i;
    816 	char	*raw;
    817 	boolean_t maindev_is_d0;
    818 	GQueue	*mq;
    819 	HalDevice *volume;
    820 	struct devinfo_storage_minor *m;
    821 	struct devinfo_storage_minor *maindev = NULL;
    822 
    823 	/* for cdroms whole disk is always s2 */
    824 	is_cdrom = hal_device_has_capability (parent, "storage.cdrom");
    825 	whole_disk = is_cdrom ? "s2" : WHOLE_DISK;
    826 
    827 	major = di_driver_major(node);
    828 
    829 	/* the "whole disk" p0/s2/d0 node must come first in the hotplug queue
    830 	 * so we put other minor nodes on the local queue and move to the
    831 	 * hotplug queue up in the end
    832 	 */
    833 	if ((mq = g_queue_new()) == NULL) {
    834 		goto err;
    835 	}
    836 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
    837 		g_queue_free (mq);
    838 		goto err;
    839 	}
    840 	minor = DI_MINOR_NIL;
    841 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
    842 		dev = di_minor_devt(minor);
    843 		if ((major != major(dev)) ||
    844 		    (di_minor_type(minor) != DDM_MINOR) ||
    845 		    (di_minor_spectype(minor) != S_IFBLK) ||
    846 		    ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
    847 			continue;
    848 		}
    849 		if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
    850 			di_devfs_path_free (minor_path);
    851         		continue;
    852 		}
    853 
    854 		slice = devinfo_volume_get_slice_name (devlink);
    855 		if (strlen (slice) < 2) {
    856 			free (devlink);
    857 			di_devfs_path_free (minor_path);
    858 			continue;
    859 		}
    860 
    861 		/* ignore p1..N - we'll use p0:N instead */
    862 		if ((strlen (slice) > 1) && (slice[0] == 'p') && isdigit(slice[1]) &&
    863 		    ((atol(&slice[1])) > 0)) {
    864 			free (devlink);
    865 			di_devfs_path_free (minor_path);
    866 			continue;
    867 		}
    868 
    869 		m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1);
    870 		if (m == NULL) {
    871 			free (devlink);
    872 			di_devfs_path_free (minor_path);
    873 			continue;
    874 		}
    875 
    876 		/* main device is either s2/p0 or d0, the latter taking precedence */
    877 		if ((strcmp (slice, "d0") == 0) ||
    878 		    (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) {
    879 			if (maindev_path != NULL) {
    880 				di_devfs_path_free (maindev_path);
    881 			}
    882 			maindev_path = minor_path;
    883 			maindev = m;
    884 			g_queue_push_head (mq, maindev);
    885 		} else {
    886 			di_devfs_path_free (minor_path);
    887 			g_queue_push_tail (mq, m);
    888 		}
    889 
    890 		free (devlink);
    891 	}
    892 	di_devlink_fini (&devlink_hdl);
    893 
    894 	if (maindev == NULL) {
    895 		/* shouldn't typically happen */
    896 		while (!g_queue_is_empty (mq)) {
    897 			devinfo_storage_free_minor (g_queue_pop_head (mq));
    898 		}
    899 		goto err;
    900 	}
    901 
    902 	/* first enqueue main storage device */
    903 	if (!rescan) {
    904 		hal_device_property_set_int (parent, "block.major", major);
    905 		hal_device_property_set_int (parent, "block.minor", minor(maindev->dev));
    906 		hal_device_property_set_string (parent, "block.device", maindev->devlink);
    907 		raw = dsk_to_rdsk (maindev->devlink);
    908 		hal_device_property_set_string (parent, "block.solaris.raw_device", raw);
    909 		free (raw);
    910 		hal_device_property_set_bool (parent, "block.is_volume", FALSE);
    911 		hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path);
    912 		devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler);
    913 	}
    914 
    915 	/* add virtual dos volumes to enable pcfs probing */
    916 	if (!is_cdrom) {
    917 		doslink_len = strlen (maindev->devlink) + sizeof (":NNN") + 1;
    918 		if ((doslink = (char *)calloc (1, doslink_len)) != NULL) {
    919 			for (i = 1; i < 16; i++) {
    920 				snprintf(dospath, sizeof (dospath), "%s:%d", maindev->slice, i);
    921 				snprintf(doslink, doslink_len, "%s:%d", maindev->devlink, i);
    922 				m = devinfo_storage_new_minor(maindev_path, dospath, doslink, maindev->dev, i);
    923 				g_queue_push_tail (mq, m);
    924 			}
    925 			free (doslink);
    926 		}
    927 	}
    928 
    929 	maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0);
    930 
    931 	/* enqueue all volumes */
    932 	while (!g_queue_is_empty (mq)) {
    933 		m = g_queue_pop_head (mq);
    934 
    935 		/* if main device is d0, we'll throw away s2/p0 */
    936 		if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) {
    937 			devinfo_storage_free_minor (m);
    938 			continue;
    939 		}
    940 		/* don't do p0 on cdrom */
    941 		if (is_cdrom && (strcmp (m->slice, "p0") == 0)) {
    942 			devinfo_storage_free_minor (m);
    943 			continue;
    944 		}
    945 		if (rescan) {
    946 			/* in rescan mode, don't reprobe existing volumes */
    947 			/* XXX detect volume removal? */
    948 			volume = hal_device_store_match_key_value_string (hald_get_gdl (),
    949 			    "solaris.devfs_path", m->devpath);
    950 			if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) {
    951 				devinfo_volume_add (parent, node, m);
    952 			} else {
    953 				HAL_INFO(("rescan volume exists %s", m->devpath));
    954 			}
    955 		} else {
    956 			devinfo_volume_add (parent, node, m);
    957 		}
    958 		devinfo_storage_free_minor (m);
    959 	}
    960 
    961 	if (maindev_path != NULL) {
    962 		di_devfs_path_free (maindev_path);
    963 	}
    964 
    965 	return;
    966 
    967 err:
    968 	if (maindev_path != NULL) {
    969 		di_devfs_path_free (maindev_path);
    970 	}
    971 	if (!rescan) {
    972 		devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler);
    973 	}
    974 }
    975 
    976 HalDevice *
    977 devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m)
    978 {
    979 	HalDevice *d;
    980 	char	*raw;
    981         char    udi[HAL_PATH_MAX];
    982 	char	*devfs_path = m->devpath;
    983 	char	*devlink = m->devlink;
    984 	dev_t	dev = m->dev;
    985 	int	dosnum = m->dosnum;
    986 	char	*slice = m->slice;
    987 
    988 	HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink));
    989 	d = hal_device_new ();
    990 
    991 	devinfo_set_default_properties (d, parent, node, devfs_path);
    992         hal_device_property_set_string (d, "info.category", "volume");
    993 
    994        	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
    995 		"%s/%s", hal_device_get_udi (parent), slice);
    996         hal_device_set_udi (d, udi);
    997         hal_device_property_set_string (d, "info.udi", udi);
    998         hal_device_property_set_string (d, "info.product", slice);
    999 
   1000        	hal_device_add_capability (d, "volume");
   1001        	hal_device_add_capability (d, "block");
   1002 	hal_device_property_set_int (d, "block.major", major (dev));
   1003 	hal_device_property_set_int (d, "block.minor", minor (dev));
   1004 	hal_device_property_set_string (d, "block.device", devlink);
   1005 	raw = dsk_to_rdsk (devlink);
   1006 	hal_device_property_set_string (d, "block.solaris.raw_device", raw);
   1007 	free (raw);
   1008 	hal_device_property_set_string (d, "block.solaris.slice", slice);
   1009 	hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */
   1010 
   1011 	hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent));
   1012 
   1013 	/* set volume defaults */
   1014 	hal_device_property_set_string (d, "volume.fstype", "");
   1015 	hal_device_property_set_string (d, "volume.fsusage", "");
   1016 	hal_device_property_set_string (d, "volume.fsversion", "");
   1017 	hal_device_property_set_string (d, "volume.uuid", "");
   1018 	hal_device_property_set_string (d, "volume.label", "");
   1019 	hal_device_property_set_string (d, "volume.mount_point", "");
   1020 	hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
   1021 	if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) {
   1022 		hal_device_property_set_bool (d, "volume.is_disc", TRUE);
   1023 		hal_device_add_capability (d, "volume.disc");
   1024 	} else {
   1025 		hal_device_property_set_bool (d, "volume.is_disc", FALSE);
   1026 	}
   1027 
   1028 	if (dosnum > 0) {
   1029 		hal_device_property_set_bool (d, "volume.is_partition", TRUE);
   1030 		hal_device_property_set_int (d, "volume.partition.number", dosnum);
   1031 	} else {
   1032 		hal_device_property_set_bool (d, "volume.is_partition", FALSE);
   1033 	}
   1034 
   1035 	/* prober may override these */
   1036         hal_device_property_set_int (d, "volume.block_size", 512);
   1037 
   1038 	devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler);
   1039 
   1040 	return (d);
   1041 }
   1042 
   1043 static void
   1044 devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
   1045 {
   1046 	void *end_token = (void *) userdata1;
   1047 	char *whole_disk;
   1048 	char *block_device;
   1049 	const char *storage_udi;
   1050 	HalDevice *storage_d;
   1051 	const char *slice;
   1052 	int dos_num;
   1053 
   1054 	if (hal_device_property_get_bool (d, "info.ignore")) {
   1055 		HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d)));
   1056 		goto skip;
   1057 	}
   1058 
   1059 	/*
   1060 	 * Optimizations: only probe if there's a chance to find something
   1061 	 */
   1062 	block_device = (char *)hal_device_property_get_string (d, "block.device");
   1063 	storage_udi = hal_device_property_get_string (d, "block.storage_device");
   1064 	slice = hal_device_property_get_string(d, "block.solaris.slice");
   1065 	if ((block_device == NULL) || (storage_udi == NULL) ||
   1066 	    (slice == NULL) || (strlen (slice) < 2)) {
   1067 		HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d)));
   1068 		goto skip;
   1069 	}
   1070 	storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi);
   1071 	if (storage_d == NULL) {
   1072 		HAL_INFO (("Storage device not found %s", hal_device_get_udi (d)));
   1073 		goto skip;
   1074 	}
   1075 
   1076 	whole_disk = hal_device_has_capability (storage_d,
   1077 	    "storage.cdrom") ? "s2" : WHOLE_DISK;
   1078 
   1079 	if (is_dos_path(block_device, &dos_num)) {
   1080 		/* don't probe more dos volumes than probe-storage found */
   1081 		if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") ||
   1082 		    (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) {
   1083 			    HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d,
   1084 				"storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d)));
   1085 			goto skip;
   1086 		}
   1087 	} else {
   1088 		/* if no VTOC slices found, don't probe slices except s2 */
   1089 		if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) &&
   1090 		    !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) {
   1091 			HAL_INFO (("Not probing slice %s", hal_device_get_udi (d)));
   1092 			goto skip;
   1093 		}
   1094 	}
   1095 
   1096 	HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
   1097 	hald_runner_run (d,
   1098 			"hald-probe-volume", NULL,
   1099 			DEVINFO_PROBE_VOLUME_TIMEOUT,
   1100 			devinfo_callouts_probing_done,
   1101 			(gpointer) end_token, userdata2);
   1102 
   1103 	return;
   1104 
   1105 skip:
   1106 	hal_device_store_remove (hald_get_tdl (), d);
   1107 	g_object_unref (d);
   1108 	hotplug_event_end (end_token);
   1109 }
   1110 
   1111 static void
   1112 devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
   1113 {
   1114 	HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d)));
   1115 
   1116 	if (parent == NULL) {
   1117 		HAL_INFO (("no parent %s", hal_device_get_udi (d)));
   1118 		goto skip;
   1119 	}
   1120 
   1121 	if (hal_device_property_get_bool (parent, "info.ignore")) {
   1122 		HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE"));
   1123 		goto skip;
   1124 	}
   1125 
   1126         /* add to TDL so preprobing callouts and prober can access it */
   1127         hal_device_store_add (hald_get_tdl (), d);
   1128 
   1129         /* Process preprobe fdi files */
   1130         di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
   1131 
   1132         /* Run preprobe callouts */
   1133         hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler);
   1134 
   1135 	return;
   1136 
   1137 skip:
   1138 	g_object_unref (d);
   1139 	hotplug_event_end (end_token);
   1140 }
   1141 
   1142 void
   1143 devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
   1144 {
   1145 	const char *drive_type;
   1146 	const char *p_udi;
   1147 	HalDevice *p_d;
   1148 	HalDevice *phys_d = NULL;
   1149 	const char *phys_bus;
   1150 	const char *bus;
   1151 	static const char *busses[] = { "usb", "ide", "scsi", "ieee1394",
   1152 					"pseudo" };
   1153 	int i;
   1154 
   1155 	HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d)));
   1156 
   1157 	if (parent == NULL) {
   1158 		HAL_INFO (("no parent %s", hal_device_get_udi (d)));
   1159 		goto error;
   1160 	}
   1161 
   1162 	/*
   1163 	 * figure out physical device and bus, except for floppy
   1164 	 */
   1165 	drive_type = hal_device_property_get_string (d, "storage.drive_type");
   1166 	if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) {
   1167 		goto skip_bus;
   1168 	}
   1169 
   1170 	p_d = parent;
   1171 	for (;;) {
   1172 		bus = hal_device_property_get_string (p_d, "info.subsystem");
   1173 		if (bus != NULL) {
   1174 			for (i = 0; i < NELEM(busses); i++) {
   1175 				if (strcmp(bus, busses[i]) == 0) {
   1176 					phys_d = p_d;
   1177 					phys_bus = busses[i];
   1178 					break;
   1179 				}
   1180 			}
   1181 		}
   1182 		/* up the tree */
   1183 		p_udi = hal_device_property_get_string (p_d, "info.parent");
   1184 		if (p_udi == NULL) {
   1185 			break;
   1186 		}
   1187 		p_d = hal_device_store_find (hald_get_gdl (), p_udi);
   1188 	}
   1189 	if (phys_d == NULL) {
   1190 		HAL_INFO (("no physical device %s", hal_device_get_udi (d)));
   1191 	} else {
   1192 		hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d));
   1193 		hal_device_property_set_string (d, "storage.bus", phys_bus);
   1194 	}
   1195 
   1196 skip_bus:
   1197 
   1198 	/* add to TDL so preprobing callouts and prober can access it */
   1199 	hal_device_store_add (hald_get_tdl (), d);
   1200 
   1201 	/* Process preprobe fdi files */
   1202 	di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
   1203 
   1204 	/* Run preprobe callouts */
   1205 	hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
   1206 
   1207 	return;
   1208 
   1209 error:
   1210 	g_object_unref (d);
   1211 	hotplug_event_end (end_token);
   1212 }
   1213 
   1214 static void
   1215 devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
   1216 {
   1217         void *end_token = (void *) userdata1;
   1218 
   1219 	HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d)));
   1220 
   1221         /* Discard device if probing reports failure */
   1222         if (exit_type != HALD_RUN_SUCCESS || return_code != 0) {
   1223 		HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code));
   1224                 hal_device_store_remove (hald_get_tdl (), d);
   1225                 g_object_unref (d);
   1226                 hotplug_event_end (end_token);
   1227 		return;
   1228         }
   1229 
   1230 	devinfo_storage_set_nicknames (d);
   1231 
   1232         /* Merge properties from .fdi files */
   1233         di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
   1234         di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
   1235 
   1236 	hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
   1237 }
   1238 
   1239 const gchar *
   1240 devinfo_storage_get_prober (HalDevice *d, int *timeout)
   1241 {
   1242 	*timeout = DEVINFO_PROBE_STORAGE_TIMEOUT;
   1243 	return "hald-probe-storage";
   1244 }
   1245 
   1246 const gchar *
   1247 devinfo_volume_get_prober (HalDevice *d, int *timeout)
   1248 {
   1249 	*timeout = DEVINFO_PROBE_VOLUME_TIMEOUT;
   1250 	return "hald-probe-volume";
   1251 }
   1252 
   1253 /*
   1254  * After reprobing storage, reprobe its volumes.
   1255  */
   1256 static void
   1257 devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
   1258 {
   1259         void *end_token = (void *) userdata1;
   1260 	const char *devfs_path_orig = NULL;
   1261 	char *devfs_path = NULL;
   1262 	char *p;
   1263 	di_node_t node;
   1264 
   1265 	HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d)));
   1266 
   1267 	devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path");
   1268 	if (devfs_path_orig == NULL) {
   1269 		HAL_INFO (("device has no solaris.devfs_path"));
   1270 		hotplug_event_process_queue ();
   1271 		return;
   1272 	}
   1273 
   1274 	/* strip trailing minor part if any */
   1275 	if (strrchr(devfs_path_orig, ':') != NULL) {
   1276 		if ((devfs_path = strdup (devfs_path_orig)) != NULL) {
   1277 			p = strrchr(devfs_path, ':');
   1278 			*p = '\0';
   1279 		}
   1280 	} else {
   1281 		devfs_path = (char *)devfs_path_orig;
   1282 	}
   1283 
   1284 	if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
   1285 		HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d)));
   1286 		hotplug_event_process_queue ();
   1287 		return;
   1288 	} else {
   1289 		devinfo_storage_minors (d, node, (char *)devfs_path, TRUE);
   1290 		di_fini (node);
   1291 	}
   1292 
   1293 	if (devfs_path != devfs_path_orig) {
   1294 		free (devfs_path);
   1295 	}
   1296 
   1297 	hotplug_event_process_queue ();
   1298 }
   1299 
   1300 /*
   1301  * For removable media devices, check for "storage.removable.media_available".
   1302  * For non-removable media devices, assume media is always there.
   1303  *
   1304  * If media is gone, enqueue remove events for all children volumes.
   1305  * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone).
   1306  */
   1307 gboolean
   1308 devinfo_storage_device_rescan (HalDevice *d)
   1309 {
   1310 	GSList *i;
   1311 	GSList *volumes;
   1312 	HalDevice *v;
   1313 	gchar *v_devfs_path;
   1314 	const char *drive_type;
   1315 	gboolean is_floppy;
   1316 	gboolean media_available;
   1317 
   1318 	HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d)));
   1319 
   1320 	if (hal_device_property_get_bool (d, "block.is_volume")) {
   1321 		HAL_INFO (("nothing to do for volume"));
   1322 		return (FALSE);
   1323 	}
   1324 
   1325 	drive_type = hal_device_property_get_string (d, "storage.drive_type");
   1326 	is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0);
   1327 
   1328 	media_available = !hal_device_property_get_bool (d, "storage.removable") ||
   1329 	    hal_device_property_get_bool (d, "storage.removable.media_available");
   1330 
   1331 	if (!media_available && !is_floppy) {
   1332 		HAL_INFO (("media gone %s", hal_device_get_udi (d)));
   1333 
   1334 		volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
   1335         	    "block.storage_device", hal_device_get_udi (d));
   1336 		for (i = volumes; i != NULL; i = g_slist_next (i)) {
   1337         		v = HAL_DEVICE (i->data);
   1338 			v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path");
   1339 			HAL_INFO (("child volume %s", hal_device_get_udi (v)));
   1340 			if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) {
   1341 				HAL_INFO (("removing volume %s", hal_device_get_udi (v)));
   1342 				devinfo_remove_enqueue (v_devfs_path, NULL);
   1343 			} else {
   1344 				HAL_INFO (("not a volume %s", hal_device_get_udi (v)));
   1345 			}
   1346 		}
   1347 		g_slist_free (volumes);
   1348 
   1349 		hotplug_event_process_queue ();
   1350 	} else if (is_floppy) {
   1351 		HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d)));
   1352 
   1353 		hald_runner_run (d,
   1354 				 "hald-probe-storage --only-check-for-media", NULL,
   1355 				 DEVINFO_PROBE_STORAGE_TIMEOUT,
   1356 				 devinfo_floppy_rescan_probing_done,
   1357 				 NULL, NULL);
   1358 	} else {
   1359 		HAL_INFO (("media available %s", hal_device_get_udi (d)));
   1360 
   1361 		hald_runner_run (d,
   1362 				 "hald-probe-storage --only-check-for-media", NULL,
   1363 				 DEVINFO_PROBE_STORAGE_TIMEOUT,
   1364 				 devinfo_storage_rescan_probing_done,
   1365 				 NULL, NULL);
   1366 	}
   1367 
   1368 	return TRUE;
   1369 }
   1370 
   1371 static char *
   1372 devinfo_volume_get_slice_name (char *devlink)
   1373 {
   1374 	char	*part, *slice, *disk;
   1375 	char	*s = NULL;
   1376 	char	*p;
   1377 
   1378 	if ((p = strstr(devlink, "/lofi/")) != 0) {
   1379 		return (p + sizeof ("/lofi/") - 1);
   1380 	}
   1381 
   1382 	part = strrchr(devlink, 'p');
   1383 	slice = strrchr(devlink, 's');
   1384 	disk = strrchr(devlink, 'd');
   1385 
   1386 	if ((part != NULL) && (part > slice) && (part > disk)) {
   1387 		s = part;
   1388 	} else if ((slice != NULL) && (slice > disk)) {
   1389 		s = slice;
   1390 	} else {
   1391 		s = disk;
   1392 	}
   1393 	if ((s != NULL) && isdigit(s[1])) {
   1394 		return (s);
   1395 	} else {
   1396 		return ("");
   1397 	}
   1398 }
   1399 
   1400 static gboolean
   1401 is_dos_path(char *path, int *partnum)
   1402 {
   1403 	char *p;
   1404 
   1405 	if ((p = strrchr (path, ':')) == NULL) {
   1406 		return (FALSE);
   1407 	}
   1408 	return ((*partnum = atoi(p + 1)) != 0);
   1409 }
   1410 
   1411 static gboolean
   1412 dos_to_dev(char *path, char **devpath, int *partnum)
   1413 {
   1414 	char *p;
   1415 
   1416 	if ((p = strrchr (path, ':')) == NULL) {
   1417 		return (FALSE);
   1418 	}
   1419 	if ((*partnum = atoi(p + 1)) == 0) {
   1420 		return (FALSE);
   1421 	}
   1422 	p[0] = '\0';
   1423 	*devpath = strdup(path);
   1424 	p[0] = ':';
   1425 	return (*devpath != NULL);
   1426 }
   1427 
   1428 static void
   1429 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type,
   1430 		       gint return_code, gchar **error,
   1431 		       gpointer data1, gpointer data2)
   1432 {
   1433 	char *mount_point = (char *) data1;
   1434 
   1435 	HAL_INFO (("Cleaned up mount point '%s'", mount_point));
   1436 	g_free (mount_point);
   1437 }
   1438 
   1439 
   1440 void
   1441 devinfo_storage_mnttab_event (HalDevice *hal_volume)
   1442 {
   1443 	FILE *fp = NULL;
   1444         struct extmnttab m;
   1445 	HalDevice *d;
   1446 	unsigned int major;
   1447 	unsigned int minor;
   1448 	GSList *volumes = NULL;
   1449 	GSList *v;
   1450 	char *mount_point;
   1451 	dbus_bool_t is_partition;
   1452 	const char *fstype;
   1453 	int partition_number;
   1454 
   1455 	if (hal_volume != NULL) {
   1456 		volumes = g_slist_append (NULL, hal_volume);
   1457 	} else {
   1458 		volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
   1459 	}
   1460 	if (volumes == NULL) {
   1461 		return;
   1462 	}
   1463 
   1464 	if ((fp = fopen(MNTTAB, "r")) == NULL) {
   1465 		HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno));
   1466 		return;
   1467 	}
   1468 
   1469 	while (getextmntent(fp, &m, 1) == 0) {
   1470 		for (v = volumes; v != NULL; v = g_slist_next (v)) {
   1471 			d = HAL_DEVICE (v->data);
   1472 			major = hal_device_property_get_int (d, "block.major");
   1473 			minor = hal_device_property_get_int (d, "block.minor");
   1474 
   1475 			/*
   1476 			 * special handling for pcfs, which encodes logical
   1477 			 * drive number into the 6 upper bits of the minor
   1478 			 */
   1479 			is_partition = hal_device_property_get_bool (d, "volume.is_partition");
   1480 			partition_number = hal_device_property_get_int (d, "volume.partition.number");
   1481 			fstype = hal_device_property_get_string (d, "volume.fstype");
   1482 
   1483 			if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) {
   1484 				minor |= partition_number << 12;
   1485 			}
   1486 
   1487 			if (m.mnt_major != major || m.mnt_minor != minor) {
   1488 				continue;
   1489 			}
   1490 
   1491 			/* this volume matches the mnttab entry */
   1492 			device_property_atomic_update_begin ();
   1493 			hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
   1494 			hal_device_property_set_bool (d, "volume.is_mounted_read_only",
   1495 						      hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE);
   1496 			hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp);
   1497 			device_property_atomic_update_end ();
   1498 
   1499 			HAL_INFO (("set %s to be mounted at %s",
   1500 				   hal_device_get_udi (d), m.mnt_mountp));
   1501 			volumes = g_slist_delete_link (volumes, v);
   1502 		}
   1503 	}
   1504 
   1505 	/* all remaining volumes are not mounted */
   1506 	for (v = volumes; v != NULL; v = g_slist_next (v)) {
   1507 		d = HAL_DEVICE (v->data);
   1508 		mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point"));
   1509 		if (mount_point == NULL || strlen (mount_point) == 0) {
   1510 			g_free (mount_point);
   1511 			continue;
   1512 		}
   1513 
   1514 		device_property_atomic_update_begin ();
   1515 		hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
   1516 		hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE);
   1517 		hal_device_property_set_string (d, "volume.mount_point", "");
   1518 		device_property_atomic_update_end ();
   1519 
   1520 		HAL_INFO (("set %s to unmounted", hal_device_get_udi (d)));
   1521 
   1522 		/* cleanup if was mounted by us */
   1523 		if (hal_util_is_mounted_by_hald (mount_point)) {
   1524 			char *cleanup_stdin;
   1525 			char *extra_env[2];
   1526 
   1527 			HAL_INFO (("Cleaning up '%s'", mount_point));
   1528 
   1529 			extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point);
   1530 			extra_env[1] = NULL;
   1531 			cleanup_stdin = "\n";
   1532 
   1533 			hald_runner_run_method (d,
   1534 						"hal-storage-cleanup-mountpoint",
   1535 						extra_env,
   1536 						cleanup_stdin, TRUE,
   1537 						0,
   1538 						devinfo_storage_cleanup_mountpoint_cb,
   1539 						g_strdup (mount_point), NULL);
   1540 
   1541 			g_free (extra_env[0]);
   1542 		}
   1543 
   1544 		g_free (mount_point);
   1545 	}
   1546 	g_slist_free (volumes);
   1547 
   1548 	(void) fclose (fp);
   1549 }
   1550 
   1551 static void
   1552 devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type,
   1553 		  gint return_code, gchar **error,
   1554 		  gpointer data1, gpointer data2)
   1555 {
   1556 	void *end_token = (void *) data1;
   1557 
   1558 	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));
   1559 
   1560 	if (exit_type == HALD_RUN_SUCCESS && error != NULL &&
   1561 	    error[0] != NULL && error[1] != NULL) {
   1562 		char *exp_name = NULL;
   1563 		char *exp_detail = NULL;
   1564 
   1565 		exp_name = error[0];
   1566 		if (error[0] != NULL) {
   1567 			exp_detail = error[1];
   1568 		}
   1569 		HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
   1570 	}
   1571 
   1572 	hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
   1573 }
   1574 
   1575 static void
   1576 devinfo_volume_force_unmount (HalDevice *d, void *end_token)
   1577 {
   1578 	const char *device_file;
   1579 	const char *mount_point;
   1580 	char *unmount_stdin;
   1581 	char *extra_env[2];
   1582 	extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
   1583 	extra_env[1] = NULL;
   1584 
   1585 	device_file = hal_device_property_get_string (d, "block.device");
   1586 	mount_point = hal_device_property_get_string (d, "volume.mount_point");
   1587 
   1588 	if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) {
   1589 		hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
   1590 		return;
   1591 	}
   1592 
   1593 	HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d)));
   1594 
   1595 	unmount_stdin = "\n";
   1596 
   1597 	hald_runner_run_method (d,
   1598 				"hal-storage-unmount",
   1599 				extra_env,
   1600 				unmount_stdin, TRUE,
   1601 				0,
   1602 				devinfo_volume_force_unmount_cb,
   1603 				end_token, NULL);
   1604 }
   1605 
   1606 void
   1607 devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token)
   1608 {
   1609 	if (hal_device_property_get_bool (d, "volume.is_mounted")) {
   1610 		devinfo_volume_force_unmount (d, end_token);
   1611 	} else {
   1612 		hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
   1613 	}
   1614 }
   1615 
   1616 
   1617 enum {
   1618 	LEGACY_CDROM,
   1619 	LEGACY_FLOPPY,
   1620 	LEGACY_RMDISK
   1621 };
   1622 
   1623 static const char *legacy_media_str[] = {
   1624 	"cdrom",
   1625 	"floppy",
   1626 	"rmdisk"
   1627 };
   1628 
   1629 struct enum_nick {
   1630 	const char *type;
   1631 	GSList	*nums;
   1632 };
   1633 
   1634 static int
   1635 devinfo_storage_get_legacy_media(HalDevice *d)
   1636 {
   1637 	const char *drive_type;
   1638 
   1639 	if (hal_device_has_capability (d, "storage.cdrom")) {
   1640 		return (LEGACY_CDROM);
   1641 	} else if (((drive_type = hal_device_property_get_string (d,
   1642 	    "storage.drive_type")) != NULL) && (strcmp (drive_type, "floppy") == 0)) {
   1643 		return (LEGACY_FLOPPY);
   1644 	} else if (hal_device_property_get_bool (d, "storage.removable") ||
   1645 	           hal_device_property_get_bool (d, "storage.hotpluggable")) {
   1646 		return (LEGACY_RMDISK);
   1647 	} else {
   1648 		return (-1);
   1649 	}
   1650 }
   1651 
   1652 static gboolean
   1653 devinfo_storage_foreach_nick (HalDeviceStore *store, HalDevice *d, gpointer user_data)
   1654 {
   1655 	struct enum_nick *en = (struct enum_nick *) user_data;
   1656 	const char *media_type;
   1657 	int media_num;
   1658 
   1659 	media_type = hal_device_property_get_string (d, "storage.solaris.legacy.media_type");
   1660 	media_num = hal_device_property_get_int (d, "storage.solaris.legacy.media_num");
   1661 	if ((media_type != NULL) && (strcmp (media_type, en->type) == 0) &&
   1662 	    (media_num >= 0)) {
   1663 		en->nums = g_slist_prepend (en->nums, GINT_TO_POINTER(media_num));
   1664 	}
   1665 	return TRUE;
   1666 }
   1667 
   1668 static void
   1669 devinfo_storage_append_nickname (HalDevice *d, const char *media_type, int media_num)
   1670 {
   1671 	char buf[64];
   1672 
   1673 	if (media_num == 0) {
   1674 		hal_device_property_strlist_append (d, "storage.solaris.nicknames", media_type);
   1675 	}
   1676 	snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
   1677 	hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf);
   1678 }
   1679 
   1680 static void
   1681 devinfo_storage_set_nicknames (HalDevice *d)
   1682 {
   1683 	int media;
   1684 	const char *media_type;
   1685 	int media_num;
   1686 	GSList *i;
   1687 	struct enum_nick en;
   1688 	char buf[64];
   1689 
   1690 	if ((media = devinfo_storage_get_legacy_media (d)) < 0) {
   1691 		return;
   1692 	}
   1693 	media_type = legacy_media_str[media];
   1694 
   1695 	/* enumerate all storage devices of this media type */
   1696 	en.type = media_type;
   1697 	en.nums = NULL;
   1698 	hal_device_store_foreach (hald_get_gdl (), devinfo_storage_foreach_nick, &en);
   1699 
   1700 	/* find a free number */
   1701 	for (media_num = 0; ; media_num++) {
   1702 		for (i = en.nums; i != NULL; i = g_slist_next (i)) {
   1703         		if (GPOINTER_TO_INT (i->data) == media_num) {
   1704 				break;
   1705 			}
   1706 		}
   1707 		if (i == NULL) {
   1708 			break;
   1709 		}
   1710 	}
   1711 	g_slist_free (en.nums);
   1712 
   1713 	hal_device_property_set_string (d, "storage.solaris.legacy.media_type", media_type);
   1714 	hal_device_property_set_int (d, "storage.solaris.legacy.media_num", media_num);
   1715 
   1716 	/* primary nickname, and also vold-style symdev */
   1717 	snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
   1718 	hal_device_property_set_string (d, "storage.solaris.legacy.symdev", buf);
   1719 	devinfo_storage_append_nickname(d, media_type, media_num);
   1720 
   1721 	/* additional nicknames */
   1722 	if (media == LEGACY_CDROM) {
   1723 		devinfo_storage_append_nickname(d, "cd", media_num);
   1724 		devinfo_storage_append_nickname(d, "sr", media_num);
   1725 	} else if (media == LEGACY_FLOPPY) {
   1726 		devinfo_storage_append_nickname(d, "fd", media_num);
   1727 		devinfo_storage_append_nickname(d, "diskette", media_num);
   1728 		devinfo_storage_append_nickname(d, "rdiskette", media_num);
   1729 	}
   1730 }
   1731