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