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  *
   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_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
  65 static HalDevice *devinfo_blkdev_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_blkdev_handler = {
 106         devinfo_blkdev_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 /* blkdev */
 370 
 371 HalDevice *
 372 devinfo_blkdev_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, "blkdev") != 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", "pseudo");
 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", "Block Device");
 394 
 395         devinfo_add_enqueue (d, devfs_path, &devinfo_blkdev_handler);
 396 
 397         return (devinfo_blkdev_storage_add (d, node, devfs_path));
 398 }
 399 
 400 static HalDevice *
 401 devinfo_blkdev_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/blkdev%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 
 423         PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable");
 424         PROP_BOOL(d, node, i, "removable-media", "storage.removable");
 425 
 426         hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
 427         hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE);
 428         hal_device_property_set_string (d, "storage.drive_type", "disk");
 429 
 430         hal_device_add_capability (d, "block");
 431 
 432         devinfo_storage_minors (d, node, devfs_path, FALSE);
 433 
 434         return (d);
 435 }
 436 
 437 /* floppy */
 438 
 439 HalDevice *
 440 devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
 441 {
 442         char    *driver_name;
 443         char    *raw;
 444         char    udi[HAL_PATH_MAX];
 445         di_devlink_handle_t devlink_hdl;
 446         int     major;
 447         di_minor_t minor;
 448         dev_t   dev;
 449         HalDevice *d = NULL;
 450         char    *minor_path = NULL;
 451         char    *devlink = NULL;
 452 
 453         driver_name = di_driver_name (node);
 454         if ((driver_name == NULL) || (strcmp (driver_name, "fd") != 0)) {
 455                 return (NULL);
 456         }
 457 
 458         /*
 459          * The only minor node we're interested in is /dev/diskette*
 460          */
 461         major = di_driver_major(node);
 462         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
 463                 return (NULL);
 464         }
 465         minor = DI_MINOR_NIL;
 466         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
 467                 dev = di_minor_devt(minor);
 468                 if ((major != major(dev)) ||
 469                     (di_minor_type(minor) != DDM_MINOR) ||
 470                     (di_minor_spectype(minor) != S_IFBLK) ||
 471                     ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
 472                         continue;
 473                 }
 474                 if ((devlink = get_devlink(devlink_hdl, "diskette.+" , minor_path)) != NULL) {
 475                         break;
 476                 }
 477                 di_devfs_path_free (minor_path);
 478                 minor_path = NULL;
 479                 free(devlink);
 480                 devlink = NULL;
 481         }
 482         di_devlink_fini (&devlink_hdl);
 483 
 484         if ((devlink == NULL) || (minor_path == NULL)) {
 485                 HAL_INFO (("floppy devlink not found %s", devfs_path));
 486                 goto out;
 487         }
 488 
 489         d = hal_device_new ();
 490 
 491         devinfo_set_default_properties (d, parent, node, devfs_path);
 492         hal_device_property_set_string (d, "info.category", "storage");
 493         hal_device_add_capability (d, "storage");
 494         hal_device_property_set_string (d, "storage.bus", "platform");
 495         hal_device_property_set_bool (d, "storage.hotpluggable", FALSE);
 496         hal_device_property_set_bool (d, "storage.removable", TRUE);
 497         hal_device_property_set_bool (d, "storage.requires_eject", TRUE);
 498         hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE);
 499         hal_device_property_set_string (d, "storage.drive_type", "floppy");
 500 
 501         hal_device_add_capability (d, "block");
 502         hal_device_property_set_bool (d, "block.is_volume", FALSE);
 503         hal_device_property_set_int (d, "block.major", major(dev));
 504         hal_device_property_set_int (d, "block.minor", minor(dev));
 505         hal_device_property_set_string (d, "block.device", devlink);
 506         raw = dsk_to_rdsk (devlink);
 507         hal_device_property_set_string (d, "block.solaris.raw_device", raw);
 508         free (raw);
 509 
 510         devinfo_add_enqueue (d, devfs_path, &devinfo_storage_handler);
 511 
 512         /* trigger initial probe-volume */
 513         devinfo_floppy_add_volume(d, node);
 514 
 515 out:
 516         di_devfs_path_free (minor_path);
 517         free(devlink);
 518 
 519         return (d);
 520 }
 521 
 522 static void
 523 devinfo_floppy_add_volume(HalDevice *parent, di_node_t node)
 524 {
 525         char    *devlink;
 526         char    *devfs_path;
 527         int     minor, major;
 528         dev_t   dev;
 529         struct devinfo_storage_minor *m;
 530 
 531         devfs_path = (char *)hal_device_property_get_string (parent, "solaris.devfs_path");
 532         devlink = (char *)hal_device_property_get_string (parent, "block.device");
 533         major = hal_device_property_get_int (parent, "block.major");
 534         minor = hal_device_property_get_int (parent, "block.minor");
 535         dev = makedev (major, minor);
 536 
 537         m = devinfo_storage_new_minor (devfs_path, WHOLE_DISK, devlink, dev, -1);
 538         devinfo_volume_add (parent, node, m);
 539         devinfo_storage_free_minor (m);
 540 }
 541 
 542 /*
 543  * After reprobing storage, reprobe its volumes.
 544  */
 545 static void
 546 devinfo_floppy_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code,
 547     char **error, gpointer userdata1, gpointer userdata2)
 548 {
 549         void *end_token = (void *) userdata1;
 550         const char *devfs_path;
 551         di_node_t node;
 552         HalDevice *v;
 553 
 554         if (!hal_device_property_get_bool (d, "storage.removable.media_available")) {
 555                 HAL_INFO (("no floppy media", hal_device_get_udi (d)));
 556 
 557                 /* remove child (can only be single volume) */
 558                 if (((v = hal_device_store_match_key_value_string (hald_get_gdl(),
 559                     "info.parent", hal_device_get_udi (d))) != NULL) &&
 560                     ((devfs_path = hal_device_property_get_string (v,
 561                     "solaris.devfs_path")) != NULL)) {
 562                         devinfo_remove_enqueue ((char *)devfs_path, NULL);
 563                 }
 564         } else {
 565                 HAL_INFO (("floppy media found", hal_device_get_udi (d)));
 566 
 567                 if ((devfs_path = hal_device_property_get_string(d, "solaris.devfs_path")) == NULL) {
 568                         HAL_INFO (("no devfs_path", hal_device_get_udi (d)));
 569                         hotplug_event_process_queue ();
 570                         return;
 571                 }
 572                 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
 573                         HAL_INFO (("di_init %s failed %d", devfs_path, errno));
 574                         hotplug_event_process_queue ();
 575                         return;
 576                 }
 577 
 578                 devinfo_floppy_add_volume (d, node);
 579 
 580                 di_fini (node);
 581         }
 582 
 583         hotplug_event_process_queue ();
 584 }
 585         
 586 /* lofi */
 587 
 588 HalDevice *
 589 devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
 590 {
 591         return (devinfo_lofi_add_major(parent,node, devfs_path, device_type, FALSE, NULL));
 592 }
 593 
 594 HalDevice *
 595 devinfo_lofi_add_major(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type,
 596     gboolean rescan, HalDevice *lofi_d)
 597 {
 598         char    *driver_name;
 599         HalDevice *d = NULL;
 600         char    udi[HAL_PATH_MAX];
 601         di_devlink_handle_t devlink_hdl;
 602         int     major;
 603         di_minor_t minor;
 604         dev_t   dev;
 605         char    *minor_path = NULL;
 606         char    *devlink = NULL;
 607 
 608         driver_name = di_driver_name (node);
 609         if ((driver_name == NULL) || (strcmp (driver_name, "lofi") != 0)) {
 610                 return (NULL);
 611         }
 612 
 613         if (!rescan) {
 614                 d = hal_device_new ();
 615 
 616                 devinfo_set_default_properties (d, parent, node, devfs_path);
 617                 hal_device_property_set_string (d, "info.subsystem", "pseudo");
 618 
 619                 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
 620                         "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node));
 621                 hal_device_set_udi (d, udi);
 622                 hal_device_property_set_string (d, "info.udi", udi);
 623 
 624                 devinfo_add_enqueue (d, devfs_path, &devinfo_lofi_handler);
 625         } else {
 626                 d = lofi_d;
 627         }
 628 
 629         /*
 630          * Unlike normal storage, as in devinfo_storage_minors(), where
 631          * sd instance -> HAL storage, sd minor node -> HAL volume,
 632          * lofi always has one instance, lofi minor -> HAL storage.
 633          * lofi storage never has slices, but it can have
 634          * embedded pcfs partitions that fstyp would recognize
 635          */
 636         major = di_driver_major(node);
 637         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
 638                 return (d);
 639         }
 640         minor = DI_MINOR_NIL;
 641         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
 642                 dev = di_minor_devt(minor);
 643                 if ((major != major(dev)) ||
 644                     (di_minor_type(minor) != DDM_MINOR) ||
 645                     (di_minor_spectype(minor) != S_IFBLK) ||
 646                     ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
 647                         continue;
 648                 }
 649                 if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
 650                         di_devfs_path_free (minor_path);
 651                         continue;
 652                 }
 653 
 654                 if (!rescan ||
 655                     (hal_device_store_match_key_value_string (hald_get_gdl (),
 656                     "solaris.devfs_path", minor_path) == NULL)) {
 657                         devinfo_lofi_add_minor(d, node, minor_path, devlink, dev);
 658                 }
 659 
 660                 di_devfs_path_free (minor_path);
 661                 free(devlink);
 662         }
 663         di_devlink_fini (&devlink_hdl);
 664 
 665         return (d);
 666 }
 667 
 668 static void
 669 devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev)
 670 {
 671         HalDevice *d;
 672         char    *raw;
 673         char    *doslink;
 674         char    dospath[64];
 675         struct devinfo_storage_minor *m;
 676         int     i;
 677 
 678         /* add storage */
 679         d = hal_device_new ();
 680 
 681         devinfo_set_default_properties (d, parent, node, minor_path);
 682         hal_device_property_set_string (d, "info.category", "storage");
 683         hal_device_add_capability (d, "storage");
 684         hal_device_property_set_string (d, "storage.bus", "lofi");
 685         hal_device_property_set_bool (d, "storage.hotpluggable", TRUE);
 686         hal_device_property_set_bool (d, "storage.removable", FALSE);
 687         hal_device_property_set_bool (d, "storage.requires_eject", FALSE);
 688         hal_device_property_set_string (d, "storage.drive_type", "disk");
 689         hal_device_add_capability (d, "block");
 690         hal_device_property_set_int (d, "block.major", major(dev));
 691         hal_device_property_set_int (d, "block.minor", minor(dev));
 692         hal_device_property_set_string (d, "block.device", devlink);
 693         raw = dsk_to_rdsk (devlink);
 694         hal_device_property_set_string (d, "block.solaris.raw_device", raw);
 695         free (raw);
 696         hal_device_property_set_bool (d, "block.is_volume", FALSE);
 697 
 698         devinfo_add_enqueue (d, minor_path, &devinfo_storage_handler);
 699 
 700         /* add volumes: one on main device and a few pcfs candidates */
 701         m = devinfo_storage_new_minor(minor_path, WHOLE_DISK, devlink, dev, -1);
 702         devinfo_volume_add (d, node, m);
 703         devinfo_storage_free_minor (m);
 704 
 705         doslink = (char *)calloc (1, strlen (devlink) + sizeof (":NNN") + 1);
 706         if (doslink != NULL) {
 707                 for (i = 1; i < 16; i++) {
 708                         snprintf(dospath, sizeof (dospath), WHOLE_DISK":%d", i);
 709                         sprintf(doslink, "%s:%d", devlink, i);
 710                         m = devinfo_storage_new_minor(minor_path, dospath, doslink, dev, i);
 711                         devinfo_volume_add (d, node, m);
 712                         devinfo_storage_free_minor (m);
 713                 }
 714                 free (doslink);
 715         }
 716 }
 717 
 718 void
 719 devinfo_lofi_remove_minor(char *parent_devfs_path, char *name)
 720 {
 721         GSList *i;
 722         GSList *devices;
 723         HalDevice *d = NULL;
 724         const char *devfs_path;
 725 
 726         devices = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
 727                 "block.solaris.raw_device", name);
 728         for (i = devices; i != NULL; i = g_slist_next (i)) {
 729                 if (hal_device_has_capability (HAL_DEVICE (i->data), "storage")) {
 730                         d = HAL_DEVICE (i->data);
 731                         break;
 732                 }
 733         }
 734         g_slist_free (devices);
 735 
 736         if (d == NULL) {
 737                 HAL_INFO (("device not found %s", name));
 738                 return;
 739         }
 740 
 741         if ((devfs_path = hal_device_property_get_string (d,
 742             "solaris.devfs_path")) == NULL) {
 743                 HAL_INFO (("devfs_path not found %s", hal_device_get_udi (d)));
 744                 return;
 745         }
 746 
 747         if (d != NULL) {
 748                 devinfo_remove_branch ((char *)devfs_path, d);
 749         }
 750 }
 751 
 752 /* common storage */
 753 
 754 static void
 755 devinfo_storage_free_minor(struct devinfo_storage_minor *m)
 756 {
 757         if (m != NULL) {
 758                 free (m->slice);
 759                 free (m->devlink);
 760                 free (m->devpath);
 761                 free (m);
 762         }
 763 }
 764 
 765 static struct devinfo_storage_minor *
 766 devinfo_storage_new_minor(char *maindev_path, char *slice, char *devlink, dev_t dev, int dosnum)
 767 {
 768         struct devinfo_storage_minor *m;
 769         int pathlen;
 770         char *devpath;
 771 
 772         m = (struct devinfo_storage_minor *)calloc (sizeof (struct devinfo_storage_minor), 1);
 773         if (m != NULL) {
 774                 /*
 775                  * For volume's devfs_path we'll use minor_path/slice instead of
 776                  * minor_path which we use for parent storage device.
 777                  */
 778                 pathlen = strlen (maindev_path) + strlen (slice) + 2;
 779                 devpath = (char *)calloc (1, pathlen);
 780                 snprintf(devpath, pathlen, "%s/%s", maindev_path, slice);
 781 
 782                 m->devpath = devpath;
 783                 m->devlink = strdup (devlink);
 784                 m->slice = strdup (slice);
 785                 m->dev = dev;
 786                 m->dosnum = dosnum;
 787                 if ((m->devpath == NULL) || (m->devlink == NULL)) {
 788                         devinfo_storage_free_minor (m);
 789                         m = NULL;
 790                 }
 791         }
 792         return (m);
 793 }
 794 
 795 /*
 796  * Storage minor nodes are potential "volume" objects.
 797  * This function also completes building the parent object (main storage device).
 798  */
 799 static void
 800 devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean rescan)
 801 {
 802         di_devlink_handle_t devlink_hdl;
 803         gboolean is_cdrom;
 804         const char *whole_disk;
 805         int     major;
 806         di_minor_t minor;
 807         dev_t   dev;
 808         char    *minor_path = NULL;
 809         char    *maindev_path = NULL;
 810         char    *devpath, *devlink;
 811         int     doslink_len;
 812         char    *doslink;
 813         char    dospath[64];
 814         char    *slice;
 815         int     pathlen;
 816         int     i;
 817         char    *raw;
 818         boolean_t maindev_is_d0;
 819         GQueue  *mq;
 820         HalDevice *volume;
 821         struct devinfo_storage_minor *m;
 822         struct devinfo_storage_minor *maindev = NULL;
 823 
 824         /* for cdroms whole disk is always s2 */
 825         is_cdrom = hal_device_has_capability (parent, "storage.cdrom");
 826         whole_disk = is_cdrom ? "s2" : WHOLE_DISK;
 827 
 828         major = di_driver_major(node);
 829 
 830         /* the "whole disk" p0/s2/d0 node must come first in the hotplug queue
 831          * so we put other minor nodes on the local queue and move to the
 832          * hotplug queue up in the end
 833          */
 834         if ((mq = g_queue_new()) == NULL) {
 835                 goto err;
 836         }
 837         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
 838                 g_queue_free (mq);
 839                 goto err;
 840         }
 841         minor = DI_MINOR_NIL;
 842         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
 843                 dev = di_minor_devt(minor);
 844                 if ((major != major(dev)) ||
 845                     (di_minor_type(minor) != DDM_MINOR) ||
 846                     (di_minor_spectype(minor) != S_IFBLK) ||
 847                     ((minor_path = di_devfs_minor_path(minor)) == NULL)) {
 848                         continue;
 849                 }
 850                 if ((devlink = get_devlink(devlink_hdl, NULL, minor_path)) == NULL) {
 851                         di_devfs_path_free (minor_path);
 852                         continue;
 853                 }
 854 
 855                 slice = devinfo_volume_get_slice_name (devlink);
 856                 if (strlen (slice) < 2) {
 857                         free (devlink);
 858                         di_devfs_path_free (minor_path);
 859                         continue;
 860                 }
 861 
 862                 /* ignore p1..N - we'll use p0:N instead */
 863                 if ((strlen (slice) > 1) && (slice[0] == 'p') && isdigit(slice[1]) &&
 864                     ((atol(&slice[1])) > 0)) {
 865                         free (devlink);
 866                         di_devfs_path_free (minor_path);
 867                         continue;
 868                 }
 869 
 870                 m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1);
 871                 if (m == NULL) {
 872                         free (devlink);
 873                         di_devfs_path_free (minor_path);
 874                         continue;
 875                 }
 876 
 877                 /* main device is either s2/p0 or d0, the latter taking precedence */
 878                 if ((strcmp (slice, "d0") == 0) ||
 879                     (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) {
 880                         if (maindev_path != NULL) {
 881                                 di_devfs_path_free (maindev_path);
 882                         }
 883                         maindev_path = minor_path;
 884                         maindev = m;
 885                         g_queue_push_head (mq, maindev);
 886                 } else {
 887                         di_devfs_path_free (minor_path);
 888                         g_queue_push_tail (mq, m);
 889                 }
 890 
 891                 free (devlink);
 892         }
 893         di_devlink_fini (&devlink_hdl);
 894 
 895         if (maindev == NULL) {
 896                 /* shouldn't typically happen */
 897                 while (!g_queue_is_empty (mq)) {
 898                         devinfo_storage_free_minor (g_queue_pop_head (mq));
 899                 }
 900                 goto err;
 901         }
 902 
 903         /* first enqueue main storage device */
 904         if (!rescan) {
 905                 hal_device_property_set_int (parent, "block.major", major);
 906                 hal_device_property_set_int (parent, "block.minor", minor(maindev->dev));
 907                 hal_device_property_set_string (parent, "block.device", maindev->devlink);
 908                 raw = dsk_to_rdsk (maindev->devlink);
 909                 hal_device_property_set_string (parent, "block.solaris.raw_device", raw);
 910                 free (raw);
 911                 hal_device_property_set_bool (parent, "block.is_volume", FALSE);
 912                 hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path);
 913                 devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler);
 914         }
 915 
 916         /* add virtual dos volumes to enable pcfs probing */
 917         if (!is_cdrom) {
 918                 doslink_len = strlen (maindev->devlink) + sizeof (":NNN") + 1;
 919                 if ((doslink = (char *)calloc (1, doslink_len)) != NULL) {
 920                         for (i = 1; i < 16; i++) {
 921                                 snprintf(dospath, sizeof (dospath), "%s:%d", maindev->slice, i);
 922                                 snprintf(doslink, doslink_len, "%s:%d", maindev->devlink, i);
 923                                 m = devinfo_storage_new_minor(maindev_path, dospath, doslink, maindev->dev, i);
 924                                 g_queue_push_tail (mq, m);
 925                         }
 926                         free (doslink);
 927                 }
 928         }
 929 
 930         maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0);
 931 
 932         /* enqueue all volumes */
 933         while (!g_queue_is_empty (mq)) {
 934                 m = g_queue_pop_head (mq);
 935 
 936                 /* if main device is d0, we'll throw away s2/p0 */
 937                 if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) {
 938                         devinfo_storage_free_minor (m);
 939                         continue;
 940                 }
 941                 /* don't do p0 on cdrom */
 942                 if (is_cdrom && (strcmp (m->slice, "p0") == 0)) {
 943                         devinfo_storage_free_minor (m);
 944                         continue;
 945                 }
 946                 if (rescan) {
 947                         /* in rescan mode, don't reprobe existing volumes */
 948                         /* XXX detect volume removal? */
 949                         volume = hal_device_store_match_key_value_string (hald_get_gdl (),
 950                             "solaris.devfs_path", m->devpath);
 951                         if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) {
 952                                 devinfo_volume_add (parent, node, m);
 953                         } else {
 954                                 HAL_INFO(("rescan volume exists %s", m->devpath));
 955                         }
 956                 } else {
 957                         devinfo_volume_add (parent, node, m);
 958                 }
 959                 devinfo_storage_free_minor (m);
 960         }
 961 
 962         if (maindev_path != NULL) {
 963                 di_devfs_path_free (maindev_path);
 964         }
 965 
 966         return;
 967 
 968 err:
 969         if (maindev_path != NULL) {
 970                 di_devfs_path_free (maindev_path);
 971         }
 972         if (!rescan) {
 973                 devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler);
 974         }
 975 }
 976 
 977 HalDevice *
 978 devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m)
 979 {
 980         HalDevice *d;
 981         char    *raw;
 982         char    udi[HAL_PATH_MAX];
 983         char    *devfs_path = m->devpath;
 984         char    *devlink = m->devlink;
 985         dev_t   dev = m->dev;
 986         int     dosnum = m->dosnum;
 987         char    *slice = m->slice;
 988 
 989         HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink));
 990         d = hal_device_new ();
 991 
 992         devinfo_set_default_properties (d, parent, node, devfs_path);
 993         hal_device_property_set_string (d, "info.category", "volume");
 994 
 995         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
 996                 "%s/%s", hal_device_get_udi (parent), slice);
 997         hal_device_set_udi (d, udi);
 998         hal_device_property_set_string (d, "info.udi", udi);
 999         hal_device_property_set_string (d, "info.product", slice);
