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