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 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * This file contains functions that implement the fdisk menu commands. 28 */ 29 #include "global.h" 30 #include <errno.h> 31 #include <sys/time.h> 32 #include <sys/resource.h> 33 #include <sys/wait.h> 34 #include <signal.h> 35 #include <string.h> 36 #include <fcntl.h> 37 #include <stdlib.h> 38 #include <sys/dktp/fdisk.h> 39 #include <sys/stat.h> 40 #include <sys/dklabel.h> 41 #ifdef i386 42 #include <libfdisk.h> 43 #endif 44 45 #include "main.h" 46 #include "analyze.h" 47 #include "menu.h" 48 #include "menu_command.h" 49 #include "menu_defect.h" 50 #include "menu_partition.h" 51 #include "menu_fdisk.h" 52 #include "param.h" 53 #include "misc.h" 54 #include "label.h" 55 #include "startup.h" 56 #include "partition.h" 57 #include "prompts.h" 58 #include "checkdev.h" 59 #include "io.h" 60 #include "ctlr_scsi.h" 61 #include "auto_sense.h" 62 63 extern struct menu_item menu_fdisk[]; 64 65 /* 66 * Byte swapping macros for accessing struct ipart 67 * to resolve little endian on Sparc. 68 */ 69 #if defined(sparc) 70 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF)) 71 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \ 72 (les((unsigned)((val)&0xffff0000)>>16))) 73 74 #elif defined(i386) 75 76 #define les(val) (val) 77 #define lel(val) (val) 78 79 #else /* defined(sparc) */ 80 81 #error No Platform defined 82 83 #endif /* defined(sparc) */ 84 85 86 /* Function prototypes */ 87 #ifdef __STDC__ 88 89 #if defined(sparc) 90 91 static int getbyte(uchar_t **); 92 static int getlong(uchar_t **); 93 94 #endif /* defined(sparc) */ 95 96 static int get_solaris_part(int fd, struct ipart *ipart); 97 98 #else /* __STDC__ */ 99 100 #if defined(sparc) 101 102 static int getbyte(); 103 static int getlong(); 104 105 #endif /* defined(sparc) */ 106 107 static int get_solaris_part(); 108 109 #endif /* __STDC__ */ 110 111 #ifdef i386 112 int extpart_init(ext_part_t **epp); 113 #endif 114 /* 115 * Handling the alignment problem of struct ipart. 116 */ 117 static void 118 fill_ipart(char *bootptr, struct ipart *partp) 119 { 120 #if defined(sparc) 121 /* 122 * Sparc platform: 123 * 124 * Packing short/word for struct ipart to resolve 125 * little endian on Sparc since it is not 126 * properly aligned on Sparc. 127 */ 128 partp->bootid = getbyte((uchar_t **)&bootptr); 129 partp->beghead = getbyte((uchar_t **)&bootptr); 130 partp->begsect = getbyte((uchar_t **)&bootptr); 131 partp->begcyl = getbyte((uchar_t **)&bootptr); 132 partp->systid = getbyte((uchar_t **)&bootptr); 133 partp->endhead = getbyte((uchar_t **)&bootptr); 134 partp->endsect = getbyte((uchar_t **)&bootptr); 135 partp->endcyl = getbyte((uchar_t **)&bootptr); 136 partp->relsect = getlong((uchar_t **)&bootptr); 137 partp->numsect = getlong((uchar_t **)&bootptr); 138 #elif defined(i386) 139 /* 140 * i386 platform: 141 * 142 * The fdisk table does not begin on a 4-byte boundary within 143 * the master boot record; so, we need to recopy its contents 144 * to another data structure to avoid an alignment exception. 145 */ 146 (void) bcopy(bootptr, partp, sizeof (struct ipart)); 147 #else 148 #error No Platform defined 149 #endif /* defined(sparc) */ 150 } 151 152 /* 153 * Get a correct byte/short/word routines for Sparc platform. 154 */ 155 #if defined(sparc) 156 static int 157 getbyte(uchar_t **bp) 158 { 159 int b; 160 161 b = **bp; 162 *bp = *bp + 1; 163 return (b); 164 } 165 166 #ifdef DEADCODE 167 static int 168 getshort(uchar_t **bp) 169 { 170 int b; 171 172 b = ((**bp) << 8) | *(*bp + 1); 173 *bp += 2; 174 return (b); 175 } 176 #endif /* DEADCODE */ 177 178 static int 179 getlong(uchar_t **bp) 180 { 181 int b, bh, bl; 182 183 bh = ((**bp) << 8) | *(*bp + 1); 184 *bp += 2; 185 bl = ((**bp) << 8) | *(*bp + 1); 186 *bp += 2; 187 188 b = (bh << 16) | bl; 189 return (b); 190 } 191 #endif /* defined(sparc) */ 192 193 /* 194 * Convert cn[tn]dn to cn[tn]dns2 path 195 */ 196 static void 197 get_sname(char *name) 198 { 199 char buf[MAXPATHLEN]; 200 char *devp = "/dev/dsk"; 201 char *rdevp = "/dev/rdsk"; 202 char np[MAXNAMELEN]; 203 char *npt; 204 205 /* 206 * If it is a full path /dev/[r]dsk/cn[tn]dn, use this path 207 */ 208 (void) strcpy(np, cur_disk->disk_name); 209 if (strncmp(rdevp, cur_disk->disk_name, strlen(rdevp)) == 0 || 210 strncmp(devp, cur_disk->disk_name, strlen(devp)) == 0) { 211 /* 212 * Skip if the path is already included with sN 213 */ 214 if (strchr(np, 's') == strrchr(np, 's')) { 215 npt = strrchr(np, 'p'); 216 /* If pN is found, do not include it */ 217 if (npt != NULL) { 218 *npt = '\0'; 219 } 220 (void) snprintf(buf, sizeof (buf), "%ss2", np); 221 } else { 222 (void) snprintf(buf, sizeof (buf), "%s", np); 223 } 224 } else { 225 (void) snprintf(buf, sizeof (buf), "/dev/rdsk/%ss2", np); 226 } 227 (void) strcpy(name, buf); 228 } 229 230 /* 231 * Convert cn[tn]dnsn to cn[tn]dnp0 path 232 */ 233 static void 234 get_pname(char *name) 235 { 236 char buf[MAXPATHLEN]; 237 char *devp = "/dev/dsk"; 238 char *rdevp = "/dev/rdsk"; 239 char np[MAXNAMELEN]; 240 char *npt; 241 242 /* 243 * If it is a full path /dev/[r]dsk/cn[tn]dnsn, use this path 244 */ 245 if (cur_disk == NULL) { 246 (void) strcpy(np, x86_devname); 247 } else { 248 (void) strcpy(np, cur_disk->disk_name); 249 } 250 251 if (strncmp(rdevp, np, strlen(rdevp)) == 0 || 252 strncmp(devp, np, strlen(devp)) == 0) { 253 /* 254 * Skip if the path is already included with pN 255 */ 256 if (strchr(np, 'p') == NULL) { 257 npt = strrchr(np, 's'); 258 /* If sN is found, do not include it */ 259 if (isdigit(*++npt)) { 260 *--npt = '\0'; 261 } 262 (void) snprintf(buf, sizeof (buf), "%sp0", np); 263 } else { 264 (void) snprintf(buf, sizeof (buf), "%s", np); 265 } 266 } else { 267 (void) snprintf(buf, sizeof (buf), "/dev/rdsk/%sp0", np); 268 } 269 (void) strcpy(name, buf); 270 } 271 272 /* 273 * Open file descriptor for current disk (cur_file) 274 * with "p0" path or cur_disk->disk_path 275 */ 276 void 277 open_cur_file(int mode) 278 { 279 char *dkpath; 280 char pbuf[MAXPATHLEN]; 281 282 switch (mode) { 283 case FD_USE_P0_PATH: 284 (void) get_pname(&pbuf[0]); 285 dkpath = pbuf; 286 break; 287 case FD_USE_CUR_DISK_PATH: 288 if (cur_disk->fdisk_part.systid == SUNIXOS || 289 cur_disk->fdisk_part.systid == SUNIXOS2) { 290 (void) get_sname(&pbuf[0]); 291 dkpath = pbuf; 292 } else { 293 dkpath = cur_disk->disk_path; 294 } 295 break; 296 default: 297 err_print("Error: Invalid mode option for opening " 298 "cur_file\n"); 299 fullabort(); 300 } 301 302 /* Close previous cur_file */ 303 (void) close(cur_file); 304 /* Open cur_file with the required path dkpath */ 305 if ((cur_file = open_disk(dkpath, O_RDWR | O_NDELAY)) < 0) { 306 err_print( 307 "Error: can't open selected disk '%s'.\n", dkpath); 308 fullabort(); 309 } 310 } 311 312 313 /* 314 * This routine implements the 'fdisk' command. It simply runs 315 * the fdisk command on the current disk. 316 * Use of this is restricted to interactive mode only. 317 */ 318 int 319 c_fdisk() 320 { 321 322 char buf[MAXPATHLEN]; 323 char pbuf[MAXPATHLEN]; 324 struct stat statbuf; 325 326 /* 327 * We must be in interactive mode to use the fdisk command 328 */ 329 if (option_f != (char *)NULL || isatty(0) != 1 || isatty(1) != 1) { 330 err_print("Fdisk command is for interactive use only!\n"); 331 return (-1); 332 } 333 334 /* 335 * There must be a current disk type and a current disk 336 */ 337 if (cur_dtype == NULL) { 338 err_print("Current Disk Type is not set.\n"); 339 return (-1); 340 } 341 342 /* 343 * Before running the fdisk command, get file status of 344 * /dev/rdsk/cn[tn]dnp0 path to see if this disk 345 * supports fixed disk partition table. 346 */ 347 (void) get_pname(&pbuf[0]); 348 if (stat(pbuf, (struct stat *)&statbuf) == -1 || 349 !S_ISCHR(statbuf.st_mode)) { 350 err_print( 351 "Disk does not support fixed disk partition table\n"); 352 return (0); 353 } 354 355 /* 356 * Run the fdisk program. 357 */ 358 (void) snprintf(buf, sizeof (buf), "fdisk %s\n", pbuf); 359 (void) system(buf); 360 361 /* 362 * Open cur_file with "p0" path for accessing the fdisk table 363 */ 364 (void) open_cur_file(FD_USE_P0_PATH); 365 366 /* 367 * Get solaris partition information in the fdisk partition table 368 */ 369 if (get_solaris_part(cur_file, &cur_disk->fdisk_part) == -1) { 370 err_print("No fdisk solaris partition found\n"); 371 cur_disk->fdisk_part.numsect = 0; /* No Solaris */ 372 } 373 374 /* 375 * Restore cur_file with cur_disk->disk_path 376 */ 377 (void) open_cur_file(FD_USE_CUR_DISK_PATH); 378 379 return (0); 380 } 381 382 /* 383 * Read MBR on the disk 384 * if the Solaris partition has changed, 385 * reread the vtoc 386 */ 387 #ifdef DEADCODE 388 static void 389 update_cur_parts() 390 { 391 392 int i; 393 register struct partition_info *parts; 394 395 for (i = 0; i < NDKMAP; i++) { 396 #if defined(_SUNOS_VTOC_16) 397 if (cur_parts->vtoc.v_part[i].p_tag && 398 cur_parts->vtoc.v_part[i].p_tag != V_ALTSCTR) { 399 cur_parts->vtoc.v_part[i].p_start = 0; 400 cur_parts->vtoc.v_part[i].p_size = 0; 401 402 #endif 403 cur_parts->pinfo_map[i].dkl_nblk = 0; 404 cur_parts->pinfo_map[i].dkl_cylno = 0; 405 cur_parts->vtoc.v_part[i].p_tag = 406 default_vtoc_map[i].p_tag; 407 cur_parts->vtoc.v_part[i].p_flag = 408 default_vtoc_map[i].p_flag; 409 #if defined(_SUNOS_VTOC_16) 410 } 411 #endif 412 } 413 cur_parts->pinfo_map[C_PARTITION].dkl_nblk = ncyl * spc(); 414 415 #if defined(_SUNOS_VTOC_16) 416 /* 417 * Adjust for the boot partitions 418 */ 419 cur_parts->pinfo_map[I_PARTITION].dkl_nblk = spc(); 420 cur_parts->pinfo_map[I_PARTITION].dkl_cylno = 0; 421 cur_parts->vtoc.v_part[C_PARTITION].p_start = 422 cur_parts->pinfo_map[C_PARTITION].dkl_cylno * nhead * nsect; 423 cur_parts->vtoc.v_part[C_PARTITION].p_size = 424 cur_parts->pinfo_map[C_PARTITION].dkl_nblk; 425 426 cur_parts->vtoc.v_part[I_PARTITION].p_start = 427 cur_parts->pinfo_map[I_PARTITION].dkl_cylno; 428 cur_parts->vtoc.v_part[I_PARTITION].p_size = 429 cur_parts->pinfo_map[I_PARTITION].dkl_nblk; 430 431 #endif /* defined(_SUNOS_VTOC_16) */ 432 parts = cur_dtype->dtype_plist; 433 cur_dtype->dtype_ncyl = ncyl; 434 cur_dtype->dtype_plist = cur_parts; 435 parts->pinfo_name = cur_parts->pinfo_name; 436 cur_disk->disk_parts = cur_parts; 437 cur_ctype->ctype_dlist = cur_dtype; 438 439 } 440 #endif /* DEADCODE */ 441 442 static int 443 get_solaris_part(int fd, struct ipart *ipart) 444 { 445 int i; 446 struct ipart ip; 447 int status; 448 char *mbr; 449 char *bootptr; 450 struct dk_label update_label; 451 ushort_t found = 0; 452 #ifdef i386 453 uint32_t relsec, numsec; 454 int pno, rval, ext_part_found = 0; 455 ext_part_t *epp; 456 #endif 457 458 (void) lseek(fd, 0, 0); 459 460 /* 461 * We may get mbr of different size, but the first 512 bytes 462 * are valid information. 463 */ 464 mbr = malloc(cur_blksz); 465 if (mbr == NULL) { 466 err_print("No memory available.\n"); 467 return (-1); 468 } 469 status = read(fd, mbr, cur_blksz); 470 471 if (status != cur_blksz) { 472 err_print("Bad read of fdisk partition. Status = %x\n", status); 473 err_print("Cannot read fdisk partition information.\n"); 474 free(mbr); 475 return (-1); 476 } 477 478 (void) memcpy(&boot_sec, mbr, sizeof (struct mboot)); 479 free(mbr); 480 481 #ifdef i386 482 (void) extpart_init(&epp); 483 #endif 484 for (i = 0; i < FD_NUMPART; i++) { 485 int ipc; 486 487 ipc = i * sizeof (struct ipart); 488 489 /* Handling the alignment problem of struct ipart */ 490 bootptr = &boot_sec.parts[ipc]; 491 (void) fill_ipart(bootptr, &ip); 492 493 #ifdef i386 494 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) { 495 /* We support only one extended partition per disk */ 496 ext_part_found = 1; 497 rval = fdisk_get_solaris_part(epp, &pno, &relsec, 498 &numsec); 499 if (rval == FDISK_SUCCESS) { 500 /* 501 * Found a solaris partition inside the 502 * extended partition. Update the statistics. 503 */ 504 if (nhead != 0 && nsect != 0) { 505 pcyl = numsec / (nhead * nsect); 506 xstart = relsec / (nhead * nsect); 507 ncyl = pcyl - acyl; 508 } 509 solaris_offset = relsec; 510 found = 2; 511 ip.bootid = 0; 512 ip.beghead = ip.begsect = ip.begcyl = 0xff; 513 ip.endhead = ip.endsect = ip.endcyl = 0xff; 514 ip.systid = SUNIXOS2; 515 ip.relsect = relsec; 516 ip.numsect = numsec; 517 ipart->bootid = ip.bootid; 518 status = bcmp(&ip, ipart, 519 sizeof (struct ipart)); 520 bcopy(&ip, ipart, sizeof (struct ipart)); 521 } 522 continue; 523 } 524 #endif 525 526 /* 527 * we are interested in Solaris and EFI partition types 528 */ 529 #ifdef i386 530 if ((ip.systid == SUNIXOS && 531 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) || 532 ip.systid == SUNIXOS2 || 533 ip.systid == EFI_PMBR) { 534 #else 535 if (ip.systid == SUNIXOS || 536 ip.systid == SUNIXOS2 || 537 ip.systid == EFI_PMBR) { 538 #endif 539 /* 540 * if the disk has an EFI label, nhead and nsect may 541 * be zero. This test protects us from FPE's, and 542 * format still seems to work fine 543 */ 544 if (nhead != 0 && nsect != 0) { 545 pcyl = lel(ip.numsect) / (nhead * nsect); 546 xstart = lel(ip.relsect) / (nhead * nsect); 547 ncyl = pcyl - acyl; 548 } 549 #ifdef DEBUG 550 else { 551 err_print("Critical geometry values are zero:\n" 552 "\tnhead = %d; nsect = %d\n", nhead, nsect); 553 } 554 #endif /* DEBUG */ 555 556 solaris_offset = (uint_t)lel(ip.relsect); 557 found = 1; 558 break; 559 } 560 } 561 562 #ifdef i386 563 libfdisk_fini(&epp); 564 #endif 565 566 if (!found) { 567 err_print("Solaris fdisk partition not found\n"); 568 return (-1); 569 } else if (found == 1) { 570 /* 571 * Found a primary solaris partition. 572 * compare the previous and current Solaris partition 573 * but don't use bootid in determination of Solaris partition 574 * changes 575 */ 576 ipart->bootid = ip.bootid; 577 status = bcmp(&ip, ipart, sizeof (struct ipart)); 578 579 bcopy(&ip, ipart, sizeof (struct ipart)); 580 } 581 582 /* if the disk partitioning has changed - get the VTOC */ 583 if (status) { 584 struct extvtoc exvtoc; 585 struct vtoc vtoc; 586 587 status = ioctl(fd, DKIOCGEXTVTOC, &exvtoc); 588 if (status == -1) { 589 i = errno; 590 /* Try the old ioctl DKIOCGVTOC */ 591 status = ioctl(fd, DKIOCGVTOC, &vtoc); 592 if (status == -1) { 593 err_print("Bad ioctl DKIOCGEXTVTOC.\n"); 594 err_print("errno=%d %s\n", i, strerror(i)); 595 err_print("Cannot read vtoc information.\n"); 596 return (-1); 597 } 598 } 599 600 status = read_label(fd, &update_label); 601 if (status == -1) { 602 err_print("Cannot read label information.\n"); 603 return (-1); 604 } 605 606 /* copy vtoc information */ 607 cur_parts->vtoc = update_label.dkl_vtoc; 608 609 #if defined(_SUNOS_VTOC_16) 610 /* 611 * this is to update the slice table on x86 612 * we don't care about VTOC8 here 613 */ 614 for (i = 0; i < NDKMAP; i ++) { 615 cur_parts->pinfo_map[i].dkl_cylno = 616 update_label.dkl_vtoc.v_part[i].p_start / 617 ((int)(update_label.dkl_nhead * 618 update_label.dkl_nsect)); 619 cur_parts->pinfo_map[i].dkl_nblk = 620 update_label.dkl_vtoc.v_part[i].p_size; 621 } 622 #endif /* defined(_SUNOS_VTOC_16) */ 623 624 cur_dtype->dtype_ncyl = update_label.dkl_ncyl; 625 cur_dtype->dtype_pcyl = update_label.dkl_pcyl; 626 cur_dtype->dtype_acyl = update_label.dkl_acyl; 627 cur_dtype->dtype_nhead = update_label.dkl_nhead; 628 cur_dtype->dtype_nsect = update_label.dkl_nsect; 629 ncyl = cur_dtype->dtype_ncyl; 630 acyl = cur_dtype->dtype_acyl; 631 pcyl = cur_dtype->dtype_pcyl; 632 nsect = cur_dtype->dtype_nsect; 633 nhead = cur_dtype->dtype_nhead; 634 } 635 return (0); 636 } 637 638 639 int 640 copy_solaris_part(struct ipart *ipart) 641 { 642 643 int status, i, fd; 644 struct mboot mboot; 645 char *mbr; 646 struct ipart ip; 647 char buf[MAXPATHLEN]; 648 char *bootptr; 649 struct stat statbuf; 650 #ifdef i386 651 uint32_t relsec, numsec; 652 int pno, rval, ext_part_found = 0; 653 ext_part_t *epp; 654 #endif 655 656 (void) get_pname(&buf[0]); 657 if (stat(buf, &statbuf) == -1 || 658 !S_ISCHR(statbuf.st_mode) || 659 ((cur_label == L_TYPE_EFI) && 660 (cur_disk->disk_flags & DSK_LABEL_DIRTY))) { 661 /* 662 * Make sure to reset solaris_offset to zero if it is 663 * previously set by a selected disk that 664 * supports the fdisk table. 665 */ 666 solaris_offset = 0; 667 /* 668 * Return if this disk does not support fdisk table or 669 * if it uses an EFI label but has not yet been labelled. 670 * If the EFI label has not been written then the open 671 * on the partition will fail. 672 */ 673 return (0); 674 } 675 676 if ((fd = open(buf, O_RDONLY)) < 0) { 677 err_print("Error: can't open disk '%s'.\n", buf); 678 return (-1); 679 } 680 681 /* 682 * We may get mbr of different size, but the first 512 bytes 683 * are valid information. 684 */ 685 mbr = malloc(cur_blksz); 686 if (mbr == NULL) { 687 err_print("No memory available.\n"); 688 return (-1); 689 } 690 status = read(fd, mbr, cur_blksz); 691 692 if (status != cur_blksz) { 693 err_print("Bad read of fdisk partition.\n"); 694 (void) close(fd); 695 free(mbr); 696 return (-1); 697 } 698 699 (void) memcpy(&mboot, mbr, sizeof (struct mboot)); 700 701 #ifdef i386 702 (void) extpart_init(&epp); 703 #endif 704 for (i = 0; i < FD_NUMPART; i++) { 705 int ipc; 706 707 ipc = i * sizeof (struct ipart); 708 709 /* Handling the alignment problem of struct ipart */ 710 bootptr = &mboot.parts[ipc]; 711 (void) fill_ipart(bootptr, &ip); 712 713 #ifdef i386 714 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) { 715 /* We support only one extended partition per disk */ 716 ext_part_found = 1; 717 rval = fdisk_get_solaris_part(epp, &pno, &relsec, 718 &numsec); 719 if (rval == FDISK_SUCCESS) { 720 /* 721 * Found a solaris partition inside the 722 * extended partition. Update the statistics. 723 */ 724 if (nhead != 0 && nsect != 0) { 725 pcyl = numsec / (nhead * nsect); 726 ncyl = pcyl - acyl; 727 } 728 solaris_offset = relsec; 729 ip.bootid = 0; 730 ip.beghead = ip.begsect = ip.begcyl = 0xff; 731 ip.endhead = ip.endsect = ip.endcyl = 0xff; 732 ip.systid = SUNIXOS2; 733 ip.relsect = relsec; 734 ip.numsect = numsec; 735 bcopy(&ip, ipart, sizeof (struct ipart)); 736 } 737 continue; 738 } 739 #endif 740 741 742 #ifdef i386 743 if ((ip.systid == SUNIXOS && 744 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) || 745 ip.systid == SUNIXOS2 || 746 ip.systid == EFI_PMBR) { 747 #else 748 if (ip.systid == SUNIXOS || 749 ip.systid == SUNIXOS2 || 750 ip.systid == EFI_PMBR) { 751 #endif 752 solaris_offset = lel(ip.relsect); 753 bcopy(&ip, ipart, sizeof (struct ipart)); 754 755 /* 756 * if the disk has an EFI label, we typically won't 757 * have values for nhead and nsect. format seems to 758 * work without them, and we need to protect ourselves 759 * from FPE's 760 */ 761 if (nhead != 0 && nsect != 0) { 762 pcyl = lel(ip.numsect) / (nhead * nsect); 763 ncyl = pcyl - acyl; 764 } 765 #ifdef DEBUG 766 else { 767 err_print("Critical geometry values are zero:\n" 768 "\tnhead = %d; nsect = %d\n", nhead, nsect); 769 } 770 #endif /* DEBUG */ 771 772 break; 773 } 774 } 775 #ifdef i386 776 libfdisk_fini(&epp); 777 #endif 778 779 (void) close(fd); 780 free(mbr); 781 return (0); 782 } 783 784 #if defined(_FIRMWARE_NEEDS_FDISK) 785 int 786 auto_solaris_part(struct dk_label *label) 787 { 788 789 int status, i, fd; 790 struct mboot mboot; 791 char *mbr; 792 struct ipart ip; 793 char *bootptr; 794 char pbuf[MAXPATHLEN]; 795 #ifdef i386 796 uint32_t relsec, numsec; 797 int pno, rval, ext_part_found = 0; 798 ext_part_t *epp; 799 #endif 800 801 (void) get_pname(&pbuf[0]); 802 if ((fd = open_disk(pbuf, O_RDONLY)) < 0) { 803 err_print("Error: can't open selected disk '%s'.\n", pbuf); 804 return (-1); 805 } 806 807 /* 808 * We may get mbr of different size, but the first 512 bytes 809 * are valid information. 810 */ 811 mbr = malloc(cur_blksz); 812 if (mbr == NULL) { 813 err_print("No memory available.\n"); 814 return (-1); 815 } 816 status = read(fd, mbr, cur_blksz); 817 818 if (status != cur_blksz) { 819 err_print("Bad read of fdisk partition.\n"); 820 free(mbr); 821 return (-1); 822 } 823 824 (void) memcpy(&mboot, mbr, sizeof (struct mboot)); 825 826 #ifdef i386 827 (void) extpart_init(&epp); 828 #endif 829 for (i = 0; i < FD_NUMPART; i++) { 830 int ipc; 831 832 ipc = i * sizeof (struct ipart); 833 834 /* Handling the alignment problem of struct ipart */ 835 bootptr = &mboot.parts[ipc]; 836 (void) fill_ipart(bootptr, &ip); 837 838 #ifdef i386 839 if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) { 840 /* We support only one extended partition per disk */ 841 ext_part_found = 1; 842 rval = fdisk_get_solaris_part(epp, &pno, &relsec, 843 &numsec); 844 if (rval == FDISK_SUCCESS) { 845 /* 846 * Found a solaris partition inside the 847 * extended partition. Update the statistics. 848 */ 849 if ((label->dkl_nhead != 0) && 850 (label->dkl_nsect != 0)) { 851 label->dkl_pcyl = 852 numsec / (label->dkl_nhead * 853 label->dkl_nsect); 854 label->dkl_ncyl = label->dkl_pcyl - 855 label->dkl_acyl; 856 } 857 solaris_offset = relsec; 858 } 859 continue; 860 } 861 #endif 862 863 /* 864 * if the disk has an EFI label, the nhead and nsect fields 865 * the label may be zero. This protects us from FPE's, and 866 * format still seems to work happily 867 */ 868 869 870 #ifdef i386 871 if ((ip.systid == SUNIXOS && 872 (fdisk_is_linux_swap(epp, lel(ip.relsect), NULL) != 0)) || 873 ip.systid == SUNIXOS2 || 874 ip.systid == EFI_PMBR) { 875 #else 876 if (ip.systid == SUNIXOS || 877 ip.systid == SUNIXOS2 || 878 ip.systid == EFI_PMBR) { 879 #endif 880 if ((label->dkl_nhead != 0) && 881 (label->dkl_nsect != 0)) { 882 label->dkl_pcyl = lel(ip.numsect) / 883 (label->dkl_nhead * label->dkl_nsect); 884 label->dkl_ncyl = label->dkl_pcyl - 885 label->dkl_acyl; 886 } 887 #ifdef DEBUG 888 else { 889 err_print("Critical label fields aren't " 890 "non-zero:\n" 891 "\tlabel->dkl_nhead = %d; " 892 "label->dkl_nsect = " 893 "%d\n", label->dkl_nhead, 894 label->dkl_nsect); 895 } 896 #endif /* DEBUG */ 897 898 solaris_offset = lel(ip.relsect); 899 break; 900 } 901 } 902 903 #ifdef i386 904 libfdisk_fini(&epp); 905 #endif 906 (void) close(fd); 907 free(mbr); 908 return (0); 909 } 910 #endif /* defined(_FIRMWARE_NEEDS_FDISK) */ 911 912 913 int 914 good_fdisk() 915 { 916 char buf[MAXPATHLEN]; 917 struct stat statbuf; 918 919 (void) get_pname(&buf[0]); 920 if (stat(buf, &statbuf) == -1 || 921 !S_ISCHR(statbuf.st_mode) || 922 cur_label == L_TYPE_EFI) { 923 /* 924 * Return if this disk does not support fdisk table or 925 * if the disk is labeled with EFI. 926 */ 927 return (1); 928 } 929 930 if (lel(cur_disk->fdisk_part.numsect) > 0) { 931 return (1); 932 } else { 933 err_print("WARNING - "); 934 err_print("This disk may be in use by an application " 935 "that has\n\t modified the fdisk table. Ensure " 936 "that this disk is\n\t not currently in use " 937 "before proceeding to use fdisk.\n"); 938 return (0); 939 } 940 } 941 942 #ifdef i386 943 int 944 extpart_init(ext_part_t **epp) 945 { 946 int rval, lf_op_flag = 0; 947 char p0_path[MAXPATHLEN]; 948 949 get_pname(&p0_path[0]); 950 lf_op_flag |= FDISK_READ_DISK; 951 if ((rval = libfdisk_init(epp, p0_path, NULL, lf_op_flag)) != 952 FDISK_SUCCESS) { 953 switch (rval) { 954 /* 955 * FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE 956 * and FDISK_EBADMAGIC can be considered 957 * as soft errors and hence we do not exit. 958 */ 959 case FDISK_EBADLOGDRIVE: 960 break; 961 case FDISK_ENOLOGDRIVE: 962 break; 963 case FDISK_EBADMAGIC: 964 break; 965 case FDISK_ENOVGEOM: 966 err_print("Could not get virtual geometry for" 967 " this device\n"); 968 fullabort(); 969 break; 970 case FDISK_ENOPGEOM: 971 err_print("Could not get physical geometry for" 972 " this device\n"); 973 fullabort(); 974 break; 975 case FDISK_ENOLGEOM: 976 err_print("Could not get label geometry for " 977 " this device\n"); 978 fullabort(); 979 break; 980 default: 981 err_print("Failed to initialise libfdisk.\n"); 982 fullabort(); 983 break; 984 } 985 } 986 return (0); 987 } 988 #endif 989