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 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #pragma ident "%Z%%M% %I% %E% SMI" 27 28 #include <fcntl.h> 29 #include <libdevinfo.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <sys/sunddi.h> 34 #include <sys/types.h> 35 #include <sys/stat.h> 36 #include <dirent.h> 37 #include <unistd.h> 38 #include <sys/dkio.h> 39 40 #include "libdiskmgt.h" 41 #include "disks_private.h" 42 #include "partition.h" 43 44 #ifdef sparc 45 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF)) 46 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \ 47 (les((unsigned)((val)&0xffff0000)>>16))) 48 #else 49 #define les(val) (val) 50 #define lel(val) (val) 51 #endif 52 53 #define ISIZE FD_NUMPART * sizeof (struct ipart) 54 55 static int desc_ok(descriptor_t *dp); 56 static int get_attrs(descriptor_t *dp, struct ipart *iparts, 57 nvlist_t *attrs); 58 static int get_parts(disk_t *disk, struct ipart *iparts, char *opath, 59 int opath_len); 60 static int open_disk(disk_t *diskp, char *opath, int len); 61 static int has_slices(descriptor_t *desc, int *errp); 62 63 descriptor_t ** 64 partition_get_assoc_descriptors(descriptor_t *desc, dm_desc_type_t type, 65 int *errp) 66 { 67 if (!desc_ok(desc)) { 68 *errp = ENODEV; 69 return (NULL); 70 } 71 72 switch (type) { 73 case DM_MEDIA: 74 return (media_get_assocs(desc, errp)); 75 case DM_SLICE: 76 if (!has_slices(desc, errp)) { 77 if (*errp != 0) { 78 return (NULL); 79 } 80 return (libdiskmgt_empty_desc_array(errp)); 81 } 82 return (slice_get_assocs(desc, errp)); 83 } 84 85 *errp = EINVAL; 86 return (NULL); 87 } 88 89 /* 90 * This is called by media/slice to get the associated partitions. 91 * For a media desc. we just get all the partitions, but for a slice desc. 92 * we just get the active solaris partition. 93 */ 94 descriptor_t ** 95 partition_get_assocs(descriptor_t *desc, int *errp) 96 { 97 descriptor_t **partitions; 98 int pos; 99 int i; 100 struct ipart iparts[FD_NUMPART]; 101 char pname[MAXPATHLEN]; 102 int conv_flag = 0; 103 #if defined(i386) || defined(__amd64) 104 int len; 105 #endif 106 107 if (get_parts(desc->p.disk, iparts, pname, sizeof (pname)) != 0) { 108 return (libdiskmgt_empty_desc_array(errp)); 109 } 110 111 /* allocate the array for the descriptors */ 112 partitions = (descriptor_t **)calloc(FD_NUMPART + 1, 113 sizeof (descriptor_t *)); 114 if (partitions == NULL) { 115 *errp = ENOMEM; 116 return (NULL); 117 } 118 119 #if defined(i386) || defined(__amd64) 120 /* convert part. name (e.g. c0d0p0) */ 121 len = strlen(pname); 122 if (len > 1 && *(pname + (len - 2)) == 'p') { 123 conv_flag = 1; 124 *(pname + (len - 1)) = 0; 125 } 126 #endif 127 128 /* 129 * If this is a slice desc. we need the first active solaris partition 130 * and if there isn't one then we need the first solaris partition. 131 */ 132 if (desc->type == DM_SLICE) { 133 for (i = 0; i < FD_NUMPART; i++) { 134 if (iparts[i].bootid == ACTIVE && 135 (iparts[i].systid == SUNIXOS || 136 iparts[i].systid == SUNIXOS2)) { 137 break; 138 } 139 } 140 141 /* no active solaris part., try to get the first solaris part. */ 142 if (i >= FD_NUMPART) { 143 for (i = 0; i < FD_NUMPART; i++) { 144 if (iparts[i].systid == SUNIXOS || 145 iparts[i].systid == SUNIXOS2) { 146 break; 147 } 148 } 149 } 150 151 if (i < FD_NUMPART) { 152 /* we found a solaris partition to use */ 153 char part_name[MAXPATHLEN]; 154 155 if (conv_flag) { 156 /* convert part. name (e.g. c0d0p0) */ 157 (void) snprintf(part_name, sizeof (part_name), "%s%d", 158 pname, i); 159 } else { 160 (void) snprintf(part_name, sizeof (part_name), "%d", i); 161 } 162 163 /* the media name comes from the slice desc. */ 164 partitions[0] = cache_get_desc(DM_PARTITION, desc->p.disk, 165 part_name, desc->secondary_name, errp); 166 if (*errp != 0) { 167 cache_free_descriptors(partitions); 168 return (NULL); 169 } 170 partitions[1] = NULL; 171 172 return (partitions); 173 174 } 175 176 return (libdiskmgt_empty_desc_array(errp)); 177 } 178 179 /* Must be for media, so get all the parts. */ 180 181 pos = 0; 182 for (i = 0; i < FD_NUMPART; i++) { 183 if (iparts[i].systid != 0) { 184 char part_name[MAXPATHLEN]; 185 186 if (conv_flag) { 187 /* convert part. name (e.g. c0d0p0) */ 188 (void) snprintf(part_name, sizeof (part_name), "%s%d", 189 pname, i); 190 } else { 191 (void) snprintf(part_name, sizeof (part_name), "%d", i); 192 } 193 194 /* the media name comes from the media desc. */ 195 partitions[pos] = cache_get_desc(DM_PARTITION, desc->p.disk, 196 part_name, desc->name, errp); 197 if (*errp != 0) { 198 cache_free_descriptors(partitions); 199 return (NULL); 200 } 201 202 pos++; 203 } 204 } 205 partitions[pos] = NULL; 206 207 *errp = 0; 208 return (partitions); 209 } 210 211 nvlist_t * 212 partition_get_attributes(descriptor_t *dp, int *errp) 213 { 214 nvlist_t *attrs = NULL; 215 struct ipart iparts[FD_NUMPART]; 216 217 if (!desc_ok(dp)) { 218 *errp = ENODEV; 219 return (NULL); 220 } 221 222 if ((*errp = get_parts(dp->p.disk, iparts, NULL, 0)) != 0) { 223 return (NULL); 224 } 225 226 if (nvlist_alloc(&attrs, NVATTRS, 0) != 0) { 227 *errp = ENOMEM; 228 return (NULL); 229 } 230 231 if ((*errp = get_attrs(dp, iparts, attrs)) != 0) { 232 nvlist_free(attrs); 233 attrs = NULL; 234 } 235 236 return (attrs); 237 } 238 239 /* 240 * Look for the partition by the partition number (which is not too useful). 241 */ 242 descriptor_t * 243 partition_get_descriptor_by_name(char *name, int *errp) 244 { 245 descriptor_t **partitions; 246 int i; 247 descriptor_t *partition = NULL; 248 249 partitions = cache_get_descriptors(DM_PARTITION, errp); 250 if (*errp != 0) { 251 return (NULL); 252 } 253 254 for (i = 0; partitions[i]; i++) { 255 if (libdiskmgt_str_eq(name, partitions[i]->name)) { 256 partition = partitions[i]; 257 } else { 258 /* clean up the unused descriptors */ 259 cache_free_descriptor(partitions[i]); 260 } 261 } 262 free(partitions); 263 264 if (partition == NULL) { 265 *errp = ENODEV; 266 } 267 268 return (partition); 269 } 270 271 /* ARGSUSED */ 272 descriptor_t ** 273 partition_get_descriptors(int filter[], int *errp) 274 { 275 return (cache_get_descriptors(DM_PARTITION, errp)); 276 } 277 278 char * 279 partition_get_name(descriptor_t *desc) 280 { 281 return (desc->name); 282 } 283 284 /* ARGSUSED */ 285 nvlist_t * 286 partition_get_stats(descriptor_t *dp, int stat_type, int *errp) 287 { 288 /* There are no stat types defined for partitions */ 289 *errp = EINVAL; 290 return (NULL); 291 } 292 293 /* ARGSUSED */ 294 int 295 partition_has_fdisk(disk_t *dp, int fd) 296 { 297 char bootsect[512 * 3]; /* 3 sectors to be safe */ 298 299 #ifdef sparc 300 if (dp->drv_type == DM_DT_FIXED) { 301 /* on sparc, only removable media can have fdisk parts. */ 302 return (0); 303 } 304 #endif 305 306 /* 307 * We assume the caller already made sure media was inserted and 308 * spun up. 309 */ 310 311 if ((ioctl(fd, DKIOCGMBOOT, bootsect) < 0) && (errno != ENOTTY)) { 312 return (0); 313 } 314 315 return (1); 316 } 317 318 /* 319 * A partition descriptor points to a disk, the name is the partition number 320 * and the secondary name is the media name. 321 */ 322 int 323 partition_make_descriptors() 324 { 325 int error; 326 disk_t *dp; 327 328 dp = cache_get_disklist(); 329 while (dp != NULL) { 330 struct ipart iparts[FD_NUMPART]; 331 char pname[MAXPATHLEN]; 332 333 if (get_parts(dp, iparts, pname, sizeof (pname)) == 0) { 334 int i; 335 char mname[MAXPATHLEN]; 336 int conv_flag = 0; 337 #if defined(i386) || defined(__amd64) 338 /* convert part. name (e.g. c0d0p0) */ 339 int len; 340 341 len = strlen(pname); 342 if (len > 1 && *(pname + (len - 2)) == 'p') { 343 conv_flag = 1; 344 *(pname + (len - 1)) = 0; 345 } 346 #endif 347 348 mname[0] = 0; 349 (void) media_read_name(dp, mname, sizeof (mname)); 350 351 for (i = 0; i < FD_NUMPART; i++) { 352 if (iparts[i].systid != 0) { 353 char part_name[MAXPATHLEN]; 354 355 if (conv_flag) { 356 /* convert part. name (e.g. c0d0p0) */ 357 (void) snprintf(part_name, sizeof (part_name), 358 "%s%d", pname, i); 359 } else { 360 (void) snprintf(part_name, sizeof (part_name), 361 "%d", i); 362 } 363 364 cache_load_desc(DM_PARTITION, dp, part_name, mname, 365 &error); 366 if (error != 0) { 367 return (error); 368 } 369 } 370 } 371 } 372 dp = dp->next; 373 } 374 375 return (0); 376 } 377 378 static int 379 get_attrs(descriptor_t *dp, struct ipart *iparts, nvlist_t *attrs) 380 { 381 char *p; 382 int part_num; 383 384 /* 385 * We already made sure the media was loaded and ready in the 386 * get_parts call within partition_get_attributes. 387 */ 388 389 p = strrchr(dp->name, 'p'); 390 if (p == NULL) { 391 p = dp->name; 392 } else { 393 p++; 394 } 395 part_num = atoi(p); 396 if (part_num >= FD_NUMPART || iparts[part_num].systid == 0) { 397 return (ENODEV); 398 } 399 400 /* we found the partition */ 401 402 if (nvlist_add_uint32(attrs, DM_BOOTID, 403 (unsigned int)iparts[part_num].bootid) != 0) { 404 return (ENOMEM); 405 } 406 407 if (nvlist_add_uint32(attrs, DM_PTYPE, 408 (unsigned int)iparts[part_num].systid) != 0) { 409 return (ENOMEM); 410 } 411 412 if (nvlist_add_uint32(attrs, DM_BHEAD, 413 (unsigned int)iparts[part_num].beghead) != 0) { 414 return (ENOMEM); 415 } 416 417 if (nvlist_add_uint32(attrs, DM_BSECT, 418 (unsigned int)((iparts[part_num].begsect) & 0x3f)) != 0) { 419 return (ENOMEM); 420 } 421 422 if (nvlist_add_uint32(attrs, DM_BCYL, (unsigned int) 423 ((iparts[part_num].begcyl & 0xff) | 424 ((iparts[part_num].begsect & 0xc0) << 2))) != 0) { 425 return (ENOMEM); 426 } 427 428 if (nvlist_add_uint32(attrs, DM_EHEAD, 429 (unsigned int)iparts[part_num].endhead) != 0) { 430 return (ENOMEM); 431 } 432 433 if (nvlist_add_uint32(attrs, DM_ESECT, 434 (unsigned int)((iparts[part_num].endsect) & 0x3f)) != 0) { 435 return (ENOMEM); 436 } 437 438 if (nvlist_add_uint32(attrs, DM_ECYL, (unsigned int) 439 ((iparts[part_num].endcyl & 0xff) | 440 ((iparts[part_num].endsect & 0xc0) << 2))) != 0) { 441 return (ENOMEM); 442 } 443 444 if (nvlist_add_uint32(attrs, DM_RELSECT, 445 (unsigned int)iparts[part_num].relsect) != 0) { 446 return (ENOMEM); 447 } 448 449 if (nvlist_add_uint32(attrs, DM_NSECTORS, 450 (unsigned int)iparts[part_num].numsect) != 0) { 451 return (ENOMEM); 452 } 453 454 return (0); 455 } 456 457 static int 458 get_parts(disk_t *disk, struct ipart *iparts, char *opath, int opath_len) 459 { 460 int fd; 461 struct dk_minfo minfo; 462 struct mboot bootblk; 463 char bootsect[512]; 464 int i; 465 466 /* Can't use drive_open_disk since we need the partition dev name. */ 467 if ((fd = open_disk(disk, opath, opath_len)) < 0) { 468 return (ENODEV); 469 } 470 471 /* First make sure media is inserted and spun up. */ 472 if (!media_read_info(fd, &minfo)) { 473 (void) close(fd); 474 return (ENODEV); 475 } 476 477 if (!partition_has_fdisk(disk, fd)) { 478 (void) close(fd); 479 return (ENOTTY); 480 } 481 482 if (lseek(fd, 0, 0) == -1) { 483 (void) close(fd); 484 return (ENODEV); 485 } 486 487 if (read(fd, bootsect, 512) != 512) { 488 (void) close(fd); 489 return (ENODEV); 490 } 491 (void) close(fd); 492 493 (void) memcpy(&bootblk, bootsect, sizeof (bootblk)); 494 495 if (les(bootblk.signature) != MBB_MAGIC) { 496 return (ENOTTY); 497 } 498 499 (void) memcpy(iparts, bootblk.parts, ISIZE); 500 501 for (i = 0; i < FD_NUMPART; i++) { 502 if (iparts[i].systid != 0) { 503 iparts[i].relsect = lel(iparts[i].relsect); 504 iparts[i].numsect = lel(iparts[i].numsect); 505 } 506 } 507 508 return (0); 509 } 510 /* return 1 if the partition descriptor is still valid, 0 if not. */ 511 static int 512 desc_ok(descriptor_t *dp) 513 { 514 /* First verify the media name for removable media */ 515 if (dp->p.disk->removable) { 516 char mname[MAXPATHLEN]; 517 518 if (!media_read_name(dp->p.disk, mname, sizeof (mname))) { 519 return (0); 520 } 521 522 if (mname[0] == 0) { 523 return (libdiskmgt_str_eq(dp->secondary_name, NULL)); 524 } else { 525 return (libdiskmgt_str_eq(dp->secondary_name, mname)); 526 } 527 } 528 529 /* 530 * We could verify the partition is still there but this is kind of 531 * expensive and other code down the line will do that (e.g. see 532 * get_attrs). 533 */ 534 535 return (1); 536 } 537 538 /* 539 * Return 1 if partition has slices, 0 if not. 540 */ 541 static int 542 has_slices(descriptor_t *desc, int *errp) 543 { 544 int pnum; 545 int i; 546 char *p; 547 struct ipart iparts[FD_NUMPART]; 548 549 if (get_parts(desc->p.disk, iparts, NULL, 0) != 0) { 550 *errp = ENODEV; 551 return (0); 552 } 553 554 p = strrchr(desc->name, 'p'); 555 if (p == NULL) { 556 p = desc->name; 557 } else { 558 p++; 559 } 560 pnum = atoi(p); 561 562 /* 563 * Slices are associated with the active solaris partition or if there 564 * is no active solaris partition, then the first solaris partition. 565 */ 566 567 *errp = 0; 568 if (iparts[pnum].bootid == ACTIVE && 569 (iparts[pnum].systid == SUNIXOS || 570 iparts[pnum].systid == SUNIXOS2)) { 571 return (1); 572 } else { 573 int active = 0; 574 575 /* Check if there are no active solaris partitions. */ 576 for (i = 0; i < FD_NUMPART; i++) { 577 if (iparts[i].bootid == ACTIVE && 578 (iparts[i].systid == SUNIXOS || 579 iparts[i].systid == SUNIXOS2)) { 580 active = 1; 581 break; 582 } 583 } 584 585 if (!active) { 586 /* Check if this is the first solaris partition. */ 587 for (i = 0; i < FD_NUMPART; i++) { 588 if (iparts[i].systid == SUNIXOS || 589 iparts[i].systid == SUNIXOS2) { 590 break; 591 } 592 } 593 594 if (i < FD_NUMPART && i == pnum) { 595 return (1); 596 } 597 } 598 } 599 600 return (0); 601 } 602 603 static int 604 open_disk(disk_t *diskp, char *opath, int len) 605 { 606 /* 607 * Just open the first devpath. 608 */ 609 if (diskp->aliases != NULL && diskp->aliases->devpaths != NULL) { 610 #ifdef sparc 611 if (opath != NULL) { 612 (void) strlcpy(opath, diskp->aliases->devpaths->devpath, len); 613 } 614 return (open(diskp->aliases->devpaths->devpath, O_RDONLY|O_NDELAY)); 615 #else 616 /* On intel we need to open partition device (e.g. c0d0p0). */ 617 char part_dev[MAXPATHLEN]; 618 char *p; 619 620 (void) strlcpy(part_dev, diskp->aliases->devpaths->devpath, 621 sizeof (part_dev)); 622 p = strrchr(part_dev, '/'); 623 if (p == NULL) { 624 p = strrchr(part_dev, 's'); 625 if (p != NULL) { 626 *p = 'p'; 627 } 628 } else { 629 char *ps; 630 631 *p = 0; 632 ps = strrchr((p + 1), 's'); 633 if (ps != NULL) { 634 *ps = 'p'; 635 } 636 *p = '/'; 637 } 638 639 if (opath != NULL) { 640 (void) strlcpy(opath, part_dev, len); 641 } 642 return (open(part_dev, O_RDONLY|O_NDELAY)); 643 #endif 644 } 645 646 return (-1); 647 } 648