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