#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 "[1;1H[0J"
#define CLR_LIN "[0K"
#define HOME "[1;1H[0K[2;1H[0K[3;1H[0K[4;1H[0K[5;1H[0K" \
"[6;1H[0K[7;1H[0K[8;1H[0K[9;1H[0K[10;1H[0K[1;1H"
#define Q_LINE "[22;1H[0K[21;1H[0K[20;1H[0K"
#ifdef i386
#define W_LINE "[11;1H[0K"
#else
#define W_LINE "[12;1H[0K[11;1H[0K"
#endif
#define E_LINE "[24;1H[0K[23;1H[0K"
#ifdef i386
#define M_LINE "[12;1H[0K[13;1H[0K[14;1H[0K[15;1H[0K" \
"[16;1H[0K[17;1H[0K[18;1H[0K[19;1H[0K[12;1H"
#else
#define M_LINE "[13;1H[0K[14;1H[0K[15;1H[0K[16;1H[0K[17;1H" \
"[0K[18;1H[0K[19;1H[0K[13;1H"
#endif
#define T_LINE "[1;1H[0K"
#define DEFAULT_PATH "/dev/rdsk/"
#define DEFAULT_MASTER_BOOT_FILE "/boot/pmbr"
#define DK_MAX_2TB UINT32_MAX
#define OLD 0
#define NEW 1
#define VTOC_OK 0
#define VTOC_INVAL 1
#define VTOC_NOTSUP 2
#define VTOC_RWERR 3
#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
#define FDISK_MAX_VALID_CYL_NUM_DIGITS 10
#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[] = " ";
static char *Dfltdev;
static int io_wrt = 0;
static int io_rd = 0;
static char *io_fatt;
static int io_patt = 0;
static int io_lgeom = 0;
static int io_pgeom = 0;
static char *io_sgeom = 0;
static int io_readonly = 0;
static off_t io_offset = 0;
static off_t io_size = 0;
static int v_flag = 0;
static int stdo_flag = 0;
static int io_fdisk = 0;
static int io_ifdisk = 0;
static int io_nifdisk = 0;
static int io_adjt = 0;
static int io_ADJT = 0;
static char *io_ffdisk = 0;
static char *io_Wfdisk = 0;
static char *io_Afdisk = 0;
static char *io_Dfdisk = 0;
static char *io_mboot = 0;
static struct mboot BootCod;
static int io_wholedisk = 0;
static int io_EFIdisk = 0;
static int io_EFIslot = 0;
static int io_EFIactive = 0;
static int io_debug = 0;
static int io_image = 0;
static struct mboot *Bootblk;
static char *Bootsect;
static char *Nullsect;
static struct extvtoc disk_vtoc;
static int vt_inval = 0;
static int no_virtgeom_ioctl = 0;
static int no_physgeom_ioctl = 0;
static struct ipart Table[FD_NUMPART];
static struct ipart Old_Table[FD_NUMPART];
static int skip_verify[FD_NUMPART];
static struct dk_minfo minfo;
static struct dk_geom disk_geom;
static int Dev;
static diskaddr_t dev_capacity;
static diskaddr_t chs_capacity;
static int Numcyl_usable;
static int Numcyl;
static int heads;
static int sectors;
static int acyl;
static int hba_Numcyl;
static int hba_heads;
static int hba_sectors;
static int sectsiz;
#define LOADFILE 0
#define LOADDEL 1
#define LOADADD 2
#define CBUFLEN 80
static char s[CBUFLEN];
#ifdef i386
char *fdisk_part_types[] = {
"Empty",
"FAT12",
"XENIX /",
"XENIX /usr",
"FAT16 (Upto 32M)",
"DOS Extended",
"FAT16 (>32M, HUGEDOS)",
"IFS: NTFS",
"AIX Boot/QNX(qny)",
"AIX Data/QNX(qnz)",
"OS/2 Boot/Coherent swap",
"WIN95 FAT32(Upto 2047GB)",
"WIN95 FAT32(LBA)",
"Unused",
"WIN95 FAT16(LBA)",
"WIN95 Extended(LBA)",
"OPUS",
"Hidden FAT12",
"Diagnostic",
"Unknown",
"Hidden FAT16(Upto 32M)",
"Unknown",
"Hidden FAT16(>=32M)",
"Hidden IFS: HPFS",
"AST SmartSleep Partition",
"Unused/Willowtech Photon",
"Unknown",
"Hidden FAT32",
"Hidden FAT32(LBA)",
"Unused",
"Hidden FAT16(LBA)",
"Unknown",
"Unused/OSF1",
"Reserved/FSo2(Oxygen FS)",
"Unused/(Oxygen EXT)",
"Reserved",
"NEC DOS 3.x",
"Unknown",
"Reserved",
"Unknown",
"Unknown",
"Unknown",
"AtheOS File System",
"SyllableSecure",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Reserved",
"NOS",
"Reserved",
"Reserved",
"JFS on OS/2",
"Reserved",
"Unknown",
"THEOS 3.2 2GB",
"Plan9/THEOS 4",
"THEOS 4 4GB",
"THEOS 4 Extended",
"PartitionMagic Recovery",
"Hidden NetWare",
"Unknown",
"Unknown",
"Venix 80286",
"MINIX/PPC PReP Boot",
"Win2K Dynamic Disk/SFS(DOS)",
"Linux+DRDOS shared",
"GoBack partition",
"Boot-US boot manager",
"EUMEL/Elan",
"EUMEL/Elan",
"EUMEL/Elan",
"Unknown",
"ALFS/THIN FS for DOS",
"Unknown",
"Oberon partition",
"QNX 4,x",
"QNX 4,x 2nd Part",
"QNX 4,x 3rd Part",
"OnTrack DM R/O, Lynx RTOS",
"OnTrack DM R/W, Novell",
"CP/M",
"Disk Manager 6.0 Aux3",
"Disk Manager 6.0 DDO",
"EZ-Drive",
"Golden Bow VFeature/AT&T MS-DOS",
"DrivePro",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Priam EDisk",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"SpeedStor",
"Unknown",
"Unix SysV, Mach, GNU Hurd",
"PC-ARMOUR, Netware 286",
"Netware 386",
"Netware SMS",
"Novell",
"Novell",
"Netware NSS",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"DiskSecure Multi-Boot",
"Reserved",
"Unknown",
"Reserved",
"Scramdisk partition",
"IBM PC/IX",
"Reserved",
"M2FS/M2CS,Netware VNDI",
"XOSL FS",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unused",
"Unused",
"MINIX until 1.4a",
"MINIX since 1.4b, early Linux",
"Solaris/Linux swap",
"Linux native",
"OS/2 hidden,Win Hibernation",
"Linux extended",
"Old Linux RAID,NT FAT16 RAID",
"NTFS volume set",
"Linux plaintext part table",
"Unknown",
"Linux Kernel Partition",
"Fault Tolerant FAT32 volume",
"Fault Tolerant FAT32 volume",
"Free FDISK hidden PDOS FAT12",
"Linux LVM partition",
"Unknown",
"Free FDISK hidden PDOS FAT16",
"Free FDISK hidden DOS EXT",
"Free FDISK hidden FAT16 Large",
"Hidden Linux native, Amoeba",
"Amoeba Bad Block Table",
"MIT EXOPC Native",
"Unknown",
"Free FDISK hidden PDOS FAT32",
"Free FDISK hidden FAT32 LBA",
"DCE376 logical drive",
"Free FDISK hidden FAT16 LBA",
"Free FDISK hidden DOS EXT",
"Unknown",
"Unknown",
"Unknown",
"BSD/OS",
"Laptop hibernation",
"Laptop hibernate,HP SpeedStor",
"Unknown",
"HP SpeedStor",
"HP SpeedStor",
"BSD/386,386BSD,NetBSD,FreeBSD",
"OpenBSD,HP SpeedStor",
"NeXTStep",
"Mac OS-X",
"NetBSD",
"Olivetti FAT12 1.44MB Service",
"Mac OS-X Boot",
"Unknown",
"Unknown",
"ShagOS filesystem",
"ShagOS swap",
"BootStar Dummy",
"HP SpeedStor",
"Unknown",
"HP SpeedStor",
"HP SpeedStor",
"Unknown",
"Corrupted FAT16 NT Mirror Set",
"Corrupted NTFS NT Mirror Set",
"Old BSDI BSD/386 swap",
"Unknown",
"Unknown",
"Boot Wizard hidden",
"Unknown",
"Unknown",
"Solaris x86 boot",
"Solaris2",
"REAL/32 or Novell DOS secured",
"DRDOS/secured(FAT12)",
"Hidden Linux",
"Hidden Linux swap",
"DRDOS/secured(FAT16,< 32M)",
"DRDOS/secured(Extended)",
"NT corrupted FAT16 volume",
"NT corrupted NTFS volume",
"DRDOS8.0+",
"DRDOS8.0+",
"DRDOS8.0+",
"DRDOS7.04+ secured FAT32(CHS)",
"DRDOS7.04+ secured FAT32(LBA)",
"CTOS Memdump",
"DRDOS7.04+ FAT16X(LBA)",
"DRDOS7.04+ secure EXT DOS(LBA)",
"REAL/32 secure big, MDOS",
"Old MDOS secure FAT12",
"Unknown",
"Unknown",
"Old MDOS secure FAT16 <32M",
"Old MDOS secure EXT",
"Old MDOS secure FAT16 >=32M",
"Unknown",
"CP/M-86",
"Unknown",
"Non-FS Data",
"CP/M,Concurrent DOS,CTOS",
"Unknown",
"Hidden CTOS memdump",
"Dell PowerEdge utilities(FAT)",
"DG/UX virtual disk manager",
"ST AVFS(STMicroelectronics)",
"SpeedStor 12-bit FAT EXT",
"Unknown",
"SpeedStor",
"SpeedStor 16-bit FAT EXT",
"Tandy MSDOS",
"Storage Dimensions SpeedStor",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"BeOS BFS",
"SkyOS SkyFS",
"Unused",
"EFI Header Indicator",
"EFI Filesystem",
"Linux/PA-RISC boot loader",
"SpeedStor",
"DOS 3.3+ secondary",
"SpeedStor Reserved",
"SpeedStor Large",
"Prologue multi-volume",
"SpeedStor",
"Unused",
"Unknown",
"pCache",
"Bochs",
"VMware File System",
"VMware swap",
"Linux raid autodetect",
"NT Disk Administrator hidden",
"Xenix Bad Block Table"
};
static char ext_part_menu_opts[] = "adhipr";
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
#endif
static void
update_disk_and_exit(boolean_t table_changed)
{
#ifdef i386
int rval;
#endif
if (table_changed) {
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
}
if (io_adjt)
fix_slice();
#ifdef i386
if (!io_readonly) {
rval = fdisk_commit_ext_part(epp);
switch (rval) {
case FDISK_SUCCESS:
break;
case FDISK_ENOEXTPART:
break;
default:
(void) fprintf(stderr, "Error in"
" fdisk_commit_ext_part\n");
exit(rval);
}
}
libfdisk_fini(&epp);
#endif
exit(0);
}
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);
setbuf(stdout, 0);
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++;
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 (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);
case 'v':
v_flag = 1;
continue;
case '?':
errflg++;
break;
}
break;
}
if (io_image && io_sgeom && diag_cnt == 1) {
diag_cnt = 0;
}
if (!io_fdisk && !diag_cnt && !io_nifdisk) {
io_ifdisk++;
io_fdisk++;
}
if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
errflg++;
}
if (errflg || argc == optind) {
(void) fprintf(stderr, "%s\n", Usage);
(void) fprintf(stderr,
"\nDetailed help is available with the -h option.\n");
exit(2);
}
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);
}
if (ioctl(Dev, DKIOCGMEDIAINFO, &minfo)) {
(void) memset(&minfo, 0, sizeof (minfo));
}
if (!io_image) {
errno = 0;
if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) {
if (errno == ENOTTY) {
v_flag = 0;
no_virtgeom_ioctl = 1;
} else if (errno == EINVAL) {
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 {
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);
}
}
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 (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) {
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 (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);
}
}
chs_capacity = (diskaddr_t)Numcyl * heads * sectors;
dev_capacity = chs_capacity;
Numcyl_usable = Numcyl;
if (chs_capacity > DK_MAX_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;
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;
for (i = 0; i < sectsiz; i++) {
Nullsect[i] = 0;
}
if (io_rd) {
abs_read();
} else if (io_wrt && !io_readonly) {
abs_write();
} else if (io_patt && !io_readonly) {
fill_patt();
}
sanity_check_provided_device(Dfltdev, Dev);
mboot_read();
dev_mboot_read();
Bootblk = (struct mboot *)Bootsect;
copy_Bootblk_to_Table();
copy_Table_to_Old_Table();
#ifdef i386
if (!io_ffdisk) {
lf_op_flag |= FDISK_READ_DISK;
}
if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag))
!= FDISK_SUCCESS) {
switch (rval) {
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
if (io_ffdisk) {
load(LOADFILE, io_ffdisk);
}
if (io_Dfdisk) {
load(LOADDEL, io_Dfdisk);
}
if (io_Afdisk) {
load(LOADADD, io_Afdisk);
}
if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) {
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");
}
if (io_wholedisk ||(io_ifdisk && yesno())) {
nulltbl();
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;
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);
}
}
}
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);
}
}
if (io_ifdisk) {
(void) printf(CLR_SCR);
disptbl();
for (;;) {
stage0();
copy_Bootblk_to_Table();
disptbl();
}
}
if (io_Wfdisk)
ffile_write(io_Wfdisk);
else if (stdo_flag)
ffile_write((char *)stdout);
update_disk_and_exit(TableChanged() == 1);
return (0);
}
static int
read_geom(char *sgeom)
{
char line[256];
FILE *fp;
if ((fp = fopen(sgeom, "r")) == NULL) {
(void) fprintf(stderr, "fdisk: Cannot open file %s.\n",
io_sgeom);
return (1);
}
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,
§siz) != 7) {
(void) fprintf(stderr,
"Syntax error:\n \"%s\".\n",
line);
return (1);
}
break;
}
}
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);
}
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);
}
}
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);
}
}
for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
if (Table[new_pt].systid != SUNIXOS &&
Table[new_pt].systid != SUNIXOS2)
continue;
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
if ((Old_Table[old_pt].systid == SUNIXOS) ||
(Old_Table[old_pt].systid == SUNIXOS2)) {
if ((Old_Table[old_pt].relsect ==
Table[new_pt].relsect) &&
(Old_Table[old_pt].numsect ==
Table[new_pt].numsect))
break;
}
}
if (old_pt >= FD_NUMPART) {
if (io_debug) {
(void) fprintf(stderr,
"Clearing VTOC labels from NEW"
" table\n");
}
clear_vtoc(NEW, new_pt);
}
}
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
if (Old_Table[old_pt].systid == EFI_PMBR) {
clr_efi = old_pt;
}
}
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)) {
clr_efi = -1;
break;
}
}
if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
clr_efi = 0;
}
break;
}
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;
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);
}
}
static void
mboot_read(void)
{
int mDev, i;
struct ipart *part;
if (io_mboot == NULL) {
io_mboot = DEFAULT_MASTER_BOOT_FILE;
if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
return;
}
} else {
if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
(void) fprintf(stderr,
"fdisk: Cannot open master boot file '%s' : %s\n",
io_mboot, strerror(errno));
exit(1);
}
}
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);
}
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);
part = (struct ipart *)BootCod.parts;
for (i = 0; i < FD_NUMPART; i++, part++) {
(void) memset(part, 0, sizeof (struct ipart));
}
}
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;
}
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;
}
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);
}
}
}
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);
}
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);
}
}
}
exit(0);
}
static void
abs_write(void)
{
int c, i;
while (io_size--) {
int part_exit = 0;
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);
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);
}
}
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);
}
exit(1);
}
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:
nulltbl();
if ((fp = fopen(file, "r")) == NULL) {
(void) fprintf(stderr,
"fdisk: Cannot open prototype partition file %s.\n",
file);
exit(1);
}
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;
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) {
int offset = MAX_LOGDRIVE_OFFSET;
if (!ext_part_present) {
(void) fprintf(stderr,
"More than 4 primary"
" partitions found in input\n");
(void) fprintf(stderr, "Exiting...\n");
exit(1);
}
if (numsect == 0) {
continue;
}
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) {
if (rsect < offset) {
(void) fprintf(stderr,
"Minimum of "
"63 free sectors required "
"before the beginning of "
"a logical drive.");
exit(1);
}
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
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) {
startindex = tmpindex + 1;
continue;
}
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++;
}
if (verify_tbl() < 0) {
(void) fprintf(stderr,
"fdisk: Cannot create partition table\n");
exit(1);
}
(void) fclose(fp);
return;
case LOADDEL:
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);
}
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);
case LOADADD:
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);
}
if (rsect == 0) {
(void) fprintf(stderr,
"fdisk: New partition cannot start at sector 0:\n"
" \"%s\".\n",
file);
exit(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;
if (rsect < offset) {
return;
}
begsec = rsect - offset;
if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) {
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) {
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
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);
}
if (verify_tbl() < 0) {
(void) fprintf(stderr,
"fdisk: Cannot create partition \"%s\"\n", file);
exit(1);
}
}
}
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) {
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);
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);
}
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;
if (((diskaddr_t)rsect + numsect) > dev_capacity) {
(void) fprintf(stderr,
"fdisk: Partition table exceeds the size of the disk.\n");
return (-1);
}
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 (bcyl > MAX_CYL) {
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 {
Set_Table_CHS_Values(i);
}
return (i);
}
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)) {
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);
}
static int
verify_tbl(void)
{
uint32_t i, j, rsect, numsect;
int noMoreParts = 0;
int numParts = 0;
for (i = 0; i < FD_NUMPART - 1; i++) {
if (Table[i].systid != UNUSED) {
numParts++;
if (noMoreParts) {
return (-1);
}
if (Table[i].systid == EFI_PMBR) {
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);
}
}
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);
}
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);
}
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);
}
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);
#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':
if (TableChanged() == 1) {
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
}
if (io_adjt) {
fix_slice();
}
if (!io_readonly) {
rval = fdisk_commit_ext_part(epp);
switch (rval) {
case FDISK_SUCCESS:
case FDISK_ENOEXTPART:
break;
case FDISK_EMOUNTED:
(void) printf(Q_LINE);
preach_and_continue();
continue;
default:
perror("Commit failed");
exit(1);
}
libfdisk_fini(&epp);
}
(void) close(Dev);
exit(0);
#else
case '5':
if (TableChanged() == 1) {
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
}
if (io_adjt) {
fix_slice();
}
(void) close(Dev);
exit(0);
#endif
#ifdef i386
case '7':
#else
case '6':
#endif
if (io_adjt) {
fix_slice();
}
(void) close(Dev);
exit(0);
default:
break;
}
copy_Table_to_Bootblk();
disptbl();
dispmenu();
}
}
static int
pcreate(void)
{
uchar_t tsystid = 'z';
int i, j;
uint32_t numsect;
int retCode = 0;
#ifdef i386
int ext_part_present = 0;
#endif
i = 0;
for (;;) {
if (i == FD_NUMPART) {
(void) printf(E_LINE);
(void) printf(
"The partition table is full!\n"
"You must delete a partition before creating"
" a new one.\n");
return (-1);
}
if (Table[i].systid == UNUSED) {
break;
}
i++;
}
numsect = 0;
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid != UNUSED) {
numsect += LE_32(Table[i].numsect);
}
#ifdef i386
if (fdisk_is_dos_extended(Table[i].systid)) {
ext_part_present = 1;
}
#endif
if (numsect >= chs_capacity) {
(void) printf(E_LINE);
(void) printf("There is no more room on the disk for"
" another partition.\n");
(void) printf(
"You must delete a partition before creating"
" a new one.\n");
return (-1);
}
}
while (tsystid == 'z') {
(void) printf(W_LINE);
(void) printf(Q_LINE);
(void) printf(
"Select the partition type to create:\n"
" 1=SOLARIS2 2=UNIX 3=PCIXOS 4=Other\n"
" 5=DOS12 6=DOS16 7=DOSEXT 8=DOSBIG\n"
" 9=DOS16LBA A=x86 Boot B=Diagnostic C=FAT32\n"
" D=FAT32LBA E=DOSEXTLBA F=EFI 0=Exit? ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
if ((s[1] != '\0') && (s[1] != '\n')) {
(void) printf(E_LINE);
(void) printf("Invalid selection, try again.");
continue;
}
switch (s[0]) {
case '0':
(void) printf(E_LINE);
return (-1);
case '1':
tsystid = SUNIXOS2;
break;
case '2':
tsystid = UNIXOS;
break;
case '3':
tsystid = PCIXOS;
break;
case '4':
tsystid = OTHEROS;
break;
case '5':
tsystid = DOSOS12;
break;
case '6':
tsystid = DOSOS16;
break;
case '7':
#ifdef i386
if (ext_part_present) {
(void) printf(Q_LINE);
(void) printf(E_LINE);
(void) fprintf(stderr,
"Extended partition already exists\n");
(void) fprintf(stderr,
"Press enter to continue\n");
ext_read_input(s);
continue;
}
#endif
tsystid = EXTDOS;
break;
case '8':
tsystid = DOSHUGE;
break;
case '9':
tsystid = FDISK_FAT95;
break;
case 'a':
case 'A':
tsystid = X86BOOT;
break;
case 'b':
case 'B':
tsystid = DIAGPART;
break;
case 'c':
case 'C':
tsystid = FDISK_WINDOWS;
break;
case 'd':
case 'D':
tsystid = FDISK_EXT_WIN;
break;
case 'e':
case 'E':
#ifdef i386
if (ext_part_present) {
(void) printf(Q_LINE);
(void) printf(E_LINE);
(void) fprintf(stderr,
"Extended partition already exists\n");
(void) fprintf(stderr,
"Press enter to continue\n");
ext_read_input(s);
continue;
}
#endif
tsystid = FDISK_EXTLBA;
break;
case 'f':
case 'F':
tsystid = EFI_PMBR;
break;
default:
(void) printf(E_LINE);
(void) printf("Invalid selection, try again.");
continue;
}
}
(void) printf(E_LINE);
if (tsystid != EFI_PMBR) {
(void) printf(W_LINE);
if ((dev_capacity > DK_MAX_2TB))
(void) printf("WARNING: Disk is larger than 2 TB. "
"Upper limit is 2 TB for non-EFI partition ID\n");
i = specify(tsystid);
if (i != -1) {
(void) printf(E_LINE);
(void) printf(Q_LINE);
(void) printf(
"Should this become the active partition? If "
"yes, it will be activated\n"
"each time the computer is reset or turned on.\n"
"Please type \"y\" or \"n\". ");
if (yesno()) {
(void) printf(E_LINE);
for (j = 0; j < FD_NUMPART; j++) {
if (j == i) {
Table[j].bootid = ACTIVE;
(void) printf(E_LINE);
(void) printf(
"Partition %d is now "
"the active partition.",
j + 1);
} else {
Table[j].bootid = 0;
}
}
} else {
Table[i].bootid = 0;
}
#ifdef i386
if (fdisk_is_dos_extended(Table[i].systid)) {
(void) fdisk_init_ext_part(epp,
LE_32(Table[i].relsect),
LE_32(Table[i].numsect));
}
#endif
i = 1;
}
} else {
retCode = verify_tbl();
if (retCode < 0) {
(void) fprintf(stderr,
"fdisk: Cannot create EFI partition table; \n"
"current partition table is invalid.\n");
return (-1);
} else if (retCode > 0) {
(void) printf(
"An EFI partition must be the only partition on "
"disk. You may manually delete existing\n"
"partitions, or fdisk can do it.\n"
"Do you want fdisk to destroy existing "
"partitions?\n"
"Please type \"y\" or \"n\". ");
if (yesno()) {
nulltbl();
} else {
return (-1);
}
}
i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, 1,
(dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB:
(dev_capacity - 1), 0);
if (i != 0) {
(void) printf("Error creating EFI partition!!!\n");
i = -1;
} else {
Table[i].bootid = 0;
i = 1;
}
}
return (i);
}
static int
specify(uchar_t tsystid)
{
int i, j, percent = -1;
int cyl, cylen;
diskaddr_t first_free, size_free;
diskaddr_t max_free;
int cyl_size;
struct ipart *partition[FD_NUMPART];
struct ipart localpart[FD_NUMPART];
cyl_size = heads * sectors;
for (i = 0, j = 0; i < FD_NUMPART; i++) {
if (Table[i].systid != UNUSED) {
localpart[j] = Table[i];
j++;
}
}
while (j < FD_NUMPART) {
(void) memset(&localpart[j], 0, sizeof (struct ipart));
j++;
}
for (i = 0; i < FD_NUMPART; i++)
partition[i] = &localpart[i];
for (i = 0; i < FD_NUMPART - 1; i++) {
if (partition[i]->systid == UNUSED)
break;
for (j = i + 1; j < FD_NUMPART; j++) {
if (partition[j]->systid == UNUSED)
break;
if (LE_32(partition[j]->relsect) <
LE_32(partition[i]->relsect)) {
struct ipart *temp = partition[i];
partition[i] = partition[j];
partition[j] = temp;
}
}
}
(void) printf(Q_LINE);
(void) printf(
"Specify the percentage of disk to use for this partition\n"
"(or type \"c\" to specify the size in cylinders). ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
if (s[0] != 'c') {
i = 0;
while ((s[i] != '\0') && (s[i] != '\n')) {
if (s[i] < '0' || s[i] > '9') {
(void) printf(E_LINE);
(void) printf("Invalid percentage value "
"specified; retry the operation.");
return (-1);
}
i++;
if (i > 3) {
(void) printf(E_LINE);
(void) printf("Invalid percentage value "
"specified; retry the operation.");
return (-1);
}
}
if ((percent = atoi(s)) > 100) {
(void) printf(E_LINE);
(void) printf(
"Percentage value is too large. The value must be"
" between 1 and 100;\nretry the operation.\n");
return (-1);
}
if (percent < 1) {
(void) printf(E_LINE);
(void) printf(
"Percentage value is too small. The value must be"
" between 1 and 100;\nretry the operation.\n");
return (-1);
}
if (percent == 100)
cylen = Numcyl_usable - 1;
else
cylen = (Numcyl_usable * percent) / 100;
if ((tsystid == DOSOS12) &&
((long)((long)cylen * cyl_size) > MAXDOS)) {
int n;
n = MAXDOS * 100 / (int)(cyl_size) / Numcyl_usable;
(void) printf(E_LINE);
(void) printf("Maximum size for a DOS partition "
"is %d%%; retry the operation.",
n <= 100 ? n : 100);
return (-1);
}
max_free = 0;
for (i = 0; i < FD_NUMPART; i++) {
if (i) {
first_free = LE_32(partition[i - 1]->relsect) +
LE_32(partition[i - 1]->numsect);
} else {
first_free = cyl_size;
}
if (partition[i]->systid == UNUSED) {
size_free = chs_capacity - first_free;
} else {
size_free =
(LE_32(partition[i]->relsect > first_free))
? (LE_32(partition[i]->relsect) -
first_free) : 0;
}
if (max_free < size_free)
max_free = size_free;
if (((uint64_t)cylen * cyl_size) <= size_free) {
break;
}
if (partition[i]->systid == UNUSED) {
(void) printf(E_LINE);
max_free /= (cyl_size);
(void) fprintf(stderr, "fdisk: "
"Maximum percentage available is %lld\n",
100 * max_free / Numcyl_usable);
return (-1);
}
}
(void) printf(E_LINE);
if (i >= FD_NUMPART) {
(void) fprintf(stderr,
"fdisk: Partition table is full.\n");
return (-1);
}
if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
first_free, cylen * cyl_size, 0)) >= 0) {
return (i);
}
return (-1);
} else {
(void) printf(E_LINE);
(void) printf(Q_LINE);
(void) printf("Enter starting cylinder number: ");
if ((cyl = getcyl()) == -1) {
(void) printf(E_LINE);
(void) printf("Invalid number; retry the operation.");
return (-1);
}
if (cyl == 0) {
(void) printf(E_LINE);
(void) printf(
"New partition cannot start at cylinder 0.\n");
return (-1);
}
if (cyl >= Numcyl_usable) {
(void) printf(E_LINE);
(void) printf(
"Cylinder %d is out of bounds, "
"the maximum is %d.\n",
cyl, Numcyl_usable - 1);
return (-1);
}
(void) printf(Q_LINE);
(void) printf("Enter partition size in cylinders: ");
if ((cylen = getcyl()) == -1) {
(void) printf(E_LINE);
(void) printf("Invalid number, retry the operation.");
return (-1);
}
for (i = 0; i < FD_NUMPART; i++) {
uint32_t t_relsect, t_numsect;
if (partition[i]->systid == UNUSED)
break;
t_relsect = LE_32(partition[i]->relsect);
t_numsect = LE_32(partition[i]->numsect);
if (cyl * cyl_size >= t_relsect &&
cyl * cyl_size < t_relsect + t_numsect) {
(void) printf(E_LINE);
(void) printf(
"Cylinder %d is already allocated"
"\nretry the operation.",
cyl);
return (-1);
}
if (cyl * cyl_size < t_relsect &&
(cyl + cylen - 1) * cyl_size > t_relsect) {
(void) printf(E_LINE);
(void) printf(
"Maximum size for partition is %u cylinders"
"\nretry the operation.",
(t_relsect - cyl * cyl_size) / cyl_size);
return (-1);
}
}
if (cyl + cylen > Numcyl_usable) {
(void) printf(E_LINE);
if (Numcyl > Numcyl_usable) {
(void) printf(
"Maximum size for partition is %d "
"cylinders; \nretry the operation.",
Numcyl_usable - cyl);
} else {
(void) printf(
"Maximum size for partition is %d "
"cylinders; \nretry the operation.",
Numcyl_usable - cyl);
}
return (-1);
}
if ((tsystid == DOSOS12) &&
((long)((long)cylen * cyl_size) > MAXDOS)) {
(void) printf(E_LINE);
(void) printf(
"Maximum size for a %s partition is %ld cylinders;"
"\nretry the operation.",
Dstr, MAXDOS / (int)(cyl_size));
return (-1);
}
(void) printf(E_LINE);
i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
cyl * cyl_size, cylen * cyl_size, 0);
if (i < 0)
return (-1);
if (verify_tbl() < 0) {
(void) printf(E_LINE);
(void) printf("fdisk: Cannot create partition table\n");
return (-1);
}
return (i);
}
}
static void
dispmenu(void)
{
(void) printf(M_LINE);
#ifdef i386
(void) printf(
"SELECT ONE OF THE FOLLOWING:\n"
" 1. Create a partition\n"
" 2. Specify the active partition\n"
" 3. Delete a partition\n"
" 4. Change between Solaris and Solaris2 Partition IDs\n"
" 5. Edit/View extended partitions\n"
" 6. Exit (update disk configuration and exit)\n"
" 7. Cancel (exit without updating disk configuration)\n");
#else
(void) printf(
"SELECT ONE OF THE FOLLOWING:\n"
" 1. Create a partition\n"
" 2. Specify the active partition\n"
" 3. Delete a partition\n"
" 4. Change between Solaris and Solaris2 Partition IDs\n"
" 5. Exit (update disk configuration and exit)\n"
" 6. Cancel (exit without updating disk configuration)\n");
#endif
}
static int
pchange(void)
{
char s[80];
int i, j;
for (;;) {
(void) printf(Q_LINE);
{
(void) printf(
"Specify the partition number to boot from"
" (or specify 0 for none): ");
}
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
if (((s[1] != '\0') && (s[1] != '\n')) ||
(s[0] < '0') || (s[0] > '4')) {
(void) printf(E_LINE);
(void) printf(
"Invalid response, please specify a number"
" between 0 and 4.\n");
} else {
break;
}
}
if (s[0] == '0') {
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid != UNUSED &&
Table[i].bootid == ACTIVE)
Table[i].bootid = 0;
}
(void) printf(E_LINE);
(void) printf(
"No partition is currently marked as active.");
return (0);
} else {
i = s[0] - '1';
if (Table[i].systid == UNUSED) {
(void) printf(E_LINE);
(void) printf("Partition does not exist.");
return (-1);
}
else if ((Table[i].systid == DOSDATA) ||
(Table[i].systid == EXTDOS) ||
(Table[i].systid == FDISK_EXTLBA)) {
(void) printf(E_LINE);
(void) printf(
"DOS-DATA, EXT_DOS and EXT_DOS_LBA partitions "
"cannot be made active.\n");
(void) printf("Select another partition.");
return (-1);
}
Table[i].bootid = ACTIVE;
for (j = 0; j < FD_NUMPART; j++) {
if (j != i)
Table[j].bootid = 0;
}
}
(void) printf(E_LINE);
{
(void) printf(
"Partition %d is now active. The system will start up"
" from this\n", i + 1);
(void) printf("partition after the next reboot.");
}
return (1);
}
static int
ppartid(void)
{
char *p, s[80];
int i;
for (;;) {
(void) printf(Q_LINE);
(void) printf("Specify the partition number to change"
" (or enter 0 to exit): ");
if (!fgets(s, sizeof (s), stdin))
return (1);
i = strtol(s, &p, 10);
if (*p != '\n' || i < 0 || i > FD_NUMPART) {
(void) printf(E_LINE);
(void) printf(
"Invalid response, retry the operation.\n");
continue;
}
if (i == 0) {
(void) printf(E_LINE);
return (1);
}
i -= 1;
if (Table[i].systid == SUNIXOS) {
Table[i].systid = SUNIXOS2;
} else if (Table[i].systid == SUNIXOS2) {
Table[i].systid = SUNIXOS;
} else {
(void) printf(E_LINE);
(void) printf(
"Partition %d is not a Solaris partition.",
i + 1);
continue;
}
(void) printf(E_LINE);
(void) printf("Partition %d has been changed.", i + 1);
return (1);
}
}
static char
pdelete(void)
{
char s[80];
int i;
char pactive;
DEL1: (void) printf(Q_LINE);
(void) printf("Specify the partition number to delete"
" (or enter 0 to exit): ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
if ((s[0] == '0')) {
(void) printf(E_LINE);
return (1);
}
if (((s[1] != '\0') && (s[1] != '\n')) ||
(i = atoi(s)) < 1 || i > FD_NUMPART) {
(void) printf(E_LINE);
(void) printf("Invalid response, retry the operation.\n");
goto DEL1;
} else {
--i;
}
if (Table[i].systid == UNUSED) {
(void) printf(E_LINE);
(void) printf("Partition %d does not exist.", i + 1);
return (-1);
}
#ifdef i386
if (fdisk_is_dos_extended(Table[i].systid) &&
(Table[i].relsect == fdisk_get_ext_beg_sec(epp)) &&
fdisk_get_logical_drive_count(epp)) {
(void) printf(Q_LINE);
(void) printf("There are logical drives inside the"
" extended partition\n");
(void) printf("Are you sure of proceeding with deletion ?"
" (type \"y\" or \"n\") ");
(void) printf(E_LINE);
if (! yesno()) {
return (1);
}
if (fdisk_mounted_logical_drives(epp) == FDISK_EMOUNTED) {
(void) printf(Q_LINE);
(void) printf("There are mounted logical drives. "
"Committing changes now can cause data loss or "
"corruption. Unmount all logical drives and then "
"try committing the changes again.\n");
(void) printf("Press enter to continue.\n");
ext_read_input(s);
return (1);
}
(void) fdisk_delete_ext_part(epp);
} else {
#endif
(void) printf(Q_LINE);
(void) printf("Are you sure you want to delete partition %d?"
" This will make all files and \n", i + 1);
(void) printf("programs in this partition inaccessible (type"
" \"y\" or \"n\"). ");
(void) printf(E_LINE);
if (! yesno()) {
return (1);
}
#ifdef i386
}
#endif
if (Table[i].bootid == ACTIVE) {
pactive = 1;
} else {
pactive = 0;
}
(void) memset(&Table[i], 0, sizeof (struct ipart));
(void) printf(E_LINE);
(void) printf("Partition %d has been deleted.", i + 1);
if (pactive) {
(void) printf(" This was the active partition.");
}
return (1);
}
static void
rm_blanks(char *s)
{
register int i, j;
for (i = 0; i < CBUFLEN; i++) {
if ((s[i] == ' ') || (s[i] == '\t')) {
continue;
} else {
break;
}
}
for (j = 0; i < CBUFLEN; j++, i++) {
if ((s[j] = s[i]) == '\0') {
return;
}
}
}
static int
getcyl(void)
{
int slen, i, j;
unsigned int cyl;
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
slen = strlen(s);
if (s[slen - 1] == '\n')
slen--;
j = 1;
cyl = 0;
for (i = slen - 1; i >= 0; i--) {
if (s[i] < '0' || s[i] > '9') {
return (-1);
}
cyl += (j * (s[i] - '0'));
j *= 10;
}
return (cyl);
}
static void
disptbl(void)
{
int i;
unsigned int startcyl, endcyl, length, percent, remainder;
char *stat, *type;
int is_pmbr = 0;
if ((heads == 0) || (sectors == 0)) {
(void) printf("WARNING: critical disk geometry information"
" missing!\n");
(void) printf("\theads = %d, sectors = %d\n", heads, sectors);
exit(1);
}
(void) printf(HOME);
(void) printf(T_LINE);
(void) printf(" Total disk size is %d cylinders\n", Numcyl);
(void) printf(" Cylinder size is %d (%d byte) blocks\n\n",
heads * sectors, sectsiz);
(void) printf(
" Cylinders\n");
(void) printf(
" Partition Status Type Start End Length"
" %%\n");
(void) printf(
" ========= ====== ============ ===== === ======"
" ===");
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid == UNUSED) {
continue;
}
if (Table[i].bootid == ACTIVE)
stat = Actvstr;
else
stat = NAstr;
switch (Table[i].systid) {
case UNIXOS:
type = Ustr;
break;
case SUNIXOS:
type = SUstr;
#ifdef i386
if (fdisk_is_linux_swap(epp, Table[i].relsect,
NULL) == 0)
type = LINSWAPstr;
#endif
break;
case SUNIXOS2:
type = SU2str;
break;
case X86BOOT:
type = X86str;
break;
case DOSOS12:
type = Dstr;
break;
case DOSOS16:
type = D16str;
break;
case EXTDOS:
type = EDstr;
break;
case DOSDATA:
type = DDstr;
break;
case DOSHUGE:
type = DBstr;
break;
case PCIXOS:
type = PCstr;
break;
case DIAGPART:
type = DIAGstr;
break;
case FDISK_IFS:
type = IFSstr;
break;
case FDISK_AIXBOOT:
type = AIXstr;
break;
case FDISK_AIXDATA:
type = AIXDstr;
break;
case FDISK_OS2BOOT:
type = OS2str;
break;
case FDISK_WINDOWS:
type = WINstr;
break;
case FDISK_EXT_WIN:
type = EWINstr;
break;
case FDISK_FAT95:
type = FAT95str;
break;
case FDISK_EXTLBA:
type = EXTLstr;
break;
case FDISK_LINUX:
type = LINUXstr;
break;
case FDISK_CPM:
type = CPMstr;
break;
case FDISK_NOVELL2:
type = NOV2str;
break;
case FDISK_NOVELL3:
type = NOVstr;
break;
case FDISK_QNX4:
type = QNXstr;
break;
case FDISK_QNX42:
type = QNX2str;
break;
case FDISK_QNX43:
type = QNX3str;
break;
case FDISK_LINUXNAT:
type = LINNATstr;
break;
case FDISK_NTFSVOL1:
type = NTFSVOL1str;
break;
case FDISK_NTFSVOL2:
type = NTFSVOL2str;
break;
case FDISK_BSD:
type = BSDstr;
break;
case FDISK_NEXTSTEP:
type = NEXTSTEPstr;
break;
case FDISK_BSDIFS:
type = BSDIFSstr;
break;
case FDISK_BSDISWAP:
type = BSDISWAPstr;
break;
case EFI_PMBR:
type = EFIstr;
if (LE_32(Table[i].numsect) == DK_MAX_2TB)
is_pmbr = 1;
break;
default:
type = Ostr;
break;
}
startcyl = LE_32(Table[i].relsect) /
(unsigned long)(heads * sectors);
if (LE_32(Table[i].numsect) == DK_MAX_2TB) {
endcyl = Numcyl - 1;
length = endcyl - startcyl + 1;
} else {
length = LE_32(Table[i].numsect) /
(unsigned long)(heads * sectors);
if (LE_32(Table[i].numsect) %
(unsigned long)(heads * sectors))
length++;
endcyl = startcyl + length - 1;
}
percent = length * 100 / Numcyl_usable;
if ((remainder = (length * 100 % Numcyl_usable)) != 0) {
if ((remainder * 100 / Numcyl_usable) > 50) {
percent++;
}
}
if (percent > 100)
percent = 100;
(void) printf(
"\n %d %s %-12.12s %4d %4d %4d"
" %3d",
i + 1, stat, type, startcyl, endcyl, length, percent);
}
if (nopartdefined()) {
(void) printf(W_LINE);
(void) printf("WARNING: no partitions are defined!");
} else {
(void) printf(W_LINE);
if (!is_pmbr && (dev_capacity > DK_MAX_2TB))
(void) printf("WARNING: Disk is larger than 2 TB. "
"Upper limit is 2 TB for non-EFI partition ID\n");
}
}
static void
print_Table(void)
{
int i;
(void) fprintf(stderr,
" SYSID ACT BHEAD BSECT BEGCYL EHEAD ESECT ENDCYL RELSECT"
" NUMSECT\n");
for (i = 0; i < FD_NUMPART; i++) {
(void) fprintf(stderr, " %-5d ", Table[i].systid);
(void) fprintf(stderr, "%-3d ", Table[i].bootid);
(void) fprintf(stderr, "%-5d ", Table[i].beghead);
(void) fprintf(stderr, "%-5d ", Table[i].begsect & 0x3f);
(void) fprintf(stderr, "%-8d ",
(((uint_t)Table[i].begsect & 0xc0) << 2) + Table[i].begcyl);
(void) fprintf(stderr, "%-5d ", Table[i].endhead);
(void) fprintf(stderr, "%-5d ", Table[i].endsect & 0x3f);
(void) fprintf(stderr, "%-8d ",
(((uint_t)Table[i].endsect & 0xc0) << 2) + Table[i].endcyl);
(void) fprintf(stderr, "%-10u ", LE_32(Table[i].relsect));
(void) fprintf(stderr, "%-10u\n", LE_32(Table[i].numsect));
}
}
static void
copy_Table_to_Old_Table(void)
{
int i;
for (i = 0; i < FD_NUMPART; i++) {
(void) memcpy(&Old_Table[i], &Table[i], sizeof (Table[0]));
}
}
static void
nulltbl(void)
{
int i;
for (i = 0; i < FD_NUMPART; i++) {
Table[i].systid = UNUSED;
Table[i].numsect = LE_32(UNUSED);
Table[i].relsect = LE_32(UNUSED);
Table[i].bootid = 0;
skip_verify[i] = 0;
}
}
static void
copy_Bootblk_to_Table(void)
{
int i;
char *bootptr;
struct ipart iparts[FD_NUMPART];
(void) memcpy(iparts, Bootblk->parts, sizeof (iparts));
bootptr = (char *)iparts;
if (LE_16(Bootblk->signature) != MBB_MAGIC) {
nulltbl();
(void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
return;
}
for (i = 0; i < FD_NUMPART; i++) {
if (iparts[i].systid == 0) {
(void) memset(&Table[i], 0, sizeof (struct ipart));
} else {
fill_ipart(bootptr, &Table[i]);
}
bootptr += sizeof (struct ipart);
}
(void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
copy_Table_to_Bootblk();
}
static void
fill_ipart(char *bootptr, struct ipart *partp)
{
#ifdef sparc
partp->bootid = getbyte(&bootptr);
partp->beghead = getbyte(&bootptr);
partp->begsect = getbyte(&bootptr);
partp->begcyl = getbyte(&bootptr);
partp->systid = getbyte(&bootptr);
partp->endhead = getbyte(&bootptr);
partp->endsect = getbyte(&bootptr);
partp->endcyl = getbyte(&bootptr);
partp->relsect = (int32_t)getlong(&bootptr);
partp->numsect = (int32_t)getlong(&bootptr);
#else
*partp = *(struct ipart *)bootptr;
#endif
}
#ifdef sparc
uchar_t
getbyte(char **bp)
{
uchar_t b;
b = (uchar_t)**bp;
*bp = *bp + 1;
return (b);
}
uint32_t
getlong(char **bp)
{
int32_t b, bh, bl;
bh = ((**bp) << 8) | *(*bp + 1);
*bp += 2;
bl = ((**bp) << 8) | *(*bp + 1);
*bp += 2;
b = (bh << 16) | bl;
return ((uint32_t)b);
}
#endif
static void
copy_Table_to_Bootblk(void)
{
struct ipart *boot_ptr, *tbl_ptr;
boot_ptr = (struct ipart *)Bootblk->parts;
tbl_ptr = (struct ipart *)&Table[0].bootid;
for (; tbl_ptr < (struct ipart *)&Table[FD_NUMPART].bootid;
tbl_ptr++, boot_ptr++) {
if (tbl_ptr->systid == UNUSED)
(void) memset(boot_ptr, 0, sizeof (struct ipart));
else
(void) memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart));
}
Bootblk->signature = LE_16(MBB_MAGIC);
}
static int
TableChanged(void)
{
int i, changed;
changed = 0;
for (i = 0; i < FD_NUMPART; i++) {
if (memcmp(&Old_Table[i], &Table[i], sizeof (Table[0])) != 0) {
changed = 1;
}
}
return (changed);
}
static void
ffile_write(char *file)
{
register int i;
FILE *fp;
if (file != (char *)stdout) {
if ((fp = fopen(file, "w")) == NULL) {
(void) fprintf(stderr,
"fdisk: Cannot open output file %s.\n",
file);
exit(1);
}
}
else
fp = stdout;
(void) fprintf(fp, "\n* %s default fdisk table\n", Dfltdev);
(void) fprintf(fp, "* Dimensions:\n");
(void) fprintf(fp, "* %4d bytes/sector\n", sectsiz);
(void) fprintf(fp, "* %4d sectors/track\n", sectors);
(void) fprintf(fp, "* %4d tracks/cylinder\n", heads);
(void) fprintf(fp, "* %4d cylinders\n", Numcyl);
(void) fprintf(fp, "*\n");
if (v_flag) {
(void) fprintf(fp, "* HBA Dimensions:\n");
(void) fprintf(fp, "* %4d bytes/sector\n", sectsiz);
(void) fprintf(fp, "* %4d sectors/track\n", hba_sectors);
(void) fprintf(fp, "* %4d tracks/cylinder\n", hba_heads);
(void) fprintf(fp, "* %4d cylinders\n", hba_Numcyl);
(void) fprintf(fp, "*\n");
}
(void) fprintf(fp, "* systid:\n");
(void) fprintf(fp, "* 1: DOSOS12\n");
(void) fprintf(fp, "* 2: PCIXOS\n");
(void) fprintf(fp, "* 4: DOSOS16\n");
(void) fprintf(fp, "* 5: EXTDOS\n");
(void) fprintf(fp, "* 6: DOSBIG\n");
(void) fprintf(fp, "* 7: FDISK_IFS\n");
(void) fprintf(fp, "* 8: FDISK_AIXBOOT\n");
(void) fprintf(fp, "* 9: FDISK_AIXDATA\n");
(void) fprintf(fp, "* 10: FDISK_0S2BOOT\n");
(void) fprintf(fp, "* 11: FDISK_WINDOWS\n");
(void) fprintf(fp, "* 12: FDISK_EXT_WIN\n");
(void) fprintf(fp, "* 14: FDISK_FAT95\n");
(void) fprintf(fp, "* 15: FDISK_EXTLBA\n");
(void) fprintf(fp, "* 18: DIAGPART\n");
(void) fprintf(fp, "* 65: FDISK_LINUX\n");
(void) fprintf(fp, "* 82: FDISK_CPM\n");
(void) fprintf(fp, "* 86: DOSDATA\n");
(void) fprintf(fp, "* 98: OTHEROS\n");
(void) fprintf(fp, "* 99: UNIXOS\n");
(void) fprintf(fp, "* 100: FDISK_NOVELL2\n");
(void) fprintf(fp, "* 101: FDISK_NOVELL3\n");
(void) fprintf(fp, "* 119: FDISK_QNX4\n");
(void) fprintf(fp, "* 120: FDISK_QNX42\n");
(void) fprintf(fp, "* 121: FDISK_QNX43\n");
(void) fprintf(fp, "* 130: SUNIXOS\n");
(void) fprintf(fp, "* 131: FDISK_LINUXNAT\n");
(void) fprintf(fp, "* 134: FDISK_NTFSVOL1\n");
(void) fprintf(fp, "* 135: FDISK_NTFSVOL2\n");
(void) fprintf(fp, "* 165: FDISK_BSD\n");
(void) fprintf(fp, "* 167: FDISK_NEXTSTEP\n");
(void) fprintf(fp, "* 183: FDISK_BSDIFS\n");
(void) fprintf(fp, "* 184: FDISK_BSDISWAP\n");
(void) fprintf(fp, "* 190: X86BOOT\n");
(void) fprintf(fp, "* 191: SUNIXOS2\n");
(void) fprintf(fp, "* 238: EFI_PMBR\n");
(void) fprintf(fp, "* 239: EFI_FS\n");
(void) fprintf(fp, "*\n");
(void) fprintf(fp,
"\n* Id Act Bhead Bsect Bcyl Ehead Esect Ecyl"
" Rsect Numsect\n");
for (i = 0; i < FD_NUMPART; i++) {
(void) fprintf(fp,
" %-5d %-4d %-6d %-6d %-7d %-6d %-6d %-7d %-10u"
" %-10u\n",
Table[i].systid,
Table[i].bootid,
Table[i].beghead,
Table[i].begsect & 0x3f,
((Table[i].begcyl & 0xff) | ((Table[i].begsect &
0xc0) << 2)),
Table[i].endhead,
Table[i].endsect & 0x3f,
((Table[i].endcyl & 0xff) | ((Table[i].endsect &
0xc0) << 2)),
LE_32(Table[i].relsect),
LE_32(Table[i].numsect));
}
#ifdef i386
if (fdisk_ext_part_exists(epp)) {
struct ipart ext_tab;
logical_drive_t *temp;
uint32_t rsect, numsect, tempsect = 0;
for (temp = fdisk_get_ld_head(epp); temp != NULL;
temp = temp->next) {
ext_tab = temp->parts[0];
rsect = tempsect + LE_32(ext_tab.relsect) +
fdisk_get_ext_beg_sec(epp);
numsect = LE_32(ext_tab.numsect);
tempsect = LE_32(temp->parts[1].relsect);
(void) fprintf(fp,
" %-5d %-4d %-6d %-6d %-7d %-6d %-6d "
"%-7d %-8u %-8u\n",
ext_tab.systid,
ext_tab.bootid,
ext_tab.beghead,
ext_tab.begsect & 0x3f,
((ext_tab.begcyl & 0xff) |
((ext_tab.begsect & 0xc0) << 2)),
ext_tab.endhead,
ext_tab.endsect & 0x3f,
((ext_tab.endcyl & 0xff) |
((ext_tab.endsect & 0xc0) << 2)),
rsect,
numsect);
}
}
#endif
if (fp != stdout)
(void) fclose(fp);
}
static void
fix_slice(void)
{
int i;
uint32_t numsect;
if (io_image) {
return;
}
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) {
numsect = LE_32(Table[i].numsect);
break;
}
}
if (i >= FD_NUMPART) {
if (!io_nifdisk) {
(void) fprintf(stderr,
"fdisk: No Solaris partition found - VTOC not"
" checked.\n");
}
return;
}
if (readvtoc() != VTOC_OK) {
exit(1);
}
for (i = 0; i < V_NUMPAR; i++) {
if (i == 2) {
if (disk_vtoc.v_part[i].p_start != 0) {
(void) fprintf(stderr,
"slice %d starts at %llu, is not at"
" start of partition",
i, disk_vtoc.v_part[i].p_start);
if (!io_nifdisk) {
(void) printf(" adjust ?:");
if (yesno())
disk_vtoc.v_part[i].p_start = 0;
} else {
disk_vtoc.v_part[i].p_start = 0;
(void) fprintf(stderr, " adjusted!\n");
}
}
if (disk_vtoc.v_part[i].p_size != numsect) {
(void) fprintf(stderr,
"slice %d size %llu does not cover"
" complete partition",
i, disk_vtoc.v_part[i].p_size);
if (!io_nifdisk) {
(void) printf(" adjust ?:");
if (yesno())
disk_vtoc.v_part[i].p_size =
numsect;
} else {
disk_vtoc.v_part[i].p_size = numsect;
(void) fprintf(stderr, " adjusted!\n");
}
}
if (disk_vtoc.v_part[i].p_tag != V_BACKUP) {
(void) fprintf(stderr,
"slice %d tag was %d should be %d",
i, disk_vtoc.v_part[i].p_tag,
V_BACKUP);
if (!io_nifdisk) {
(void) printf(" fix ?:");
if (yesno())
disk_vtoc.v_part[i].p_tag =
V_BACKUP;
} else {
disk_vtoc.v_part[i].p_tag = V_BACKUP;
(void) fprintf(stderr, " fixed!\n");
}
}
continue;
}
if (io_ADJT) {
if (disk_vtoc.v_part[i].p_start > numsect ||
disk_vtoc.v_part[i].p_start +
disk_vtoc.v_part[i].p_size > numsect) {
(void) fprintf(stderr,
"slice %d (start %llu, end %llu)"
" is larger than the partition",
i, disk_vtoc.v_part[i].p_start,
disk_vtoc.v_part[i].p_start +
disk_vtoc.v_part[i].p_size);
if (!io_nifdisk) {
(void) printf(" remove ?:");
if (yesno()) {
disk_vtoc.v_part[i].p_size = 0;
disk_vtoc.v_part[i].p_start = 0;
disk_vtoc.v_part[i].p_tag = 0;
disk_vtoc.v_part[i].p_flag = 0;
}
} else {
disk_vtoc.v_part[i].p_size = 0;
disk_vtoc.v_part[i].p_start = 0;
disk_vtoc.v_part[i].p_tag = 0;
disk_vtoc.v_part[i].p_flag = 0;
(void) fprintf(stderr,
" removed!\n");
}
}
continue;
}
if (disk_vtoc.v_part[i].p_start > numsect) {
(void) fprintf(stderr,
"slice %d (start %llu) is larger than the "
"partition", i, disk_vtoc.v_part[i].p_start);
if (!io_nifdisk) {
(void) printf(" remove ?:");
if (yesno()) {
disk_vtoc.v_part[i].p_size = 0;
disk_vtoc.v_part[i].p_start = 0;
disk_vtoc.v_part[i].p_tag = 0;
disk_vtoc.v_part[i].p_flag = 0;
}
} else {
disk_vtoc.v_part[i].p_size = 0;
disk_vtoc.v_part[i].p_start = 0;
disk_vtoc.v_part[i].p_tag = 0;
disk_vtoc.v_part[i].p_flag = 0;
(void) fprintf(stderr,
" removed!\n");
}
} else if (disk_vtoc.v_part[i].p_start
+ disk_vtoc.v_part[i].p_size > numsect) {
(void) fprintf(stderr,
"slice %d (end %llu) is larger"
" than the partition",
i,
disk_vtoc.v_part[i].p_start +
disk_vtoc.v_part[i].p_size);
if (!io_nifdisk) {
(void) printf(" adjust ?:");
if (yesno()) {
disk_vtoc.v_part[i].p_size = numsect;
}
} else {
disk_vtoc.v_part[i].p_size = numsect;
(void) fprintf(stderr, " adjusted!\n");
}
}
}
#if 1
disk_vtoc.v_version = V_VERSION;
disk_vtoc.v_sanity = VTOC_SANE;
disk_vtoc.v_nparts = V_NUMPAR;
if (disk_vtoc.v_sectorsz == 0)
disk_vtoc.v_sectorsz = NBPSCTR;
#endif
if (!io_readonly)
(void) writevtoc();
}
static int
yesno(void)
{
char s[80];
for (;;) {
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
if (((s[1] != '\0') && (s[1] != '\n')) ||
((s[0] != 'y') && (s[0] != 'n'))) {
(void) printf(E_LINE);
(void) printf("Please answer with \"y\" or \"n\": ");
continue;
}
if (s[0] == 'y')
return (1);
else
return (0);
}
}
static int
readvtoc(void)
{
int i;
int retval = VTOC_OK;
if ((i = read_extvtoc(Dev, &disk_vtoc)) < VTOC_OK) {
if (i == VT_EINVAL) {
(void) fprintf(stderr, "fdisk: Invalid VTOC.\n");
vt_inval++;
retval = VTOC_INVAL;
} else if (i == VT_ENOTSUP) {
(void) fprintf(stderr, "fdisk: partition may have EFI "
"GPT\n");
retval = VTOC_NOTSUP;
} else {
(void) fprintf(stderr, "fdisk: Cannot read VTOC.\n");
retval = VTOC_RWERR;
}
}
return (retval);
}
static int
writevtoc(void)
{
int i;
int retval = 0;
if ((i = write_extvtoc(Dev, &disk_vtoc)) != 0) {
if (i == VT_EINVAL) {
(void) fprintf(stderr,
"fdisk: Invalid entry exists in VTOC.\n");
retval = VTOC_INVAL;
} else if (i == VT_ENOTSUP) {
(void) fprintf(stderr, "fdisk: partition may have EFI "
"GPT\n");
retval = VTOC_NOTSUP;
} else {
(void) fprintf(stderr, "fdisk: Cannot write VTOC.\n");
retval = VTOC_RWERR;
}
}
return (retval);
}
static int
efi_ioctl(int fd, int cmd, dk_efi_t *dk_ioc)
{
void *data = dk_ioc->dki_data;
int error;
dk_ioc->dki_data_64 = (uintptr_t)data;
error = ioctl(fd, cmd, (void *)dk_ioc);
return (error);
}
static int
clear_efi(void)
{
struct dk_gpt *efi_vtoc;
dk_efi_t dk_ioc;
if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) {
return (VT_ERROR);
}
dk_ioc.dki_lba = 1;
dk_ioc.dki_length = EFI_MIN_ARRAY_SIZE + efi_vtoc->efi_lbasize;
if ((dk_ioc.dki_data = calloc(dk_ioc.dki_length, 1)) == NULL) {
return (VT_ERROR);
}
if (io_debug) {
(void) fprintf(stderr,
"\tClearing primary EFI label at block %lld\n",
dk_ioc.dki_lba);
}
if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
free(dk_ioc.dki_data);
switch (errno) {
case EIO:
return (VT_EIO);
case EINVAL:
return (VT_EINVAL);
default:
return (VT_ERROR);
}
}
dk_ioc.dki_lba = efi_vtoc->efi_last_u_lba + 1;
dk_ioc.dki_length -= efi_vtoc->efi_lbasize;
dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data +
efi_vtoc->efi_lbasize);
if (io_debug) {
(void) fprintf(stderr,
"\tClearing backup partition table at block %lld\n",
dk_ioc.dki_lba);
}
if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
(void) fprintf(stderr, "\tUnable to clear backup EFI label at "
"block %llu; errno %d\n", efi_vtoc->efi_last_u_lba + 1,
errno);
}
dk_ioc.dki_lba = efi_vtoc->efi_last_lba;
dk_ioc.dki_length = efi_vtoc->efi_lbasize;
dk_ioc.dki_data = (efi_gpt_t *)((char *)dk_ioc.dki_data -
efi_vtoc->efi_lbasize);
if (io_debug) {
(void) fprintf(stderr, "\tClearing backup label at block "
"%lld\n", dk_ioc.dki_lba);
}
if (efi_ioctl(Dev, DKIOCSETEFI, &dk_ioc) == -1) {
(void) fprintf(stderr,
"\tUnable to clear backup EFI label at "
"block %llu; errno %d\n",
efi_vtoc->efi_last_lba,
errno);
}
free(dk_ioc.dki_data);
efi_free(efi_vtoc);
return (0);
}
static void
clear_vtoc(int table, int part)
{
struct ipart *clr_table;
char *disk_label;
uint32_t pcyl, ncyl, count;
diskaddr_t backup_block, solaris_offset;
ssize_t bytes;
off_t seek_byte;
#ifdef DEBUG
char *read_label;
#endif
if (table == OLD) {
clr_table = &Old_Table[part];
} else {
clr_table = &Table[part];
}
disk_label = (char *)calloc(sectsiz, 1);
if (disk_label == NULL) {
return;
}
seek_byte = (off_t)(LE_32(clr_table->relsect) + VTOC_OFFSET) * sectsiz;
if (io_debug) {
(void) fprintf(stderr,
"\tClearing primary VTOC at byte %llu (block %llu)\n",
(uint64_t)seek_byte,
(uint64_t)(LE_32(clr_table->relsect) + VTOC_OFFSET));
}
if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
(void) fprintf(stderr,
"\tError seeking to primary label at byte %llu\n",
(uint64_t)seek_byte);
free(disk_label);
return;
}
bytes = write(Dev, disk_label, sectsiz);
if (bytes != sectsiz) {
(void) fprintf(stderr,
"\tWarning: only %d bytes written to clear primary"
" VTOC!\n", bytes);
}
#ifdef DEBUG
if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
(void) fprintf(stderr,
"DEBUG: Error seeking to primary label at byte %llu\n",
(uint64_t)seek_byte);
free(disk_label);
return;
} else {
(void) fprintf(stderr,
"DEBUG: Successful lseek() to byte %llu\n",
(uint64_t)seek_byte);
}
read_label = (char *)calloc(sectsiz, 1);
if (read_label == NULL) {
free(disk_label);
return;
}
bytes = read(Dev, read_label, sectsiz);
if (bytes != sectsiz) {
(void) fprintf(stderr,
"DEBUG: Warning: only %d bytes read of label\n",
bytes);
}
if (memcmp(disk_label, read_label, sectsiz) != 0) {
(void) fprintf(stderr,
"DEBUG: Warning: disk_label and read_label differ!!!\n");
} else {
(void) fprintf(stderr, "DEBUG Good compare of disk_label and "
"read_label\n");
}
#endif
pcyl = LE_32(clr_table->numsect) / (heads * sectors);
solaris_offset = LE_32(clr_table->relsect);
ncyl = pcyl - acyl;
backup_block = ((ncyl + acyl - 1) *
(heads * sectors)) + ((heads - 1) * sectors) + 1;
for (count = 1; count < 6; count++) {
seek_byte = (off_t)(solaris_offset + backup_block) * sectsiz;
if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
(void) fprintf(stderr,
"\tError seeking to backup label at byte %llu on "
"%s.\n", (uint64_t)seek_byte, Dfltdev);
free(disk_label);
#ifdef DEBUG
free(read_label);
#endif
return;
}
if (io_debug) {
(void) fprintf(stderr, "\tClearing backup VTOC at"
" byte %llu (block %llu)\n",
(uint64_t)seek_byte,
(uint64_t)(solaris_offset + backup_block));
}
bytes = write(Dev, disk_label, sectsiz);
if (bytes != sectsiz) {
(void) fprintf(stderr,
"\t\tWarning: only %d bytes written to "
"clear backup VTOC at block %llu!\n", bytes,
(uint64_t)(solaris_offset + backup_block));
}
#ifdef DEBUG
if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
(void) fprintf(stderr,
"DEBUG: Error seeking to backup label at byte %llu\n",
(uint64_t)seek_byte);
free(disk_label);
free(read_label);
return;
} else {
(void) fprintf(stderr,
"DEBUG: Successful lseek() to byte %llu\n",
(uint64_t)seek_byte);
}
bytes = read(Dev, read_label, sectsiz);
if (bytes != sectsiz) {
(void) fprintf(stderr,
"DEBUG: Warning: only %d bytes read of backup label\n",
bytes);
}
if (memcmp(disk_label, read_label, sectsiz) != 0) {
(void) fprintf(stderr,
"DEBUG: Warning: disk_label and read_label differ!!!\n");
} else {
(void) fprintf(stderr,
"DEBUG: Good compare of disk_label and backup "
"read_label\n");
}
#endif
backup_block += 2;
}
#ifdef DEBUG
free(read_label);
#endif
free(disk_label);
}
#define FDISK_STANDARD_LECTURE \
"Fdisk is normally used with the device that " \
"represents the entire fixed disk.\n" \
"(For example, /dev/rdsk/c0d0p0 on x86 or " \
"/dev/rdsk/c0t5d0s2 on sparc).\n"
#define FDISK_LECTURE_NOT_SECTOR_ZERO \
"The device does not appear to include absolute\n" \
"sector 0 of the PHYSICAL disk " \
"(the normal location for an fdisk table).\n"
#define FDISK_LECTURE_NOT_FULL \
"The device does not appear to encompass the entire PHYSICAL disk.\n"
#define FDISK_LECTURE_NO_VTOC \
"Unable to find a volume table of contents.\n" \
"Cannot verify the device encompasses the full PHYSICAL disk.\n"
#define FDISK_LECTURE_NO_GEOM \
"Unable to get geometry from device.\n" \
"Cannot verify the device encompasses the full PHYSICAL disk.\n"
#define FDISK_SHALL_I_CONTINUE \
"Are you sure you want to continue? (y/n) "
static int
lecture_and_query(char *warning, char *devname)
{
if (io_nifdisk)
return (0);
(void) fprintf(stderr, "WARNING: Device %s: \n", devname);
(void) fprintf(stderr, "%s", warning);
(void) fprintf(stderr, FDISK_STANDARD_LECTURE);
(void) fprintf(stderr, FDISK_SHALL_I_CONTINUE);
return (yesno());
}
static void
sanity_check_provided_device(char *devname, int fd)
{
struct extvtoc v;
struct dk_geom d;
struct part_info pi;
struct extpart_info extpi;
diskaddr_t totsize;
int idx = -1;
if (ioctl(fd, DKIOCEXTPARTINFO, &extpi) != -1) {
if (extpi.p_start != 0) {
if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
devname)) {
(void) close(fd);
exit(1);
}
}
} else if (ioctl(fd, DKIOCPARTINFO, &pi) != -1) {
if (pi.p_start != 0) {
if (!lecture_and_query(FDISK_LECTURE_NOT_SECTOR_ZERO,
devname)) {
(void) close(fd);
exit(1);
}
}
} else {
if ((idx = read_extvtoc(fd, &v)) < 0) {
if (!lecture_and_query(FDISK_LECTURE_NO_VTOC,
devname)) {
(void) close(fd);
exit(1);
}
return;
}
if (ioctl(fd, DKIOCGGEOM, &d) == -1) {
perror(devname);
if (!lecture_and_query(FDISK_LECTURE_NO_GEOM,
devname)) {
(void) close(fd);
exit(1);
}
return;
}
totsize = (diskaddr_t)d.dkg_ncyl * d.dkg_nhead * d.dkg_nsect;
if (v.v_part[idx].p_size != totsize) {
if (!lecture_and_query(FDISK_LECTURE_NOT_FULL,
devname)) {
(void) close(fd);
exit(1);
}
}
}
}
static char *
get_node(char *devname)
{
char *node;
struct stat statbuf;
size_t space;
if (io_image)
return (devname);
node = devname;
if (stat(node, (struct stat *)&statbuf) == -1) {
space = strlen(DEFAULT_PATH) + strlen(devname) + 1;
if ((node = malloc(space)) == NULL) {
(void) fprintf(stderr, "fdisk: Unable to obtain memory "
"for device node.\n");
exit(1);
}
(void) strncpy(node, DEFAULT_PATH, strlen(DEFAULT_PATH));
space -= strlen(DEFAULT_PATH);
(void) strlcpy(node + strlen(DEFAULT_PATH), devname, space);
if (stat(node, (struct stat *)&statbuf) == -1) {
(void) fprintf(stderr,
"fdisk: Cannot stat device %s.\n",
devname);
exit(1);
}
}
if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
(void) fprintf(stderr,
"fdisk: %s must be a raw device.\n", node);
exit(1);
}
return (node);
}
#ifdef i386
static void
preach_and_continue()
{
(void) fprintf(stderr, "There are mounted logical drives. Committing "
"changes now can lead to inconsistancy in internal system state "
"which can eventually cause data loss or corruption. Unmount all "
"logical drives and try committing the changes again.\n");
ext_read_input(s);
}
void
id_to_name(uchar_t sysid, char *buffer)
{
(void) strcpy(buffer, fdisk_part_types[sysid]);
}
static int
ext_invalid_option(char ch)
{
char *p;
p = strchr(ext_part_menu_opts, tolower(ch));
if (p == NULL) {
return (1);
}
return (0);
}
static void
ext_read_input(char *buf)
{
(void) fgets(buf, 16, stdin);
(void) fflush(stdin);
}
static int
ext_read_options(char *buf)
{
ext_read_input(buf);
if ((strlen(buf) != 2) || (ext_invalid_option(buf[0]))) {
(void) printf("\nUnknown Command\n");
return (-1);
}
return (0);
}
static void
ext_print_part_types()
{
int i, rowmax, rowcount = 1;
struct winsize ws;
char buf[80];
if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
perror("ioctl");
rowmax = 20;
} else {
rowmax = ws.ws_row - 5;
}
if (rowmax < 3) {
(void) fprintf(stderr, "Window size too small."
" Try resizing the window\n");
return;
}
(void) printf("List of known partition types : \n");
(void) printf("PartID Partition Type\n");
(void) printf("====== ==============\n");
for (i = 0; i <= FDISK_MAX_VALID_PART_ID; i++) {
(void) printf("%-3d %s\n", i, fdisk_part_types[i]);
rowcount++;
if (rowcount == rowmax) {
rowmax = ws.ws_row - 1;
(void) fprintf(stderr, "\nPress enter to see next "
"page or 'q' to quit : ");
ext_read_input(buf);
if ((strlen(buf) == 2) && (tolower(buf[0]) == 'q')) {
return;
}
rowcount = 1;
}
}
}
static void
ext_read_valid_part_num(int *pno)
{
char buf[80];
int len, i;
for (;;) {
(void) printf("Enter the partition number : ");
ext_read_input(buf);
len = strlen(buf);
if ((len < 2) || (len > (FDISK_MAX_VALID_PART_NUM_DIGITS+1))) {
goto print_error_and_continue;
}
for (i = 0; i < len-1; i++) {
if (!isdigit(buf[i])) {
goto print_error_and_continue;
}
}
*pno = atoi(buf);
if ((*pno <= FD_NUMPART) ||
*pno > (fdisk_get_logical_drive_count(epp) + FD_NUMPART)) {
goto print_error_and_continue;
}
break;
print_error_and_continue:
(void) printf("Invalid partition number\n");
continue;
}
}
static void
ext_read_valid_part_id(uchar_t *partid)
{
char buf[80];
int len, i, id;
for (;;) {
(void) printf("Enter the ID ( Type I for list of "
"partition IDs ) : ");
ext_read_input(buf);
len = strlen(buf);
if ((len < 2) || (len > (FDISK_MAX_VALID_PART_ID_DIGITS + 1))) {
(void) printf("Invalid partition ID\n");
continue;
}
if ((len == 2) && (toupper(buf[0]) == 'I')) {
ext_print_part_types();
continue;
}
for (i = 0; i < len-1; i++) {
if (!isdigit(buf[i])) {
(void) printf("Invalid partition ID\n");
break;
}
}
if (i < len - 1) {
continue;
}
if ((id = atoi(buf)) > FDISK_MAX_VALID_PART_ID) {
(void) printf("Invalid partition ID\n");
continue;
}
*partid = (uchar_t)id;
if (fdisk_is_dos_extended(*partid)) {
(void) printf("Multiple extended partitions not "
"allowed\n");
continue;
}
if (*partid == EFI_PMBR) {
(void) printf("EFI partitions within an extended "
"partition is not allowed\n");
continue;
}
return;
}
}
static void
delete_logical_drive()
{
int pno;
if (!fdisk_get_logical_drive_count(epp)) {
(void) printf("\nNo logical drives defined.\n");
return;
}
(void) printf("\n");
ext_read_valid_part_num(&pno);
fdisk_delete_logical_drive(epp, pno);
(void) printf("Partition %d deleted\n", pno);
}
static int
ext_read_valid_partition_start(uint32_t *begsec)
{
char buf[80];
int ret, len, i;
uint32_t begcyl;
uint32_t first_free_cyl;
uint32_t first_free_sec;
ret = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
if (ret != FDISK_SUCCESS) {
return (ret);
}
first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec);
for (;;) {
(void) printf("Enter the beginning cylinder (Default - %d) : ",
first_free_cyl);
ext_read_input(buf);
len = strlen(buf);
if (len == 1) {
*begsec = first_free_sec;
return (FDISK_SUCCESS);
}
if (len > (FDISK_MAX_VALID_CYL_NUM_DIGITS + 1)) {
(void) printf("Input too long\n");
(void) printf("Invalid beginning cylinder number\n");
continue;
}
for (i = 0; i < len - 1; i++) {
if (!isdigit(buf[i])) {
(void) printf("Invalid beginning cylinder "
"number\n");
break;
}
}
if (i < len - 1) {
continue;
}
begcyl = atoi(buf);
ret = fdisk_ext_validate_part_start(epp, begcyl, begsec);
switch (ret) {
case FDISK_SUCCESS:
break;
case FDISK_EOVERLAP:
(void) printf("Partition boundary overlaps "
"with ");
(void) printf("existing partitions\n");
(void) printf("Invalid beginning cylinder "
"number\n");
continue;
case FDISK_EOOBOUND:
(void) printf("Cylinder boundary beyond the "
"limits\n");
(void) printf("Invalid beginning cylinder "
"number\n");
continue;
}
return (FDISK_SUCCESS);
}
}
static void
ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec)
{
char buf[80];
uint32_t last_free_sec;
uint32_t last_free_cyl;
int i, len, ch, mbgb = 0, scale = FDISK_SECTS_PER_CYL(epp);
uint64_t size = 0;
int copy_len;
char numbuf[FDISK_MAX_VALID_CYL_NUM_DIGITS + 1];
int sectsize = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE);
uint32_t remdr, spc, poss_end;
if (sectsize == EINVAL) {
(void) fprintf(stderr, "Unsupported geometry statistics.\n");
exit(1);
}
last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
last_free_cyl = FDISK_SECT_TO_CYL(epp, last_free_sec);
for (;;) {
(void) printf("Enter the size in cylinders (Default End "
"Cylinder -");
(void) printf(" %u)\n", last_free_cyl);
(void) printf("Type +<size>K, +<size>M or +<size>G to enter "
"size in");
(void) printf("KB, MB or GB : ");
ext_read_input(buf);
len = strlen(buf);
mbgb = 0;
scale = FDISK_SECTS_PER_CYL(epp);
if (len == 1) {
*endsec = last_free_sec;
return;
}
copy_len = len - 1;
if ((buf[0] == '+') && (isdigit(buf[1]))) {
copy_len--;
if ((ch = toupper(buf[len - 2])) == 'B') {
ch = toupper(buf[len - 3]);
copy_len--;
}
if (!((ch == 'K') || (ch == 'M') || (ch == 'G'))) {
(void) printf("Invalid partition size\n");
continue;
}
copy_len--;
mbgb = 1;
scale = ((ch == 'K') ? FDISK_KB :
((ch == 'M') ? FDISK_MB : FDISK_GB));
}
if (copy_len > FDISK_MAX_VALID_CYL_NUM_DIGITS) {
(void) printf("Input too long\n");
(void) printf("Invalid partition size\n");
continue;
}
(void) strncpy(numbuf, &buf[mbgb], copy_len);
numbuf[copy_len] = '\0';
for (i = mbgb; i < copy_len + mbgb; i++) {
if (!isdigit(buf[i])) {
break;
}
}
if (i < copy_len + mbgb) {
(void) printf("Invalid partition size\n");
continue;
}
size = (atoll(numbuf) * (scale));
if (size == 0) {
(void) printf("Zero size is invalid\n");
(void) printf("Invalid partition size\n");
continue;
}
if (mbgb) {
size /= sectsize;
}
if (size > (last_free_sec - begsec + 1)) {
(void) printf("Cylinder boundary beyond the limits");
(void) printf(" or overlaps with existing");
(void) printf(" partitions\n");
(void) printf("Invalid partition size\n");
continue;
}
spc = FDISK_SECTS_PER_CYL(epp);
poss_end = begsec + size - 1;
if ((remdr = (poss_end % spc)) != 0) {
poss_end += spc - remdr - 1;
}
*endsec = (poss_end > last_free_sec) ? last_free_sec :
poss_end;
return;
}
}
static void
add_logical_drive()
{
uint32_t begsec, endsec;
uchar_t partid;
char buf[80];
int rval;
if (fdisk_get_logical_drive_count(epp) >= MAX_EXT_PARTS) {
(void) printf("\nNumber of logical drives exceeds limit of "
"%d.\n", MAX_EXT_PARTS);
(void) printf("Command did not succeed. Press enter to "
"continue\n");
ext_read_input(buf);
return;
}
(void) printf("\n");
rval = ext_read_valid_partition_start(&begsec);
switch (rval) {
case FDISK_SUCCESS:
break;
case FDISK_EOOBOUND:
(void) printf("\nNo space left in the extended "
"partition\n");
(void) printf("Press enter to continue\n");
ext_read_input(buf);
return;
}
ext_read_valid_partition_size(begsec, &endsec);
ext_read_valid_part_id(&partid);
fdisk_add_logical_drive(epp, begsec, endsec, partid);
(void) printf("New partition with ID %d added\n", partid);
}
static void
ext_change_logical_drive_id()
{
int pno;
uchar_t partid;
if (!fdisk_get_logical_drive_count(epp)) {
(void) printf("\nNo logical drives defined.\n");
return;
}
(void) printf("\n");
ext_read_valid_part_num(&pno);
ext_read_valid_part_id(&partid);
fdisk_change_logical_drive_id(epp, pno, partid);
(void) printf("Partition ID of partition %d changed to %d\n", pno,
partid);
}
#ifdef DEBUG
static void
ext_print_logdrive_layout_debug()
{
int pno;
char namebuff[255];
logical_drive_t *head = fdisk_get_ld_head(epp);
logical_drive_t *temp;
if (!fdisk_get_logical_drive_count(epp)) {
(void) printf("\nNo logical drives defined.\n");
return;
}
(void) printf("\n\n");
puts("# start block end block abs start abs end OSType");
for (temp = head, pno = 5; temp != NULL; temp = temp->next, pno++) {
id_to_name(temp->parts[0].systid, namebuff);
(void) printf("%d: %.10u %.10u %.10u %.10u",
pno,
LE_32(temp->parts[0].relsect),
LE_32(temp->parts[0].numsect),
temp->abs_secnum,
temp->abs_secnum + temp->numsect - 1 +
MAX_LOGDRIVE_OFFSET);
(void) printf(" %s\n", namebuff);
id_to_name(temp->parts[1].systid, namebuff);
(void) printf("%d: %.10u %.10u %.10s %.10s",
pno,
LE_32(temp->parts[1].relsect),
LE_32(temp->parts[1].numsect),
" ", " ");
(void) printf(" %s\n", namebuff);
}
}
#endif
static void
ext_print_logical_drive_layout()
{
int sysid;
unsigned int startcyl, endcyl, length, percent, remainder;
logical_drive_t *temp;
uint32_t part_start;
struct ipart *fpart;
char namebuff[255];
int numcyl = fdisk_get_disk_geom(epp, PHYSGEOM, NCYL);
int pno;
if (numcyl == EINVAL) {
(void) fprintf(stderr, "Unsupported geometry statistics.\n");
exit(1);
}
if (!fdisk_get_logical_drive_count(epp)) {
(void) printf("\nNo logical drives defined.\n");
return;
}
(void) printf("\n");
(void) printf("Number of cylinders in disk : %u\n",
numcyl);
(void) printf("Beginning cylinder of extended partition : %u\n",
fdisk_get_ext_beg_cyl(epp));
(void) printf("Ending cylinder of extended partition : %u\n",
fdisk_get_ext_end_cyl(epp));
(void) printf("\n");
(void) printf("Part# StartCyl EndCyl Length %% "
"Part ID (Type)\n");
(void) printf("===== ======== ======== ======= ==="
" ==============\n");
for (temp = fdisk_get_ld_head(epp), pno = 5; temp != NULL;
temp = temp->next, pno++) {
fpart = &temp->parts[0];
sysid = fpart->systid;
if (sysid == SUNIXOS) {
part_start = temp->abs_secnum +
temp->logdrive_offset;
if (fdisk_is_linux_swap(epp, part_start,
NULL) == 0)
(void) strcpy(namebuff, LINSWAPstr);
else
(void) strcpy(namebuff, SUstr);
} else {
id_to_name(sysid, namebuff);
}
startcyl = temp->begcyl;
endcyl = temp->endcyl;
if (startcyl == endcyl) {
length = 1;
} else {
length = endcyl - startcyl + 1;
}
percent = length * 100 / numcyl;
if ((remainder = (length * 100 % numcyl)) != 0) {
if ((remainder * 100 / numcyl) > 50) {
percent++;
}
}
if (percent > 100) {
percent = 100;
}
(void) printf("%-5d %-8u %-8u %-7u %-3d "
"%-3d (%-.28s)\n",
pno, startcyl, endcyl, length, percent, sysid, namebuff);
}
#ifdef DEBUG
ext_print_logdrive_layout_debug();
#endif
(void) printf("\n");
}
static void
ext_print_help_menu()
{
(void) printf("\n");
(void) printf("a Add a logical drive\n");
(void) printf("d Delete a logical drive\n");
(void) printf("h Print this help menu\n");
(void) printf("i Change the id of the logical drive\n");
(void) printf("p Print the logical drive layout\n");
(void) printf("r Return to the main fdisk menu\n");
(void) printf(" (To commit or cancel the changes)\n");
(void) printf("\n");
}
static void
ext_part_menu()
{
char buf[80];
uchar_t *bbsigp;
static int bbsig_disp_flag = 1;
int i;
(void) printf(CLR_SCR);
if (fdisk_corrupt_logical_drives(epp)) {
(void) printf("One or more logical drives seem to be "
"corrupt.\n");
(void) printf("Displaying only sane logical drives.\n");
}
if (bbsig_disp_flag && fdisk_invalid_bb_sig(epp, &bbsigp)) {
(void) printf("The following logical drives have a wrong "
"boot block signature :\n\n");
for (i = 0; bbsigp[i]; i++) {
(void) printf("%d ", bbsigp[i]);
}
(void) printf("\n\n");
(void) printf("They will be corrected when you choose to "
"commit\n");
bbsig_disp_flag = 0;
}
(void) printf("Extended partition menu\n");
for (;;) {
(void) printf("\nEnter Command (Type h for help) : ");
if ((ext_read_options(buf)) < 0) {
(void) printf("\nCommand Options : \n");
ext_print_help_menu();
continue;
}
switch (buf[0]) {
case 'a':
add_logical_drive();
break;
case 'd':
delete_logical_drive();
break;
case 'h':
ext_print_help_menu();
break;
case 'i':
ext_change_logical_drive_id();
break;
case 'p':
ext_print_logical_drive_layout();
break;
case 'r':
(void) printf(CLR_SCR);
return;
default :
break;
}
}
}
#endif
static int
nopartdefined()
{
int i;
for (i = 0; i < FD_NUMPART; i++)
if (Table[i].systid != UNUSED)
return (0);
return (1);
}
static int
efi_create()
{
if (io_EFIslot < 0 || io_EFIslot > 3) {
(void) fprintf(stderr,
"EFI partition slot must be between 0 and 3 inclusive.\n");
return (0);
}
if (io_EFIactive != 0 && io_EFIactive != 1) {
(void) fprintf(stderr,
"EFI partition active flag must be 0 or 1.\n");
return (0);
}
nulltbl();
if (insert_tbl(EFI_PMBR,
io_EFIactive ? ACTIVE : NOTACTIVE,
MAX_HEAD + 1, MAX_SECT, MAX_CYL + 1,
MAX_HEAD + 1, MAX_SECT, MAX_CYL + 1,
1,
(dev_capacity > DK_MAX_2TB) ? DK_MAX_2TB : (dev_capacity - 1),
io_EFIslot) != io_EFIslot)
return (0);
copy_Table_to_Bootblk();
dev_mboot_write(0, Bootsect, sectsiz);
return (1);
}