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