1 /*************************************************************************** 2 * 3 * devinfo_storage.c : storage devices 4 * 5 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 6 * Copyright 2013 Garrett D'Amore <garrett@damore.org> 7 * Copyright 2014 Andrew Stormont. 8 * 9 * Licensed under the Academic Free License version 2.1 10 * 11 **************************************************************************/ 12 13 #ifdef HAVE_CONFIG_H 14 # include <config.h> 15 #endif 16 17 #include <stdio.h> 18 #include <string.h> 19 #include <strings.h> 20 #include <ctype.h> 21 #include <libdevinfo.h> 22 #include <sys/types.h> 23 #include <sys/mkdev.h> 24 #include <sys/stat.h> 25 #include <sys/mntent.h> 26 #include <sys/mnttab.h> 27 28 #include "../osspec.h" 29 #include "../logger.h" 30 #include "../hald.h" 31 #include "../hald_dbus.h" 32 #include "../device_info.h" 33 #include "../util.h" 34 #include "../hald_runner.h" 35 #include "hotplug.h" 36 #include "devinfo.h" 37 #include "devinfo_misc.h" 38 #include "devinfo_storage.h" 39 #include "osspec_solaris.h" 40 41 #ifdef sparc 42 #define WHOLE_DISK "s2" 43 #else 44 #define WHOLE_DISK "p0" 45 #endif 46 47 /* some devices,especially CDROMs, may take a while to be probed (values in ms) */ 48 #define DEVINFO_PROBE_STORAGE_TIMEOUT 60000 49 #define DEVINFO_PROBE_VOLUME_TIMEOUT 60000 50 51 typedef struct devinfo_storage_minor { 52 char *devpath; 53 char *devlink; 54 char *slice; 55 dev_t dev; 56 int dosnum; /* dos disk number or -1 */ 57 } devinfo_storage_minor_t; 58 59 HalDevice *devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 60 static HalDevice *devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path); 61 static HalDevice *devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path); 62 static HalDevice *devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 63 HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 64 static HalDevice *devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 65 HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 66 static HalDevice *devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 67 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 68 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node); 69 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 70 static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev); 71 static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean); 72 static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice, 73 char *devlink, dev_t dev, int dosnum); 74 static void devinfo_storage_free_minor(struct devinfo_storage_minor *m); 75 HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m); 76 static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2); 77 static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token); 78 static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token); 79 static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2); 80 const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout); 81 const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout); 82 83 static char *devinfo_scsi_dtype2str(int dtype); 84 static char *devinfo_volume_get_slice_name (char *devlink); 85 static boolean_t is_dos_slice(const char *slice, 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 m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1); 863 if (m == NULL) { 864 free (devlink); 865 di_devfs_path_free (minor_path); 866 continue; 867 } 868 869 /* main device is either s2/p0 or d0, the latter taking precedence */ 870 if ((strcmp (slice, "d0") == 0) || 871 (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) { 872 if (maindev_path != NULL) { 873 di_devfs_path_free (maindev_path); 874 } 875 maindev_path = minor_path; 876 maindev = m; 877 g_queue_push_head (mq, maindev); 878 } else { 879 di_devfs_path_free (minor_path); 880 g_queue_push_tail (mq, m); 881 } 882 883 free (devlink); 884 } 885 di_devlink_fini (&devlink_hdl); 886 887 if (maindev == NULL) { 888 /* shouldn't typically happen */ 889 while (!g_queue_is_empty (mq)) { 890 devinfo_storage_free_minor (g_queue_pop_head (mq)); 891 } 892 goto err; 893 } 894 895 /* first enqueue main storage device */ 896 if (!rescan) { 897 hal_device_property_set_int (parent, "block.major", major); 898 hal_device_property_set_int (parent, "block.minor", minor(maindev->dev)); 899 hal_device_property_set_string (parent, "block.device", maindev->devlink); 900 raw = dsk_to_rdsk (maindev->devlink); 901 hal_device_property_set_string (parent, "block.solaris.raw_device", raw); 902 free (raw); 903 hal_device_property_set_bool (parent, "block.is_volume", FALSE); 904 hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path); 905 devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler); 906 } 907 908 maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0); 909 910 /* enqueue all volumes */ 911 while (!g_queue_is_empty (mq)) { 912 m = g_queue_pop_head (mq); 913 914 /* if main device is d0, we'll throw away s2/p0 */ 915 if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) { 916 devinfo_storage_free_minor (m); 917 continue; 918 } 919 /* don't do p0 on cdrom */ 920 if (is_cdrom && (strcmp (m->slice, "p0") == 0)) { 921 devinfo_storage_free_minor (m); 922 continue; 923 } 924 if (rescan) { 925 /* in rescan mode, don't reprobe existing volumes */ 926 /* XXX detect volume removal? */ 927 volume = hal_device_store_match_key_value_string (hald_get_gdl (), 928 "solaris.devfs_path", m->devpath); 929 if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) { 930 devinfo_volume_add (parent, node, m); 931 } else { 932 HAL_INFO(("rescan volume exists %s", m->devpath)); 933 } 934 } else { 935 devinfo_volume_add (parent, node, m); 936 } 937 devinfo_storage_free_minor (m); 938 } 939 940 if (maindev_path != NULL) { 941 di_devfs_path_free (maindev_path); 942 } 943 944 return; 945 946 err: 947 if (maindev_path != NULL) { 948 di_devfs_path_free (maindev_path); 949 } 950 if (!rescan) { 951 devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler); 952 } 953 } 954 955 HalDevice * 956 devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m) 957 { 958 HalDevice *d; 959 char *raw; 960 char udi[HAL_PATH_MAX]; 961 char *devfs_path = m->devpath; 962 char *devlink = m->devlink; 963 dev_t dev = m->dev; 964 int dosnum = m->dosnum; 965 char *slice = m->slice; 966 967 HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink)); 968 d = hal_device_new (); 969 970 devinfo_set_default_properties (d, parent, node, devfs_path); 971 hal_device_property_set_string (d, "info.category", "volume"); 972 973 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 974 "%s/%s", hal_device_get_udi (parent), slice); 975 hal_device_set_udi (d, udi); 976 hal_device_property_set_string (d, "info.udi", udi); 977 hal_device_property_set_string (d, "info.product", slice); 978 979 hal_device_add_capability (d, "volume"); 980 hal_device_add_capability (d, "block"); 981 hal_device_property_set_int (d, "block.major", major (dev)); 982 hal_device_property_set_int (d, "block.minor", minor (dev)); 983 hal_device_property_set_string (d, "block.device", devlink); 984 raw = dsk_to_rdsk (devlink); 985 hal_device_property_set_string (d, "block.solaris.raw_device", raw); 986 free (raw); 987 hal_device_property_set_string (d, "block.solaris.slice", slice); 988 hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */ 989 990 hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent)); 991 992 /* set volume defaults */ 993 hal_device_property_set_string (d, "volume.fstype", ""); 994 hal_device_property_set_string (d, "volume.fsusage", ""); 995 hal_device_property_set_string (d, "volume.fsversion", ""); 996 hal_device_property_set_string (d, "volume.uuid", ""); 997 hal_device_property_set_string (d, "volume.label", ""); 998 hal_device_property_set_string (d, "volume.mount_point", ""); 999 hal_device_property_set_bool (d, "volume.is_mounted", FALSE); 1000 if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) { 1001 hal_device_property_set_bool (d, "volume.is_disc", TRUE); 1002 hal_device_add_capability (d, "volume.disc"); 1003 } else { 1004 hal_device_property_set_bool (d, "volume.is_disc", FALSE); 1005 } 1006 1007 if (dosnum > 0) { 1008 hal_device_property_set_bool (d, "volume.is_partition", TRUE); 1009 hal_device_property_set_int (d, "volume.partition.number", dosnum); 1010 } else { 1011 hal_device_property_set_bool (d, "volume.is_partition", FALSE); 1012 } 1013 1014 /* prober may override these */ 1015 hal_device_property_set_int (d, "volume.block_size", 512); 1016 1017 devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler); 1018 1019 return (d); 1020 } 1021 1022 static void 1023 devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 1024 { 1025 void *end_token = (void *) userdata1; 1026 char *whole_disk; 1027 char *block_device; 1028 const char *storage_udi; 1029 HalDevice *storage_d; 1030 const char *slice; 1031 int dos_num; 1032 1033 if (hal_device_property_get_bool (d, "info.ignore")) { 1034 HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d))); 1035 goto skip; 1036 } 1037 1038 /* 1039 * Optimizations: only probe if there's a chance to find something 1040 */ 1041 block_device = (char *)hal_device_property_get_string (d, "block.device"); 1042 storage_udi = hal_device_property_get_string (d, "block.storage_device"); 1043 slice = hal_device_property_get_string(d, "block.solaris.slice"); 1044 if ((block_device == NULL) || (storage_udi == NULL) || 1045 (slice == NULL) || (strlen (slice) < 2)) { 1046 HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d))); 1047 goto skip; 1048 } 1049 storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi); 1050 if (storage_d == NULL) { 1051 HAL_INFO (("Storage device not found %s", hal_device_get_udi (d))); 1052 goto skip; 1053 } 1054 1055 whole_disk = hal_device_has_capability (storage_d, 1056 "storage.cdrom") ? "s2" : WHOLE_DISK; 1057 1058 if (is_dos_slice(slice, &dos_num)) { 1059 /* don't probe more dos volumes than probe-storage found */ 1060 if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") || 1061 (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) { 1062 HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d, 1063 "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d))); 1064 goto skip; 1065 } 1066 } else { 1067 /* if no VTOC slices found, don't probe slices except s2 */ 1068 if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) && 1069 !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) { 1070 HAL_INFO (("Not probing slice %s", hal_device_get_udi (d))); 1071 goto skip; 1072 } 1073 } 1074 1075 HAL_INFO(("Probing udi=%s", hal_device_get_udi (d))); 1076 hald_runner_run (d, 1077 "hald-probe-volume", NULL, 1078 DEVINFO_PROBE_VOLUME_TIMEOUT, 1079 devinfo_callouts_probing_done, 1080 (gpointer) end_token, userdata2); 1081 1082 return; 1083 1084 skip: 1085 hal_device_store_remove (hald_get_tdl (), d); 1086 g_object_unref (d); 1087 hotplug_event_end (end_token); 1088 } 1089 1090 static void 1091 devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 1092 { 1093 HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d))); 1094 1095 if (parent == NULL) { 1096 HAL_INFO (("no parent %s", hal_device_get_udi (d))); 1097 goto skip; 1098 } 1099 1100 if (hal_device_property_get_bool (parent, "info.ignore")) { 1101 HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE")); 1102 goto skip; 1103 } 1104 1105 /* add to TDL so preprobing callouts and prober can access it */ 1106 hal_device_store_add (hald_get_tdl (), d); 1107 1108 /* Process preprobe fdi files */ 1109 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 1110 1111 /* Run preprobe callouts */ 1112 hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler); 1113 1114 return; 1115 1116 skip: 1117 g_object_unref (d); 1118 hotplug_event_end (end_token); 1119 } 1120 1121 void 1122 devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 1123 { 1124 const char *drive_type; 1125 const char *p_udi; 1126 HalDevice *p_d; 1127 HalDevice *phys_d = NULL; 1128 const char *phys_bus; 1129 const char *bus; 1130 static const char *busses[] = { "usb", "ide", "scsi", "ieee1394", 1131 "pseudo" }; 1132 int i; 1133 1134 HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d))); 1135 1136 if (parent == NULL) { 1137 HAL_INFO (("no parent %s", hal_device_get_udi (d))); 1138 goto error; 1139 } 1140 1141 /* 1142 * figure out physical device and bus, except for floppy 1143 */ 1144 drive_type = hal_device_property_get_string (d, "storage.drive_type"); 1145 if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) { 1146 goto skip_bus; 1147 } 1148 1149 p_d = parent; 1150 for (;;) { 1151 bus = hal_device_property_get_string (p_d, "info.subsystem"); 1152 if (bus != NULL) { 1153 for (i = 0; i < NELEM(busses); i++) { 1154 if (strcmp(bus, busses[i]) == 0) { 1155 phys_d = p_d; 1156 phys_bus = busses[i]; 1157 break; 1158 } 1159 } 1160 } 1161 /* up the tree */ 1162 p_udi = hal_device_property_get_string (p_d, "info.parent"); 1163 if (p_udi == NULL) { 1164 break; 1165 } 1166 p_d = hal_device_store_find (hald_get_gdl (), p_udi); 1167 } 1168 if (phys_d == NULL) { 1169 HAL_INFO (("no physical device %s", hal_device_get_udi (d))); 1170 } else { 1171 hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d)); 1172 hal_device_property_set_string (d, "storage.bus", phys_bus); 1173 } 1174 1175 skip_bus: 1176 1177 /* add to TDL so preprobing callouts and prober can access it */ 1178 hal_device_store_add (hald_get_tdl (), d); 1179 1180 /* Process preprobe fdi files */ 1181 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 1182 1183 /* Run preprobe callouts */ 1184 hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 1185 1186 return; 1187 1188 error: 1189 g_object_unref (d); 1190 hotplug_event_end (end_token); 1191 } 1192 1193 static void 1194 devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 1195 { 1196 void *end_token = (void *) userdata1; 1197 1198 HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d))); 1199 1200 /* Discard device if probing reports failure */ 1201 if (exit_type != HALD_RUN_SUCCESS || return_code != 0) { 1202 HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code)); 1203 hal_device_store_remove (hald_get_tdl (), d); 1204 g_object_unref (d); 1205 hotplug_event_end (end_token); 1206 return; 1207 } 1208 1209 devinfo_storage_set_nicknames (d); 1210 1211 /* Merge properties from .fdi files */ 1212 di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 1213 di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 1214 1215 hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 1216 } 1217 1218 const gchar * 1219 devinfo_storage_get_prober (HalDevice *d, int *timeout) 1220 { 1221 *timeout = DEVINFO_PROBE_STORAGE_TIMEOUT; 1222 return "hald-probe-storage"; 1223 } 1224 1225 const gchar * 1226 devinfo_volume_get_prober (HalDevice *d, int *timeout) 1227 { 1228 *timeout = DEVINFO_PROBE_VOLUME_TIMEOUT; 1229 return "hald-probe-volume"; 1230 } 1231 1232 /* 1233 * After reprobing storage, reprobe its volumes. 1234 */ 1235 static void 1236 devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 1237 { 1238 void *end_token = (void *) userdata1; 1239 const char *devfs_path_orig = NULL; 1240 char *devfs_path = NULL; 1241 char *p; 1242 di_node_t node; 1243 1244 HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d))); 1245 1246 devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path"); 1247 if (devfs_path_orig == NULL) { 1248 HAL_INFO (("device has no solaris.devfs_path")); 1249 hotplug_event_process_queue (); 1250 return; 1251 } 1252 1253 /* strip trailing minor part if any */ 1254 if (strrchr(devfs_path_orig, ':') != NULL) { 1255 if ((devfs_path = strdup (devfs_path_orig)) != NULL) { 1256 p = strrchr(devfs_path, ':'); 1257 *p = '\0'; 1258 } 1259 } else { 1260 devfs_path = (char *)devfs_path_orig; 1261 } 1262 1263 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) { 1264 HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d))); 1265 hotplug_event_process_queue (); 1266 return; 1267 } else { 1268 devinfo_storage_minors (d, node, (char *)devfs_path, TRUE); 1269 di_fini (node); 1270 } 1271 1272 if (devfs_path != devfs_path_orig) { 1273 free (devfs_path); 1274 } 1275 1276 hotplug_event_process_queue (); 1277 } 1278 1279 /* 1280 * For removable media devices, check for "storage.removable.media_available". 1281 * For non-removable media devices, assume media is always there. 1282 * 1283 * If media is gone, enqueue remove events for all children volumes. 1284 * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone). 1285 */ 1286 gboolean 1287 devinfo_storage_device_rescan (HalDevice *d) 1288 { 1289 GSList *i; 1290 GSList *volumes; 1291 HalDevice *v; 1292 gchar *v_devfs_path; 1293 const char *drive_type; 1294 gboolean is_floppy; 1295 gboolean media_available; 1296 1297 HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d))); 1298 1299 if (hal_device_property_get_bool (d, "block.is_volume")) { 1300 HAL_INFO (("nothing to do for volume")); 1301 return (FALSE); 1302 } 1303 1304 drive_type = hal_device_property_get_string (d, "storage.drive_type"); 1305 is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0); 1306 1307 media_available = !hal_device_property_get_bool (d, "storage.removable") || 1308 hal_device_property_get_bool (d, "storage.removable.media_available"); 1309 1310 if (!media_available && !is_floppy) { 1311 HAL_INFO (("media gone %s", hal_device_get_udi (d))); 1312 1313 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 1314 "block.storage_device", hal_device_get_udi (d)); 1315 for (i = volumes; i != NULL; i = g_slist_next (i)) { 1316 v = HAL_DEVICE (i->data); 1317 v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path"); 1318 HAL_INFO (("child volume %s", hal_device_get_udi (v))); 1319 if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) { 1320 HAL_INFO (("removing volume %s", hal_device_get_udi (v))); 1321 devinfo_remove_enqueue (v_devfs_path, NULL); 1322 } else { 1323 HAL_INFO (("not a volume %s", hal_device_get_udi (v))); 1324 } 1325 } 1326 g_slist_free (volumes); 1327 1328 hotplug_event_process_queue (); 1329 } else if (is_floppy) { 1330 HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d))); 1331 1332 hald_runner_run (d, 1333 "hald-probe-storage --only-check-for-media", NULL, 1334 DEVINFO_PROBE_STORAGE_TIMEOUT, 1335 devinfo_floppy_rescan_probing_done, 1336 NULL, NULL); 1337 } else { 1338 HAL_INFO (("media available %s", hal_device_get_udi (d))); 1339 1340 hald_runner_run (d, 1341 "hald-probe-storage --only-check-for-media", NULL, 1342 DEVINFO_PROBE_STORAGE_TIMEOUT, 1343 devinfo_storage_rescan_probing_done, 1344 NULL, NULL); 1345 } 1346 1347 return TRUE; 1348 } 1349 1350 static char * 1351 devinfo_volume_get_slice_name (char *devlink) 1352 { 1353 char *part, *slice, *disk; 1354 char *s = NULL; 1355 char *p; 1356 1357 if ((p = strstr(devlink, "/lofi/")) != 0) { 1358 return (p + sizeof ("/lofi/") - 1); 1359 } 1360 1361 part = strrchr(devlink, 'p'); 1362 slice = strrchr(devlink, 's'); 1363 disk = strrchr(devlink, 'd'); 1364 1365 if ((part != NULL) && (part > slice) && (part > disk)) { 1366 s = part; 1367 } else if ((slice != NULL) && (slice > disk)) { 1368 s = slice; 1369 } else { 1370 s = disk; 1371 } 1372 if ((s != NULL) && isdigit(s[1])) { 1373 return (s); 1374 } else { 1375 return (""); 1376 } 1377 } 1378 1379 static boolean_t 1380 is_dos_slice(const char *slice, int *partnum) 1381 { 1382 char *p; 1383 1384 if ((p = strrchr(slice, 'p')) == NULL && 1385 (p = strrchr(slice, ':')) == NULL) { 1386 return (B_FALSE); 1387 } 1388 1389 return ((*partnum = atoi(p + 1)) != 0); 1390 } 1391 1392 static void 1393 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type, 1394 gint return_code, gchar **error, 1395 gpointer data1, gpointer data2) 1396 { 1397 char *mount_point = (char *) data1; 1398 1399 HAL_INFO (("Cleaned up mount point '%s'", mount_point)); 1400 g_free (mount_point); 1401 } 1402 1403 1404 void 1405 devinfo_storage_mnttab_event (HalDevice *hal_volume) 1406 { 1407 FILE *fp = NULL; 1408 struct extmnttab m; 1409 HalDevice *d; 1410 unsigned int major; 1411 unsigned int minor; 1412 GSList *volumes = NULL; 1413 GSList *v; 1414 char *mount_point; 1415 dbus_bool_t is_partition; 1416 const char *fstype; 1417 int partition_number; 1418 1419 if (hal_volume != NULL) { 1420 volumes = g_slist_append (NULL, hal_volume); 1421 } else { 1422 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume"); 1423 } 1424 if (volumes == NULL) { 1425 return; 1426 } 1427 1428 if ((fp = fopen(MNTTAB, "r")) == NULL) { 1429 HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno)); 1430 return; 1431 } 1432 1433 while (getextmntent(fp, &m, 1) == 0) { 1434 for (v = volumes; v != NULL; v = g_slist_next (v)) { 1435 d = HAL_DEVICE (v->data); 1436 major = hal_device_property_get_int (d, "block.major"); 1437 minor = hal_device_property_get_int (d, "block.minor"); 1438 1439 /* 1440 * special handling for pcfs, which encodes logical 1441 * drive number into the 6 upper bits of the minor 1442 */ 1443 is_partition = hal_device_property_get_bool (d, "volume.is_partition"); 1444 partition_number = hal_device_property_get_int (d, "volume.partition.number"); 1445 fstype = hal_device_property_get_string (d, "volume.fstype"); 1446 1447 if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) { 1448 minor |= partition_number << 12; 1449 } 1450 1451 if (m.mnt_major != major || m.mnt_minor != minor) { 1452 continue; 1453 } 1454 1455 /* this volume matches the mnttab entry */ 1456 device_property_atomic_update_begin (); 1457 hal_device_property_set_bool (d, "volume.is_mounted", TRUE); 1458 hal_device_property_set_bool (d, "volume.is_mounted_read_only", 1459 hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE); 1460 hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp); 1461 device_property_atomic_update_end (); 1462 1463 HAL_INFO (("set %s to be mounted at %s", 1464 hal_device_get_udi (d), m.mnt_mountp)); 1465 volumes = g_slist_delete_link (volumes, v); 1466 } 1467 } 1468 1469 /* all remaining volumes are not mounted */ 1470 for (v = volumes; v != NULL; v = g_slist_next (v)) { 1471 d = HAL_DEVICE (v->data); 1472 mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point")); 1473 if (mount_point == NULL || strlen (mount_point) == 0) { 1474 g_free (mount_point); 1475 continue; 1476 } 1477 1478 device_property_atomic_update_begin (); 1479 hal_device_property_set_bool (d, "volume.is_mounted", FALSE); 1480 hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE); 1481 hal_device_property_set_string (d, "volume.mount_point", ""); 1482 device_property_atomic_update_end (); 1483 1484 HAL_INFO (("set %s to unmounted", hal_device_get_udi (d))); 1485 1486 /* cleanup if was mounted by us */ 1487 if (hal_util_is_mounted_by_hald (mount_point)) { 1488 char *cleanup_stdin; 1489 char *extra_env[2]; 1490 1491 HAL_INFO (("Cleaning up '%s'", mount_point)); 1492 1493 extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point); 1494 extra_env[1] = NULL; 1495 cleanup_stdin = "\n"; 1496 1497 hald_runner_run_method (d, 1498 "hal-storage-cleanup-mountpoint", 1499 extra_env, 1500 cleanup_stdin, TRUE, 1501 0, 1502 devinfo_storage_cleanup_mountpoint_cb, 1503 g_strdup (mount_point), NULL); 1504 1505 g_free (extra_env[0]); 1506 } 1507 1508 g_free (mount_point); 1509 } 1510 g_slist_free (volumes); 1511 1512 (void) fclose (fp); 1513 } 1514 1515 static void 1516 devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type, 1517 gint return_code, gchar **error, 1518 gpointer data1, gpointer data2) 1519 { 1520 void *end_token = (void *) data1; 1521 1522 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)); 1523 1524 if (exit_type == HALD_RUN_SUCCESS && error != NULL && 1525 error[0] != NULL && error[1] != NULL) { 1526 char *exp_name = NULL; 1527 char *exp_detail = NULL; 1528 1529 exp_name = error[0]; 1530 if (error[0] != NULL) { 1531 exp_detail = error[1]; 1532 } 1533 HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail)); 1534 } 1535 1536 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 1537 } 1538 1539 static void 1540 devinfo_volume_force_unmount (HalDevice *d, void *end_token) 1541 { 1542 const char *device_file; 1543 const char *mount_point; 1544 char *unmount_stdin; 1545 char *extra_env[2]; 1546 extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0"; 1547 extra_env[1] = NULL; 1548 1549 device_file = hal_device_property_get_string (d, "block.device"); 1550 mount_point = hal_device_property_get_string (d, "volume.mount_point"); 1551 1552 if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) { 1553 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 1554 return; 1555 } 1556 1557 HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d))); 1558 1559 unmount_stdin = "\n"; 1560 1561 hald_runner_run_method (d, 1562 "hal-storage-unmount", 1563 extra_env, 1564 unmount_stdin, TRUE, 1565 0, 1566 devinfo_volume_force_unmount_cb, 1567 end_token, NULL); 1568 } 1569 1570 void 1571 devinfo_volume_hotplug_begin_remove (HalDevice *d, char *devfs_path, void *end_token) 1572 { 1573 if (hal_device_property_get_bool (d, "volume.is_mounted")) { 1574 devinfo_volume_force_unmount (d, end_token); 1575 } else { 1576 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 1577 } 1578 } 1579 1580 1581 enum { 1582 LEGACY_CDROM, 1583 LEGACY_FLOPPY, 1584 LEGACY_RMDISK 1585 }; 1586 1587 static const char *legacy_media_str[] = { 1588 "cdrom", 1589 "floppy", 1590 "rmdisk" 1591 }; 1592 1593 struct enum_nick { 1594 const char *type; 1595 GSList *nums; 1596 }; 1597 1598 static int 1599 devinfo_storage_get_legacy_media(HalDevice *d) 1600 { 1601 const char *drive_type; 1602 1603 if (hal_device_has_capability (d, "storage.cdrom")) { 1604 return (LEGACY_CDROM); 1605 } else if (((drive_type = hal_device_property_get_string (d, 1606 "storage.drive_type")) != NULL) && (strcmp (drive_type, "floppy") == 0)) { 1607 return (LEGACY_FLOPPY); 1608 } else if (hal_device_property_get_bool (d, "storage.removable") || 1609 hal_device_property_get_bool (d, "storage.hotpluggable")) { 1610 return (LEGACY_RMDISK); 1611 } else { 1612 return (-1); 1613 } 1614 } 1615 1616 static gboolean 1617 devinfo_storage_foreach_nick (HalDeviceStore *store, HalDevice *d, gpointer user_data) 1618 { 1619 struct enum_nick *en = (struct enum_nick *) user_data; 1620 const char *media_type; 1621 int media_num; 1622 1623 media_type = hal_device_property_get_string (d, "storage.solaris.legacy.media_type"); 1624 media_num = hal_device_property_get_int (d, "storage.solaris.legacy.media_num"); 1625 if ((media_type != NULL) && (strcmp (media_type, en->type) == 0) && 1626 (media_num >= 0)) { 1627 en->nums = g_slist_prepend (en->nums, GINT_TO_POINTER(media_num)); 1628 } 1629 return TRUE; 1630 } 1631 1632 static void 1633 devinfo_storage_append_nickname (HalDevice *d, const char *media_type, int media_num) 1634 { 1635 char buf[64]; 1636 1637 if (media_num == 0) { 1638 hal_device_property_strlist_append (d, "storage.solaris.nicknames", media_type); 1639 } 1640 snprintf(buf, sizeof (buf), "%s%d", media_type, media_num); 1641 hal_device_property_strlist_append (d, "storage.solaris.nicknames", buf); 1642 } 1643 1644 static void 1645 devinfo_storage_set_nicknames (HalDevice *d) 1646 { 1647 int media; 1648 const char *media_type; 1649 int media_num; 1650 GSList *i; 1651 struct enum_nick en; 1652 char buf[64]; 1653 1654 if ((media = devinfo_storage_get_legacy_media (d)) < 0) { 1655 return; 1656 } 1657 media_type = legacy_media_str[media]; 1658 1659 /* enumerate all storage devices of this media type */ 1660 en.type = media_type; 1661 en.nums = NULL; 1662 hal_device_store_foreach (hald_get_gdl (), devinfo_storage_foreach_nick, &en); 1663 1664 /* find a free number */ 1665 for (media_num = 0; ; media_num++) { 1666 for (i = en.nums; i != NULL; i = g_slist_next (i)) { 1667 if (GPOINTER_TO_INT (i->data) == media_num) { 1668 break; 1669 } 1670 } 1671 if (i == NULL) { 1672 break; 1673 } 1674 } 1675 g_slist_free (en.nums); 1676 1677 hal_device_property_set_string (d, "storage.solaris.legacy.media_type", media_type); 1678 hal_device_property_set_int (d, "storage.solaris.legacy.media_num", media_num); 1679 1680 /* primary nickname, and also vold-style symdev */ 1681 snprintf(buf, sizeof (buf), "%s%d", media_type, media_num); 1682 hal_device_property_set_string (d, "storage.solaris.legacy.symdev", buf); 1683 devinfo_storage_append_nickname(d, media_type, media_num); 1684 1685 /* additional nicknames */ 1686 if (media == LEGACY_CDROM) { 1687 devinfo_storage_append_nickname(d, "cd", media_num); 1688 devinfo_storage_append_nickname(d, "sr", media_num); 1689 } else if (media == LEGACY_FLOPPY) { 1690 devinfo_storage_append_nickname(d, "fd", media_num); 1691 devinfo_storage_append_nickname(d, "diskette", media_num); 1692 devinfo_storage_append_nickname(d, "rdiskette", media_num); 1693 } 1694 }