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