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