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