blob: 466a608bc2d80065762cf8d2e87ee6e94759bc6e [file] [log] [blame]
<
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* or http://www.opensolaris.org/os/licensing.
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved.
* Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
*/
/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
/* All Rights Reserved */
/* Copyright (c) 1987, 1988 Microsoft Corporation */
/* All Rights Reserved */
/*
* PROGRAM: fdisk(1M)
* This program reads the partition table on the specified device and
* also reads the drive parameters. The user can perform various
* operations from a supplied menu or from the command line. Diagnostic
* options are also available.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <ctype.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <limits.h>
#include <sys/param.h>
#include <sys/systeminfo.h>
#include <sys/efi_partition.h>
#include <sys/byteorder.h>
#include <sys/systeminfo.h>
#include <sys/dktp/fdisk.h>
#include <sys/dkio.h>
#include <sys/vtoc.h>
#ifdef i386
#include <sys/tty.h>
#include <libfdisk.h>
#endif
#define CLR_SCR ""
#define CLR_LIN ""
#define HOME "" \
""
#define Q_LINE ""
#ifdef i386
#define W_LINE ""
#else
#define W_LINE ""
#endif
#define E_LINE ""
#ifdef i386
#define M_LINE "" \
""
#else
#define M_LINE "" \
""
#endif
#define T_LINE ""
#define DEFAULT_PATH "/dev/rdsk/"
#define DK_MAX_2TB UINT32_MAX /* Max # of sectors in 2TB */
/* for clear_vtoc() */
#define OLD 0
#define NEW 1
/* readvtoc/writevtoc return codes */
#define VTOC_OK 0 /* Good VTOC */
#define VTOC_INVAL 1 /* invalid VTOC */
#define VTOC_NOTSUP 2 /* operation not supported - EFI label */
#define VTOC_RWERR 3 /* couldn't read or write VTOC */
/*
* Support for fdisk(1M) on the SPARC platform
* In order to convert little endian values to big endian for SPARC,
* byte/short and long values must be swapped.
* These swapping macros will be used to access information in the
* mboot and ipart structures.
*/
#ifdef sparc
#define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
#define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \
(les((unsigned)((val)&0xffff0000)>>16)))
#else
#define les(val) (val)
#define lel(val) (val)
#endif
#if defined(_SUNOS_VTOC_16)
#define VTOC_OFFSET 1
#elif defined(_SUNOS_VTOC_8)
#define VTOC_OFFSET 0
#else
#error No VTOC format defined.
#endif
#ifdef i386
#define FDISK_KB (1024)
#define FDISK_MB (FDISK_KB * 1024)
#define FDISK_GB (FDISK_MB * 1024)
#define TRUE 1
#define FDISK_MAX_VALID_PART_ID 255
#define FDISK_MAX_VALID_PART_NUM_DIGITS 2
#define FDISK_MAX_VALID_PART_ID_DIGITS 3
/* Maximum number of digits for a valid partition size */
#define FDISK_MAX_VALID_CYL_NUM_DIGITS 10
/* Minimum partition size in cylinders */
#define FDISK_MIN_PART_SIZE 1
#endif
static char Usage[] = "Usage: fdisk\n"
"[ -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
"[ -b masterboot ]\n"
"[ -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
"[ -E [slot:active] ]\n"
"[ -F fdisk_file ] [ -h ] [ -o offset ] [ -P fill_patt ] [ -s size ]\n"
"[ -S geom_file ] [ [ -v ] -W { creat_fdisk_file | - } ]\n"
"[ -w | r | d | n | I | B | g | G | R | t | T ] rdevice";
static char Usage1[] = " Partition options:\n"
" -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
" Create a partition with specific attributes:\n"
" id = system id number (fdisk.h) for the partition type\n"
" act = active partition flag (0 is off and 128 is on)\n"
" bhead = beginning head for start of partition\n"
" bsect = beginning sector for start of partition\n"
" bcyl = beginning cylinder for start of partition\n"
" ehead = ending head for end of partition\n"
" esect = ending sector for end of partition\n"
" ecyl = ending cylinder for end of partition\n"
" rsect = sector number from start of disk for\n"
" start of partition\n"
" numsect = partition size in sectors\n"
" -b master_boot\n"
" Use master_boot as the master boot file.\n"
" -B Create one Solaris partition that uses the entire disk.\n"
" -D id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect\n"
" Delete a partition. See attribute definitions for -A.\n"
" -E [slot:active]\n"
" Create an EFI partition that uses the entire disk.\n"
" -F fdisk_file\n"
" Use fdisk_file to initialize on-line fdisk table.\n"
" -I Forego device checks. Generate a file image of what would go\n"
" on a disk using the geometry specified with the -S option.\n"
" -n Do not run in interactive mode.\n"
" -R Open the disk device as read-only.\n"
" -t Check and adjust VTOC to be consistent with fdisk table.\n"
" VTOC slices exceeding the partition size will be truncated.\n"
" -T Check and adjust VTOC to be consistent with fdisk table.\n"
" VTOC slices exceeding the partition size will be removed.\n"
" -W fdisk_file\n"
" Write on-disk table to fdisk_file.\n"
" -W - Write on-disk table to standard output.\n"
" -v Display virtual geometry. Must be used with the -W option.\n"
" Diagnostic options:\n"
" -d Activate debug information about progress.\n"
" -g Write label geometry to standard output:\n"
" PCYL number of physical cylinders\n"
" NCYL number of usable cylinders\n"
" ACYL number of alternate cylinders\n"
" BCYL cylinder offset\n"
" NHEADS number of heads\n"
" NSECTORS number of sectors per track\n"
" SECTSIZ size of a sector in bytes\n"
" -G Write physical geometry to standard output (see -g).\n"
" -h Issue this verbose help message.\n"
" -o offset\n"
" Block offset from start of disk (default 0). Ignored if\n"
" -P # specified.\n"
" -P fill_patt\n"
" Fill disk with pattern fill_patt. fill_patt can be decimal or\n"
" hexadecimal and is used as number for constant long word\n"
" pattern. If fill_patt is \"#\" then pattern of block #\n"
" for each block. Pattern is put in each block as long words\n"
" and fills each block (see -o and -s).\n"
" -r Read from a disk to stdout (see -o and -s).\n"
" -s size Number of blocks on which to perform operation (see -o).\n"
" -S geom_file\n"
" Use geom_file to set the label geometry (see -g).\n"
" -w Write to a disk from stdin (see -o and -s).";
static char Ostr[] = "Other OS";
static char Dstr[] = "DOS12";
static char D16str[] = "DOS16";
static char DDstr[] = "DOS-DATA";
static char EDstr[] = "EXT-DOS";
static char DBstr[] = "DOS-BIG";
static char PCstr[] = "PCIX";
static char Ustr[] = "UNIX System";
static char SUstr[] = "Solaris";
static char SU2str[] = "Solaris2";
static char X86str[] = "x86 Boot";
static char DIAGstr[] = "Diagnostic";
static char IFSstr[] = "IFS: NTFS";
static char AIXstr[] = "AIX Boot";
static char AIXDstr[] = "AIX Data";
static char OS2str[] = "OS/2 Boot";
static char WINstr[] = "Win95 FAT32";
static char EWINstr[] = "Ext Win95";
static char FAT95str[] = "FAT16 LBA";
static char EXTLstr[] = "EXT LBA";
static char LINUXstr[] = "Linux";
static char CPMstr[] = "CP/M";
static char NOV2str[] = "Netware 286";
static char NOVstr[] = "Netware 3.x+";
static char QNXstr[] = "QNX 4.x";
static char QNX2str[] = "QNX part 2";
static char QNX3str[] = "QNX part 3";
static char LINNATstr[] = "Linux native";
#ifdef i386
static char LINSWAPstr[] = "Linux swap";
#endif
static char NTFSVOL1str[] = "NT volset 1";
static char NTFSVOL2str[] = "NT volset 2";
static char BSDstr[] = "BSD OS";
static char NEXTSTEPstr[] = "NeXTSTEP";
static char BSDIFSstr[] = "BSDI FS";
static char BSDISWAPstr[] = "BSDI swap";
static char Actvstr[] = "Active";
static char EFIstr[] = "EFI";
static char NAstr[] = " ";
/* All the user options and flags */
static char *Dfltdev; /* name of fixed disk drive */
/* Diagnostic options */
static int io_wrt = 0; /* write stdin to disk (-w) */
static int io_rd = 0; /* read disk and write stdout (-r) */
static char *io_fatt; /* user supplied pattern (-P pattern) */
static int io_patt = 0; /* write pattern to disk (-P pattern) */
static int io_lgeom = 0; /* get label geometry (-g) */
static int io_pgeom = 0; /* get drive physical geometry (-G) */
static char *io_sgeom = 0; /* set label geometry (-S geom_file) */
static int io_readonly = 0; /* do not write to disk (-R) */
/* The -o offset and -s size options specify the area of the disk on */
/* which to perform the particular operation; i.e., -P, -r, or -w. */
static off_t io_offset = 0; /* offset sector (-o offset) */
static off_t io_size = 0; /* size in sectors (-s size) */
/* Partition table flags */
static int v_flag = 0; /* virtual geometry-HBA flag (-v) */
static int stdo_flag = 0; /* stdout flag (-W -) */
static int io_fdisk = 0; /* do fdisk operation */
static int io_ifdisk = 0; /* interactive partition */
static int io_nifdisk = 0; /* non-interactive partition (-n) */
static int io_adjt = 0; /* check/adjust VTOC (truncate (-t)) */
static int io_ADJT = 0; /* check/adjust VTOC (delete (-T)) */
static char *io_ffdisk = 0; /* input fdisk file name (-F file) */
static char *io_Wfdisk = 0; /* output fdisk file name (-W file) */
static char *io_Afdisk = 0; /* add entry to partition table (-A) */
static char *io_Dfdisk = 0; /* delete entry from part. table (-D) */
static char *io_mboot = 0; /* master boot record (-b boot_file) */
static struct mboot BootCod; /* buffer for master boot record */
static int io_wholedisk = 0; /* use whole disk for Solaris (-B) */
static int io_EFIdisk = 0; /* use whole disk for EFI (-E) */
static int io_EFIslot = 0; /* slot in which to place EFI entry */
static int io_EFIactive = 0; /* mark EFI entry as active */
static int io_debug = 0; /* activate verbose mode (-d) */
static int io_image = 0; /* create image using geometry (-I) */
static struct mboot *Bootblk; /* pointer to cut/paste sector zero */
static char *Bootsect; /* pointer to sector zero buffer */
static char *Nullsect;
static struct extvtoc disk_vtoc; /* verify VTOC table */
static int vt_inval = 0;
static int no_virtgeom_ioctl = 0; /* ioctl for virtual geometry failed */
static int no_physgeom_ioctl = 0; /* ioctl for physical geometry failed */
static struct ipart Table[FD_NUMPART];
static struct ipart Old_Table[FD_NUMPART];
static int skip_verify[FD_NUMPART]; /* special case skip sz chk */
/* Disk geometry information */
static struct dk_minfo minfo;
static struct dk_geom disk_geom;
static int Dev; /* fd for open device */
static diskaddr_t dev_capacity; /* number of blocks on device */
static diskaddr_t chs_capacity; /* Numcyl_usable * heads * sectors */
static int Numcyl_usable; /* Number of usable cylinders */
/* used to limit fdisk to 2TB */
/* Physical geometry for the drive */
static int Numcyl; /* number of cylinders */
static int heads; /* number of heads */
static int sectors; /* number of sectors per track */
static int acyl; /* number of alternate sectors */
/* HBA (virtual) geometry for the drive */
static int hba_Numcyl; /* number of cylinders */
static int hba_heads; /* number of heads */
static int hba_sectors; /* number of sectors per track */
static int sectsiz; /* sector size */
/* Load functions for fdisk table modification */
#define LOADFILE 0 /* load fdisk from file */
#define LOADDEL 1 /* delete an fdisk entry */
#define LOADADD 2 /* add an fdisk entry */
#define CBUFLEN 80
static char s[CBUFLEN];
#ifdef i386
/*
* Complete list of all the 255 partition types. Some are unknown types
* and some entries are known to be unused.
*
* Courtesy of http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
*/
char *fdisk_part_types[] = {
"Empty", /* 0 */
"FAT12", /* 1 */
"XENIX /", /* 2 */
"XENIX /usr", /* 3 */
"FAT16 (Upto 32M)", /* 4 */
"DOS Extended", /* 5 */
"FAT16 (>32M, HUGEDOS)", /* 6 */
"IFS: NTFS", /* 7 */
"AIX Boot/QNX(qny)", /* 8 */
"AIX Data/QNX(qnz)", /* 9 */
"OS/2 Boot/Coherent swap", /* 10 */
"WIN95 FAT32(Upto 2047GB)", /* 11 */
"WIN95 FAT32(LBA)", /* 12 */
"Unused", /* 13 */
"WIN95 FAT16(LBA)", /* 14 */
"WIN95 Extended(LBA)", /* 15 */
"OPUS", /* 16 */
"Hidden FAT12", /* 17 */
"Diagnostic", /* 18 */
"Unknown", /* 19 */
"Hidden FAT16(Upto 32M)", /* 20 */
"Unknown", /* 21 */
"Hidden FAT16(>=32M)", /* 22 */
"Hidden IFS: HPFS", /* 23 */
"AST SmartSleep Partition", /* 24 */
"Unused/Willowtech Photon", /* 25 */
"Unknown", /* 26 */
"Hidden FAT32", /* 27 */
"Hidden FAT32(LBA)", /* 28 */
"Unused", /* 29 */
"Hidden FAT16(LBA)", /* 30 */
"Unknown", /* 31 */
"Unused/OSF1", /* 32 */
"Reserved/FSo2(Oxygen FS)", /* 33 */
"Unused/(Oxygen EXT)", /* 34 */
"Reserved", /* 35 */
"NEC DOS 3.x", /* 36 */
"Unknown", /* 37 */
"Reserved", /* 38 */
"Unknown", /* 39 */
"Unknown", /* 40 */
"Unknown", /* 41 */
"AtheOS File System", /* 42 */
"SyllableSecure", /* 43 */
"Unknown", /* 44 */
"Unknown", /* 45 */
"Unknown", /* 46 */
"Unknown", /* 47 */
"Unknown", /* 48 */
"Reserved", /* 49 */
"NOS", /* 50 */
"Reserved", /* 51 */
"Reserved", /* 52 */
"JFS on OS/2", /* 53 */
"Reserved", /* 54 */
"Unknown", /* 55 */
"THEOS 3.2 2GB", /* 56 */
"Plan9/THEOS 4", /* 57 */
"THEOS 4 4GB", /* 58 */
"THEOS 4 Extended", /* 59 */
"PartitionMagic Recovery", /* 60 */
"Hidden NetWare", /* 61 */
"Unknown", /* 62 */
"Unknown", /* 63 */
"Venix 80286", /* 64 */
"MINIX/PPC PReP Boot", /* 65 */
"Win2K Dynamic Disk/SFS(DOS)", /* 66 */
"Linux+DRDOS shared", /* 67 */
"GoBack partition", /* 68 */
"Boot-US boot manager", /* 69 */
"EUMEL/Elan", /* 70 */
"EUMEL/Elan", /* 71 */
"EUMEL/Elan", /* 72 */
"Unknown", /* 73 */
"ALFS/THIN FS for DOS", /* 74 */
"Unknown", /* 75 */
"Oberon partition", /* 76 */
"QNX 4,x", /* 77 */
"QNX 4,x 2nd Part", /* 78 */
"QNX 4,x 3rd Part", /* 79 */
"OnTrack DM R/O, Lynx RTOS", /* 80 */
"OnTrack DM R/W, Novell", /* 81 */
"CP/M", /* 82 */
"Disk Manager 6.0 Aux3", /* 83 */
"Disk Manager 6.0 DDO", /* 84 */
"EZ-Drive", /* 85 */
"Golden Bow VFeature/AT&T MS-DOS", /* 86 */
"DrivePro", /* 87 */
"Unknown", /* 88 */
"Unknown", /* 89 */
"Unknown", /* 90 */
"Unknown", /* 91 */
"Priam EDisk", /* 92 */
"Unknown", /* 93 */
"Unknown", /* 94 */
"Unknown", /* 95 */
"Unknown", /* 96 */
"SpeedStor", /* 97 */
"Unknown", /* 98 */
"Unix SysV, Mach, GNU Hurd", /* 99 */
"PC-ARMOUR, Netware 286", /* 100 */
"Netware 386", /* 101 */
"Netware SMS", /* 102 */
"Novell", /* 103 */
"Novell", /* 104 */
"Netware NSS", /* 105 */
"Unknown", /* 106 */
"Unknown", /* 107 */
"Unknown", /* 108 */
"Unknown", /* 109 */
"Unknown", /* 110 */
"Unknown", /* 111 */
"DiskSecure Multi-Boot", /* 112 */
"Reserved", /* 113 */
"Unknown", /* 114 */
"Reserved", /* 115 */
"Scramdisk partition", /* 116 */
"IBM PC/IX", /* 117 */
"Reserved", /* 118 */
"M2FS/M2CS,Netware VNDI", /* 119 */
"XOSL FS", /* 120 */
"Unknown", /* 121 */
"Unknown", /* 122 */
"Unknown", /* 123 */
"Unknown", /* 124 */
"Unknown", /* 125 */
"Unused", /* 126 */
"Unused", /* 127 */
"MINIX until 1.4a", /* 128 */
"MINIX since 1.4b, early Linux", /* 129 */
"Solaris/Linux swap", /* 130 */
"Linux native", /* 131 */
"OS/2 hidden,Win Hibernation", /* 132 */
"Linux extended", /* 133 */
"Old Linux RAID,NT FAT16 RAID", /* 134 */
"NTFS volume set", /* 135 */
"Linux plaintext part table", /* 136 */
"Unknown", /* 137 */
"Linux Kernel Partition", /* 138 */
"Fault Tolerant FAT32 volume", /* 139 */
"Fault Tolerant FAT32 volume", /* 140 */
"Free FDISK hidden PDOS FAT12", /* 141 */
"Linux LVM partition", /* 142 */
"Unknown", /* 143 */
"Free FDISK hidden PDOS FAT16", /* 144 */
"Free FDISK hidden DOS EXT", /* 145 */
"Free FDISK hidden FAT16 Large", /* 146 */
"Hidden Linux native, Amoeba", /* 147 */
"Amoeba Bad Block Table", /* 148 */
"MIT EXOPC Native", /* 149 */
"Unknown", /* 150 */
"Free FDISK hidden PDOS FAT32", /* 151 */
"Free FDISK hidden FAT32 LBA", /* 152 */
"DCE376 logical drive", /* 153 */
"Free FDISK hidden FAT16 LBA", /* 154 */
"Free FDISK hidden DOS EXT", /* 155 */
"Unknown", /* 156 */
"Unknown", /* 157 */
"Unknown", /* 158 */
"BSD/OS", /* 159 */
"Laptop hibernation", /* 160 */
"Laptop hibernate,HP SpeedStor", /* 161 */
"Unknown", /* 162 */
"HP SpeedStor", /* 163 */
"HP SpeedStor", /* 164 */
"BSD/386,386BSD,NetBSD,FreeBSD", /* 165 */
"OpenBSD,HP SpeedStor", /* 166 */
"NeXTStep", /* 167 */
"Mac OS-X", /* 168 */
"NetBSD", /* 169 */
"Olivetti FAT12 1.44MB Service", /* 170 */
"Mac OS-X Boot", /* 171 */
"Unknown", /* 172 */
"Unknown", /* 173 */
"ShagOS filesystem", /* 174 */
"ShagOS swap", /* 175 */
"BootStar Dummy", /* 176 */
"HP SpeedStor", /* 177 */
"Unknown", /* 178 */
"HP SpeedStor", /* 179 */
"HP SpeedStor", /* 180 */
"Unknown", /* 181 */
"Corrupted FAT16 NT Mirror Set", /* 182 */
"Corrupted NTFS NT Mirror Set", /* 183 */
"Old BSDI BSD/386 swap", /* 184 */
"Unknown", /* 185 */
"Unknown", /* 186 */
"Boot Wizard hidden", /* 187 */
"Unknown", /* 188 */
"Unknown", /* 189 */
"Solaris x86 boot", /* 190 */
"Solaris2", /* 191 */
"REAL/32 or Novell DOS secured", /* 192 */
"DRDOS/secured(FAT12)", /* 193 */
"Hidden Linux", /* 194 */
"Hidden Linux swap", /* 195 */
"DRDOS/secured(FAT16,< 32M)", /* 196 */
"DRDOS/secured(Extended)", /* 197 */
"NT corrupted FAT16 volume", /* 198 */
"NT corrupted NTFS volume", /* 199 */
"DRDOS8.0+", /* 200 */
"DRDOS8.0+", /* 201 */
"DRDOS8.0+", /* 202 */
"DRDOS7.04+ secured FAT32(CHS)", /* 203 */
"DRDOS7.04+ secured FAT32(LBA)", /* 204 */
"CTOS Memdump", /* 205 */
"DRDOS7.04+ FAT16X(LBA)", /* 206 */
"DRDOS7.04+ secure EXT DOS(LBA)", /* 207 */
"REAL/32 secure big, MDOS", /* 208 */
"Old MDOS secure FAT12", /* 209 */
"Unknown", /* 210 */
"Unknown", /* 211 */
"Old MDOS secure FAT16 <32M", /* 212 */
"Old MDOS secure EXT", /* 213 */
"Old MDOS secure FAT16 >=32M", /* 214 */
"Unknown", /* 215 */
"CP/M-86", /* 216 */
"Unknown", /* 217 */
"Non-FS Data", /* 218 */
"CP/M,Concurrent DOS,CTOS", /* 219 */
"Unknown", /* 220 */
"Hidden CTOS memdump", /* 221 */
"Dell PowerEdge utilities(FAT)", /* 222 */
"DG/UX virtual disk manager", /* 223 */
"ST AVFS(STMicroelectronics)", /* 224 */
"SpeedStor 12-bit FAT EXT", /* 225 */
"Unknown", /* 226 */
"SpeedStor", /* 227 */
"SpeedStor 16-bit FAT EXT", /* 228 */
"Tandy MSDOS", /* 229 */
"Storage Dimensions SpeedStor", /* 230 */
"Unknown", /* 231 */
"Unknown", /* 232 */
"Unknown", /* 233 */
"Unknown", /* 234 */
"BeOS BFS", /* 235 */
"SkyOS SkyFS", /* 236 */
"Unused", /* 237 */
"EFI Header Indicator", /* 238 */
"EFI Filesystem", /* 239 */
"Linux/PA-RISC boot loader", /* 240 */
"SpeedStor", /* 241 */
"DOS 3.3+ secondary", /* 242 */
"SpeedStor Reserved", /* 243 */
"SpeedStor Large", /* 244 */
"Prologue multi-volume", /* 245 */
"SpeedStor", /* 246 */
"Unused", /* 247 */
"Unknown", /* 248 */
"pCache", /* 249 */
"Bochs", /* 250 */
"VMware File System", /* 251 */
"VMware swap", /* 252 */
"Linux raid autodetect", /* 253 */
"NT Disk Administrator hidden", /* 254 */
"Xenix Bad Block Table" /* 255 */
};
/* Allowed extended partition menu options */
static char ext_part_menu_opts[] = "adhipr";
/*
* Structure holding all information about the extended partition
* NOTE : As of now, there will be just one instance of ext_part_t, since most
* known systems allow only one extended dos partition per disk.
*/
static ext_part_t *epp;
#endif
static void update_disk_and_exit(boolean_t table_changed);
int main(int argc, char *argv[]);
static int read_geom(char *sgeom);
static void dev_mboot_read(void);
static void dev_mboot_write(off_t sect, char *buff, int bootsiz);
static void mboot_read(void);
static void fill_patt(void);
static void abs_read(void);
static void abs_write(void);
static void load(int funct, char *file);
static void Set_Table_CHS_Values(int ti);
static int nopartdefined();
static int insert_tbl(int id, int act,
int bhead, int bsect, int bcyl,
int ehead, int esect, int ecyl,
uint32_t rsect, uint32_t numsect, int startindex);
static int entry_from_old_table(int id, int act,
int bhead, int bsect, int bcyl,
int ehead, int esect, int ecyl,
uint32_t rsect, uint32_t numsect, int startindex);
static int verify_tbl(void);
static int pars_fdisk(char *line,
int *id, int *act,
int *bhead, int *bsect, int *bcyl,
int *ehead, int *esect, int *ecyl,
uint32_t *rsect, uint32_t *numsect);
static int validate_part(int id, uint32_t rsect, uint32_t numsect);
static void stage0(void);
static int pcreate(void);
static int specify(uchar_t tsystid);
static void dispmenu(void);
static int pchange(void);
static int ppartid(void);
static char pdelete(void);
static void rm_blanks(char *s);
static int getcyl(void);
static void disptbl(void);
static void print_Table(void);
static void copy_Table_to_Old_Table(void);
static void nulltbl(void);
static void copy_Bootblk_to_Table(void);
static void fill_ipart(char *bootptr, struct ipart *partp);
#ifdef sparc
uchar_t getbyte(char **bp);
uint32_t getlong(char **bp);
#endif
static void copy_Table_to_Bootblk(void);
static int TableChanged(void);
static void ffile_write(char *file);
static void fix_slice(void);
static int yesno(void);
static int readvtoc(void);
static int writevtoc(void);
static int efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc);
static int clear_efi(void);
static void clear_vtoc(int table, int part);
static int lecture_and_query(char *warning, char *devname);
static void sanity_check_provided_device(char *devname, int fd);
static char *get_node(char *devname);
static int efi_create(void);
#ifdef i386
static void id_to_name(uchar_t sysid, char *buffer);
static void ext_read_input(char *buf);
static int ext_read_options(char *buf);
static int ext_invalid_option(char ch);
static void ext_read_valid_part_num(int *pno);
static void ext_read_valid_part_id(uchar_t *partid);
static int ext_read_valid_partition_start(uint32_t *begsec);
static void ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec);
static void ext_part_menu();
static void add_logical_drive();
static void delete_logical_drive();
static void ext_print_help_menu();
static void ext_change_logical_drive_id();
static void ext_print_part_types();
static void ext_print_logical_drive_layout();
static void preach_and_continue();
#ifdef DEBUG
static void ext_print_logdrive_layout_debug();
#endif /* DEBUG */
#endif /* i386 */
/*
* This function is called only during the non-interactive mode.
* It is touchy and does not tolerate any errors. If there are
* mounted logical drives, changes to the partition table
* are disallowed.
*/
static void
update_disk_and_exit(boolean_t table_changed)
{
#ifdef i386
int rval;
#endif
if (table_changed) {
/*
* Copy the new table back to the sector buffer
* and write it to disk
*/
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
}
/* If the VTOC table is wrong fix it (truncation only) */
if (io_adjt)
fix_slice();
#ifdef i386
if (!io_readonly) {
rval = fdisk_commit_ext_part(epp);
switch (rval) {
case FDISK_SUCCESS:
/* Success */
break;
case FDISK_ENOEXTPART:
/* Nothing to do */
break;
default:
(void) fprintf(stderr, "Error in"
" fdisk_commit_ext_part\n");
exit(rval);
}
}
libfdisk_fini(&epp);
#endif
exit(0);
}
/*
* main
* Process command-line options.
*/
int
main(int argc, char *argv[])
{
int c, i;
extern int optind;
extern char *optarg;
int errflg = 0;
int diag_cnt = 0;
int openmode;
#ifdef i386
int rval;
int lf_op_flag = 0;
#endif
setbuf(stderr, 0); /* so all output gets out on exit */
setbuf(stdout, 0);
/* Process the options. */
while ((c = getopt(argc, argv, "o:s:P:F:b:A:D:W:S:tTIhwvrndgGRBE:"))
!= EOF) {
switch (c) {
case 'o':
io_offset = (off_t)strtoull(optarg, 0, 0);
continue;
case 's':
io_size = (off_t)strtoull(optarg, 0, 0);
continue;
case 'P':
diag_cnt++;
io_patt++;
io_fatt = optarg;
continue;
case 'w':
diag_cnt++;
io_wrt++;
continue;
case 'r':
diag_cnt++;
io_rd++;
continue;
case 'd':
io_debug++;
continue;
case 'I':
io_image++;
continue;
case 'R':
io_readonly++;
continue;
case 'S':
diag_cnt++;
io_sgeom = optarg;
continue;
case 'T':
io_ADJT++;
/* FALLTHROUGH */
case 't':
io_adjt++;
continue;
case 'B':
io_wholedisk++;
io_fdisk++;
continue;
case 'E':
if (sscanf(optarg, "%d:%d",
&io_EFIslot, &io_EFIactive) != 2) {
io_EFIslot = io_EFIactive = 0;
optind--;
}
io_EFIdisk++;
io_fdisk++;
continue;
case 'g':
diag_cnt++;
io_lgeom++;
continue;
case 'G':
diag_cnt++;
io_pgeom++;
continue;
case 'n':
io_nifdisk++;
io_fdisk++;
continue;
case 'F':
io_fdisk++;
io_ffdisk = optarg;
continue;
case 'b':
io_mboot = optarg;
continue;
case 'W':
/*
* If '-' is the -W argument, then write
* to standard output, otherwise write
* to the specified file.
*/
if (strncmp(optarg, "-", 1) == 0)
stdo_flag = 1;
else
io_Wfdisk = optarg;
io_fdisk++;
continue;
case 'A':
io_fdisk++;
io_Afdisk = optarg;
continue;
case 'D':
io_fdisk++;
io_Dfdisk = optarg;
continue;
case 'h':
(void) fprintf(stderr, "%s\n", Usage);
(void) fprintf(stderr, "%s\n", Usage1);
exit(0);
/* FALLTHROUGH */
case 'v':
v_flag = 1;
continue;
case '?':
errflg++;
break;
}
break;
}
if (io_image && io_sgeom && diag_cnt == 1) {
diag_cnt = 0;
}
/* User option checking */
/* By default, run in interactive mode */
if (!io_fdisk && !diag_cnt && !io_nifdisk) {
io_ifdisk++;
io_fdisk++;
}
if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
errflg++;
}
/* Was any error detected? */
if (errflg || argc == optind) {
(void) fprintf(stderr, "%s\n", Usage);
(void) fprintf(stderr,
"\nDetailed help is available with the -h option.\n");
exit(2);
}
/* Figure out the correct device node to open */
Dfltdev = get_node(argv[optind]);
if (io_readonly)
openmode = O_RDONLY;
else
openmode = O_RDWR|O_CREAT;
if ((Dev = open(Dfltdev, openmode, 0666)) == -1) {
(void) fprintf(stderr,
"fdisk: Cannot open device %s.\n",
Dfltdev);
exit(1);
}
/*
* not all disk (or disklike) drivers support DKIOCGMEDIAINFO
* in that case leave the minfo structure zeroed
*/
if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) {
(void) memset(&minfo, 0, sizeof (minfo));
}
/* Get the disk geometry */
if (!io_image) {
/* Get disk's HBA (virtual) geometry */
errno = 0;
if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) {
/*
* If ioctl isn't implemented on this platform, then
* turn off flag to print out virtual geometry (-v),
* otherwise use the virtual geometry.
*/
if (errno == ENOTTY) {
v_flag = 0;
no_virtgeom_ioctl = 1;
} else if (errno == EINVAL) {
/*
* This means that the ioctl exists, but
* is invalid for this disk, meaning the
* disk doesn't have an HBA geometry
* (like, say, it's larger than 8GB).
*/
v_flag = 0;
hba_Numcyl = hba_heads = hba_sectors = 0;
} else {
(void) fprintf(stderr,
"%s: Cannot get virtual disk geometry.\n",
argv[optind]);
exit(1);
}
} else {
/* save virtual geometry values obtained by ioctl */
hba_Numcyl = disk_geom.dkg_ncyl;
hba_heads = disk_geom.dkg_nhead;
hba_sectors = disk_geom.dkg_nsect;
}
errno = 0;
if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
if (errno == ENOTTY) {
no_physgeom_ioctl = 1;
} else {
(void) fprintf(stderr,
"%s: Cannot get physical disk geometry.\n",
argv[optind]);
exit(1);
}
}
/*
* Call DKIOCGGEOM if the ioctls for physical and virtual
* geometry fail. Get both from this generic call.
*/
if (no_virtgeom_ioctl && no_physgeom_ioctl) {
errno = 0;
if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
(void) fprintf(stderr,
"%s: Cannot get disk label geometry.\n",
argv[optind]);
exit(1);
}
}
Numcyl = disk_geom.dkg_ncyl;
heads = disk_geom.dkg_nhead;
sectors = disk_geom.dkg_nsect;
if (minfo.dki_lbsize != 0)
sectsiz = minfo.dki_lbsize;
else
sectsiz = 512;
acyl = disk_geom.dkg_acyl;
/*
* if hba geometry was not set by DKIOC_VIRTGEOM
* or we got an invalid hba geometry
* then set hba geometry based on max values
*/
if (no_virtgeom_ioctl ||
disk_geom.dkg_ncyl == 0 ||
disk_geom.dkg_nhead == 0 ||
disk_geom.dkg_nsect == 0 ||
disk_geom.dkg_ncyl > MAX_CYL ||
disk_geom.dkg_nhead > MAX_HEAD + 1 ||
disk_geom.dkg_nsect > MAX_SECT) {
/*
* turn off flag to print out virtual geometry (-v)
*/
v_flag = 0;
hba_sectors = MAX_SECT;
hba_heads = MAX_HEAD + 1;
hba_Numcyl = (Numcyl * heads * sectors) /
(hba_sectors * hba_heads);
}
if (io_debug) {
(void) fprintf(stderr, "Physical Geometry:\n");
(void) fprintf(stderr,
" cylinders[%d] heads[%d] sectors[%d]\n"
" sector size[%d] blocks[%d] mbytes[%d]\n",
Numcyl,
heads,
sectors,
sectsiz,
Numcyl * heads * sectors,
(Numcyl * heads * sectors * sectsiz) / 1048576);
(void) fprintf(stderr, "Virtual (HBA) Geometry:\n");
(void) fprintf(stderr,
" cylinders[%d] heads[%d] sectors[%d]\n"
" sector size[%d] blocks[%d] mbytes[%d]\n",
hba_Numcyl,
hba_heads,
hba_sectors,
sectsiz,
hba_Numcyl * hba_heads * hba_sectors,
(hba_Numcyl * hba_heads * hba_sectors * sectsiz) /
1048576);
}
}
/* If user has requested a geometry report just do it and exit */
if (io_lgeom) {
if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
(void) fprintf(stderr,
"%s: Cannot get disk label geometry.\n",
argv[optind]);
exit(1);
}
Numcyl = disk_geom.dkg_ncyl;
heads = disk_geom.dkg_nhead;
sectors = disk_geom.dkg_nsect;
if (minfo.dki_lbsize != 0)
sectsiz = minfo.dki_lbsize;
else
sectsiz = 512;
acyl = disk_geom.dkg_acyl;
(void) printf("* Label geometry for device %s\n", Dfltdev);
(void) printf(
"* PCYL NCYL ACYL BCYL NHEAD NSECT"
" SECSIZ\n");
(void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
Numcyl,
disk_geom.dkg_ncyl,
disk_geom.dkg_acyl,
disk_geom.dkg_bcyl,
heads,
sectors,
sectsiz);
exit(0);
} else if (io_pgeom) {
if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
(void) fprintf(stderr,
"%s: Cannot get physical disk geometry.\n",
argv[optind]);
exit(1);
}
(void) printf("* Physical geometry for device %s\n", Dfltdev);
(void) printf(
"* PCYL NCYL ACYL BCYL NHEAD NSECT"
" SECSIZ\n");
(void) printf(" %-8d %-8d %-8d %-8d %-5d %-5d %-6d\n",
disk_geom.dkg_pcyl,
disk_geom.dkg_ncyl,
disk_geom.dkg_acyl,
disk_geom.dkg_bcyl,
disk_geom.dkg_nhead,
disk_geom.dkg_nsect,
sectsiz);
exit(0);
} else if (io_sgeom) {
if (read_geom(io_sgeom)) {
exit(1);
} else if (!io_image) {
exit(0);
}
}
/*
* some drivers may not support DKIOCGMEDIAINFO
* in that case use CHS
*/
chs_capacity = (diskaddr_t)Numcyl * heads * sectors;
dev_capacity = chs_capacity;
Numcyl_usable = Numcyl;
if (chs_capacity > DK_MAX_2TB) {
/* limit to 2TB */
Numcyl_usable = DK_MAX_2TB / (heads * sectors);
chs_capacity = (diskaddr_t)Numcyl_usable * heads * sectors;
}
if (minfo.dki_capacity > 0)
dev_capacity = minfo.dki_capacity;
/* Allocate memory to hold three complete sectors */
Bootsect = (char *)calloc(3 * sectsiz, 1);
if (Bootsect == NULL) {
(void) fprintf(stderr,
"fdisk: Unable to obtain enough buffer memory"
" (%d bytes).\n",
3 * sectsiz);
exit(1);
}
Nullsect = Bootsect + sectsiz;
/* Zero out the "NULL" sector */
for (i = 0; i < sectsiz; i++) {
Nullsect[i] = 0;
}
/* Find out what the user wants done */
if (io_rd) { /* abs disk read */
abs_read(); /* will not return */
} else if (io_wrt && !io_readonly) {
abs_write(); /* will not return */
} else if (io_patt && !io_readonly) {
fill_patt(); /* will not return */
}
/* This is the fdisk edit, the real reason for the program. */
sanity_check_provided_device(Dfltdev, Dev);
/* Get the new BOOT program in case we write a new fdisk table */
mboot_read();
/* Read from disk master boot */
dev_mboot_read();
/*
* Verify and copy the device's fdisk table. This will be used
* as the prototype mboot if the device's mboot looks invalid.
*/
Bootblk = (struct mboot *)Bootsect;
copy_Bootblk_to_Table();
/* save away a copy of Table in Old_Table for sensing changes */
copy_Table_to_Old_Table();
#ifdef i386
/*
* Read extended partition only when the fdisk table is not
* supplied from a file
*/
if (!io_ffdisk) {
lf_op_flag |= FDISK_READ_DISK;
}
if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag))
!= FDISK_SUCCESS) {
switch (rval) {
/*
* FDISK_EBADLOGDRIVE, FDISK_ENOLOGDRIVE and
* FDISK_EBADMAGIC can be considered as
* soft errors and hence we do not exit
*/
case FDISK_EBADLOGDRIVE:
break;
case FDISK_ENOLOGDRIVE:
break;
case FDISK_EBADMAGIC:
break;
case FDISK_ENOVGEOM:
(void) fprintf(stderr, "Could not get virtual"
" geometry for this device\n");
exit(1);
break;
case FDISK_ENOPGEOM:
(void) fprintf(stderr, "Could not get physical"
" geometry for this device\n");
exit(1);
break;
case FDISK_ENOLGEOM:
(void) fprintf(stderr, "Could not get label"
" geometry for this device\n");
exit(1);
break;
default:
perror("Failed to initialise libfdisk.\n");
exit(1);
break;
}
}
#endif
/* Load fdisk table from specified file (-F fdisk_file) */
if (io_ffdisk) {
/* Load and verify user-specified table parameters */
load(LOADFILE, io_ffdisk);
}
/* Does user want to delete or add an entry? */
if (io_Dfdisk) {
load(LOADDEL, io_Dfdisk);
}
if (io_Afdisk) {
load(LOADADD, io_Afdisk);
}
if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) {
/* Check if there is no fdisk table */
if (nopartdefined() || io_wholedisk || io_EFIdisk) {
if (io_ifdisk && !io_wholedisk && !io_EFIdisk) {
(void) printf(
"No fdisk table exists. The default"
" partition for the disk is:\n\n"
" a 100%% \"SOLARIS System\" "
"partition\n\n"
"Type \"y\" to accept the default "
"partition, otherwise type \"n\" to "
"edit the\n partition table.\n");
if (Numcyl > Numcyl_usable)
(void) printf("WARNING: Disk is larger"
" than 2TB. Solaris partition will"
" be limited to 2 TB.\n");
}
/* Edit the partition table as directed */
if (io_wholedisk ||(io_ifdisk && yesno())) {
/* Default scenario */
nulltbl();
/* now set up UNIX System partition */
Table[0].bootid = ACTIVE;
Table[0].relsect = LE_32(heads * sectors);
Table[0].numsect =
LE_32((ulong_t)((Numcyl_usable - 1) *
heads * sectors));
Table[0].systid = SUNIXOS2; /* Solaris */
/* calculate CHS values for table entry 0 */
Set_Table_CHS_Values(0);
update_disk_and_exit(B_TRUE);
} else if (io_EFIdisk) {
if (efi_create() == 0) {
(void) fprintf(stderr,
"Error creating EFI partition\n");
exit(1);
}
(void) close(Dev);
exit(0);
/* NOTREACHED */
}
}
}
/* Display complete fdisk table entries for debugging purposes */
if (io_debug) {
(void) fprintf(stderr, "Partition Table Entry Values:\n");
print_Table();
if (io_ifdisk) {
(void) fprintf(stderr, "\n");
(void) fprintf(stderr, "Press Enter to continue.\n");
(void) fgets(s, sizeof (s), stdin);
}
}
/* Interactive fdisk mode */
if (io_ifdisk) {
(void) printf(CLR_SCR);
disptbl();
for (;;) {
stage0();
copy_Bootblk_to_Table();
disptbl();
}
}
/* If user wants to write the table to a file, do it */
if (io_Wfdisk)
ffile_write(io_Wfdisk);
else if (stdo_flag)
ffile_write((char *)stdout);
update_disk_and_exit(TableChanged() == 1);
return (0);
}
/*
* read_geom
* Read geometry from specified file (-S).
*/
static int
read_geom(char *sgeom)
{
char line[256];
FILE *fp;
/* open the prototype file */
if ((fp = fopen(sgeom, "r")) == NULL) {
(void) fprintf(stderr, "fdisk: Cannot open file %s.\n",
io_sgeom);
return (1);
}
/* Read a line from the file */
while (fgets(line, sizeof (line) - 1, fp)) {
if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
continue;
else {
line[strlen(line)] = '\0';
if (sscanf(line, "%hu %hu %hu %hu %hu %hu %d",
&disk_geom.dkg_pcyl,
&disk_geom.dkg_ncyl,
&disk_geom.dkg_acyl,
&disk_geom.dkg_bcyl,
&disk_geom.dkg_nhead,
&disk_geom.dkg_nsect,
&sectsiz) != 7) {
(void) fprintf(stderr,
"Syntax error:\n \"%s\".\n",
line);
return (1);
}
break;
} /* else */
} /* while (fgets(line, sizeof (line) - 1, fp)) */
if (!io_image) {
if (ioctl(Dev, DKIOCSGEOM, &disk_geom)) {
(void) fprintf(stderr,
"fdisk: Cannot set label geometry.\n");
return (1);
}
} else {
Numcyl = hba_Numcyl = disk_geom.dkg_ncyl;
heads = hba_heads = disk_geom.dkg_nhead;
sectors = hba_sectors = disk_geom.dkg_nsect;
acyl = disk_geom.dkg_acyl;
}
(void) fclose(fp);
return (0);
}
/*
* dev_mboot_read
* Read the master boot sector from the device.
*/
static void
dev_mboot_read(void)
{
if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) {
perror("Error in ioctl DKIOCGMBOOT");
}
if (errno == 0)
return;
if (lseek(Dev, 0, SEEK_SET) == -1) {
(void) fprintf(stderr,
"fdisk: Error seeking to partition table on %s.\n",
Dfltdev);
if (!io_image)
exit(1);
}
if (read(Dev, Bootsect, sectsiz) != sectsiz) {
(void) fprintf(stderr,
"fdisk: Error reading partition table from %s.\n",
Dfltdev);
if (!io_image)
exit(1);
}
}
/*
* dev_mboot_write
* Write the master boot sector to the device.
*/
static void
dev_mboot_write(off_t sect, char *buff, int bootsiz)
{
int new_pt, old_pt, error;
int clr_efi = -1;
if (io_readonly)
return;
if (io_debug) {
(void) fprintf(stderr, "About to write fdisk table:\n");
print_Table();
if (io_ifdisk) {
(void) fprintf(stderr, "Press Enter to continue.\n");
(void) fgets(s, sizeof (s), stdin);
}
}
/*
* If the new table has any Solaris partitions and the old
* table does not have an entry that describes it
* exactly then clear the old vtoc (if any).
*/
for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
/* We only care about potential Solaris parts. */
if (Table[new_pt].systid != SUNIXOS &&
Table[new_pt].systid != SUNIXOS2)
continue;
/* Does the old table have an exact entry for the new entry? */
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
/* We only care about old Solaris partitions. */
if ((Old_Table[old_pt].systid == SUNIXOS) ||
(Old_Table[old_pt].systid == SUNIXOS2)) {
/* Is this old one the same as a new one? */
if ((Old_Table[old_pt].relsect ==
Table[new_pt].relsect) &&
(Old_Table[old_pt].numsect ==
Table[new_pt].numsect))
break; /* Yes */
}
}
/* Did a solaris partition change location or size? */
if (old_pt >= FD_NUMPART) {
/* Yes clear old vtoc */
if (io_debug) {
(void) fprintf(stderr,
"Clearing VTOC labels from NEW"
" table\n");
}
clear_vtoc(NEW, new_pt);
}
}
/* see if the old table had EFI */
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
if (Old_Table[old_pt].systid == EFI_PMBR) {
clr_efi = old_pt;
}
}
/* look to see if a EFI partition changed in relsect/numsect */
for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
if (Table[new_pt].systid != EFI_PMBR)
continue;
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
if ((Old_Table[old_pt].systid ==
Table[new_pt].systid) &&
(Old_Table[old_pt].relsect ==
Table[new_pt].relsect) &&
(Old_Table[old_pt].numsect ==
Table[new_pt].numsect)) {
/*
* New EFI guard partition matches old.
* Do not clear EFI labels in this case.
*/
clr_efi = -1;
break;
}
}
/*
* if EFI partition changed, set the flag to clear
* the EFI GPT
*/
if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
clr_efi = 0;
}
break;
}
/* clear labels if necessary */
if (clr_efi >= 0) {
if (io_debug) {
(void) fprintf(stderr, "Clearing EFI labels\n");
}
if ((error = clear_efi()) != 0) {
if (io_debug) {
(void) fprintf(stderr,
"\tError %d clearing EFI labels"
" (probably no EFI labels exist)\n",
error);
}
}
}
if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) {
(void) fprintf(stderr,
"fdisk: Error in ioctl DKIOCSMBOOT on %s.\n",
Dfltdev);
}
if (errno == 0)
return;
/* write to disk drive */
if (lseek(Dev, sect, SEEK_SET) == -1) {
(void) fprintf(stderr,
"fdisk: Error seeking to master boot record on %s.\n",
Dfltdev);
exit(1);
}
if (write(Dev, buff, bootsiz) != bootsiz) {
(void) fprintf(stderr,
"fdisk: Error writing master boot record to %s.\n",
Dfltdev);
exit(1);
}
}
/*
* mboot_read
* Read the prototype boot records from the files.
*/
static void
mboot_read(void)
{
int mDev, i;
struct ipart *part;
#if defined(i386) || defined(sparc)
/*
* If the master boot file hasn't been specified, use the
* implementation architecture name to generate the default one.
*/
if (io_mboot == (char *)0) {
/*
* Bug ID 1249035:
* The mboot file must be delivered on all platforms
* and installed in a non-platform-dependent
* directory; i.e., /usr/lib/fs/ufs.
*/
io_mboot = "/usr/lib/fs/ufs/mboot";
}
/* First read in the master boot record */
/* Open the master boot proto file */
if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
(void) fprintf(stderr,
"fdisk: Cannot open master boot file %s.\n",
io_mboot);
exit(1);
}
/* Read the master boot program */
if (read(mDev, &BootCod, sizeof (struct mboot)) != sizeof
(struct mboot)) {
(void) fprintf(stderr,
"fdisk: Cannot read master boot file %s.\n",
io_mboot);
exit(1);
}
/* Is this really a master boot record? */
if (LE_16(BootCod.signature) != MBB_MAGIC) {
(void) fprintf(stderr,
"fdisk: Invalid master boot file %s.\n", io_mboot);
(void) fprintf(stderr,
"Bad magic number: is %x, but should be %x.\n",
LE_16(BootCod.signature), MBB_MAGIC);
exit(1);
}
(void) close(mDev);
#else
#error fdisk needs to be ported to new architecture
#endif
/* Zero out the partitions part of this record */
part = (struct ipart *)BootCod.parts;
for (i = 0; i < FD_NUMPART; i++, part++) {
(void) memset(part, 0, sizeof (struct ipart));
}
}
/*
* fill_patt
* Fill the disk with user/sector number pattern.
*/
static void
fill_patt(void)
{
int *buff_ptr, i;
off_t *off_ptr;
int io_fpatt = 0;
int io_ipatt = 0;
if (strncmp(io_fatt, "#", 1) != 0) {
io_fpatt++;
io_ipatt = strtoul(io_fatt, 0, 0);
buff_ptr = (int *)Bootsect;
for (i = 0; i < sectsiz; i += 4, buff_ptr++)
*buff_ptr = io_ipatt;
}
/*
* Fill disk with pattern based on block number.
* Write to the disk at absolute relative block io_offset
* for io_size blocks.
*/
while (io_size--) {
off_ptr = (off_t *)Bootsect;
if (!io_fpatt) {
for (i = 0; i < sectsiz;
i += sizeof (off_t), off_ptr++)
*off_ptr = io_offset;
}
/* Write the data to disk */
if (lseek(Dev, (off_t)(sectsiz * io_offset++),
SEEK_SET) == -1) {
(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
Dfltdev);
exit(1);
}
if (write(Dev, Bootsect, sectsiz) != sectsiz) {
(void) fprintf(stderr, "fdisk: Error writing %s.\n",
Dfltdev);
exit(1);
}
} /* while (--io_size); */
}
/*
* abs_read
* Read from the disk at absolute relative block io_offset for
* io_size blocks. Write the data to standard ouput (-r).
*/
static void
abs_read(void)
{
int c;
while (io_size--) {
if (lseek(Dev, (off_t)(sectsiz * io_offset++),
SEEK_SET) == -1) {
(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
Dfltdev);
exit(1);
}
if (read(Dev, Bootsect, sectsiz) != sectsiz) {
(void) fprintf(stderr, "fdisk: Error reading %s.\n",
Dfltdev);
exit(1);
}
/* Write to standard ouptut */
if ((c = write(1, Bootsect, (unsigned)sectsiz)) != sectsiz) {
if (c >= 0) {
if (io_debug)
(void) fprintf(stderr,
"fdisk: Output warning: %d of %d"
" characters written.\n",
c, sectsiz);
exit(2);
} else {
perror("write error on output file.");
exit(2);
}
} /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */
/* != sectsiz) */
} /* while (--io_size); */
exit(0);
}
/*
* abs_write
* Read the data from standard input. Write to the disk at
* absolute relative block io_offset for io_size blocks (-w).
*/
static void
abs_write(void)
{
int c, i;
while (io_size--) {
int part_exit = 0;
/* Read from standard input */
if ((c = read(0, Bootsect, (unsigned)sectsiz)) != sectsiz) {
if (c >= 0) {
if (io_debug)
(void) fprintf(stderr,
"fdisk: WARNING: Incomplete read (%d of"
" %d characters read) on input file.\n",
c, sectsiz);
/* Fill pattern to mark partial sector in buf */
for (i = c; i < sectsiz; ) {
Bootsect[i++] = 0x41;
Bootsect[i++] = 0x62;
Bootsect[i++] = 0x65;
Bootsect[i++] = 0;
}
part_exit++;
} else {
perror("read error on input file.");
exit(2);
}
}
/* Write to disk drive */
if (lseek(Dev, (off_t)(sectsiz * io_offset++),
SEEK_SET) == -1) {
(void) fprintf(stderr, "fdisk: Error seeking on %s.\n",
Dfltdev);
exit(1);
}
if (write(Dev, Bootsect, sectsiz) != sectsiz) {
(void) fprintf(stderr, "fdisk: Error writing %s.\n",
Dfltdev);
exit(1);
}
if (part_exit)
exit(0);
} /* while (--io_size); */
exit(1);
}
/*
* load
* Load will either read the fdisk table from a file or add or
* delete an entry (-A, -D, -F).
*/
static void
load(int funct, char *file)
{
int id;
int act;
int bhead;
int bsect;
int bcyl;
int ehead;
int esect;
int ecyl;
uint32_t rsect;
uint32_t numsect;
char line[256];
int i = 0;
FILE *fp;
int startindex = 0;
int tmpindex = 0;
#ifdef i386
int ext_part_present = 0;
uint32_t begsec, endsec, relsect;
logical_drive_t *temp;
int part_count = 0, ldcnt = 0;
uint32_t ext_beg_sec;
uint32_t old_ext_beg_sec = 0, old_ext_num_sec = 0;
uint32_t new_ext_beg_sec = 0, new_ext_num_sec = 0;
int ext_part_inited = 0;
uchar_t systid;
#endif
switch (funct) {
case LOADFILE:
/*
* Zero out the table before loading it, which will
* force it to be updated on disk later (-F
* fdisk_file).
*/
nulltbl();
/* Open the prototype file */
if ((fp = fopen(file, "r")) == NULL) {
(void) fprintf(stderr,
"fdisk: Cannot open prototype partition file %s.\n",
file);
exit(1);
}
/* Read a line from the file */
while (fgets(line, sizeof (line) - 1, fp)) {
if (pars_fdisk(line, &id, &act, &bhead, &bsect,
&bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) {
continue;
}
#ifdef i386
part_count++;
if (fdisk_is_dos_extended((uchar_t)id)) {
if (ext_part_present) {
(void) fprintf(stderr,
"Extended partition"
" already exists\n");
(void) fprintf(stderr, "fdisk: Error on"
" entry \"%s\".\n", line);
exit(1);
}
ext_part_present = 1;
/*
* If the existing extended partition's start
* and size matches the new one, do not
* initialize the extended partition EBR
* (Extended Boot Record) because there could
* be existing logical drives.
*/
for (i = 0; i < FD_NUMPART; i++) {
systid = Old_Table[i].systid;
if (fdisk_is_dos_extended(systid)) {
old_ext_beg_sec =
Old_Table[i].relsect;
old_ext_num_sec =
Old_Table[i].numsect;
break;
}
}
new_ext_beg_sec = rsect;
new_ext_num_sec = numsect;
if ((old_ext_beg_sec != new_ext_beg_sec) ||
(old_ext_num_sec != new_ext_num_sec)) {
(void) fdisk_init_ext_part(epp,
new_ext_beg_sec, new_ext_num_sec);
ext_part_inited = 1;
}
}
if (part_count > FD_NUMPART) {
/* This line should be logical drive info */
int offset = MAX_LOGDRIVE_OFFSET;
if (!ext_part_present) {
/* Erroneous input file */
(void) fprintf(stderr,
"More than 4 primary"
" partitions found in input\n");
(void) fprintf(stderr, "Exiting...\n");
exit(1);
}
if (numsect == 0) {
continue;
}
/*
* If the start and size of the existing
* extended partition matches the new one and
* new logical drives are being defined via
* the input file, initialize the EBR.
*/
if (!ext_part_inited) {
(void) fdisk_init_ext_part(epp,
new_ext_beg_sec, new_ext_num_sec);
ext_part_inited = 1;
}
begsec = rsect - offset;
if ((ldcnt =
fdisk_get_logical_drive_count(epp)) == 0) {
/* Adding the first logical drive */
/*
* Make sure that begsec doesnt wrap
* around. This can happen if rsect is
* less than offset.
*/
if (rsect < offset) {
(void) fprintf(stderr,
"Minimum of "
"63 free sectors required "
"before the beginning of "
"a logical drive.");
exit(1);
}
/*
* Check if the first logical drive
* is out of order. In that case, do
* not subtract MAX_LOGDRIVE_OFFSET
* from the given start of partition.
*/
if (begsec != new_ext_beg_sec) {
begsec = rsect;
offset = 0;
}
}
if (ldcnt >= MAX_EXT_PARTS) {
(void) fprintf(stderr,
"\nError : Number of "
"logical drives exceeds limit of "
"%d.\n", MAX_EXT_PARTS);
exit(1);
}
if (id > FDISK_MAX_VALID_PART_ID) {
(void) fprintf(stderr,
"Invalid partition ID\n");
(void) fprintf(stderr, "fdisk: Error on"
" entry \"%s\".\n", line);
exit(1);
}
endsec = rsect + numsect - 1;
if (fdisk_validate_logical_drive(epp,
begsec, offset, numsect) == 0) {
if (id == EFI_PMBR) {
(void) fprintf(stderr, "EFI "
"partitions not supported "
"inside extended "
"partition\n");
exit(1);
}
fdisk_add_logical_drive(epp, begsec,
endsec, id);
continue;
} else {
(void) fprintf(stderr, "fdisk: Error on"
" entry \"%s\".\n", line);
exit(1);
}
}
#endif
/*
* Validate the partition. It cannot start at sector
* 0 unless it is UNUSED or already exists
*/
if (validate_part(id, rsect, numsect) < 0) {
(void) fprintf(stderr,
"fdisk: Error on entry \"%s\".\n",
line);
exit(1);
}
if ((tmpindex = entry_from_old_table(id, act, bhead,
bsect, bcyl, ehead, esect, ecyl, rsect, numsect,
startindex)) != -1) {
/*
* If we got here it means we copied an
* unmodified entry. So there is no need
* to insert it in the table or do any
* checks against disk size.
*
* This is a work around on the following
* situation (for IDE disks, at least):
* Different operation systems calculate
* disk size different ways, of which there
* are two main ways.
*
* The first, rounds the disk size to modulo
* cylinder size (virtual made-up cylinder
* usually based on maximum number of heads
* and sectors in partition table fields).
* Our OS's (for IDE) and most other "Unix"
* type OS's do this.
*
* The second, uses every single block
* on the disk (to maximize available space).
* Since disk manufactures do not know about
* "virtual cylinders", there are some number
* of blocks that make up a partial cylinder
* at the end of the disk.
*
* The difference between these two methods
* is where the problem is. When one
* tries to install Solaris/OpenSolaris on
* a disk that has another OS using that
* "partial cylinder", install fails. It fails
* since fdisk thinks its asked to create a
* partition with the -F option that contains
* a partition that runs off the end of the
* disk.
*/
startindex = tmpindex + 1;
continue;
}
/*
* Find an unused entry to use and put the entry
* in table
*/
if ((startindex = insert_tbl(id, act, bhead, bsect,
bcyl, ehead, esect, ecyl, rsect, numsect,
startindex)) < 0) {
(void) fprintf(stderr,
"fdisk: Error on entry \"%s\".\n",
line);
exit(1);
}
startindex++;
} /* while (fgets(line, sizeof (line) - 1, fp)) */
if (verify_tbl() < 0) {
(void) fprintf(stderr,
"fdisk: Cannot create partition table\n");
exit(1);
}
(void) fclose(fp);
return;
case LOADDEL:
/* Parse the user-supplied deletion line (-D) */
if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl,
&ehead, &esect, &ecyl, &rsect, &numsect)) {
(void) fprintf(stderr,
"fdisk: Syntax error \"%s\"\n", file);
exit(1);
}
/* Find the exact entry in the table */
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid == id &&
Table[i].bootid == act &&
Table[i].beghead == bhead &&
Table[i].begsect == ((bsect & 0x3f) |
(uchar_t)((bcyl>>2) & 0xc0)) &&
Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
Table[i].endhead == ehead &&
Table[i].endsect == ((esect & 0x3f) |
(uchar_t)((ecyl>>2) & 0xc0)) &&
Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
Table[i].relsect == LE_32(rsect) &&
Table[i].numsect == LE_32(numsect)) {
(void) memset(&Table[i], 0,
sizeof (struct ipart));
#ifdef i386
if (fdisk_is_dos_extended(id)) {
(void) fdisk_delete_ext_part(epp);
}
#endif
return;
}
}
#ifdef i386
ldcnt = FD_NUMPART + 1;
for (temp = fdisk_get_ld_head(epp); temp != NULL;
temp = temp->next) {
relsect = temp->abs_secnum + temp->logdrive_offset;
if (temp->parts[0].systid == id &&
temp->parts[0].bootid == act &&
temp->parts[0].beghead == bhead &&
temp->parts[0].begsect == ((bsect & 0x3f) |
(uchar_t)((bcyl>>2) & 0xc0)) &&
temp->parts[0].begcyl == (uchar_t)(bcyl & 0xff) &&
temp->parts[0].endhead == ehead &&
temp->parts[0].endsect == ((esect & 0x3f) |
(uchar_t)((ecyl>>2) & 0xc0)) &&
temp->parts[0].endcyl == (uchar_t)(ecyl & 0xff) &&
relsect == LE_32(rsect) &&
temp->parts[0].numsect == LE_32(numsect)) {
fdisk_delete_logical_drive(epp, ldcnt);
return;
}
ldcnt++;
}
#endif
(void) fprintf(stderr,
"fdisk: Entry does not match any existing partition:\n"
" \"%s\"\n",
file);
exit(1);
/* FALLTHROUGH */
case LOADADD:
/* Parse the user-supplied addition line (-A) */
if (pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead,
&esect, &ecyl, &rsect, &numsect)) {
(void) fprintf(stderr,
"fdisk: Syntax error \"%s\"\n", file);
exit(1);
}
/* Validate the partition. It cannot start at sector 0 */
if (rsect == 0) {
(void) fprintf(stderr,
"fdisk: New partition cannot start at sector 0:\n"
" \"%s\".\n",
file);
exit(1);
}
/*
* if the user wishes to add an EFI partition, we need
* more extensive validation. rsect should be 1, and
* numsect should equal the entire disk capacity - 1
*/
if (id == EFI_PMBR) {
if (rsect != 1) {
(void) fprintf(stderr,
"fdisk: EFI partitions must start at sector"
" 1 (input rsect = %d)\n", rsect);
exit(1);
}
if (dev_capacity > DK_MAX_2TB) {
if (numsect != DK_MAX_2TB) {
(void) fprintf(stderr,
"fdisk: EFI partitions must "
"encompass the entire maximum 2 TB "
"(input numsect: %u - max: %llu)\n",
numsect, (diskaddr_t)DK_MAX_2TB);
exit(1);
}
} else if (numsect != dev_capacity - 1) {
(void) fprintf(stderr,
"fdisk: EFI partitions must encompass the "
"entire disk\n"
"(input numsect: %u - avail: %llu)\n",
numsect,
dev_capacity - 1);
exit(1);
}
}
#ifdef i386
if (id > FDISK_MAX_VALID_PART_ID) {
(void) printf("Invalid partition ID\n");
exit(1);
}
if ((fdisk_ext_part_exists(epp)) &&
(fdisk_is_dos_extended(id))) {
(void) fprintf(stderr,
"Extended partition already exists.\n");
(void) fprintf(stderr,
"fdisk: Invalid entry could not be "
"inserted:\n \"%s\"\n", file);
exit(1);
}
if (fdisk_ext_part_exists(epp) &&
(rsect >= (ext_beg_sec = fdisk_get_ext_beg_sec(epp))) &&
(rsect <= (fdisk_get_ext_end_sec(epp)))) {
int offset = MAX_LOGDRIVE_OFFSET;
/*
* Make sure that begsec doesnt wrap around.
* This can happen if rsect is less than offset
*/
if (rsect < offset) {
return;
}
begsec = rsect - offset;
if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) {
/*
* Adding the first logical drive
* Check if the first logical drive
* is out of order. In that case, do
* not subtract MAX_LOGDRIVE_OFFSET
* from the given start of partition.
*/
if (begsec != ext_beg_sec) {
begsec = rsect;
offset = 0;
}
}
if (ldcnt >= MAX_EXT_PARTS) {
(void) printf("\nNumber of logical drives "
"exceeds limit of %d.\n", MAX_EXT_PARTS);
(void) printf("Failing further additions.\n");
exit(1);
}
if (numsect == 0) {
(void) fprintf(stderr,
"fdisk: Partition size cannot be zero:\n"
" \"%s\".\n",
file);
exit(1);
}
endsec = rsect + numsect - 1;
if (fdisk_validate_logical_drive(epp, begsec,
offset, numsect) == 0) {
/* Valid logical drive */
fdisk_add_logical_drive(epp, begsec, endsec,
id);
return;
} else {
(void) fprintf(stderr,
"fdisk: Invalid entry could not be "
"inserted:\n \"%s\"\n", file);
exit(1);
}
}
#endif
/* Find unused entry for use and put entry in table */
if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect,
ecyl, rsect, numsect, 0) < 0) {
(void) fprintf(stderr,
"fdisk: Invalid entry could not be inserted:\n"
" \"%s\"\n",
file);
exit(1);
}
/* Make sure new entry does not overlap existing entry */
if (verify_tbl() < 0) {
(void) fprintf(stderr,
"fdisk: Cannot create partition \"%s\"\n", file);
exit(1);
}
} /* switch funct */
}
/*
* Set_Table_CHS_Values
*
* This will calculate the CHS values for beginning and ending CHS
* for a single partition table entry (ti) based on the relsect
* and numsect values contained in the partion table entry.
*
* hba_heads and hba_sectors contain the number of heads and sectors.
*
* If the number of cylinders exceeds the MAX_CYL,
* then maximum values will be placed in the corresponding chs entry.
*/
static void
Set_Table_CHS_Values(int ti)
{
uint32_t lba, cy, hd, sc;
lba = (uint32_t)Table[ti].relsect;
if (lba >= hba_heads * hba_sectors * MAX_CYL) {
/*
* the lba address cannot be expressed in CHS value
* so store the maximum CHS field values in the CHS fields.
*/
cy = MAX_CYL + 1;
hd = MAX_HEAD + 1;
sc = MAX_SECT;
} else {
cy = lba / hba_sectors / hba_heads;
hd = lba / hba_sectors % hba_heads;
sc = lba % hba_sectors + 1;
}
Table[ti].begcyl = cy & 0xff;
Table[ti].beghead = (uchar_t)hd;
Table[ti].begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
/*
* This code is identical to the code above
* except that it works on ending CHS values
*/
lba = (uint32_t)(Table[ti].relsect + Table[ti].numsect - 1);
if (lba >= hba_heads * hba_sectors * MAX_CYL) {
cy = MAX_CYL + 1;
hd = MAX_HEAD + 1;
sc = MAX_SECT;
} else {
cy = lba / hba_sectors / hba_heads;
hd = lba / hba_sectors % hba_heads;
sc = lba % hba_sectors + 1;
}
Table[ti].endcyl = cy & 0xff;
Table[ti].endhead = (uchar_t)hd;
Table[ti].endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
}
/*
* insert_tbl
* Insert entry into fdisk table. Check all user-supplied values
* for the entry, but not the validity relative to other table
* entries!
*/
static int
insert_tbl(
int id, int act,
int bhead, int bsect, int bcyl,
int ehead, int esect, int ecyl,
uint32_t rsect, uint32_t numsect, int startindex)
{
int i;
/* validate partition size */
if (((diskaddr_t)rsect + numsect) > dev_capacity) {
(void) fprintf(stderr,
"fdisk: Partition table exceeds the size of the disk.\n");
return (-1);
}
/* find UNUSED partition table entry */
for (i = startindex; i < FD_NUMPART; i++) {
if (Table[i].systid == UNUSED) {
break;
}
}
if (i >= FD_NUMPART) {
(void) fprintf(stderr, "fdisk: Partition table is full.\n");
return (-1);
}
Table[i].systid = (uchar_t)id;
Table[i].bootid = (uchar_t)act;
Table[i].numsect = LE_32(numsect);
Table[i].relsect = LE_32(rsect);
if (id == UNUSED) {
(void) memset(&Table[i], 0, sizeof (struct ipart));
} else if (0 < bsect && bsect <= MAX_SECT &&
0 <= bhead && bhead <= MAX_HEAD + 1 &&
0 < esect && esect <= MAX_SECT &&
0 <= ehead && ehead <= MAX_HEAD + 1) {
/*
* If we have been called with a valid geometry, use it
* valid means non-zero values that fit in the BIOS fields
*/
if (bcyl > MAX_CYL) {
/*
* bcyl is set to the special fence value indicating
* that the geometry is not representable for the
* start LBA.
* Set all fields to the maximum values.
*/
bcyl = MAX_CYL + 1;
bhead = MAX_HEAD + 1;
bsect = MAX_SECT;
}
if (ecyl > MAX_CYL) {
ecyl = MAX_CYL + 1;
ehead = MAX_HEAD + 1;
esect = MAX_SECT;
}
Table[i].begcyl = bcyl & 0xff;
Table[i].endcyl = ecyl & 0xff;
Table[i].beghead = (uchar_t)bhead;
Table[i].endhead = (uchar_t)ehead;
Table[i].begsect = (uchar_t)(((bcyl >> 2) & 0xc0) | bsect);
Table[i].endsect = ((ecyl >> 2) & 0xc0) | esect;
} else {
/*
* The specified values are invalid,
* so calculate the values based on hba_heads, hba_sectors
*/
Set_Table_CHS_Values(i);
}
/*
* return partition index
*/
return (i);
}
/*
* entry_from_old_table
* If the specified entry is in the old table and is not a Solaris entry
* then insert same entry into new fdisk table. If we do this then
* all checks are skipped for that entry!
*/
static int
entry_from_old_table(
int id, int act,
int bhead, int bsect, int bcyl,
int ehead, int esect, int ecyl,
uint32_t rsect, uint32_t numsect, int startindex)
{
uint32_t i, j;
if (id == SUNIXOS || id == SUNIXOS2 || id == UNUSED)
return (-1);
for (i = 0; i < FD_NUMPART; i++) {
if (Old_Table[i].systid == id &&
Old_Table[i].bootid == act &&
Old_Table[i].beghead == bhead &&
Old_Table[i].begsect == ((bsect & 0x3f) |
(uchar_t)((bcyl>>2) & 0xc0)) &&
Old_Table[i].begcyl == (uchar_t)(bcyl & 0xff) &&
Old_Table[i].endhead == ehead &&
Old_Table[i].endsect == ((esect & 0x3f) |
(uchar_t)((ecyl>>2) & 0xc0)) &&
Old_Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
Old_Table[i].relsect == lel(rsect) &&
Old_Table[i].numsect == lel(numsect)) {
/* find UNUSED partition table entry */
for (j = startindex; j < FD_NUMPART; j++) {
if (Table[j].systid == UNUSED) {
(void) memcpy(&Table[j], &Old_Table[i],
sizeof (Table[0]));
skip_verify[j] = 1;
return (j);
}
}
return (-1);
}
}
return (-1);
}
/*
* verify_tbl
* Verify that no partition entries overlap or exceed the size of
* the disk.
*/
static int
verify_tbl(void)
{
uint32_t i, j, rsect, numsect;
int noMoreParts = 0;
int numParts = 0;
/* Make sure new entry does not overlap an existing entry */
for (i = 0; i < FD_NUMPART - 1; i++) {
if (Table[i].systid != UNUSED) {
numParts++;
/*
* No valid partitions allowed after EFI_PMBR part
*/
if (noMoreParts) {
return (-1);
}
if (Table[i].systid == EFI_PMBR) {
/*
* EFI_PMBR partition must be the only
* partition
*/
noMoreParts = 1;
if (Table[i].relsect != 1) {
(void) fprintf(stderr, "ERROR: "
"Invalid starting sector "
"for EFI_PMBR partition:\n"
"relsect %d "
"(should be 1)\n",
Table[i].relsect);
return (-1);
}
if (Table[i].numsect !=
((dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
(dev_capacity - 1))) {
(void) fprintf(stderr, "ERROR: "
"EFI_PMBR partition must "
"encompass the entire");
if (dev_capacity > DK_MAX_2TB)
(void) fprintf(stderr,
"maximum 2 TB.\n "
"numsect %u - "
"actual %llu\n",
Table[i].numsect,
(diskaddr_t)DK_MAX_2TB);
else
(void) fprintf(stderr,
"disk.\n numsect %u - "
"actual %llu\n",
Table[i].numsect,
dev_capacity - 1);
return (-1);
}
}
/* make sure the partition isn't larger than the disk */
rsect = LE_32(Table[i].relsect);
numsect = LE_32(Table[i].numsect);
if ((((diskaddr_t)rsect + numsect) > dev_capacity) ||
(((diskaddr_t)rsect + numsect) > DK_MAX_2TB)) {
if (!skip_verify[i])
return (-1);
}
for (j = i + 1; j < FD_NUMPART; j++) {
if (Table[j].systid != UNUSED) {
uint32_t t_relsect =
LE_32(Table[j].relsect);
uint32_t t_numsect =
LE_32(Table[j].numsect);
if (noMoreParts) {
(void) fprintf(stderr,
"Cannot add partition to "
"table; no more partitions "
"allowed\n");
if (io_debug) {
(void) fprintf(stderr,
"DEBUG: Current "
"partition:\t"
"%d:%d:%d:%d:%d:"
"%d:%d:%d:%d:%d\n"
" Next "
"partition:\t\t"
"%d:%d:%d:%d:%d:"
"%d:%d:%d:%d:%d\n",
Table[i].systid,
Table[i].bootid,
Table[i].begcyl,
Table[i].beghead,
Table[i].begsect,
Table[i].endcyl,
Table[i].endhead,
Table[i].endsect,
Table[i].relsect,
Table[i].numsect,
Table[j].systid,
Table[j].bootid,
Table[j].begcyl,
Table[j].beghead,
Table[j].begsect,
Table[j].endcyl,
Table[j].endhead,
Table[j].endsect,
Table[j].relsect,
Table[j].numsect);
}
return (-1);
}
if ((rsect >=
(t_relsect + t_numsect)) ||
((rsect + numsect) <= t_relsect)) {
continue;
} else {
(void) fprintf(stderr, "ERROR: "
"current partition overlaps"
" following partition\n");
return (-1);
}
}
}
}
}
if (Table[i].systid != UNUSED) {
if (noMoreParts)
return (-1);
if (!skip_verify[i] &&
((((diskaddr_t)lel(Table[i].relsect) +
lel(Table[i].numsect)) > dev_capacity) ||
(((diskaddr_t)lel(Table[i].relsect) +
lel(Table[i].numsect)) > DK_MAX_2TB))) {
return (-1);
}
}
return (numParts);
}
/*
* pars_fdisk
* Parse user-supplied data to set up fdisk partitions
* (-A, -D, -F).
*/
static int
pars_fdisk(
char *line,
int *id, int *act,
int *bhead, int *bsect, int *bcyl,
int *ehead, int *esect, int *ecyl,
uint32_t *rsect, uint32_t *numsect)
{
int i;
int64_t test;
char *tok, *p;
char buf[256];
if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
return (1);
line[strlen(line)] = '\0';
for (i = 0; i < strlen(line); i++) {
if (line[i] == '\0') {
break;
} else if (line[i] == ':') {
line[i] = ' ';
}
}
(void) strncpy(buf, line, 256);
errno = 0;
tok = strtok(buf, ": \t\n");
while (tok != NULL) {
for (p = tok; *p != '\0'; p++) {
if (!isdigit(*p)) {
(void) printf("Invalid input %s in line %s.\n",
tok, line);
exit(1);
}
}
test = strtoll(tok, (char **)NULL, 10);
if ((test < 0) || (test > 0xFFFFFFFF) || (errno != 0)) {
(void) printf("Invalid input %s in line %s.\n", tok,
line);
exit(1);
}
tok = strtok(NULL, ": \t\n");
}
if (sscanf(line, "%d %d %d %d %d %d %d %d %u %u",
id, act, bhead, bsect, bcyl, ehead, esect, ecyl,
rsect, numsect) != 10) {
(void) fprintf(stderr, "Syntax error:\n \"%s\".\n", line);
exit(1);
}
return (0);
}
/*
* validate_part
* Validate that a new partition does not start at sector 0. Only UNUSED
* partitions and previously existing partitions are allowed to start at 0.
*/
static int
validate_part(int id, uint32_t rsect, uint32_t numsect)
{
int i;
if ((id != UNUSED) && (rsect == 0)) {
for (i = 0; i < FD_NUMPART; i++) {
if ((Old_Table[i].systid == id) &&
(Old_Table[i].relsect == LE_32(rsect)) &&
(Old_Table[i].numsect == LE_32(numsect)))
return (0);
}
(void) fprintf(stderr,
"New partition cannot start at sector 0\n");
return (-1);
}
#ifdef i386
if (id > FDISK_MAX_VALID_PART_ID) {
(void) fprintf(stderr, "Invalid partition ID\n");
return (-1);
}
#endif
return (0);
}
/*
* stage0
* Print out interactive menu and process user input.
*/
static void
stage0(void)
{
#ifdef i386
int rval;
#endif
dispmenu();
for (;;) {
(void) printf(Q_LINE);
(void) printf("Enter Selection: ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
#ifdef i386
while (!((s[0] > '0') && (s[0] < '8') &&
((s[1] == '\0') || (s[1] == '\n')))) {
#else
while (!((s[0] > '0') && (s[0] < '7') &&
((s[1] == '\0') || (s[1] == '\n')))) {
#endif
(void) printf(E_LINE); /* Clear any previous error */
#ifdef i386
(void) printf(
"Enter a one-digit number between 1 and 7.");
#else
(void) printf(
"Enter a one-digit number between 1 and 6.");
#endif
(void) printf(Q_LINE);
(void) printf("Enter Selection: ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
}
(void) printf(E_LINE);
switch (s[0]) {
case '1':
if (pcreate() == -1)
return;
break;
case '2':
if (pchange() == -1)
return;
break;
case '3':
if (pdelete() == -1)
return;
break;
case '4':
if (ppartid() == -1)
return;
break;
#ifdef i386
case '5':
if (fdisk_ext_part_exists(epp)) {
ext_part_menu();
} else {
(void) printf(Q_LINE);
(void) printf("\nNo extended partition"
" found\n");
(void) printf("Press enter to "
"continue\n");
ext_read_input(s);
}
break;
case '6':
/* update disk partition table, if changed */
if (TableChanged() == 1) {
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
}
/*
* If the VTOC table is wrong fix it
* (truncate only)
*/
if (io_adjt) {
fix_slice();
}
if (!io_readonly) {
rval = fdisk_commit_ext_part(epp);
switch (rval) {
case FDISK_SUCCESS:
/* Success */
/* Fallthrough */
case FDISK_ENOEXTPART:
/* Nothing to do */
break;
case FDISK_EMOUNTED:
(void) printf(Q_LINE);
preach_and_continue();
continue;
default:
perror("Commit failed");
exit(1);
}
libfdisk_fini(&epp);