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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <fcntl.h> 27 #include <libdevinfo.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <sys/sunddi.h> 32 #include <sys/types.h> 33 #include <sys/stat.h> 34 #include <dirent.h> 35 #include <unistd.h> 36 #include <sys/dkio.h> 37 38 #if defined(i386) || defined(__amd64) 39 #include <sys/dktp/fdisk.h> 40 #include <libfdisk.h> 41 #endif 42 43 #include "libdiskmgt.h" 44 #include "disks_private.h" 45 #include "partition.h" 46 47 #ifdef sparc 48 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF)) 49 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \ 50 (les((unsigned)((val)&0xffff0000)>>16))) 51 #else 52 #define les(val) (val) 53 #define lel(val) (val) 54 #endif 55 56 #define TOTAL_NUMPART (FD_NUMPART + MAX_EXT_PARTS) 57 58 #define ISIZE FD_NUMPART * sizeof (struct ipart) 59 60 static int desc_ok(descriptor_t *dp); 61 static int get_attrs(descriptor_t *dp, struct ipart *iparts, 62 nvlist_t *attrs); 63 static int get_parts(disk_t *disk, struct ipart *iparts, char *opath, 64 int opath_len); 65 static int open_disk(disk_t *diskp, char *opath, int len); 66 static int has_slices(descriptor_t *desc, int *errp); 67 68 descriptor_t ** 69 partition_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, 70 int *errp) 71 { 72 if (!desc_ok(desc)) { 73 *errp = ENODEV; 74 return (NULL); 75 } 76 77 switch (type) { 78 case DM_MEDIA: 79 return (media_get_assocs(desc, errp)); 80 case DM_SLICE: 81 if (!has_slices(desc, errp)) { 82 if (*errp != 0) { 83 return (NULL); 84 } 85 return (libdiskmgt_empty_desc_array(errp)); 86 } 87 return (slice_get_assocs(desc, errp)); 88 } 89 90 *errp = EINVAL; 91 return (NULL); 92 } 93 94 /* 95 * This is called by media/slice to get the associated partitions. 96 * For a media desc. we just get all the partitions, but for a slice desc. 97 * we just get the active solaris partition. 98 */ 99 descriptor_t ** 100 partition_get_assocs(descriptor_t *desc, int *errp) 101 { 102 descriptor_t **partitions; 103 int pos; 104 int i; 105 struct ipart iparts[TOTAL_NUMPART]; 106 char pname[MAXPATHLEN]; 107 int conv_flag = 0; 108 #if defined(i386) || defined(__amd64) 109 int len; 110 #endif 111 112 if (get_parts(desc->p.disk, iparts, pname, sizeof (pname)) != 0) { 113 return (libdiskmgt_empty_desc_array(errp)); 114 } 115 116 /* allocate the array for the descriptors */ 117 partitions = (descriptor_t **)calloc(TOTAL_NUMPART + 1, 118 sizeof (descriptor_t *)); 119 if (partitions == NULL) { 120 *errp = ENOMEM; 121 return (NULL); 122 } 123 124 #if defined(i386) || defined(__amd64) 125 /* convert part. name (e.g. c0d0p1) */ 126 len = strlen(pname); 127 if (len > 1 && *(pname + (len - 2)) == 'p') { 128 conv_flag = 1; 129 *(pname + (len - 1)) = 0; 130 } 131 #endif 132 133 /* 134 * If this is a slice desc. we need the first active solaris partition 135 * and if there isn't one then we need the first solaris partition. 136 */ 137 if (desc->type == DM_SLICE) { 138 for (i = 0; i < TOTAL_NUMPART; i++) { 139 if (iparts[i].bootid == ACTIVE && 140 (iparts[i].systid == SUNIXOS || 141 iparts[i].systid == SUNIXOS2)) { 142 break; 143 } 144 } 145 146 /* 147 * no active solaris part.,*try to get the first solaris part. 148 */ 149 if (i >= TOTAL_NUMPART) { 150 for (i = 0; i < TOTAL_NUMPART; i++) { 151 if (iparts[i].systid == SUNIXOS || 152 iparts[i].systid == SUNIXOS2) { 153 break; 154 } 155 } 156 } 157 158 if (i < TOTAL_NUMPART) { 159 /* we found a solaris partition to use */ 160 char part_name[MAXPATHLEN]; 161 162 if (conv_flag) { 163 /* convert part. name (e.g. c0d0p1) */ 164 (void) snprintf(part_name, sizeof (part_name), 165 "%s%d", pname, i+1); 166 } else { 167 (void) snprintf(part_name, sizeof (part_name), 168 "%d", i+1); 169 } 170 171 /* the media name comes from the slice desc. */ 172 partitions[0] = cache_get_desc(DM_PARTITION, 173 desc->p.disk, part_name, desc->secondary_name, 174 errp); 175 if (*errp != 0) { 176 cache_free_descriptors(partitions); 177 return (NULL); 178 } 179 partitions[1] = NULL; 180 181 return (partitions); 182 } 183 184 return (libdiskmgt_empty_desc_array(errp)); 185 } 186 187 /* Must be for media, so get all the parts. */ 188 189 pos = 0; 190 for (i = 0; i < TOTAL_NUMPART; i++) { 191 if (iparts[i].systid != UNUSED) { 192 char part_name[MAXPATHLEN]; 193 194 /* 195 * Process the descriptors and modify the cxdxpx 196 * format so that it refers to the fdisk partition 197 * number and not to the physical disk. This is 198 * achieved by i+1, where i is the number of the 199 * physical disk partition. 200 */ 201 if (conv_flag) { 202 /* convert part. name (e.g. c0d0p1) */ 203 (void) snprintf(part_name, sizeof (part_name), 204 "%s%d", pname, i+1); 205 } else { 206 (void) snprintf(part_name, sizeof (part_name), 207 "%d", i+1); 208 } 209 210 /* the media name comes from the media desc. */ 211 partitions[pos] = cache_get_desc(DM_PARTITION, 212 desc->p.disk, part_name, desc->name, errp); 213 if (*errp != 0) { 214 cache_free_descriptors(partitions); 215 return (NULL); 216 } 217 218 pos++; 219 } 220 } 221 partitions[pos] = NULL; 222 223 *errp = 0; 224 return (partitions); 225 } 226 227 nvlist_t * 228 partition_get_attributes(descriptor_t *dp, int *errp) 229 { 230 nvlist_t *attrs = NULL; 231 struct ipart iparts[TOTAL_NUMPART]; 232 233 if (!desc_ok(dp)) { 234 *errp = ENODEV; 235 return (NULL); 236 } 237 238 if ((*errp = get_parts(dp->p.disk, iparts, NULL, 0)) != 0) { 239 return (NULL); 240 } 241 242 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) { 243 *errp = ENOMEM; 244 return (NULL); 245 } 246 247 if ((*errp = get_attrs(dp, iparts, attrs)) != 0) { 248 nvlist_free(attrs); 249 attrs = NULL; 250 } 251 252 return (attrs); 253 } 254 255 /* 256 * Look for the partition by the partition number (which is not too useful). 257 */ 258 descriptor_t * 259 partition_get_descriptor_by_name(char *name, int *errp) 260 { 261 descriptor_t **partitions; 262 int i; 263 descriptor_t *partition = NULL; 264 265 partitions = cache_get_descriptors(DM_PARTITION, errp); 266 if (*errp != 0) { 267 return (NULL); 268 } 269 270 for (i = 0; partitions[i]; i++) { 271 if (libdiskmgt_str_eq(name, partitions[i]->name)) { 272 partition = partitions[i]; 273 } else { 274 /* clean up the unused descriptors */ 275 cache_free_descriptor(partitions[i]); 276 } 277 } 278 free(partitions); 279 280 if (partition == NULL) { 281 *errp = ENODEV; 282 } 283 284 return (partition); 285 } 286 287 /* ARGSUSED */ 288 descriptor_t ** 289 partition_get_descriptors(int filter[], int *errp) 290 { 291 return (cache_get_descriptors(DM_PARTITION, errp)); 292 } 293 294 char * 295 partition_get_name(descriptor_t *desc) 296 { 297 return (desc->name); 298 } 299 300 /* ARGSUSED */ 301 nvlist_t * 302 partition_get_stats(descriptor_t *dp, int stat_type, int *errp) 303 { 304 /* There are no stat types defined for partitions */ 305 *errp = EINVAL; 306 return (NULL); 307 } 308 309 /* ARGSUSED */ 310 int 311 partition_has_fdisk(disk_t *dp, int fd) 312 { 313 char bootsect[512 * 3]; /* 3 sectors to be safe */ 314 315 #ifdef sparc 316 if (dp->drv_type == DM_DT_FIXED) { 317 /* on sparc, only removable media can have fdisk parts. */ 318 return (0); 319 } 320 #endif 321 322 /* 323 * We assume the caller already made sure media was inserted and 324 * spun up. 325 */ 326 327 if ((ioctl(fd, DKIOCGMBOOT, bootsect) < 0) && (errno != ENOTTY)) { 328 return (0); 329 } 330 331 return (1); 332 } 333 334 /* 335 * partition_make_descriptors 336 * 337 * A partition descriptor points to a disk, the name is the partition number 338 * and the secondary name is the media name. The iparts parameter returned 339 * by the get_parts function contains the structures of all of the identified 340 * partitions found on each disk on a system. These are processed into an array 341 * of descriptors. A descriptor contains all of the information about a 342 * specific partition. 343 * 344 * Parameters: none 345 * 346 * Returns: 0 on success 347 * Error value on failure 348 * 349 */ 350 351 int 352 partition_make_descriptors() 353 { 354 int error; 355 disk_t *dp; 356 357 dp = cache_get_disklist(); 358 while (dp != NULL) { 359 struct ipart iparts[TOTAL_NUMPART]; 360 char pname[MAXPATHLEN]; 361 362 if (get_parts(dp, iparts, pname, sizeof (pname)) == 0) { 363 int i; 364 char mname[MAXPATHLEN]; 365 int conv_flag = 0; 366 #if defined(i386) || defined(__amd64) 367 /* convert part. name (e.g. c0d0p1) */ 368 int len; 369 370 len = strlen(pname); 371 if (len > 1 && *(pname + (len - 2)) == 'p') { 372 conv_flag = 1; 373 *(pname + (len - 1)) = 0; 374 } 375 #endif 376 377 mname[0] = 0; 378 (void) media_read_name(dp, mname, sizeof (mname)); 379 380 /* 381 * Process the descriptors and modify the cxdxpx 382 * format so that it refers to the fdisk partition 383 * number and not to the physical disk. This is 384 * achieved by i+1, where i is the number of the 385 * physical disk partition. 386 */ 387 for (i = 0; i < TOTAL_NUMPART; i++) { 388 if (iparts[i].systid != UNUSED) { 389 char part_name[MAXPATHLEN]; 390 391 if (conv_flag) { 392 /* 393 * convert partition name 394 * (e.g. c0d0p1) 395 */ 396 (void) snprintf(part_name, 397 sizeof (part_name), 398 "%s%d", pname, i+1); 399 } else { 400 (void) snprintf(part_name, 401 sizeof (part_name), 402 "%d", i+1); 403 } 404 405 cache_load_desc(DM_PARTITION, dp, 406 part_name, mname, &error); 407 if (error != 0) { 408 return (error); 409 } 410 } 411 } 412 } 413 dp = dp->next; 414 } 415 416 return (0); 417 } 418 419 static int 420 get_attrs(descriptor_t *dp, struct ipart *iparts, nvlist_t *attrs) 421 { 422 char *p; 423 int part_num; 424 425 /* 426 * We already made sure the media was loaded and ready in the 427 * get_parts call within partition_get_attributes. 428 */ 429 430 p = strrchr(dp->name, 'p'); 431 if (p == NULL) { 432 p = dp->name; 433 } else { 434 p++; 435 } 436 part_num = atoi(p); 437 if (part_num > TOTAL_NUMPART || 438 iparts[part_num - 1].systid == UNUSED) { 439 return (ENODEV); 440 } 441 442 /* 443 * A partition has been found. Determine what type of 444 * partition it is: logical, extended, or primary. 445 * Collect the information for the partition. 446 */ 447 #if defined(i386) || defined(__amd64) 448 if (part_num > FD_NUMPART) { 449 if (nvlist_add_uint32(attrs, DM_PARTITION_TYPE, 450 DM_LOGICAL) != 0) { 451 return (ENOMEM); 452 } 453 } else if (fdisk_is_dos_extended(iparts[part_num - 1].systid)) { 454 if (nvlist_add_uint32(attrs, DM_PARTITION_TYPE, 455 DM_EXTENDED) != 0) { 456 return (ENOMEM); 457 } 458 459 } else { 460 if (nvlist_add_uint32(attrs, DM_PARTITION_TYPE, 461 DM_PRIMARY) != 0) { 462 return (ENOMEM); 463 } 464 } 465 #endif 466 467 #ifdef sparc 468 if (nvlist_add_uint32(attrs, DM_PARTITION_TYPE, 469 DM_PRIMARY) != 0) { 470 return (ENOMEM); 471 } 472 #endif 473 474 475 if (nvlist_add_uint32(attrs, DM_BOOTID, 476 (unsigned int)iparts[part_num - 1].bootid) != 0) { 477 return (ENOMEM); 478 } 479 480 if (nvlist_add_uint32(attrs, DM_PTYPE, 481 (unsigned int)iparts[part_num - 1].systid) != 0) { 482 return (ENOMEM); 483 } 484 485 if (nvlist_add_uint32(attrs, DM_BHEAD, 486 (unsigned int)iparts[part_num - 1].beghead) != 0) { 487 return (ENOMEM); 488 } 489 490 if (nvlist_add_uint32(attrs, DM_BSECT, 491 (unsigned int)((iparts[part_num - 1].begsect) & 0x3f)) != 0) { 492 return (ENOMEM); 493 } 494 495 if (nvlist_add_uint32(attrs, DM_BCYL, (unsigned int) 496 ((iparts[part_num - 1].begcyl & 0xff) | 497 ((iparts[part_num - 1].begsect & 0xc0) << 2))) != 0) { 498 return (ENOMEM); 499 } 500 501 if (nvlist_add_uint32(attrs, DM_EHEAD, 502 (unsigned int)iparts[part_num - 1].endhead) != 0) { 503 return (ENOMEM); 504 } 505 506 if (nvlist_add_uint32(attrs, DM_ESECT, 507 (unsigned int)((iparts[part_num - 1].endsect) & 0x3f)) != 0) { 508 return (ENOMEM); 509 } 510 511 if (nvlist_add_uint32(attrs, DM_ECYL, (unsigned int) 512 ((iparts[part_num - 1].endcyl & 0xff) | 513 ((iparts[part_num - 1].endsect & 0xc0) << 2))) != 0) { 514 return (ENOMEM); 515 } 516 517 if (nvlist_add_uint32(attrs, DM_RELSECT, 518 (unsigned int)iparts[part_num - 1].relsect) != 0) { 519 return (ENOMEM); 520 } 521 522 if (nvlist_add_uint32(attrs, DM_NSECTORS, 523 (unsigned int)iparts[part_num - 1].numsect) != 0) { 524 return (ENOMEM); 525 } 526 527 return (0); 528 } 529 530 /* 531 * get_parts 532 * Discovers the primary, extended, and logical partitions that have 533 * been created on a disk. get_parts loops through the partitions, 534 * collects the information on each partition and stores it in a 535 * partition table. 536 * 537 * Parameters; 538 * disk -The disk device to be evaluated for partitions 539 * iparts -The structure that holds information about 540 * the partitions 541 * opath -The device path 542 * opath_len -Buffer size used with opath 543 * Returns: 544 * 0 on Successful completion 545 * Error Value on failure 546 * 547 */ 548 static int 549 get_parts(disk_t *disk, struct ipart *iparts, char *opath, int opath_len) 550 { 551 int fd; 552 struct dk_minfo minfo; 553 struct mboot bootblk; 554 char bootsect[512]; 555 int i; 556 557 #if defined(i386) || defined(__amd64) 558 int j, ret; 559 ext_part_t *epp; /* extended partition structure */ 560 char *device; /* name of fixed disk drive */ 561 size_t len; 562 logical_drive_t *log_drv; /* logical drive structure */ 563 uint64_t tmpsect; 564 #endif 565 566 /* Can't use drive_open_disk since we need the partition dev name. */ 567 if ((fd = open_disk(disk, opath, opath_len)) < 0) { 568 return (ENODEV); 569 } 570 571 /* First make sure media is inserted and spun up. */ 572 if (!media_read_info(fd, &minfo)) { 573 (void) close(fd); 574 return (ENODEV); 575 } 576 577 if (!partition_has_fdisk(disk, fd)) { 578 (void) close(fd); 579 return (ENOTTY); 580 } 581 582 if (lseek(fd, 0, 0) == -1) { 583 (void) close(fd); 584 return (ENODEV); 585 } 586 587 if (read(fd, bootsect, 512) != 512) { 588 (void) close(fd); 589 return (ENODEV); 590 } 591 (void) close(fd); 592 593 (void) memcpy(&bootblk, bootsect, sizeof (bootblk)); 594 595 if (les(bootblk.signature) != MBB_MAGIC) { 596 return (ENOTTY); 597 } 598 599 /* 600 * Initialize the memory space to clear unknown garbage 601 * that might create confusing results. 602 */ 603 for (i = 0; i < TOTAL_NUMPART; i++) { 604 (void) memset(&iparts[i], 0, sizeof (struct ipart)); 605 iparts[i].systid = UNUSED; 606 } 607 608 (void) memcpy(iparts, bootblk.parts, ISIZE); 609 610 /* 611 * Check to see if a valid partition exists. If a valid partition 612 * exists, check to see if it is an extended partition. 613 * If an extended partition exists, collect the logical partition 614 * data. 615 */ 616 for (i = 0; i < FD_NUMPART; i++) { 617 if (iparts[i].systid == UNUSED) 618 continue; 619 620 iparts[i].relsect = lel(iparts[i].relsect); 621 iparts[i].numsect = lel(iparts[i].numsect); 622 623 #if defined(i386) || defined(__amd64) 624 if (!fdisk_is_dos_extended(iparts[i].systid)) 625 continue; 626 627 len = strlen(disk->aliases->alias) + strlen("/dev/rdsk/") + 1; 628 if ((device = malloc(len)) == NULL) { 629 if (device) 630 free(device); 631 continue; 632 } 633 634 /* Check the above fix w Jean */ 635 (void) snprintf(device, len, "/dev/rdsk/%s", 636 disk->aliases->alias); 637 638 if ((ret = libfdisk_init(&epp, device, &iparts[i], 639 FDISK_READ_DISK)) != FDISK_SUCCESS) { 640 641 switch (ret) { 642 /* 643 * The first 2 error cases indicate that 644 * there is no Solaris logical partition, 645 * which is a valid condition, 646 * so iterating through the disk continues. 647 * Any other error cases indicate there is 648 * a potential problem with the disk, so 649 * don't continue iterating through the disk 650 * and return an error. 651 */ 652 case FDISK_EBADLOGDRIVE: 653 case FDISK_ENOLOGDRIVE: 654 free(device); 655 continue; 656 default: 657 free(device); 658 return (ENODEV); 659 } 660 } 661 662 /* 663 * Collect logical drive information 664 */ 665 for (log_drv = fdisk_get_ld_head(epp), j = FD_NUMPART, 666 tmpsect = 0; (j < TOTAL_NUMPART) && (log_drv != NULL); 667 log_drv = log_drv->next, j++) { 668 iparts[j].bootid = log_drv->parts[0].bootid; 669 iparts[j].beghead = log_drv->parts[0].beghead; 670 iparts[j].begsect = log_drv->parts[0].begsect; 671 iparts[j].begcyl = log_drv->parts[0].begcyl; 672 iparts[j].systid = log_drv->parts[0].systid; 673 iparts[j].endhead = log_drv->parts[0].endhead; 674 iparts[j].endsect = log_drv->parts[0].endsect; 675 iparts[j].endcyl = log_drv->parts[0].endcyl; 676 iparts[j].relsect = (tmpsect + 677 lel(log_drv->parts[0].relsect) + epp->ext_beg_sec); 678 iparts[j].numsect = lel(log_drv->parts[0].numsect); 679 tmpsect = lel(log_drv->parts[1].relsect); 680 } 681 682 /* free the device and the epp memory. */ 683 free(device); 684 libfdisk_fini(&epp); 685 #endif 686 } 687 688 return (0); 689 } 690 691 /* return 1 if the partition descriptor is still valid, 0 if not. */ 692 static int 693 desc_ok(descriptor_t *dp) 694 { 695 /* First verify the media name for removable media */ 696 if (dp->p.disk->removable) { 697 char mname[MAXPATHLEN]; 698 699 if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { 700 return (0); 701 } 702 703 if (mname[0] == 0) { 704 return (libdiskmgt_str_eq(dp->secondary_name, NULL)); 705 } else { 706 return (libdiskmgt_str_eq(dp->secondary_name, mname)); 707 } 708 } 709 710 /* 711 * We could verify the partition is still there but this is kind of 712 * expensive and other code down the line will do that (e.g. see 713 * get_attrs). 714 */ 715 716 return (1); 717 } 718 719 /* 720 * Return 1 if partition has slices, 0 if not. 721 */ 722 static int 723 has_slices(descriptor_t *desc, int *errp) 724 { 725 int pnum; 726 int i; 727 char *p; 728 struct ipart iparts[TOTAL_NUMPART]; 729 730 if (get_parts(desc->p.disk, iparts, NULL, 0) != 0) { 731 *errp = ENODEV; 732 return (0); 733 } 734 735 p = strrchr(desc->name, 'p'); 736 if (p == NULL) { 737 p = desc->name; 738 } else { 739 p++; 740 } 741 pnum = atoi(p); 742 743 /* 744 * Slices are associated with the active solaris partition or if there 745 * is no active solaris partition, then the first solaris partition. 746 */ 747 748 *errp = 0; 749 if (iparts[pnum].bootid == ACTIVE && 750 (iparts[pnum].systid == SUNIXOS || 751 iparts[pnum].systid == SUNIXOS2)) { 752 return (1); 753 } else { 754 int active = 0; 755 756 /* Check if there are no active solaris partitions. */ 757 for (i = 0; i < TOTAL_NUMPART; i++) { 758 if (iparts[i].bootid == ACTIVE && 759 (iparts[i].systid == SUNIXOS || 760 iparts[i].systid == SUNIXOS2)) { 761 active = 1; 762 break; 763 } 764 } 765 766 if (!active) { 767 /* Check if this is the first solaris partition. */ 768 for (i = 0; i < TOTAL_NUMPART; i++) { 769 if (iparts[i].systid == SUNIXOS || 770 iparts[i].systid == SUNIXOS2) { 771 break; 772 } 773 } 774 775 if (i < TOTAL_NUMPART && i == pnum) { 776 return (1); 777 } 778 } 779 } 780 781 return (0); 782 } 783 784 static int 785 open_disk(disk_t *diskp, char *opath, int len) 786 { 787 /* 788 * Just open the first devpath. 789 */ 790 if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) { 791 #ifdef sparc 792 if (opath != NULL) { 793 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len); 794 } 795 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY)); 796 #else 797 /* On intel we need to open partition device (e.g. c0d0p1). */ 798 char part_dev[MAXPATHLEN]; 799 char *p; 800 801 (void) strlcpy(part_dev, diskp->aliases->devpaths->devpath, 802 sizeof (part_dev)); 803 p = strrchr(part_dev, '/'); 804 if (p == NULL) { 805 p = strrchr(part_dev, 's'); 806 if (p != NULL) { 807 *p = 'p'; 808 } 809 } else { 810 char *ps; 811 812 *p = 0; 813 ps = strrchr((p + 1), 's'); 814 if (ps != NULL) { 815 *ps = 'p'; 816 } 817 *p = '/'; 818 } 819 820 if (opath != NULL) { 821 (void) strlcpy(opath, part_dev, len); 822 } 823 return (open(part_dev, O_RDONLY|O_NDELAY)); 824 #endif 825 } 826 827 return (-1); 828 } 829