summaryrefslogtreecommitdiff
path: root/usr/src/cmd/fdisk/fdisk.c
diff options
context:
space:
mode:
authorstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
committerstevel@tonic-gate <none@none>2005-06-14 00:00:00 -0700
commit7c478bd95313f5f23a4c958a745db2134aa03244 (patch)
treec871e58545497667cbb4b0a4f2daf204743e1fe7 /usr/src/cmd/fdisk/fdisk.c
downloadillumos-joyent-7c478bd95313f5f23a4c958a745db2134aa03244.tar.gz
OpenSolaris Launch
Diffstat (limited to 'usr/src/cmd/fdisk/fdisk.c')
-rw-r--r--usr/src/cmd/fdisk/fdisk.c3587
1 files changed, 3587 insertions, 0 deletions
diff --git a/usr/src/cmd/fdisk/fdisk.c b/usr/src/cmd/fdisk/fdisk.c
new file mode 100644
index 0000000000..985281cbf4
--- /dev/null
+++ b/usr/src/cmd/fdisk/fdisk.c
@@ -0,0 +1,3587 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
+/* All Rights Reserved */
+
+/* Copyright (c) 1987, 1988 Microsoft Corporation */
+/* All Rights Reserved */
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * PROGRAM: fdisk(1M)
+ * This program reads the partition table on the specified device and
+ * also reads the drive parameters. The user can perform various
+ * operations from a supplied menu or from the command line. Diagnostic
+ * options are also available.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <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>
+
+#define CLR_SCR ""
+#define CLR_LIN ""
+#define HOME "" \
+ ""
+#define Q_LINE ""
+#define W_LINE ""
+#define E_LINE ""
+#define M_LINE "" \
+ ""
+#define T_LINE ""
+
+#define DEFAULT_PATH "/dev/rdsk/"
+
+/* XXX - should be in fdisk.h, used by sd as well */
+
+/*
+ * the MAX values are the maximum usable values for BIOS chs values
+ * The MAX_CYL value of 1022 is the maximum usable value
+ * the value of 1023 is a fence value,
+ * indicating no CHS geometry exists for the corresponding LBA value.
+ * HEAD range [ 0 .. MAX_HEAD ], so number of heads is (MAX_HEAD + 1)
+ * SECT range [ 1 .. MAX_SECT ], so number of sectors is (MAX_SECT)
+ */
+#define MAX_SECT (63)
+#define MAX_CYL (1022)
+#define MAX_HEAD (254)
+
+/* for clear_vtoc() */
+#define OLD 0
+#define NEW 1
+
+/* readvtoc/writevtoc return codes */
+#define VTOC_OK 0 /* Good VTOC */
+#define VTOC_INVAL 1 /* invalid VTOC */
+#define VTOC_NOTSUP 2 /* operation not supported - EFI label */
+#define VTOC_RWERR 3 /* couldn't read or write VTOC */
+
+/*
+ * Support for fdisk(1M) on the SPARC platform
+ * In order to convert little endian values to big endian for SPARC,
+ * byte/short and long values must be swapped.
+ * These swapping macros will be used to access information in the
+ * mboot and ipart structures.
+ */
+
+#ifdef sparc
+#define les(val) ((((val)&0xFF)<<8)|(((val)>>8)&0xFF))
+#define lel(val) (((unsigned)(les((val)&0x0000FFFF))<<16) | \
+ (les((unsigned)((val)&0xffff0000)>>16)))
+#else
+#define les(val) (val)
+#define lel(val) (val)
+#endif
+
+#if defined(_SUNOS_VTOC_16)
+#define VTOC_OFFSET 512
+#elif defined(_SUNOS_VTOC_8)
+#define VTOC_OFFSET 0
+#else
+#error No VTOC format defined.
+#endif
+
+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"
+"[ -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 | E | g | G | R | t | T ] rdevice";
+
+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"
+" -E Create one EFI 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"
+" -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).";
+
+char Ostr[] = "Other OS";
+char Dstr[] = "DOS12";
+char D16str[] = "DOS16";
+char DDstr[] = "DOS-DATA";
+char EDstr[] = "EXT-DOS";
+char DBstr[] = "DOS-BIG";
+char PCstr[] = "PCIX";
+char Ustr[] = "UNIX System";
+char SUstr[] = "Solaris";
+char SU2str[] = "Solaris2";
+char X86str[] = "x86 Boot";
+char DIAGstr[] = "Diagnostic";
+char IFSstr[] = "IFS: NTFS";
+char AIXstr[] = "AIX Boot";
+char AIXDstr[] = "AIX Data";
+char OS2str[] = "OS/2 Boot";
+char WINstr[] = "Win95 FAT32";
+char EWINstr[] = "Ext Win95";
+char FAT95str[] = "FAT16 LBA";
+char EXTLstr[] = "EXT LBA";
+char LINUXstr[] = "Linux";
+char CPMstr[] = "CP/M";
+char NOVstr[] = "Netware 3.x+";
+char QNXstr[] = "QNX 4.x";
+char QNX2str[] = "QNX part 2";
+char QNX3str[] = "QNX part 3";
+char LINNATstr[] = "Linux native";
+char NTFSVOL1str[] = "NT volset 1";
+char NTFSVOL2str[] = "NT volset 2";
+char BSDstr[] = "BSD OS";
+char NEXTSTEPstr[] = "NeXTSTEP";
+char BSDIFSstr[] = "BSDI FS";
+char BSDISWAPstr[] = "BSDI swap";
+char Actvstr[] = "Active";
+char EFIstr[] = "EFI";
+char NAstr[] = " ";
+
+/* All the user options and flags */
+char *Dfltdev; /* name of fixed disk drive */
+
+/* Diagnostic options */
+int io_wrt = 0; /* write standard input to disk (-w) */
+int io_rd = 0; /* read from disk and write to stdout (-r) */
+char *io_fatt; /* user supplied pattern (-P pattern) */
+int io_patt = 0; /* write a pattern to disk (-P pattern) */
+int io_lgeom = 0; /* get label geometry (-g) */
+int io_pgeom = 0; /* get drive physical geometry (-G) */
+char *io_sgeom = 0; /* set label geometry (-S geom_file) */
+int io_readonly = 0; /* do not write to disk (-R) */
+
+/* The -o offset and -s size options specify the area of the disk on */
+/* which to perform the particular operation; i.e., -P, -r, or -w. */
+int io_offset = 0; /* offset sector (-o offset) */
+int io_size = 0; /* size in sectors (-s size) */
+
+/* Partition table flags */
+int v_flag = 0; /* virtual geometry-HBA flag (-v) */
+int stdo_flag = 0; /* stdout flag (-W -) */
+int io_fdisk = 0; /* do fdisk operation */
+int io_ifdisk = 0; /* interactive partition */
+int io_nifdisk = 0; /* non-interactive partition (-n) */
+
+int io_adjt = 0; /* check and adjust VTOC (truncate (-t)) */
+int io_ADJT = 0; /* check and adjust VTOC (delete (-T)) */
+char *io_ffdisk = 0; /* name of input fdisk file (-F file) */
+char *io_Wfdisk = 0; /* name of output fdisk file (-W file) */
+char *io_Afdisk = 0; /* entry to add to partition table (-A) */
+char *io_Dfdisk = 0; /* entry to delete from partition table (-D) */
+
+char *io_mboot = 0; /* master boot record (-b boot_file) */
+
+struct mboot BootCod; /* buffer for master boot record */
+
+int io_wholedisk = 0; /* use whole disk for Solaris partition (-B) */
+int io_EFIdisk = 0; /* use whole disk for EFI partition (-E) */
+int io_debug = 0; /* activate verbose mode (-d) */
+int io_image = 0; /* create image using supplied geometry (-I) */
+
+struct mboot *Bootblk; /* pointer to cut and paste sector zero */
+char *Bootsect; /* pointer to sector zero buffer */
+char *Nullsect;
+struct vtoc disk_vtoc; /* verify VTOC table */
+int vt_inval = 0;
+int no_virtgeom_ioctl = 0; /* ioctl for virtual geometry failed */
+int no_physgeom_ioctl = 0; /* ioctl for physical geometry failed */
+
+struct ipart Table[FD_NUMPART];
+struct ipart Old_Table[FD_NUMPART];
+
+/* Disk geometry information */
+struct dk_geom disk_geom;
+
+int Dev; /* fd for open device */
+/* Physical geometry for the drive */
+int Numcyl; /* number of cylinders */
+int heads; /* number of heads */
+int sectors; /* number of sectors per track */
+int acyl; /* number of alternate sectors */
+
+/* HBA (virtual) geometry for the drive */
+int hba_Numcyl; /* number of cylinders */
+int hba_heads; /* number of heads */
+int hba_sectors; /* number of sectors per track */
+
+int sectsiz; /* sector size */
+int drtype; /* Type of drive; i.e., scsi, floppy, ... */
+
+/* Load functions for fdisk table modification */
+#define LOADFILE 0 /* load fdisk from file */
+#define LOADDEL 1 /* delete an fdisk entry */
+#define LOADADD 2 /* add an fdisk entry */
+
+#define CBUFLEN 80
+char s[CBUFLEN];
+
+void sanity_check_provided_device(char *devname, int fd);
+static int clear_vtoc(int table, int part);
+static char *get_node(char *devname);
+static void Set_Table_CHS_Values(int ti);
+
+static void
+update_disk_and_exit(boolean_t table_changed)
+{
+ if (table_changed) {
+ /*
+ * Copy the new table back to the sector buffer
+ * and write it to disk
+ */
+ copy_Table_to_Bootblk();
+ dev_mboot_write(0, Bootsect, sectsiz);
+ }
+
+ /* If the VTOC table is wrong fix it (truncation only) */
+ if (io_adjt)
+ fix_slice();
+
+ exit(0);
+}
+
+
+
+/*
+ * main
+ * Process command-line options.
+ */
+void
+main(int argc, char *argv[])
+{
+ int c, i, j;
+ extern int optind;
+ extern char *optarg;
+ int errflg = 0;
+ int diag_cnt = 0;
+ int openmode;
+ int check_support_fdisk();
+
+ setbuf(stderr, 0); /* so all output gets out on exit */
+ setbuf(stdout, 0);
+
+ /* Process the options. */
+ while ((c = getopt(argc, argv, "o:s:P:F:b:A:D:W:S:tTIhwvrndgGRBE"))
+ != EOF) {
+ switch (c) {
+
+ case 'o':
+ io_offset = strtoul(optarg, 0, 0);
+ continue;
+ case 's':
+ io_size = strtoul(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':
+ io_EFIdisk++;
+ io_fdisk++;
+ continue;
+ case 'g':
+ diag_cnt++;
+ io_lgeom++;
+ continue;
+ case 'G':
+ diag_cnt++;
+ io_pgeom++;
+ continue;
+ case 'n':
+ io_nifdisk++;
+ io_fdisk++;
+ continue;
+ case 'F':
+ io_fdisk++;
+ io_ffdisk = optarg;
+ continue;
+ case 'b':
+ io_mboot = optarg;
+ continue;
+ case 'W':
+ /*
+ * If '-' is the -W argument, then write
+ * to standard output, otherwise write
+ * to the specified file.
+ */
+ if (strncmp(optarg, "-", 1) == 0)
+ stdo_flag = 1;
+ else
+ io_Wfdisk = optarg;
+ io_fdisk++;
+ continue;
+ case 'A':
+ io_fdisk++;
+ io_Afdisk = optarg;
+ continue;
+ case 'D':
+ io_fdisk++;
+ io_Dfdisk = optarg;
+ continue;
+ case 'h':
+ fprintf(stderr, "%s\n", Usage);
+ 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;
+ }
+
+ /* User option checking */
+
+ /* By default, run in interactive mode */
+ if (!io_fdisk && !diag_cnt && !io_nifdisk) {
+ io_ifdisk++;
+ io_fdisk++;
+ }
+ if (((io_fdisk || io_adjt) && diag_cnt) || (diag_cnt > 1)) {
+ errflg++;
+ }
+
+ /* Was any error detected? */
+ if (errflg || argc == optind) {
+ fprintf(stderr, "%s\n", Usage);
+ fprintf(stderr,
+ "\nDetailed help is available with the -h option.\n");
+ exit(2);
+ }
+
+
+ /* Figure out the correct device node to open */
+ Dfltdev = get_node(argv[optind]);
+
+ if (io_readonly)
+ openmode = O_RDONLY;
+ else
+ openmode = O_RDWR|O_CREAT;
+
+ if ((Dev = open(Dfltdev, openmode, 0666)) == -1) {
+ fprintf(stderr, "fdisk: Cannot open device %s.\n", Dfltdev);
+ exit(1);
+ }
+
+ /* Get the disk geometry */
+ if (!io_image) {
+ /* Get disk's HBA (virtual) geometry */
+ errno = 0;
+ if (ioctl(Dev, DKIOCG_VIRTGEOM, &disk_geom)) {
+
+ /*
+ * If ioctl isn't implemented on this platform, then
+ * turn off flag to print out virtual geometry (-v),
+ * otherwise use the virtual geometry.
+ */
+
+ if (errno == ENOTTY) {
+ v_flag = 0;
+ no_virtgeom_ioctl = 1;
+ } else if (errno == EINVAL) {
+ /*
+ * This means that the ioctl exists, but
+ * is invalid for this disk, meaning the
+ * disk doesn't have an HBA geometry
+ * (like, say, it's larger than 8GB).
+ */
+ v_flag = 0;
+ hba_Numcyl = hba_heads = hba_sectors = 0;
+ } else {
+ (void) fprintf(stderr,
+ "%s: Cannot get virtual disk geometry.\n",
+ argv[optind]);
+ exit(1);
+ }
+ } else {
+ /* save virtual geometry values obtained by ioctl */
+ hba_Numcyl = disk_geom.dkg_ncyl;
+ hba_heads = disk_geom.dkg_nhead;
+ hba_sectors = disk_geom.dkg_nsect;
+ }
+
+ errno = 0;
+ if (ioctl(Dev, DKIOCG_PHYGEOM, &disk_geom)) {
+ if (errno == ENOTTY) {
+ no_physgeom_ioctl = 1;
+ } else {
+ (void) fprintf(stderr,
+ "%s: Cannot get physical disk geometry.\n",
+ argv[optind]);
+ exit(1);
+ }
+
+ }
+ /*
+ * Call DKIOCGGEOM if the ioctls for physical and virtual
+ * geometry fail. Get both from this generic call.
+ */
+ if (no_virtgeom_ioctl && no_physgeom_ioctl) {
+ errno = 0;
+ if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
+ (void) fprintf(stderr,
+ "%s: Cannot get disk label geometry.\n",
+ argv[optind]);
+ exit(1);
+ }
+ }
+
+ Numcyl = disk_geom.dkg_ncyl;
+ heads = disk_geom.dkg_nhead;
+ sectors = disk_geom.dkg_nsect;
+ sectsiz = 512;
+ acyl = disk_geom.dkg_acyl;
+
+ /*
+ * if hba geometry was not set by DKIOC_VIRTGEOM
+ * or we got an invalid hba geometry
+ * then set hba geometry based on max values
+ */
+ if (no_virtgeom_ioctl ||
+ disk_geom.dkg_ncyl <= 0 ||
+ disk_geom.dkg_nhead <= 0 ||
+ disk_geom.dkg_nsect <= 0 ||
+ disk_geom.dkg_ncyl > MAX_CYL ||
+ disk_geom.dkg_nhead > MAX_HEAD ||
+ disk_geom.dkg_nsect > MAX_SECT) {
+
+ /*
+ * turn off flag to print out virtual geometry (-v)
+ */
+ v_flag = 0;
+ hba_sectors = MAX_SECT;
+ hba_heads = MAX_HEAD + 1;
+ hba_Numcyl = (Numcyl * heads * sectors) /
+ (hba_sectors * hba_heads);
+ }
+
+ if (io_debug) {
+ fprintf(stderr, "Physical Geometry:\n");
+ 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);
+ fprintf(stderr, "Virtual (HBA) Geometry:\n");
+ fprintf(stderr,
+ " cylinders[%d] heads[%d] sectors[%d]\n"
+ " sector size[%d] blocks[%d] mbytes[%d]\n",
+ hba_Numcyl,
+ hba_heads,
+ hba_sectors,
+ sectsiz,
+ hba_Numcyl*hba_heads*hba_sectors,
+ (hba_Numcyl*hba_heads*hba_sectors*sectsiz)/1048576);
+ }
+ }
+
+ /* If user has requested a geometry report just do it and exit */
+ if (io_lgeom) {
+ if (ioctl(Dev, DKIOCGGEOM, &disk_geom)) {
+ (void) fprintf(stderr,
+ "%s: Cannot get disk label geometry.\n",
+ argv[optind]);
+ exit(1);
+ }
+ Numcyl = disk_geom.dkg_ncyl;
+ heads = disk_geom.dkg_nhead;
+ sectors = disk_geom.dkg_nsect;
+ sectsiz = 512;
+ acyl = disk_geom.dkg_acyl;
+ printf("* Label geometry for device %s\n", Dfltdev);
+ printf("* PCYL NCYL ACYL BCYL NHEAD NSECT"
+ " SECSIZ\n");
+ 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);
+ }
+ printf("* Physical geometry for device %s\n", Dfltdev);
+ printf("* PCYL NCYL ACYL BCYL NHEAD NSECT"
+ " SECSIZ\n");
+ 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);
+ }
+ }
+
+ /* Allocate memory to hold three complete sectors */
+ Bootsect = (char *)malloc(3 * sectsiz);
+ if (Bootsect == NULL) {
+ fprintf(stderr,
+ "fdisk: Unable to obtain enough buffer memory"
+ " (%d bytes).\n",
+ 3*sectsiz);
+ exit(1);
+ }
+
+ Nullsect = Bootsect + sectsiz;
+ /* Zero out the "NULL" sector */
+ for (i = 0; i < sectsiz; i++) {
+ Nullsect[i] = 0;
+ }
+
+ /* Find out what the user wants done */
+ if (io_rd) { /* abs disk read */
+ abs_read(); /* will not return */
+ } else if (io_wrt && !io_readonly) {
+ abs_write(); /* will not return */
+ } else if (io_patt && !io_readonly) {
+ fill_patt(); /* will not return */
+ }
+
+
+ /* This is the fdisk edit, the real reason for the program. */
+
+ sanity_check_provided_device(Dfltdev, Dev);
+
+ /* Get the new BOOT program in case we write a new fdisk table */
+ mboot_read();
+
+ /* Read from disk master boot */
+ dev_mboot_read();
+
+ /*
+ * Verify and copy the device's fdisk table. This will be used
+ * as the prototype mboot if the device's mboot looks invalid.
+ */
+ Bootblk = (struct mboot *)Bootsect;
+ copy_Bootblk_to_Table();
+
+ /* save away a copy of Table in Old_Table for sensing changes */
+ copy_Table_to_Old_Table();
+
+ /* Load fdisk table from specified file (-F fdisk_file) */
+ if (io_ffdisk) {
+ /* Load and verify user-specified table parameters */
+ load(LOADFILE, io_ffdisk);
+ }
+
+ /* Does user want to delete or add an entry? */
+ if (io_Dfdisk) {
+ load(LOADDEL, io_Dfdisk);
+ }
+ if (io_Afdisk) {
+ load(LOADADD, io_Afdisk);
+ }
+
+ if (!io_ffdisk && !io_Afdisk && !io_Dfdisk) {
+ /* Check if there is no fdisk table */
+ if (Table[0].systid == UNUSED || io_wholedisk || io_EFIdisk) {
+ if (io_ifdisk && !io_wholedisk && !io_EFIdisk) {
+ printf("No fdisk table exists. The default"
+ " partition for the disk is:\n\n");
+ printf(" a 100%% \"SOLARIS System\" "
+ "partition\n\n");
+ printf("Type \"y\" to accept the default "
+ "partition, otherwise type \"n\" to "
+ "edit the\n partition table.\n");
+ }
+
+ /* Edit the partition table as directed */
+ if (io_wholedisk ||(io_ifdisk && yesno())) {
+
+ /* Default scenario */
+ nulltbl();
+
+ /* now set up UNIX System partition */
+ Table[0].bootid = ACTIVE;
+ Table[0].relsect = lel(heads * sectors);
+ Table[0].numsect = lel((long)((Numcyl-1) *
+ heads * sectors));
+ Table[0].systid = SUNIXOS2; /* Solaris */
+
+ /* calculate CHS values for table entry 0 */
+ Set_Table_CHS_Values(0);
+
+ update_disk_and_exit(B_TRUE);
+ } else if (io_EFIdisk) {
+ /* create an EFI partition for the whole disk */
+ nulltbl();
+ i = insert_tbl(EFI_PMBR, 0, 0, 0, 0, 0, 0, 0, 1,
+ (Numcyl * heads * sectors) - 1);
+ if (i != 0) {
+ fprintf(stderr, "Error creating EFI "
+ "partition\n");
+ exit(1);
+ }
+ update_disk_and_exit(B_TRUE);
+ }
+ }
+ }
+
+ /* Display complete fdisk table entries for debugging purposes */
+ if (io_debug) {
+ fprintf(stderr, "Partition Table Entry Values:\n");
+ print_Table();
+ if (io_ifdisk) {
+ fprintf(stderr, "\n");
+ fprintf(stderr, "Press Enter to continue.\n");
+ gets(s);
+ }
+ }
+
+ /* Interactive fdisk mode */
+ if (io_ifdisk) {
+ printf(CLR_SCR);
+ disptbl();
+ while (1) {
+ stage0(argv[1]);
+ copy_Bootblk_to_Table();
+ disptbl();
+ }
+ }
+
+ /* If user wants to write the table to a file, do it */
+ if (io_Wfdisk)
+ ffile_write(io_Wfdisk);
+ else if (stdo_flag)
+ ffile_write((char *)stdout);
+
+ update_disk_and_exit(TableChanged() == 1);
+}
+
+/*
+ * read_geom
+ * Read geometry from specified file (-S).
+ */
+
+read_geom(sgeom)
+char *sgeom;
+{
+ char line[256];
+ FILE *fp;
+
+ /* open the prototype file */
+ if ((fp = fopen(sgeom, "r")) == NULL) {
+ (void) fprintf(stderr, "fdisk: Cannot open file %s.\n",
+ io_sgeom);
+ return (1);
+ }
+
+ /* Read a line from the file */
+ while (fgets(line, sizeof (line) - 1, fp)) {
+ if (line[0] == '\0' || line[0] == '\n' || line[0] == '*')
+ continue;
+ else {
+ line[strlen(line)] = '\0';
+ if (sscanf(line, "%d %d %d %d %d %d %d",
+ &disk_geom.dkg_pcyl,
+ &disk_geom.dkg_ncyl,
+ &disk_geom.dkg_acyl,
+ &disk_geom.dkg_bcyl,
+ &disk_geom.dkg_nhead,
+ &disk_geom.dkg_nsect,
+ &sectsiz) != 7) {
+ (void) fprintf(stderr,
+ "Syntax error:\n \"%s\".\n",
+ line);
+ return (1);
+ }
+ break;
+ } /* else */
+ } /* while (fgets(line, sizeof (line) - 1, fp)) */
+
+ if (!io_image) {
+ if (ioctl(Dev, DKIOCSGEOM, &disk_geom)) {
+ (void) fprintf(stderr,
+ "fdisk: Cannot set label geometry.\n");
+ return (1);
+ }
+ } else {
+ Numcyl = hba_Numcyl = disk_geom.dkg_ncyl;
+ heads = hba_heads = disk_geom.dkg_nhead;
+ sectors = hba_sectors = disk_geom.dkg_nsect;
+ acyl = disk_geom.dkg_acyl;
+ }
+
+ fclose(fp);
+ return (0);
+}
+
+/*
+ * dev_mboot_read
+ * Read the master boot sector from the device.
+ */
+dev_mboot_read()
+{
+ if ((ioctl(Dev, DKIOCGMBOOT, Bootsect) < 0) && (errno != ENOTTY)) {
+ perror("Error in ioctl DKIOCGMBOOT");
+ }
+ if (errno == 0)
+ return;
+ if (lseek(Dev, 0, SEEK_SET) == -1) {
+ fprintf(stderr,
+ "fdisk: Error seeking to partition table on %s.\n",
+ Dfltdev);
+ if (!io_image)
+ exit(1);
+ }
+ if (read(Dev, Bootsect, sectsiz) != sectsiz) {
+ fprintf(stderr,
+ "fdisk: Error reading partition table from %s.\n",
+ Dfltdev);
+ if (!io_image)
+ exit(1);
+ }
+}
+
+/*
+ * dev_mboot_write
+ * Write the master boot sector to the device.
+ */
+dev_mboot_write(int sect, char *buff, int bootsiz)
+{
+ int new_pt, old_pt, error;
+ int clr_efi = -1, old_solaris = -1, new_solaris = -1;
+
+ if (io_readonly)
+ return (0);
+
+ if (io_debug) {
+ fprintf(stderr, "About to write fdisk table:\n");
+ print_Table();
+ if (io_ifdisk) {
+ fprintf(stderr, "Press Enter to continue.\n");
+ gets(s);
+ }
+ }
+
+ /* see if the old table had EFI or Solaris partitions */
+ for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
+ if (Old_Table[old_pt].systid == SUNIXOS ||
+ Old_Table[old_pt].systid == SUNIXOS2) {
+ old_solaris = old_pt;
+ } else if (Old_Table[old_pt].systid == EFI_PMBR) {
+ clr_efi = old_pt;
+ }
+ }
+
+ /* look to see if Solaris partition changed in relsect/numsect */
+ for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
+
+ /*
+ * if this is not a Solaris partition, ignore it
+ */
+ if (Table[new_pt].systid != SUNIXOS &&
+ Table[new_pt].systid != SUNIXOS2)
+ continue;
+
+ /*
+ * if there was no previous Solaris partition
+ * or if the old partition was in a different place
+ * or if the old partition was a different size
+ * then this must be a new Solaris partition
+ */
+ if (old_solaris == -1 ||
+ Old_Table[old_solaris].relsect != Table[new_pt].relsect ||
+ Old_Table[old_solaris].numsect != Table[new_pt].numsect) {
+ new_solaris = new_pt;
+ break;
+ }
+ }
+
+ /* look to see if a EFI partition changed in relsect/numsect */
+ for (new_pt = 0; new_pt < FD_NUMPART; new_pt++) {
+ if (Table[new_pt].systid != EFI_PMBR)
+ continue;
+ for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
+ if ((Old_Table[old_pt].systid == Table[new_pt].systid) &&
+ (Old_Table[old_pt].relsect == Table[new_pt].relsect) &&
+ (Old_Table[old_pt].numsect == Table[new_pt].numsect))
+ break;
+ }
+
+ /*
+ * if EFI partition changed, set the flag to clear
+ * the EFI GPT
+ */
+ if (old_pt == FD_NUMPART && Table[new_pt].begcyl != 0) {
+ clr_efi = 0;
+ }
+ break;
+ }
+
+ /* clear labels if necessary */
+ if (clr_efi >= 0) {
+ if (io_debug) {
+ fprintf(stderr, "Clearing EFI labels\n");
+ }
+ if ((error = clear_efi()) != 0) {
+ if (io_debug) {
+ fprintf(stderr, "\tError %d clearing EFI labels"
+ " (probably no EFI labels exist)\n",
+ error);
+ }
+ }
+ }
+
+ if (new_solaris >= 0) {
+ if (io_debug) {
+ fprintf(stderr, "Clearing VTOC labels from NEW"
+ " table\n");
+ }
+ clear_vtoc(NEW, new_solaris);
+ }
+
+ if ((ioctl(Dev, DKIOCSMBOOT, buff) == -1) && (errno != ENOTTY)) {
+ fprintf(stderr,
+ "fdisk: Error in ioctl DKIOCSMBOOT on %s.\n",
+ Dfltdev);
+ }
+ if (errno == 0)
+ return;
+
+ /* write to disk drive */
+ if (lseek(Dev, sect, SEEK_SET) == -1) {
+ fprintf(stderr,
+ "fdisk: Error seeking to master boot record on %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ if (write(Dev, buff, bootsiz) != bootsiz) {
+ fprintf(stderr,
+ "fdisk: Error writing master boot record to %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+}
+
+/*
+ * mboot_read
+ * Read the prototype boot records from the files.
+ */
+mboot_read()
+{
+ int mDev, i;
+ struct stat statbuf;
+ struct ipart *part;
+
+#if defined(i386) || defined(sparc)
+ /*
+ * If the master boot file hasn't been specified, use the
+ * implementation architecture name to generate the default one.
+ */
+ if (io_mboot == (char *)0) {
+ /*
+ * Bug ID 1249035:
+ * The mboot file must be delivered on all platforms
+ * and installed in a non-platform-dependent
+ * directory; i.e., /usr/lib/fs/ufs.
+ */
+ io_mboot = "/usr/lib/fs/ufs/mboot";
+ }
+
+ /* First read in the master boot record */
+
+ /* Open the master boot proto file */
+ if ((mDev = open(io_mboot, O_RDONLY, 0666)) == -1) {
+ fprintf(stderr,
+ "fdisk: Cannot open master boot file %s.\n",
+ io_mboot);
+ exit(1);
+ }
+
+ /* Read the master boot program */
+ if (read(mDev, &BootCod, sizeof (struct mboot)) != sizeof
+ (struct mboot)) {
+ fprintf(stderr,
+ "fdisk: Cannot read master boot file %s.\n",
+ io_mboot);
+ exit(1);
+ }
+
+ /* Is this really a master boot record? */
+ if (les(BootCod.signature) != MBB_MAGIC) {
+ fprintf(stderr,
+ "fdisk: Invalid master boot file %s.\n", io_mboot);
+ fprintf(stderr, "Bad magic number: is %x, but should be %x.\n",
+ les(BootCod.signature), MBB_MAGIC);
+ exit(1);
+ }
+
+ close(mDev);
+#else
+#error fdisk needs to be ported to new architecture
+#endif
+
+ /* Zero out the partitions part of this record */
+ part = (struct ipart *)BootCod.parts;
+ for (i = 0; i < FD_NUMPART; i++, part++) {
+ memset(part, 0, sizeof (struct ipart));
+ }
+
+}
+
+/*
+ * fill_patt
+ * Fill the disk with user/sector number pattern.
+ */
+fill_patt()
+{
+ int *buff_ptr, i, c;
+ int io_fpatt = 0;
+ int io_ipatt = 0;
+
+ if (strncmp(io_fatt, "#", 1) != 0) {
+ io_fpatt++;
+ io_ipatt = strtoul(io_fatt, 0, 0);
+ buff_ptr = (int *)Bootsect;
+ for (i = 0; i < sectsiz; i += 4, buff_ptr++)
+ *buff_ptr = io_ipatt;
+ }
+
+ /*
+ * Fill disk with pattern based on block number.
+ * Write to the disk at absolute relative block io_offset
+ * for io_size blocks.
+ */
+ while (io_size--) {
+ buff_ptr = (int *)Bootsect;
+ if (!io_fpatt) {
+ for (i = 0; i < sectsiz; i += 4, buff_ptr++)
+ *buff_ptr = io_offset;
+ }
+ /* Write the data to disk */
+ if (lseek(Dev, sectsiz * io_offset++, SEEK_SET) == -1) {
+ fprintf(stderr, "fdisk: Error seeking on %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ if (write(Dev, Bootsect, sectsiz) != sectsiz) {
+ fprintf(stderr, "fdisk: Error writing %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ } /* while (--io_size); */
+}
+
+/*
+ * abs_read
+ * Read from the disk at absolute relative block io_offset for
+ * io_size blocks. Write the data to standard ouput (-r).
+ */
+abs_read() {
+ int c;
+
+ while (io_size--) {
+ if (lseek(Dev, sectsiz * io_offset++, SEEK_SET) == -1) {
+ fprintf(stderr, "fdisk: Error seeking on %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ if (read(Dev, Bootsect, sectsiz) != sectsiz) {
+ fprintf(stderr, "fdisk: Error reading %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+
+ /* Write to standard ouptut */
+ if ((c = write(1, Bootsect, (unsigned)sectsiz)) != sectsiz)
+ {
+ if (c >= 0) {
+ if (io_debug)
+ fprintf(stderr,
+ "fdisk: Output warning: %d of %d"
+ " characters written.\n",
+ c, sectsiz);
+ exit(2);
+ } else {
+ perror("write error on output file.");
+ exit(2);
+ }
+ } /* if ((c = write(1, Bootsect, (unsigned)sectsiz)) */
+ /* != sectsiz) */
+ } /* while (--io_size); */
+ exit(0);
+}
+
+/*
+ * abs_write
+ * Read the data from standard input. Write to the disk at
+ * absolute relative block io_offset for io_size blocks (-w).
+ */
+abs_write()
+{
+ int c, i;
+
+ while (io_size--) {
+ int part_exit = 0;
+ /* Read from standard input */
+ if ((c = read(0, Bootsect, (unsigned)sectsiz)) != sectsiz) {
+ if (c >= 0) {
+ if (io_debug)
+ fprintf(stderr,
+ "fdisk: WARNING: Incomplete read (%d of"
+ " %d characters read) on input file.\n",
+ c, sectsiz);
+ /* Fill pattern to mark partial sector in buf */
+ for (i = c; i < sectsiz; ) {
+ Bootsect[i++] = 0x41;
+ Bootsect[i++] = 0x62;
+ Bootsect[i++] = 0x65;
+ Bootsect[i++] = 0;
+ }
+ part_exit++;
+ } else {
+ perror("read error on input file.");
+ exit(2);
+ }
+
+ }
+ /* Write to disk drive */
+ if (lseek(Dev, sectsiz * io_offset++, SEEK_SET) == -1) {
+ fprintf(stderr, "fdisk: Error seeking on %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ if (write(Dev, Bootsect, sectsiz) != sectsiz) {
+ fprintf(stderr, "fdisk: Error writing %s.\n",
+ Dfltdev);
+ exit(1);
+ }
+ if (part_exit)
+ exit(0);
+ } /* while (--io_size); */
+ exit(1);
+}
+
+/*
+ * load
+ * Load will either read the fdisk table from a file or add or
+ * delete an entry (-A, -D, -F).
+ */
+
+load(funct, file)
+int funct;
+char *file; /* Either file name or delete/add line */
+{
+ int id;
+ int act;
+ int bhead;
+ int bsect;
+ int bcyl;
+ int ehead;
+ int esect;
+ int ecyl;
+ int rsect;
+ int numsect;
+ char line[256];
+ int i = 0;
+ int j;
+ FILE *fp;
+
+ switch (funct) {
+
+ case LOADFILE:
+
+ /*
+ * Zero out the table before loading it, which will
+ * force it to be updated on disk later (-F
+ * fdisk_file).
+ */
+ nulltbl();
+
+ /* Open the prototype file */
+ if ((fp = fopen(file, "r")) == NULL) {
+ (void) fprintf(stderr,
+ "fdisk: Cannot open prototype partition file %s.\n",
+ file);
+ exit(1);
+ }
+
+ /* Read a line from the file */
+ while (fgets(line, sizeof (line) - 1, fp)) {
+ if (pars_fdisk(line, &id, &act, &bhead, &bsect,
+ &bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) {
+ continue;
+ }
+
+ /*
+ * Validate the partition. It cannot start at sector
+ * 0 unless it is UNUSED or already exists
+ */
+ if (validate_part(id, rsect, numsect) < 0) {
+ (void) fprintf(stderr,
+ "fdisk: Error on entry \"%s\".\n",
+ line);
+ exit(1);
+ }
+ /*
+ * Find an unused entry to use and put the entry
+ * in table
+ */
+ if (insert_tbl(id, act, bhead, bsect, bcyl, ehead,
+ esect, ecyl, rsect, numsect) < 0) {
+ (void) fprintf(stderr,
+ "fdisk: Error on entry \"%s\".\n",
+ line);
+ exit(1);
+ }
+ } /* while (fgets(line, sizeof (line) - 1, fp)) */
+
+ if (verify_tbl() < 0) {
+ fprintf(stderr,
+ "fdisk: Cannot create partition table\n");
+ exit(1);
+ }
+
+ fclose(fp);
+ return;
+
+ case LOADDEL:
+
+ /* Parse the user-supplied deletion line (-D) */
+ pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead,
+ &esect, &ecyl, &rsect, &numsect);
+
+ /* Find the exact entry in the table */
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid == id &&
+ Table[i].bootid == act &&
+ Table[i].beghead == bhead &&
+ Table[i].begsect == ((bsect & 0x3f) |
+ (unsigned char)((bcyl>>2) & 0xc0)) &&
+ Table[i].begcyl == (unsigned char)(bcyl & 0xff) &&
+ Table[i].endhead == ehead &&
+ Table[i].endsect == ((esect & 0x3f) |
+ (unsigned char)((ecyl>>2) & 0xc0)) &&
+ Table[i].endcyl == (unsigned char)(ecyl & 0xff) &&
+ Table[i].relsect == lel(rsect) &&
+ Table[i].numsect == lel(numsect)) {
+
+ /*
+ * Found the entry. Now move rest of
+ * entries up toward the top of the
+ * table, leaving available entries at
+ * the end of the fdisk table.
+ */
+ for (j = i; j < FD_NUMPART-1; j++) {
+ Table[j].systid = Table[j+1].systid;
+ Table[j].bootid = Table[j+1].bootid;
+ Table[j].beghead = Table[j+1].beghead;
+ Table[j].begsect = Table[j+1].begsect;
+ Table[j].begcyl = Table[j+1].begcyl;
+ Table[j].endhead = Table[j+1].endhead;
+ Table[j].endsect = Table[j+1].endsect;
+ Table[j].endcyl = Table[j+1].endcyl;
+ Table[j].relsect = Table[j+1].relsect;
+ Table[j].numsect = Table[j+1].numsect;
+ }
+
+ /*
+ * Mark the last entry as unused in case
+ * all table entries were in use prior
+ * to the deletion.
+ */
+
+ Table[FD_NUMPART-1].systid = UNUSED;
+ Table[FD_NUMPART-1].bootid = 0;
+ return;
+ }
+ }
+ fprintf(stderr,
+ "fdisk: Entry does not match any existing partition:\n"
+ " \"%s\"\n",
+ file);
+ exit(1);
+
+ case LOADADD:
+
+ /* Parse the user-supplied addition line (-A) */
+ pars_fdisk(file, &id, &act, &bhead, &bsect, &bcyl, &ehead,
+ &esect, &ecyl, &rsect, &numsect);
+
+ /* Validate the partition. It cannot start at sector 0 */
+ if (rsect == 0) {
+ (void) fprintf(stderr,
+ "fdisk: New partition cannot start at sector 0:\n"
+ " \"%s\".\n",
+ file);
+ exit(1);
+ }
+
+ /*
+ * if the user wishes to add an EFI partition, we need
+ * more extensive validation. rsect should be 1, and
+ * numsect should equal the entire disk capacity - 1
+ */
+
+ if (id == EFI_PMBR) {
+ if (rsect != 1) {
+ (void) fprintf(stderr,
+ "fdisk: EFI partitions must start at sector"
+ " 1 (input rsect = %d)\n", rsect);
+ exit(1);
+ }
+
+ if (numsect != ((Numcyl * heads * sectors) -1)) {
+ (void) fprintf(stderr,
+ "fdisk: EFI partitions must encompass the "
+ "entire disk\n (input numsect: %ld - avail:"
+ " %ld)\n", numsect,
+ ((Numcyl * heads * sectors) -1));
+ exit(1);
+ }
+ }
+
+ /* Find unused entry for use and put entry in table */
+ if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect,
+ ecyl, rsect, numsect) < 0) {
+ (void) fprintf(stderr,
+ "fdisk: Invalid entry could not be inserted:\n"
+ " \"%s\"\n",
+ file);
+ exit(1);
+ }
+
+ /* Make sure new entry does not overlap existing entry */
+ if (verify_tbl() < 0) {
+ fprintf(stderr,
+ "fdisk: Cannot create partition \"%s\",\n");
+ exit(1);
+ }
+ } /* switch funct */
+}
+
+/*
+ * Set_Table_CHS_Values
+ *
+ * This will calculate the CHS values for beginning and ending CHS
+ * for a single partition table entry (ti) based on the relsect
+ * and numsect values contained in the partion table entry.
+ *
+ * hba_heads and hba_sectors contain the number of heads and sectors.
+ *
+ * If the number of cylinders exceeds the MAX_CYL,
+ * then maximum values will be placed in the corresponding chs entry.
+ */
+static void
+Set_Table_CHS_Values(int ti)
+{
+ uint32_t lba, cy, hd, sc;
+
+ lba = (uint32_t)Table[ti].relsect;
+ if (lba >= hba_heads * hba_sectors * MAX_CYL) {
+ /*
+ * the lba address cannot be expressed in CHS value
+ * so store the maximum CHS field values in the CHS fields.
+ */
+ cy = MAX_CYL + 1;
+ hd = MAX_HEAD;
+ 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 = hd;
+ Table[ti].begsect = ((cy >> 2) & 0xc0) | sc;
+
+ /*
+ * This code is identical to the code above
+ * except that it works on ending CHS values
+ */
+ lba = (uint32_t)(Table[ti].relsect + Table[ti].numsect - 1);
+ if (lba >= hba_heads * hba_sectors * MAX_CYL) {
+ cy = MAX_CYL + 1;
+ hd = MAX_HEAD;
+ 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 = hd;
+ Table[ti].endsect = ((cy >> 2) & 0xc0) | sc;
+}
+
+/*
+ * insert_tbl
+ * Insert entry into fdisk table. Check all user-supplied values
+ * for the entry, but not the validity relative to other table
+ * entries!
+ */
+insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect, ecyl, rsect, numsect)
+int id, act, bhead, bsect, bcyl, ehead, esect, ecyl, rsect, numsect;
+{
+ int i;
+
+ /* validate partition size */
+ if (rsect+numsect > (Numcyl * heads * sectors)) {
+ fprintf(stderr,
+ "fdisk: Partition table exceeds the size of the disk.\n");
+ return (-1);
+ }
+
+ /* find UNUSED partition table entry */
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid == UNUSED) {
+ break;
+ }
+ }
+ if (i >= FD_NUMPART) {
+ fprintf(stderr, "fdisk: Partition table is full.\n");
+ return (-1);
+ }
+
+
+ Table[i].systid = id;
+ Table[i].bootid = act;
+ Table[i].numsect = lel(numsect);
+ Table[i].relsect = lel(rsect);
+
+ /*
+ * If we have been called with a valid geometry, use it
+ * valid means non-zero values that fit in the BIOS fields
+ */
+ if (0 < bsect && bsect <= MAX_SECT &&
+ 0 <= bhead && bhead <= MAX_HEAD &&
+ 0 < esect && esect <= MAX_SECT &&
+ 0 <= ehead && ehead <= MAX_HEAD) {
+ if (bcyl > MAX_CYL)
+ bcyl = MAX_CYL + 1;
+ if (ecyl > MAX_CYL)
+ ecyl = MAX_CYL + 1;
+ Table[i].begcyl = bcyl & 0xff;
+ Table[i].endcyl = ecyl & 0xff;
+ Table[i].beghead = bhead;
+ Table[i].endhead = ehead;
+ Table[i].begsect = ((bcyl >> 2) & 0xc0) | bsect;
+ Table[i].endsect = ((ecyl >> 2) & 0xc0) | esect;
+ } else {
+
+ /*
+ * The specified values are invalid,
+ * so calculate the values based on hba_heads, hba_sectors
+ */
+ Set_Table_CHS_Values(i);
+ }
+
+ /*
+ * return partition index
+ */
+ return (i);
+}
+
+/*
+ * verify_tbl
+ * Verify that no partition entries overlap or exceed the size of
+ * the disk.
+ */
+int
+verify_tbl()
+{
+ int i, j, rsect, numsect;
+ int noMoreParts = 0;
+ int numParts = 0;
+
+ /* Make sure new entry does not overlap an existing entry */
+ for (i = 0; i < FD_NUMPART-1; i++) {
+ if (Table[i].systid != UNUSED) {
+ numParts++;
+ /*
+ * No valid partitions allowed after an UNUSED or
+ * EFI_PMBR part
+ */
+ if (noMoreParts) {
+ return (-1);
+ }
+
+ /*
+ * EFI_PMBR partitions must be the only partition
+ * and must be Table entry 0
+ */
+ if (Table[i].systid == EFI_PMBR) {
+ if (i == 0) {
+ noMoreParts = 1;
+ } else {
+ return (-1);
+ }
+
+ if (Table[i].relsect != 1) {
+ 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 !=
+ ((Numcyl * heads * sectors) - 1)) {
+ fprintf(stderr, "ERROR: "
+ "EFI_PMBR partition must "
+ "encompass the entire "
+ "disk.\n numsect %ld - "
+ "actual %ld\n",
+ Table[i].numsect,
+ ((Numcyl * heads * sectors) - 1));
+
+ return (-1);
+ }
+ }
+
+ /* make sure the partition isn't larger than the disk */
+ rsect = lel(Table[i].relsect);
+ numsect = lel(Table[i].numsect);
+ if ((rsect + numsect) > (Numcyl * heads * sectors)) {
+ return (-1);
+ }
+
+ for (j = i+1; j < FD_NUMPART; j++) {
+ if (Table[j].systid != UNUSED) {
+ int t_relsect = lel(Table[j].relsect);
+ int t_numsect = lel(Table[j].numsect);
+
+ if (noMoreParts) {
+ fprintf(stderr,
+ "Cannot add partition to "
+ "table; no more partitions "
+ "allowed\n");
+
+ if (io_debug) {
+ fprintf(stderr,
+ "DEBUG: Current "
+ "partition:\t"
+ "%d:%d:%d:%d:%d:"
+ "%d:%d:%d:%d:%ld\n"
+ " Next "
+ "partition:\t\t"
+ "%d:%d:%d:%d:%d:"
+ "%d:%d:%d:%d:%ld\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 {
+ fprintf(stderr, "ERROR: "
+ "current partition overlaps"
+ " following partition\n");
+
+ return (-1);
+ }
+ }
+ }
+ } else {
+ noMoreParts = 1;
+ }
+ }
+ if (Table[i].systid != UNUSED) {
+ if (noMoreParts ||
+ ((lel(Table[i].relsect) + lel(Table[i].numsect)) >
+ (Numcyl * heads * sectors))) {
+ return (-1);
+ }
+ }
+
+ return (numParts);
+}
+
+/*
+ * pars_fdisk
+ * Parse user-supplied data to set up fdisk partitions
+ * (-A, -D, -F).
+ */
+pars_fdisk(line, id, act, bhead, bsect, bcyl, ehead, esect, ecyl,
+ rsect, numsect)
+char *line;
+char *id, *act, *bhead, *bsect, *bcyl, *ehead, *esect, *ecyl, *rsect;
+char *numsect;
+{
+ int i;
+ 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] = ' ';
+ }
+ }
+ if (sscanf(line, "%d %d %d %d %d %d %d %d %ld %ld",
+ id, act, bhead, bsect, bcyl, ehead, esect, ecyl,
+ rsect, numsect) != 10) {
+ (void) fprintf(stderr, "Syntax error:\n \"%s\".\n", line);
+ exit(1);
+ }
+ return (0);
+}
+
+/*
+ * validate_part
+ * Validate that a new partition does not start at sector 0. Only UNUSED
+ * partitions and previously existing partitions are allowed to start at 0.
+ */
+validate_part(id, rsect, numsect)
+int id, rsect, 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 == lel(rsect)) &&
+ (Old_Table[i].numsect == lel(numsect))) return (0);
+ }
+ fprintf(stderr, "New partition cannot start at sector 0\n");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * stage0
+ * Print out interactive menu and process user input.
+ */
+stage0(file)
+char *file;
+{
+ dispmenu(file);
+ while (1) {
+ printf(Q_LINE);
+ printf("Enter Selection: ");
+ gets(s);
+ rm_blanks(s);
+ while (!((s[0] > '0') && (s[0] < '7') && (s[1] == 0))) {
+ printf(E_LINE); /* Clear any previous error */
+ printf("Enter a one-digit number between 1 and 6.");
+ printf(Q_LINE);
+ printf("Enter Selection: ");
+ gets(s);
+ rm_blanks(s);
+ }
+ 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;
+ case '5':
+ /* update disk partition table, if changed */
+ if (TableChanged() == 1) {
+ copy_Table_to_Bootblk();
+ dev_mboot_write(0, Bootsect, sectsiz);
+ }
+ /*
+ * If the VTOC table is wrong fix it
+ * (truncate only)
+ */
+ if (io_adjt) {
+ fix_slice();
+ }
+ close(Dev);
+ exit(0);
+ case '6':
+ /*
+ * If the VTOC table is wrong fix it
+ * (truncate only)
+ */
+ if (io_adjt) {
+ fix_slice();
+ }
+ close(Dev);
+ exit(0);
+ default:
+ break;
+ }
+ copy_Table_to_Bootblk();
+ disptbl();
+ dispmenu(file);
+ }
+}
+
+/*
+ * pcreate
+ * Create partition entry in the table (interactive mode).
+ */
+pcreate()
+{
+ unsigned char tsystid = 'z';
+ int i, j;
+ int startcyl, endcyl;
+ int rsect = 1;
+ int retCode = 0;
+
+ i = 0;
+ while (1) {
+ if (i == FD_NUMPART) {
+ printf(E_LINE);
+ printf("The partition table is full!\n");
+ printf("You must delete a partition before creating"
+ " a new one.\n");
+ return (-1);
+ }
+ if (Table[i].systid == UNUSED) {
+ break;
+ }
+ i++;
+ }
+
+ j = 0;
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid != UNUSED) {
+ j += lel(Table[i].numsect);
+ }
+ if (j >= Numcyl * heads * sectors) {
+ printf(E_LINE);
+ printf("There is no more room on the disk for"
+ " another partition.\n");
+ printf("You must delete a partition before creating"
+ " a new one.\n");
+ return (-1);
+ }
+ }
+ while (tsystid == 'z') {
+ printf(Q_LINE);
+ printf("Select the partition type to create:\n");
+ printf(" 1=SOLARIS2 2=UNIX 3=PCIXOS 4=Other\n");
+ printf(" 5=DOS12 6=DOS16 7=DOSEXT 8=DOSBIG\n");
+ printf(" 9=DOS16LBA A=x86 Boot B=Diagnostic C=FAT32\n");
+ printf(" D=FAT32LBA E=DOSEXTLBA F=EFI 0=Exit? ");
+ gets(s);
+ rm_blanks(s);
+ if (s[1] != 0) {
+ printf(E_LINE);
+ printf("Invalid selection, try again.");
+ continue;
+ }
+ switch (s[0]) {
+ case '0': /* exit */
+ printf(E_LINE);
+ return (-1);
+ case '1': /* Solaris partition */
+ tsystid = SUNIXOS2;
+ break;
+ case '2': /* UNIX partition */
+ tsystid = UNIXOS;
+ break;
+ case '3': /* PCIXOS partition */
+ tsystid = PCIXOS;
+ break;
+ case '4': /* OTHEROS System partition */
+ tsystid = OTHEROS;
+ break;
+ case '5':
+ tsystid = DOSOS12; /* DOS 12 bit fat */
+ break;
+ case '6':
+ tsystid = DOSOS16; /* DOS 16 bit fat */
+ break;
+ case '7':
+ tsystid = EXTDOS;
+ break;
+ case '8':
+ tsystid = DOSHUGE;
+ break;
+ case '9':
+ tsystid = FDISK_FAT95; /* FAT16, need extended int13 */
+ break;
+ case 'a': /* x86 Boot partition */
+ case 'A':
+ tsystid = X86BOOT;
+ break;
+ case 'b': /* Diagnostic boot partition */
+ case 'B':
+ tsystid = DIAGPART;
+ break;
+ case 'c': /* FAT32 */
+ case 'C':
+ tsystid = FDISK_WINDOWS;
+ break;
+ case 'd': /* FAT32 and need extended int13 */
+ case 'D':
+ tsystid = FDISK_EXT_WIN;
+ break;
+ case 'e': /* Extended partition, need extended int13 */
+ case 'E':
+ tsystid = FDISK_EXTLBA;
+ break;
+ case 'f':
+ case 'F':
+ tsystid = EFI_PMBR;
+ break;
+ default:
+ printf(E_LINE);
+ printf("Invalid selection, try again.");
+ continue;
+ }
+ }
+
+ printf(E_LINE);
+
+ if (tsystid != EFI_PMBR) {
+ /* create the new partition */
+ i = specify(tsystid);
+
+ if (i != -1) {
+ /* see if it should be the active partition */
+ printf(E_LINE);
+ printf(Q_LINE);
+
+ printf("Should this become the active partition? If "
+ "yes, it will be activated\n");
+ printf("each time the computer is reset or turned "
+ "on.\n");
+ printf("Please type \"y\" or \"n\". ");
+
+ if (yesno()) {
+ printf(E_LINE);
+ for (j = 0; j < FD_NUMPART; j++) {
+ if (j == i) {
+ Table[j].bootid = ACTIVE;
+ printf(E_LINE);
+ printf("Partition %d is now "
+ "the active partition.",
+ j+1);
+ } else {
+ Table[j].bootid = 0;
+ }
+ }
+ } else {
+ Table[i].bootid = 0;
+ }
+
+ /* set up the return code */
+ i = 1;
+ }
+ } else {
+ /*
+ * partitions of type EFI_PMBR must be the only partitions in
+ * the table
+ *
+ * First, make sure there were no errors the table is
+ * empty
+ */
+ retCode = verify_tbl();
+
+ if (retCode < 0) {
+ fprintf(stderr,
+ "fdisk: Cannot create EFI partition table; \n"
+ "current partition table is invalid.\n");
+ return (-1);
+ } else if (retCode > 0) {
+ printf("An EFI partition must be the only partition on "
+ "disk. You may manually delete existing\n"
+ "partitions, or fdisk can do it.\n");
+ printf("Do you want fdisk to destroy existing "
+ "partitions?\n");
+ printf("Please type \"y\" or \"n\". ");
+
+ if (yesno()) {
+ nulltbl();
+ } else {
+ return (-1);
+ }
+ }
+
+ /* create the table entry - i should be 0 */
+ i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, rsect,
+ (Numcyl * heads * sectors) - rsect);
+
+ if (i != 0) {
+ printf("Error creating EFI partition!!!\n");
+ i = -1;
+ } else {
+
+ /* EFI partitions are currently never active */
+ Table[i].bootid = 0;
+
+ /* set up the return code */
+ i = 1;
+ }
+ }
+
+ return (i);
+}
+
+/*
+ * specify
+ * Query the user to specify the size of the new partition in
+ * terms of percentage of the disk or by specifying the starting
+ * cylinder and length in cylinders.
+ */
+specify(tsystid)
+unsigned char tsystid;
+{
+ int i, j,
+ percent = -1;
+ int cyl, cylen, first_free, size_free;
+ struct ipart *partition[FD_NUMPART];
+
+ printf(Q_LINE);
+ printf("Specify the percentage of disk to use for this partition\n");
+ printf("(or type \"c\" to specify the size in cylinders). ");
+ gets(s);
+ rm_blanks(s);
+ if (s[0] != 'c') { /* Specify size in percentage of disk */
+ i = 0;
+ while (s[i] != '\0') {
+ if (s[i] < '0' || s[i] > '9') {
+ printf(E_LINE);
+ printf("Invalid percentage value specified; retry"
+ " the operation.");
+ return (-1);
+ }
+ i++;
+ if (i > 3) {
+ printf(E_LINE);
+ printf("Invalid percentage value specified; retry"
+ " the operation.");
+ return (-1);
+ }
+ }
+ if ((percent = atoi(s)) > 100) {
+ printf(E_LINE);
+ printf("Percentage value is too large. The value must be"
+ " between 1 and 100;\nretry the operation.\n");
+ return (-1);
+ }
+ if (percent < 1) {
+ printf(E_LINE);
+ printf("Percentage value is too small. The value must be"
+ " between 1 and 100;\nretry the operation.\n");
+ return (-1);
+ }
+
+ cylen = (Numcyl * percent) / 100;
+ if ((percent < 100) && (((Numcyl * percent) % 10) > 5))
+ cylen++;
+
+ /* Verify that the DOS12 partition does not exceed the maximum */
+ /* size of 32MB. */
+ if ((tsystid == DOSOS12) && ((long)((long)cylen*heads*sectors) >
+ MAXDOS)) {
+ int n;
+ n = (int)(MAXDOS*100/(int)(heads*sectors)/Numcyl);
+ printf(E_LINE);
+ printf("Maximum size for a DOS partition is %d%%;"
+ " retry the operation.",
+ n <= 100 ? n : 100);
+ return (-1);
+ }
+
+ /* Before searching the partitions, sort them into sector order */
+ /* in the partition array, note that we only need to sort */
+ /* NUMPART-1 entries as at least the last one must be empty */
+ for (i = 0; i < FD_NUMPART; i++) partition[i] = &Table[i];
+
+ for (i = 0; i < FD_NUMPART-2; i++) {
+ if (partition[i]->systid == UNUSED) break;
+ for (j = i+1; j < FD_NUMPART-1; j++) {
+ if (partition[j]->systid == UNUSED) break;
+ if (lel(partition[j]->relsect) <
+ lel(partition[i]->relsect)) {
+ struct ipart *temp = partition[i];
+ partition[i] = partition[j];
+ partition[j] = temp;
+ }
+ }
+ }
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ int last_ent = 0;
+
+ /* Find start of current check area */
+ if (i) { /* Not an empty table */
+ first_free = lel(partition[i-1]->relsect) +
+ lel(partition[i-1]->numsect);
+ } else {
+ first_free = heads * sectors;
+ }
+
+ /* Determine size of current check area */
+ if (partition[i]->systid == UNUSED) {
+ /* Special case hack for whole unused disk */
+ if (percent == 100 && i == 0)
+ cylen--;
+ size_free = (Numcyl*heads*sectors) - first_free;
+ last_ent++;
+ } else {
+ if (i && ((lel(partition[i-1]->relsect) +
+ lel(partition[i-1]->numsect)) !=
+ lel(partition[i]->relsect))) {
+ /* There is a hole in table */
+ size_free = lel(partition[i]->relsect) -
+ (lel(partition[i-1]->relsect) +
+ lel(partition[i-1]->numsect));
+ } else if (i == 0) {
+ size_free = lel(partition[i]->relsect) -
+ heads*sectors;
+ } else {
+ size_free = 0;
+ }
+ }
+
+ if ((cylen*heads*sectors) <= size_free) {
+ /* We found a place to use */
+ break;
+ } else if (last_ent) {
+ size_free = 0;
+ break;
+ }
+ }
+ if (i < FD_NUMPART && size_free) {
+ printf(E_LINE);
+ if ((i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0,
+ first_free, cylen*heads*sectors)) < 0) {
+ fprintf(stderr,
+ "fdisk: Partition entry too big.\n");
+ return (-1);
+ }
+ } else {
+ printf(E_LINE);
+ fprintf(stderr, "fdisk: Partition entry too big.\n");
+ i = -1;
+ }
+ return (i);
+ } else { /* Specifying size in cylinders */
+
+ printf(E_LINE);
+ printf(Q_LINE);
+ printf("Enter starting cylinder number: ");
+ if ((cyl = getcyl()) == -1) {
+ printf(E_LINE);
+ printf("Invalid number; retry the operation.");
+ return (-1);
+ }
+ if (cyl == 0) {
+ printf(E_LINE);
+ printf("New partition cannot start at cylinder 0.\n");
+ return (-1);
+ }
+ if (cyl >= (unsigned int)Numcyl) {
+ printf(E_LINE);
+ printf("Cylinder %d is out of bounds, the maximum is %d.\n",
+ cyl, Numcyl - 1);
+ return (-1);
+ }
+ printf(Q_LINE);
+ printf("Enter partition size in cylinders: ");
+ if ((cylen = getcyl()) == -1) {
+ printf(E_LINE);
+ printf("Invalid number, retry the operation.");
+ return (-1);
+ }
+
+ /* Verify that the DOS12 partition does not exceed the maximum */
+ /* size of 32MB. */
+ if ((tsystid == DOSOS12) &&
+ ((long)((long)cylen*heads*sectors) > MAXDOS)) {
+ printf(E_LINE);
+ printf("Maximum size for a %s partition is %ld cylinders;"
+ "\nretry the operation.",
+ Dstr, MAXDOS/(int)(heads*sectors));
+ return (-1);
+ }
+
+ i = insert_tbl(tsystid, 0, 0, 0, 0, 0, 0, 0, cyl*heads*sectors,
+ cylen*heads*sectors);
+
+ if (verify_tbl() < 0) {
+ printf(E_LINE);
+ printf("fdisk: Cannot create partition table\n");
+ return (-1);
+ }
+
+ return (i);
+ }
+}
+
+/*
+ * dispmenu
+ * Display command menu (interactive mode).
+ */
+dispmenu(file)
+char *file;
+{
+ printf(M_LINE);
+ printf("SELECT ONE OF THE FOLLOWING:\n");
+ printf(" 1. Create a partition\n");
+ printf(" 2. Specify the active partition\n");
+ printf(" 3. Delete a partition\n");
+ printf(" 4. Change between Solaris and Solaris2 Partition IDs\n");
+ printf(" 5. Exit (update disk configuration and exit)\n");
+ printf(" 6. Cancel (exit without updating disk configuration)\n");
+}
+
+/*
+ * pchange
+ * Change the ACTIVE designation of a partition.
+ */
+pchange()
+{
+ char s[80];
+ int i, j;
+
+ while (1) {
+ printf(Q_LINE);
+ {
+ printf("Specify the partition number to boot from"
+ " (or specify 0 for none): ");
+ }
+ gets(s);
+ rm_blanks(s);
+ if ((s[1] != 0) || (s[0] < '0') || (s[0] > '4')) {
+ printf(E_LINE);
+ printf("Invalid response, please specify a number"
+ " between 0 and 4.\n");
+ } else {
+ break;
+ }
+ }
+ if (s[0] == '0') { /* No active partitions */
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid != UNUSED &&
+ Table[i].bootid == ACTIVE)
+ Table[i].bootid = 0;
+ }
+ printf(E_LINE);
+ printf("No partition is currently marked as active.");
+ return (0);
+ } else { /* User has selected a partition to be active */
+ i = s[0] - '1';
+ if (Table[i].systid == UNUSED) {
+ printf(E_LINE);
+ printf("Partition does not exist.");
+ return (-1);
+ }
+ /* a DOS-DATA or EXT-DOS partition cannot be active */
+ else if ((Table[i].systid == DOSDATA) ||
+ (Table[i].systid == EXTDOS) ||
+ (Table[i].systid == FDISK_EXTLBA)) {
+ printf(E_LINE);
+ printf("DOS-DATA, EXT_DOS and EXT_DOS_LBA partitions "
+ "cannot be made active.\n");
+ printf("Select another partition.");
+ return (-1);
+ }
+ Table[i].bootid = ACTIVE;
+ for (j = 0; j < FD_NUMPART; j++) {
+ if (j != i)
+ Table[j].bootid = 0;
+ }
+ }
+ printf(E_LINE);
+ {
+ printf("Partition %d is now active. The system will start up"
+ " from this\n", i+1);
+ printf("partition after the next reboot.");
+ }
+ return (1);
+}
+
+/*
+ * Change between SOLARIS and SOLARIS2 partition id
+ */
+ppartid()
+{
+ char *p, s[80];
+ int i;
+
+ for (;;) {
+ printf(Q_LINE);
+ printf("Specify the partition number to change"
+ " (or enter 0 to exit): ");
+ fgets(s, sizeof (s), stdin);
+ i = strtol(s, &p, 10);
+
+ if (*p != '\n' || i < 0 || i > FD_NUMPART) {
+ printf(E_LINE);
+ printf("Invalid response, retry the operation.\n");
+ continue;
+ }
+
+ if (i == 0) {
+ /* exit delete command */
+ printf(E_LINE); /* clear error message */
+ return (1);
+ }
+
+ i -= 1;
+ if (Table[i].systid == SUNIXOS) {
+ Table[i].systid = SUNIXOS2;
+ } else if (Table[i].systid == SUNIXOS2) {
+ Table[i].systid = SUNIXOS;
+ } else {
+ printf(E_LINE);
+ printf("Partition %d is not a Solaris partition.",
+ i + 1);
+ continue;
+ }
+
+ printf(E_LINE);
+ printf("Partition %d has been changed.", i + 1);
+ return (1);
+ }
+}
+
+/*
+ * pdelete
+ * Remove partition entry from the table (interactive mode).
+ */
+pdelete()
+{
+ char s[80];
+ int i, j;
+ char pactive;
+
+DEL1: printf(Q_LINE);
+ printf("Specify the partition number to delete"
+ " (or enter 0 to exit): ");
+ gets(s);
+ rm_blanks(s);
+ if ((s[0] == '0')) { /* exit delete command */
+ printf(E_LINE); /* clear error message */
+ return (1);
+ }
+ /* Accept only a single digit between 1 and 4 */
+ if (s[1] != 0 || (i = atoi(s)) < 1 || i > FD_NUMPART) {
+ printf(E_LINE);
+ printf("Invalid response, retry the operation.\n");
+ goto DEL1;
+ } else { /* Found a digit between 1 and 4 */
+ --i; /* Structure begins with element 0 */
+ }
+
+ if (Table[i].systid == UNUSED) {
+ printf(E_LINE);
+ printf("Partition %d does not exist.", i+1);
+ return (-1);
+ }
+
+ printf(Q_LINE);
+ printf("Are you sure you want to delete partition %d?"
+ " This will make all files and \n", i+1);
+ printf("programs in this partition inaccessible (type"
+ " \"y\" or \"n\"). ");
+
+ printf(E_LINE);
+ if (! yesno()) {
+ return (1);
+ }
+
+ if (Table[i].bootid == ACTIVE) {
+ pactive = 1;
+ } else {
+ pactive = 0;
+ }
+
+ for (j = i; j < FD_NUMPART - 1; j++) {
+ Table[j] = Table[j+1];
+ }
+
+ Table[j].systid = UNUSED;
+ Table[j].numsect = 0;
+ Table[j].relsect = 0;
+ Table[j].bootid = 0;
+ printf(E_LINE);
+ printf("Partition %d has been deleted.", i+1);
+
+ if (pactive) {
+ printf(" This was the active partition.");
+ }
+
+ return (1);
+}
+
+/*
+ * rm_blanks
+ * Remove blanks from strings of user responses.
+ */
+rm_blanks(s)
+char *s;
+{
+ register int i, j;
+
+ for (i = 0; i < CBUFLEN; i++) {
+ if ((s[i] == ' ') || (s[i] == '\t'))
+ continue;
+ else
+ /* Found first non-blank character of the string */
+ break;
+ }
+ for (j = 0; i < CBUFLEN; j++, i++) {
+ if ((s[j] = s[i]) == '\0') {
+ /* Reached end of string */
+ return;
+ }
+ }
+}
+
+/*
+ * getcyl
+ * Take the user-specified cylinder number and convert it from a
+ * string to a decimal value.
+ */
+getcyl()
+{
+int slen, i, j;
+unsigned int cyl;
+ gets(s);
+ rm_blanks(s);
+ slen = strlen(s);
+ 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);
+}
+
+/*
+ * disptbl
+ * Display the current fdisk table; determine percentage
+ * of the disk used for each partition.
+ */
+disptbl()
+{
+ int i;
+ unsigned int startcyl, endcyl, length, percent, remainder;
+ char *stat, *type;
+ unsigned char *t;
+
+ if ((heads == 0) || (sectors == 0)) {
+ printf("WARNING: critical disk geometry information"
+ " missing!\n");
+ printf("\theads = %d, sectors = %d\n", heads, sectors);
+ exit(1);
+ }
+
+ printf(HOME);
+ printf(T_LINE);
+ printf(" Total disk size is %d cylinders\n", Numcyl);
+ printf(" Cylinder size is %d (512 byte) blocks\n\n",
+ heads*sectors);
+ printf(" Cylinders\n");
+ printf(" Partition Status Type Start End Length"
+ " %%\n");
+ printf(" ========= ====== ============ ===== === ======"
+ " ===");
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid == UNUSED) {
+ printf("\n");
+ printf(CLR_LIN);
+ continue;
+ }
+ if (Table[i].bootid == ACTIVE)
+ stat = Actvstr;
+ else
+ stat = NAstr;
+ switch (Table[i].systid) {
+ case UNIXOS:
+ type = Ustr;
+ break;
+ case SUNIXOS:
+ type = SUstr;
+ 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_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;
+ break;
+ default:
+ type = Ostr;
+ break;
+ }
+ t = &Table[i].bootid;
+ startcyl = lel(Table[i].relsect)/(heads*sectors);
+ length = lel(Table[i].numsect) / (long)(heads * sectors);
+ if (lel(Table[i].numsect) % (long)(heads * sectors))
+ length++;
+ endcyl = startcyl + length - 1;
+ percent = length * 100 / Numcyl;
+ if ((remainder = (length*100 % Numcyl)) != 0) {
+ if ((remainder * 100 / Numcyl) > 50) {
+ /* round up */
+ percent++;
+ }
+ /* Else leave the percent as is since it's already */
+ /* rounded down */
+ }
+ if (percent > 100)
+ percent = 100;
+ printf("\n %d %s %-12.12s %4d %4d %4d"
+ " %3d", i+1, stat, type, startcyl, endcyl, length,
+ percent);
+ }
+ /* Print warning message if table is empty */
+ if (Table[0].systid == UNUSED) {
+ printf(W_LINE);
+ printf("WARNING: no partitions are defined!");
+ } else {
+ /* Clear the warning line */
+ printf(W_LINE);
+ }
+}
+
+/*
+ * print_Table
+ * Write the detailed fdisk table to standard error for
+ * the selected disk device.
+ */
+print_Table() {
+ int i;
+
+ fprintf(stderr,
+ " SYSID ACT BHEAD BSECT BEGCYL EHEAD ESECT ENDCYL RELSECT"
+ " NUMSECT\n");
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ fprintf(stderr, " %-5d ", Table[i].systid);
+ fprintf(stderr, "%-3d ", Table[i].bootid);
+ fprintf(stderr, "%-5d ", Table[i].beghead);
+ fprintf(stderr, "%-5d ", Table[i].begsect & 0x3f);
+ fprintf(stderr, "%-8d ", (((uint_t)Table[i].begsect &
+ 0xc0) << 2) + Table[i].begcyl);
+
+ fprintf(stderr, "%-5d ", Table[i].endhead);
+ fprintf(stderr, "%-5d ", Table[i].endsect & 0x3f);
+ fprintf(stderr, "%-8d ", (((uint_t)Table[i].endsect &
+ 0xc0) << 2) + Table[i].endcyl);
+ fprintf(stderr, "%-9d ", lel(Table[i].relsect));
+ fprintf(stderr, "%-9d\n", lel(Table[i].numsect));
+
+ }
+}
+
+/*
+ * copy_Table_to_Old_Table
+ * Copy Table into Old_Table. The function only copies the systid,
+ * numsect, relsect, and bootid values because they are the only
+ * ones compared when determining if Table has changed.
+ */
+copy_Table_to_Old_Table()
+{
+ int i;
+ for (i = 0; i < FD_NUMPART; i++) {
+ memcpy(&Old_Table[i], &Table[i], sizeof (Table[0]));
+ }
+}
+
+/*
+ * nulltbl
+ * Zero out the systid, numsect, relsect, and bootid values in the
+ * fdisk table.
+ */
+nulltbl()
+{
+ int i;
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ Table[i].systid = UNUSED;
+ Table[i].numsect = lel(UNUSED);
+ Table[i].relsect = lel(UNUSED);
+ Table[i].bootid = 0;
+ }
+}
+
+/*
+ * copy_Bootblk_to_Table
+ * Copy the bytes from the boot record to an internal "Table".
+ * All unused are padded with zeros starting at offset 446.
+ */
+copy_Bootblk_to_Table()
+{
+ int i, j;
+ char *bootptr;
+ unsigned char *tbl_ptr;
+ int tblpos;
+ void fill_ipart(char *, struct ipart *);
+ struct ipart iparts[FD_NUMPART];
+
+ /* Get an aligned copy of the partition tables */
+ memcpy(iparts, Bootblk->parts, sizeof (iparts));
+ tbl_ptr = &Table[0].bootid;
+ bootptr = (char *)iparts; /* Points to start of partition table */
+ if (les(Bootblk->signature) != MBB_MAGIC) {
+ /* Signature is missing */
+ nulltbl();
+ memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
+ return;
+ }
+ /*
+ * When the DOS fdisk command deletes a partition, it is not
+ * recognized by the old algorithm. The algorithm that
+ * follows looks at each entry in the Bootrec and copies all
+ * those that are valid.
+ */
+ j = 0;
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (iparts[i].systid == 0) {
+ /* Null entry */
+ bootptr += sizeof (struct ipart);
+ } else {
+ (void) fill_ipart(bootptr, &Table[j]);
+ j++;
+ bootptr += sizeof (struct ipart);
+ }
+ }
+ for (i = j; i < FD_NUMPART; i++) {
+ Table[i].systid = UNUSED;
+ Table[i].numsect = lel(UNUSED);
+ Table[i].relsect = lel(UNUSED);
+ Table[i].bootid = 0;
+
+ }
+ /* For now, always replace the bootcode with ours */
+ memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
+ copy_Table_to_Bootblk();
+}
+
+/*
+ * fill_ipart
+ * Initialize ipart structure values.
+ */
+void
+fill_ipart(char *bootptr, struct ipart *partp)
+{
+#ifdef sparc
+ /* Packing struct ipart for 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 = getlong(&bootptr);
+ partp->numsect = getlong(&bootptr);
+#else
+ *partp = *(struct ipart *)bootptr;
+#endif
+}
+
+/*
+ * getbyte, getshort, getlong
+ * Get a byte, a short, or a long (SPARC only).
+ */
+#ifdef sparc
+getbyte(uchar_t **bp)
+{
+ int b;
+
+ b = **bp;
+ *bp = *bp + 1;
+ return (b);
+}
+
+getshort(uchar_t **bp)
+{
+ int b;
+
+ b = ((**bp) << 8) | *(*bp + 1);
+ *bp += 2;
+ return (b);
+}
+
+getlong(uchar_t **bp)
+{
+ int b, bh, bl;
+
+ bh = ((**bp) << 8) | *(*bp + 1);
+ *bp += 2;
+ bl = ((**bp) << 8) | *(*bp + 1);
+ *bp += 2;
+
+ b = (bh << 16) | bl;
+ return (b);
+}
+#endif
+
+/*
+ * copy_Table_to_Bootblk
+ * Copy the table into the 512 boot record. Note that the unused
+ * entries will always be the last ones in the table and they are
+ * marked with 100 in sysind. The the unused portion of the table
+ * is padded with zeros in the bytes after the used entries.
+ */
+copy_Table_to_Bootblk()
+{
+ 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)
+ memset(boot_ptr, 0, sizeof (struct ipart));
+ else
+ memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart));
+ }
+ Bootblk->signature = les(MBB_MAGIC);
+}
+
+/*
+ * TableChanged
+ * Check for any changes in the partition table.
+ */
+TableChanged()
+{
+ int i, changed;
+
+ changed = 0;
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (memcmp(&Old_Table[i], &Table[i], sizeof (Table[0])) != 0) {
+ /* Partition table changed, write back to disk */
+ changed = 1;
+ }
+ }
+
+ return (changed);
+}
+
+/*
+ * ffile_write
+ * Display contents of partition table to standard output or
+ * another file name without writing it to the disk (-W file).
+ */
+ffile_write(file)
+char *file;
+{
+ register int i;
+ register int c;
+ FILE *fp;
+
+ /*
+ * If file isn't standard output, then it's a file name.
+ * Open file and write it.
+ */
+ 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;
+
+ /*
+ * Write the fdisk table information
+ */
+ fprintf(fp, "\n* %s default fdisk table\n", Dfltdev);
+ fprintf(fp, "* Dimensions:\n");
+ fprintf(fp, "* %4d bytes/sector\n", sectsiz);
+ fprintf(fp, "* %4d sectors/track\n", sectors);
+ fprintf(fp, "* %4d tracks/cylinder\n", heads);
+ fprintf(fp, "* %4d cylinders\n", Numcyl);
+ fprintf(fp, "*\n");
+ /* Write virtual (HBA) geometry, if required */
+ if (v_flag) {
+ fprintf(fp, "* HBA Dimensions:\n");
+ fprintf(fp, "* %4d bytes/sector\n", sectsiz);
+ fprintf(fp, "* %4d sectors/track\n", hba_sectors);
+ fprintf(fp, "* %4d tracks/cylinder\n", hba_heads);
+ fprintf(fp, "* %4d cylinders\n", hba_Numcyl);
+ fprintf(fp, "*\n");
+ }
+ fprintf(fp, "* systid:\n");
+ fprintf(fp, "* 1: DOSOS12\n");
+ fprintf(fp, "* 2: PCIXOS\n");
+ fprintf(fp, "* 4: DOSOS16\n");
+ fprintf(fp, "* 5: EXTDOS\n");
+ fprintf(fp, "* 6: DOSBIG\n");
+ fprintf(fp, "* 7: FDISK_IFS\n");
+ fprintf(fp, "* 8: FDISK_AIXBOOT\n");
+ fprintf(fp, "* 9: FDISK_AIXDATA\n");
+ fprintf(fp, "* 10: FDISK_0S2BOOT\n");
+ fprintf(fp, "* 11: FDISK_WINDOWS\n");
+ fprintf(fp, "* 12: FDISK_EXT_WIN\n");
+ fprintf(fp, "* 14: FDISK_FAT95\n");
+ fprintf(fp, "* 15: FDISK_EXTLBA\n");
+ fprintf(fp, "* 18: DIAGPART\n");
+ fprintf(fp, "* 65: FDISK_LINUX\n");
+ fprintf(fp, "* 82: FDISK_CPM\n");
+ fprintf(fp, "* 86: DOSDATA\n");
+ fprintf(fp, "* 98: OTHEROS\n");
+ fprintf(fp, "* 99: UNIXOS\n");
+ fprintf(fp, "* 101: FDISK_NOVELL3\n");
+ fprintf(fp, "* 119: FDISK_QNX4\n");
+ fprintf(fp, "* 120: FDISK_QNX42\n");
+ fprintf(fp, "* 121: FDISK_QNX43\n");
+ fprintf(fp, "* 130: SUNIXOS\n");
+ fprintf(fp, "* 131: FDISK_LINUXNAT\n");
+ fprintf(fp, "* 134: FDISK_NTFSVOL1\n");
+ fprintf(fp, "* 135: FDISK_NTFSVOL2\n");
+ fprintf(fp, "* 165: FDISK_BSD\n");
+ fprintf(fp, "* 167: FDISK_NEXTSTEP\n");
+ fprintf(fp, "* 183: FDISK_BSDIFS\n");
+ fprintf(fp, "* 184: FDISK_BSDISWAP\n");
+ fprintf(fp, "* 190: X86BOOT\n");
+ fprintf(fp, "* 191: SUNIXOS2\n");
+ fprintf(fp, "* 238: EFI_PMBR\n");
+ fprintf(fp, "* 239: EFI_FS\n");
+ fprintf(fp, "*\n");
+ fprintf(fp,
+ "\n* Id Act Bhead Bsect Bcyl Ehead Esect Ecyl"
+ " Rsect Numsect\n");
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid != UNUSED)
+ fprintf(fp,
+ " %-5d %-4d %-6d %-6d %-7d %-6d %-6d %-7d %-8d"
+ " %-8d\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)),
+ lel(Table[i].relsect),
+ lel(Table[i].numsect));
+ }
+ if (fp != stdout)
+ fclose(fp);
+}
+
+/*
+ * fix_slice
+ * Read the VTOC table on the Solaris partition and check that no
+ * slices exist that extend past the end of the Solaris partition.
+ * If no Solaris partition exists, nothing is done.
+ */
+fix_slice()
+{
+ int i;
+ int ret;
+ int numsect;
+
+ if (io_image) {
+ return (0);
+ }
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (Table[i].systid == SUNIXOS || Table[i].systid == SUNIXOS2) {
+ /*
+ * Only the size matters (not starting point), since
+ * VTOC entries are relative to the start of
+ * the partition.
+ */
+ numsect = lel(Table[i].numsect);
+ break;
+ }
+ }
+
+ if (i >= FD_NUMPART) {
+ if (!io_nifdisk) {
+ (void) fprintf(stderr,
+ "fdisk: No Solaris partition found - VTOC not"
+ " checked.\n");
+ }
+ return (1);
+ }
+
+ if ((ret = readvtoc()) != VTOC_OK) {
+ exit(1); /* Failed to read the VTOC */
+ } else {
+ for (i = 0; i < V_NUMPAR; i++) {
+ /* Special case for slice two (entire disk) */
+ if (i == 2) {
+ if (disk_vtoc.v_part[i].p_start != 0) {
+ (void) fprintf(stderr,
+ "slice %d starts at %d, is not at"
+ " start of partition",
+ i, disk_vtoc.v_part[i].p_start);
+ if (!io_nifdisk) {
+ 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 %d does not cover"
+ " complete partition",
+ i, disk_vtoc.v_part[i].p_size);
+ if (!io_nifdisk) {
+ 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) {
+ 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");
+ }
+ }
+ } else {
+ 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 %d, end %d) 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) {
+ 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 >
+ numsect) {
+ (void) fprintf(stderr,
+ "slice %d (start %d) is larger"
+ " than the partition",
+ i, disk_vtoc.v_part[i].p_start);
+ if (!io_nifdisk) {
+ 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 %d) is larger"
+ " than the partition",
+ i,
+ disk_vtoc.v_part[i].p_start +
+ disk_vtoc.v_part[i].p_size);
+ if (!io_nifdisk) {
+ 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 /* bh for now */
+ /* Make the VTOC look sane - ha ha */
+ 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
+
+ /* Write the VTOC back to the disk */
+ if (!io_readonly)
+ writevtoc();
+}
+
+/*
+ * yesno
+ * Get yes or no answer. Return 1 for yes and 0 for no.
+ */
+
+yesno()
+{
+ char s[80];
+
+ for (;;) {
+ gets(s);
+ rm_blanks(s);
+ if ((s[1] != 0) || ((s[0] != 'y') && (s[0] != 'n'))) {
+ printf(E_LINE);
+ printf("Please answer with \"y\" or \"n\": ");
+ continue;
+ }
+ if (s[0] == 'y')
+ return (1);
+ else
+ return (0);
+ }
+}
+
+/*
+ * readvtoc
+ * Read the VTOC from the Solaris partition of the device.
+ */
+readvtoc()
+{
+ int i;
+ int retval = VTOC_OK;
+
+ if ((i = read_vtoc(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);
+}
+
+/*
+ * writevtoc
+ * Write the VTOC to the Solaris partition on the device.
+ */
+writevtoc()
+{
+ int i;
+ int retval = 0;
+
+ if ((i = write_vtoc(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);
+}
+
+/*
+ * efi_ioctl
+ * issues DKIOCSETEFI IOCTL
+ * (duplicate of private efi_ioctl() in rdwr_efi.c
+ */
+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);
+}
+
+/*
+ * clear_efi
+ * Clear EFI labels from the EFI_PMBR partition on the device
+ * This function is modeled on the libefi(3LIB) call efi_write()
+ */
+int
+clear_efi()
+{
+ struct dk_gpt *efi_vtoc;
+ dk_efi_t dk_ioc;
+
+ /*
+ * see if we can read the EFI label
+ */
+ if (efi_alloc_and_read(Dev, &efi_vtoc) < 0) {
+ return (VT_ERROR);
+ }
+
+ /*
+ * set up the dk_ioc structure for writing
+ */
+ 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);
+ }
+
+ /*
+ * clear the primary label
+ */
+ if (io_debug) {
+ fprintf(stderr, "\tClearing primary EFI label at block "
+ "%d\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);
+ }
+ }
+
+ /*
+ * clear the backup partition table
+ */
+ dk_ioc.dki_lba = efi_vtoc->efi_last_u_lba + 1;
+ dk_ioc.dki_length -= efi_vtoc->efi_lbasize;
+ dk_ioc.dki_data++;
+ if (io_debug) {
+ fprintf(stderr, "\tClearing backup partition table at block "
+ "%d\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);
+ }
+
+ /*
+ * clear the backup label
+ */
+ dk_ioc.dki_lba = efi_vtoc->efi_last_lba;
+ dk_ioc.dki_length = efi_vtoc->efi_lbasize;
+ dk_ioc.dki_data--;
+ if (io_debug) {
+ fprintf(stderr, "\tClearing backup label at block "
+ "%d\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);
+}
+
+/*
+ * clear_vtoc
+ * Clear the VTOC from the current or previous Solaris partition on the
+ * device.
+ */
+int
+clear_vtoc(int table, int part)
+{
+ struct ipart *clr_table;
+ struct dk_label disk_label;
+ int pcyl, ncyl, backup_block, solaris_offset, count, bytes, seek_byte;
+
+#ifdef DEBUG
+ struct dk_label read_label;
+#endif /* DEBUG */
+
+ if (table == OLD) {
+ clr_table = &Old_Table[part];
+ } else {
+ clr_table = &Table[part];
+ }
+
+ if (memset(&disk_label, 0, sizeof (struct dk_label)) == NULL) {
+ fprintf(stderr, "\tError zeroing dk_label structure\n");
+ }
+
+ seek_byte = (lel(clr_table->relsect) * sectsiz) + VTOC_OFFSET;
+
+ if (io_debug) {
+ fprintf(stderr, "\tClearing primary VTOC at byte %d\n",
+ seek_byte);
+ }
+
+ if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
+ fprintf(stderr, "\tError seeking to primary label at byte %d\n",
+ seek_byte);
+ return (0);
+ }
+
+ bytes = write(Dev, &disk_label, sizeof (struct dk_label));
+
+ if (bytes != sizeof (struct dk_label)) {
+ fprintf(stderr, "\tWarning: only %d bytes written to clear"
+ " primary VTOC!\n", bytes);
+ }
+
+#ifdef DEBUG
+ if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
+ fprintf(stderr, "DEBUG: Error seeking to primary label at byte "
+ "%d\n", seek_byte);
+ return (0);
+ } else {
+ fprintf(stderr, "DEBUG: Successful lseek() to byte %d\n",
+ seek_byte);
+ }
+
+ bytes = read(Dev, &read_label, sizeof (struct dk_label));
+
+ if (bytes != sizeof (struct dk_label)) {
+ fprintf(stderr, "DEBUG: Warning: only %d bytes read of label\n",
+ bytes);
+ }
+
+ if (memcmp(&disk_label, &read_label, sizeof (struct dk_label)) != 0) {
+ fprintf(stderr, "DEBUG: Warning: disk_label and read_label "
+ "differ!!!\n");
+ } else {
+ fprintf(stderr, "DEBUG Good compare of disk_label and "
+ "read_label\n");
+ }
+#endif /* DEBUG */
+
+ /* Clear backup label */
+ pcyl = lel(clr_table->numsect) / (heads * sectors);
+ solaris_offset = lel(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 = (solaris_offset + backup_block) * 512;
+
+ if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
+ fprintf(stderr,
+ "\tError seeking to backup label at byte %d on "
+ "%s.\n", seek_byte, Dfltdev);
+ return (0);
+ }
+
+ if (io_debug) {
+ fprintf(stderr, "\tClearing backup VTOC at"
+ " byte %d (block %d)\n",
+ (solaris_offset + backup_block) * 512,
+ (solaris_offset + backup_block));
+ }
+
+ bytes = write(Dev, &disk_label, sizeof (struct dk_label));
+
+ if (bytes != sizeof (struct dk_label)) {
+ fprintf(stderr, "\t\tWarning: only %d bytes written to "
+ "clear backup VTOC at block %d!\n", bytes,
+ (solaris_offset + backup_block));
+ }
+
+#ifdef DEBUG
+ if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
+ fprintf(stderr, "DEBUG: Error seeking to backup label at byte "
+ "%d\n", seek_byte);
+ return (0);
+ } else {
+ fprintf(stderr, "DEBUG: Successful lseek() to byte %d\n",
+ seek_byte);
+ }
+
+ bytes = read(Dev, &read_label, sizeof (struct dk_label));
+
+ if (bytes != sizeof (struct dk_label)) {
+ fprintf(stderr, "DEBUG: Warning: only %d bytes read of backup "
+ "label\n", bytes);
+ }
+
+ if (memcmp(&disk_label, &read_label, sizeof (struct dk_label)) != 0) {
+ fprintf(stderr, "DEBUG: Warning: disk_label and read_label "
+ "differ!!!\n");
+ } else {
+ fprintf(stderr, "DEBUG: Good compare of disk_label and backup "
+ "read_label\n");
+ }
+#endif /* DEBUG */
+
+ backup_block += 2;
+ }
+
+ return (0);
+}
+
+#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) "
+
+/*
+ * lecture_and_query
+ * Called when a sanity check fails. This routine gives a warning
+ * specific to the check that fails, followed by a generic lecture
+ * about the "right" device to supply as input. Then, if appropriate,
+ * it will prompt the user on whether or not they want to continue.
+ * Inappropriate times for prompting are when the user has selected
+ * non-interactive mode or read-only mode.
+ */
+int
+lecture_and_query(char *warning, char *devname)
+{
+ if (io_nifdisk)
+ return (0);
+
+ fprintf(stderr, "WARNING: Device %s: \n", devname);
+ fprintf(stderr, "%s", warning);
+ fprintf(stderr, FDISK_STANDARD_LECTURE);
+ fprintf(stderr, FDISK_SHALL_I_CONTINUE);
+
+ return (yesno());
+}
+
+void
+sanity_check_provided_device(char *devname, int fd)
+{
+ struct vtoc v;
+ struct dk_geom d;
+ struct part_info pi;
+ long totsize;
+ int idx = -1;
+
+ /*
+ * First try the PARTINFO ioctl. If it works, we will be able
+ * to tell if they've specified the full disk partition by checking
+ * to see if they've specified a partition that starts at sector 0.
+ */
+ 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_vtoc(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 = 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);
+ }
+ }
+ }
+}
+
+
+/*
+ * get_node
+ * Called from main to construct the name of the device node to open.
+ * Initially tries to stat the node exactly as provided, if that fails
+ * we prepend the default path (/dev/rdsk/).
+ */
+static char *
+get_node(char *devname)
+{
+ char *node;
+ struct stat statbuf;
+ size_t space;
+
+ /* Don't do anything if we are skipping device checks */
+ if (io_image)
+ return (devname);
+
+ node = devname;
+
+ /* Try the node as provided first */
+ if (stat(node, (struct stat *)&statbuf) == -1) {
+ /*
+ * Copy the passed in string to a new buffer, prepend the
+ * default path and try again.
+ */
+ space = strlen(DEFAULT_PATH) + strlen(devname) + 1;
+
+ if ((node = malloc(space)) == NULL) {
+ fprintf(stderr, "fdisk: Unable to obtain memory "
+ "for device node.\n");
+ exit(1);
+ }
+
+ /* Copy over the default path and the provided node */
+ (void) strncpy(node, DEFAULT_PATH, strlen(DEFAULT_PATH));
+ space -= strlen(DEFAULT_PATH);
+ (void) strlcpy(node + strlen(DEFAULT_PATH), devname, space);
+
+ /* Try to stat it again */
+ if (stat(node, (struct stat *)&statbuf) == -1) {
+ /* Failed all options, give up */
+ fprintf(stderr, "fdisk: Cannot stat device %s.\n",
+ devname);
+ exit(1);
+ }
+ }
+
+ /* Make sure the device specified is the raw device */
+ if ((statbuf.st_mode & S_IFMT) != S_IFCHR) {
+ fprintf(stderr, "fdisk: %s must be a raw device.\n", node);
+ exit(1);
+ }
+
+ return (node);
+}