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