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