1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <fcntl.h> 30 #include <libdevinfo.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <dirent.h> 35 #include <sys/dkio.h> 36 #include <sys/stat.h> 37 #include <sys/sunddi.h> 38 #include <sys/types.h> 39 #include <sys/vtoc.h> 40 #include <unistd.h> 41 #include <devid.h> 42 #include <dirent.h> 43 #include <sys/dktp/fdisk.h> 44 #include <sys/efi_partition.h> 45 46 #include "libdiskmgt.h" 47 #include "disks_private.h" 48 #include "partition.h" 49 #ifndef VT_ENOTSUP 50 #define VT_ENOTSUP (-5) 51 #endif 52 53 #define FMT_UNKNOWN 0 54 #define FMT_VTOC 1 55 #define FMT_EFI 2 56 57 static struct inuse_detectors { 58 int (*detectorp)(char *slice, nvlist_t *attrs, int *errp); 59 char *used_by; 60 } detectors[] = { 61 {inuse_mnt, DM_USE_MOUNT}, 62 {inuse_svm, DM_USE_SVM}, 63 {inuse_zpool, DM_USE_ZPOOL}, 64 {inuse_lu, DM_USE_LU}, 65 {inuse_dump, DM_USE_DUMP}, 66 {inuse_vxvm, DM_USE_VXVM}, 67 {inuse_fs, DM_USE_FS}, /* fs should always be last */ 68 {NULL, NULL} 69 }; 70 71 static int add_inuse(char *name, nvlist_t *attrs); 72 static int desc_ok(descriptor_t *dp); 73 static void dsk2rdsk(char *dsk, char *rdsk, int size); 74 static int get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs); 75 static descriptor_t **get_fixed_assocs(descriptor_t *desc, int *errp); 76 static descriptor_t **get_removable_assocs(descriptor_t *desc, char *volm_path, 77 int *errp); 78 static int get_slice_num(slice_t *devp); 79 static int match_fixed_name(disk_t *dp, char *name, int *errp); 80 static int match_removable_name(disk_t *dp, char *name, int *errp); 81 static int make_fixed_descriptors(disk_t *dp); 82 static int make_removable_descriptors(disk_t *dp); 83 static int make_volm_dir_descriptors(disk_t *dp, int fd, 84 char *volm_path); 85 static int num_removable_slices(int fd, struct stat *bufp, 86 char *volm_path); 87 88 descriptor_t ** 89 slice_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, 90 int *errp) 91 { 92 if (!desc_ok(desc)) { 93 *errp = ENODEV; 94 return (NULL); 95 } 96 97 switch (type) { 98 case DM_MEDIA: 99 return (media_get_assocs(desc, errp)); 100 case DM_PARTITION: 101 return (partition_get_assocs(desc, errp)); 102 } 103 104 *errp = EINVAL; 105 return (NULL); 106 } 107 108 /* 109 * This is called by media/partition to get the slice descriptors for the given 110 * media/partition descriptor. 111 * For media, just get the slices, but for a partition, it must be a solaris 112 * partition and if there are active partitions, it must be the active one. 113 */ 114 descriptor_t ** 115 slice_get_assocs(descriptor_t *desc, int *errp) 116 { 117 int under_volm = 0; 118 char volm_path[MAXPATHLEN]; 119 120 /* Just check the first drive name. */ 121 if (desc->p.disk->aliases == NULL) { 122 *errp = 0; 123 return (libdiskmgt_empty_desc_array(errp)); 124 } 125 126 if (desc->p.disk->removable) { 127 if ((under_volm = media_get_volm_path(desc->p.disk, volm_path, 128 sizeof (volm_path)))) { 129 if (volm_path[0] == 0) { 130 /* no media */ 131 *errp = 0; 132 return (libdiskmgt_empty_desc_array(errp)); 133 } 134 } 135 } 136 137 if (desc->p.disk->removable) { 138 if (under_volm) { 139 return (get_removable_assocs(desc, volm_path, errp)); 140 } else { 141 return (get_fixed_assocs(desc, errp)); 142 } 143 } else { 144 return (get_fixed_assocs(desc, errp)); 145 } 146 } 147 148 nvlist_t * 149 slice_get_attributes(descriptor_t *dp, int *errp) 150 { 151 nvlist_t *attrs = NULL; 152 int fd; 153 char devpath[MAXPATHLEN]; 154 155 if (!desc_ok(dp)) { 156 *errp = ENODEV; 157 return (NULL); 158 } 159 160 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) { 161 *errp = ENOMEM; 162 return (NULL); 163 } 164 165 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */ 166 dsk2rdsk(dp->name, devpath, sizeof (devpath)); 167 fd = open(devpath, O_RDONLY|O_NDELAY); 168 169 if ((*errp = get_attrs(dp, fd, attrs)) != 0) { 170 nvlist_free(attrs); 171 attrs = NULL; 172 } 173 174 if (fd >= 0) { 175 (void) close(fd); 176 } 177 178 return (attrs); 179 } 180 181 /* 182 * Look for the slice by the slice devpath. 183 */ 184 descriptor_t * 185 slice_get_descriptor_by_name(char *name, int *errp) 186 { 187 int found = 0; 188 disk_t *dp; 189 190 for (dp = cache_get_disklist(); dp != NULL; dp = dp->next) { 191 if (dp->removable) { 192 found = match_removable_name(dp, name, errp); 193 } else { 194 found = match_fixed_name(dp, name, errp); 195 } 196 197 if (found) { 198 char mname[MAXPATHLEN]; 199 200 if (*errp != 0) { 201 return (NULL); 202 } 203 204 mname[0] = 0; 205 (void) media_read_name(dp, mname, sizeof (mname)); 206 207 return (cache_get_desc(DM_SLICE, dp, name, mname, errp)); 208 } 209 } 210 211 *errp = ENODEV; 212 return (NULL); 213 } 214 215 /* ARGSUSED */ 216 descriptor_t ** 217 slice_get_descriptors(int filter[], int *errp) 218 { 219 return (cache_get_descriptors(DM_SLICE, errp)); 220 } 221 222 char * 223 slice_get_name(descriptor_t *desc) 224 { 225 return (desc->name); 226 } 227 228 nvlist_t * 229 slice_get_stats(descriptor_t *dp, int stat_type, int *errp) 230 { 231 nvlist_t *stats; 232 char *str; 233 234 if (stat_type != DM_SLICE_STAT_USE) { 235 *errp = EINVAL; 236 return (NULL); 237 } 238 239 *errp = 0; 240 241 if (nvlist_alloc(&stats, NVATTRS_STAT, 0) != 0) { 242 *errp = ENOMEM; 243 return (NULL); 244 } 245 246 if ((*errp = add_inuse(dp->name, stats)) != 0) { 247 return (NULL); 248 } 249 250 /* if no cluster use, check for a use of the local name */ 251 if (nvlist_lookup_string(stats, DM_USED_BY, &str) != 0) { 252 disk_t *diskp; 253 254 diskp = dp->p.disk; 255 if (diskp->aliases != NULL && diskp->aliases->cluster) { 256 slice_t *sp; 257 int snum = -1; 258 struct dk_minfo minfo; 259 struct dk_cinfo dkinfo; 260 char devpath[MAXPATHLEN]; 261 int fd; 262 263 /* dp->name is /dev/dsk, need to convert back to /dev/rdsk */ 264 dsk2rdsk(dp->name, devpath, sizeof (devpath)); 265 fd = open(devpath, O_RDONLY|O_NDELAY); 266 267 if (fd >= 0 && media_read_info(fd, &minfo) && 268 ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { 269 snum = dkinfo.dki_partition; 270 } 271 272 if (fd >= 0) { 273 (void) close(fd); 274 } 275 276 if (snum >= 0) { 277 for (sp = diskp->aliases->orig_paths; sp != NULL; 278 sp = sp->next) { 279 280 if (sp->slice_num == snum) { 281 char localpath[MAXPATHLEN]; 282 283 slice_rdsk2dsk(sp->devpath, localpath, 284 sizeof (localpath)); 285 286 if ((*errp = add_inuse(localpath, stats)) != 0) { 287 return (NULL); 288 } 289 290 break; 291 } 292 } 293 } 294 } 295 } 296 297 return (stats); 298 } 299 300 /* 301 * A slice descriptor points to a disk, the name is the devpath and the 302 * secondary name is the media name. 303 */ 304 int 305 slice_make_descriptors() 306 { 307 disk_t *dp; 308 309 dp = cache_get_disklist(); 310 while (dp != NULL) { 311 int error; 312 313 if (dp->removable) { 314 error = make_removable_descriptors(dp); 315 } else { 316 error = make_fixed_descriptors(dp); 317 } 318 if (error != 0) { 319 return (error); 320 } 321 322 dp = dp->next; 323 } 324 325 return (0); 326 } 327 328 /* convert rdsk paths to dsk paths */ 329 void 330 slice_rdsk2dsk(char *rdsk, char *dsk, int size) 331 { 332 char *strp; 333 334 (void) strlcpy(dsk, rdsk, size); 335 336 if ((strp = strstr(dsk, "/rdsk/")) == NULL) { 337 /* not rdsk, check for floppy */ 338 strp = strstr(dsk, "/rdiskette"); 339 } 340 341 if (strp != NULL) { 342 strp++; /* move ptr to the r in rdsk or rdiskette */ 343 344 /* move the succeeding chars over by one */ 345 do { 346 *strp = *(strp + 1); 347 strp++; 348 } while (*strp); 349 } 350 } 351 352 /* 353 * Check if/how the slice is used. 354 */ 355 static int 356 add_inuse(char *name, nvlist_t *attrs) 357 { 358 int i; 359 int error; 360 361 for (i = 0; detectors[i].detectorp != NULL; i ++) { 362 if ((detectors[i].detectorp)(name, attrs, &error) || error != 0) { 363 if (error != 0) { 364 return (error); 365 } 366 break; 367 } 368 } 369 370 return (0); 371 } 372 373 /* return 1 if the slice descriptor is still valid, 0 if not. */ 374 static int 375 desc_ok(descriptor_t *dp) 376 { 377 /* First verify the media name for removable media */ 378 if (dp->p.disk->removable) { 379 char mname[MAXPATHLEN]; 380 381 if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { 382 return (0); 383 } 384 385 if (mname[0] == 0) { 386 return (libdiskmgt_str_eq(dp->secondary_name, NULL)); 387 } else { 388 return (libdiskmgt_str_eq(dp->secondary_name, mname)); 389 } 390 } 391 392 /* 393 * We could verify the slice is still there, but other code down the 394 * line already does these checks (e.g. see get_attrs). 395 */ 396 397 return (1); 398 } 399 400 /* convert dsk paths to rdsk paths */ 401 static void 402 dsk2rdsk(char *dsk, char *rdsk, int size) 403 { 404 char *slashp; 405 size_t len; 406 407 (void) strlcpy(rdsk, dsk, size); 408 409 /* make sure there is enough room to add the r to dsk */ 410 len = strlen(dsk); 411 if (len + 2 > size) { 412 return; 413 } 414 415 if ((slashp = strstr(rdsk, "/dsk/")) == NULL) { 416 /* not dsk, check for floppy */ 417 slashp = strstr(rdsk, "/diskette"); 418 } 419 420 if (slashp != NULL) { 421 char *endp; 422 423 endp = rdsk + len; /* point to terminating 0 */ 424 /* move the succeeding chars over by one */ 425 do { 426 *(endp + 1) = *endp; 427 endp--; 428 } while (endp != slashp); 429 430 *(endp + 1) = 'r'; 431 } 432 } 433 434 static int 435 get_attrs(descriptor_t *dp, int fd, nvlist_t *attrs) 436 { 437 struct dk_minfo minfo; 438 int status; 439 int data_format = FMT_UNKNOWN; 440 int snum = -1; 441 int error; 442 struct vtoc vtoc; 443 struct dk_gpt *efip; 444 struct dk_cinfo dkinfo; 445 disk_t *diskp; 446 char localpath[MAXPATHLEN]; 447 int cooked_fd; 448 struct stat buf; 449 int mntpnt = 0; 450 451 if (fd < 0) { 452 return (ENODEV); 453 } 454 455 /* First make sure media is inserted and spun up. */ 456 if (!media_read_info(fd, &minfo)) { 457 return (ENODEV); 458 } 459 460 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 461 data_format = FMT_VTOC; 462 } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { 463 data_format = FMT_EFI; 464 if (nvlist_add_boolean(attrs, DM_EFI) != 0) { 465 efi_free(efip); 466 return (ENOMEM); 467 } 468 } 469 470 if (data_format == FMT_UNKNOWN) { 471 return (ENODEV); 472 } 473 474 if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { 475 snum = dkinfo.dki_partition; 476 } 477 478 /* check the slice */ 479 if (data_format == FMT_VTOC) { 480 if (snum < 0 || snum >= vtoc.v_nparts || 481 vtoc.v_part[snum].p_size == 0) { 482 return (ENODEV); 483 } 484 } else { /* data_format == FMT_EFI */ 485 if (snum < 0 || snum >= efip->efi_nparts || 486 efip->efi_parts[snum].p_size == 0) { 487 efi_free(efip); 488 return (ENODEV); 489 } 490 } 491 492 /* the slice exists */ 493 494 if (nvlist_add_uint32(attrs, DM_INDEX, snum) != 0) { 495 if (data_format == FMT_EFI) { 496 efi_free(efip); 497 } 498 return (ENOMEM); 499 } 500 501 if (data_format == FMT_VTOC) { 502 if (nvlist_add_uint64(attrs, DM_START, vtoc.v_part[snum].p_start) 503 != 0) { 504 return (ENOMEM); 505 } 506 507 if (nvlist_add_uint64(attrs, DM_SIZE, vtoc.v_part[snum].p_size) 508 != 0) { 509 return (ENOMEM); 510 } 511 512 if (nvlist_add_uint32(attrs, DM_TAG, vtoc.v_part[snum].p_tag) 513 != 0) { 514 return (ENOMEM); 515 } 516 517 if (nvlist_add_uint32(attrs, DM_FLAG, vtoc.v_part[snum].p_flag) 518 != 0) { 519 return (ENOMEM); 520 } 521 522 } else { /* data_format == FMT_EFI */ 523 if (nvlist_add_uint64(attrs, DM_START, 524 efip->efi_parts[snum].p_start) != 0) { 525 efi_free(efip); 526 return (ENOMEM); 527 } 528 529 if (nvlist_add_uint64(attrs, DM_SIZE, efip->efi_parts[snum].p_size) 530 != 0) { 531 efi_free(efip); 532 return (ENOMEM); 533 } 534 535 if (efip->efi_parts[snum].p_name[0] != 0) { 536 char label[EFI_PART_NAME_LEN + 1]; 537 538 (void) snprintf(label, sizeof (label), "%.*s", 539 EFI_PART_NAME_LEN, efip->efi_parts[snum].p_name); 540 if (nvlist_add_string(attrs, DM_EFI_NAME, label) != 0) { 541 efi_free(efip); 542 return (ENOMEM); 543 } 544 } 545 } 546 547 if (data_format == FMT_EFI) { 548 efi_free(efip); 549 } 550 551 if (inuse_mnt(dp->name, attrs, &error)) { 552 if (error != 0) { 553 return (error); 554 } 555 mntpnt = 1; 556 } 557 558 /* 559 * Some extra attrs for cluster slices. 560 * 561 * get localname and possible mnt point for localpath 562 */ 563 localpath[0] = 0; 564 diskp = dp->p.disk; 565 if (diskp->aliases != NULL && diskp->aliases->cluster) { 566 slice_t *sp; 567 568 for (sp = diskp->aliases->orig_paths; sp != NULL; sp = sp->next) { 569 if (sp->slice_num == -1) { 570 /* determine the slice number for this path */ 571 int sfd; 572 struct dk_cinfo dkinfo; 573 574 if ((sfd = open(sp->devpath, O_RDONLY|O_NDELAY)) >= 0) { 575 if (ioctl(sfd, DKIOCINFO, &dkinfo) >= 0) { 576 sp->slice_num = dkinfo.dki_partition; 577 } 578 (void) close(sfd); 579 } 580 } 581 582 if (sp->slice_num == snum) { 583 slice_rdsk2dsk(sp->devpath, localpath, sizeof (localpath)); 584 585 if (nvlist_add_string(attrs, DM_LOCALNAME, localpath) 586 != 0) { 587 return (ENOMEM); 588 } 589 590 if (mntpnt == 0) { 591 if (inuse_mnt(localpath, attrs, &error)) { 592 if (error != 0) { 593 return (error); 594 } 595 } 596 } 597 598 break; 599 } 600 } 601 } 602 603 if (fstat(fd, &buf) != -1) { 604 if (nvlist_add_uint64(attrs, DM_DEVT, buf.st_rdev) != 0) { 605 return (ENOMEM); 606 } 607 } 608 609 /* 610 * We need to open the cooked slice (not the raw one) to get the 611 * correct devid. Also see if we need to read the localpath for the 612 * cluster disk, since the minor name is unavailable for the did pseudo 613 * device. 614 */ 615 if (localpath[0] != 0) { 616 cooked_fd = open(localpath, O_RDONLY|O_NDELAY); 617 } else { 618 cooked_fd = open(dp->name, O_RDONLY|O_NDELAY); 619 } 620 621 if (cooked_fd >= 0) { 622 int no_mem = 0; 623 ddi_devid_t devid; 624 625 if (devid_get(cooked_fd, &devid) == 0) { 626 char *minor; 627 628 if (devid_get_minor_name(cooked_fd, &minor) == 0) { 629 char *devidstr; 630 631 if ((devidstr = devid_str_encode(devid, minor)) != 0) { 632 633 if (nvlist_add_string(attrs, DM_DEVICEID, devidstr) 634 != 0) { 635 no_mem = 1; 636 } 637 638 devid_str_free(devidstr); 639 } 640 devid_str_free(minor); 641 } 642 devid_free(devid); 643 } 644 (void) close(cooked_fd); 645 646 if (no_mem) { 647 return (ENOMEM); 648 } 649 } 650 651 return (0); 652 } 653 654 static descriptor_t ** 655 get_fixed_assocs(descriptor_t *desc, int *errp) 656 { 657 int fd; 658 int status; 659 int data_format = FMT_UNKNOWN; 660 int cnt; 661 struct vtoc vtoc; 662 struct dk_gpt *efip; 663 int pos; 664 char *media_name = NULL; 665 slice_t *devp; 666 descriptor_t **slices; 667 668 if ((fd = drive_open_disk(desc->p.disk, NULL, 0)) < 0) { 669 *errp = ENODEV; 670 return (NULL); 671 } 672 673 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 674 data_format = FMT_VTOC; 675 } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { 676 data_format = FMT_EFI; 677 } else { 678 (void) close(fd); 679 *errp = 0; 680 return (libdiskmgt_empty_desc_array(errp)); 681 } 682 (void) close(fd); 683 684 /* count the number of slices */ 685 for (cnt = 0, devp = desc->p.disk->aliases->devpaths; devp != NULL; 686 devp = devp->next, cnt++); 687 688 /* allocate the array for the descriptors */ 689 slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 690 if (slices == NULL) { 691 if (data_format == FMT_EFI) { 692 efi_free(efip); 693 } 694 *errp = ENOMEM; 695 return (NULL); 696 } 697 698 /* get the media name from the descriptor */ 699 if (desc->type == DM_MEDIA) { 700 media_name = desc->name; 701 } else { 702 /* must be a DM_PARTITION */ 703 media_name = desc->secondary_name; 704 } 705 706 pos = 0; 707 for (devp = desc->p.disk->aliases->devpaths; devp != NULL; 708 devp = devp->next) { 709 710 int slice_num; 711 char devpath[MAXPATHLEN]; 712 713 slice_num = get_slice_num(devp); 714 /* can't get slicenum, so no need to keep trying the drive */ 715 if (slice_num == -1) { 716 break; 717 } 718 719 if (data_format == FMT_VTOC) { 720 if (slice_num >= vtoc.v_nparts || 721 vtoc.v_part[slice_num].p_size == 0) { 722 continue; 723 } 724 } else { /* data_format == FMT_EFI */ 725 if (slice_num >= efip->efi_nparts || 726 efip->efi_parts[slice_num].p_size == 0) { 727 continue; 728 } 729 } 730 731 slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); 732 slices[pos] = cache_get_desc(DM_SLICE, desc->p.disk, devpath, 733 media_name, errp); 734 if (*errp != 0) { 735 cache_free_descriptors(slices); 736 if (data_format == FMT_EFI) { 737 efi_free(efip); 738 } 739 return (NULL); 740 } 741 pos++; 742 } 743 slices[pos] = NULL; 744 745 if (data_format == FMT_EFI) { 746 efi_free(efip); 747 } 748 749 *errp = 0; 750 return (slices); 751 } 752 753 /* 754 * Called for loaded removable media under volume management control. 755 */ 756 static descriptor_t ** 757 get_removable_assocs(descriptor_t *desc, char *volm_path, int *errp) 758 { 759 int pos; 760 int fd; 761 int cnt; 762 struct stat buf; 763 descriptor_t **slices; 764 char *media_name = NULL; 765 char devpath[MAXPATHLEN]; 766 767 /* get the media name from the descriptor */ 768 if (desc->type == DM_MEDIA) { 769 media_name = desc->name; 770 } else { 771 /* must be a DM_PARTITION */ 772 media_name = desc->secondary_name; 773 } 774 775 /* 776 * For removable media under volm control the volm_path will 777 * either be a device (if the media is made up of a single slice) or 778 * a directory (if the media has multiple slices) with the slices 779 * as devices contained in the directory. 780 */ 781 782 if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) < 0 || 783 fstat(fd, &buf) != 0) { 784 *errp = ENODEV; 785 return (NULL); 786 } 787 788 cnt = num_removable_slices(fd, &buf, volm_path); 789 790 /* allocate the array for the descriptors */ 791 slices = (descriptor_t **)calloc(cnt + 1, sizeof (descriptor_t *)); 792 if (slices == NULL) { 793 *errp = ENOMEM; 794 return (NULL); 795 } 796 797 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 798 799 pos = 0; 800 *errp = 0; 801 if (buf.st_mode & S_IFCHR) { 802 struct dk_minfo minfo; 803 804 /* Make sure media has readable label */ 805 if (media_read_info(fd, &minfo)) { 806 int status; 807 int data_format = FMT_UNKNOWN; 808 struct vtoc vtoc; 809 struct dk_gpt *efip; 810 811 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 812 data_format = FMT_VTOC; 813 } else if (status == VT_ENOTSUP && 814 efi_alloc_and_read(fd, &efip) >= 0) { 815 data_format = FMT_EFI; 816 } 817 818 if (data_format != FMT_UNKNOWN) { 819 /* has a readable label */ 820 slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk, 821 devpath, media_name, errp); 822 } 823 } 824 825 } else if (buf.st_mode & S_IFDIR) { 826 DIR *dirp; 827 #ifdef _LP64 828 struct dirent *result; 829 #endif 830 831 /* rewind, num_removable_slices already traversed */ 832 (void) lseek(fd, 0, SEEK_SET); 833 834 if ((dirp = fdopendir(fd)) != NULL) { 835 struct dirent *dentp; 836 837 dentp = (struct dirent *)malloc(sizeof (struct dirent) + 838 PATH_MAX + 1); 839 if (dentp != NULL) { 840 #ifdef _LP64 841 while (readdir_r(dirp, dentp, &result) != NULL) { 842 #else 843 while (readdir_r(dirp, dentp) != NULL) { 844 #endif 845 int dfd; 846 int is_dev = 0; 847 char slice_path[MAXPATHLEN]; 848 849 if (libdiskmgt_str_eq(".", dentp->d_name) || 850 libdiskmgt_str_eq("..", dentp->d_name)) { 851 continue; 852 } 853 854 (void) snprintf(slice_path, sizeof (slice_path), 855 "%s/%s", devpath, dentp->d_name); 856 857 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 858 struct stat buf; 859 860 if (fstat(dfd, &buf) == 0 && 861 buf.st_mode & S_IFCHR) { 862 is_dev = 1; 863 } 864 (void) close(dfd); 865 } 866 867 if (!is_dev) { 868 continue; 869 } 870 871 slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk, 872 slice_path, media_name, errp); 873 if (*errp != 0) { 874 break; 875 } 876 877 } 878 free(dentp); 879 } 880 /* don't call closedir since it closes the fd */ 881 } 882 } 883 884 (void) close(fd); 885 886 slices[pos] = NULL; 887 888 if (*errp != 0) { 889 cache_free_descriptors(slices); 890 return (NULL); 891 } 892 893 return (slices); 894 } 895 896 static int 897 get_slice_num(slice_t *devp) 898 { 899 /* check if we already determined the devpath slice number */ 900 if (devp->slice_num == -1) { 901 int fd; 902 903 if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) { 904 struct dk_cinfo dkinfo; 905 if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { 906 devp->slice_num = dkinfo.dki_partition; 907 } 908 (void) close(fd); 909 } 910 } 911 912 return (devp->slice_num); 913 } 914 915 static int 916 make_fixed_descriptors(disk_t *dp) 917 { 918 int error = 0; 919 alias_t *ap; 920 slice_t *devp; 921 char mname[MAXPATHLEN]; 922 int data_format = FMT_UNKNOWN; 923 struct vtoc vtoc; 924 struct dk_gpt *efip; 925 926 /* Just check the first drive name. */ 927 if ((ap = dp->aliases) == NULL) { 928 return (0); 929 } 930 931 mname[0] = 0; 932 (void) media_read_name(dp, mname, sizeof (mname)); 933 934 for (devp = ap->devpaths; devp != NULL; devp = devp->next) { 935 int slice_num; 936 char devpath[MAXPATHLEN]; 937 938 slice_num = get_slice_num(devp); 939 /* can't get slicenum, so no need to keep trying the drive */ 940 if (slice_num == -1) { 941 break; 942 } 943 944 if (data_format == FMT_UNKNOWN) { 945 int fd; 946 int status; 947 948 if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { 949 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 950 data_format = FMT_VTOC; 951 } else if (status == VT_ENOTSUP && 952 efi_alloc_and_read(fd, &efip) >= 0) { 953 data_format = FMT_EFI; 954 } 955 (void) close(fd); 956 } 957 } 958 959 /* can't get slice data, so no need to keep trying the drive */ 960 if (data_format == FMT_UNKNOWN) { 961 break; 962 } 963 964 if (data_format == FMT_VTOC) { 965 if (slice_num >= vtoc.v_nparts || 966 vtoc.v_part[slice_num].p_size == 0) { 967 continue; 968 } 969 } else { /* data_format == FMT_EFI */ 970 if (slice_num >= efip->efi_nparts || 971 efip->efi_parts[slice_num].p_size == 0) { 972 continue; 973 } 974 } 975 976 slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); 977 cache_load_desc(DM_SLICE, dp, devpath, mname, &error); 978 if (error != 0) { 979 break; 980 } 981 } 982 983 if (data_format == FMT_EFI) { 984 efi_free(efip); 985 } 986 987 return (error); 988 } 989 990 /* 991 * For removable media under volm control we have to do some special handling. 992 * We don't use the vtoc and /dev/dsk devpaths, since the slices are named 993 * under the /vol fs. 994 */ 995 static int 996 make_removable_descriptors(disk_t *dp) 997 { 998 char volm_path[MAXPATHLEN]; 999 int error; 1000 int fd; 1001 1002 /* 1003 * If this removable drive is not under volm control, just use 1004 * normal handling. 1005 */ 1006 if (!media_get_volm_path(dp, volm_path, sizeof (volm_path))) { 1007 return (make_fixed_descriptors(dp)); 1008 } 1009 1010 if (volm_path[0] == 0) { 1011 /* no media */ 1012 return (0); 1013 } 1014 1015 /* 1016 * For removable media under volm control the rmmedia_devapth will 1017 * either be a device (if the media is made up of a single slice) or 1018 * a directory (if the media has multiple slices) with the slices 1019 * as devices contained in the directory. 1020 */ 1021 error = 0; 1022 if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0) { 1023 struct stat buf; 1024 1025 if (fstat(fd, &buf) == 0) { 1026 if (buf.st_mode & S_IFCHR) { 1027 int status; 1028 int data_format = FMT_UNKNOWN; 1029 struct dk_minfo minfo; 1030 int error; 1031 struct vtoc vtoc; 1032 struct dk_gpt *efip; 1033 char devpath[MAXPATHLEN]; 1034 1035 /* Make sure media has readable label */ 1036 if (!media_read_info(fd, &minfo)) { 1037 /* no media */ 1038 return (0); 1039 } 1040 1041 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 1042 data_format = FMT_VTOC; 1043 } else if (status == VT_ENOTSUP && 1044 efi_alloc_and_read(fd, &efip) >= 0) { 1045 data_format = FMT_EFI; 1046 } 1047 1048 if (data_format == FMT_UNKNOWN) { 1049 /* no readable label */ 1050 return (0); 1051 } 1052 1053 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1054 /* The media name is the volm_path in this case. */ 1055 cache_load_desc(DM_SLICE, dp, devpath, volm_path, &error); 1056 1057 } else if (buf.st_mode & S_IFDIR) { 1058 /* each device file in the dir represents a slice */ 1059 error = make_volm_dir_descriptors(dp, fd, volm_path); 1060 } 1061 } 1062 (void) close(fd); 1063 } 1064 1065 return (error); 1066 } 1067 1068 /* 1069 * This handles removable media with slices under volume management control. 1070 * In this case we have a dir which is the media name and each slice on the 1071 * media is a device file in this dir. 1072 */ 1073 static int 1074 make_volm_dir_descriptors(disk_t *dp, int dirfd, char *volm_path) 1075 { 1076 int error; 1077 DIR *dirp; 1078 struct dirent *dentp; 1079 #ifdef _LP64 1080 struct dirent *result; 1081 #endif 1082 char devpath[MAXPATHLEN]; 1083 1084 if ((dirp = fdopendir(dirfd)) == NULL) { 1085 return (0); 1086 } 1087 1088 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1089 1090 error = 0; 1091 dentp = (struct dirent *)malloc(sizeof (struct dirent) + 1092 PATH_MAX + 1); 1093 if (dentp != NULL) { 1094 #ifdef _LP64 1095 while (readdir_r(dirp, dentp, &result) != NULL) { 1096 #else 1097 while (readdir_r(dirp, dentp) != NULL) { 1098 #endif 1099 int fd; 1100 char slice_path[MAXPATHLEN]; 1101 1102 if (libdiskmgt_str_eq(".", dentp->d_name) || 1103 libdiskmgt_str_eq("..", dentp->d_name)) { 1104 continue; 1105 } 1106 1107 (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", 1108 devpath, dentp->d_name); 1109 1110 if ((fd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 1111 struct stat buf; 1112 1113 if (fstat(fd, &buf) == 0 && buf.st_mode & S_IFCHR) { 1114 /* The media name is the volm_path in this case. */ 1115 cache_load_desc(DM_SLICE, dp, slice_path, volm_path, 1116 &error); 1117 if (error != 0) { 1118 (void) close(fd); 1119 break; 1120 } 1121 } 1122 1123 (void) close(fd); 1124 } 1125 } 1126 free(dentp); 1127 } 1128 /* don't call closedir since it closes the fd */ 1129 1130 return (error); 1131 } 1132 1133 /* 1134 * Just look for the name on the devpaths we have cached. Return 1 if we 1135 * find the name and the size of that slice is non-zero. 1136 */ 1137 static int 1138 match_fixed_name(disk_t *diskp, char *name, int *errp) 1139 { 1140 slice_t *dp = NULL; 1141 alias_t *ap; 1142 int slice_num; 1143 int fd; 1144 int status; 1145 int data_format = FMT_UNKNOWN; 1146 struct vtoc vtoc; 1147 struct dk_gpt *efip; 1148 1149 ap = diskp->aliases; 1150 while (ap != NULL) { 1151 slice_t *devp; 1152 1153 devp = ap->devpaths; 1154 while (devp != NULL) { 1155 char path[MAXPATHLEN]; 1156 1157 slice_rdsk2dsk(devp->devpath, path, sizeof (path)); 1158 if (libdiskmgt_str_eq(path, name)) { 1159 /* found it */ 1160 dp = devp; 1161 break; 1162 } 1163 1164 devp = devp->next; 1165 } 1166 1167 if (dp != NULL) { 1168 break; 1169 } 1170 1171 ap = ap->next; 1172 } 1173 1174 if (dp == NULL) { 1175 *errp = 0; 1176 return (0); 1177 } 1178 1179 /* 1180 * If we found a match on the name we now have to check that this 1181 * slice really exists (non-0 size). 1182 */ 1183 1184 slice_num = get_slice_num(dp); 1185 /* can't get slicenum, so no slice */ 1186 if (slice_num == -1) { 1187 *errp = ENODEV; 1188 return (1); 1189 } 1190 1191 if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) { 1192 *errp = ENODEV; 1193 return (1); 1194 } 1195 1196 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 1197 data_format = FMT_VTOC; 1198 } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { 1199 data_format = FMT_EFI; 1200 } else { 1201 (void) close(fd); 1202 *errp = ENODEV; 1203 return (1); 1204 } 1205 (void) close(fd); 1206 1207 if (data_format == FMT_VTOC) { 1208 if (slice_num < vtoc.v_nparts && 1209 vtoc.v_part[slice_num].p_size > 0) { 1210 *errp = 0; 1211 return (1); 1212 } 1213 } else { /* data_format == FMT_EFI */ 1214 if (slice_num < efip->efi_nparts && 1215 efip->efi_parts[slice_num].p_size > 0) { 1216 efi_free(efip); 1217 *errp = 0; 1218 return (1); 1219 } 1220 efi_free(efip); 1221 } 1222 1223 *errp = ENODEV; 1224 return (1); 1225 } 1226 1227 static int 1228 match_removable_name(disk_t *diskp, char *name, int *errp) 1229 { 1230 char volm_path[MAXPATHLEN]; 1231 int found; 1232 int fd; 1233 struct stat buf; 1234 1235 /* 1236 * If this removable drive is not under volm control, just use 1237 * normal handling. 1238 */ 1239 if (!media_get_volm_path(diskp, volm_path, sizeof (volm_path))) { 1240 return (match_fixed_name(diskp, name, errp)); 1241 } 1242 1243 if (volm_path[0] == 0) { 1244 /* no media */ 1245 *errp = 0; 1246 return (0); 1247 } 1248 1249 /* 1250 * For removable media under volm control the rmmedia_devapth will 1251 * either be a device (if the media is made up of a single slice) or 1252 * a directory (if the media has multiple slices) with the slices 1253 * as devices contained in the directory. 1254 */ 1255 1256 *errp = 0; 1257 1258 found = 0; 1259 if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0 && 1260 fstat(fd, &buf) == 0) { 1261 1262 if (buf.st_mode & S_IFCHR) { 1263 char devpath[MAXPATHLEN]; 1264 1265 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1266 if (libdiskmgt_str_eq(name, devpath)) { 1267 found = 1; 1268 } 1269 1270 } else if (buf.st_mode & S_IFDIR) { 1271 /* each device file in the dir represents a slice */ 1272 DIR *dirp; 1273 1274 if ((dirp = fdopendir(fd)) != NULL) { 1275 struct dirent *dentp; 1276 #ifdef _LP64 1277 struct dirent *result; 1278 #endif 1279 char devpath[MAXPATHLEN]; 1280 1281 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1282 1283 dentp = (struct dirent *)malloc(sizeof (struct dirent) + 1284 PATH_MAX + 1); 1285 if (dentp != NULL) { 1286 #ifdef _LP64 1287 while (readdir_r(dirp, dentp, &result) != NULL) { 1288 #else 1289 while (readdir_r(dirp, dentp) != NULL) { 1290 #endif 1291 char slice_path[MAXPATHLEN]; 1292 1293 if (libdiskmgt_str_eq(".", dentp->d_name) || 1294 libdiskmgt_str_eq("..", dentp->d_name)) { 1295 continue; 1296 } 1297 1298 (void) snprintf(slice_path, sizeof (slice_path), 1299 "%s/%s", devpath, dentp->d_name); 1300 1301 if (libdiskmgt_str_eq(name, slice_path)) { 1302 /* found name, check device */ 1303 int dfd; 1304 int is_dev = 0; 1305 1306 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) 1307 >= 0) { 1308 struct stat buf; 1309 1310 if (fstat(dfd, &buf) == 0 && 1311 buf.st_mode & S_IFCHR) { 1312 is_dev = 1; 1313 } 1314 (void) close(dfd); 1315 } 1316 1317 /* we found the name */ 1318 found = 1; 1319 1320 if (!is_dev) { 1321 *errp = ENODEV; 1322 } 1323 1324 break; 1325 } 1326 } 1327 free(dentp); 1328 } 1329 /* don't call closedir since it closes the fd */ 1330 } 1331 } /* end of dir handling */ 1332 1333 (void) close(fd); 1334 } 1335 1336 return (found); 1337 } 1338 1339 static int 1340 num_removable_slices(int fd, struct stat *bufp, char *volm_path) 1341 { 1342 int cnt = 0; 1343 1344 if (bufp->st_mode & S_IFCHR) { 1345 cnt = 1; 1346 1347 } else if (bufp->st_mode & S_IFDIR) { 1348 /* each device file in the dir represents a slice */ 1349 DIR *dirp; 1350 1351 if ((dirp = fdopendir(fd)) != NULL) { 1352 struct dirent *dentp; 1353 #ifdef _LP64 1354 struct dirent *result; 1355 #endif 1356 char devpath[MAXPATHLEN]; 1357 1358 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1359 1360 dentp = (struct dirent *)malloc(sizeof (struct dirent) + 1361 PATH_MAX + 1); 1362 if (dentp != NULL) { 1363 #ifdef _LP64 1364 while (readdir_r(dirp, dentp, &result) != NULL) { 1365 #else 1366 while (readdir_r(dirp, dentp) != NULL) { 1367 #endif 1368 int dfd; 1369 char slice_path[MAXPATHLEN]; 1370 1371 if (libdiskmgt_str_eq(".", dentp->d_name) || 1372 libdiskmgt_str_eq("..", dentp->d_name)) { 1373 continue; 1374 } 1375 1376 (void) snprintf(slice_path, sizeof (slice_path), 1377 "%s/%s", devpath, dentp->d_name); 1378 1379 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 1380 struct stat buf; 1381 1382 if (fstat(dfd, &buf) == 0 && 1383 buf.st_mode & S_IFCHR) { 1384 cnt++; 1385 } 1386 (void) close(dfd); 1387 } 1388 } 1389 free(dentp); 1390 } 1391 /* don't call closedir since it closes the fd */ 1392 } 1393 } /* end of dir handling */ 1394 1395 return (cnt); 1396 } 1397