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 = 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 (S_ISCHR(buf.st_mode)) { 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++] = 821 cache_get_desc(DM_SLICE, desc->p.disk, 822 devpath, media_name, errp); 823 } 824 } 825 (void) close(fd); 826 } else if (S_ISDIR(buf.st_mode)) { 827 DIR *dirp; 828 struct dirent *dentp; 829 830 /* rewind, num_removable_slices already traversed */ 831 (void) lseek(fd, 0, SEEK_SET); 832 833 if ((dirp = fdopendir(fd)) == NULL) { 834 *errp = errno; 835 (void) close(fd); 836 return (NULL); 837 } 838 839 while ((dentp = readdir(dirp)) != NULL) { 840 int dfd; 841 int is_dev = 0; 842 char slice_path[MAXPATHLEN]; 843 844 if (libdiskmgt_str_eq(".", dentp->d_name) || 845 libdiskmgt_str_eq("..", dentp->d_name)) { 846 continue; 847 } 848 849 (void) snprintf(slice_path, sizeof (slice_path), 850 "%s/%s", devpath, dentp->d_name); 851 852 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 853 struct stat buf; 854 855 if (fstat(dfd, &buf) == 0 && 856 S_ISCHR(buf.st_mode)) { 857 is_dev = 1; 858 } 859 (void) close(dfd); 860 } 861 862 if (!is_dev) { 863 continue; 864 } 865 866 slices[pos++] = cache_get_desc(DM_SLICE, desc->p.disk, 867 slice_path, media_name, errp); 868 if (*errp != 0) { 869 break; 870 } 871 } 872 (void) closedir(dirp); 873 } else { 874 (void) close(fd); 875 } 876 877 slices[pos] = NULL; 878 879 if (*errp != 0) { 880 cache_free_descriptors(slices); 881 return (NULL); 882 } 883 884 return (slices); 885 } 886 887 static int 888 get_slice_num(slice_t *devp) 889 { 890 /* check if we already determined the devpath slice number */ 891 if (devp->slice_num == -1) { 892 int fd; 893 894 if ((fd = open(devp->devpath, O_RDONLY|O_NDELAY)) >= 0) { 895 struct dk_cinfo dkinfo; 896 if (ioctl(fd, DKIOCINFO, &dkinfo) >= 0) { 897 devp->slice_num = dkinfo.dki_partition; 898 } 899 (void) close(fd); 900 } 901 } 902 903 return (devp->slice_num); 904 } 905 906 static int 907 make_fixed_descriptors(disk_t *dp) 908 { 909 int error = 0; 910 alias_t *ap; 911 slice_t *devp; 912 char mname[MAXPATHLEN]; 913 int data_format = FMT_UNKNOWN; 914 struct vtoc vtoc; 915 struct dk_gpt *efip; 916 917 /* Just check the first drive name. */ 918 if ((ap = dp->aliases) == NULL) { 919 return (0); 920 } 921 922 mname[0] = 0; 923 (void) media_read_name(dp, mname, sizeof (mname)); 924 925 for (devp = ap->devpaths; devp != NULL; devp = devp->next) { 926 int slice_num; 927 char devpath[MAXPATHLEN]; 928 929 slice_num = get_slice_num(devp); 930 /* can't get slicenum, so no need to keep trying the drive */ 931 if (slice_num == -1) { 932 break; 933 } 934 935 if (data_format == FMT_UNKNOWN) { 936 int fd; 937 int status; 938 939 if ((fd = drive_open_disk(dp, NULL, 0)) >= 0) { 940 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 941 data_format = FMT_VTOC; 942 } else if (status == VT_ENOTSUP && 943 efi_alloc_and_read(fd, &efip) >= 0) { 944 data_format = FMT_EFI; 945 } 946 (void) close(fd); 947 } 948 } 949 950 /* can't get slice data, so no need to keep trying the drive */ 951 if (data_format == FMT_UNKNOWN) { 952 break; 953 } 954 955 if (data_format == FMT_VTOC) { 956 if (slice_num >= vtoc.v_nparts || 957 vtoc.v_part[slice_num].p_size == 0) { 958 continue; 959 } 960 } else { /* data_format == FMT_EFI */ 961 if (slice_num >= efip->efi_nparts || 962 efip->efi_parts[slice_num].p_size == 0) { 963 continue; 964 } 965 } 966 967 slice_rdsk2dsk(devp->devpath, devpath, sizeof (devpath)); 968 cache_load_desc(DM_SLICE, dp, devpath, mname, &error); 969 if (error != 0) { 970 break; 971 } 972 } 973 974 if (data_format == FMT_EFI) { 975 efi_free(efip); 976 } 977 978 return (error); 979 } 980 981 /* 982 * For removable media under volm control we have to do some special handling. 983 * We don't use the vtoc and /dev/dsk devpaths, since the slices are named 984 * under the /vol fs. 985 */ 986 static int 987 make_removable_descriptors(disk_t *dp) 988 { 989 char volm_path[MAXPATHLEN]; 990 int error; 991 int fd; 992 993 /* 994 * If this removable drive is not under volm control, just use 995 * normal handling. 996 */ 997 if (!media_get_volm_path(dp, volm_path, sizeof (volm_path))) { 998 return (make_fixed_descriptors(dp)); 999 } 1000 1001 if (volm_path[0] == 0) { 1002 /* no media */ 1003 return (0); 1004 } 1005 1006 /* 1007 * For removable media under volm control the rmmedia_devapth will 1008 * either be a device (if the media is made up of a single slice) or 1009 * a directory (if the media has multiple slices) with the slices 1010 * as devices contained in the directory. 1011 */ 1012 error = 0; 1013 if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) >= 0) { 1014 struct stat buf; 1015 1016 if (fstat(fd, &buf) == 0) { 1017 if (S_ISCHR(buf.st_mode)) { 1018 int status; 1019 int data_format = FMT_UNKNOWN; 1020 struct dk_minfo minfo; 1021 int error; 1022 struct vtoc vtoc; 1023 struct dk_gpt *efip; 1024 char devpath[MAXPATHLEN]; 1025 1026 /* Make sure media has readable label */ 1027 if (!media_read_info(fd, &minfo)) { 1028 /* no media */ 1029 return (0); 1030 } 1031 1032 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 1033 data_format = FMT_VTOC; 1034 } else if (status == VT_ENOTSUP && 1035 efi_alloc_and_read(fd, &efip) >= 0) { 1036 data_format = FMT_EFI; 1037 } 1038 1039 if (data_format == FMT_UNKNOWN) { 1040 /* no readable label */ 1041 return (0); 1042 } 1043 1044 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1045 /* The media name is the volm_path in this case. */ 1046 cache_load_desc(DM_SLICE, dp, devpath, volm_path, &error); 1047 1048 } else if (S_ISDIR(buf.st_mode)) { 1049 /* each device file in the dir represents a slice */ 1050 error = make_volm_dir_descriptors(dp, fd, volm_path); 1051 } 1052 } 1053 (void) close(fd); 1054 } 1055 1056 return (error); 1057 } 1058 1059 /* 1060 * This handles removable media with slices under volume management control. 1061 * In this case we have a dir which is the media name and each slice on the 1062 * media is a device file in this dir. 1063 */ 1064 static int 1065 make_volm_dir_descriptors(disk_t *dp, int dirfd, char *volm_path) 1066 { 1067 int error; 1068 DIR *dirp; 1069 struct dirent *dentp; 1070 char devpath[MAXPATHLEN]; 1071 1072 dirfd = dup(dirfd); 1073 if (dirfd < 0) 1074 return (0); 1075 if ((dirp = fdopendir(dirfd)) == NULL) { 1076 (void) close(dirfd); 1077 return (0); 1078 } 1079 1080 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1081 1082 error = 0; 1083 while ((dentp = readdir(dirp)) != NULL) { 1084 int fd; 1085 char slice_path[MAXPATHLEN]; 1086 1087 if (libdiskmgt_str_eq(".", dentp->d_name) || 1088 libdiskmgt_str_eq("..", dentp->d_name)) { 1089 continue; 1090 } 1091 1092 (void) snprintf(slice_path, sizeof (slice_path), "%s/%s", 1093 devpath, dentp->d_name); 1094 1095 if ((fd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 1096 struct stat buf; 1097 1098 /* The media name is the volm_path in this case. */ 1099 if (fstat(fd, &buf) == 0 && S_ISCHR(buf.st_mode)) { 1100 cache_load_desc(DM_SLICE, dp, slice_path, 1101 volm_path, &error); 1102 if (error != 0) { 1103 (void) close(fd); 1104 break; 1105 } 1106 } 1107 1108 (void) close(fd); 1109 } 1110 } 1111 (void) closedir(dirp); 1112 1113 return (error); 1114 } 1115 1116 /* 1117 * Just look for the name on the devpaths we have cached. Return 1 if we 1118 * find the name and the size of that slice is non-zero. 1119 */ 1120 static int 1121 match_fixed_name(disk_t *diskp, char *name, int *errp) 1122 { 1123 slice_t *dp = NULL; 1124 alias_t *ap; 1125 int slice_num; 1126 int fd; 1127 int status; 1128 int data_format = FMT_UNKNOWN; 1129 struct vtoc vtoc; 1130 struct dk_gpt *efip; 1131 1132 ap = diskp->aliases; 1133 while (ap != NULL) { 1134 slice_t *devp; 1135 1136 devp = ap->devpaths; 1137 while (devp != NULL) { 1138 char path[MAXPATHLEN]; 1139 1140 slice_rdsk2dsk(devp->devpath, path, sizeof (path)); 1141 if (libdiskmgt_str_eq(path, name)) { 1142 /* found it */ 1143 dp = devp; 1144 break; 1145 } 1146 1147 devp = devp->next; 1148 } 1149 1150 if (dp != NULL) { 1151 break; 1152 } 1153 1154 ap = ap->next; 1155 } 1156 1157 if (dp == NULL) { 1158 *errp = 0; 1159 return (0); 1160 } 1161 1162 /* 1163 * If we found a match on the name we now have to check that this 1164 * slice really exists (non-0 size). 1165 */ 1166 1167 slice_num = get_slice_num(dp); 1168 /* can't get slicenum, so no slice */ 1169 if (slice_num == -1) { 1170 *errp = ENODEV; 1171 return (1); 1172 } 1173 1174 if ((fd = drive_open_disk(diskp, NULL, 0)) < 0) { 1175 *errp = ENODEV; 1176 return (1); 1177 } 1178 1179 if ((status = read_vtoc(fd, &vtoc)) >= 0) { 1180 data_format = FMT_VTOC; 1181 } else if (status == VT_ENOTSUP && efi_alloc_and_read(fd, &efip) >= 0) { 1182 data_format = FMT_EFI; 1183 } else { 1184 (void) close(fd); 1185 *errp = ENODEV; 1186 return (1); 1187 } 1188 (void) close(fd); 1189 1190 if (data_format == FMT_VTOC) { 1191 if (slice_num < vtoc.v_nparts && 1192 vtoc.v_part[slice_num].p_size > 0) { 1193 *errp = 0; 1194 return (1); 1195 } 1196 } else { /* data_format == FMT_EFI */ 1197 if (slice_num < efip->efi_nparts && 1198 efip->efi_parts[slice_num].p_size > 0) { 1199 efi_free(efip); 1200 *errp = 0; 1201 return (1); 1202 } 1203 efi_free(efip); 1204 } 1205 1206 *errp = ENODEV; 1207 return (1); 1208 } 1209 1210 static int 1211 match_removable_name(disk_t *diskp, char *name, int *errp) 1212 { 1213 char volm_path[MAXPATHLEN]; 1214 int found; 1215 int fd; 1216 struct stat buf; 1217 1218 /* 1219 * If this removable drive is not under volm control, just use 1220 * normal handling. 1221 */ 1222 if (!media_get_volm_path(diskp, volm_path, sizeof (volm_path))) { 1223 return (match_fixed_name(diskp, name, errp)); 1224 } 1225 1226 if (volm_path[0] == 0) { 1227 /* no media */ 1228 *errp = 0; 1229 return (0); 1230 } 1231 1232 /* 1233 * For removable media under volm control the rmmedia_devapth will 1234 * either be a device (if the media is made up of a single slice) or 1235 * a directory (if the media has multiple slices) with the slices 1236 * as devices contained in the directory. 1237 */ 1238 1239 *errp = 0; 1240 1241 if ((fd = open(volm_path, O_RDONLY|O_NDELAY)) == -1 || 1242 fstat(fd, &buf) != 0) { 1243 return (0); 1244 } 1245 1246 found = 0; 1247 1248 if (S_ISCHR(buf.st_mode)) { 1249 char devpath[MAXPATHLEN]; 1250 1251 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1252 if (libdiskmgt_str_eq(name, devpath)) { 1253 found = 1; 1254 } 1255 (void) close(fd); 1256 return (found); 1257 } else if (S_ISDIR(buf.st_mode)) { 1258 /* each device file in the dir represents a slice */ 1259 DIR *dirp; 1260 struct dirent *dentp; 1261 char devpath[MAXPATHLEN]; 1262 1263 if ((dirp = fdopendir(fd)) == NULL) { 1264 (void) close(fd); 1265 return (0); 1266 } 1267 1268 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1269 1270 while ((dentp = readdir(dirp)) != NULL) { 1271 char slice_path[MAXPATHLEN]; 1272 1273 if (libdiskmgt_str_eq(".", dentp->d_name) || 1274 libdiskmgt_str_eq("..", dentp->d_name)) { 1275 continue; 1276 } 1277 1278 (void) snprintf(slice_path, sizeof (slice_path), 1279 "%s/%s", devpath, dentp->d_name); 1280 1281 if (libdiskmgt_str_eq(name, slice_path)) { 1282 /* found name, check device */ 1283 int dfd; 1284 int is_dev = 0; 1285 1286 dfd = open(slice_path, O_RDONLY|O_NDELAY); 1287 if (dfd >= 0) { 1288 struct stat buf; 1289 1290 if (fstat(dfd, &buf) == 0 && 1291 S_ISCHR(buf.st_mode)) { 1292 is_dev = 1; 1293 } 1294 (void) close(dfd); 1295 } 1296 1297 /* we found the name */ 1298 found = 1; 1299 1300 if (!is_dev) { 1301 *errp = ENODEV; 1302 } 1303 1304 break; 1305 } 1306 } 1307 (void) closedir(dirp); 1308 } else { 1309 (void) close(fd); 1310 } 1311 1312 return (found); 1313 } 1314 1315 static int 1316 num_removable_slices(int fd, struct stat *bufp, char *volm_path) 1317 { 1318 int cnt = 0; 1319 1320 if (S_ISCHR(bufp->st_mode)) 1321 return (1); 1322 1323 if (S_ISDIR(bufp->st_mode)) { 1324 /* each device file in the dir represents a slice */ 1325 DIR *dirp; 1326 struct dirent *dentp; 1327 char devpath[MAXPATHLEN]; 1328 1329 fd = dup(fd); 1330 1331 if (fd < 0) 1332 return (0); 1333 1334 if ((dirp = fdopendir(fd)) == NULL) { 1335 (void) close(fd); 1336 return (0); 1337 } 1338 1339 slice_rdsk2dsk(volm_path, devpath, sizeof (devpath)); 1340 1341 while ((dentp = readdir(dirp)) != NULL) { 1342 int dfd; 1343 char slice_path[MAXPATHLEN]; 1344 1345 if (libdiskmgt_str_eq(".", dentp->d_name) || 1346 libdiskmgt_str_eq("..", dentp->d_name)) { 1347 continue; 1348 } 1349 1350 (void) snprintf(slice_path, sizeof (slice_path), 1351 "%s/%s", devpath, dentp->d_name); 1352 1353 if ((dfd = open(slice_path, O_RDONLY|O_NDELAY)) >= 0) { 1354 struct stat buf; 1355 1356 if (fstat(dfd, &buf) == 0 && 1357 S_ISCHR(buf.st_mode)) { 1358 cnt++; 1359 } 1360 (void) close(dfd); 1361 } 1362 } 1363 (void) closedir(dirp); 1364 } 1365 return (cnt); 1366 } 1367