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 /* 23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 29 /* All Rights Reserved */ 30 31 /* Copyright (c) 1987, 1988 Microsoft Corporation */ 32 /* All Rights Reserved */ 33 34 /* 35 * PROGRAM: fdisk(1M) 36 * This program reads the partition table on the specified device and 37 * also reads the drive parameters. The user can perform various 38 * operations from a supplied menu or from the command line. Diagnostic 39 * options are also available. 40 */ 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <ctype.h> 48 #include <sys/stat.h> 49 #include <sys/types.h> 50 #include <limits.h> 51 #include <sys/param.h> 52 #include <sys/systeminfo.h> 53 #include <sys/efi_partition.h> 54 #include <sys/byteorder.h> 55 #include <sys/systeminfo.h> 56 57 #include <sys/dktp/fdisk.h> 58 #include <sys/dkio.h> 59 #include <sys/vtoc.h> 60 #ifdef i386 61 #include <sys/tty.h> 62 #include <libfdisk.h> 63 #endif 64 65 #define CLR_SCR "[1;1H[0J" 66 #define CLR_LIN "[0K" 67 #define HOME "[1;1H[0K[2;1H[0K[3;1H[0K[4;1H[0K[5;1H[0K" \ 68 "[6;1H[0K[7;1H[0K[8;1H[0K[9;1H[0K[10;1H[0K[1;1H" 69 #define Q_LINE "[22;1H[0K[21;1H[0K[20;1H[0K" 70 71 #ifdef i386 72 #define W_LINE "[11;1H[0K" 73 #else 74 #define W_LINE "[12;1H[0K[11;1H[0K" 75 #endif 76 77 #define E_LINE "[24;1H[0K[23;1H[0K" 78 79 #ifdef i386 80 #define M_LINE "[12;1H[0K[13;1H[0K[14;1H[0K[15;1H[0K" \ 81 "[16;1H[0K[17;1H[0K[18;1H[0K[19;1H[0K[12;1H" 82 #else 83 #define M_LINE "[13;1H[0K[14;1H[0K[15;1H[0K[16;1H[0K[17;1H" \ 84 "[0K[18;1H[0K[19;1H[0K[13;1H" 85 #endif 86 87 #define T_LINE "[1;1H[0K" 88 89 #define DEFAULT_PATH "/dev/rdsk/" 90 91 /* XXX - should be in fdisk.h, used by sd as well */ 92 93 /* 94 * the MAX values are the maximum usable values for BIOS chs values 95 * The MAX_CYL value of 1022 is the maximum usable value 96 * the value of 1023 is a fence value, 97 * indicating no CHS geometry exists for the corresponding LBA value. 98 * HEAD range [ 0 .. MAX_HEAD ], so number of heads is (MAX_HEAD + 1) 99 * SECT range [ 1 .. MAX_SECT ], so number of sectors is (MAX_SECT) 100 */ 101 #define MAX_SECT (63) 102 #define MAX_CYL (1022) 103 #define MAX_HEAD (254) 104 105 #define DK_MAX_2TB UINT32_MAX /* Max # of sectors in 2TB */ 106 107 /* for clear_vtoc() */ 108 #define OLD 0 109 #define NEW 1 110 111 /* readvtoc/writevtoc return codes */ 112 #define VTOC_OK 0 /* Good VTOC */ 113 #define VTOC_INVAL 1 /* invalid VTOC */ 114 #define VTOC_NOTSUP 2 /* operation not supported - EFI label */ 115 #define VTOC_RWERR 3 /* couldn't read or write VTOC */ 116 117 /* 118 * Support for fdisk(1M) on the SPARC platform 119 * In order to convert little endian values to big endian for SPARC, 120 * byte/short and long values must be swapped. 121 * These swapping macros will be used to access information in the 122 * mboot and ipart structures. 123 */ 124 125 #ifdef sparc 126 #define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF)) 127 #define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \ 128 (les((unsigned)((val)&0xffff0000)>>16))) 129 #else 130 #define les(val) (val) 131 #define lel(val) (val) 132 #endif 133 134 #if defined(_SUNOS_VTOC_16) 135 #define VTOC_OFFSET 1 136 #elif defined(_SUNOS_VTOC_8) 137 #define VTOC_OFFSET 0 138 #else 139 #error No VTOC format defined. 140 #endif 141 142 #ifdef i386 143 #define FDISK_KB (1024) 144 #define FDISK_MB (FDISK_KB * 1024) 145 #define FDISK_GB (FDISK_MB * 1024) 146 #define TRUE 1 147 148 #define FDISK_MAX_VALID_PART_ID 255 149 #define FDISK_MAX_VALID_PART_NUM_DIGITS 2 150 #define FDISK_MAX_VALID_PART_ID_DIGITS 3 151 152 /* Maximum number of digits for a valid partition size */ 153 #define FDISK_MAX_VALID_CYL_NUM_DIGITS 10 154 155 /* Minimum partition size in cylinders */ 156 #define FDISK_MIN_PART_SIZE 1 157 #endif 158 159 static char Usage[] = "Usage: fdisk\n" 160 "[ -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n" 161 "[ -b masterboot ]\n" 162 "[ -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n" 163 "[ -F fdisk_file ] [ -h ] [ -o offset ] [ -P fill_patt ] [ -s size ]\n" 164 "[ -S geom_file ] [ [ -v ] -W { creat_fdisk_file | - } ]\n" 165 "[ -w | r | d | n | I | B | E | g | G | R | t | T ] rdevice"; 166 167 static char Usage1[] = " Partition options:\n" 168 " -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n" 169 " Create a partition with specific attributes:\n" 170 " id = system id number (fdisk.h) for the partition type\n" 171 " act = active partition flag (0 is off and 128 is on)\n" 172 " bhead = beginning head for start of partition\n" 173 " bsect = beginning sector for start of partition\n" 174 " bcyl = beginning cylinder for start of partition\n" 175 " ehead = ending head for end of partition\n" 176 " esect = ending sector for end of partition\n" 177 " ecyl = ending cylinder for end of partition\n" 178 " rsect = sector number from start of disk for\n" 179 " start of partition\n" 180 " numsect = partition size in sectors\n" 181 " -b master_boot\n" 182 " Use master_boot as the master boot file.\n" 183 " -B Create one Solaris partition that uses the entire disk.\n" 184 " -E Create one EFI partition that uses the entire disk.\n" 185 " -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n" 186 " Delete a partition. See attribute definitions for -A.\n" 187 " -F fdisk_file\n" 188 " Use fdisk_file to initialize on-line fdisk table.\n" 189 " -I Forego device checks. Generate a file image of what would go\n" 190 " on a disk using the geometry specified with the -S option.\n" 191 " -n Do not run in interactive mode.\n" 192 " -R Open the disk device as read-only.\n" 193 " -t Check and adjust VTOC to be consistent with fdisk table.\n" 194 " VTOC slices exceeding the partition size will be truncated.\n" 195 " -T Check and adjust VTOC to be consistent with fdisk table.\n" 196 " VTOC slices exceeding the partition size will be removed.\n" 197 " -W fdisk_file\n" 198 " Write on-disk table to fdisk_file.\n" 199 " -W - Write on-disk table to standard output.\n" 200 " -v Display virtual geometry. Must be used with the -W option.\n" 201 " Diagnostic options:\n" 202 " -d Activate debug information about progress.\n" 203 " -g Write label geometry to standard output:\n" 204 " PCYL number of physical cylinders\n" 205 " NCYL number of usable cylinders\n" 206 " ACYL number of alternate cylinders\n" 207 " BCYL cylinder offset\n" 208 " NHEADS number of heads\n" 209 " NSECTORS number of sectors per track\n" 210 " SECTSIZ size of a sector in bytes\n" 211 " -G Write physical geometry to standard output (see -g).\n" 212 " -h Issue this verbose help message.\n" 213 " -o offset\n" 214 " Block offset from start of disk (default 0). Ignored if\n" 215 " -P # specified.\n" 216 " -P fill_patt\n" 217 " Fill disk with pattern fill_patt. fill_patt can be decimal or\n" 218 " hexadecimal and is used as number for constant long word\n" 219 " pattern. If fill_patt is \"#\" then pattern of block #\n" 220 " for each block. Pattern is put in each block as long words\n" 221 " and fills each block (see -o and -s).\n" 222 " -r Read from a disk to stdout (see -o and -s).\n" 223 " -s size Number of blocks on which to perform operation (see -o).\n" 224 " -S geom_file\n" 225 " Use geom_file to set the label geometry (see -g).\n" 226 " -w Write to a disk from stdin (see -o and -s)."; 227 228 static char Ostr[] = "Other OS"; 229 static char Dstr[] = "DOS12"; 230 static char D16str[] = "DOS16"; 231 static char DDstr[] = "DOS-DATA"; 232 static char EDstr[] = "EXT-DOS"; 233 static char DBstr[] = "DOS-BIG"; 234 static char PCstr[] = "PCIX"; 235 static char Ustr[] = "UNIX System"; 236 static char SUstr[] = "Solaris"; 237 static char SU2str[] = "Solaris2"; 238 static char X86str[] = "x86 Boot"; 239 static char DIAGstr[] = "Diagnostic"; 240 static char IFSstr[] = "IFS: NTFS"; 241 static char AIXstr[] = "AIX Boot"; 242 static char AIXDstr[] = "AIX Data"; 243 static char OS2str[] = "OS/2 Boot"; 244 static char WINstr[] = "Win95 FAT32"; 245 static char EWINstr[] = "Ext Win95"; 246 static char FAT95str[] = "FAT16 LBA"; 247 static char EXTLstr[] = "EXT LBA"; 248 static char LINUXstr[] = "Linux"; 249 static char CPMstr[] = "CP/M"; 250 static char NOV2str[] = "Netware 286"; 251 static char NOVstr[] = "Netware 3.x+"; 252 static char QNXstr[] = "QNX 4.x"; 253 static char QNX2str[] = "QNX part 2"; 254 static char QNX3str[] = "QNX part 3"; 255 static char LINNATstr[] = "Linux native"; 256 static char LINSWAPstr[] = "Linux swap"; 257 static char NTFSVOL1str[] = "NT volset 1"; 258 static char NTFSVOL2str[] = "NT volset 2"; 259 static char BSDstr[] = "BSD OS"; 260 static char NEXTSTEPstr[] = "NeXTSTEP"; 261 static char BSDIFSstr[] = "BSDI FS"; 262 static char BSDISWAPstr[] = "BSDI swap"; 263 static char Actvstr[] = "Active"; 264 static char EFIstr[] = "EFI"; 265 static char NAstr[] = " "; 266 267 /* All the user options and flags */ 268 static char *Dfltdev; /* name of fixed disk drive */ 269 270 /* Diagnostic options */ 271 static int io_wrt = 0; /* write stdin to disk (-w) */ 272 static int io_rd = 0; /* read disk and write stdout (-r) */ 273 static char *io_fatt; /* user supplied pattern (-P pattern) */ 274 static int io_patt = 0; /* write pattern to disk (-P pattern) */ 275 static int io_lgeom = 0; /* get label geometry (-g) */ 276 static int io_pgeom = 0; /* get drive physical geometry (-G) */ 277 static char *io_sgeom = 0; /* set label geometry (-S geom_file) */ 278 static int io_readonly = 0; /* do not write to disk (-R) */ 279 280 /* The -o offset and -s size options specify the area of the disk on */ 281 /* which to perform the particular operation; i.e., -P, -r, or -w. */ 282 static off_t io_offset = 0; /* offset sector (-o offset) */ 283 static off_t io_size = 0; /* size in sectors (-s size) */ 284 285 /* Partition table flags */ 286 static int v_flag = 0; /* virtual geometry-HBA flag (-v) */ 287 static int stdo_flag = 0; /* stdout flag (-W -) */ 288 static int io_fdisk = 0; /* do fdisk operation */ 289 static int io_ifdisk = 0; /* interactive partition */ 290 static int io_nifdisk = 0; /* non-interactive partition (-n) */ 291 292 static int io_adjt = 0; /* check/adjust VTOC (truncate (-t)) */ 293 static int io_ADJT = 0; /* check/adjust VTOC (delete (-T)) */ 294 static char *io_ffdisk = 0; /* input fdisk file name (-F file) */ 295 static char *io_Wfdisk = 0; /* output fdisk file name (-W file) */ 296 static char *io_Afdisk = 0; /* add entry to partition table (-A) */ 297 static char *io_Dfdisk = 0; /* delete entry from part. table (-D) */ 298 299 static char *io_mboot = 0; /* master boot record (-b boot_file) */ 300 301 static struct mboot BootCod; /* buffer for master boot record */ 302 303 static int io_wholedisk = 0; /* use whole disk for Solaris (-B) */ 304 static int io_EFIdisk = 0; /* use whole disk for EFI (-E) */ 305 static int io_debug = 0; /* activate verbose mode (-d) */ 306 static int io_image = 0; /* create image using geometry (-I) */ 307 308 static struct mboot *Bootblk; /* pointer to cut/paste sector zero */ 309 static char *Bootsect; /* pointer to sector zero buffer */ 310 static char *Nullsect; 311 static struct extvtoc disk_vtoc; /* verify VTOC table */ 312 static int vt_inval = 0; 313 static int no_virtgeom_ioctl = 0; /* ioctl for virtual geometry failed */ 314 static int no_physgeom_ioctl = 0; /* ioctl for physical geometry failed */ 315 316 static struct ipart Table[FD_NUMPART]; 317 static struct ipart Old_Table[FD_NUMPART]; 318 static int skip_verify[FD_NUMPART]; /* special case skip sz chk */ 319 320 /* Disk geometry information */ 321 static struct dk_minfo minfo; 322 static struct dk_geom disk_geom; 323 324 static int Dev; /* fd for open device */ 325 326 static diskaddr_t dev_capacity; /* number of blocks on device */ 327 static diskaddr_t chs_capacity; /* Numcyl_usable * heads * sectors */ 328 329 static int Numcyl_usable; /* Number of usable cylinders */ 330 /* used to limit fdisk to 2TB */ 331 332 /* Physical geometry for the drive */ 333 static int Numcyl; /* number of cylinders */ 334 static int heads; /* number of heads */ 335 static int sectors; /* number of sectors per track */ 336 static int acyl; /* number of alternate sectors */ 337 338 /* HBA (virtual) geometry for the drive */ 339 static int hba_Numcyl; /* number of cylinders */ 340 static int hba_heads; /* number of heads */ 341 static int hba_sectors; /* number of sectors per track */ 342 343 static int sectsiz; /* sector size */ 344 345 /* Load functions for fdisk table modification */ 346 #define LOADFILE 0 /* load fdisk from file */ 347 #define LOADDEL 1 /* delete an fdisk entry */ 348 #define LOADADD 2 /* add an fdisk entry */ 349 350 #define CBUFLEN 80 351 static char s[CBUFLEN]; 352 353 #ifdef i386 354 /* 355 * Complete list of all the 255 partition types. Some are unknown types 356 * and some entries are known to be unused. 357 * 358 * Courtesy of http://www.win.tue.nl/~aeb/partitions/partition_types-1.html 359 */ 360 char *fdisk_part_types[] = { 361 "Empty", /* 0 */ 362 "FAT12", /* 1 */ 363 "XENIX /", /* 2 */ 364 "XENIX /usr", /* 3 */ 365 "FAT16 (Upto 32M)", /* 4 */ 366 "DOS Extended", /* 5 */ 367 "FAT16 (>32M, HUGEDOS)", /* 6 */ 368 "IFS: NTFS", /* 7 */ 369 "AIX Boot/QNX(qny)", /* 8 */ 370 "AIX Data/QNX(qnz)", /* 9 */ 371 "OS/2 Boot/Coherent swap", /* 10 */ 372 "WIN95 FAT32(Upto 2047GB)", /* 11 */ 373 "WIN95 FAT32(LBA)", /* 12 */ 374 "Unused", /* 13 */ 375 "WIN95 FAT16(LBA)", /* 14 */ 376 "WIN95 Extended(LBA)", /* 15 */ 377 "OPUS", /* 16 */ 378 "Hidden FAT12", /* 17 */ 379 "Diagnostic", /* 18 */ 380 "Unknown", /* 19 */ 381 "Hidden FAT16(Upto 32M)", /* 20 */ 382 "Unknown", /* 21 */ 383 "Hidden FAT16(>=32M)", /* 22 */ 384 "Hidden IFS: HPFS", /* 23 */ 385 "AST SmartSleep Partition", /* 24 */ 386 "Unused/Willowtech Photon", /* 25 */ 387 "Unknown", /* 26 */ 388 "Hidden FAT32", /* 27 */ 389 "Hidden FAT32(LBA)", /* 28 */ 390 "Unused", /* 29 */ 391 "Hidden FAT16(LBA)", /* 30 */ 392 "Unknown", /* 31 */ 393 "Unused/OSF1", /* 32 */ 394 "Reserved/FSo2(Oxygen FS)", /* 33 */ 395 "Unused/(Oxygen EXT)", /* 34 */ 396 "Reserved", /* 35 */ 397 "NEC DOS 3.x", /* 36 */ 398 "Unknown", /* 37 */ 399 "Reserved", /* 38 */ 400 "Unknown", /* 39 */ 401 "Unknown", /* 40 */ 402 "Unknown", /* 41 */ 403 "AtheOS File System", /* 42 */ 404 "SyllableSecure", /* 43 */ 405 "Unknown", /* 44 */ 406 "Unknown", /* 45 */ 407 "Unknown", /* 46 */ 408 "Unknown", /* 47 */ 409 "Unknown", /* 48 */ 410 "Reserved", /* 49 */ 411 "NOS", /* 50 */ 412 "Reserved", /* 51 */ 413 "Reserved", /* 52 */ 414 "JFS on OS/2", /* 53 */ 415 "Reserved", /* 54 */ 416 "Unknown", /* 55 */ 417 "THEOS 3.2 2GB", /* 56 */ 418 "Plan9/THEOS 4", /* 57 */ 419 "THEOS 4 4GB", /* 58 */ 420 "THEOS 4 Extended", /* 59 */ 421 "PartitionMagic Recovery", /* 60 */ 422 "Hidden NetWare", /* 61 */ 423 "Unknown", /* 62 */ 424 "Unknown", /* 63 */ 425 "Venix 80286", /* 64 */ 426 "MINIX/PPC PReP Boot", /* 65 */ 427 "Win2K Dynamic Disk/SFS(DOS)", /* 66 */ 428 "Linux+DRDOS shared", /* 67 */ 429 "GoBack partition", /* 68 */ 430 "Boot-US boot manager", /* 69 */ 431 "EUMEL/Elan", /* 70 */ 432 "EUMEL/Elan", /* 71 */ 433 "EUMEL/Elan", /* 72 */ 434 "Unknown", /* 73 */ 435 "ALFS/THIN FS for DOS", /* 74 */ 436 "Unknown", /* 75 */ 437 "Oberon partition", /* 76 */ 438 "QNX 4,x", /* 77 */ 439 "QNX 4,x 2nd Part", /* 78 */ 440 "QNX 4,x 3rd Part", /* 79 */ 441 "OnTrack DM R/O, Lynx RTOS", /* 80 */ 442 "OnTrack DM R/W, Novell", /* 81 */ 443 "CP/M", /* 82 */ 444 "Disk Manager 6.0 Aux3", /* 83 */ 445 "Disk Manager 6.0 DDO", /* 84 */ 446 "EZ-Drive", /* 85 */ 447 "Golden Bow VFeature/AT&T MS-DOS", /* 86 */ 448 "DrivePro", /* 87 */ 449 "Unknown", /* 88 */ 450 "Unknown", /* 89 */ 451 "Unknown", /* 90 */ 452 "Unknown", /* 91 */ 453 "Priam EDisk", /* 92 */ 454 "Unknown", /* 93 */ 455 "Unknown", /* 94 */ 456 "Unknown", /* 95 */ 457 "Unknown", /* 96 */ 458 "SpeedStor", /* 97 */ 459 "Unknown", /* 98 */ 460 "Unix SysV, Mach, GNU Hurd", /* 99 */ 461 "PC-ARMOUR, Netware 286", /* 100 */ 462 "Netware 386", /* 101 */ 463 "Netware SMS", /* 102 */ 464 "Novell", /* 103 */ 465 "Novell", /* 104 */ 466 "Netware NSS", /* 105 */ 467 "Unknown", /* 106 */ 468 "Unknown", /* 107 */ 469 "Unknown", /* 108 */ 470 "Unknown", /* 109 */ 471 "Unknown", /* 110 */ 472 "Unknown", /* 111 */ 473 "DiskSecure Multi-Boot", /* 112 */ 474 "Reserved", /* 113 */ 475 "Unknown", /* 114 */ 476 "Reserved", /* 115 */ 477 "Scramdisk partition", /* 116 */ 478 "IBM PC/IX", /* 117 */ 479 "Reserved", /* 118 */ 480 "M2FS/M2CS,Netware VNDI", /* 119 */ 481 "XOSL FS", /* 120 */ 482 "Unknown", /* 121 */ 483 "Unknown", /* 122 */ 484 "Unknown", /* 123 */ 485 "Unknown", /* 124 */ 486 "Unknown", /* 125 */ 487 "Unused", /* 126 */ 488 "Unused", /* 127 */ 489 "MINIX until 1.4a", /* 128 */ 490 "MINIX since 1.4b, early Linux", /* 129 */ 491 "Solaris/Linux swap", /* 130 */ 492 "Linux native", /* 131 */ 493 "OS/2 hidden,Win Hibernation", /* 132 */ 494 "Linux extended", /* 133 */ 495 "Old Linux RAID,NT FAT16 RAID", /* 134 */ 496 "NTFS volume set", /* 135 */ 497 "Linux plaintext part table", /* 136 */ 498 "Unknown", /* 137 */ 499 "Linux Kernel Partition", /* 138 */ 500 "Fault Tolerant FAT32 volume", /* 139 */ 501 "Fault Tolerant FAT32 volume", /* 140 */ 502 "Free FDISK hidden PDOS FAT12", /* 141 */ 503 "Linux LVM partition", /* 142 */ 504 "Unknown", /* 143 */ 505 "Free FDISK hidden PDOS FAT16", /* 144 */ 506 "Free FDISK hidden DOS EXT", /* 145 */ 507 "Free FDISK hidden FAT16 Large", /* 146 */ 508 "Hidden Linux native, Amoeba", /* 147 */ 509 "Amoeba Bad Block Table", /* 148 */ 510 "MIT EXOPC Native", /* 149 */ 511 "Unknown", /* 150 */ 512 "Free FDISK hidden PDOS FAT32", /* 151 */ 513 "Free FDISK hidden FAT32 LBA", /* 152 */ 514 "DCE376 logical drive", /* 153 */ 515 "Free FDISK hidden FAT16 LBA", /* 154 */ 516 "Free FDISK hidden DOS EXT", /* 155 */ 517 "Unknown", /* 156 */ 518 "Unknown", /* 157 */ 519 "Unknown", /* 158 */ 520 "BSD/OS", /* 159 */ 521 "Laptop hibernation", /* 160 */ 522 "Laptop hibernate,HP SpeedStor", /* 161 */ 523 "Unknown", /* 162 */ 524 "HP SpeedStor", /* 163 */ 525 "HP SpeedStor", /* 164 */ 526 "BSD/386,386BSD,NetBSD,FreeBSD", /* 165 */ 527 "OpenBSD,HP SpeedStor", /* 166 */ 528 "NeXTStep", /* 167 */ 529 "Mac OS-X", /* 168 */ 530 "NetBSD", /* 169 */ 531 "Olivetti FAT12 1.44MB Service", /* 170 */ 532 "Mac OS-X Boot", /* 171 */ 533 "Unknown", /* 172 */ 534 "Unknown", /* 173 */ 535 "ShagOS filesystem", /* 174 */ 536 "ShagOS swap", /* 175 */ 537 "BootStar Dummy", /* 176 */ 538 "HP SpeedStor", /* 177 */ 539 "Unknown", /* 178 */ 540 "HP SpeedStor", /* 179 */ 541 "HP SpeedStor", /* 180 */ 542 "Unknown", /* 181 */ 543 "Corrupted FAT16 NT Mirror Set", /* 182 */ 544 "Corrupted NTFS NT Mirror Set", /* 183 */ 545 "Old BSDI BSD/386 swap", /* 184 */ 546 "Unknown", /* 185 */ 547 "Unknown", /* 186 */ 548 "Boot Wizard hidden", /* 187 */ 549 "Unknown", /* 188 */ 550 "Unknown", /* 189 */ 551 "Solaris x86 boot", /* 190 */ 552 "Solaris2", /* 191 */ 553 "REAL/32 or Novell DOS secured", /* 192 */ 554 "DRDOS/secured(FAT12)", /* 193 */ 555 "Hidden Linux", /* 194 */ 556 "Hidden Linux swap", /* 195 */ 557 "DRDOS/secured(FAT16,< 32M)", /* 196 */ 558 "DRDOS/secured(Extended)", /* 197 */ 559 "NT corrupted FAT16 volume", /* 198 */ 560 "NT corrupted NTFS volume", /* 199 */ 561 "DRDOS8.0+", /* 200 */ 562 "DRDOS8.0+", /* 201 */ 563 "DRDOS8.0+", /* 202 */ 564 "DRDOS7.04+ secured FAT32(CHS)", /* 203 */ 565 "DRDOS7.04+ secured FAT32(LBA)", /* 204 */ 566 "CTOS Memdump", /* 205 */ 567 "DRDOS7.04+ FAT16X(LBA)", /* 206 */ 568 "DRDOS7.04+ secure EXT DOS(LBA)", /* 207 */ 569 "REAL/32 secure big, MDOS", /* 208 */ 570 "Old MDOS secure FAT12", /* 209 */ 571 "Unknown", /* 210 */ 572 "Unknown", /* 211 */ 573 "Old MDOS secure FAT16 <32M", /* 212 */ 574 "Old MDOS secure EXT", /* 213 */ 575 "Old MDOS secure FAT16 >=32M", /* 214 */ 576 "Unknown", /* 215 */ 577 "CP/M-86", /* 216 */ 578 "Unknown", /* 217 */ 579 "Non-FS Data", /* 218 */ 580 "CP/M,Concurrent DOS,CTOS", /* 219 */ 581 "Unknown", /* 220 */ 582 "Hidden CTOS memdump", /* 221 */ 583 "Dell PowerEdge utilities(FAT)", /* 222 */ 584 "DG/UX virtual disk manager", /* 223 */ 585 "ST AVFS(STMicroelectronics)", /* 224 */ 586 "SpeedStor 12-bit FAT EXT", /* 225 */ 587 "Unknown", /* 226 */ 588 "SpeedStor", /* 227 */ 589 "SpeedStor 16-bit FAT EXT", /* 228 */ 590 "Tandy MSDOS", /* 229 */ 591 "Storage Dimensions SpeedStor", /* 230 */ 592 "Unknown", /* 231 */ 593 "Unknown", /* 232 */ 594 "Unknown", /* 233 */ 595 "Unknown", /* 234 */ 596 "BeOS BFS", /* 235 */ 597 "SkyOS SkyFS", /* 236 */ 598 "Unused", /* 237 */ 599 "EFI Header Indicator", /* 238 */ 600 "EFI Filesystem", /* 239 */ 601 "Linux/PA-RISC boot loader", /* 240 */ 602 "SpeedStor", /* 241 */ 603 "DOS 3.3+ secondary", /* 242 */ 604 "SpeedStor Reserved", /* 243 */ 605 "SpeedStor Large", /* 244 */ 606 "Prologue multi-volume", /* 245 */ 607 "SpeedStor", /* 246 */ 608 "Unused", /* 247 */ 609 "Unknown", /* 248 */ 610 "pCache", /* 249 */ 611 "Bochs", /* 250 */ 612 "VMware File System", /* 251 */ 613 "VMware swap", /* 252 */ 614 "Linux raid autodetect", /* 253 */ 615 "NT Disk Administrator hidden", /* 254 */ 616 "Xenix Bad Block Table" /* 255 */ 617 }; 618 619 /* Allowed extended partition menu options */ 620 static char ext_part_menu_opts[] = "adhipr"; 621 622 /* 623 * Structure holding all information about the extended partition 624 * NOTE : As of now, there will be just one instance of ext_part_t, since most 625 * known systems allow only one extended dos partition per disk. 626 */ 627 static ext_part_t *epp; 628 #endif 629 630 static void update_disk_and_exit(boolean_t table_changed); 631 int main(int argc, char *argv[]); 632 static int read_geom(char *sgeom); 633 static void dev_mboot_read(void); 634 static void dev_mboot_write(off_t sect, char *buff, int bootsiz); 635 static void mboot_read(void); 636 static void fill_patt(void); 637 static void abs_read(void); 638 static void abs_write(void); 639 static void load(int funct, char *file); 640 static void Set_Table_CHS_Values(int ti); 641 static int nopartdefined(); 642 static int insert_tbl(int id, int act, 643 int bhead, int bsect, int bcyl, 644 int ehead, int esect, int ecyl, 645 uint32_t rsect, uint32_t numsect, int startindex); 646 static int entry_from_old_table(int id, int act, 647 int bhead, int bsect, int bcyl, 648 int ehead, int esect, int ecyl, 649 uint32_t rsect, uint32_t numsect, int startindex); 650 static int verify_tbl(void); 651 static int pars_fdisk(char *line, 652 int *id, int *act, 653 int *bhead, int *bsect, int *bcyl, 654 int *ehead, int *esect, int *ecyl, 655 uint32_t *rsect, uint32_t *numsect); 656 static int validate_part(int id, uint32_t rsect, uint32_t numsect); 657 static void stage0(void); 658 static int pcreate(void); 659 static int specify(uchar_t tsystid); 660 static void dispmenu(void); 661 static int pchange(void); 662 static int ppartid(void); 663 static char pdelete(void); 664 static void rm_blanks(char *s); 665 static int getcyl(void); 666 static void disptbl(void); 667 static void print_Table(void); 668 static void copy_Table_to_Old_Table(void); 669 static void nulltbl(void); 670 static void copy_Bootblk_to_Table(void); 671 static void fill_ipart(char *bootptr, struct ipart *partp); 672 #ifdef sparc 673 uchar_t getbyte(char **bp); 674 uint32_t getlong(char **bp); 675 #endif 676 static void copy_Table_to_Bootblk(void); 677 static int TableChanged(void); 678 static void ffile_write(char *file); 679 static void fix_slice(void); 680 static int yesno(void); 681 static int readvtoc(void); 682 static int writevtoc(void); 683 static int efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc); 684 static int clear_efi(void); 685 static void clear_vtoc(int table, int part); 686 static int lecture_and_query(char *warning, char *devname); 687 static void sanity_check_provided_device(char *devname, int fd); 688 static char *get_node(char *devname); 689 690 #ifdef i386 691 static void id_to_name(uchar_t sysid, char *buffer); 692 static void ext_read_input(char *buf); 693 static int ext_read_options(char *buf); 694 static int ext_invalid_option(char ch); 695 static void ext_read_valid_part_num(int *pno); 696 static void ext_read_valid_part_id(uchar_t *partid); 697 static int ext_read_valid_partition_start(uint32_t *begsec); 698 static void ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec); 699 static void ext_part_menu(); 700 static void add_logical_drive(); 701 static void delete_logical_drive(); 702 static void ext_print_help_menu(); 703 static void ext_change_logical_drive_id(); 704 static void ext_print_part_types(); 705 static void ext_print_logical_drive_layout(); 706 static void preach_and_continue(); 707 #ifdef DEBUG 708 static void ext_print_logdrive_layout_debug(); 709 #endif /* DEBUG */ 710 #endif /* i386 */ 711 712 /* 713 * This function is called only during the non-interactive mode. 714 * It is touchy and does not tolerate any errors. If there are 715 * mounted logical drives, changes to the partition table 716 * is disallowed. 717 */ 718 static void 719 update_disk_and_exit(boolean_t table_changed) 720 { 721 #ifdef i386 722 int rval; 723 #endif 724 if (table_changed) { 725 /* 726 * Copy the new table back to the sector buffer 727 * and write it to disk 728 */ 729 copy_Table_to_Bootblk(); 730 dev_mboot_write(0, Bootsect, sectsiz); 731 } 732 733 /* If the VTOC table is wrong fix it (truncation only) */ 734 if (io_adjt) 735 fix_slice(); 736 737 #ifdef i386 738 if (!io_readonly) { 739 rval = fdisk_commit_ext_part(epp); 740 switch (rval) { 741 case FDISK_SUCCESS: 742 /* Success */ 743 break; 744 case FDISK_ENOEXTPART: 745 /* Nothing to do */ 746 break; 747 default: 748 fprintf(stderr, "Error in" 749 " fdisk_commit_ext_part\n"); 750 exit(rval); 751 } 752 } 753 libfdisk_fini(&epp); 754 #endif 755 exit(0); 756 } 757 758 /* 759 * main 760 * Process command-line options. 761 */ 762 int 763 main(int argc, char *argv[]) 764 { 765 int c, i; 766 extern int optind; 767 extern char *optarg; 768 int errflg = 0; 769 int diag_cnt = 0; 770 int openmode; 771 #ifdef i386 772 int rval; 773 int lf_op_flag = 0; 774 #endif 775 776 setbuf(stderr, 0); /* so all output gets out on exit */ 777 setbuf(stdout, 0); 778 779 /* Process the options. */ 780 while ((c = getopt(argc, argv, "o:s:P:F:b:A:D:W:S:tTIhwvrndgGRBE")) 781 != EOF) { 782 switch (c) { 783 784 case 'o': 785 io_offset = (off_t)strtoull(optarg, 0, 0); 786 continue; 787 case 's': 788 io_size = (off_t)strtoull(optarg, 0, 0); 789 continue; 790 case 'P': 791 diag_cnt++; 792 io_patt++; 793 io_fatt = optarg; 794 continue; 795 case 'w': 796 diag_cnt++; 797 io_wrt++; 798 continue; 799 case 'r': 800 diag_cnt++; 801 io_rd++; 802 continue; 803 case 'd': 804 io_debug++; 805 continue; 806 case 'I': 807 io_image++; 808 continue; 809 case 'R': 810 io_readonly++; 811 continue; 812 case 'S': 813 diag_cnt++; 814 io_sgeom = optarg; 815 continue; 816 case 'T': 817 io_ADJT++; 818 /* FALLTHRU */ 819 case 't': 820 io_adjt++; 821 continue; 822 case 'B': 823 io_wholedisk++; 824 io_fdisk++; 825 continue; 826 case 'E': 827 io_EFIdisk++; 828 io_fdisk++; 829 continue; 830 case 'g': 831 diag_cnt++; 832 io_lgeom++; 833 continue; 834 case 'G': 835 diag_cnt++; 836 io_pgeom++; 837 continue; 838 case 'n': 839 io_nifdisk++; 840 io_fdisk++; 841 continue; 842 case 'F': 843 io_fdisk++; 844 io_ffdisk = optarg; 845 continue; 846 case 'b': 847 io_mboot = optarg; 848 continue; 849 case 'W': 850 /* 851 * If '-' is the -W argument, then write 852 * to standard output, otherwise write 853 * to the specified file. 854 */ 855 if (strncmp(optarg, "-", 1) == 0) 856 stdo_flag = 1; 857 else 858 io_Wfdisk = optarg; 859 io_fdisk++; 860 continue; 861 case 'A': 862 io_fdisk++; 863 io_Afdisk = optarg; 864 continue; 865 case 'D': 866 io_fdisk++; 867 io_Dfdisk = optarg; 868 continue; 869 case 'h': 870 (void) fprintf(stderr, "%s\n", Usage); 871 (void) fprintf(stderr, "%s\n", Usage1); 872 exit(0); 873 /* FALLTHRU */ 874 case 'v': 875 v_flag = 1; 876 continue; 877 case '?': 878 errflg++; 879 break; 880 } 881 break; 882 } 883 884 if (io_image && io_sgeom && diag_cnt == 1) { 885 diag_cnt = 0; 886 } 887 888 /* User option checking */ 889 890 /* By default, run in interactive mode */ 891 if (!io_fdisk && !diag_cnt && !io_nifdisk) { 892 io_ifdisk++; 893 io_fdisk++; 894 } 895 if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) { 896 errflg++; 897 } 898 899 /* Was any error detected? */ 900 if (errflg || argc == optind) { 901 (void) fprintf(stderr, "%s\n", Usage); 902 (void) fprintf(stderr, 903 "\nDetailed help is available with the -h option.\n"); 904 exit(2); 905 } 906 907 908 /* Figure out the correct device node to open */ 909 Dfltdev = get_node(argv[optind]); 910 911 if (io_readonly) 912 openmode = O_RDONLY; 913 else 914 openmode = O_RDWR|O_CREAT; 915 916 if ((Dev = open(Dfltdev, openmode, 0666)) == -1) { 917 (void) fprintf(stderr, 918 "fdisk: Cannot open device %s.\n", 919 Dfltdev); 920 exit(1); 921 } 922 /* 923 * not all disk (or disklike) drivers support DKIOCGMEDIAINFO 924 * in that case leave the minfo structure zeroed 925 */ 926 if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) { 927 (void) memset(&minfo, 0, sizeof (minfo)); 928 } 929 930 /* Get the disk geometry */ 931 if (!io_image) { 932 /* Get disk's HBA (virtual) geometry */ 933 errno = 0; 934 if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) { 935 936 /* 937 * If ioctl isn't implemented on this platform, then 938 * turn off flag to print out virtual geometry (-v), 939 * otherwise use the virtual geometry. 940 */ 941 942 if (errno == ENOTTY) { 943 v_flag = 0; 944 no_virtgeom_ioctl = 1; 945 } else if (errno == EINVAL) { 946 /* 947 * This means that the ioctl exists, but 948 * is invalid for this disk, meaning the 949 * disk doesn't have an HBA geometry 950 * (like, say, it's larger than 8GB). 951 */ 952 v_flag = 0; 953 hba_Numcyl = hba_heads = hba_sectors = 0; 954 } else { 955 (void) fprintf(stderr, 956 "%s: Cannot get virtual disk geometry.\n", 957 argv[optind]); 958 exit(1); 959 } 960 } else { 961 /* save virtual geometry values obtained by ioctl */ 962 hba_Numcyl = disk_geom.dkg_ncyl; 963 hba_heads = disk_geom.dkg_nhead; 964 hba_sectors = disk_geom.dkg_nsect; 965 } 966 967 errno = 0; 968 if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) { 969 if (errno == ENOTTY) { 970 no_physgeom_ioctl = 1; 971 } else { 972 (void) fprintf(stderr, 973 "%s: Cannot get physical disk geometry.\n", 974 argv[optind]); 975 exit(1); 976 } 977 978 } 979 /* 980 * Call DKIOCGGEOM if the ioctls for physical and virtual 981 * geometry fail. Get both from this generic call. 982 */ 983 if (no_virtgeom_ioctl && no_physgeom_ioctl) { 984 errno = 0; 985 if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) { 986 (void) fprintf(stderr, 987 "%s: Cannot get disk label geometry.\n", 988 argv[optind]); 989 exit(1); 990 } 991 } 992 993 Numcyl = disk_geom.dkg_ncyl; 994 heads = disk_geom.dkg_nhead; 995 sectors = disk_geom.dkg_nsect; 996 997 if (minfo.dki_lbsize != 0) 998 sectsiz = minfo.dki_lbsize; 999 else 1000 sectsiz = 512; 1001 1002 acyl = disk_geom.dkg_acyl; 1003 1004 /* 1005 * if hba geometry was not set by DKIOC_VIRTGEOM 1006 * or we got an invalid hba geometry 1007 * then set hba geometry based on max values 1008 */ 1009 if (no_virtgeom_ioctl || 1010 disk_geom.dkg_ncyl == 0 || 1011 disk_geom.dkg_nhead == 0 || 1012 disk_geom.dkg_nsect == 0 || 1013 disk_geom.dkg_ncyl > MAX_CYL || 1014 disk_geom.dkg_nhead > MAX_HEAD || 1015 disk_geom.dkg_nsect > MAX_SECT) { 1016 1017 /* 1018 * turn off flag to print out virtual geometry (-v) 1019 */ 1020 v_flag = 0; 1021 hba_sectors = MAX_SECT; 1022 hba_heads = MAX_HEAD + 1; 1023 hba_Numcyl = (Numcyl * heads * sectors) / 1024 (hba_sectors * hba_heads); 1025 } 1026 1027 if (io_debug) { 1028 (void) fprintf(stderr, "Physical Geometry:\n"); 1029 (void) fprintf(stderr, 1030 " cylinders[%d] heads[%d] sectors[%d]\n" 1031 " sector size[%d] blocks[%d] mbytes[%d]\n", 1032 Numcyl, 1033 heads, 1034 sectors, 1035 sectsiz, 1036 Numcyl * heads * sectors, 1037 (Numcyl * heads * sectors * sectsiz) / 1048576); 1038 (void) fprintf(stderr, "Virtual (HBA) Geometry:\n"); 1039 (void) fprintf(stderr, 1040 " cylinders[%d] heads[%d] sectors[%d]\n" 1041 " sector size[%d] blocks[%d] mbytes[%d]\n", 1042 hba_Numcyl, 1043 hba_heads, 1044 hba_sectors, 1045 sectsiz, 1046 hba_Numcyl * hba_heads * hba_sectors, 1047 (hba_Numcyl * hba_heads * hba_sectors * sectsiz) / 1048 1048576); 1049 } 1050 } 1051 1052 /* If user has requested a geometry report just do it and exit */ 1053 if (io_lgeom) { 1054 if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) { 1055 (void) fprintf(stderr, 1056 "%s: Cannot get disk label geometry.\n", 1057 argv[optind]); 1058 exit(1); 1059 } 1060 Numcyl = disk_geom.dkg_ncyl; 1061 heads = disk_geom.dkg_nhead; 1062 sectors = disk_geom.dkg_nsect; 1063 if (minfo.dki_lbsize != 0) 1064 sectsiz = minfo.dki_lbsize; 1065 else 1066 sectsiz = 512; 1067 1068 acyl = disk_geom.dkg_acyl; 1069 (void) printf("* Label geometry for device %s\n", Dfltdev); 1070 (void) printf( 1071 "* PCYL NCYL ACYL BCYL NHEAD NSECT" 1072 " SECSIZ\n"); 1073 (void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n", 1074 Numcyl, 1075 disk_geom.dkg_ncyl, 1076 disk_geom.dkg_acyl, 1077 disk_geom.dkg_bcyl, 1078 heads, 1079 sectors, 1080 sectsiz); 1081 exit(0); 1082 } else if (io_pgeom) { 1083 if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) { 1084 (void) fprintf(stderr, 1085 "%s: Cannot get physical disk geometry.\n", 1086 argv[optind]); 1087 exit(1); 1088 } 1089 (void) printf("* Physical geometry for device %s\n", Dfltdev); 1090 (void) printf( 1091 "* PCYL NCYL ACYL BCYL NHEAD NSECT" 1092 " SECSIZ\n"); 1093 (void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n", 1094 disk_geom.dkg_pcyl, 1095 disk_geom.dkg_ncyl, 1096 disk_geom.dkg_acyl, 1097 disk_geom.dkg_bcyl, 1098 disk_geom.dkg_nhead, 1099 disk_geom.dkg_nsect, 1100 sectsiz); 1101 exit(0); 1102 } else if (io_sgeom) { 1103 if (read_geom(io_sgeom)) { 1104 exit(1); 1105 } else if (!io_image) { 1106 exit(0); 1107 } 1108 } 1109 1110 /* 1111 * some drivers may not support DKIOCGMEDIAINFO 1112 * in that case use CHS 1113 */ 1114 chs_capacity = (diskaddr_t)Numcyl * heads * sectors; 1115 dev_capacity = chs_capacity; 1116 Numcyl_usable = Numcyl; 1117 1118 if (chs_capacity > DK_MAX_2TB) { 1119 /* limit to 2TB */ 1120 Numcyl_usable = DK_MAX_2TB / (heads * sectors); 1121 chs_capacity = (diskaddr_t)Numcyl_usable * heads * sectors; 1122 } 1123 1124 if (minfo.dki_capacity > 0) 1125 dev_capacity = minfo.dki_capacity; 1126 1127 /* Allocate memory to hold three complete sectors */ 1128 Bootsect = (char *)calloc(3 * sectsiz, 1); 1129 if (Bootsect == NULL) { 1130 (void) fprintf(stderr, 1131 "fdisk: Unable to obtain enough buffer memory" 1132 " (%d bytes).\n", 1133 3 * sectsiz); 1134 exit(1); 1135 } 1136 1137 Nullsect = Bootsect + sectsiz; 1138 /* Zero out the "NULL" sector */ 1139 for (i = 0; i < sectsiz; i++) { 1140 Nullsect[i] = 0; 1141 } 1142 1143 /* Find out what the user wants done */ 1144 if (io_rd) { /* abs disk read */ 1145 abs_read(); /* will not return */ 1146 } else if (io_wrt && !io_readonly) { 1147 abs_write(); /* will not return */ 1148 } else if (io_patt && !io_readonly) { 1149 fill_patt(); /* will not return */ 1150 } 1151 1152 1153 /* This is the fdisk edit, the real reason for the program. */ 1154 1155 sanity_check_provided_device(Dfltdev, Dev); 1156 1157 /* Get the new BOOT program in case we write a new fdisk table */ 1158 mboot_read(); 1159 1160 /* Read from disk master boot */ 1161 dev_mboot_read(); 1162 1163 /* 1164 * Verify and copy the device's fdisk table. This will be used 1165 * as the prototype mboot if the device's mboot looks invalid. 1166 */ 1167 Bootblk = (struct mboot *)Bootsect; 1168 copy_Bootblk_to_Table(); 1169 1170 /* save away a copy of Table in Old_Table for sensing changes */ 1171 copy_Table_to_Old_Table(); 1172 1173 #ifdef i386 1174 /* 1175 * Read extended partition only when the fdisk table is not 1176 * supplied from a file 1177 */ 1178 if (!io_ffdisk) { 1179 lf_op_flag |= FDISK_READ_DISK; 1180 } 1181 if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag)) 1182 != FDISK_SUCCESS) { 1183 switch (rval) { 1184 /* 1185 * FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE and 1186 * FDISK_EBADMAGIC can be considered as 1187 * soft errors and hence we do not exit 1188 */ 1189 case FDISK_EBADLOGDRIVE: 1190 break; 1191 case FDISK_ENOLOGDRIVE: 1192 break; 1193 case FDISK_EBADMAGIC: 1194 break; 1195 case FDISK_ENOVGEOM: 1196 fprintf(stderr, "Could not get virtual" 1197 " geometry for this device\n"); 1198 libfdisk_fini(&epp); 1199 exit(1); 1200 break; 1201 case FDISK_ENOPGEOM: 1202 fprintf(stderr, "Could not get physical" 1203 " geometry for this device\n"); 1204 libfdisk_fini(&epp); 1205 exit(1); 1206 break; 1207 case FDISK_ENOLGEOM: 1208 fprintf(stderr, "Could not get label" 1209 " geometry for this device\n"); 1210 libfdisk_fini(&epp); 1211 exit(1); 1212 break; 1213 default: 1214 perror("Failed to initialise libfdisk.\n"); 1215 libfdisk_fini(&epp); 1216 exit(1); 1217 break; 1218 } 1219 } 1220 #endif 1221 1222 /* Load fdisk table from specified file (-F fdisk_file) */ 1223 if (io_ffdisk) { 1224 /* Load and verify user-specified table parameters */ 1225 load(LOADFILE, io_ffdisk); 1226 } 1227 1228 /* Does user want to delete or add an entry? */ 1229 if (io_Dfdisk) { 1230 load(LOADDEL, io_Dfdisk); 1231 } 1232 if (io_Afdisk) { 1233 load(LOADADD, io_Afdisk); 1234 } 1235 1236 if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) { 1237 /* Check if there is no fdisk table */ 1238 if (nopartdefined() || io_wholedisk || io_EFIdisk) { 1239 if (io_ifdisk && !io_wholedisk && !io_EFIdisk) { 1240 (void) printf( 1241 "No fdisk table exists. The default" 1242 " partition for the disk is:\n\n" 1243 " a 100%% \"SOLARIS System\" " 1244 "partition\n\n" 1245 "Type \"y\" to accept the default " 1246 "partition, otherwise type \"n\" to " 1247 "edit the\n partition table.\n"); 1248 1249 if (Numcyl > Numcyl_usable) 1250 (void) printf("WARNING: Disk is larger" 1251 " than 2TB. Solaris partition will" 1252 " be limited to 2 TB.\n"); 1253 } 1254 1255 /* Edit the partition table as directed */ 1256 if (io_wholedisk ||(io_ifdisk && yesno())) { 1257 1258 /* Default scenario */ 1259 nulltbl(); 1260 /* now set up UNIX System partition */ 1261 Table[0].bootid = ACTIVE; 1262 Table[0].relsect = LE_32(heads * sectors); 1263 1264 Table[0].numsect = 1265 LE_32((ulong_t)((Numcyl_usable - 1) * 1266 heads * sectors)); 1267 1268 Table[0].systid = SUNIXOS2; /* Solaris */ 1269 1270 /* calculate CHS values for table entry 0 */ 1271 Set_Table_CHS_Values(0); 1272 update_disk_and_exit(B_TRUE); 1273 } else if (io_EFIdisk) { 1274 /* create an EFI partition for the whole disk */ 1275 nulltbl(); 1276 i = insert_tbl(EFI_PMBR, 0, 0, 0, 0, 0, 0, 0, 1, 1277 (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB : 1278 (dev_capacity - 1), 0); 1279 if (i != 0) { 1280 (void) fprintf(stderr, 1281 "Error creating EFI partition\n"); 1282 exit(1); 1283 } 1284 update_disk_and_exit(B_TRUE); 1285 } 1286 } 1287 } 1288 1289 /* Display complete fdisk table entries for debugging purposes */ 1290 if (io_debug) { 1291 (void) fprintf(stderr, "Partition Table Entry Values:\n"); 1292 print_Table(); 1293 if (io_ifdisk) { 1294 (void) fprintf(stderr, "\n"); 1295 (void) fprintf(stderr, "Press Enter to continue.\n"); 1296 (void) fgets(s, sizeof (s), stdin); 1297 } 1298 } 1299 1300 /* Interactive fdisk mode */ 1301 if (io_ifdisk) { 1302 (void) printf(CLR_SCR); 1303 disptbl(); 1304 for (;;) { 1305 stage0(); 1306 copy_Bootblk_to_Table(); 1307 disptbl(); 1308 } 1309 } 1310 1311 /* If user wants to write the table to a file, do it */ 1312 if (io_Wfdisk) 1313 ffile_write(io_Wfdisk); 1314 else if (stdo_flag) 1315 ffile_write((char *)stdout); 1316 1317 update_disk_and_exit(TableChanged() == 1); 1318 return (0); 1319 } 1320 1321 /* 1322 * read_geom 1323 * Read geometry from specified file (-S). 1324 */ 1325 1326 static int 1327 read_geom(char *sgeom) 1328 { 1329 char line[256]; 1330 FILE *fp; 1331 1332 /* open the prototype file */ 1333 if ((fp = fopen(sgeom, "r")) == NULL) { 1334 (void) fprintf(stderr, "fdisk: Cannot open file %s.\n", 1335 io_sgeom); 1336 return (1); 1337 } 1338 1339 /* Read a line from the file */ 1340 while (fgets(line, sizeof (line) - 1, fp)) { 1341 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*') 1342 continue; 1343 else { 1344 line[strlen(line)] = '\0'; 1345 if (sscanf(line, "%hu %hu %hu %hu %hu %hu %d", 1346 &disk_geom.dkg_pcyl, 1347 &disk_geom.dkg_ncyl, 1348 &disk_geom.dkg_acyl, 1349 &disk_geom.dkg_bcyl, 1350 &disk_geom.dkg_nhead, 1351 &disk_geom.dkg_nsect, 1352 §siz) != 7) { 1353 (void) fprintf(stderr, 1354 "Syntax error:\n \"%s\".\n", 1355 line); 1356 return (1); 1357 } 1358 break; 1359 } /* else */ 1360 } /* while (fgets(line, sizeof (line) - 1, fp)) */ 1361 1362 if (!io_image) { 1363 if (ioctl(Dev, DKIOCSGEOM, &disk_geom)) { 1364 (void) fprintf(stderr, 1365 "fdisk: Cannot set label geometry.\n"); 1366 return (1); 1367 } 1368 } else { 1369 Numcyl = hba_Numcyl = disk_geom.dkg_ncyl; 1370 heads = hba_heads = disk_geom.dkg_nhead; 1371 sectors = hba_sectors = disk_geom.dkg_nsect; 1372 acyl = disk_geom.dkg_acyl; 1373 } 1374 1375 (void) fclose(fp); 1376 return (0); 1377 } 1378 1379 /* 1380 * dev_mboot_read 1381 * Read the master boot sector from the device. 1382 */ 1383 static void 1384 dev_mboot_read(void) 1385 { 1386 if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) { 1387 perror("Error in ioctl DKIOCGMBOOT"); 1388 } 1389 if (errno == 0) 1390 return; 1391 if (lseek(Dev, 0, SEEK_SET) == -1) { 1392 (void) fprintf(stderr, 1393 "fdisk: Error seeking to partition table on %s.\n", 1394 Dfltdev); 1395 if (!io_image) 1396 exit(1); 1397 } 1398 if (read(Dev, Bootsect, sectsiz) != sectsiz) { 1399 (void) fprintf(stderr, 1400 "fdisk: Error reading partition table from %s.\n", 1401 Dfltdev); 1402 if (!io_image) 1403 exit(1); 1404 } 1405 } 1406 1407 /* 1408 * dev_mboot_write 1409 * Write the master boot sector to the device. 1410 */ 1411 static void 1412 dev_mboot_write(off_t sect, char *buff, int bootsiz) 1413 { 1414 int new_pt, old_pt, error; 1415 int clr_efi = -1; 1416 1417 if (io_readonly) 1418 return; 1419 1420 if (io_debug) { 1421 (void) fprintf(stderr, "About to write fdisk table:\n"); 1422 print_Table(); 1423 if (io_ifdisk) { 1424 (void) fprintf(stderr, "Press Enter to continue.\n"); 1425 (void) fgets(s, sizeof (s), stdin); 1426 } 1427 } 1428 1429 /* 1430 * If the new table has any Solaris partitions and the old 1431 * table does not have an entry that describes it 1432 * exactly then clear the old vtoc (if any). 1433 */ 1434 for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) { 1435 1436 /* We only care about potential Solaris parts. */ 1437 if (Table[new_pt].systid != SUNIXOS && 1438 Table[new_pt].systid != SUNIXOS2) 1439 continue; 1440 1441 /* Does the old table have an exact entry for the new entry? */ 1442 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) { 1443 1444 /* We only care about old Solaris partitions. */ 1445 if ((Old_Table[old_pt].systid == SUNIXOS) || 1446 (Old_Table[old_pt].systid == SUNIXOS2)) { 1447 1448 /* Is this old one the same as a new one? */ 1449 if ((Old_Table[old_pt].relsect == 1450 Table[new_pt].relsect) && 1451 (Old_Table[old_pt].numsect == 1452 Table[new_pt].numsect)) 1453 break; /* Yes */ 1454 } 1455 } 1456 1457 /* Did a solaris partition change location or size? */ 1458 if (old_pt >= FD_NUMPART) { 1459 /* Yes clear old vtoc */ 1460 if (io_debug) { 1461 (void) fprintf(stderr, 1462 "Clearing VTOC labels from NEW" 1463 " table\n"); 1464 } 1465 clear_vtoc(NEW, new_pt); 1466 } 1467 } 1468 1469 1470 /* see if the old table had EFI */ 1471 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) { 1472 if (Old_Table[old_pt].systid == EFI_PMBR) { 1473 clr_efi = old_pt; 1474 } 1475 } 1476 1477 /* look to see if a EFI partition changed in relsect/numsect */ 1478 for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) { 1479 if (Table[new_pt].systid != EFI_PMBR) 1480 continue; 1481 for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) { 1482 if ((Old_Table[old_pt].systid == 1483 Table[new_pt].systid) && 1484 (Old_Table[old_pt].relsect == 1485 Table[new_pt].relsect) && 1486 (Old_Table[old_pt].numsect == 1487 Table[new_pt].numsect)) 1488 break; 1489 } 1490 1491 /* 1492 * if EFI partition changed, set the flag to clear 1493 * the EFI GPT 1494 */ 1495 if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) { 1496 clr_efi = 0; 1497 } 1498 break; 1499 } 1500 1501 /* clear labels if necessary */ 1502 if (clr_efi >= 0) { 1503 if (io_debug) { 1504 (void) fprintf(stderr, "Clearing EFI labels\n"); 1505 } 1506 if ((error = clear_efi()) != 0) { 1507 if (io_debug) { 1508 (void) fprintf(stderr, 1509 "\tError %d clearing EFI labels" 1510 " (probably no EFI labels exist)\n", 1511 error); 1512 } 1513 } 1514 } 1515 1516 if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) { 1517 (void) fprintf(stderr, 1518 "fdisk: Error in ioctl DKIOCSMBOOT on %s.\n", 1519 Dfltdev); 1520 } 1521 if (errno == 0) 1522 return; 1523 1524 /* write to disk drive */ 1525 if (lseek(Dev, sect, SEEK_SET) == -1) { 1526 (void) fprintf(stderr, 1527 "fdisk: Error seeking to master boot record on %s.\n", 1528 Dfltdev); 1529 exit(1); 1530 } 1531 if (write(Dev, buff, bootsiz) != bootsiz) { 1532 (void) fprintf(stderr, 1533 "fdisk: Error writing master boot record to %s.\n", 1534 Dfltdev); 1535 exit(1); 1536 } 1537 } 1538 1539 /* 1540 * mboot_read 1541 * Read the prototype boot records from the files. 1542 */ 1543 static void 1544 mboot_read(void) 1545 { 1546 int mDev, i; 1547 struct ipart *part; 1548 1549 #if defined(i386) || defined(sparc) 1550 /* 1551 * If the master boot file hasn't been specified, use the 1552 * implementation architecture name to generate the default one. 1553 */ 1554 if (io_mboot == (char *)0) { 1555 /* 1556 * Bug ID 1249035: 1557 * The mboot file must be delivered on all platforms 1558 * and installed in a non-platform-dependent 1559 * directory; i.e., /usr/lib/fs/ufs. 1560 */ 1561 io_mboot = "/usr/lib/fs/ufs/mboot"; 1562 } 1563 1564 /* First read in the master boot record */ 1565 1566 /* Open the master boot proto file */ 1567 if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) { 1568 (void) fprintf(stderr, 1569 "fdisk: Cannot open master boot file %s.\n", 1570 io_mboot); 1571 exit(1); 1572 } 1573 1574 /* Read the master boot program */ 1575 if (read(mDev, &BootCod, sizeof (struct mboot)) != sizeof 1576 (struct mboot)) { 1577 (void) fprintf(stderr, 1578 "fdisk: Cannot read master boot file %s.\n", 1579 io_mboot); 1580 exit(1); 1581 } 1582 1583 /* Is this really a master boot record? */ 1584 if (LE_16(BootCod.signature) != MBB_MAGIC) { 1585 (void) fprintf(stderr, 1586 "fdisk: Invalid master boot file %s.\n", io_mboot); 1587 (void) fprintf(stderr, 1588 "Bad magic number: is %x, but should be %x.\n", 1589 LE_16(BootCod.signature), MBB_MAGIC); 1590 exit(1); 1591 } 1592 1593 (void) close(mDev); 1594 #else 1595 #error fdisk needs to be ported to new architecture 1596 #endif 1597 1598 /* Zero out the partitions part of this record */ 1599 part = (struct ipart *)BootCod.parts; 1600 for (i = 0; i < FD_NUMPART; i++, part++) { 1601 (void) memset(part, 0, sizeof (struct ipart)); 1602 } 1603 1604 } 1605 1606 /* 1607 * fill_patt 1608 * Fill the disk with user/sector number pattern. 1609 */ 1610 static void 1611 fill_patt(void) 1612 { 1613 int *buff_ptr, i; 1614 off_t *off_ptr; 1615 int io_fpatt = 0; 1616 int io_ipatt = 0; 1617 1618 if (strncmp(io_fatt, "#", 1) != 0) { 1619 io_fpatt++; 1620 io_ipatt = strtoul(io_fatt, 0, 0); 1621 buff_ptr = (int *)Bootsect; 1622 for (i = 0; i < sectsiz; i += 4, buff_ptr++) 1623 *buff_ptr = io_ipatt; 1624 } 1625 1626 /* 1627 * Fill disk with pattern based on block number. 1628 * Write to the disk at absolute relative block io_offset 1629 * for io_size blocks. 1630 */ 1631 while (io_size--) { 1632 off_ptr = (off_t *)Bootsect; 1633 if (!io_fpatt) { 1634 for (i = 0; i < sectsiz; 1635 i += sizeof (off_t), off_ptr++) 1636 *off_ptr = io_offset; 1637 } 1638 /* Write the data to disk */ 1639 if (lseek(Dev, (off_t)(sectsiz * io_offset++), 1640 SEEK_SET) == -1) { 1641 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n", 1642 Dfltdev); 1643 exit(1); 1644 } 1645 if (write(Dev, Bootsect, sectsiz) != sectsiz) { 1646 (void) fprintf(stderr, "fdisk: Error writing %s.\n", 1647 Dfltdev); 1648 exit(1); 1649 } 1650 } /* while (--io_size); */ 1651 } 1652 1653 /* 1654 * abs_read 1655 * Read from the disk at absolute relative block io_offset for 1656 * io_size blocks. Write the data to standard ouput (-r). 1657 */ 1658 static void 1659 abs_read(void) 1660 { 1661 int c; 1662 1663 while (io_size--) { 1664 if (lseek(Dev, (off_t)(sectsiz * io_offset++), 1665 SEEK_SET) == -1) { 1666 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n", 1667 Dfltdev); 1668 exit(1); 1669 } 1670 if (read(Dev, Bootsect, sectsiz) != sectsiz) { 1671 (void) fprintf(stderr, "fdisk: Error reading %s.\n", 1672 Dfltdev); 1673 exit(1); 1674 } 1675 1676 /* Write to standard ouptut */ 1677 if ((c = write(1, Bootsect, (unsigned)sectsiz)) != sectsiz) { 1678 if (c >= 0) { 1679 if (io_debug) 1680 (void) fprintf(stderr, 1681 "fdisk: Output warning: %d of %d" 1682 " characters written.\n", 1683 c, sectsiz); 1684 exit(2); 1685 } else { 1686 perror("write error on output file."); 1687 exit(2); 1688 } 1689 } /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */ 1690 /* != sectsiz) */ 1691 } /* while (--io_size); */ 1692 exit(0); 1693 } 1694 1695 /* 1696 * abs_write 1697 * Read the data from standard input. Write to the disk at 1698 * absolute relative block io_offset for io_size blocks (-w). 1699 */ 1700 static void 1701 abs_write(void) 1702 { 1703 int c, i; 1704 1705 while (io_size--) { 1706 int part_exit = 0; 1707 /* Read from standard input */ 1708 if ((c = read(0, Bootsect, (unsigned)sectsiz)) != sectsiz) { 1709 if (c >= 0) { 1710 if (io_debug) 1711 (void) fprintf(stderr, 1712 "fdisk: WARNING: Incomplete read (%d of" 1713 " %d characters read) on input file.\n", 1714 c, sectsiz); 1715 /* Fill pattern to mark partial sector in buf */ 1716 for (i = c; i < sectsiz; ) { 1717 Bootsect[i++] = 0x41; 1718 Bootsect[i++] = 0x62; 1719 Bootsect[i++] = 0x65; 1720 Bootsect[i++] = 0; 1721 } 1722 part_exit++; 1723 } else { 1724 perror("read error on input file."); 1725 exit(2); 1726 } 1727 1728 } 1729 /* Write to disk drive */ 1730 if (lseek(Dev, (off_t)(sectsiz * io_offset++), 1731 SEEK_SET) == -1) { 1732 (void) fprintf(stderr, "fdisk: Error seeking on %s.\n", 1733 Dfltdev); 1734 exit(1); 1735 } 1736 if (write(Dev, Bootsect, sectsiz) != sectsiz) { 1737 (void) fprintf(stderr, "fdisk: Error writing %s.\n", 1738 Dfltdev); 1739 exit(1); 1740 } 1741 if (part_exit) 1742 exit(0); 1743 } /* while (--io_size); */ 1744 exit(1); 1745 } 1746 1747 1748 /* 1749 * load 1750 * Load will either read the fdisk table from a file or add or 1751 * delete an entry (-A, -D, -F). 1752 */ 1753 1754 static void 1755 load(int funct, char *file) 1756 { 1757 int id; 1758 int act; 1759 int bhead; 1760 int bsect; 1761 int bcyl; 1762 int ehead; 1763 int esect; 1764 int ecyl; 1765 uint32_t rsect; 1766 uint32_t numsect; 1767 char line[256]; 1768 int i = 0; 1769 FILE *fp; 1770 int startindex = 0; 1771 int tmpindex = 0; 1772 #ifdef i386 1773 int ext_part_present = 0; 1774 uint32_t begsec, endsec, relsect; 1775 logical_drive_t *temp; 1776 int part_count = 0, ldcnt = 0; 1777 uint32_t ext_beg_sec, ext_end_sec; 1778 uint32_t old_ext_beg_sec = 0, old_ext_num_sec = 0; 1779 uint32_t new_ext_beg_sec = 0, new_ext_num_sec = 0; 1780 int ext_part_inited = 0; 1781 uchar_t systid; 1782 #endif 1783 1784 switch (funct) { 1785 1786 case LOADFILE: 1787 1788 /* 1789 * Zero out the table before loading it, which will 1790 * force it to be updated on disk later (-F 1791 * fdisk_file). 1792 */ 1793 nulltbl(); 1794 1795 /* Open the prototype file */ 1796 if ((fp = fopen(file, "r")) == NULL) { 1797 (void) fprintf(stderr, 1798 "fdisk: Cannot open prototype partition file %s.\n", 1799 file); 1800 exit(1); 1801 } 1802 1803 /* Read a line from the file */ 1804 while (fgets(line, sizeof (line) - 1, fp)) { 1805 if (pars_fdisk(line, &id, &act, &bhead, &bsect, 1806 &bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) { 1807 continue; 1808 } 1809 #ifdef i386 1810 part_count++; 1811 1812 if (fdisk_is_dos_extended((uchar_t)id)) { 1813 if (ext_part_present) { 1814 fprintf(stderr, "Extended partition" 1815 " already exists\n"); 1816 fprintf(stderr, "fdisk: Error on" 1817 " entry \"%s\".\n", line); 1818 exit(1); 1819 } 1820 ext_part_present = 1; 1821 /* 1822 * If the existing extended partition's start 1823 * and size matches the new one, do not 1824 * initialize the extended partition EBR 1825 * (Extended Boot Record) because there could 1826 * be existing logical drives. 1827 */ 1828 for (i = 0; i < FD_NUMPART; i++) { 1829 systid = Old_Table[i].systid; 1830 if (fdisk_is_dos_extended(systid)) { 1831 old_ext_beg_sec = 1832 Old_Table[i].relsect; 1833 old_ext_num_sec = 1834 Old_Table[i].numsect; 1835 break; 1836 } 1837 } 1838 new_ext_beg_sec = rsect; 1839 new_ext_num_sec = numsect; 1840 if ((old_ext_beg_sec != new_ext_beg_sec) || 1841 (old_ext_num_sec != new_ext_num_sec)) { 1842 fdisk_init_ext_part(epp, 1843 new_ext_beg_sec, new_ext_num_sec); 1844 ext_part_inited = 1; 1845 } 1846 } 1847 1848 if (part_count > FD_NUMPART) { 1849 /* This line should be logical drive info */ 1850 int offset = MAX_LOGDRIVE_OFFSET; 1851 if (!ext_part_present) { 1852 /* Erroneous input file */ 1853 fprintf(stderr, "More than 4 primary" 1854 " partitions found in input\n"); 1855 fprintf(stderr, "Exiting...\n"); 1856 exit(1); 1857 } 1858 1859 if (numsect == 0) { 1860 continue; 1861 } 1862 1863 /* 1864 * If the start and size of the existing 1865 * extended partition matches the new one and 1866 * new logical drives are being defined via 1867 * the input file, initialize the EBR. 1868 */ 1869 if (!ext_part_inited) { 1870 fdisk_init_ext_part(epp, 1871 new_ext_beg_sec, new_ext_num_sec); 1872 ext_part_inited = 1; 1873 } 1874 1875 begsec = rsect - offset; 1876 if ((ldcnt = 1877 fdisk_get_logical_drive_count(epp)) == 0) { 1878 /* Adding the first logical drive */ 1879 /* 1880 * Make sure that begsec doesnt wrap 1881 * around. This can happen if rsect is 1882 * less than offset. 1883 */ 1884 if (rsect < offset) { 1885 fprintf(stderr, "Minimum of " 1886 "63 free sectors required " 1887 "before the beginning of " 1888 "a logical drive."); 1889 exit(1); 1890 } 1891 /* 1892 * Check if the first logical drive 1893 * is out of order. In that case, do 1894 * not subtract MAX_LOGDRIVE_OFFSET 1895 * from the given start of partition. 1896 */ 1897 if (begsec != new_ext_beg_sec) { 1898 begsec = rsect; 1899 offset = 0; 1900 } 1901 } 1902 if (ldcnt >= MAX_EXT_PARTS) { 1903 fprintf(stderr, "\nError : Number of " 1904 "logical drives exceeds limit of " 1905 "%d.\n", MAX_EXT_PARTS); 1906 exit(1); 1907 } 1908 1909 if (id > FDISK_MAX_VALID_PART_ID) { 1910 fprintf(stderr, "Invalid partition " 1911 "ID\n"); 1912 fprintf(stderr, "fdisk: Error on" 1913 " entry \"%s\".\n", line); 1914 exit(1); 1915 } 1916 1917 endsec = rsect + numsect - 1; 1918 if (fdisk_validate_logical_drive(epp, 1919 begsec, offset, numsect) == 0) { 1920 if (id == EFI_PMBR) { 1921 fprintf(stderr, "EFI " 1922 "partitions not supported " 1923 "inside extended " 1924 "partition\n"); 1925 exit(1); 1926 } 1927 fdisk_add_logical_drive(epp, begsec, 1928 endsec, id); 1929 continue; 1930 } else { 1931 fprintf(stderr, "fdisk: Error on" 1932 " entry \"%s\".\n", line); 1933 exit(1); 1934 } 1935 } 1936 #endif 1937 1938 /* 1939 * Validate the partition. It cannot start at sector 1940 * 0 unless it is UNUSED or already exists 1941 */ 1942 if (validate_part(id, rsect, numsect) < 0) { 1943 (void) fprintf(stderr, 1944 "fdisk: Error on entry \"%s\".\n", 1945 line); 1946 exit(1); 1947 } 1948 1949 if ((tmpindex = entry_from_old_table(id, act, bhead, 1950 bsect, bcyl, ehead, esect, ecyl, rsect, numsect, 1951 startindex)) != -1) { 1952 /* 1953 * If we got here it means we copied an 1954 * unmodified entry. So there is no need 1955 * to insert it in the table or do any 1956 * checks against disk size. 1957 * 1958 * This is a work around on the following 1959 * situation (for IDE disks, at least): 1960 * Different operation systems calculate 1961 * disk size different ways, of which there 1962 * are two main ways. 1963 * 1964 * The first, rounds the disk size to modulo 1965 * cylinder size (virtual made-up cylinder 1966 * usually based on maximum number of heads 1967 * and sectors in partition table fields). 1968 * Our OS's (for IDE) and most other "Unix" 1969 * type OS's do this. 1970 * 1971 * The second, uses every single block 1972 * on the disk (to maximize available space). 1973 * Since disk manufactures do not know about 1974 * "virtual cylinders", there are some number 1975 * of blocks that make up a partial cylinder 1976 * at the end of the disk. 1977 * 1978 * The difference between these two methods 1979 * is where the problem is. When one 1980 * tries to install Solaris/OpenSolaris on 1981 * a disk that has another OS using that 1982 * "partial cylinder", install fails. It fails 1983 * since fdisk thinks its asked to create a 1984 * partition with the -F option that contains 1985 * a partition that runs off the end of the 1986 * disk. 1987 */ 1988 startindex = tmpindex + 1; 1989 continue; 1990 } 1991 1992 /* 1993 * Find an unused entry to use and put the entry 1994 * in table 1995 */ 1996 if ((startindex = insert_tbl(id, act, bhead, bsect, 1997 bcyl, ehead, esect, ecyl, rsect, numsect, 1998 startindex)) < 0) { 1999 (void) fprintf(stderr, 2000 "fdisk: Error on entry \"%s\".\n", 2001 line); 2002 exit(1); 2003 } 2004 startindex++; 2005 } /* while (fgets(line, sizeof (line) - 1, fp)) */ 2006 2007 if (verify_tbl() < 0) { 2008 (void) fprintf(stderr, 2009 "fdisk: Cannot create partition table\n"); 2010 exit(1); 2011 } 2012 2013 (void) fclose(fp); 2014 return; 2015 2016 case LOADDEL: 2017 2018 /* Parse the user-supplied deletion line (-D) */ 2019 if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, 2020 &ehead, &esect, &ecyl, &rsect, &numsect)) { 2021 (void) fprintf(stderr, 2022 "fdisk: Syntax error \"%s\"\n", file); 2023 exit(1); 2024 } 2025 2026 /* Find the exact entry in the table */ 2027 for (i = 0; i < FD_NUMPART; i++) { 2028 if (Table[i].systid == id && 2029 Table[i].bootid == act && 2030 Table[i].beghead == bhead && 2031 Table[i].begsect == ((bsect & 0x3f) | 2032 (uchar_t)((bcyl>>2) & 0xc0)) && 2033 Table[i].begcyl == (uchar_t)(bcyl & 0xff) && 2034 Table[i].endhead == ehead && 2035 Table[i].endsect == ((esect & 0x3f) | 2036 (uchar_t)((ecyl>>2) & 0xc0)) && 2037 Table[i].endcyl == (uchar_t)(ecyl & 0xff) && 2038 Table[i].relsect == LE_32(rsect) && 2039 Table[i].numsect == LE_32(numsect)) { 2040 2041 (void) memset(&Table[i], 0, 2042 sizeof (struct ipart)); 2043 #ifdef i386 2044 if (fdisk_is_dos_extended(id)) { 2045 fdisk_delete_ext_part(epp); 2046 } 2047 #endif 2048 return; 2049 } 2050 } 2051 2052 #ifdef i386 2053 ldcnt = FD_NUMPART + 1; 2054 for (temp = fdisk_get_ld_head(epp); temp != NULL; 2055 temp = temp->next) { 2056 relsect = temp->abs_secnum + temp->logdrive_offset; 2057 if (temp->parts[0].systid == id && 2058 temp->parts[0].bootid == act && 2059 temp->parts[0].beghead == bhead && 2060 temp->parts[0].begsect == ((bsect & 0x3f) | 2061 (uchar_t)((bcyl>>2) & 0xc0)) && 2062 temp->parts[0].begcyl == (uchar_t)(bcyl & 0xff) && 2063 temp->parts[0].endhead == ehead && 2064 temp->parts[0].endsect == ((esect & 0x3f) | 2065 (uchar_t)((ecyl>>2) & 0xc0)) && 2066 temp->parts[0].endcyl == (uchar_t)(ecyl & 0xff) && 2067 relsect == LE_32(rsect) && 2068 temp->parts[0].numsect == LE_32(numsect)) { 2069 fdisk_delete_logical_drive(epp, ldcnt); 2070 return; 2071 } 2072 ldcnt++; 2073 } 2074 #endif 2075 2076 (void) fprintf(stderr, 2077 "fdisk: Entry does not match any existing partition:\n" 2078 " \"%s\"\n", 2079 file); 2080 exit(1); 2081 /* FALLTHRU */ 2082 2083 case LOADADD: 2084 2085 /* Parse the user-supplied addition line (-A) */ 2086 if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead, 2087 &esect, &ecyl, &rsect, &numsect)) { 2088 (void) fprintf(stderr, 2089 "fdisk: Syntax error \"%s\"\n", file); 2090 exit(1); 2091 } 2092 2093 /* Validate the partition. It cannot start at sector 0 */ 2094 if (rsect == 0) { 2095 (void) fprintf(stderr, 2096 "fdisk: New partition cannot start at sector 0:\n" 2097 " \"%s\".\n", 2098 file); 2099 exit(1); 2100 } 2101 2102 /* 2103 * if the user wishes to add an EFI partition, we need 2104 * more extensive validation. rsect should be 1, and 2105 * numsect should equal the entire disk capacity - 1 2106 */ 2107 2108 if (id == EFI_PMBR) { 2109 if (rsect != 1) { 2110 (void) fprintf(stderr, 2111 "fdisk: EFI partitions must start at sector" 2112 " 1 (input rsect = %d)\n", rsect); 2113 exit(1); 2114 } 2115 2116 2117 if (dev_capacity > DK_MAX_2TB) { 2118 if (numsect != DK_MAX_2TB) { 2119 (void) fprintf(stderr, 2120 "fdisk: EFI partitions must " 2121 "encompass the entire maximum 2 TB " 2122 "(input numsect: %u - max: %llu)\n", 2123 numsect, (diskaddr_t)DK_MAX_2TB); 2124 exit(1); 2125 } 2126 } else if (numsect != dev_capacity - 1) { 2127 (void) fprintf(stderr, 2128 "fdisk: EFI partitions must encompass the " 2129 "entire disk\n" 2130 "(input numsect: %u - avail: %llu)\n", 2131 numsect, 2132 dev_capacity - 1); 2133 exit(1); 2134 } 2135 } 2136 2137 #ifdef i386 2138 if (id > FDISK_MAX_VALID_PART_ID) { 2139 printf("Invalid partition ID\n"); 2140 exit(1); 2141 } 2142 2143 if ((fdisk_ext_part_exists(epp)) && 2144 (fdisk_is_dos_extended(id))) { 2145 (void) fprintf(stderr, 2146 "Extended partition already exists.\n"); 2147 (void) fprintf(stderr, 2148 "fdisk: Invalid entry could not be " 2149 "inserted:\n \"%s\"\n", file); 2150 exit(1); 2151 } 2152 2153 if (fdisk_ext_part_exists(epp) && 2154 (rsect >= (ext_beg_sec = fdisk_get_ext_beg_sec(epp))) && 2155 (rsect <= (ext_end_sec = fdisk_get_ext_end_sec(epp)))) { 2156 int offset = MAX_LOGDRIVE_OFFSET; 2157 2158 /* 2159 * Make sure that begsec doesnt wrap around. 2160 * This can happen if rsect is less than offset 2161 */ 2162 if (rsect < offset) { 2163 return; 2164 } 2165 begsec = rsect - offset; 2166 if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) { 2167 /* 2168 * Adding the first logical drive 2169 * Check if the first logical drive 2170 * is out of order. In that case, do 2171 * not subtract MAX_LOGDRIVE_OFFSET 2172 * from the given start of partition. 2173 */ 2174 if (begsec != ext_beg_sec) { 2175 begsec = rsect; 2176 offset = 0; 2177 } 2178 } 2179 2180 if (ldcnt >= MAX_EXT_PARTS) { 2181 printf("\nNumber of logical drives exceeds " 2182 "limit of %d.\n", MAX_EXT_PARTS); 2183 printf("Failing further additions.\n"); 2184 exit(1); 2185 } 2186 2187 if (numsect == 0) { 2188 (void) fprintf(stderr, 2189 "fdisk: Partition size cannot be zero:\n" 2190 " \"%s\".\n", 2191 file); 2192 exit(1); 2193 } 2194 endsec = rsect + numsect - 1; 2195 if (fdisk_validate_logical_drive(epp, begsec, 2196 offset, numsect) == 0) { 2197 /* Valid logical drive */ 2198 fdisk_add_logical_drive(epp, begsec, endsec, 2199 id); 2200 return; 2201 } else { 2202 (void) fprintf(stderr, 2203 "fdisk: Invalid entry could not be " 2204 "inserted:\n \"%s\"\n", file); 2205 exit(1); 2206 } 2207 } 2208 #endif 2209 2210 /* Find unused entry for use and put entry in table */ 2211 if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect, 2212 ecyl, rsect, numsect, 0) < 0) { 2213 (void) fprintf(stderr, 2214 "fdisk: Invalid entry could not be inserted:\n" 2215 " \"%s\"\n", 2216 file); 2217 exit(1); 2218 } 2219 2220 /* Make sure new entry does not overlap existing entry */ 2221 if (verify_tbl() < 0) { 2222 (void) fprintf(stderr, 2223 "fdisk: Cannot create partition \"%s\"\n", file); 2224 exit(1); 2225 } 2226 } /* switch funct */ 2227 } 2228 2229 /* 2230 * Set_Table_CHS_Values 2231 * 2232 * This will calculate the CHS values for beginning and ending CHS 2233 * for a single partition table entry (ti) based on the relsect 2234 * and numsect values contained in the partion table entry. 2235 * 2236 * hba_heads and hba_sectors contain the number of heads and sectors. 2237 * 2238 * If the number of cylinders exceeds the MAX_CYL, 2239 * then maximum values will be placed in the corresponding chs entry. 2240 */ 2241 static void 2242 Set_Table_CHS_Values(int ti) 2243 { 2244 uint32_t lba, cy, hd, sc; 2245 2246 lba = (uint32_t)Table[ti].relsect; 2247 if (lba >= hba_heads * hba_sectors * MAX_CYL) { 2248 /* 2249 * the lba address cannot be expressed in CHS value 2250 * so store the maximum CHS field values in the CHS fields. 2251 */ 2252 cy = MAX_CYL + 1; 2253 hd = MAX_HEAD; 2254 sc = MAX_SECT; 2255 } else { 2256 cy = lba / hba_sectors / hba_heads; 2257 hd = lba / hba_sectors % hba_heads; 2258 sc = lba % hba_sectors + 1; 2259 } 2260 Table[ti].begcyl = cy & 0xff; 2261 Table[ti].beghead = (uchar_t)hd; 2262 Table[ti].begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc); 2263 2264 /* 2265 * This code is identical to the code above 2266 * except that it works on ending CHS values 2267 */ 2268 lba = (uint32_t)(Table[ti].relsect + Table[ti].numsect - 1); 2269 if (lba >= hba_heads * hba_sectors * MAX_CYL) { 2270 cy = MAX_CYL + 1; 2271 hd = MAX_HEAD; 2272 sc = MAX_SECT; 2273 } else { 2274 cy = lba / hba_sectors / hba_heads; 2275 hd = lba / hba_sectors % hba_heads; 2276 sc = lba % hba_sectors + 1; 2277 } 2278 Table[ti].endcyl = cy & 0xff; 2279 Table[ti].endhead = (uchar_t)hd; 2280 Table[ti].endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc); 2281 } 2282 2283 /* 2284 * insert_tbl 2285 * Insert entry into fdisk table. Check all user-supplied values 2286 * for the entry, but not the validity relative to other table 2287 * entries! 2288 */ 2289 static int 2290 insert_tbl( 2291 int id, int act, 2292 int bhead, int bsect, int bcyl, 2293 int ehead, int esect, int ecyl, 2294 uint32_t rsect, uint32_t numsect, int startindex) 2295 { 2296 int i; 2297 2298 /* validate partition size */ 2299 if (((diskaddr_t)rsect + numsect) > dev_capacity) { 2300 (void) fprintf(stderr, 2301 "fdisk: Partition table exceeds the size of the disk.\n"); 2302 return (-1); 2303 } 2304 2305 2306 /* find UNUSED partition table entry */ 2307 for (i = startindex; i < FD_NUMPART; i++) { 2308 if (Table[i].systid == UNUSED) { 2309 break; 2310 } 2311 } 2312 if (i >= FD_NUMPART) { 2313 (void) fprintf(stderr, "fdisk: Partition table is full.\n"); 2314 return (-1); 2315 } 2316 2317 2318 Table[i].systid = (uchar_t)id; 2319 Table[i].bootid = (uchar_t)act; 2320 Table[i].numsect = LE_32(numsect); 2321 Table[i].relsect = LE_32(rsect); 2322 2323 if (id == UNUSED) { 2324 (void) memset(&Table[i], 0, sizeof (struct ipart)); 2325 } else if (0 < bsect && bsect <= MAX_SECT && 2326 0 <= bhead && bhead <= MAX_HEAD && 2327 0 < esect && esect <= MAX_SECT && 2328 0 <= ehead && ehead <= MAX_HEAD) { 2329 2330 /* 2331 * If we have been called with a valid geometry, use it 2332 * valid means non-zero values that fit in the BIOS fields 2333 */ 2334 if (bcyl > MAX_CYL) 2335 bcyl = MAX_CYL + 1; 2336 if (ecyl > MAX_CYL) 2337 ecyl = MAX_CYL + 1; 2338 Table[i].begcyl = bcyl & 0xff; 2339 Table[i].endcyl = ecyl & 0xff; 2340 Table[i].beghead = (uchar_t)bhead; 2341 Table[i].endhead = (uchar_t)ehead; 2342 Table[i].begsect = (uchar_t)(((bcyl >> 2) & 0xc0) | bsect); 2343 Table[i].endsect = ((ecyl >> 2) & 0xc0) | esect; 2344 } else { 2345 2346 /* 2347 * The specified values are invalid, 2348 * so calculate the values based on hba_heads, hba_sectors 2349 */ 2350 Set_Table_CHS_Values(i); 2351 } 2352 2353 /* 2354 * return partition index 2355 */ 2356 return (i); 2357 } 2358 2359 /* 2360 * entry_from_old_table 2361 * If the specified entry is in the old table and is not a Solaris entry 2362 * then insert same entry into new fdisk table. If we do this then 2363 * all checks are skipped for that entry! 2364 */ 2365 static int 2366 entry_from_old_table( 2367 int id, int act, 2368 int bhead, int bsect, int bcyl, 2369 int ehead, int esect, int ecyl, 2370 uint32_t rsect, uint32_t numsect, int startindex) 2371 { 2372 uint32_t i, j; 2373 2374 if (id == SUNIXOS || id == SUNIXOS2 || id == UNUSED) 2375 return (-1); 2376 for (i = 0; i < FD_NUMPART; i++) { 2377 if (Old_Table[i].systid == id && 2378 Old_Table[i].bootid == act && 2379 Old_Table[i].beghead == bhead && 2380 Old_Table[i].begsect == ((bsect & 0x3f) | 2381 (uchar_t)((bcyl>>2) & 0xc0)) && 2382 Old_Table[i].begcyl == (uchar_t)(bcyl & 0xff) && 2383 Old_Table[i].endhead == ehead && 2384 Old_Table[i].endsect == ((esect & 0x3f) | 2385 (uchar_t)((ecyl>>2) & 0xc0)) && 2386 Old_Table[i].endcyl == (uchar_t)(ecyl & 0xff) && 2387 Old_Table[i].relsect == lel(rsect) && 2388 Old_Table[i].numsect == lel(numsect)) { 2389 /* find UNUSED partition table entry */ 2390 for (j = startindex; j < FD_NUMPART; j++) { 2391 if (Table[j].systid == UNUSED) { 2392 (void) memcpy(&Table[j], &Old_Table[i], 2393 sizeof (Table[0])); 2394 skip_verify[j] = 1; 2395 return (j); 2396 2397 } 2398 } 2399 return (-1); 2400 } 2401 2402 } 2403 return (-1); 2404 } 2405 2406 /* 2407 * verify_tbl 2408 * Verify that no partition entries overlap or exceed the size of 2409 * the disk. 2410 */ 2411 static int 2412 verify_tbl(void) 2413 { 2414 uint32_t i, j, rsect, numsect; 2415 int noMoreParts = 0; 2416 int numParts = 0; 2417 2418 /* Make sure new entry does not overlap an existing entry */ 2419 for (i = 0; i < FD_NUMPART - 1; i++) { 2420 if (Table[i].systid != UNUSED) { 2421 numParts++; 2422 /* 2423 * No valid partitions allowed after EFI_PMBR part 2424 */ 2425 if (noMoreParts) { 2426 return (-1); 2427 } 2428 2429 if (Table[i].systid == EFI_PMBR) { 2430 /* 2431 * EFI_PMBR partition must be the only 2432 * partition 2433 */ 2434 noMoreParts = 1; 2435 2436 if (Table[i].relsect != 1) { 2437 (void) fprintf(stderr, "ERROR: " 2438 "Invalid starting sector " 2439 "for EFI_PMBR partition:\n" 2440 "relsect %d " 2441 "(should be 1)\n", 2442 Table[i].relsect); 2443 2444 return (-1); 2445 } 2446 2447 if (Table[i].numsect != 2448 ((dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB: 2449 (dev_capacity - 1))) { 2450 2451 (void) fprintf(stderr, "ERROR: " 2452 "EFI_PMBR partition must " 2453 "encompass the entire"); 2454 2455 if (dev_capacity > DK_MAX_2TB) 2456 (void) fprintf(stderr, 2457 "maximum 2 TB.\n " 2458 "numsect %u - " 2459 "actual %llu\n", 2460 Table[i].numsect, 2461 (diskaddr_t)DK_MAX_2TB); 2462 2463 else 2464 (void) fprintf(stderr, 2465 "disk.\n numsect %u - " 2466 "actual %llu\n", 2467 Table[i].numsect, 2468 dev_capacity - 1); 2469 2470 return (-1); 2471 } 2472 } 2473 2474 /* make sure the partition isn't larger than the disk */ 2475 rsect = LE_32(Table[i].relsect); 2476 numsect = LE_32(Table[i].numsect); 2477 2478 if ((((diskaddr_t)rsect + numsect) > dev_capacity) || 2479 (((diskaddr_t)rsect + numsect) > DK_MAX_2TB)) { 2480 if (!skip_verify[i]) 2481 return (-1); 2482 } 2483 2484 for (j = i + 1; j < FD_NUMPART; j++) { 2485 if (Table[j].systid != UNUSED) { 2486 uint32_t t_relsect = 2487 LE_32(Table[j].relsect); 2488 uint32_t t_numsect = 2489 LE_32(Table[j].numsect); 2490 2491 if (noMoreParts) { 2492 (void) fprintf(stderr, 2493 "Cannot add partition to " 2494 "table; no more partitions " 2495 "allowed\n"); 2496 2497 if (io_debug) { 2498 (void) fprintf(stderr, 2499 "DEBUG: Current " 2500 "partition:\t" 2501 "%d:%d:%d:%d:%d:" 2502 "%d:%d:%d:%d:%d\n" 2503 " Next " 2504 "partition:\t\t" 2505 "%d:%d:%d:%d:%d:" 2506 "%d:%d:%d:%d:%d\n", 2507 Table[i].systid, 2508 Table[i].bootid, 2509 Table[i].begcyl, 2510 Table[i].beghead, 2511 Table[i].begsect, 2512 Table[i].endcyl, 2513 Table[i].endhead, 2514 Table[i].endsect, 2515 Table[i].relsect, 2516 Table[i].numsect, 2517 Table[j].systid, 2518 Table[j].bootid, 2519 Table[j].begcyl, 2520 Table[j].beghead, 2521 Table[j].begsect, 2522 Table[j].endcyl, 2523 Table[j].endhead, 2524 Table[j].endsect, 2525 Table[j].relsect, 2526 Table[j].numsect); 2527 } 2528 2529 return (-1); 2530 } 2531 if ((rsect >= 2532 (t_relsect + t_numsect)) || 2533 ((rsect + numsect) <= t_relsect)) { 2534 continue; 2535 } else { 2536 (void) fprintf(stderr, "ERROR: " 2537 "current partition overlaps" 2538 " following partition\n"); 2539 2540 return (-1); 2541 } 2542 } 2543 } 2544 } 2545 } 2546 if (Table[i].systid != UNUSED) { 2547 if (noMoreParts) 2548 return (-1); 2549 if (!skip_verify[i] && 2550 ((((diskaddr_t)lel(Table[i].relsect) + 2551 lel(Table[i].numsect)) > dev_capacity) || 2552 (((diskaddr_t)lel(Table[i].relsect) + 2553 lel(Table[i].numsect)) > DK_MAX_2TB))) { 2554 return (-1); 2555 } 2556 } 2557 2558 return (numParts); 2559 } 2560 2561 /* 2562 * pars_fdisk 2563 * Parse user-supplied data to set up fdisk partitions 2564 * (-A, -D, -F). 2565 */ 2566 static int 2567 pars_fdisk( 2568 char *line, 2569 int *id, int *act, 2570 int *bhead, int *bsect, int *bcyl, 2571 int *ehead, int *esect, int *ecyl, 2572 uint32_t *rsect, uint32_t *numsect) 2573 { 2574 int i; 2575 int64_t test; 2576 char *tok, *p; 2577 char buf[256]; 2578 2579 if (line[0] == '\0' || line[0] == '\n' || line[0] == '*') 2580 return (1); 2581 line[strlen(line)] = '\0'; 2582 for (i = 0; i < strlen(line); i++) { 2583 if (line[i] == '\0') { 2584 break; 2585 } else if (line[i] == ':') { 2586 line[i] = ' '; 2587 } 2588 } 2589 strncpy(buf, line, 256); 2590 errno = 0; 2591 tok = strtok(buf, ": \t\n"); 2592 while (tok != NULL) { 2593 for (p = tok; *p != '\0'; p++) { 2594 if (!isdigit(*p)) { 2595 printf("Invalid input %s in line %s.\n", 2596 tok, line); 2597 exit(1); 2598 } 2599 } 2600 2601 test = strtoll(tok, (char **)NULL, 10); 2602 if ((test < 0) || (test > 0xFFFFFFFF) || (errno != 0)) { 2603 printf("Invalid input %s in line %s.\n", tok, line); 2604 exit(1); 2605 } 2606 tok = strtok(NULL, ": \t\n"); 2607 } 2608 if (sscanf(line, "%d %d %d %d %d %d %d %d %u %u", 2609 id, act, bhead, bsect, bcyl, ehead, esect, ecyl, 2610 rsect, numsect) != 10) { 2611 (void) fprintf(stderr, "Syntax error:\n \"%s\".\n", line); 2612 exit(1); 2613 } 2614 return (0); 2615 } 2616 2617 /* 2618 * validate_part 2619 * Validate that a new partition does not start at sector 0. Only UNUSED 2620 * partitions and previously existing partitions are allowed to start at 0. 2621 */ 2622 static int 2623 validate_part(int id, uint32_t rsect, uint32_t numsect) 2624 { 2625 int i; 2626 if ((id != UNUSED) && (rsect == 0)) { 2627 for (i = 0; i < FD_NUMPART; i++) { 2628 if ((Old_Table[i].systid == id) && 2629 (Old_Table[i].relsect == LE_32(rsect)) && 2630 (Old_Table[i].numsect == LE_32(numsect))) 2631 return (0); 2632 } 2633 (void) fprintf(stderr, 2634 "New partition cannot start at sector 0\n"); 2635 return (-1); 2636 } 2637 #ifdef i386 2638 if (id > FDISK_MAX_VALID_PART_ID) { 2639 fprintf(stderr, "Invalid partition ID\n"); 2640 return (-1); 2641 } 2642 #endif 2643 return (0); 2644 } 2645 2646 /* 2647 * stage0 2648 * Print out interactive menu and process user input. 2649 */ 2650 static void 2651 stage0(void) 2652 { 2653 #ifdef i386 2654 int rval; 2655 #endif 2656 dispmenu(); 2657 for (;;) { 2658 (void) printf(Q_LINE); 2659 (void) printf("Enter Selection: "); 2660 (void) fgets(s, sizeof (s), stdin); 2661 rm_blanks(s); 2662 #ifdef i386 2663 while (!((s[0] > '0') && (s[0] < '8') && 2664 ((s[1] == '\0') || (s[1] == '\n')))) { 2665 #else 2666 while (!((s[0] > '0') && (s[0] < '7') && 2667 ((s[1] == '\0') || (s[1] == '\n')))) { 2668 #endif 2669 (void) printf(E_LINE); /* Clear any previous error */ 2670 #ifdef i386 2671 (void) printf( 2672 "Enter a one-digit number between 1 and 7."); 2673 #else 2674 (void) printf( 2675 "Enter a one-digit number between 1 and 6."); 2676 #endif 2677 (void) printf(Q_LINE); 2678 (void) printf("Enter Selection: "); 2679 (void) fgets(s, sizeof (s), stdin); 2680 rm_blanks(s); 2681 } 2682 (void) printf(E_LINE); 2683 switch (s[0]) { 2684 case '1': 2685 if (pcreate() == -1) 2686 return; 2687 break; 2688 case '2': 2689 if (pchange() == -1) 2690 return; 2691 break; 2692 case '3': 2693 if (pdelete() == -1) 2694 return; 2695 break; 2696 case '4': 2697 if (ppartid() == -1) 2698 return; 2699 break; 2700 #ifdef i386 2701 case '5': 2702 if (fdisk_ext_part_exists(epp)) { 2703 ext_part_menu(); 2704 } else { 2705 printf(Q_LINE); 2706 printf("\nNo extended partition found" 2707 "\n"); 2708 printf("Press enter to continue\n"); 2709 ext_read_input(s); 2710 } 2711 break; 2712 case '6': 2713 /* update disk partition table, if changed */ 2714 if (TableChanged() == 1) { 2715 copy_Table_to_Bootblk(); 2716 dev_mboot_write(0, Bootsect, sectsiz); 2717 } 2718 2719 /* 2720 * If the VTOC table is wrong fix it 2721 * (truncate only) 2722 */ 2723 if (io_adjt) { 2724 fix_slice(); 2725 } 2726 if (!io_readonly) { 2727 rval = fdisk_commit_ext_part(epp); 2728 switch (rval) { 2729 case FDISK_SUCCESS: 2730 /* Success */ 2731 /* Fallthrough */ 2732 case FDISK_ENOEXTPART: 2733 /* Nothing to do */ 2734 break; 2735 case FDISK_EMOUNTED: 2736 printf(Q_LINE); 2737 preach_and_continue(); 2738 continue; 2739 default: 2740 perror("Commit failed"); 2741 exit(1); 2742 } 2743 libfdisk_fini(&epp); 2744 } 2745 (void) close(Dev); 2746 exit(0); 2747 #else 2748 case '5': 2749 /* update disk partition table, if changed */ 2750 if (TableChanged() == 1) { 2751 copy_Table_to_Bootblk(); 2752 dev_mboot_write(0, Bootsect, sectsiz); 2753 } 2754 /* 2755 * If the VTOC table is wrong fix it 2756 * (truncate only) 2757 */ 2758 if (io_adjt) { 2759 fix_slice(); 2760 } 2761 (void) close(Dev); 2762 exit(0); 2763 /* FALLTHRU */ 2764 #endif 2765 #ifdef i386 2766 case '7': 2767 #else 2768 case '6': 2769 #endif 2770 /* 2771 * If the VTOC table is wrong fix it 2772 * (truncate only) 2773 */ 2774 if (io_adjt) { 2775 fix_slice(); 2776 } 2777 (void) close(Dev); 2778 exit(0); 2779 /* FALLTHRU */ 2780 default: 2781 break; 2782 } 2783 copy_Table_to_Bootblk(); 2784 disptbl(); 2785 dispmenu(); 2786 } 2787 } 2788 2789 /* 2790 * pcreate 2791 * Create partition entry in the table (interactive mode). 2792 */ 2793 static int 2794 pcreate(void) 2795 { 2796 uchar_t tsystid = 'z'; 2797 int i, j; 2798 uint32_t numsect; 2799 int retCode = 0; 2800 #ifdef i386 2801 int ext_part_present = 0; 2802 #endif 2803 2804 i = 0; 2805 for (;;) { 2806 if (i == FD_NUMPART) { 2807 (void) printf(E_LINE); 2808 (void) printf( 2809 "The partition table is full!\n" 2810 "You must delete a partition before creating" 2811 " a new one.\n"); 2812 return (-1); 2813 } 2814 if (Table[i].systid == UNUSED) { 2815 break; 2816 } 2817 i++; 2818 } 2819 2820 numsect = 0; 2821 for (i = 0; i < FD_NUMPART; i++) { 2822 if (Table[i].systid != UNUSED) { 2823 numsect += LE_32(Table[i].numsect); 2824 } 2825 #ifdef i386 2826 /* Check if an extended partition already exists */ 2827 if (fdisk_is_dos_extended(Table[i].systid)) { 2828 ext_part_present = 1; 2829 } 2830 #endif 2831 if (numsect >= chs_capacity) { 2832 (void) printf(E_LINE); 2833 (void) printf("There is no more room on the disk for" 2834 " another partition.\n"); 2835 (void) printf( 2836 "You must delete a partition before creating" 2837 " a new one.\n"); 2838 return (-1); 2839 } 2840 } 2841 while (tsystid == 'z') { 2842 2843 /* 2844 * The question here is expanding to more than what is 2845 * allocated for question lines (Q_LINE) which garbles 2846 * at least warning line. Clearing warning line as workaround 2847 * for now. 2848 */ 2849 2850 (void) printf(W_LINE); 2851 (void) printf(Q_LINE); 2852 (void) printf( 2853 "Select the partition type to create:\n" 2854 " 1=SOLARIS2 2=UNIX 3=PCIXOS 4=Other\n" 2855 " 5=DOS12 6=DOS16 7=DOSEXT 8=DOSBIG\n" 2856 " 9=DOS16LBA A=x86 Boot B=Diagnostic C=FAT32\n" 2857 " D=FAT32LBA E=DOSEXTLBA F=EFI 0=Exit? "); 2858 (void) fgets(s, sizeof (s), stdin); 2859 rm_blanks(s); 2860 if ((s[1] != '\0') && (s[1] != '\n')) { 2861 (void) printf(E_LINE); 2862 (void) printf("Invalid selection, try again."); 2863 continue; 2864 } 2865 switch (s[0]) { 2866 case '0': /* exit */ 2867 (void) printf(E_LINE); 2868 return (-1); 2869 case '1': /* Solaris partition */ 2870 tsystid = SUNIXOS2; 2871 break; 2872 case '2': /* UNIX partition */ 2873 tsystid = UNIXOS; 2874 break; 2875 case '3': /* PCIXOS partition */ 2876 tsystid = PCIXOS; 2877 break; 2878 case '4': /* OTHEROS System partition */ 2879 tsystid = OTHEROS; 2880 break; 2881 case '5': 2882 tsystid = DOSOS12; /* DOS 12 bit fat */ 2883 break; 2884 case '6': 2885 tsystid = DOSOS16; /* DOS 16 bit fat */ 2886 break; 2887 case '7': 2888 #ifdef i386 2889 if (ext_part_present) { 2890 printf(Q_LINE); 2891 printf(E_LINE); 2892 fprintf(stderr, 2893 "Extended partition already exists\n"); 2894 fprintf(stderr, "Press enter to continue\n"); 2895 ext_read_input(s); 2896 continue; 2897 } 2898 #endif 2899 tsystid = EXTDOS; 2900 break; 2901 case '8': 2902 tsystid = DOSHUGE; 2903 break; 2904 case '9': 2905 tsystid = FDISK_FAT95; /* FAT16, need extended int13 */ 2906 break; 2907 case 'a': /* x86 Boot partition */ 2908 case 'A': 2909 tsystid = X86BOOT; 2910 break; 2911 case 'b': /* Diagnostic boot partition */ 2912 case 'B': 2913 tsystid = DIAGPART; 2914 break; 2915 case 'c': /* FAT32 */ 2916 case 'C': 2917 tsystid = FDISK_WINDOWS; 2918 break; 2919 case 'd': /* FAT32 and need extended int13 */ 2920 case 'D': 2921 tsystid = FDISK_EXT_WIN; 2922 break; 2923 case 'e': /* Extended partition, need extended int13 */ 2924 case 'E': 2925 #ifdef i386 2926 if (ext_part_present) { 2927 printf(Q_LINE); 2928 printf(E_LINE); 2929 fprintf(stderr, 2930 "Extended partition already exists\n"); 2931 fprintf(stderr, "Press enter to continue\n"); 2932 ext_read_input(s); 2933 continue; 2934 } 2935 #endif 2936 tsystid = FDISK_EXTLBA; 2937 break; 2938 case 'f': 2939 case 'F': 2940 tsystid = EFI_PMBR; 2941 break; 2942 default: 2943 (void) printf(E_LINE); 2944 (void) printf("Invalid selection, try again."); 2945 continue; 2946 } 2947 } 2948 2949 (void) printf(E_LINE); 2950 2951 if (tsystid != EFI_PMBR) { 2952 (void) printf(W_LINE); 2953 if ((dev_capacity > DK_MAX_2TB)) 2954 (void) printf("WARNING: Disk is larger than 2 TB. " 2955 "Upper limit is 2 TB for non-EFI partition ID\n"); 2956 2957 /* create the new partition */ 2958 i = specify(tsystid); 2959 2960 if (i != -1) { 2961 /* see if it should be the active partition */ 2962 (void) printf(E_LINE); 2963 (void) printf(Q_LINE); 2964 2965 (void) printf( 2966 "Should this become the active partition? If " 2967 "yes, it will be activated\n" 2968 "each time the computer is reset or turned on.\n" 2969 "Please type \"y\" or \"n\". "); 2970 2971 if (yesno()) { 2972 (void) printf(E_LINE); 2973 for (j = 0; j < FD_NUMPART; j++) { 2974 if (j == i) { 2975 Table[j].bootid = ACTIVE; 2976 (void) printf(E_LINE); 2977 (void) printf( 2978 "Partition %d is now " 2979 "the active partition.", 2980 j + 1); 2981 } else { 2982 Table[j].bootid = 0; 2983 } 2984 } 2985 } else { 2986 Table[i].bootid = 0; 2987 } 2988 2989 #ifdef i386 2990 /* 2991 * If partition created is an extended partition, null 2992 * out the first sector of the first cylinder of the 2993 * extended partition 2994 */ 2995 if (fdisk_is_dos_extended(Table[i].systid)) { 2996 fdisk_init_ext_part(epp, 2997 LE_32(Table[i].relsect), 2998 LE_32(Table[i].numsect)); 2999 } 3000 #endif 3001 /* set up the return code */ 3002 i = 1; 3003 } 3004 } else { 3005 /* 3006 * partitions of type EFI_PMBR must be the only partitions in 3007 * the table 3008 * 3009 * First, make sure there were no errors the table is 3010 * empty 3011 */ 3012 retCode = verify_tbl(); 3013 3014 if (retCode < 0) { 3015 (void) fprintf(stderr, 3016 "fdisk: Cannot create EFI partition table; \n" 3017 "current partition table is invalid.\n"); 3018 return (-1); 3019 } else if (retCode > 0) { 3020 (void) printf( 3021 "An EFI partition must be the only partition on " 3022 "disk. You may manually delete existing\n" 3023 "partitions, or fdisk can do it.\n" 3024 "Do you want fdisk to destroy existing " 3025 "partitions?\n" 3026 "Please type \"y\" or \"n\". "); 3027 3028 if (yesno()) { 3029 nulltbl(); 3030 } else { 3031 return (-1); 3032 } 3033 } 3034 3035 /* create the table entry - i should be 0 */ 3036 i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 1, 3037 (dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB: 3038 (dev_capacity - 1), 0); 3039 3040 if (i != 0) { 3041 (void) printf("Error creating EFI partition!!!\n"); 3042 i = -1; 3043 } else { 3044 3045 /* EFI partitions are currently never active */ 3046 Table[i].bootid = 0; 3047 3048 /* set up the return code */ 3049 i = 1; 3050 } 3051 } 3052 3053 return (i); 3054 } 3055 3056 /* 3057 * specify 3058 * Query the user to specify the size of the new partition in 3059 * terms of percentage of the disk or by specifying the starting 3060 * cylinder and length in cylinders. 3061 */ 3062 static int 3063 specify(uchar_t tsystid) 3064 { 3065 int i, j, percent = -1; 3066 int cyl, cylen; 3067 diskaddr_t first_free, size_free; 3068 diskaddr_t max_free; 3069 int cyl_size; 3070 struct ipart *partition[FD_NUMPART]; 3071 struct ipart localpart[FD_NUMPART]; 3072 3073 cyl_size = heads * sectors; 3074 3075 /* 3076 * make a local copy of the partition table 3077 * and sort it into relsect order 3078 */ 3079 3080 3081 for (i = 0, j = 0; i < FD_NUMPART; i++) { 3082 if (Table[i].systid != UNUSED) { 3083 localpart[j] = Table[i]; 3084 j++; 3085 } 3086 } 3087 3088 while (j < FD_NUMPART) { 3089 (void) memset(&localpart[j], 0, sizeof (struct ipart)); 3090 j++; 3091 } 3092 3093 for (i = 0; i < FD_NUMPART; i++) 3094 partition[i] = &localpart[i]; 3095 3096 for (i = 0; i < FD_NUMPART - 1; i++) { 3097 if (partition[i]->systid == UNUSED) 3098 break; 3099 for (j = i + 1; j < FD_NUMPART; j++) { 3100 if (partition[j]->systid == UNUSED) 3101 break; 3102 if (LE_32(partition[j]->relsect) < 3103 LE_32(partition[i]->relsect)) { 3104 struct ipart *temp = partition[i]; 3105 partition[i] = partition[j]; 3106 partition[j] = temp; 3107 } 3108 } 3109 } 3110 3111 3112 (void) printf(Q_LINE); 3113 (void) printf( 3114 "Specify the percentage of disk to use for this partition\n" 3115 "(or type \"c\" to specify the size in cylinders). "); 3116 (void) fgets(s, sizeof (s), stdin); 3117 rm_blanks(s); 3118 if (s[0] != 'c') { /* Specify size in percentage of disk */ 3119 i = 0; 3120 while ((s[i] != '\0') && (s[i] != '\n')) { 3121 if (s[i] < '0' || s[i] > '9') { 3122 (void) printf(E_LINE); 3123 (void) printf("Invalid percentage value " 3124 "specified; retry the operation."); 3125 return (-1); 3126 } 3127 i++; 3128 if (i > 3) { 3129 (void) printf(E_LINE); 3130 (void) printf("Invalid percentage value " 3131 "specified; retry the operation."); 3132 return (-1); 3133 } 3134 } 3135 if ((percent = atoi(s)) > 100) { 3136 (void) printf(E_LINE); 3137 (void) printf( 3138 "Percentage value is too large. The value must be" 3139 " between 1 and 100;\nretry the operation.\n"); 3140 return (-1); 3141 } 3142 if (percent < 1) { 3143 (void) printf(E_LINE); 3144 (void) printf( 3145 "Percentage value is too small. The value must be" 3146 " between 1 and 100;\nretry the operation.\n"); 3147 return (-1); 3148 } 3149 3150 if (percent == 100) 3151 cylen = Numcyl_usable - 1; 3152 else 3153 cylen = (Numcyl_usable * percent) / 100; 3154 3155 /* Verify DOS12 partition doesn't exceed max size of 32MB. */ 3156 if ((tsystid == DOSOS12) && 3157 ((long)((long)cylen * cyl_size) > MAXDOS)) { 3158 int n; 3159 n = MAXDOS * 100 / (int)(cyl_size) / Numcyl_usable; 3160 (void) printf(E_LINE); 3161 (void) printf("Maximum size for a DOS partition " 3162 "is %d%%; retry the operation.", 3163 n <= 100 ? n : 100); 3164 return (-1); 3165 } 3166 3167 3168 max_free = 0; 3169 for (i = 0; i < FD_NUMPART; i++) { 3170 3171 /* 3172 * check for free space before partition i 3173 * where i varies from 0 to 3 3174 * 3175 * freespace after partition 3 is unusable 3176 * because there are no free partitions 3177 * 3178 * freespace begins at the end of previous partition 3179 * or cylinder 1 3180 */ 3181 if (i) { 3182 /* Not an empty table */ 3183 first_free = LE_32(partition[i - 1]->relsect) + 3184 LE_32(partition[i - 1]->numsect); 3185 } else { 3186 first_free = cyl_size; 3187 } 3188 3189 /* 3190 * freespace ends before the current partition 3191 * or the end of the disk (chs end) 3192 */ 3193 if (partition[i]->systid == UNUSED) { 3194 size_free = chs_capacity - first_free; 3195 } else { 3196 /* 3197 * Partition might start before cylinder 1. 3198 * Make sure free space is not negative. 3199 */ 3200 size_free = 3201 (LE_32(partition[i]->relsect > first_free)) 3202 ? (LE_32(partition[i]->relsect) - 3203 first_free) : 0; 3204 } 3205 3206 /* save largest free space */ 3207 if (max_free < size_free) 3208 max_free = size_free; 3209 3210 if (((uint64_t)cylen * cyl_size) <= size_free) { 3211 /* We found a place to use */ 3212 break; 3213 } 3214 if (partition[i]->systid == UNUSED) { 3215 (void) printf(E_LINE); 3216 max_free /= (cyl_size); 3217 (void) fprintf(stderr, "fdisk: " 3218 "Maximum percentage available is %lld\n", 3219 100 * max_free / Numcyl_usable); 3220 return (-1); 3221 } 3222 } 3223 3224 (void) printf(E_LINE); 3225 if (i >= FD_NUMPART) { 3226 (void) fprintf(stderr, 3227 "fdisk: Partition table is full.\n"); 3228 return (-1); 3229 } 3230 3231 if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 3232 first_free, cylen * cyl_size, 0)) >= 0) { 3233 return (i); 3234 } 3235 return (-1); 3236 } else { 3237 3238 /* Specifying size in cylinders */ 3239 (void) printf(E_LINE); 3240 (void) printf(Q_LINE); 3241 (void) printf("Enter starting cylinder number: "); 3242 if ((cyl = getcyl()) == -1) { 3243 (void) printf(E_LINE); 3244 (void) printf("Invalid number; retry the operation."); 3245 return (-1); 3246 } 3247 if (cyl == 0) { 3248 (void) printf(E_LINE); 3249 (void) printf( 3250 "New partition cannot start at cylinder 0.\n"); 3251 return (-1); 3252 } 3253 3254 3255 if (cyl >= Numcyl_usable) { 3256 (void) printf(E_LINE); 3257 (void) printf( 3258 "Cylinder %d is out of bounds, " 3259 "the maximum is %d.\n", 3260 cyl, Numcyl_usable - 1); 3261 return (-1); 3262 } 3263 3264 (void) printf(Q_LINE); 3265 (void) printf("Enter partition size in cylinders: "); 3266 if ((cylen = getcyl()) == -1) { 3267 (void) printf(E_LINE); 3268 (void) printf("Invalid number, retry the operation."); 3269 return (-1); 3270 } 3271 3272 for (i = 0; i < FD_NUMPART; i++) { 3273 uint32_t t_relsect, t_numsect; 3274 3275 if (partition[i]->systid == UNUSED) 3276 break; 3277 t_relsect = LE_32(partition[i]->relsect); 3278 t_numsect = LE_32(partition[i]->numsect); 3279 3280 if (cyl * cyl_size >= t_relsect && 3281 cyl * cyl_size < t_relsect + t_numsect) { 3282 (void) printf(E_LINE); 3283 (void) printf( 3284 "Cylinder %d is already allocated" 3285 "\nretry the operation.", 3286 cyl); 3287 return (-1); 3288 } 3289 3290 if (cyl * cyl_size < t_relsect && 3291 (cyl + cylen - 1) * cyl_size > t_relsect) { 3292 (void) printf(E_LINE); 3293 (void) printf( 3294 "Maximum size for partition is %u cylinders" 3295 "\nretry the operation.", 3296 (t_relsect - cyl * cyl_size) / cyl_size); 3297 return (-1); 3298 } 3299 } 3300 3301 /* Verify partition doesn't exceed disk size or 2 TB */ 3302 if (cyl + cylen > Numcyl_usable) { 3303 (void) printf(E_LINE); 3304 if (Numcyl > Numcyl_usable) { 3305 (void) printf( 3306 "Maximum size for partition is %d " 3307 "cylinders; \nretry the operation.", 3308 Numcyl_usable - cyl); 3309 } else { 3310 (void) printf( 3311 "Maximum size for partition is %d " 3312 "cylinders; \nretry the operation.", 3313 Numcyl_usable - cyl); 3314 } 3315 return (-1); 3316 } 3317 3318 /* Verify DOS12 partition doesn't exceed max size of 32MB. */ 3319 if ((tsystid == DOSOS12) && 3320 ((long)((long)cylen * cyl_size) > MAXDOS)) { 3321 (void) printf(E_LINE); 3322 (void) printf( 3323 "Maximum size for a %s partition is %ld cylinders;" 3324 "\nretry the operation.", 3325 Dstr, MAXDOS / (int)(cyl_size)); 3326 return (-1); 3327 } 3328 3329 (void) printf(E_LINE); 3330 i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 3331 cyl * cyl_size, cylen * cyl_size, 0); 3332 if (i < 0) 3333 return (-1); 3334 3335 if (verify_tbl() < 0) { 3336 (void) printf(E_LINE); 3337 (void) printf("fdisk: Cannot create partition table\n"); 3338 return (-1); 3339 } 3340 3341 return (i); 3342 } 3343 } 3344 3345 /* 3346 * dispmenu 3347 * Display command menu (interactive mode). 3348 */ 3349 static void 3350 dispmenu(void) 3351 { 3352 (void) printf(M_LINE); 3353 #ifdef i386 3354 (void) printf( 3355 "SELECT ONE OF THE FOLLOWING:\n" 3356 " 1. Create a partition\n" 3357 " 2. Specify the active partition\n" 3358 " 3. Delete a partition\n" 3359 " 4. Change between Solaris and Solaris2 Partition IDs\n" 3360 " 5. Edit/View extended partitions\n" 3361 " 6. Exit (update disk configuration and exit)\n" 3362 " 7. Cancel (exit without updating disk configuration)\n"); 3363 #else 3364 (void) printf( 3365 "SELECT ONE OF THE FOLLOWING:\n" 3366 " 1. Create a partition\n" 3367 " 2. Specify the active partition\n" 3368 " 3. Delete a partition\n" 3369 " 4. Change between Solaris and Solaris2 Partition IDs\n" 3370 " 5. Exit (update disk configuration and exit)\n" 3371 " 6. Cancel (exit without updating disk configuration)\n"); 3372 #endif 3373 } 3374 3375 /* 3376 * pchange 3377 * Change the ACTIVE designation of a partition. 3378 */ 3379 static int 3380 pchange(void) 3381 { 3382 char s[80]; 3383 int i, j; 3384 3385 for (;;) { 3386 (void) printf(Q_LINE); 3387 { 3388 (void) printf( 3389 "Specify the partition number to boot from" 3390 " (or specify 0 for none): "); 3391 } 3392 (void) fgets(s, sizeof (s), stdin); 3393 rm_blanks(s); 3394 if (((s[1] != '\0') && (s[1] != '\n')) || 3395 (s[0] < '0') || (s[0] > '4')) { 3396 (void) printf(E_LINE); 3397 (void) printf( 3398 "Invalid response, please specify a number" 3399 " between 0 and 4.\n"); 3400 } else { 3401 break; 3402 } 3403 } 3404 if (s[0] == '0') { /* No active partitions */ 3405 for (i = 0; i < FD_NUMPART; i++) { 3406 if (Table[i].systid != UNUSED && 3407 Table[i].bootid == ACTIVE) 3408 Table[i].bootid = 0; 3409 } 3410 (void) printf(E_LINE); 3411 (void) printf( 3412 "No partition is currently marked as active."); 3413 return (0); 3414 } else { /* User has selected a partition to be active */ 3415 3416 i = s[0] - '1'; 3417 3418 if (Table[i].systid == UNUSED) { 3419 (void) printf(E_LINE); 3420 (void) printf("Partition does not exist."); 3421 return (-1); 3422 } 3423 /* a DOS-DATA or EXT-DOS partition cannot be active */ 3424 else if ((Table[i].systid == DOSDATA) || 3425 (Table[i].systid == EXTDOS) || 3426 (Table[i].systid == FDISK_EXTLBA)) { 3427 (void) printf(E_LINE); 3428 (void) printf( 3429 "DOS-DATA, EXT_DOS and EXT_DOS_LBA partitions " 3430 "cannot be made active.\n"); 3431 (void) printf("Select another partition."); 3432 return (-1); 3433 } 3434 Table[i].bootid = ACTIVE; 3435 for (j = 0; j < FD_NUMPART; j++) { 3436 if (j != i) 3437 Table[j].bootid = 0; 3438 } 3439 } 3440 (void) printf(E_LINE); 3441 { 3442 (void) printf( 3443 "Partition %d is now active. The system will start up" 3444 " from this\n", i + 1); 3445 (void) printf("partition after the next reboot."); 3446 } 3447 return (1); 3448 } 3449 3450 /* 3451 * Change between SOLARIS and SOLARIS2 partition id 3452 */ 3453 static int 3454 ppartid(void) 3455 { 3456 char *p, s[80]; 3457 int i; 3458 3459 for (;;) { 3460 (void) printf(Q_LINE); 3461 (void) printf("Specify the partition number to change" 3462 " (or enter 0 to exit): "); 3463 if (!fgets(s, sizeof (s), stdin)) 3464 return (1); 3465 i = strtol(s, &p, 10); 3466 3467 if (*p != '\n' || i < 0 || i > FD_NUMPART) { 3468 (void) printf(E_LINE); 3469 (void) printf( 3470 "Invalid response, retry the operation.\n"); 3471 continue; 3472 } 3473 3474 if (i == 0) { 3475 /* exit delete command */ 3476 (void) printf(E_LINE); /* clear error message */ 3477 return (1); 3478 } 3479 3480 i -= 1; 3481 3482 if (Table[i].systid == SUNIXOS) { 3483 Table[i].systid = SUNIXOS2; 3484 } else if (Table[i].systid == SUNIXOS2) { 3485 Table[i].systid = SUNIXOS; 3486 } else { 3487 (void) printf(E_LINE); 3488 (void) printf( 3489 "Partition %d is not a Solaris partition.", 3490 i + 1); 3491 continue; 3492 } 3493 3494 (void) printf(E_LINE); 3495 (void) printf("Partition %d has been changed.", i + 1); 3496 return (1); 3497 } 3498 } 3499 3500 /* 3501 * pdelete 3502 * Remove partition entry from the table (interactive mode). 3503 */ 3504 static char 3505 pdelete(void) 3506 { 3507 char s[80]; 3508 int i; 3509 char pactive; 3510 3511 DEL1: (void) printf(Q_LINE); 3512 (void) printf("Specify the partition number to delete" 3513 " (or enter 0 to exit): "); 3514 (void) fgets(s, sizeof (s), stdin); 3515 rm_blanks(s); 3516 if ((s[0] == '0')) { /* exit delete command */ 3517 (void) printf(E_LINE); /* clear error message */ 3518 return (1); 3519 } 3520 /* Accept only a single digit between 1 and 4 */ 3521 if (((s[1] != '\0') && (s[1] != '\n')) || 3522 (i = atoi(s)) < 1 || i > FD_NUMPART) { 3523 (void) printf(E_LINE); 3524 (void) printf("Invalid response, retry the operation.\n"); 3525 goto DEL1; 3526 } else { /* Found a digit between 1 and 4 */ 3527 --i; /* Structure begins with element 0 */ 3528 } 3529 3530 if (Table[i].systid == UNUSED) { 3531 (void) printf(E_LINE); 3532 (void) printf("Partition %d does not exist.", i + 1); 3533 return (-1); 3534 } 3535 3536 #ifdef i386 3537 if (fdisk_is_dos_extended(Table[i].systid) && 3538 (Table[i].relsect == fdisk_get_ext_beg_sec(epp)) && 3539 fdisk_get_logical_drive_count(epp)) { 3540 (void) printf(Q_LINE); 3541 (void) printf("There are logical drives inside the" 3542 " extended partition\n"); 3543 (void) printf("Are you sure of proceeding with deletion ?" 3544 " (type \"y\" or \"n\") "); 3545 3546 (void) printf(E_LINE); 3547 if (! yesno()) { 3548 return (1); 3549 } 3550 if (fdisk_mounted_logical_drives(epp) == FDISK_EMOUNTED) { 3551 (void) printf(Q_LINE); 3552 (void) printf("There are mounted logical drives. " 3553 "Committing changes now can cause data loss or " 3554 "corruption. Unmount all logical drives and then " 3555 "try committing the changes again.\n"); 3556 (void) printf("Press enter to continue.\n"); 3557 ext_read_input(s); 3558 return (1); 3559 } 3560 fdisk_delete_ext_part(epp); 3561 } else { 3562 #endif 3563 (void) printf(Q_LINE); 3564 (void) printf("Are you sure you want to delete partition %d?" 3565 " This will make all files and \n", i + 1); 3566 (void) printf("programs in this partition inaccessible (type" 3567 " \"y\" or \"n\"). "); 3568 3569 (void) printf(E_LINE); 3570 if (! yesno()) { 3571 return (1); 3572 } 3573 #ifdef i386 3574 } 3575 #endif 3576 3577 if (Table[i].bootid == ACTIVE) { 3578 pactive = 1; 3579 } else { 3580 pactive = 0; 3581 } 3582 3583 (void) memset(&Table[i], 0, sizeof (struct ipart)); 3584 3585 (void) printf(E_LINE); 3586 (void) printf("Partition %d has been deleted.", i + 1); 3587 3588 if (pactive) { 3589 (void) printf(" This was the active partition."); 3590 } 3591 3592 return (1); 3593 } 3594 3595 /* 3596 * rm_blanks 3597 * Remove blanks from strings of user responses. 3598 */ 3599 static void 3600 rm_blanks(char *s) 3601 { 3602 register int i, j; 3603 3604 for (i = 0; i < CBUFLEN; i++) { 3605 if ((s[i] == ' ') || (s[i] == '\t')) 3606 continue; 3607 else 3608 /* Found first non-blank character of the string */ 3609 break; 3610 } 3611 for (j = 0; i < CBUFLEN; j++, i++) { 3612 if ((s[j] = s[i]) == '\0') { 3613 /* Reached end of string */ 3614 return; 3615 } 3616 } 3617 } 3618 3619 /* 3620 * getcyl 3621 * Take the user-specified cylinder number and convert it from a 3622 * string to a decimal value. 3623 */ 3624 static int 3625 getcyl(void) 3626 { 3627 int slen, i, j; 3628 unsigned int cyl; 3629 (void) fgets(s, sizeof (s), stdin); 3630 rm_blanks(s); 3631 slen = strlen(s); 3632 if (s[slen - 1] == '\n') 3633 slen--; 3634 j = 1; 3635 cyl = 0; 3636 for (i = slen - 1; i >= 0; i--) { 3637 if (s[i] < '0' || s[i] > '9') { 3638 return (-1); 3639 } 3640 cyl += (j * (s[i] - '0')); 3641 j *= 10; 3642 } 3643 return (cyl); 3644 } 3645 3646 /* 3647 * disptbl 3648 * Display the current fdisk table; determine percentage 3649 * of the disk used for each partition. 3650 */ 3651 static void 3652 disptbl(void) 3653 { 3654 int i; 3655 unsigned int startcyl, endcyl, length, percent, remainder; 3656 char *stat, *type; 3657 int is_pmbr = 0; 3658 3659 if ((heads == 0) || (sectors == 0)) { 3660 (void) printf("WARNING: critical disk geometry information" 3661 " missing!\n"); 3662 (void) printf("\theads = %d, sectors = %d\n", heads, sectors); 3663 exit(1); 3664 } 3665 3666 (void) printf(HOME); 3667 (void) printf(T_LINE); 3668 (void) printf(" Total disk size is %d cylinders\n", Numcyl); 3669 (void) printf(" Cylinder size is %d (%d byte) blocks\n\n", 3670 heads * sectors, sectsiz); 3671 (void) printf( 3672 " Cylinders\n"); 3673 (void) printf( 3674 " Partition Status Type Start End Length" 3675 " %%\n"); 3676 (void) printf( 3677 " ========= ====== ============ ===== === ======" 3678 " ==="); 3679 3680 3681 for (i = 0; i < FD_NUMPART; i++) { 3682 3683 if (Table[i].systid == UNUSED) { 3684 continue; 3685 } 3686 3687 if (Table[i].bootid == ACTIVE) 3688 stat = Actvstr; 3689 else 3690 stat = NAstr; 3691 switch (Table[i].systid) { 3692 case UNIXOS: 3693 type = Ustr; 3694 break; 3695 case SUNIXOS: 3696 type = SUstr; 3697 #ifdef i386 3698 if (fdisk_is_linux_swap(epp, Table[i].relsect, 3699 NULL) == 0) 3700 type = LINSWAPstr; 3701 #endif 3702 break; 3703 case SUNIXOS2: 3704 type = SU2str; 3705 break; 3706 case X86BOOT: 3707 type = X86str; 3708 break; 3709 case DOSOS12: 3710 type = Dstr; 3711 break; 3712 case DOSOS16: 3713 type = D16str; 3714 break; 3715 case EXTDOS: 3716 type = EDstr; 3717 break; 3718 case DOSDATA: 3719 type = DDstr; 3720 break; 3721 case DOSHUGE: 3722 type = DBstr; 3723 break; 3724 case PCIXOS: 3725 type = PCstr; 3726 break; 3727 case DIAGPART: 3728 type = DIAGstr; 3729 break; 3730 case FDISK_IFS: 3731 type = IFSstr; 3732 break; 3733 case FDISK_AIXBOOT: 3734 type = AIXstr; 3735 break; 3736 case FDISK_AIXDATA: 3737 type = AIXDstr; 3738 break; 3739 case FDISK_OS2BOOT: 3740 type = OS2str; 3741 break; 3742 case FDISK_WINDOWS: 3743 type = WINstr; 3744 break; 3745 case FDISK_EXT_WIN: 3746 type = EWINstr; 3747 break; 3748 case FDISK_FAT95: 3749 type = FAT95str; 3750 break; 3751 case FDISK_EXTLBA: 3752 type = EXTLstr; 3753 break; 3754 case FDISK_LINUX: 3755 type = LINUXstr; 3756 break; 3757 case FDISK_CPM: 3758 type = CPMstr; 3759 break; 3760 case FDISK_NOVELL2: 3761 type = NOV2str; 3762 break; 3763 case FDISK_NOVELL3: 3764 type = NOVstr; 3765 break; 3766 case FDISK_QNX4: 3767 type = QNXstr; 3768 break; 3769 case FDISK_QNX42: 3770 type = QNX2str; 3771 break; 3772 case FDISK_QNX43: 3773 type = QNX3str; 3774 break; 3775 case FDISK_LINUXNAT: 3776 type = LINNATstr; 3777 break; 3778 case FDISK_NTFSVOL1: 3779 type = NTFSVOL1str; 3780 break; 3781 case FDISK_NTFSVOL2: 3782 type = NTFSVOL2str; 3783 break; 3784 case FDISK_BSD: 3785 type = BSDstr; 3786 break; 3787 case FDISK_NEXTSTEP: 3788 type = NEXTSTEPstr; 3789 break; 3790 case FDISK_BSDIFS: 3791 type = BSDIFSstr; 3792 break; 3793 case FDISK_BSDISWAP: 3794 type = BSDISWAPstr; 3795 break; 3796 case EFI_PMBR: 3797 type = EFIstr; 3798 if (LE_32(Table[i].numsect) == DK_MAX_2TB) 3799 is_pmbr = 1; 3800 3801 break; 3802 default: 3803 type = Ostr; 3804 break; 3805 } 3806 startcyl = LE_32(Table[i].relsect) / 3807 (unsigned long)(heads * sectors); 3808 3809 if (LE_32(Table[i].numsect) == DK_MAX_2TB) { 3810 endcyl = Numcyl - 1; 3811 length = endcyl - startcyl + 1; 3812 } else { 3813 length = LE_32(Table[i].numsect) / 3814 (unsigned long)(heads * sectors); 3815 if (LE_32(Table[i].numsect) % 3816 (unsigned long)(heads * sectors)) 3817 length++; 3818 endcyl = startcyl + length - 1; 3819 } 3820 3821 percent = length * 100 / Numcyl_usable; 3822 if ((remainder = (length * 100 % Numcyl_usable)) != 0) { 3823 if ((remainder * 100 / Numcyl_usable) > 50) { 3824 /* round up */ 3825 percent++; 3826 } 3827 /* Else leave the percent as is since it's already */ 3828 /* rounded down */ 3829 } 3830 if (percent > 100) 3831 percent = 100; 3832 (void) printf( 3833 "\n %d %s %-12.12s %4d %4d %4d" 3834 " %3d", 3835 i + 1, stat, type, startcyl, endcyl, length, percent); 3836 } 3837 3838 /* Print warning message if table is empty */ 3839 if (nopartdefined()) { 3840 (void) printf(W_LINE); 3841 (void) printf("WARNING: no partitions are defined!"); 3842 } else { 3843 /* Clear the warning line */ 3844 (void) printf(W_LINE); 3845 3846 /* Print warning if disk > 2TB and is not EFI PMBR */ 3847 if (!is_pmbr && (dev_capacity > DK_MAX_2TB)) 3848 (void) printf("WARNING: Disk is larger than 2 TB. " 3849 "Upper limit is 2 TB for non-EFI partition ID\n"); 3850 } 3851 } 3852 3853 /* 3854 * print_Table 3855 * Write the detailed fdisk table to standard error for 3856 * the selected disk device. 3857 */ 3858 static void 3859 print_Table(void) 3860 { 3861 int i; 3862 3863 (void) fprintf(stderr, 3864 " SYSID ACT BHEAD BSECT BEGCYL EHEAD ESECT ENDCYL RELSECT" 3865 " NUMSECT\n"); 3866 3867 for (i = 0; i < FD_NUMPART; i++) { 3868 (void) fprintf(stderr, " %-5d ", Table[i].systid); 3869 (void) fprintf(stderr, "%-3d ", Table[i].bootid); 3870 (void) fprintf(stderr, "%-5d ", Table[i].beghead); 3871 (void) fprintf(stderr, "%-5d ", Table[i].begsect & 0x3f); 3872 (void) fprintf(stderr, "%-8d ", 3873 (((uint_t)Table[i].begsect & 0xc0) << 2) + Table[i].begcyl); 3874 3875 (void) fprintf(stderr, "%-5d ", Table[i].endhead); 3876 (void) fprintf(stderr, "%-5d ", Table[i].endsect & 0x3f); 3877 (void) fprintf(stderr, "%-8d ", 3878 (((uint_t)Table[i].endsect & 0xc0) << 2) + Table[i].endcyl); 3879 (void) fprintf(stderr, "%-10u ", LE_32(Table[i].relsect)); 3880 (void) fprintf(stderr, "%-10u\n", LE_32(Table[i].numsect)); 3881 3882 } 3883 } 3884 3885 /* 3886 * copy_Table_to_Old_Table 3887 * Copy Table into Old_Table. The function only copies the systid, 3888 * numsect, relsect, and bootid values because they are the only 3889 * ones compared when determining if Table has changed. 3890 */ 3891 static void 3892 copy_Table_to_Old_Table(void) 3893 { 3894 int i; 3895 for (i = 0; i < FD_NUMPART; i++) { 3896 (void) memcpy(&Old_Table[i], &Table[i], sizeof (Table[0])); 3897 } 3898 } 3899 3900 /* 3901 * nulltbl 3902 * Zero out the systid, numsect, relsect, and bootid values in the 3903 * fdisk table. 3904 */ 3905 static void 3906 nulltbl(void) 3907 { 3908 int i; 3909 3910 for (i = 0; i < FD_NUMPART; i++) { 3911 Table[i].systid = UNUSED; 3912 Table[i].numsect = LE_32(UNUSED); 3913 Table[i].relsect = LE_32(UNUSED); 3914 Table[i].bootid = 0; 3915 skip_verify[i] = 0; 3916 } 3917 } 3918 3919 /* 3920 * copy_Bootblk_to_Table 3921 * Copy the bytes from the boot record to an internal "Table". 3922 * All unused are padded with zeros starting at offset 446. 3923 */ 3924 static void 3925 copy_Bootblk_to_Table(void) 3926 { 3927 int i; 3928 char *bootptr; 3929 struct ipart iparts[FD_NUMPART]; 3930 3931 /* Get an aligned copy of the partition tables */ 3932 (void) memcpy(iparts, Bootblk->parts, sizeof (iparts)); 3933 bootptr = (char *)iparts; /* Points to start of partition table */ 3934 if (LE_16(Bootblk->signature) != MBB_MAGIC) { 3935 /* Signature is missing */ 3936 nulltbl(); 3937 (void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ); 3938 return; 3939 } 3940 /* 3941 * When the DOS fdisk command deletes a partition, it is not 3942 * recognized by the old algorithm. The algorithm that 3943 * follows looks at each entry in the Bootrec and copies all 3944 * those that are valid. 3945 */ 3946 for (i = 0; i < FD_NUMPART; i++) { 3947 if (iparts[i].systid == 0) { 3948 /* Null entry */ 3949 (void) memset(&Table[i], 0, sizeof (struct ipart)); 3950 } else { 3951 fill_ipart(bootptr, &Table[i]); 3952 } 3953 bootptr += sizeof (struct ipart); 3954 } 3955 3956 /* For now, always replace the bootcode with ours */ 3957 (void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ); 3958 copy_Table_to_Bootblk(); 3959 } 3960 3961 /* 3962 * fill_ipart 3963 * Initialize ipart structure values. 3964 */ 3965 static void 3966 fill_ipart(char *bootptr, struct ipart *partp) 3967 { 3968 #ifdef sparc 3969 /* Packing struct ipart for Sparc */ 3970 partp->bootid = getbyte(&bootptr); 3971 partp->beghead = getbyte(&bootptr); 3972 partp->begsect = getbyte(&bootptr); 3973 partp->begcyl = getbyte(&bootptr); 3974 partp->systid = getbyte(&bootptr); 3975 partp->endhead = getbyte(&bootptr); 3976 partp->endsect = getbyte(&bootptr); 3977 partp->endcyl = getbyte(&bootptr); 3978 partp->relsect = (int32_t)getlong(&bootptr); 3979 partp->numsect = (int32_t)getlong(&bootptr); 3980 #else 3981 *partp = *(struct ipart *)bootptr; 3982 #endif 3983 } 3984 3985 /* 3986 * getbyte, getlong 3987 * Get a byte, a short, or a long (SPARC only). 3988 */ 3989 #ifdef sparc 3990 uchar_t 3991 getbyte(char **bp) 3992 { 3993 uchar_t b; 3994 3995 b = (uchar_t)**bp; 3996 *bp = *bp + 1; 3997 return (b); 3998 } 3999 4000 uint32_t 4001 getlong(char **bp) 4002 { 4003 int32_t b, bh, bl; 4004 4005 bh = ((**bp) << 8) | *(*bp + 1); 4006 *bp += 2; 4007 bl = ((**bp) << 8) | *(*bp + 1); 4008 *bp += 2; 4009 4010 b = (bh << 16) | bl; 4011 return ((uint32_t)b); 4012 } 4013 #endif 4014 4015 /* 4016 * copy_Table_to_Bootblk 4017 * Copy the table into the boot record. Note that the unused 4018 * entries will always be the last ones in the table and they are 4019 * marked with 100 in sysind. The the unused portion of the table 4020 * is padded with zeros in the bytes after the used entries. 4021 */ 4022 static void 4023 copy_Table_to_Bootblk(void) 4024 { 4025 struct ipart *boot_ptr, *tbl_ptr; 4026 4027 boot_ptr = (struct ipart *)Bootblk->parts; 4028 tbl_ptr = (struct ipart *)&Table[0].bootid; 4029 for (; tbl_ptr < (struct ipart *)&Table[FD_NUMPART].bootid; 4030 tbl_ptr++, boot_ptr++) { 4031 if (tbl_ptr->systid == UNUSED) 4032 (void) memset(boot_ptr, 0, sizeof (struct ipart)); 4033 else 4034 (void) memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart)); 4035 } 4036 Bootblk->signature = LE_16(MBB_MAGIC); 4037 } 4038 4039 /* 4040 * TableChanged 4041 * Check for any changes in the partition table. 4042 */ 4043 static int 4044 TableChanged(void) 4045 { 4046 int i, changed; 4047 4048 changed = 0; 4049 for (i = 0; i < FD_NUMPART; i++) { 4050 if (memcmp(&Old_Table[i], &Table[i], sizeof (Table[0])) != 0) { 4051 /* Partition table changed, write back to disk */ 4052 changed = 1; 4053 } 4054 } 4055 4056 return (changed); 4057 } 4058 4059 /* 4060 * ffile_write 4061 * Display contents of partition table to standard output or 4062 * another file name without writing it to the disk (-W file). 4063 */ 4064 static void 4065 ffile_write(char *file) 4066 { 4067 register int i; 4068 FILE *fp; 4069 4070 /* 4071 * If file isn't standard output, then it's a file name. 4072 * Open file and write it. 4073 */ 4074 if (file != (char *)stdout) { 4075 if ((fp = fopen(file, "w")) == NULL) { 4076 (void) fprintf(stderr, 4077 "fdisk: Cannot open output file %s.\n", 4078 file); 4079 exit(1); 4080 } 4081 } 4082 else 4083 fp = stdout; 4084 4085 /* 4086 * Write the fdisk table information 4087 */ 4088 (void) fprintf(fp, "\n* %s default fdisk table\n", Dfltdev); 4089 (void) fprintf(fp, "* Dimensions:\n"); 4090 (void) fprintf(fp, "* %4d bytes/sector\n", sectsiz); 4091 (void) fprintf(fp, "* %4d sectors/track\n", sectors); 4092 (void) fprintf(fp, "* %4d tracks/cylinder\n", heads); 4093 (void) fprintf(fp, "* %4d cylinders\n", Numcyl); 4094 (void) fprintf(fp, "*\n"); 4095 /* Write virtual (HBA) geometry, if required */ 4096 if (v_flag) { 4097 (void) fprintf(fp, "* HBA Dimensions:\n"); 4098 (void) fprintf(fp, "* %4d bytes/sector\n", sectsiz); 4099 (void) fprintf(fp, "* %4d sectors/track\n", hba_sectors); 4100 (void) fprintf(fp, "* %4d tracks/cylinder\n", hba_heads); 4101 (void) fprintf(fp, "* %4d cylinders\n", hba_Numcyl); 4102 (void) fprintf(fp, "*\n"); 4103 } 4104 (void) fprintf(fp, "* systid:\n"); 4105 (void) fprintf(fp, "* 1: DOSOS12\n"); 4106 (void) fprintf(fp, "* 2: PCIXOS\n"); 4107 (void) fprintf(fp, "* 4: DOSOS16\n"); 4108 (void) fprintf(fp, "* 5: EXTDOS\n"); 4109 (void) fprintf(fp, "* 6: DOSBIG\n"); 4110 (void) fprintf(fp, "* 7: FDISK_IFS\n"); 4111 (void) fprintf(fp, "* 8: FDISK_AIXBOOT\n"); 4112 (void) fprintf(fp, "* 9: FDISK_AIXDATA\n"); 4113 (void) fprintf(fp, "* 10: FDISK_0S2BOOT\n"); 4114 (void) fprintf(fp, "* 11: FDISK_WINDOWS\n"); 4115 (void) fprintf(fp, "* 12: FDISK_EXT_WIN\n"); 4116 (void) fprintf(fp, "* 14: FDISK_FAT95\n"); 4117 (void) fprintf(fp, "* 15: FDISK_EXTLBA\n"); 4118 (void) fprintf(fp, "* 18: DIAGPART\n"); 4119 (void) fprintf(fp, "* 65: FDISK_LINUX\n"); 4120 (void) fprintf(fp, "* 82: FDISK_CPM\n"); 4121 (void) fprintf(fp, "* 86: DOSDATA\n"); 4122 (void) fprintf(fp, "* 98: OTHEROS\n"); 4123 (void) fprintf(fp, "* 99: UNIXOS\n"); 4124 (void) fprintf(fp, "* 100: FDISK_NOVELL2\n"); 4125 (void) fprintf(fp, "* 101: FDISK_NOVELL3\n"); 4126 (void) fprintf(fp, "* 119: FDISK_QNX4\n"); 4127 (void) fprintf(fp, "* 120: FDISK_QNX42\n"); 4128 (void) fprintf(fp, "* 121: FDISK_QNX43\n"); 4129 (void) fprintf(fp, "* 130: SUNIXOS\n"); 4130 (void) fprintf(fp, "* 131: FDISK_LINUXNAT\n"); 4131 (void) fprintf(fp, "* 134: FDISK_NTFSVOL1\n"); 4132 (void) fprintf(fp, "* 135: FDISK_NTFSVOL2\n"); 4133 (void) fprintf(fp, "* 165: FDISK_BSD\n"); 4134 (void) fprintf(fp, "* 167: FDISK_NEXTSTEP\n"); 4135 (void) fprintf(fp, "* 183: FDISK_BSDIFS\n"); 4136 (void) fprintf(fp, "* 184: FDISK_BSDISWAP\n"); 4137 (void) fprintf(fp, "* 190: X86BOOT\n"); 4138 (void) fprintf(fp, "* 191: SUNIXOS2\n"); 4139 (void) fprintf(fp, "* 238: EFI_PMBR\n"); 4140 (void) fprintf(fp, "* 239: EFI_FS\n"); 4141 (void) fprintf(fp, "*\n"); 4142 (void) fprintf(fp, 4143 "\n* Id Act Bhead Bsect Bcyl Ehead Esect Ecyl" 4144 " Rsect Numsect\n"); 4145 4146 for (i = 0; i < FD_NUMPART; i++) { 4147 (void) fprintf(fp, 4148 " %-5d %-4d %-6d %-6d %-7d %-6d %-6d %-7d %-10u" 4149 " %-10u\n", 4150 Table[i].systid, 4151 Table[i].bootid, 4152 Table[i].beghead, 4153 Table[i].begsect & 0x3f, 4154 ((Table[i].begcyl & 0xff) | ((Table[i].begsect & 4155 0xc0) << 2)), 4156 Table[i].endhead, 4157 Table[i].endsect & 0x3f, 4158 ((Table[i].endcyl & 0xff) | ((Table[i].endsect & 4159 0xc0) << 2)), 4160 LE_32(Table[i].relsect), 4161 LE_32(Table[i].numsect)); 4162 } 4163 #ifdef i386 4164 if (fdisk_ext_part_exists(epp)) { 4165 struct ipart ext_tab; 4166 logical_drive_t *temp; 4167 uint32_t rsect, numsect, tempsect = 0; 4168 for (temp = fdisk_get_ld_head(epp); temp != NULL; 4169 temp = temp->next) { 4170 ext_tab = temp->parts[0]; 4171 rsect = tempsect + LE_32(ext_tab.relsect) + 4172 fdisk_get_ext_beg_sec(epp); 4173 numsect = LE_32(ext_tab.numsect); 4174 tempsect = LE_32(temp->parts[1].relsect); 4175 (void) fprintf(fp, 4176 " %-5d %-4d %-6d %-6d %-7d %-6d %-6d " 4177 "%-7d %-8u %-8u\n", 4178 ext_tab.systid, 4179 ext_tab.bootid, 4180 ext_tab.beghead, 4181 ext_tab.begsect & 0x3f, 4182 ((ext_tab.begcyl & 0xff) | 4183 ((ext_tab.begsect & 0xc0) << 2)), 4184 ext_tab.endhead, 4185 ext_tab.endsect & 0x3f, 4186 ((ext_tab.endcyl & 0xff) | 4187 ((ext_tab.endsect & 0xc0) << 2)), 4188 rsect, 4189 numsect); 4190 } 4191 } 4192 #endif 4193 4194 if (fp != stdout) 4195 (void) fclose(fp); 4196 } 4197 4198 /* 4199 * fix_slice 4200 * Read the VTOC table on the Solaris partition and check that no 4201 * slices exist that extend past the end of the Solaris partition. 4202 * If no Solaris partition exists, nothing is done. 4203 */ 4204 static void 4205 fix_slice(void) 4206 { 4207 int i; 4208 uint32_t numsect; 4209 4210 if (io_image) { 4211 return; 4212 } 4213 4214 for (i = 0; i < FD_NUMPART; i++) { 4215 if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) { 4216 /* 4217 * Only the size matters (not starting point), since 4218 * VTOC entries are relative to the start of 4219 * the partition. 4220 */ 4221 numsect = LE_32(Table[i].numsect); 4222 break; 4223 } 4224 } 4225 4226 if (i >= FD_NUMPART) { 4227 if (!io_nifdisk) { 4228 (void) fprintf(stderr, 4229 "fdisk: No Solaris partition found - VTOC not" 4230 " checked.\n"); 4231 } 4232 return; 4233 } 4234 4235 if (readvtoc() != VTOC_OK) { 4236 exit(1); /* Failed to read the VTOC */ 4237 } 4238 for (i = 0; i < V_NUMPAR; i++) { 4239 /* Special case for slice two (entire disk) */ 4240 if (i == 2) { 4241 if (disk_vtoc.v_part[i].p_start != 0) { 4242 (void) fprintf(stderr, 4243 "slice %d starts at %llu, is not at" 4244 " start of partition", 4245 i, disk_vtoc.v_part[i].p_start); 4246 if (!io_nifdisk) { 4247 (void) printf(" adjust ?:"); 4248 if (yesno()) 4249 disk_vtoc.v_part[i].p_start = 0; 4250 } else { 4251 disk_vtoc.v_part[i].p_start = 0; 4252 (void) fprintf(stderr, " adjusted!\n"); 4253 } 4254 4255 } 4256 if (disk_vtoc.v_part[i].p_size != numsect) { 4257 (void) fprintf(stderr, 4258 "slice %d size %llu does not cover" 4259 " complete partition", 4260 i, disk_vtoc.v_part[i].p_size); 4261 if (!io_nifdisk) { 4262 (void) printf(" adjust ?:"); 4263 if (yesno()) 4264 disk_vtoc.v_part[i].p_size = 4265 numsect; 4266 } else { 4267 disk_vtoc.v_part[i].p_size = numsect; 4268 (void) fprintf(stderr, " adjusted!\n"); 4269 } 4270 } 4271 if (disk_vtoc.v_part[i].p_tag != V_BACKUP) { 4272 (void) fprintf(stderr, 4273 "slice %d tag was %d should be %d", 4274 i, disk_vtoc.v_part[i].p_tag, 4275 V_BACKUP); 4276 if (!io_nifdisk) { 4277 (void) printf(" fix ?:"); 4278 if (yesno()) 4279 disk_vtoc.v_part[i].p_tag = 4280 V_BACKUP; 4281 } else { 4282 disk_vtoc.v_part[i].p_tag = V_BACKUP; 4283 (void) fprintf(stderr, " fixed!\n"); 4284 } 4285 } 4286 continue; 4287 } 4288 if (io_ADJT) { 4289 if (disk_vtoc.v_part[i].p_start > numsect || 4290 disk_vtoc.v_part[i].p_start + 4291 disk_vtoc.v_part[i].p_size > numsect) { 4292 (void) fprintf(stderr, 4293 "slice %d (start %llu, end %llu)" 4294 " is larger than the partition", 4295 i, disk_vtoc.v_part[i].p_start, 4296 disk_vtoc.v_part[i].p_start + 4297 disk_vtoc.v_part[i].p_size); 4298 if (!io_nifdisk) { 4299 (void) printf(" remove ?:"); 4300 if (yesno()) { 4301 disk_vtoc.v_part[i].p_size = 0; 4302 disk_vtoc.v_part[i].p_start = 0; 4303 disk_vtoc.v_part[i].p_tag = 0; 4304 disk_vtoc.v_part[i].p_flag = 0; 4305 } 4306 } else { 4307 disk_vtoc.v_part[i].p_size = 0; 4308 disk_vtoc.v_part[i].p_start = 0; 4309 disk_vtoc.v_part[i].p_tag = 0; 4310 disk_vtoc.v_part[i].p_flag = 0; 4311 (void) fprintf(stderr, 4312 " removed!\n"); 4313 } 4314 } 4315 continue; 4316 } 4317 if (disk_vtoc.v_part[i].p_start > numsect) { 4318 (void) fprintf(stderr, 4319 "slice %d (start %llu) is larger than the " 4320 "partition", i, disk_vtoc.v_part[i].p_start); 4321 if (!io_nifdisk) { 4322 (void) printf(" remove ?:"); 4323 if (yesno()) { 4324 disk_vtoc.v_part[i].p_size = 0; 4325 disk_vtoc.v_part[i].p_start = 0; 4326 disk_vtoc.v_part[i].p_tag = 0; 4327 disk_vtoc.v_part[i].p_flag = 0; 4328 } 4329 } else { 4330 disk_vtoc.v_part[i].p_size = 0; 4331 disk_vtoc.v_part[i].p_start = 0; 4332 disk_vtoc.v_part[i].p_tag = 0; 4333 disk_vtoc.v_part[i].p_flag = 0; 4334 (void) fprintf(stderr, 4335 " removed!\n"); 4336 } 4337 } else if (disk_vtoc.v_part[i].p_start 4338 + disk_vtoc.v_part[i].p_size > numsect) { 4339 (void) fprintf(stderr, 4340 "slice %d (end %llu) is larger" 4341 " than the partition", 4342 i, 4343 disk_vtoc.v_part[i].p_start + 4344 disk_vtoc.v_part[i].p_size); 4345 if (!io_nifdisk) { 4346 (void) printf(" adjust ?:"); 4347 if (yesno()) { 4348 disk_vtoc.v_part[i].p_size = numsect; 4349 } 4350 } else { 4351 disk_vtoc.v_part[i].p_size = numsect; 4352 (void) fprintf(stderr, " adjusted!\n"); 4353 } 4354 } 4355 } 4356 #if 1 /* bh for now */ 4357 /* Make the VTOC look sane - ha ha */ 4358 disk_vtoc.v_version = V_VERSION; 4359 disk_vtoc.v_sanity = VTOC_SANE; 4360 disk_vtoc.v_nparts = V_NUMPAR; 4361 if (disk_vtoc.v_sectorsz == 0) 4362 disk_vtoc.v_sectorsz = NBPSCTR; 4363 #endif 4364 4365 /* Write the VTOC back to the disk */ 4366 if (!io_readonly) 4367 (void) writevtoc(); 4368 } 4369 4370 /* 4371 * yesno 4372 * Get yes or no answer. Return 1 for yes and 0 for no. 4373 */ 4374 4375 static int 4376 yesno(void) 4377 { 4378 char s[80]; 4379 4380 for (;;) { 4381 (void) fgets(s, sizeof (s), stdin); 4382 rm_blanks(s); 4383 if (((s[1] != '\0') && (s[1] != '\n')) || 4384 ((s[0] != 'y') && (s[0] != 'n'))) { 4385 (void) printf(E_LINE); 4386 (void) printf("Please answer with \"y\" or \"n\": "); 4387 continue; 4388 } 4389 if (s[0] == 'y') 4390 return (1); 4391 else 4392 return (0); 4393 } 4394 } 4395 4396 /* 4397 * readvtoc 4398 * Read the VTOC from the Solaris partition of the device. 4399 */ 4400 static int 4401 readvtoc(void) 4402 { 4403 int i; 4404 int retval = VTOC_OK; 4405 4406 if ((i = read_extvtoc(Dev, &disk_vtoc)) < VTOC_OK) { 4407 if (i == VT_EINVAL) { 4408 (void) fprintf(stderr, "fdisk: Invalid VTOC.\n"); 4409 vt_inval++; 4410 retval = VTOC_INVAL; 4411 } else if (i == VT_ENOTSUP) { 4412 (void) fprintf(stderr, "fdisk: partition may have EFI " 4413 "GPT\n"); 4414 retval = VTOC_NOTSUP; 4415 } else { 4416 (void) fprintf(stderr, "fdisk: Cannot read VTOC.\n"); 4417 retval = VTOC_RWERR; 4418 } 4419 } 4420 return (retval); 4421 } 4422 4423 /* 4424 * writevtoc 4425 * Write the VTOC to the Solaris partition on the device. 4426 */ 4427 static int 4428 writevtoc(void) 4429 { 4430 int i; 4431 int retval = 0; 4432 4433 if ((i = write_extvtoc(Dev, &disk_vtoc)) != 0) { 4434 if (i == VT_EINVAL) { 4435 (void) fprintf(stderr, 4436 "fdisk: Invalid entry exists in VTOC.\n"); 4437 retval = VTOC_INVAL; 4438 } else if (i == VT_ENOTSUP) { 4439 (void) fprintf(stderr, "fdisk: partition may have EFI " 4440 "GPT\n"); 4441 retval = VTOC_NOTSUP; 4442 } else { 4443 (void) fprintf(stderr, "fdisk: Cannot write VTOC.\n"); 4444 retval = VTOC_RWERR; 4445 } 4446 } 4447 return (retval); 4448 } 4449 4450 /* 4451 * efi_ioctl 4452 * issues DKIOCSETEFI IOCTL 4453 * (duplicate of private efi_ioctl() in rdwr_efi.c 4454 */ 4455 static int 4456 efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc) 4457 { 4458 void *data = dk_ioc->dki_data; 4459 int error; 4460 4461 dk_ioc->dki_data_64 = (uintptr_t)data; 4462 error = ioctl(fd, cmd, (void *)dk_ioc); 4463 4464 return (error); 4465 } 4466 4467 /* 4468 * clear_efi 4469 * Clear EFI labels from the EFI_PMBR partition on the device 4470 * This function is modeled on the libefi(3LIB) call efi_write() 4471 */ 4472 static int 4473 clear_efi(void) 4474 { 4475 struct dk_gpt *efi_vtoc; 4476 dk_efi_t dk_ioc; 4477 4478 /* 4479 * see if we can read the EFI label 4480 */ 4481 if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) { 4482 return (VT_ERROR); 4483 } 4484 4485 /* 4486 * set up the dk_ioc structure for writing 4487 */ 4488 dk_ioc.dki_lba = 1; 4489 dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + efi_vtoc->efi_lbasize; 4490 4491 if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL) { 4492 return (VT_ERROR); 4493 } 4494 4495 /* 4496 * clear the primary label 4497 */ 4498 if (io_debug) { 4499 (void) fprintf(stderr, 4500 "\tClearing primary EFI label at block %lld\n", 4501 dk_ioc.dki_lba); 4502 } 4503 4504 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) { 4505 free(dk_ioc.dki_data); 4506 switch (errno) { 4507 case EIO: 4508 return (VT_EIO); 4509 case EINVAL: 4510 return (VT_EINVAL); 4511 default: 4512 return (VT_ERROR); 4513 } 4514 } 4515 4516 /* 4517 * clear the backup partition table 4518 */ 4519 dk_ioc.dki_lba = efi_vtoc->efi_last_u_lba + 1; 4520 dk_ioc.dki_length -= efi_vtoc->efi_lbasize; 4521 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data + 4522 efi_vtoc->efi_lbasize); 4523 if (io_debug) { 4524 (void) fprintf(stderr, 4525 "\tClearing backup partition table at block %lld\n", 4526 dk_ioc.dki_lba); 4527 } 4528 4529 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) { 4530 (void) fprintf(stderr, "\tUnable to clear backup EFI label at " 4531 "block %llu; errno %d\n", efi_vtoc->efi_last_u_lba + 1, 4532 errno); 4533 } 4534 4535 /* 4536 * clear the backup label 4537 */ 4538 dk_ioc.dki_lba = efi_vtoc->efi_last_lba; 4539 dk_ioc.dki_length = efi_vtoc->efi_lbasize; 4540 dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data - 4541 efi_vtoc->efi_lbasize); 4542 if (io_debug) { 4543 (void) fprintf(stderr, "\tClearing backup label at block " 4544 "%lld\n", dk_ioc.dki_lba); 4545 } 4546 4547 if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) { 4548 (void) fprintf(stderr, 4549 "\tUnable to clear backup EFI label at " 4550 "block %llu; errno %d\n", 4551 efi_vtoc->efi_last_lba, 4552 errno); 4553 } 4554 4555 free(dk_ioc.dki_data); 4556 efi_free(efi_vtoc); 4557 4558 return (0); 4559 } 4560 4561 /* 4562 * clear_vtoc 4563 * Clear the VTOC from the current or previous Solaris partition on the 4564 * device. 4565 */ 4566 static void 4567 clear_vtoc(int table, int part) 4568 { 4569 struct ipart *clr_table; 4570 char *disk_label; 4571 uint32_t pcyl, ncyl, count; 4572 diskaddr_t backup_block, solaris_offset; 4573 ssize_t bytes; 4574 off_t seek_byte; 4575 4576 #ifdef DEBUG 4577 char *read_label; 4578 #endif /* DEBUG */ 4579 4580 if (table == OLD) { 4581 clr_table = &Old_Table[part]; 4582 } else { 4583 clr_table = &Table[part]; 4584 } 4585 4586 disk_label = (char *)calloc(sectsiz, 1); 4587 if (disk_label == NULL) { 4588 return; 4589 } 4590 4591 seek_byte = (off_t)(LE_32(clr_table->relsect) + VTOC_OFFSET) * sectsiz; 4592 4593 if (io_debug) { 4594 (void) fprintf(stderr, 4595 "\tClearing primary VTOC at byte %llu (block %llu)\n", 4596 (uint64_t)seek_byte, 4597 (uint64_t)(LE_32(clr_table->relsect) + VTOC_OFFSET)); 4598 } 4599 4600 if (lseek(Dev, seek_byte, SEEK_SET) == -1) { 4601 (void) fprintf(stderr, 4602 "\tError seeking to primary label at byte %llu\n", 4603 (uint64_t)seek_byte); 4604 free(disk_label); 4605 return; 4606 } 4607 4608 bytes = write(Dev, disk_label, sectsiz); 4609 4610 if (bytes != sectsiz) { 4611 (void) fprintf(stderr, 4612 "\tWarning: only %d bytes written to clear primary" 4613 " VTOC!\n", bytes); 4614 } 4615 4616 #ifdef DEBUG 4617 if (lseek(Dev, seek_byte, SEEK_SET) == -1) { 4618 (void) fprintf(stderr, 4619 "DEBUG: Error seeking to primary label at byte %llu\n", 4620 (uint64_t)seek_byte); 4621 free(disk_label); 4622 return; 4623 } else { 4624 (void) fprintf(stderr, 4625 "DEBUG: Successful lseek() to byte %llu\n", 4626 (uint64_t)seek_byte); 4627 } 4628 4629 read_label = (char *)calloc(sectsiz, 1); 4630 if (read_label == NULL) { 4631 free(disk_label); 4632 return; 4633 } 4634 4635 bytes = read(Dev, read_label, sectsiz); 4636 4637 if (bytes != sectsiz) { 4638 (void) fprintf(stderr, 4639 "DEBUG: Warning: only %d bytes read of label\n", 4640 bytes); 4641 } 4642 4643 if (memcmp(disk_label, read_label, sectsiz) != 0) { 4644 (void) fprintf(stderr, 4645 "DEBUG: Warning: disk_label and read_label differ!!!\n"); 4646 } else { 4647 (void) fprintf(stderr, "DEBUG Good compare of disk_label and " 4648 "read_label\n"); 4649 } 4650 #endif /* DEBUG */ 4651 4652 /* Clear backup label */ 4653 pcyl = LE_32(clr_table->numsect) / (heads * sectors); 4654 solaris_offset = LE_32(clr_table->relsect); 4655 ncyl = pcyl - acyl; 4656 4657 backup_block = ((ncyl + acyl - 1) * 4658 (heads * sectors)) + ((heads - 1) * sectors) + 1; 4659 4660 for (count = 1; count < 6; count++) { 4661 seek_byte = (off_t)(solaris_offset + backup_block) * sectsiz; 4662 4663 if (lseek(Dev, seek_byte, SEEK_SET) == -1) { 4664 (void) fprintf(stderr, 4665 "\tError seeking to backup label at byte %llu on " 4666 "%s.\n", (uint64_t)seek_byte, Dfltdev); 4667 free(disk_label); 4668 #ifdef DEBUG 4669 free(read_label); 4670 #endif /* DEBUG */ 4671 return; 4672 } 4673 4674 if (io_debug) { 4675 (void) fprintf(stderr, "\tClearing backup VTOC at" 4676 " byte %llu (block %llu)\n", 4677 (uint64_t)seek_byte, 4678 (uint64_t)(solaris_offset + backup_block)); 4679 } 4680 4681 bytes = write(Dev, disk_label, sectsiz); 4682 4683 if (bytes != sectsiz) { 4684 (void) fprintf(stderr, 4685 "\t\tWarning: only %d bytes written to " 4686 "clear backup VTOC at block %llu!\n", bytes, 4687 (uint64_t)(solaris_offset + backup_block)); 4688 } 4689 4690 #ifdef DEBUG 4691 if (lseek(Dev, seek_byte, SEEK_SET) == -1) { 4692 (void) fprintf(stderr, 4693 "DEBUG: Error seeking to backup label at byte %llu\n", 4694 (uint64_t)seek_byte); 4695 free(disk_label); 4696 free(read_label); 4697 return; 4698 } else { 4699 (void) fprintf(stderr, 4700 "DEBUG: Successful lseek() to byte %llu\n", 4701 (uint64_t)seek_byte); 4702 } 4703 4704 bytes = read(Dev, read_label, sectsiz); 4705 4706 if (bytes != sectsiz) { 4707 (void) fprintf(stderr, 4708 "DEBUG: Warning: only %d bytes read of backup label\n", 4709 bytes); 4710 } 4711 4712 if (memcmp(disk_label, read_label, sectsiz) != 0) { 4713 (void) fprintf(stderr, 4714 "DEBUG: Warning: disk_label and read_label differ!!!\n"); 4715 } else { 4716 (void) fprintf(stderr, 4717 "DEBUG: Good compare of disk_label and backup " 4718 "read_label\n"); 4719 } 4720 4721 #endif /* DEBUG */ 4722 4723 backup_block += 2; 4724 } 4725 4726 #ifdef DEBUG 4727 free(read_label); 4728 #endif /* DEBUG */ 4729 free(disk_label); 4730 } 4731 4732 #define FDISK_STANDARD_LECTURE \ 4733 "Fdisk is normally used with the device that " \ 4734 "represents the entire fixed disk.\n" \ 4735 "(For example, /dev/rdsk/c0d0p0 on x86 or " \ 4736 "/dev/rdsk/c0t5d0s2 on sparc).\n" 4737 4738 #define FDISK_LECTURE_NOT_SECTOR_ZERO \ 4739 "The device does not appear to include absolute\n" \ 4740 "sector 0 of the PHYSICAL disk " \ 4741 "(the normal location for an fdisk table).\n" 4742 4743 #define FDISK_LECTURE_NOT_FULL \ 4744 "The device does not appear to encompass the entire PHYSICAL disk.\n" 4745 4746 #define FDISK_LECTURE_NO_VTOC \ 4747 "Unable to find a volume table of contents.\n" \ 4748 "Cannot verify the device encompasses the full PHYSICAL disk.\n" 4749 4750 #define FDISK_LECTURE_NO_GEOM \ 4751 "Unable to get geometry from device.\n" \ 4752 "Cannot verify the device encompasses the full PHYSICAL disk.\n" 4753 4754 #define FDISK_SHALL_I_CONTINUE \ 4755 "Are you sure you want to continue? (y/n) " 4756 4757 /* 4758 * lecture_and_query 4759 * Called when a sanity check fails. This routine gives a warning 4760 * specific to the check that fails, followed by a generic lecture 4761 * about the "right" device to supply as input. Then, if appropriate, 4762 * it will prompt the user on whether or not they want to continue. 4763 * Inappropriate times for prompting are when the user has selected 4764 * non-interactive mode or read-only mode. 4765 */ 4766 static int 4767 lecture_and_query(char *warning, char *devname) 4768 { 4769 if (io_nifdisk) 4770 return (0); 4771 4772 (void) fprintf(stderr, "WARNING: Device %s: \n", devname); 4773 (void) fprintf(stderr, "%s", warning); 4774 (void) fprintf(stderr, FDISK_STANDARD_LECTURE); 4775 (void) fprintf(stderr, FDISK_SHALL_I_CONTINUE); 4776 4777 return (yesno()); 4778 } 4779 4780 static void 4781 sanity_check_provided_device(char *devname, int fd) 4782 { 4783 struct extvtoc v; 4784 struct dk_geom d; 4785 struct part_info pi; 4786 struct extpart_info extpi; 4787 diskaddr_t totsize; 4788 int idx = -1; 4789 4790 /* 4791 * First try the PARTINFO ioctl. If it works, we will be able 4792 * to tell if they've specified the full disk partition by checking 4793 * to see if they've specified a partition that starts at sector 0. 4794 */ 4795 if (ioctl(fd, DKIOCEXTPARTINFO, &extpi) != -1) { 4796 if (extpi.p_start != 0) { 4797 if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO, 4798 devname)) { 4799 (void) close(fd); 4800 exit(1); 4801 } 4802 } 4803 } else if (ioctl(fd, DKIOCPARTINFO, &pi) != -1) { 4804 if (pi.p_start != 0) { 4805 if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO, 4806 devname)) { 4807 (void) close(fd); 4808 exit(1); 4809 } 4810 } 4811 } else { 4812 if ((idx = read_extvtoc(fd, &v)) < 0) { 4813 if (!lecture_and_query(FDISK_LECTURE_NO_VTOC, 4814 devname)) { 4815 (void) close(fd); 4816 exit(1); 4817 } 4818 return; 4819 } 4820 if (ioctl(fd, DKIOCGGEOM, &d) == -1) { 4821 perror(devname); 4822 if (!lecture_and_query(FDISK_LECTURE_NO_GEOM, 4823 devname)) { 4824 (void) close(fd); 4825 exit(1); 4826 } 4827 return; 4828 } 4829 totsize = (diskaddr_t)d.dkg_ncyl * d.dkg_nhead * d.dkg_nsect; 4830 if (v.v_part[idx].p_size != totsize) { 4831 if (!lecture_and_query(FDISK_LECTURE_NOT_FULL, 4832 devname)) { 4833 (void) close(fd); 4834 exit(1); 4835 } 4836 } 4837 } 4838 } 4839 4840 4841 /* 4842 * get_node 4843 * Called from main to construct the name of the device node to open. 4844 * Initially tries to stat the node exactly as provided, if that fails 4845 * we prepend the default path (/dev/rdsk/). 4846 */ 4847 static char * 4848 get_node(char *devname) 4849 { 4850 char *node; 4851 struct stat statbuf; 4852 size_t space; 4853 4854 /* Don't do anything if we are skipping device checks */ 4855 if (io_image) 4856 return (devname); 4857 4858 node = devname; 4859 4860 /* Try the node as provided first */ 4861 if (stat(node, (struct stat *)&statbuf) == -1) { 4862 /* 4863 * Copy the passed in string to a new buffer, prepend the 4864 * default path and try again. 4865 */ 4866 space = strlen(DEFAULT_PATH) + strlen(devname) + 1; 4867 4868 if ((node = malloc(space)) == NULL) { 4869 (void) fprintf(stderr, "fdisk: Unable to obtain memory " 4870 "for device node.\n"); 4871 exit(1); 4872 } 4873 4874 /* Copy over the default path and the provided node */ 4875 (void) strncpy(node, DEFAULT_PATH, strlen(DEFAULT_PATH)); 4876 space -= strlen(DEFAULT_PATH); 4877 (void) strlcpy(node + strlen(DEFAULT_PATH), devname, space); 4878 4879 /* Try to stat it again */ 4880 if (stat(node, (struct stat *)&statbuf) == -1) { 4881 /* Failed all options, give up */ 4882 (void) fprintf(stderr, 4883 "fdisk: Cannot stat device %s.\n", 4884 devname); 4885 exit(1); 4886 } 4887 } 4888 4889 /* Make sure the device specified is the raw device */ 4890 if ((statbuf.st_mode & S_IFMT) != S_IFCHR) { 4891 (void) fprintf(stderr, 4892 "fdisk: %s must be a raw device.\n", node); 4893 exit(1); 4894 } 4895 4896 return (node); 4897 } 4898 4899 #ifdef i386 4900 static void 4901 preach_and_continue() 4902 { 4903 (void) fprintf(stderr, "There are mounted logical drives. Committing " 4904 "changes now can lead to inconsistancy in internal system state " 4905 "which can eventually cause data loss or corruption. Unmount all " 4906 "logical drives and try committing the changes again.\n"); 4907 ext_read_input(s); 4908 } 4909 4910 /* 4911 * Convert a given partition ID to an descriptive string. 4912 * Just an index into the partition types table. 4913 */ 4914 void 4915 id_to_name(uchar_t sysid, char *buffer) 4916 { 4917 strcpy(buffer, fdisk_part_types[sysid]); 4918 } 4919 4920 /* 4921 * Procedure to check the validity of the extended partition menu option 4922 * entered by the user 4923 */ 4924 static int 4925 ext_invalid_option(char ch) 4926 { 4927 char *p; 4928 4929 p = strchr(ext_part_menu_opts, tolower(ch)); 4930 4931 if (p == NULL) { 4932 return (1); 4933 } 4934 return (0); 4935 } 4936 4937 /* 4938 * Read 16 bytes of the input (assuming that no valid user input spans more 4939 * than that). Flush the input stream, so that the next read does not reap 4940 * stale data from the previous input that was not processed. 4941 * Note that fgets also reads the trailing '\n' 4942 */ 4943 static void 4944 ext_read_input(char *buf) 4945 { 4946 fgets(buf, 16, stdin); 4947 fflush(stdin); 4948 } 4949 4950 /* 4951 * Procedure to read and validate the user option at the extended partition menu 4952 */ 4953 static int 4954 ext_read_options(char *buf) 4955 { 4956 ext_read_input(buf); 4957 if ((strlen(buf) != 2) || (ext_invalid_option(buf[0]))) { 4958 printf("\nUnknown Command\n"); 4959 return (-1); 4960 } 4961 return (0); 4962 } 4963 4964 /* 4965 * Procedure to print the list of known partition types and their IDs 4966 */ 4967 static void 4968 ext_print_part_types() 4969 { 4970 int i, rowmax, rowcount = 1; 4971 struct winsize ws; 4972 char buf[80]; 4973 4974 /* Get the current window dimensions */ 4975 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) { 4976 perror("ioctl"); 4977 rowmax = 20; 4978 } else { 4979 /* 4980 * Accommodate the initial headings by reducing the number of 4981 * partition IDs being printed. 4982 */ 4983 rowmax = ws.ws_row - 5; 4984 } 4985 4986 if (rowmax < 3) { 4987 fprintf(stderr, "Window size too small." 4988 " Try resizing the window\n"); 4989 return; 4990 } 4991 4992 printf("List of known partition types : \n"); 4993 printf("PartID Partition Type\n"); 4994 printf("====== ==============\n"); 4995 for (i = 0; i <= FDISK_MAX_VALID_PART_ID; i++) { 4996 printf("%-3d %s\n", i, fdisk_part_types[i]); 4997 rowcount++; 4998 if (rowcount == rowmax) { 4999 /* 5000 * After the initial screen, use all the rows for 5001 * printing the partition IDs, but one. 5002 */ 5003 rowmax = ws.ws_row - 1; 5004 fprintf(stderr, "\nPress enter to see next page or 'q'" 5005 " to quit : "); 5006 ext_read_input(buf); 5007 if ((strlen(buf) == 2) && (tolower(buf[0]) == 'q')) { 5008 return; 5009 } 5010 rowcount = 1; 5011 } 5012 } 5013 } 5014 5015 static void 5016 ext_read_valid_part_num(int *pno) 5017 { 5018 char buf[80]; 5019 int len, i; 5020 5021 for (;;) { 5022 printf("Enter the partition number : "); 5023 ext_read_input(buf); 5024 5025 len = strlen(buf); 5026 5027 /* Check length of the input */ 5028 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_NUM_DIGITS+1))) { 5029 goto print_error_and_continue; 5030 } 5031 5032 /* Check if there is a non-digit in the input */ 5033 for (i = 0; i < len-1; i++) { 5034 if (!isdigit(buf[i])) { 5035 goto print_error_and_continue; 5036 } 5037 } 5038 5039 *pno = atoi(buf); 5040 5041 if ((*pno <= FD_NUMPART) || 5042 *pno > (fdisk_get_logical_drive_count(epp) + FD_NUMPART)) { 5043 goto print_error_and_continue; 5044 } 5045 5046 break; 5047 print_error_and_continue: 5048 printf("Invalid partition number\n"); 5049 continue; 5050 } 5051 } 5052 5053 static void 5054 ext_read_valid_part_id(uchar_t *partid) 5055 { 5056 char buf[80]; 5057 int len, i, id; 5058 5059 for (;;) { 5060 printf("Enter the ID ( Type I for list of partition IDs ) : "); 5061 ext_read_input(buf); 5062 len = strlen(buf); 5063 5064 if ((len < 2) || (len > (FDISK_MAX_VALID_PART_ID_DIGITS + 1))) { 5065 printf("Invalid partition ID\n"); 5066 continue; 5067 } 5068 5069 if ((len == 2) && (toupper(buf[0]) == 'I')) { 5070 ext_print_part_types(); 5071 continue; 5072 } 5073 5074 /* Check if there is a non-digit in the input */ 5075 for (i = 0; i < len-1; i++) { 5076 if (!isdigit(buf[i])) { 5077 printf("Invalid partition ID\n"); 5078 break; 5079 } 5080 } 5081 5082 if (i < len - 1) { 5083 continue; 5084 } 5085 5086 /* Check if the (now) valid number is greater than the limit */ 5087 if ((id = atoi(buf)) > FDISK_MAX_VALID_PART_ID) { 5088 printf("Invalid partition ID\n"); 5089 continue; 5090 } 5091 5092 *partid = (uchar_t)id; 5093 5094 /* Disallow multiple extended partitions */ 5095 if (fdisk_is_dos_extended(*partid)) { 5096 printf("Multiple extended partitions not allowed\n"); 5097 continue; 5098 } 5099 5100 /* Disallow EFI partitions within extended partition */ 5101 if (*partid == EFI_PMBR) { 5102 printf("EFI partitions within an extended partition" 5103 " is not allowed\n"); 5104 continue; 5105 } 5106 5107 return; /* Valid partition ID is in partid */ 5108 } 5109 } 5110 5111 static void 5112 delete_logical_drive() 5113 { 5114 int pno; 5115 5116 if (!fdisk_get_logical_drive_count(epp)) { 5117 printf("\nNo logical drives defined.\n"); 5118 return; 5119 } 5120 5121 printf("\n"); 5122 ext_read_valid_part_num(&pno); 5123 fdisk_delete_logical_drive(epp, pno); 5124 printf("Partition %d deleted\n", pno); 5125 } 5126 5127 static int 5128 ext_read_valid_partition_start(uint32_t *begsec) 5129 { 5130 char buf[80]; 5131 int ret, len, i; 5132 uint32_t begcyl; 5133 uint32_t first_free_cyl; 5134 uint32_t first_free_sec; 5135 5136 ret = fdisk_ext_find_first_free_sec(epp, &first_free_sec); 5137 if (ret != FDISK_SUCCESS) { 5138 return (ret); 5139 } 5140 5141 first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec); 5142 for (;;) { 5143 printf("Enter the beginning cylinder (Default - %d) : ", 5144 first_free_cyl); 5145 ext_read_input(buf); 5146 len = strlen(buf); 5147 if (len == 1) { /* User accepted the default value */ 5148 *begsec = first_free_sec; 5149 return (FDISK_SUCCESS); 5150 } 5151 5152 if (len > (FDISK_MAX_VALID_CYL_NUM_DIGITS + 1)) { 5153 printf("Input too long\n"); 5154 printf("Invalid beginning cylinder number\n"); 5155 continue; 5156 } 5157 /* Check if there is a non-digit in the input */ 5158 for (i = 0; i < len - 1; i++) { 5159 if (!isdigit(buf[i])) { 5160 printf("Invalid beginning cylinder number\n"); 5161 break; 5162 } 5163 } 5164 if (i < len - 1) { 5165 continue; 5166 } 5167 5168 begcyl = atoi(buf); 5169 ret = fdisk_ext_validate_part_start(epp, begcyl, begsec); 5170 switch (ret) { 5171 case FDISK_SUCCESS: 5172 /* 5173 * Success. 5174 * Valid beginning sector is in begsec 5175 */ 5176 break; 5177 5178 case FDISK_EOVERLAP: 5179 printf("Partition boundary overlaps with "); 5180 printf("existing partitions\n"); 5181 printf("Invalid beginning cylinder number\n"); 5182 continue; 5183 5184 case FDISK_EOOBOUND: 5185 printf("Cylinder boundary beyond the limits\n"); 5186 printf("Invalid beginning cylinder number\n"); 5187 continue; 5188 } 5189 return (FDISK_SUCCESS); 5190 } 5191 } 5192 5193 /* 5194 * Algorithm : 5195 * 1. Check if the first character is a + 5196 * a) If yes, check if the last character is 'k', 'm' or 'g' 5197 * 2. If not, check if there are any non-digits 5198 * 3. Check for the length of the numeral string 5199 * 4. atoi the numeral string 5200 * 5. In case of data entered in KB, MB or GB, convert it to number of cylinders 5201 * a) Adjust size to be cylinder boundary aligned 5202 * 6. If size specifies is zero, flag error 5203 * 7. Check if the size is less than 1 cylinder 5204 * a) If yes, default the size FDISK_MIN_PART_SIZE 5205 * b) If no, Check if the size is within endcyl - begcyl 5206 */ 5207 static void 5208 ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec) 5209 { 5210 char buf[80]; 5211 uint32_t tempcyl; 5212 uint32_t last_free_sec; 5213 uint32_t last_free_cyl; 5214 int i, len, ch, mbgb = 0, scale = FDISK_SECTS_PER_CYL(epp); 5215 uint64_t size = 0; 5216 int copy_len; 5217 char numbuf[FDISK_MAX_VALID_CYL_NUM_DIGITS + 1]; 5218 int sectsize = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE); 5219 uint32_t remdr, spc, poss_end; 5220 5221 if (sectsize == EINVAL) { 5222 fprintf(stderr, "Unsupported geometry statistics.\n"); 5223 exit(1); 5224 } 5225 5226 last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec); 5227 last_free_cyl = FDISK_SECT_TO_CYL(epp, last_free_sec); 5228 5229 for (;;) { 5230 printf("Enter the size in cylinders (Default End Cylinder -"); 5231 printf(" %u)\n", last_free_cyl); 5232 printf("Type +<size>K, +<size>M or +<size>G to enter size in"); 5233 printf("KB, MB or GB : "); 5234 ext_read_input(buf); 5235 len = strlen(buf); 5236 mbgb = 0; 5237 scale = FDISK_SECTS_PER_CYL(epp); 5238 5239 if (len == 1) { /* User accepted the default value */ 5240 *endsec = last_free_sec; 5241 return; 5242 } 5243 5244 copy_len = len - 1; 5245 5246 if ((buf[0] == '+') && (isdigit(buf[1]))) { 5247 copy_len--; 5248 if ((ch = toupper(buf[len - 2])) == 'B') { 5249 ch = toupper(buf[len - 3]); 5250 copy_len--; 5251 } 5252 5253 if (!((ch == 'K') || (ch == 'M') || (ch == 'G'))) { 5254 printf("Invalid partition size\n"); 5255 continue; 5256 } 5257 5258 copy_len--; 5259 mbgb = 1; 5260 scale = ((ch == 'K') ? FDISK_KB : 5261 ((ch == 'M') ? FDISK_MB : FDISK_GB)); 5262 } 5263 5264 if (copy_len > FDISK_MAX_VALID_CYL_NUM_DIGITS) { 5265 printf("Input too long\n"); 5266 printf("Invalid partition size\n"); 5267 continue; 5268 } 5269 5270 strncpy(numbuf, &buf[mbgb], copy_len); 5271 numbuf[copy_len] = '\0'; 5272 5273 for (i = mbgb; i < copy_len + mbgb; i++) { 5274 if (!isdigit(buf[i])) { 5275 break; 5276 } 5277 } 5278 5279 if (i < copy_len + mbgb) { 5280 printf("Invalid partition size\n"); 5281 continue; 5282 } 5283 5284 size = (atoll(numbuf) * (scale)); 5285 5286 if (size == 0) { 5287 printf("Zero size is invalid\n"); 5288 printf("Invalid partition size\n"); 5289 continue; 5290 } 5291 5292 if (mbgb) { 5293 size /= sectsize; 5294 } 5295 5296 if (size > (last_free_sec - begsec + 1)) { 5297 printf("Cylinder boundary beyond the limits"); 5298 printf(" or overlaps with existing"); 5299 printf(" partitions\n"); 5300 printf("Invalid partition size\n"); 5301 continue; 5302 } 5303 5304 /* 5305 * Adjust the ending sector such that there are no partial 5306 * cylinders allocated. But at the same time, make sure it 5307 * doesn't over shoot boundaries. 5308 */ 5309 spc = FDISK_SECTS_PER_CYL(epp); 5310 poss_end = begsec + size - 1; 5311 if (remdr = (poss_end % spc)) { 5312 poss_end += spc - remdr - 1; 5313 } 5314 *endsec = (poss_end > last_free_sec) ? last_free_sec : 5315 poss_end; 5316 5317 return; 5318 } 5319 } 5320 5321 /* 5322 * ALGORITHM: 5323 * 1. Get the starting and ending sectors/cylinder of the extended partition. 5324 * 2. Keep track of the first free sector/cylinder 5325 * 3. Allow the user to specify the beginning cylinder of the new partition 5326 * 4. Check for the validity of the entered data 5327 * a) If it is non-numeric 5328 * b) If it is beyond the extended partition limits 5329 * c) If it overlaps with the current logical drives 5330 * 5. Allow the user to specify the size in cylinders/ human readable form 5331 * 6. Check for the validity of the entered data 5332 * a) If it is non-numeric 5333 * b) If it is beyond the extended partition limits 5334 * c) If it overlaps with the current logical drives 5335 * d) If it is a number lesser than the starting cylinder 5336 * 7. Request partition ID for the new partition. 5337 * 8. Update the first free cylinder available 5338 * 9. Display Success message 5339 */ 5340 5341 static void 5342 add_logical_drive() 5343 { 5344 uint32_t begsec, endsec; 5345 uchar_t partid; 5346 char buf[80]; 5347 int rval; 5348 5349 if (fdisk_get_logical_drive_count(epp) >= MAX_EXT_PARTS) { 5350 printf("\nNumber of logical drives exceeds limit of %d.\n", 5351 MAX_EXT_PARTS); 5352 printf("Command did not succeed. Press enter to continue\n"); 5353 ext_read_input(buf); 5354 return; 5355 } 5356 5357 printf("\n"); 5358 rval = ext_read_valid_partition_start(&begsec); 5359 switch (rval) { 5360 case FDISK_SUCCESS: 5361 break; 5362 5363 case FDISK_EOOBOUND: 5364 printf("\nNo space left in the extended partition\n"); 5365 printf("Press enter to continue\n"); 5366 ext_read_input(buf); 5367 return; 5368 } 5369 5370 ext_read_valid_partition_size(begsec, &endsec); 5371 ext_read_valid_part_id(&partid); 5372 fdisk_add_logical_drive(epp, begsec, endsec, partid); 5373 5374 printf("New partition with ID %d added\n", partid); 5375 } 5376 5377 static void 5378 ext_change_logical_drive_id() 5379 { 5380 int pno; 5381 uchar_t partid; 5382 5383 if (!fdisk_get_logical_drive_count(epp)) { 5384 printf("\nNo logical drives defined.\n"); 5385 return; 5386 } 5387 5388 printf("\n"); 5389 ext_read_valid_part_num(&pno); 5390 ext_read_valid_part_id(&partid); 5391 fdisk_change_logical_drive_id(epp, pno, partid); 5392 5393 printf("Partition ID of partition %d changed to %d\n", pno, partid); 5394 } 5395 5396 #ifdef DEBUG 5397 static void 5398 ext_print_logdrive_layout_debug() 5399 { 5400 int pno; 5401 char namebuff[255]; 5402 logical_drive_t *head = fdisk_get_ld_head(epp); 5403 logical_drive_t *temp; 5404 5405 if (!fdisk_get_logical_drive_count(epp)) { 5406 printf("\nNo logical drives defined.\n"); 5407 return; 5408 } 5409 5410 printf("\n\n"); 5411 puts("# start block end block abs start abs end OSType"); 5412 for (temp = head, pno = 5; temp != NULL; temp = temp->next, pno++) { 5413 /* Print the logical drive details */ 5414 id_to_name(temp->parts[0].systid, namebuff); 5415 printf("%d: %.10u %.10u %.10u %.10u", 5416 pno, 5417 LE_32(temp->parts[0].relsect), 5418 LE_32(temp->parts[0].numsect), 5419 temp->abs_secnum, 5420 temp->abs_secnum + temp->numsect - 1 + 5421 MAX_LOGDRIVE_OFFSET); 5422 printf(" %s\n", namebuff); 5423 /* 5424 * Print the second entry in the EBR which is information 5425 * about the location and the size of the next extended 5426 * partition. 5427 */ 5428 id_to_name(temp->parts[1].systid, namebuff); 5429 printf("%d: %.10u %.10u %.10s %.10s", 5430 pno, 5431 LE_32(temp->parts[1].relsect), 5432 LE_32(temp->parts[1].numsect), 5433 " ", " "); 5434 printf(" %s\n", namebuff); 5435 } 5436 } 5437 #endif 5438 5439 static void 5440 ext_print_logical_drive_layout() 5441 { 5442 int sysid; 5443 unsigned int startcyl, endcyl, length, percent, remainder; 5444 logical_drive_t *temp; 5445 uint32_t part_start; 5446 struct ipart *fpart; 5447 char namebuff[255]; 5448 int numcyl = fdisk_get_disk_geom(epp, PHYSGEOM, NCYL); 5449 int pno; 5450 5451 if (numcyl == EINVAL) { 5452 fprintf(stderr, "Unsupported geometry statistics.\n"); 5453 exit(1); 5454 } 5455 5456 if (!fdisk_get_logical_drive_count(epp)) { 5457 printf("\nNo logical drives defined.\n"); 5458 return; 5459 } 5460 5461 printf("\n"); 5462 printf("Number of cylinders in disk : %u\n", numcyl); 5463 printf("Beginning cylinder of extended partition : %u\n", 5464 fdisk_get_ext_beg_cyl(epp)); 5465 printf("Ending cylinder of extended partition : %u\n", 5466 fdisk_get_ext_end_cyl(epp)); 5467 printf("\n"); 5468 printf("Part# StartCyl EndCyl Length %% " 5469 "Part ID (Type)\n"); 5470 printf("===== ======== ======== ======= ===" 5471 " ==============\n"); 5472 for (temp = fdisk_get_ld_head(epp), pno = 5; temp != NULL; 5473 temp = temp->next, pno++) { 5474 /* Print the logical drive details */ 5475 fpart = &temp->parts[0]; 5476 sysid = fpart->systid; 5477 /* 5478 * Check if partition id 0x82 is Solaris 5479 * or a Linux swap. Print the string 5480 * accordingly. 5481 */ 5482 if (sysid == SUNIXOS) { 5483 part_start = temp->abs_secnum + 5484 temp->logdrive_offset; 5485 if (fdisk_is_linux_swap(epp, part_start, 5486 NULL) == 0) 5487 strcpy(namebuff, LINSWAPstr); 5488 else 5489 strcpy(namebuff, SUstr); 5490 } else { 5491 id_to_name(sysid, namebuff); 5492 } 5493 startcyl = temp->begcyl; 5494 endcyl = temp->endcyl; 5495 if (startcyl == endcyl) { 5496 length = 1; 5497 } else { 5498 length = endcyl - startcyl + 1; 5499 } 5500 percent = length * 100 / numcyl; 5501 if ((remainder = (length * 100 % numcyl)) != 0) { 5502 if ((remainder * 100 / numcyl) > 50) { 5503 /* round up */ 5504 percent++; 5505 } 5506 /* Else leave the percent as is since it's already */ 5507 /* rounded down */ 5508 } 5509 if (percent > 100) { 5510 percent = 100; 5511 } 5512 printf("%-5d %-8u %-8u %-7u %-3d %-3d (%-.28s)\n", 5513 pno, startcyl, endcyl, length, percent, sysid, namebuff); 5514 } 5515 #ifdef DEBUG 5516 ext_print_logdrive_layout_debug(); 5517 #endif 5518 printf("\n"); 5519 } 5520 5521 static void 5522 ext_print_help_menu() 5523 { 5524 printf("\n"); 5525 printf("a Add a logical drive\n"); 5526 printf("d Delete a logical drive\n"); 5527 printf("h Print this help menu\n"); 5528 printf("i Change the id of the logical drive\n"); 5529 printf("p Print the logical drive layout\n"); 5530 printf("r Return to the main fdisk menu\n"); 5531 printf(" (To commit or cancel the changes)\n"); 5532 printf("\n"); 5533 } 5534 5535 static void 5536 ext_part_menu() 5537 { 5538 char buf[80]; 5539 uchar_t *bbsigp; 5540 static int bbsig_disp_flag = 1; 5541 5542 int i; 5543 5544 printf(CLR_SCR); 5545 5546 if (fdisk_corrupt_logical_drives(epp)) { 5547 printf("One or more logical drives seem to be corrupt.\n"); 5548 printf("Displaying only sane logical drives.\n"); 5549 } 5550 5551 if (bbsig_disp_flag && fdisk_invalid_bb_sig(epp, &bbsigp)) { 5552 printf("The following logical drives have a wrong boot block" 5553 " signature :\n\n"); 5554 for (i = 0; bbsigp[i]; i++) { 5555 printf("%d ", bbsigp[i]); 5556 } 5557 printf("\n\n"); 5558 printf("They will be corrected when you choose to commit\n"); 5559 bbsig_disp_flag = 0; 5560 } 5561 5562 printf("Extended partition menu\n"); 5563 5564 for (;;) { 5565 printf("\nEnter Command (Type h for help) : "); 5566 if ((ext_read_options(buf)) < 0) { 5567 printf("\nCommand Options : \n"); 5568 ext_print_help_menu(); 5569 continue; 5570 } 5571 switch (buf[0]) { 5572 case 'a': 5573 add_logical_drive(); 5574 break; 5575 case 'd': 5576 delete_logical_drive(); 5577 break; 5578 case 'h': 5579 ext_print_help_menu(); 5580 break; 5581 case 'i': 5582 ext_change_logical_drive_id(); 5583 break; 5584 case 'p': 5585 ext_print_logical_drive_layout(); 5586 break; 5587 case 'r': 5588 printf(CLR_SCR); 5589 return; 5590 default : /* NOTREACHED */ 5591 break; 5592 } 5593 } 5594 } 5595 #endif 5596 5597 static int 5598 nopartdefined() 5599 { 5600 int i; 5601 5602 for (i = 0; i < FD_NUMPART; i++) 5603 if (Table[i].systid != UNUSED) 5604 return (0); 5605 return (1); 5606 } 5607