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