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