1 /*************************************************************************** 2 * 3 * devinfo_storage.c : storage devices 4 * 5 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved. 6 * Copyright 2013 Garrett D'Amore <garrett@damore.org> 7 * Copyright 2014 Andrew Stormont. 8 * 9 * Licensed under the Academic Free License version 2.1 10 * 11 **************************************************************************/ 12 13 #ifdef HAVE_CONFIG_H 14 # include <config.h> 15 #endif 16 17 #include <stdio.h> 18 #include <string.h> 19 #include <strings.h> 20 #include <ctype.h> 21 #include <libdevinfo.h> 22 #include <sys/types.h> 23 #include <sys/mkdev.h> 24 #include <sys/stat.h> 25 #include <sys/mntent.h> 26 #include <sys/mnttab.h> 27 28 #include "../osspec.h" 29 #include "../logger.h" 30 #include "../hald.h" 31 #include "../hald_dbus.h" 32 #include "../device_info.h" 33 #include "../util.h" 34 #include "../hald_runner.h" 35 #include "hotplug.h" 36 #include "devinfo.h" 37 #include "devinfo_misc.h" 38 #include "devinfo_storage.h" 39 #include "osspec_solaris.h" 40 41 #ifdef sparc 42 #define WHOLE_DISK "s2" 43 #else 44 #define WHOLE_DISK "p0" 45 #endif 46 47 /* some devices,especially CDROMs, may take a while to be probed (values in ms) */ 48 #define DEVINFO_PROBE_STORAGE_TIMEOUT 60000 49 #define DEVINFO_PROBE_VOLUME_TIMEOUT 60000 50 51 typedef struct devinfo_storage_minor { 52 char *devpath; 53 char *devlink; 54 char *slice; 55 dev_t dev; 56 int dosnum; /* dos disk number or -1 */ 57 } devinfo_storage_minor_t; 58 59 HalDevice *devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 60 static HalDevice *devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path); 61 static HalDevice *devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path); 62 static HalDevice *devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 63 HalDevice *devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 64 static HalDevice *devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 65 HalDevice *devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 66 static HalDevice *devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path); 67 HalDevice *devinfo_floppy_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 68 static void devinfo_floppy_add_volume(HalDevice *parent, di_node_t node); 69 static HalDevice *devinfo_lofi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 70 static void devinfo_lofi_add_minor(HalDevice *parent, di_node_t node, char *minor_path, char *devlink, dev_t dev); 71 static void devinfo_storage_minors(HalDevice *parent, di_node_t node, gchar *devfs_path, gboolean); 72 static struct devinfo_storage_minor *devinfo_storage_new_minor(char *maindev_path, char *slice, 73 char *devlink, dev_t dev, int dosnum); 74 static void devinfo_storage_free_minor(struct devinfo_storage_minor *m); 75 HalDevice *devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m); 76 static void devinfo_volume_preprobing_done(HalDevice *d, gpointer userdata1, gpointer userdata2); 77 static void devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token); 78 static void devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token); 79 static void devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2); 80 const gchar *devinfo_volume_get_prober (HalDevice *d, int *timeout); 81 const gchar *devinfo_storage_get_prober (HalDevice *d, int *timeout); 82 83 static char *devinfo_scsi_dtype2str(int dtype); 84 static char *devinfo_volume_get_slice_name (char *devlink); 85 static gboolean dos_to_dev(char *path, char **devpath, int *partnum); 86 static gboolean is_dos_path(char *path, int *partnum); 87 88 static void devinfo_storage_set_nicknames (HalDevice *d); 89 90 DevinfoDevHandler devinfo_ide_handler = { 91 devinfo_ide_add, 92 NULL, 93 NULL, 94 NULL, 95 NULL, 96 NULL 97 }; 98 DevinfoDevHandler devinfo_scsi_handler = { 99 devinfo_scsi_add, 100 NULL, 101 NULL, 102 NULL, 103 NULL, 104 NULL 105 }; 106 DevinfoDevHandler devinfo_blkdev_handler = { 107 devinfo_blkdev_add, 108 NULL, 109 NULL, 110 NULL, 111 NULL, 112 NULL 113 }; 114 DevinfoDevHandler devinfo_floppy_handler = { 115 devinfo_floppy_add, 116 NULL, 117 NULL, 118 NULL, 119 NULL, 120 NULL 121 }; 122 DevinfoDevHandler devinfo_lofi_handler = { 123 devinfo_lofi_add, 124 NULL, 125 NULL, 126 NULL, 127 NULL, 128 NULL 129 }; 130 DevinfoDevHandler devinfo_storage_handler = { 131 NULL, 132 NULL, 133 devinfo_storage_hotplug_begin_add, 134 NULL, 135 devinfo_storage_probing_done, 136 devinfo_storage_get_prober 137 }; 138 DevinfoDevHandler devinfo_volume_handler = { 139 NULL, 140 NULL, 141 devinfo_volume_hotplug_begin_add, 142 NULL, 143 NULL, 144 devinfo_volume_get_prober 145 }; 146 147 /* IDE */ 148 149 HalDevice * 150 devinfo_ide_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 151 { 152 char *s; 153 154 if ((device_type != NULL) && (strcmp(device_type, "ide") == 0)) { 155 return (devinfo_ide_host_add(parent, node, devfs_path)); 156 } 157 158 if ((di_prop_lookup_strings (DDI_DEV_T_ANY, node, "class", &s) > 0) && 159 (strcmp (s, "dada") == 0)) { 160 return (devinfo_ide_device_add(parent, node, devfs_path)); 161 } 162 163 return (NULL); 164 } 165 166 static HalDevice * 167 devinfo_ide_host_add(HalDevice *parent, di_node_t node, char *devfs_path) 168 { 169 HalDevice *d; 170 171 d = hal_device_new (); 172 173 devinfo_set_default_properties (d, parent, node, devfs_path); 174 hal_device_property_set_string (d, "info.product", "IDE host controller"); 175 hal_device_property_set_string (d, "info.subsystem", "ide_host"); 176 hal_device_property_set_int (d, "ide_host.number", 0); /* XXX */ 177 178 devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler); 179 180 return (d); 181 } 182 183 static HalDevice * 184 devinfo_ide_device_add(HalDevice *parent, di_node_t node, char *devfs_path) 185 { 186 HalDevice *d; 187 188 d = hal_device_new(); 189 190 devinfo_set_default_properties (d, parent, node, devfs_path); 191 hal_device_property_set_string (parent, "info.product", "IDE device"); 192 hal_device_property_set_string (parent, "info.subsystem", "ide"); 193 hal_device_property_set_int (parent, "ide.host", 0); /* XXX */ 194 hal_device_property_set_int (parent, "ide.channel", 0); 195 196 devinfo_add_enqueue (d, devfs_path, &devinfo_ide_handler); 197 198 return (devinfo_ide_storage_add (d, node, devfs_path)); 199 } 200 201 static HalDevice * 202 devinfo_ide_storage_add(HalDevice *parent, di_node_t node, char *devfs_path) 203 { 204 HalDevice *d; 205 char *s; 206 int *i; 207 char *driver_name; 208 char udi[HAL_PATH_MAX]; 209 210 if ((driver_name = di_driver_name (node)) == NULL) { 211 return (NULL); 212 } 213 214 d = hal_device_new (); 215 216 devinfo_set_default_properties (d, parent, node, devfs_path); 217 hal_device_property_set_string (d, "info.category", "storage"); 218 219 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 220 "%s/%s%d", hal_device_get_udi (parent), driver_name, di_instance (node)); 221 hal_device_set_udi (d, udi); 222 hal_device_property_set_string (d, "info.udi", udi); 223 PROP_STR(d, node, s, "devid", "info.product"); 224 225 hal_device_add_capability (d, "storage"); 226 hal_device_property_set_string (d, "storage.bus", "ide"); 227 hal_device_property_set_int (d, "storage.lun", 0); 228 hal_device_property_set_string (d, "storage.drive_type", "disk"); 229 230 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable"); 231 PROP_BOOL(d, node, i, "removable-media", "storage.removable"); 232 233 hal_device_property_set_bool (d, "storage.media_check_enabled", FALSE); 234 235 /* XXX */ 236 hal_device_property_set_bool (d, "storage.requires_eject", FALSE); 237 238 hal_device_add_capability (d, "block"); 239 240 devinfo_storage_minors (d, node, (char *)devfs_path, FALSE); 241 242 return (d); 243 } 244 245 /* SCSI */ 246 247 HalDevice * 248 devinfo_scsi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 249 { 250 int *i; 251 char *driver_name; 252 HalDevice *d; 253 char udi[HAL_PATH_MAX]; 254 255 driver_name = di_driver_name (node); 256 if ((driver_name == NULL) || (strcmp (driver_name, "sd") != 0)) { 257 return (NULL); 258 } 259 260 d = hal_device_new (); 261 262 devinfo_set_default_properties (d, parent, node, devfs_path); 263 hal_device_property_set_string (d, "info.subsystem", "scsi"); 264 265 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 266 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node)); 267 hal_device_set_udi (d, udi); 268 hal_device_property_set_string (d, "info.udi", udi); 269 270 hal_device_property_set_int (d, "scsi.host", 271 hal_device_property_get_int (parent, "scsi_host.host")); 272 hal_device_property_set_int (d, "scsi.bus", 0); 273 PROP_INT(d, node, i, "target", "scsi.target"); 274 PROP_INT(d, node, i, "lun", "scsi.lun"); 275 hal_device_property_set_string (d, "info.product", "SCSI Device"); 276 277 devinfo_add_enqueue (d, devfs_path, &devinfo_scsi_handler); 278 279 return (devinfo_scsi_storage_add (d, node, devfs_path)); 280 } 281 282 static HalDevice * 283 devinfo_scsi_storage_add(HalDevice *parent, di_node_t node, char *devfs_path) 284 { 285 HalDevice *d; 286 int *i; 287 char *s; 288 char udi[HAL_PATH_MAX]; 289 290 d = hal_device_new (); 291 292 devinfo_set_default_properties (d, parent, node, devfs_path); 293 hal_device_property_set_string (d, "info.category", "storage"); 294 295 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 296 "%s/sd%d", hal_device_get_udi (parent), di_instance (node)); 297 hal_device_set_udi (d, udi); 298 hal_device_property_set_string (d, "info.udi", udi); 299 PROP_STR(d, node, s, "inquiry-product-id", "info.product"); 300 301 hal_device_add_capability (d, "storage"); 302 303 hal_device_property_set_int (d, "storage.lun", 304 hal_device_property_get_int (parent, "scsi.lun")); 305 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable"); 306 PROP_BOOL(d, node, i, "removable-media", "storage.removable"); 307 hal_device_property_set_bool (d, "storage.requires_eject", FALSE); 308 309 /* 310 * We have to enable polling not only for drives with removable media, 311 * but also for hotpluggable devices, because when a disk is 312 * unplugged while busy/mounted, there is not sysevent generated. 313 * Instead, the HBA driver (scsa2usb, scsa1394) will notify sd driver 314 * and the latter will report DKIO_DEV_GONE via DKIOCSTATE ioctl. 315 * So we have to enable media check so that hald-addon-storage notices 316 * the "device gone" condition and unmounts all associated volumes. 317 */ 318 hal_device_property_set_bool (d, "storage.media_check_enabled", 319 ((di_prop_lookup_ints(DDI_DEV_T_ANY, node, "removable-media", &i) >= 0) || 320 (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "hotpluggable", &i) >= 0))); 321 322 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "inquiry-device-type", 323 &i) > 0) { 324 s = devinfo_scsi_dtype2str (*i); 325 hal_device_property_set_string (d, "storage.drive_type", s); 326 327 if (strcmp (s, "cdrom") == 0) { 328 hal_device_add_capability (d, "storage.cdrom"); 329 hal_device_property_set_bool (d, "storage.no_partitions_hint", TRUE); 330 hal_device_property_set_bool (d, "storage.requires_eject", TRUE); 331 } 332 } 333 334 hal_device_add_capability (d, "block"); 335 336 devinfo_storage_minors (d, node, devfs_path, FALSE); 337 338 return (d); 339 } 340 341 static char * 342 devinfo_scsi_dtype2str(int dtype) 343 { 344 char *dtype2str[] = { 345 "disk" , /* DTYPE_DIRECT 0x00 */ 346 "tape" , /* DTYPE_SEQUENTIAL 0x01 */ 347 "printer", /* DTYPE_PRINTER 0x02 */ 348 "processor", /* DTYPE_PROCESSOR 0x03 */ 349 "worm" , /* DTYPE_WORM 0x04 */ 350 "cdrom" , /* DTYPE_RODIRECT 0x05 */ 351 "scanner", /* DTYPE_SCANNER 0x06 */ 352 "cdrom" , /* DTYPE_OPTICAL 0x07 */ 353 "changer", /* DTYPE_CHANGER 0x08 */ 354 "comm" , /* DTYPE_COMM 0x09 */ 355 "scsi" , /* DTYPE_??? 0x0A */ 356 "scsi" , /* DTYPE_??? 0x0B */ 357 "array_ctrl", /* DTYPE_ARRAY_CTRL 0x0C */ 358 "esi" , /* DTYPE_ESI 0x0D */ 359 "disk" /* DTYPE_RBC 0x0E */ 360 }; 361 362 if (dtype < NELEM(dtype2str)) { 363 return (dtype2str[dtype]); 364 } else { 365 return ("scsi"); 366 } 367 368 } 369 370 /* blkdev */ 371 372 HalDevice * 373 devinfo_blkdev_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 374 { 375 int *i; 376 char *driver_name; 377 HalDevice *d; 378 char udi[HAL_PATH_MAX]; 379 380 driver_name = di_driver_name (node); 381 if ((driver_name == NULL) || (strcmp (driver_name, "blkdev") != 0)) { 382 return (NULL); 383 } 384 385 d = hal_device_new (); 386 387 devinfo_set_default_properties (d, parent, node, devfs_path); 388 hal_device_property_set_string (d, "info.subsystem", "pseudo"); 389 390 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 391 "%s/%s%d", hal_device_get_udi (parent), di_node_name(node), di_instance (node)); 392 hal_device_set_udi (d, udi); 393 hal_device_property_set_string (d, "info.udi", udi); 394 hal_device_property_set_string (d, "info.product", "Block Device"); 395 396 devinfo_add_enqueue (d, devfs_path, &devinfo_blkdev_handler); 397 398 return (devinfo_blkdev_storage_add (d, node, devfs_path)); 399 } 400 401 static HalDevice * 402 devinfo_blkdev_storage_add(HalDevice *parent, di_node_t node, char *devfs_path) 403 { 404 HalDevice *d; 405 char *driver_name; 406 int *i; 407 char *s; 408 char udi[HAL_PATH_MAX]; 409 410 d = hal_device_new (); 411 412 devinfo_set_default_properties (d, parent, node, devfs_path); 413 hal_device_property_set_string (d, "info.category", "storage"); 414 415 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 416 "%s/blkdev%d", hal_device_get_udi (parent), di_instance (node)); 417 hal_device_set_udi (d, udi); 418 hal_device_property_set_string (d, "info.udi", udi); 419 420 hal_device_add_capability (d, "storage"); 421 422 hal_device_property_set_int (d, "storage.lun", 0); 423 424 PROP_BOOL(d, node, i, "hotpluggable", "storage.hotpluggable"); 425 PROP_BOOL(d, node, i, "removable-media", "storage.removable"); 426 427 hal_device_property_set_bool (d, "storage.requires_eject", FALSE); 428 hal_device_property_set_bool (d, "storage.media_check_enabled", TRUE); 429 hal_device_property_set_string (d, "storage.drive_type", "disk"); 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 *devlink = NULL; 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.subsystem", "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 ("pNN") + 1); 707 if (doslink != NULL) { 708 for (i = 1; i < 16; i++) { 709 snprintf(dospath, sizeof (dospath), "p%d", i); 710 sprintf(doslink, "%sp%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 m = devinfo_storage_new_minor(minor_path, slice, devlink, dev, -1); 864 if (m == NULL) { 865 free (devlink); 866 di_devfs_path_free (minor_path); 867 continue; 868 } 869 870 /* main device is either s2/p0 or d0, the latter taking precedence */ 871 if ((strcmp (slice, "d0") == 0) || 872 (((strcmp (slice, whole_disk) == 0) && (maindev == NULL)))) { 873 if (maindev_path != NULL) { 874 di_devfs_path_free (maindev_path); 875 } 876 maindev_path = minor_path; 877 maindev = m; 878 g_queue_push_head (mq, maindev); 879 } else { 880 di_devfs_path_free (minor_path); 881 g_queue_push_tail (mq, m); 882 } 883 884 free (devlink); 885 } 886 di_devlink_fini (&devlink_hdl); 887 888 if (maindev == NULL) { 889 /* shouldn't typically happen */ 890 while (!g_queue_is_empty (mq)) { 891 devinfo_storage_free_minor (g_queue_pop_head (mq)); 892 } 893 goto err; 894 } 895 896 /* first enqueue main storage device */ 897 if (!rescan) { 898 hal_device_property_set_int (parent, "block.major", major); 899 hal_device_property_set_int (parent, "block.minor", minor(maindev->dev)); 900 hal_device_property_set_string (parent, "block.device", maindev->devlink); 901 raw = dsk_to_rdsk (maindev->devlink); 902 hal_device_property_set_string (parent, "block.solaris.raw_device", raw); 903 free (raw); 904 hal_device_property_set_bool (parent, "block.is_volume", FALSE); 905 hal_device_property_set_string (parent, "solaris.devfs_path", maindev_path); 906 devinfo_add_enqueue (parent, maindev_path, &devinfo_storage_handler); 907 } 908 909 /* add virtual dos volumes to enable pcfs probing */ 910 if (!is_cdrom) { 911 doslink_len = strlen (maindev->devlink) + sizeof ("pNN") + 1; 912 if ((doslink = (char *)calloc (1, doslink_len)) != NULL) { 913 for (i = 1; i < 16; i++) { 914 snprintf(dospath, sizeof (dospath), "%sp%d", maindev->slice, i); 915 snprintf(doslink, doslink_len, "%sp%d", maindev->devlink, i); 916 m = devinfo_storage_new_minor(maindev_path, dospath, doslink, maindev->dev, i); 917 g_queue_push_tail (mq, m); 918 } 919 free (doslink); 920 } 921 } 922 923 maindev_is_d0 = (strcmp (maindev->slice, "d0") == 0); 924 925 /* enqueue all volumes */ 926 while (!g_queue_is_empty (mq)) { 927 m = g_queue_pop_head (mq); 928 929 /* if main device is d0, we'll throw away s2/p0 */ 930 if (maindev_is_d0 && (strcmp (m->slice, whole_disk) == 0)) { 931 devinfo_storage_free_minor (m); 932 continue; 933 } 934 /* don't do p0 on cdrom */ 935 if (is_cdrom && (strcmp (m->slice, "p0") == 0)) { 936 devinfo_storage_free_minor (m); 937 continue; 938 } 939 if (rescan) { 940 /* in rescan mode, don't reprobe existing volumes */ 941 /* XXX detect volume removal? */ 942 volume = hal_device_store_match_key_value_string (hald_get_gdl (), 943 "solaris.devfs_path", m->devpath); 944 if ((volume == NULL) || !hal_device_has_capability(volume, "volume")) { 945 devinfo_volume_add (parent, node, m); 946 } else { 947 HAL_INFO(("rescan volume exists %s", m->devpath)); 948 } 949 } else { 950 devinfo_volume_add (parent, node, m); 951 } 952 devinfo_storage_free_minor (m); 953 } 954 955 if (maindev_path != NULL) { 956 di_devfs_path_free (maindev_path); 957 } 958 959 return; 960 961 err: 962 if (maindev_path != NULL) { 963 di_devfs_path_free (maindev_path); 964 } 965 if (!rescan) { 966 devinfo_add_enqueue (parent, devfs_path, &devinfo_storage_handler); 967 } 968 } 969 970 HalDevice * 971 devinfo_volume_add(HalDevice *parent, di_node_t node, devinfo_storage_minor_t *m) 972 { 973 HalDevice *d; 974 char *raw; 975 char udi[HAL_PATH_MAX]; 976 char *devfs_path = m->devpath; 977 char *devlink = m->devlink; 978 dev_t dev = m->dev; 979 int dosnum = m->dosnum; 980 char *slice = m->slice; 981 982 HAL_INFO (("volume_add: devfs_path=%s devlink=%s", devfs_path, devlink)); 983 d = hal_device_new (); 984 985 devinfo_set_default_properties (d, parent, node, devfs_path); 986 hal_device_property_set_string (d, "info.category", "volume"); 987 988 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 989 "%s/%s", hal_device_get_udi (parent), slice); 990 hal_device_set_udi (d, udi); 991 hal_device_property_set_string (d, "info.udi", udi); 992 hal_device_property_set_string (d, "info.product", slice); 993 994 hal_device_add_capability (d, "volume"); 995 hal_device_add_capability (d, "block"); 996 hal_device_property_set_int (d, "block.major", major (dev)); 997 hal_device_property_set_int (d, "block.minor", minor (dev)); 998 hal_device_property_set_string (d, "block.device", devlink); 999 raw = dsk_to_rdsk (devlink); 1000 hal_device_property_set_string (d, "block.solaris.raw_device", raw); 1001 free (raw); 1002 hal_device_property_set_string (d, "block.solaris.slice", slice); 1003 hal_device_property_set_bool (d, "block.is_volume", TRUE); /* XXX */ 1004 1005 hal_device_property_set_string (d, "block.storage_device", hal_device_get_udi (parent)); 1006 1007 /* set volume defaults */ 1008 hal_device_property_set_string (d, "volume.fstype", ""); 1009 hal_device_property_set_string (d, "volume.fsusage", ""); 1010 hal_device_property_set_string (d, "volume.fsversion", ""); 1011 hal_device_property_set_string (d, "volume.uuid", ""); 1012 hal_device_property_set_string (d, "volume.label", ""); 1013 hal_device_property_set_string (d, "volume.mount_point", ""); 1014 hal_device_property_set_bool (d, "volume.is_mounted", FALSE); 1015 if (strcmp (hal_device_property_get_string (parent, "storage.drive_type"), "cdrom") == 0) { 1016 hal_device_property_set_bool (d, "volume.is_disc", TRUE); 1017 hal_device_add_capability (d, "volume.disc"); 1018 } else { 1019 hal_device_property_set_bool (d, "volume.is_disc", FALSE); 1020 } 1021 1022 if (dosnum > 0) { 1023 hal_device_property_set_bool (d, "volume.is_partition", TRUE); 1024 hal_device_property_set_int (d, "volume.partition.number", dosnum); 1025 } else { 1026 hal_device_property_set_bool (d, "volume.is_partition", FALSE); 1027 } 1028 1029 /* prober may override these */ 1030 hal_device_property_set_int (d, "volume.block_size", 512); 1031 1032 devinfo_add_enqueue (d, devfs_path, &devinfo_volume_handler); 1033 1034 return (d); 1035 } 1036 1037 static void 1038 devinfo_volume_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 1039 { 1040 void *end_token = (void *) userdata1; 1041 char *whole_disk; 1042 char *block_device; 1043 const char *storage_udi; 1044 HalDevice *storage_d; 1045 const char *slice; 1046 int dos_num; 1047 1048 if (hal_device_property_get_bool (d, "info.ignore")) { 1049 HAL_INFO (("Preprobing merged info.ignore==TRUE %s", hal_device_get_udi (d))); 1050 goto skip; 1051 } 1052 1053 /* 1054 * Optimizations: only probe if there's a chance to find something 1055 */ 1056 block_device = (char *)hal_device_property_get_string (d, "block.device"); 1057 storage_udi = hal_device_property_get_string (d, "block.storage_device"); 1058 slice = hal_device_property_get_string(d, "block.solaris.slice"); 1059 if ((block_device == NULL) || (storage_udi == NULL) || 1060 (slice == NULL) || (strlen (slice) < 2)) { 1061 HAL_INFO (("Malformed volume properties %s", hal_device_get_udi (d))); 1062 goto skip; 1063 } 1064 storage_d = hal_device_store_match_key_value_string (hald_get_gdl (), "info.udi", storage_udi); 1065 if (storage_d == NULL) { 1066 HAL_INFO (("Storage device not found %s", hal_device_get_udi (d))); 1067 goto skip; 1068 } 1069 1070 whole_disk = hal_device_has_capability (storage_d, 1071 "storage.cdrom") ? "s2" : WHOLE_DISK; 1072 1073 if (is_dos_path(block_device, &dos_num)) { 1074 /* don't probe more dos volumes than probe-storage found */ 1075 if ((hal_device_property_get_bool (storage_d, "storage.no_partitions_hint") || 1076 (dos_num > hal_device_property_get_int (storage_d, "storage.solaris.num_dos_partitions")))) { 1077 HAL_INFO (("%d > %d %s", dos_num, hal_device_property_get_int (storage_d, 1078 "storage.solaris.num_dos_partitions"), hal_device_get_udi (storage_d))); 1079 goto skip; 1080 } 1081 } else { 1082 /* if no VTOC slices found, don't probe slices except s2 */ 1083 if ((slice[0] == 's') && (isdigit(slice[1])) && ((strcmp (slice, whole_disk)) != 0) && 1084 !hal_device_property_get_bool (storage_d, "storage.solaris.vtoc_slices")) { 1085 HAL_INFO (("Not probing slice %s", hal_device_get_udi (d))); 1086 goto skip; 1087 } 1088 } 1089 1090 HAL_INFO(("Probing udi=%s", hal_device_get_udi (d))); 1091 hald_runner_run (d, 1092 "hald-probe-volume", NULL, 1093 DEVINFO_PROBE_VOLUME_TIMEOUT, 1094 devinfo_callouts_probing_done, 1095 (gpointer) end_token, userdata2); 1096 1097 return; 1098 1099 skip: 1100 hal_device_store_remove (hald_get_tdl (), d); 1101 g_object_unref (d); 1102 hotplug_event_end (end_token); 1103 } 1104 1105 static void 1106 devinfo_volume_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 1107 { 1108 HAL_INFO(("Preprobing volume udi=%s", hal_device_get_udi (d))); 1109 1110 if (parent == NULL) { 1111 HAL_INFO (("no parent %s", hal_device_get_udi (d))); 1112 goto skip; 1113 } 1114 1115 if (hal_device_property_get_bool (parent, "info.ignore")) { 1116 HAL_INFO (("Ignoring volume: parent's info.ignore is TRUE")); 1117 goto skip; 1118 } 1119 1120 /* add to TDL so preprobing callouts and prober can access it */ 1121 hal_device_store_add (hald_get_tdl (), d); 1122 1123 /* Process preprobe fdi files */ 1124 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 1125 1126 /* Run preprobe callouts */ 1127 hal_util_callout_device_preprobe (d, devinfo_volume_preprobing_done, end_token, handler); 1128 1129 return; 1130 1131 skip: 1132 g_object_unref (d); 1133 hotplug_event_end (end_token); 1134 } 1135 1136 void 1137 devinfo_storage_hotplug_begin_add (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 1138 { 1139 const char *drive_type; 1140 const char *p_udi; 1141 HalDevice *p_d; 1142 HalDevice *phys_d = NULL; 1143 const char *phys_bus; 1144 const char *bus; 1145 static const char *busses[] = { "usb", "ide", "scsi", "ieee1394", 1146 "pseudo" }; 1147 int i; 1148 1149 HAL_INFO (("Preprobing udi=%s", hal_device_get_udi (d))); 1150 1151 if (parent == NULL) { 1152 HAL_INFO (("no parent %s", hal_device_get_udi (d))); 1153 goto error; 1154 } 1155 1156 /* 1157 * figure out physical device and bus, except for floppy 1158 */ 1159 drive_type = hal_device_property_get_string (d, "storage.drive_type"); 1160 if ((drive_type != NULL) && (strcmp (drive_type, "floppy") == 0)) { 1161 goto skip_bus; 1162 } 1163 1164 p_d = parent; 1165 for (;;) { 1166 bus = hal_device_property_get_string (p_d, "info.subsystem"); 1167 if (bus != NULL) { 1168 for (i = 0; i < NELEM(busses); i++) { 1169 if (strcmp(bus, busses[i]) == 0) { 1170 phys_d = p_d; 1171 phys_bus = busses[i]; 1172 break; 1173 } 1174 } 1175 } 1176 /* up the tree */ 1177 p_udi = hal_device_property_get_string (p_d, "info.parent"); 1178 if (p_udi == NULL) { 1179 break; 1180 } 1181 p_d = hal_device_store_find (hald_get_gdl (), p_udi); 1182 } 1183 if (phys_d == NULL) { 1184 HAL_INFO (("no physical device %s", hal_device_get_udi (d))); 1185 } else { 1186 hal_device_property_set_string (d, "storage.physical_device", hal_device_get_udi (phys_d)); 1187 hal_device_property_set_string (d, "storage.bus", phys_bus); 1188 } 1189 1190 skip_bus: 1191 1192 /* add to TDL so preprobing callouts and prober can access it */ 1193 hal_device_store_add (hald_get_tdl (), d); 1194 1195 /* Process preprobe fdi files */ 1196 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 1197 1198 /* Run preprobe callouts */ 1199 hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 1200 1201 return; 1202 1203 error: 1204 g_object_unref (d); 1205 hotplug_event_end (end_token); 1206 } 1207 1208 static void 1209 devinfo_storage_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 1210 { 1211 void *end_token = (void *) userdata1; 1212 1213 HAL_INFO (("devinfo_storage_probing_done %s", hal_device_get_udi (d))); 1214 1215 /* Discard device if probing reports failure */ 1216 if (exit_type != HALD_RUN_SUCCESS || return_code != 0) { 1217 HAL_INFO (("devinfo_storage_probing_done returning exit_type=%d return_code=%d", exit_type, return_code)); 1218 hal_device_store_remove (hald_get_tdl (), d); 1219 g_object_unref (d); 1220 hotplug_event_end (end_token); 1221 return; 1222 } 1223 1224 devinfo_storage_set_nicknames (d); 1225 1226 /* Merge properties from .fdi files */ 1227 di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 1228 di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 1229 1230 hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 1231 } 1232 1233 const gchar * 1234 devinfo_storage_get_prober (HalDevice *d, int *timeout) 1235 { 1236 *timeout = DEVINFO_PROBE_STORAGE_TIMEOUT; 1237 return "hald-probe-storage"; 1238 } 1239 1240 const gchar * 1241 devinfo_volume_get_prober (HalDevice *d, int *timeout) 1242 { 1243 *timeout = DEVINFO_PROBE_VOLUME_TIMEOUT; 1244 return "hald-probe-volume"; 1245 } 1246 1247 /* 1248 * After reprobing storage, reprobe its volumes. 1249 */ 1250 static void 1251 devinfo_storage_rescan_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 1252 { 1253 void *end_token = (void *) userdata1; 1254 const char *devfs_path_orig = NULL; 1255 char *devfs_path = NULL; 1256 char *p; 1257 di_node_t node; 1258 1259 HAL_INFO (("devinfo_storage_rescan_probing_done %s", hal_device_get_udi (d))); 1260 1261 devfs_path_orig = hal_device_property_get_string (d, "solaris.devfs_path"); 1262 if (devfs_path_orig == NULL) { 1263 HAL_INFO (("device has no solaris.devfs_path")); 1264 hotplug_event_process_queue (); 1265 return; 1266 } 1267 1268 /* strip trailing minor part if any */ 1269 if (strrchr(devfs_path_orig, ':') != NULL) { 1270 if ((devfs_path = strdup (devfs_path_orig)) != NULL) { 1271 p = strrchr(devfs_path, ':'); 1272 *p = '\0'; 1273 } 1274 } else { 1275 devfs_path = (char *)devfs_path_orig; 1276 } 1277 1278 if ((node = di_init (devfs_path, DINFOCPYALL)) == DI_NODE_NIL) { 1279 HAL_INFO (("di_init %s failed %d %s", devfs_path, errno, hal_device_get_udi (d))); 1280 hotplug_event_process_queue (); 1281 return; 1282 } else { 1283 devinfo_storage_minors (d, node, (char *)devfs_path, TRUE); 1284 di_fini (node); 1285 } 1286 1287 if (devfs_path != devfs_path_orig) { 1288 free (devfs_path); 1289 } 1290 1291 hotplug_event_process_queue (); 1292 } 1293 1294 /* 1295 * For removable media devices, check for "storage.removable.media_available". 1296 * For non-removable media devices, assume media is always there. 1297 * 1298 * If media is gone, enqueue remove events for all children volumes. 1299 * If media is there, first reprobe storage, then probe for new volumes (but leave existing volumes alone). 1300 */ 1301 gboolean 1302 devinfo_storage_device_rescan (HalDevice *d) 1303 { 1304 GSList *i; 1305 GSList *volumes; 1306 HalDevice *v; 1307 gchar *v_devfs_path; 1308 const char *drive_type; 1309 gboolean is_floppy; 1310 gboolean media_available; 1311 1312 HAL_INFO (("devinfo_storage_device_rescan udi=%s", hal_device_get_udi (d))); 1313 1314 if (hal_device_property_get_bool (d, "block.is_volume")) { 1315 HAL_INFO (("nothing to do for volume")); 1316 return (FALSE); 1317 } 1318 1319 drive_type = hal_device_property_get_string (d, "storage.drive_type"); 1320 is_floppy = (drive_type != NULL) && (strcmp (drive_type, "floppy") == 0); 1321 1322 media_available = !hal_device_property_get_bool (d, "storage.removable") || 1323 hal_device_property_get_bool (d, "storage.removable.media_available"); 1324 1325 if (!media_available && !is_floppy) { 1326 HAL_INFO (("media gone %s", hal_device_get_udi (d))); 1327 1328 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 1329 "block.storage_device", hal_device_get_udi (d)); 1330 for (i = volumes; i != NULL; i = g_slist_next (i)) { 1331 v = HAL_DEVICE (i->data); 1332 v_devfs_path = (gchar *)hal_device_property_get_string (v, "solaris.devfs_path"); 1333 HAL_INFO (("child volume %s", hal_device_get_udi (v))); 1334 if ((v_devfs_path != NULL) && hal_device_has_capability (v, "volume")) { 1335 HAL_INFO (("removing volume %s", hal_device_get_udi (v))); 1336 devinfo_remove_enqueue (v_devfs_path, NULL); 1337 } else { 1338 HAL_INFO (("not a volume %s", hal_device_get_udi (v))); 1339 } 1340 } 1341 g_slist_free (volumes); 1342 1343 hotplug_event_process_queue (); 1344 } else if (is_floppy) { 1345 HAL_INFO (("rescanning floppy %s", hal_device_get_udi (d))); 1346 1347 hald_runner_run (d, 1348 "hald-probe-storage --only-check-for-media", NULL, 1349 DEVINFO_PROBE_STORAGE_TIMEOUT, 1350 devinfo_floppy_rescan_probing_done, 1351 NULL, NULL); 1352 } else { 1353 HAL_INFO (("media available %s", hal_device_get_udi (d))); 1354 1355 hald_runner_run (d, 1356 "hald-probe-storage --only-check-for-media", NULL, 1357 DEVINFO_PROBE_STORAGE_TIMEOUT, 1358 devinfo_storage_rescan_probing_done, 1359 NULL, NULL); 1360 } 1361 1362 return TRUE; 1363 } 1364 1365 static char * 1366 devinfo_volume_get_slice_name (char *devlink) 1367 { 1368 char *part, *slice, *disk; 1369 char *s = NULL; 1370 char *p; 1371 1372 if ((p = strstr(devlink, "/lofi/")) != 0) { 1373 return (p + sizeof ("/lofi/") - 1); 1374 } 1375 1376 part = strrchr(devlink, 'p'); 1377 slice = strrchr(devlink, 's'); 1378 disk = strrchr(devlink, 'd'); 1379 1380 if ((part != NULL) && (part > slice) && (part > disk)) { 1381 s = part; 1382 } else if ((slice != NULL) && (slice > disk)) { 1383 s = slice; 1384 } else { 1385 s = disk; 1386 } 1387 if ((s != NULL) && isdigit(s[1])) { 1388 return (s); 1389 } else { 1390 return (""); 1391 } 1392 } 1393 1394 static gboolean 1395 is_dos_path(char *path, int *partnum) 1396 { 1397 char *p; 1398 1399 if ((p = strrchr (path, 'p')) == NULL) { 1400 return (FALSE); 1401 } 1402 return ((*partnum = atoi(p + 1)) != 0); 1403 } 1404 1405 static gboolean 1406 dos_to_dev(char *path, char **devpath, int *partnum) 1407 { 1408 char *p; 1409 1410 if ((p = strrchr (path, 'p')) == NULL) { 1411 return (FALSE); 1412 } 1413 if ((*partnum = atoi(p + 1)) == 0) { 1414 return (FALSE); 1415 } 1416 p[0] = '\0'; 1417 *devpath = strdup(path); 1418 p[0] = 'p'; 1419 return (*devpath != NULL); 1420 } 1421 1422 static void 1423 devinfo_storage_cleanup_mountpoint_cb (HalDevice *d, guint32 exit_type, 1424 gint return_code, gchar **error, 1425 gpointer data1, gpointer data2) 1426 { 1427 char *mount_point = (char *) data1; 1428 1429 HAL_INFO (("Cleaned up mount point '%s'", mount_point)); 1430 g_free (mount_point); 1431 } 1432 1433 1434 void 1435 devinfo_storage_mnttab_event (HalDevice *hal_volume) 1436 { 1437 FILE *fp = NULL; 1438 struct extmnttab m; 1439 HalDevice *d; 1440 unsigned int major; 1441 unsigned int minor; 1442 GSList *volumes = NULL; 1443 GSList *v; 1444 char *mount_point; 1445 dbus_bool_t is_partition; 1446 const char *fstype; 1447 int partition_number; 1448 1449 if (hal_volume != NULL) { 1450 volumes = g_slist_append (NULL, hal_volume); 1451 } else { 1452 volumes = hal_device_store_match_multiple_key_value_string (hald_get_gdl (), "info.category", "volume"); 1453 } 1454 if (volumes == NULL) { 1455 return; 1456 } 1457 1458 if ((fp = fopen(MNTTAB, "r")) == NULL) { 1459 HAL_ERROR (("Open failed %s errno %d", MNTTAB, errno)); 1460 return; 1461 } 1462 1463 while (getextmntent(fp, &m, 1) == 0) { 1464 for (v = volumes; v != NULL; v = g_slist_next (v)) { 1465 d = HAL_DEVICE (v->data); 1466 major = hal_device_property_get_int (d, "block.major"); 1467 minor = hal_device_property_get_int (d, "block.minor"); 1468 1469 /* 1470 * special handling for pcfs, which encodes logical 1471 * drive number into the 6 upper bits of the minor 1472 */ 1473 is_partition = hal_device_property_get_bool (d, "volume.is_partition"); 1474 partition_number = hal_device_property_get_int (d, "volume.partition.number"); 1475 fstype = hal_device_property_get_string (d, "volume.fstype"); 1476 1477 if (is_partition && (partition_number > 0) && (strcmp (fstype, "pcfs") == 0)) { 1478 minor |= partition_number << 12; 1479 } 1480 1481 if (m.mnt_major != major || m.mnt_minor != minor) { 1482 continue; 1483 } 1484 1485 /* this volume matches the mnttab entry */ 1486 device_property_atomic_update_begin (); 1487 hal_device_property_set_bool (d, "volume.is_mounted", TRUE); 1488 hal_device_property_set_bool (d, "volume.is_mounted_read_only", 1489 hasmntopt ((struct mnttab *)&m, "ro") ? TRUE : FALSE); 1490 hal_device_property_set_string (d, "volume.mount_point", m.mnt_mountp); 1491 device_property_atomic_update_end (); 1492 1493 HAL_INFO (("set %s to be mounted at %s", 1494 hal_device_get_udi (d), m.mnt_mountp)); 1495 volumes = g_slist_delete_link (volumes, v); 1496 } 1497 } 1498 1499 /* all remaining volumes are not mounted */ 1500 for (v = volumes; v != NULL; v = g_slist_next (v)) { 1501 d = HAL_DEVICE (v->data); 1502 mount_point = g_strdup (hal_device_property_get_string (d, "volume.mount_point")); 1503 if (mount_point == NULL || strlen (mount_point) == 0) { 1504 g_free (mount_point); 1505 continue; 1506 } 1507 1508 device_property_atomic_update_begin (); 1509 hal_device_property_set_bool (d, "volume.is_mounted", FALSE); 1510 hal_device_property_set_bool (d, "volume.is_mounted_read_only", FALSE); 1511 hal_device_property_set_string (d, "volume.mount_point", ""); 1512 device_property_atomic_update_end (); 1513 1514 HAL_INFO (("set %s to unmounted", hal_device_get_udi (d))); 1515 1516 /* cleanup if was mounted by us */ 1517 if (hal_util_is_mounted_by_hald (mount_point)) { 1518 char *cleanup_stdin; 1519 char *extra_env[2]; 1520 1521 HAL_INFO (("Cleaning up '%s'", mount_point)); 1522 1523 extra_env[0] = g_strdup_printf ("HALD_CLEANUP=%s", mount_point); 1524 extra_env[1] = NULL; 1525 cleanup_stdin = "\n"; 1526 1527 hald_runner_run_method (d, 1528 "hal-storage-cleanup-mountpoint", 1529 extra_env, 1530 cleanup_stdin, TRUE, 1531 0, 1532 devinfo_storage_cleanup_mountpoint_cb, 1533 g_strdup (mount_point), NULL); 1534 1535 g_free (extra_env[0]); 1536 } 1537 1538 g_free (mount_point); 1539 } 1540 g_slist_free (volumes); 1541 1542 (void) fclose (fp); 1543 } 1544 1545 static void 1546 devinfo_volume_force_unmount_cb (HalDevice *d, guint32 exit_type, 1547 gint return_code, gchar **error, 1548 gpointer data1, gpointer data2) 1549 { 1550 void *end_token = (void *) data1; 1551 1552 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)); 1553 1554 if (exit_type == HALD_RUN_SUCCESS && error != NULL && 1555 error[0] != NULL && error[1] != NULL) { 1556 char *exp_name = NULL; 1557 char *exp_detail = NULL; 1558 1559 exp_name = error[0]; 1560 if (error[0] != NULL) { 1561 exp_detail = error[1]; 1562 } 1563 HAL_INFO (("failed with '%s' '%s'", exp_name, exp_detail)); 1564 } 1565 1566 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 1567 } 1568 1569 static void 1570 devinfo_volume_force_unmount (HalDevice *d, void *end_token) 1571 { 1572 const char *device_file; 1573 const char *mount_point; 1574 char *unmount_stdin; 1575 char *extra_env[2]; 1576 extra_env[0] = "HAL_METHOD_INVOKED_BY_UID=0"; 1577 extra_env[1] = NULL; 1578 1579 device_file = hal_device_property_get_string (d, "block.device"); 1580 mount_point = hal_device_property_get_string (d, "volume.mount_point"); 1581 1582 if (mount_point == NULL || strlen (mount_point) == 0 || !hal_util_is_mounted_by_hald (mount_point)) { 1583 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 1584 return; 1585 } 1586 1587 HAL_INFO (("devinfo_volume_force_unmount for udi='%s'", hal_device_get_udi (d))); 1588 1589 unmount_stdin = "\n"; 1590 1591 hald_runner_run_method (d, 1592 "hal-storage-unmount", 1593 extra_env, 1594 unmount_stdin, 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 }