1000 
1001         hal_device_add_capability (d, "volume");
1002         hal_device_add_capability (d, "block");
1003         hal_device_property_set_int (d, "block.major", major (dev));
1004         hal_device_property_set_int (d, "block.minor", minor (dev));
1005         hal_device_property_set_string (d, "block.device", devlink);
1006         raw = dsk_to_rdsk (devlink);
1007         hal_device_property_set_string (d, "block.solaris.raw_device", raw);
1008         free (raw);
1009         hal_device_property_set_string (d, "block.solaris.slice", slice);
1010         hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */
1011 
1012         hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent));
1013 
1014         /* set volume defaults */
1015         hal_device_property_set_string (d, "volume.fstype", "");
1016         hal_device_property_set_string (d, "volume.fsusage", "");
1017         hal_device_property_set_string (d, "volume.fsversion", "");
1018         hal_device_property_set_string (d, "volume.uuid", "");
1019         hal_device_property_set_string (d, "volume.label", "");
1020         hal_device_property_set_string (d, "volume.mount_point", "");
1021         hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
1022         if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) {
1023                 hal_device_property_set_bool (d, "volume.is_disc", TRUE);
1024                 hal_device_add_capability (d, "volume.disc");
1025         } else {
1026                 hal_device_property_set_bool (d, "volume.is_disc", FALSE);
1027         }
1028 
1029         if (dosnum > 0) {
1030                 hal_device_property_set_bool (d, "volume.is_partition", TRUE);
1031                 hal_device_property_set_int (d, "volume.partition.number", dosnum);
1032         } else {
1033                 hal_device_property_set_bool (d, "volume.is_partition", FALSE);
1034         }
1035 
1036         /* prober may override these */
1037         hal_device_property_set_int (d, "volume.block_size", 512);
1038 
1039         devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler);
1040 
1041         return (d);
1042 }
1043 
1044 static void
1045 devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
1046 {
1047         void *end_token = (void *) userdata1;
1048         char *whole_disk;
1049         char *block_device;
1050         const char *storage_udi;
1051         HalDevice *storage_d;
1052         const char *slice;
1053         int dos_num;
1054 
1055         if (hal_device_property_get_bool (d, "info.ignore")) {
1056                 HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d)));
1057                 goto skip;
1058         }
1059 
1060         /*
1061          * Optimizations: only probe if there's a chance to find something
1062          */
1063         block_device = (char *)hal_device_property_get_string (d, "block.device");
1064         storage_udi = hal_device_property_get_string (d, "block.storage_device");
1065         slice = hal_device_property_get_string(d, "block.solaris.slice");
1066         if ((block_device == NULL) || (storage_udi == NULL) ||
1067             (slice == NULL) || (strlen (slice) < 2)) {
1068                 HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d)));
1069                 goto skip;
1070         }
1071         storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi);
1072         if (storage_d == NULL) {
1073                 HAL_INFO (("Storage device not found %s", hal_device_get_udi (d)));
1074                 goto skip;
1075         }
1076 
1077         whole_disk = hal_device_has_capability (storage_d,
1078             "storage.cdrom") ? "s2" : WHOLE_DISK;
1079 
1080         if (is_dos_path(block_device, &dos_num)) {
1081                 /* don't probe more dos volumes than probe-storage found */
1082                 if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") ||
1083                     (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) {
1084                             HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d,
1085                                 "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d)));
1086                         goto skip;
1087                 }
1088         } else {
1089                 /* if no VTOC slices found, don't probe slices except s2 */
1090                 if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) &&
1091                     !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) {
1092                         HAL_INFO (("Not probing slice %s", hal_device_get_udi (d)));
1093                         goto skip;
1094                 }
1095         }
1096 
1097         HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
1098         hald_runner_run (d,
1099                         "hald-probe-volume", NULL,
1100                         DEVINFO_PROBE_VOLUME_TIMEOUT,
1101                         devinfo_callouts_probing_done,
1102                         (gpointer) end_token, userdata2);
1103 
1104         return;
1105 
1106 skip:
1107         hal_device_store_remove (hald_get_tdl (), d);
1108         g_object_unref (d);
1109         hotplug_event_end (end_token);
1110 }
1111 
1112 static void
1113 devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
1114 {
1115         HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d)));
1116 
1117         if (parent == NULL) {
1118                 HAL_INFO (("no parent %s", hal_device_get_udi (d)));
1119                 goto skip;
1120         }
1121 
1122         if (hal_device_property_get_bool (parent, "info.ignore")) {
1123                 HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE"));
1124                 goto skip;
1125         }
1126 
1127         /* add to TDL so preprobing callouts and prober can access it */
1128         hal_device_store_add (hald_get_tdl (), d);
1129 
1130         /* Process preprobe fdi files */
1131         di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
1132 
1133         /* Run preprobe callouts */
1134         hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler);
1135 
1136         return;
1137 
1138 skip:
1139         g_object_unref (d);
1140         hotplug_event_end (end_token);
1141 }
1142 
1143 void
1144 devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
1145 {
1146         const char *drive_type;
1147         const char *p_udi;
1148         HalDevice *p_d;
1149         HalDevice *phys_d = NULL;
1150         const char *phys_bus;
1151         const char *bus;
1152         static const char *busses[] = { "usb", "ide", "scsi", "ieee1394",
1153                                         "pseudo" };
1154         int i;
1155 
1156         HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d)));
1157 
1158         if (parent == NULL) {
1159                 HAL_INFO (("no parent %s", hal_device_get_udi (d)));
1160                 goto error;
1161         }
1162 
1163         /*
1164          * figure out physical device and bus, except for floppy
1165          */
1166         drive_type = hal_device_property_get_string (d, "storage.drive_type");
1167         if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) {
1168                 goto skip_bus;
1169         }
1170 
1171         p_d = parent;
1172         for (;;) {
1173                 bus = hal_device_property_get_string (p_d, "info.subsystem");
1174                 if (bus != NULL) {
1175                         for (i = 0; i < NELEM(busses); i++) {
1176                                 if (strcmp(bus, busses[i]) == 0) {
1177                                         phys_d = p_d;
1178                                         phys_bus = busses[i];
1179                                         break;
1180                                 }
1181                         }
1182                 }
1183                 /* up the tree */
1184                 p_udi = hal_device_property_get_string (p_d, "info.parent");
1185                 if (p_udi == NULL) {
1186                         break;
1187                 }
1188                 p_d = hal_device_store_find (hald_get_gdl (), p_udi);
1189         }
1190         if (phys_d == NULL) {
1191                 HAL_INFO (("no physical device %s", hal_device_get_udi (d)));
1192         } else {
1193                 hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d));
1194                 hal_device_property_set_string (d, "storage.bus", phys_bus);
1195         }
1196 
1197 skip_bus:
1198 
1199         /* add to TDL so preprobing callouts and prober can access it */
1200         hal_device_store_add (hald_get_tdl (), d);
1201 
1202         /* Process preprobe fdi files */
1203         di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
1204 
1205         /* Run preprobe callouts */
1206         hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
1207 
1208         return;
1209 
1210 error:
1211         g_object_unref (d);
1212         hotplug_event_end (end_token);
1213 }
1214 
1215 static void
1216 devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
1217 {
1218         void *end_token = (void *) userdata1;
1219 
1220         HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d)));
1221 
1222         /* Discard device if probing reports failure */
1223         if (exit_type != HALD_RUN_SUCCESS || return_code != 0) {
1224                 HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code));
1225                 hal_device_store_remove (hald_get_tdl (), d);
1226                 g_object_unref (d);
1227                 hotplug_event_end (end_token);
1228                 return;
1229         }
1230 
1231         devinfo_storage_set_nicknames (d);
1232 
1233         /* Merge properties from .fdi files */
1234         di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
1235         di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
1236 
1237         hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
1238 }
1239 
1240 const gchar *
1241 devinfo_storage_get_prober (HalDevice *d, int *timeout)
1242 {
1243         *timeout = DEVINFO_PROBE_STORAGE_TIMEOUT;
1244         return "hald-probe-storage";
1245 }
1246 
1247 const gchar *
1248 devinfo_volume_get_prober (HalDevice *d, int *timeout)
1249 {
1250         *timeout = DEVINFO_PROBE_VOLUME_TIMEOUT;
1251         return "hald-probe-volume";
1252 }
1253 
1254 /*
1255  * After reprobing storage, reprobe its volumes.
1256  */
1257 static void
1258 devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
1259 {
1260         void *end_token = (void *) userdata1;
1261         const char *devfs_path_orig = NULL;
1262         char *devfs_path = NULL;
1263         char *p;
1264         di_node_t node;
1265 
1266         HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d)));
1267 
1268         devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path");
1269         if (devfs_path_orig == NULL) {
1270                 HAL_INFO (("device has no solaris.devfs_path"));
1271                 hotplug_event_process_queue ();
1272                 return;
1273         }
1274 
1275         /* strip trailing minor part if any */
1276         if (strrchr(devfs_path_orig, ':') != NULL) {
1277                 if ((devfs_path = strdup (devfs_path_orig)) != NULL) {
1278                         p = strrchr(devfs_path, ':');
1279                         *p = '\0';
1280                 }
1281         } else {
1282                 devfs_path = (char *)devfs_path_orig;
1283         }
1284 
1285         if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) {
1286                 HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d)));
1287                 hotplug_event_process_queue ();
1288                 return;
1289         } else {
1290                 devinfo_storage_minors (d, node, (char *)devfs_path, TRUE);
1291                 di_fini (node);
1292         }
1293 
1294         if (devfs_path != devfs_path_orig) {
1295                 free (devfs_path);
1296         }
1297 
1298         hotplug_event_process_queue ();
1299 }
1300 
1301 /*
1302  * For removable media devices, check for "storage.removable.media_available".
1303  * For non-removable media devices, assume media is always there.
1304  *
1305  * If media is gone, enqueue remove events for all children volumes.
1306  * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone).
1307  */
1308 gboolean
1309 devinfo_storage_device_rescan (HalDevice *d)
1310 {
1311         GSList *i;
1312         GSList *volumes;
1313         HalDevice *v;
1314         gchar *v_devfs_path;
1315         const char *drive_type;
1316         gboolean is_floppy;
1317         gboolean media_available;
1318 
1319         HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d)));
1320 
1321         if (hal_device_property_get_bool (d, "block.is_volume")) {
1322                 HAL_INFO (("nothing to do for volume"));
1323                 return (FALSE);
1324         }
1325 
1326         drive_type = hal_device_property_get_string (d, "storage.drive_type");
1327         is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0);
1328                 
1329         media_available = !hal_device_property_get_bool (d, "storage.removable") ||
1330             hal_device_property_get_bool (d, "storage.removable.media_available");
1331 
1332         if (!media_available && !is_floppy) {
1333                 HAL_INFO (("media gone %s", hal_device_get_udi (d)));
1334 
1335                 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
1336                     "block.storage_device", hal_device_get_udi (d));
1337                 for (i = volumes; i != NULL; i = g_slist_next (i)) {
1338                         v = HAL_DEVICE (i->data);
1339                         v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path");
1340                         HAL_INFO (("child volume %s", hal_device_get_udi (v)));
1341                         if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) {
1342                                 HAL_INFO (("removing volume %s", hal_device_get_udi (v)));
1343                                 devinfo_remove_enqueue (v_devfs_path, NULL);
1344                         } else {
1345                                 HAL_INFO (("not a volume %s", hal_device_get_udi (v)));
1346                         }
1347                 }
1348                 g_slist_free (volumes);
1349 
1350                 hotplug_event_process_queue ();
1351         } else if (is_floppy) {
1352                 HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d)));
1353                 
1354                 hald_runner_run (d,
1355                                  "hald-probe-storage --only-check-for-media", NULL,
1356                                  DEVINFO_PROBE_STORAGE_TIMEOUT,
1357                                  devinfo_floppy_rescan_probing_done,
1358                                  NULL, NULL);
1359         } else {
1360                 HAL_INFO (("media available %s", hal_device_get_udi (d)));
1361 
1362                 hald_runner_run (d,
1363                                  "hald-probe-storage --only-check-for-media", NULL,
1364                                  DEVINFO_PROBE_STORAGE_TIMEOUT,
1365                                  devinfo_storage_rescan_probing_done,
1366                                  NULL, NULL);
1367         }
1368 
1369         return TRUE;
1370 }
1371 
1372 static char *
1373 devinfo_volume_get_slice_name (char *devlink)
1374 {
1375         char    *part, *slice, *disk;
1376         char    *s = NULL;
1377         char    *p;
1378 
1379         if ((p = strstr(devlink, "/lofi/")) != 0) {
1380                 return (p + sizeof ("/lofi/") - 1);
1381         }
1382 
1383         part = strrchr(devlink, 'p');
1384         slice = strrchr(devlink, 's');
1385         disk = strrchr(devlink, 'd');
1386 
1387         if ((part != NULL) && (part > slice) && (part > disk)) {
1388                 s = part;
1389         } else if ((slice != NULL) && (slice > disk)) {
1390                 s = slice;
1391         } else {
1392                 s = disk;
1393         }
1394         if ((s != NULL) && isdigit(s[1])) {
1395                 return (s);
1396         } else {
1397                 return ("");
1398         }
1399 }
1400 
1401 static gboolean
1402 is_dos_path(char *path, int *partnum)
1403 {
1404         char *p;
1405 
1406         if ((p = strrchr (path, ':')) == NULL) {
1407                 return (FALSE);
1408         }
1409         return ((*partnum = atoi(p + 1)) != 0);
1410 }
1411 
1412 static gboolean
1413 dos_to_dev(char *path, char **devpath, int *partnum)
1414 {
1415         char *p;
1416 
1417         if ((p = strrchr (path, ':')) == NULL) {
1418                 return (FALSE);
1419         }
1420         if ((*partnum = atoi(p + 1)) == 0) {
1421                 return (FALSE);
1422         }
1423         p[0] = '\0';
1424         *devpath = strdup(path);
1425         p[0] = ':';
1426         return (*devpath != NULL);
1427 }
1428 
1429 static void
1430 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type, 
1431                        gint return_code, gchar **error,
1432                        gpointer data1, gpointer data2)
1433 {
1434         char *mount_point = (char *) data1;
1435 
1436         HAL_INFO (("Cleaned up mount point '%s'", mount_point));
1437         g_free (mount_point);
1438 }
1439 
1440 
1441 void
1442 devinfo_storage_mnttab_event (HalDevice *hal_volume)
1443 {
1444         FILE *fp = NULL;
1445         struct extmnttab m;
1446         HalDevice *d;
1447         unsigned int major;
1448         unsigned int minor;
1449         GSList *volumes = NULL;
1450         GSList *v;
1451         char *mount_point;
1452         dbus_bool_t is_partition;
1453         const char *fstype;
1454         int partition_number;
1455 
1456         if (hal_volume != NULL) {
1457                 volumes = g_slist_append (NULL, hal_volume);
1458         } else {
1459                 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume");
1460         }
1461         if (volumes == NULL) {
1462                 return;
1463         }
1464 
1465         if ((fp = fopen(MNTTAB, "r")) == NULL) {
1466                 HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno));
1467                 return;
1468         }
1469 
1470         while (getextmntent(fp, &m, 1) == 0) {
1471                 for (v = volumes; v != NULL; v = g_slist_next (v)) {
1472                         d = HAL_DEVICE (v->data);
1473                         major = hal_device_property_get_int (d, "block.major");
1474                         minor = hal_device_property_get_int (d, "block.minor");
1475 
1476                         /*
1477                          * special handling for pcfs, which encodes logical
1478                          * drive number into the 6 upper bits of the minor
1479                          */
1480                         is_partition = hal_device_property_get_bool (d, "volume.is_partition");
1481                         partition_number = hal_device_property_get_int (d, "volume.partition.number");
1482                         fstype = hal_device_property_get_string (d, "volume.fstype");
1483 
1484                         if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) {
1485                                 minor |= partition_number << 12;
1486                         }
1487 
1488                         if (m.mnt_major != major || m.mnt_minor != minor) {
1489                                 continue;
1490                         }
1491 
1492                         /* this volume matches the mnttab entry */
1493                         device_property_atomic_update_begin ();
1494                         hal_device_property_set_bool (d, "volume.is_mounted", TRUE);
1495                         hal_device_property_set_bool (d, "volume.is_mounted_read_only",
1496                                                       hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE);
1497                         hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp);
1498                         device_property_atomic_update_end ();
1499 
1500                         HAL_INFO (("set %s to be mounted at %s",
1501                                    hal_device_get_udi (d), m.mnt_mountp));
1502                         volumes = g_slist_delete_link (volumes, v);
1503                 }
1504         }
1505 
1506         /* all remaining volumes are not mounted */
1507         for (v = volumes; v != NULL; v = g_slist_next (v)) {
1508                 d = HAL_DEVICE (v->data);
1509                 mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point"));
1510                 if (mount_point == NULL || strlen (mount_point) == 0) {
1511                         g_free (mount_point);
1512                         continue;
1513                 }
1514 
1515                 device_property_atomic_update_begin ();
1516                 hal_device_property_set_bool (d, "volume.is_mounted", FALSE);
1517                 hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE);
1518                 hal_device_property_set_string (d, "volume.mount_point", "");
1519                 device_property_atomic_update_end ();
1520 
1521                 HAL_INFO (("set %s to unmounted", hal_device_get_udi (d)));
1522 
1523                 /* cleanup if was mounted by us */
1524                 if (hal_util_is_mounted_by_hald (mount_point)) {
1525                         char *cleanup_stdin;
1526                         char *extra_env[2];
1527 
1528                         HAL_INFO (("Cleaning up '%s'", mount_point));
1529 
1530                         extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point);
1531                         extra_env[1] = NULL;
1532                         cleanup_stdin = "\n";
1533 
1534                         hald_runner_run_method (d, 
1535                                                 "hal-storage-cleanup-mountpoint", 
1536                                                 extra_env, 
1537                                                 cleanup_stdin, TRUE,
1538                                                 0,
1539                                                 devinfo_storage_cleanup_mountpoint_cb,
1540                                                 g_strdup (mount_point), NULL);
1541 
1542                         g_free (extra_env[0]);
1543                 }
1544 
1545                 g_free (mount_point);
1546         }
1547         g_slist_free (volumes);
1548 
1549         (void) fclose (fp);
1550 }
1551 
1552 static void
1553 devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type, 
1554                   gint return_code, gchar **error,
1555                   gpointer data1, gpointer data2)
1556 {
1557         void *end_token = (void *) data1;
1558 
1559         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));
1560 
1561         if (exit_type == HALD_RUN_SUCCESS && error != NULL && 
1562             error[0] != NULL && error[1] != NULL) {
1563                 char *exp_name = NULL;
1564                 char *exp_detail = NULL;
1565 
1566                 exp_name = error[0];
1567                 if (error[0] != NULL) {
1568                         exp_detail = error[1];
1569                 }
1570                 HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail));
1571         }
1572 
1573         hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1574 }
1575 
1576 static void
1577 devinfo_volume_force_unmount (HalDevice *d, void *end_token)
1578 {
1579         const char *device_file;
1580         const char *mount_point;
1581         char *unmount_stdin;
1582         char *extra_env[2];
1583         extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0";
1584         extra_env[1] = NULL;
1585 
1586         device_file = hal_device_property_get_string (d, "block.device");
1587         mount_point = hal_device_property_get_string (d, "volume.mount_point");
1588 
1589         if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) {
1590                 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1591                 return;
1592         }
1593 
1594         HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d)));
1595                 
1596         unmount_stdin = "\n";
1597                 
1598         hald_runner_run_method (d, 
1599                                 "hal-storage-unmount", 
1600                                 extra_env, 
1601                                 unmount_stdin, TRUE,
1602                                 0,
1603                                 devinfo_volume_force_unmount_cb,
1604                                 end_token, NULL);
1605 }
1606 
1607 void
1608 devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token)
1609 {
1610         if (hal_device_property_get_bool (d, "volume.is_mounted")) {
1611                 devinfo_volume_force_unmount (d, end_token);
1612         } else {
1613                 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
1614         }
1615 }
1616 
1617 
1618 enum {
1619         LEGACY_CDROM,
1620         LEGACY_FLOPPY,
1621         LEGACY_RMDISK
1622 };
1623 
1624 static const char *legacy_media_str[] = {
1625         "cdrom",
1626         "floppy",
1627         "rmdisk"
1628 };
1629 
1630 struct enum_nick {
1631         const char *type;
1632         GSList  *nums;
1633 };
1634 
1635 static int
1636 devinfo_storage_get_legacy_media(HalDevice *d)
1637 {
1638         const char *drive_type;
1639 
1640         if (hal_device_has_capability (d, "storage.cdrom")) {
1641                 return (LEGACY_CDROM);
1642         } else if (((drive_type = hal_device_property_get_string (d,
1643             "storage.drive_type")) != NULL) && (strcmp (drive_type, "floppy") == 0)) {
1644                 return (LEGACY_FLOPPY);
1645         } else if (hal_device_property_get_bool (d, "storage.removable") ||
1646                    hal_device_property_get_bool (d, "storage.hotpluggable")) {
1647                 return (LEGACY_RMDISK);
1648         } else {
1649                 return (-1);
1650         }
1651 }
1652 
1653 static gboolean
1654 devinfo_storage_foreach_nick (HalDeviceStore *store, HalDevice *d, gpointer user_data)
1655 {
1656         struct enum_nick *en = (struct enum_nick *) user_data;
1657         const char *media_type;
1658         int media_num;
1659 
1660         media_type = hal_device_property_get_string (d, "storage.solaris.legacy.media_type");
1661         media_num = hal_device_property_get_int (d, "storage.solaris.legacy.media_num");
1662         if ((media_type != NULL) && (strcmp (media_type, en->type) == 0) &&
1663             (media_num >= 0)) {
1664                 en->nums = g_slist_prepend (en->nums, GINT_TO_POINTER(media_num));
1665         }
1666         return TRUE;
1667 }
1668 
1669 static void
1670 devinfo_storage_append_nickname (HalDevice *d, const char *media_type, int media_num)
1671 {
1672         char buf[64];
1673 
1674         if (media_num == 0) {
1675                 hal_device_property_strlist_append (d, "storage.solaris.nicknames", media_type);
1676         }
1677         snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
1678         hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf);
1679 }
1680 
1681 static void
1682 devinfo_storage_set_nicknames (HalDevice *d)
1683 {
1684         int media;
1685         const char *media_type;
1686         int media_num;
1687         GSList *i;
1688         struct enum_nick en;
1689         char buf[64];
1690 
1691         if ((media = devinfo_storage_get_legacy_media (d)) < 0) {
1692                 return;
1693         }
1694         media_type = legacy_media_str[media];
1695 
1696         /* enumerate all storage devices of this media type */
1697         en.type = media_type;
1698         en.nums = NULL;
1699         hal_device_store_foreach (hald_get_gdl (), devinfo_storage_foreach_nick, &en);
1700 
1701         /* find a free number */
1702         for (media_num = 0; ; media_num++) {
1703                 for (i = en.nums; i != NULL; i = g_slist_next (i)) {
1704                         if (GPOINTER_TO_INT (i->data) == media_num) {
1705                                 break;
1706                         }
1707                 }
1708                 if (i == NULL) {
1709                         break;
1710                 }
1711         }
1712         g_slist_free (en.nums);
1713 
1714         hal_device_property_set_string (d, "storage.solaris.legacy.media_type", media_type);
1715         hal_device_property_set_int (d, "storage.solaris.legacy.media_num", media_num);
1716 
1717         /* primary nickname, and also vold-style symdev */
1718         snprintf(buf, sizeof (buf), "%s%d", media_type, media_num);
1719         hal_device_property_set_string (d, "storage.solaris.legacy.symdev", buf);
1720         devinfo_storage_append_nickname(d, media_type, media_num);
1721 
1722         /* additional nicknames */
1723         if (media == LEGACY_CDROM) {
1724                 devinfo_storage_append_nickname(d, "cd", media_num);
1725                 devinfo_storage_append_nickname(d, "sr", media_num);
1726         } else if (media == LEGACY_FLOPPY) {
1727                 devinfo_storage_append_nickname(d, "fd", media_num);
1728                 devinfo_storage_append_nickname(d, "diskette", media_num);
1729                 devinfo_storage_append_nickname(d, "rdiskette", media_num);
1730         }
1731 }