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