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