summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr/src/Makefile.lint3
-rw-r--r--usr/src/Targetdirs11
-rw-r--r--usr/src/cmd/boot/installgrub/Makefile10
-rw-r--r--usr/src/cmd/boot/installgrub/installgrub.c67
-rw-r--r--usr/src/cmd/boot/installgrub/message.h10
-rw-r--r--usr/src/cmd/devfsadm/disk_link.c49
-rw-r--r--usr/src/cmd/fdisk/Makefile10
-rw-r--r--usr/src/cmd/fdisk/fdisk.c1770
-rw-r--r--usr/src/cmd/format/Makefile7
-rw-r--r--usr/src/cmd/format/menu_fdisk.c221
-rw-r--r--usr/src/lib/Makefile8
-rw-r--r--usr/src/lib/libfdisk/Makefile64
-rw-r--r--usr/src/lib/libfdisk/i386/Makefile83
-rw-r--r--usr/src/lib/libfdisk/i386/libfdisk.c1372
-rw-r--r--usr/src/lib/libfdisk/i386/libfdisk.h304
-rw-r--r--usr/src/lib/libfdisk/i386/llib-lfdisk31
-rw-r--r--usr/src/lib/libfdisk/i386/mapfile-vers65
-rw-r--r--usr/src/pkgdefs/SUNWarc/prototype_i3864
-rw-r--r--usr/src/pkgdefs/SUNWarcr/prototype_i3864
-rw-r--r--usr/src/pkgdefs/SUNWcsl/prototype_i3862
-rw-r--r--usr/src/pkgdefs/SUNWcslr/prototype_i3864
-rw-r--r--usr/src/pkgdefs/SUNWhea/prototype_i3863
-rw-r--r--usr/src/uts/common/io/cmlb.c552
-rw-r--r--usr/src/uts/common/io/scsi/targets/sd.c6
-rw-r--r--usr/src/uts/common/sys/cmlb_impl.h20
-rw-r--r--usr/src/uts/common/sys/dkio.h5
-rw-r--r--usr/src/uts/common/sys/dktp/fdisk.h31
-rw-r--r--usr/src/uts/common/sys/scsi/targets/sddef.h10
-rw-r--r--usr/src/uts/common/xen/io/xdf.c1
-rw-r--r--usr/src/uts/i86pc/i86hvm/io/xdf_shell.c9
-rw-r--r--usr/src/uts/intel/io/dktp/disk/cmdk.c1
31 files changed, 4598 insertions, 139 deletions
diff --git a/usr/src/Makefile.lint b/usr/src/Makefile.lint
index 5db3761aa9..865e36e348 100644
--- a/usr/src/Makefile.lint
+++ b/usr/src/Makefile.lint
@@ -475,7 +475,8 @@ i386_SUBDIRS= \
cmd/rtc \
cmd/ucodeadm \
lib/brand/lx \
- lib/cfgadm_plugins/sata
+ lib/cfgadm_plugins/sata \
+ lib/libfdisk
sparc_SUBDIRS= \
cmd/datadm \
diff --git a/usr/src/Targetdirs b/usr/src/Targetdirs
index ea2b61a2e8..cefa12dff8 100644
--- a/usr/src/Targetdirs
+++ b/usr/src/Targetdirs
@@ -925,6 +925,8 @@ $(ROOT)/usr/lib/libefi.so.1:= REALPATH=../../lib/libefi.so.1
$(ROOT)/usr/lib/libefi.so:= REALPATH=../../lib/libefi.so.1
$(ROOT)/usr/lib/libelf.so.1:= REALPATH=../../lib/libelf.so.1
$(ROOT)/usr/lib/libelf.so:= REALPATH=../../lib/libelf.so.1
+$(ROOT)/usr/lib/libfdisk.so.1:= REALPATH=../../lib/libfdisk.so.1
+$(ROOT)/usr/lib/libfdisk.so:= REALPATH=../../lib/libfdisk.so.1
$(ROOT)/usr/lib/libgen.so.1:= REALPATH=../../lib/libgen.so.1
$(ROOT)/usr/lib/libgen.so:= REALPATH=../../lib/libgen.so.1
$(ROOT)/usr/lib/libinetcfg.so.1:= REALPATH=../../lib/libinetcfg.so.1
@@ -1049,6 +1051,8 @@ $(ROOT)/usr/lib/llib-lefi.ln:= REALPATH=../../lib/llib-lefi.ln
$(ROOT)/usr/lib/llib-lefi:= REALPATH=../../lib/llib-lefi
$(ROOT)/usr/lib/llib-lelf.ln:= REALPATH=../../lib/llib-lelf.ln
$(ROOT)/usr/lib/llib-lelf:= REALPATH=../../lib/llib-lelf
+$(ROOT)/usr/lib/llib-lfdisk.ln:= REALPATH=../../lib/llib-lfdisk.ln
+$(ROOT)/usr/lib/llib-lfdisk:= REALPATH=../../lib/llib-lfdisk
$(ROOT)/usr/lib/llib-lgen.ln:= REALPATH=../../lib/llib-lgen.ln
$(ROOT)/usr/lib/llib-lgen:= REALPATH=../../lib/llib-lgen
$(ROOT)/usr/lib/llib-linetcfg.ln:= REALPATH=../../lib/llib-linetcfg.ln
@@ -1471,7 +1475,14 @@ $(ROOT)/usr/lib/$(MACH64)/nss_nisplus.so.1:= \
$(ROOT)/usr/lib/$(MACH64)/nss_user.so.1:= \
REALPATH=../../../lib/$(MACH64)/nss_user.so.1
+i386_SYM.USRLIB= \
+ /usr/lib/libfdisk.so \
+ /usr/lib/libfdisk.so.1 \
+ /usr/lib/llib-lfdisk \
+ /usr/lib/llib-lfdisk.ln
+
SYM.USRLIB= \
+ $($(MACH)_SYM.USRLIB) \
/lib/libposix4.so \
/lib/libposix4.so.1 \
/lib/llib-lposix4 \
diff --git a/usr/src/cmd/boot/installgrub/Makefile b/usr/src/cmd/boot/installgrub/Makefile
index 125c3a7ad8..39aa17462b 100644
--- a/usr/src/cmd/boot/installgrub/Makefile
+++ b/usr/src/cmd/boot/installgrub/Makefile
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
#
@@ -37,11 +37,17 @@ CPPFLAGS += -I$(SRC)/uts/i86pc -I$(SRC)/uts/intel -I$(SRC)/uts/common
LDLIBS += -lmd5
+i386_CFLAGS += -D_LARGEFILE64_SOURCE
+i386_CFLAGS += -D_FILE_OFFSET_BITS=64
+
+LDLIBS += -lfdisk
+
LINTFLAGS += \
-erroff=E_BAD_PTR_CAST_ALIGN \
-erroff=E_STATIC_UNUSED \
-erroff=E_FUNC_RET_MAYBE_IGNORED \
- -erroff=E_FUNC_RET_MAYBE_IGNORED2
+ -erroff=E_FUNC_RET_MAYBE_IGNORED2 \
+ -xerroff=E_NAME_DEF_NOT_USED2
.KEEP_STATE:
diff --git a/usr/src/cmd/boot/installgrub/installgrub.c b/usr/src/cmd/boot/installgrub/installgrub.c
index c233cded29..f37f1430f5 100644
--- a/usr/src/cmd/boot/installgrub/installgrub.c
+++ b/usr/src/cmd/boot/installgrub/installgrub.c
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -43,6 +43,7 @@
#include <locale.h>
#include "message.h"
#include <errno.h>
+#include <libfdisk.h>
#include <md5.h>
#ifndef TEXT_DOMAIN
@@ -83,7 +84,8 @@ static int is_bootpar = 0;
static int strip = 0;
static int stage2_fd;
static int partition, slice = 0xff;
-static unsigned int stage2_first_sector, stage2_second_sector;
+static char *device_p0;
+static uint32_t stage2_first_sector, stage2_second_sector;
static char bpb_sect[SECTOR_SIZE];
@@ -226,10 +228,11 @@ static unsigned int
get_start_sector(int fd)
{
static unsigned int start_sect = 0;
-
- int i;
+ uint32_t secnum, numsec;
+ int i, pno, rval, ext_sol_part_found = 0;
struct mboot *mboot;
struct ipart *part;
+ ext_part_t *epp;
if (start_sect)
return (start_sect);
@@ -243,6 +246,44 @@ get_start_sector(int fd)
}
}
+ /* Read extended partition to find a solaris partition */
+ if ((rval = libfdisk_init(&epp, device_p0, NULL, FDISK_READ_DISK))
+ != FDISK_SUCCESS) {
+ switch (rval) {
+ /*
+ * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
+ * be considered as soft errors and hence
+ * we do not exit
+ */
+ case FDISK_EBADLOGDRIVE:
+ break;
+ case FDISK_ENOLOGDRIVE:
+ break;
+ case FDISK_ENOVGEOM:
+ (void) fprintf(stderr, NO_VIRT_GEOM);
+ exit(1);
+ break;
+ case FDISK_ENOPGEOM:
+ (void) fprintf(stderr, NO_PHYS_GEOM);
+ exit(1);
+ break;
+ case FDISK_ENOLGEOM:
+ (void) fprintf(stderr, NO_LABEL_GEOM);
+ exit(1);
+ break;
+ default:
+ (void) fprintf(stderr, LIBFDISK_INIT_FAIL);
+ exit(1);
+ break;
+ }
+ }
+
+ rval = fdisk_get_solaris_part(epp, &pno, &secnum, &numsec);
+ if (rval == FDISK_SUCCESS) {
+ ext_sol_part_found = 1;
+ }
+ libfdisk_fini(&epp);
+
/*
* If there is no boot partition, find the solaris partition
*/
@@ -272,6 +313,7 @@ get_start_sector(int fd)
(void) fprintf(stderr, BAD_PART, i);
exit(-1);
}
+
if (edkpi.p_start >= part->relsect &&
edkpi.p_start < (part->relsect + part->numsect)) {
/* Found the partition */
@@ -280,7 +322,7 @@ get_start_sector(int fd)
}
}
- if (i == FD_NUMPART) {
+ if ((i == FD_NUMPART) && (!ext_sol_part_found)) {
(void) fprintf(stderr, BOOTPAR);
exit(-1);
}
@@ -294,12 +336,18 @@ get_start_sector(int fd)
}
}
- start_sect = part->relsect;
+ if (fdisk_is_dos_extended(part->systid)) {
+ start_sect = secnum;
+ partition = pno;
+ } else {
+ start_sect = part->relsect;
+ partition = i;
+ }
+
if (part->bootid != 128 && write_mboot == 0) {
(void) fprintf(stdout, BOOTPAR_INACTIVE, i + 1);
}
- partition = i;
return (start_sect);
}
@@ -395,6 +443,7 @@ read_boot_sect(char *device)
device[i - 2] = 'p';
device[i - 1] = '0';
+ device_p0 = strdup(device);
fd = open(device, O_RDONLY);
if (fd == -1 || read(fd, boot_sect, SECTOR_SIZE) != SECTOR_SIZE) {
(void) fprintf(stderr, READ_FAIL_MBR, device);
@@ -623,8 +672,8 @@ modify_and_write_stage2(int dev_fd)
if (is_floppy || is_bootpar) {
int i = 0;
- uint_t partition_offset;
- uint_t install_addr = 0x8200;
+ uint32_t partition_offset;
+ uint32_t install_addr = 0x8200;
uchar_t *pos = (uchar_t *)stage2_buffer + STAGE2_BLOCKLIST;
stage2_first_sector = blocklist[0];
diff --git a/usr/src/cmd/boot/installgrub/message.h b/usr/src/cmd/boot/installgrub/message.h
index 1e644fb16c..594a7da1a1 100644
--- a/usr/src/cmd/boot/installgrub/message.h
+++ b/usr/src/cmd/boot/installgrub/message.h
@@ -19,7 +19,7 @@
* CDDL HEADER END
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
@@ -104,6 +104,14 @@ extern "C" {
#define OUT_OF_MEMORY gettext("diskread: out of memory\n")
+#define NO_VIRT_GEOM gettext("Could not get virtual geometry\n")
+
+#define NO_PHYS_GEOM gettext("Could not get physical geometry\n")
+
+#define NO_LABEL_GEOM gettext("Could not get label geometry\n")
+
+#define LIBFDISK_INIT_FAIL gettext("Failed to initialize libfdisk.\n")
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/cmd/devfsadm/disk_link.c b/usr/src/cmd/devfsadm/disk_link.c
index b1cc0a48fb..95cda78a19 100644
--- a/usr/src/cmd/devfsadm/disk_link.c
+++ b/usr/src/cmd/devfsadm/disk_link.c
@@ -44,6 +44,14 @@
#define MN_SMI "h"
#define MN_EFI "wd"
#define ASCIIWWNSIZE 255
+#if defined(__i386) || defined(__amd64)
+/*
+ * The number of minor nodes per LUN is defined by the disk drivers.
+ * Currently it is set to 64. Refer CMLBUNIT_SHIFT (cmlb_impl.h)
+ */
+#define NUM_MINORS_PER_INSTANCE 64
+#endif
+
extern int system_labeled;
@@ -344,14 +352,48 @@ disk_common(di_minor_t minor, di_node_t node, char *disk, int flags)
char *nt = NULL;
int *int_prop;
int nflags = 0;
+#if defined(__i386) || defined(__amd64)
+ char mn_copy[4];
+ char *part;
+ int part_num;
+#endif
- if (strstr(mn = di_minor_name(minor), ",raw")) {
+ mn = di_minor_name(minor);
+ if (strstr(mn, ",raw")) {
dir = "rdsk";
+#if defined(__i386) || defined(__amd64)
+ (void) strncpy(mn_copy, mn, 4);
+ part = strtok(mn_copy, ",");
+#endif
} else {
dir = "dsk";
+#if defined(__i386) || defined(__amd64)
+ part = mn;
+#endif
}
- if (mn[0] < 113) {
+#if defined(__i386) || defined(__amd64)
+ /*
+ * The following is a table describing the allocation of
+ * minor numbers, minor names and /dev/dsk names for partitions
+ * and slices on x86 systems.
+ *
+ * Minor Number Minor Name /dev/dsk name
+ * ---------------------------------------------
+ * 0 to 15 "a" to "p" s0 to s15
+ * 16 "q" p0
+ * 17 to 20 "r" to "u" p1 to p4
+ * 21 to 52 "p5" to "p36" p5 to p36
+ *
+ */
+ part_num = atoi(part + 1);
+
+ if ((mn[0] == 'p') && (part_num >= 5)) {
+ /* logical drive */
+ (void) snprintf(slice, 4, "%s", part);
+ } else {
+#endif
+ if (mn[0] < 'q') {
(void) sprintf(slice, "s%d", mn[0] - 'a');
} else if (strncmp(mn, MN_EFI, 2) != 0) {
(void) sprintf(slice, "p%d", mn[0] - 'q');
@@ -359,6 +401,9 @@ disk_common(di_minor_t minor, di_node_t node, char *disk, int flags)
/* For EFI label */
(void) sprintf(slice, SLICE_EFI);
}
+#if defined(__i386) || defined(__amd64)
+ }
+#endif
nflags = 0;
if (system_labeled) {
diff --git a/usr/src/cmd/fdisk/Makefile b/usr/src/cmd/fdisk/Makefile
index 4555481ce5..530f8cb70e 100644
--- a/usr/src/cmd/fdisk/Makefile
+++ b/usr/src/cmd/fdisk/Makefile
@@ -19,10 +19,9 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
#
# Makefile for fdisk
@@ -36,7 +35,12 @@ include ../Makefile.cmd
CPPFLAGS += -D_FILE_OFFSET_BITS=64
-LDLIBS += -ladm -lefi
+LDLIBS_i386= -lfdisk
+LDLIBS_sparc=
+LDLIBS += -ladm -lefi $(LDLIBS_$(MACH))
+
+i386_CFLAGS += -D_LARGEFILE64_SOURCE
+i386_CFLAGS += -D_FILE_OFFSET_BITS=64
all: $(ROOTFS_PROG)
diff --git a/usr/src/cmd/fdisk/fdisk.c b/usr/src/cmd/fdisk/fdisk.c
index 947d509064..f5a9706d6c 100644
--- a/usr/src/cmd/fdisk/fdisk.c
+++ b/usr/src/cmd/fdisk/fdisk.c
@@ -57,16 +57,33 @@
#include <sys/dktp/fdisk.h>
#include <sys/dkio.h>
#include <sys/vtoc.h>
+#ifdef i386
+#include <sys/tty.h>
+#include <libfdisk.h>
+#endif
#define CLR_SCR ""
#define CLR_LIN ""
#define HOME "" \
""
#define Q_LINE ""
+
+#ifdef i386
+#define W_LINE ""
+#else
#define W_LINE ""
+#endif
+
#define E_LINE ""
+
+#ifdef i386
+#define M_LINE "" \
+ ""
+#else
#define M_LINE "" \
""
+#endif
+
#define T_LINE ""
#define DEFAULT_PATH "/dev/rdsk/"
@@ -122,6 +139,23 @@
#error No VTOC format defined.
#endif
+#ifdef i386
+#define FDISK_KB (1024)
+#define FDISK_MB (FDISK_KB * 1024)
+#define FDISK_GB (FDISK_MB * 1024)
+#define TRUE 1
+
+#define FDISK_MAX_VALID_PART_ID 255
+#define FDISK_MAX_VALID_PART_NUM_DIGITS 2
+#define FDISK_MAX_VALID_PART_ID_DIGITS 3
+
+/* Maximum number of digits for a valid partition size */
+#define FDISK_MAX_VALID_CYL_NUM_DIGITS 10
+
+/* Minimum partition size in cylinders */
+#define FDISK_MIN_PART_SIZE 1
+#endif
+
static char Usage[] = "Usage: fdisk\n"
"[ -A id:act:bhead:bsect:bcyl:ehead:esect:ecyl:rsect:numsect ]\n"
"[ -b masterboot ]\n"
@@ -213,6 +247,7 @@ 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";
@@ -314,6 +349,283 @@ static int sectsiz; /* sector size */
#define CBUFLEN 80
static char s[CBUFLEN];
+#ifdef i386
+/*
+ * Complete list of all the 255 partition types. Some are unknown types
+ * and some entries are known to be unused.
+ *
+ * Courtesy of http://www.win.tue.nl/~aeb/partitions/partition_types-1.html
+ */
+char *fdisk_part_types[] = {
+ "Empty", /* 0 */
+ "FAT12", /* 1 */
+ "XENIX /", /* 2 */
+ "XENIX /usr", /* 3 */
+ "FAT16 (Upto 32M)", /* 4 */
+ "DOS Extended", /* 5 */
+ "FAT16 (>32M, HUGEDOS)", /* 6 */
+ "IFS: NTFS", /* 7 */
+ "AIX Boot/QNX(qny)", /* 8 */
+ "AIX Data/QNX(qnz)", /* 9 */
+ "OS/2 Boot/Coherent swap", /* 10 */
+ "WIN95 FAT32(Upto 2047GB)", /* 11 */
+ "WIN95 FAT32(LBA)", /* 12 */
+ "Unused", /* 13 */
+ "WIN95 FAT16(LBA)", /* 14 */
+ "WIN95 Extended(LBA)", /* 15 */
+ "OPUS", /* 16 */
+ "Hidden FAT12", /* 17 */
+ "Diagnostic", /* 18 */
+ "Unknown", /* 19 */
+ "Hidden FAT16(Upto 32M)", /* 20 */
+ "Unknown", /* 21 */
+ "Hidden FAT16(>=32M)", /* 22 */
+ "Hidden IFS: HPFS", /* 23 */
+ "AST SmartSleep Partition", /* 24 */
+ "Unused/Willowtech Photon", /* 25 */
+ "Unknown", /* 26 */
+ "Hidden FAT32", /* 27 */
+ "Hidden FAT32(LBA)", /* 28 */
+ "Unused", /* 29 */
+ "Hidden FAT16(LBA)", /* 30 */
+ "Unknown", /* 31 */
+ "Unused/OSF1", /* 32 */
+ "Reserved/FSo2(Oxygen FS)", /* 33 */
+ "Unused/(Oxygen EXT)", /* 34 */
+ "Reserved", /* 35 */
+ "NEC DOS 3.x", /* 36 */
+ "Unknown", /* 37 */
+ "Reserved", /* 38 */
+ "Unknown", /* 39 */
+ "Unknown", /* 40 */
+ "Unknown", /* 41 */
+ "AtheOS File System", /* 42 */
+ "SyllableSecure", /* 43 */
+ "Unknown", /* 44 */
+ "Unknown", /* 45 */
+ "Unknown", /* 46 */
+ "Unknown", /* 47 */
+ "Unknown", /* 48 */
+ "Reserved", /* 49 */
+ "NOS", /* 50 */
+ "Reserved", /* 51 */
+ "Reserved", /* 52 */
+ "JFS on OS/2", /* 53 */
+ "Reserved", /* 54 */
+ "Unknown", /* 55 */
+ "THEOS 3.2 2GB", /* 56 */
+ "Plan9/THEOS 4", /* 57 */
+ "THEOS 4 4GB", /* 58 */
+ "THEOS 4 Extended", /* 59 */
+ "PartitionMagic Recovery", /* 60 */
+ "Hidden NetWare", /* 61 */
+ "Unknown", /* 62 */
+ "Unknown", /* 63 */
+ "Venix 80286", /* 64 */
+ "MINIX/PPC PReP Boot", /* 65 */
+ "Win2K Dynamic Disk/SFS(DOS)", /* 66 */
+ "Linux+DRDOS shared", /* 67 */
+ "GoBack partition", /* 68 */
+ "Boot-US boot manager", /* 69 */
+ "EUMEL/Elan", /* 70 */
+ "EUMEL/Elan", /* 71 */
+ "EUMEL/Elan", /* 72 */
+ "Unknown", /* 73 */
+ "ALFS/THIN FS for DOS", /* 74 */
+ "Unknown", /* 75 */
+ "Oberon partition", /* 76 */
+ "QNX 4,x", /* 77 */
+ "QNX 4,x 2nd Part", /* 78 */
+ "QNX 4,x 3rd Part", /* 79 */
+ "OnTrack DM R/O, Lynx RTOS", /* 80 */
+ "OnTrack DM R/W, Novell", /* 81 */
+ "CP/M", /* 82 */
+ "Disk Manager 6.0 Aux3", /* 83 */
+ "Disk Manager 6.0 DDO", /* 84 */
+ "EZ-Drive", /* 85 */
+ "Golden Bow VFeature/AT&T MS-DOS", /* 86 */
+ "DrivePro", /* 87 */
+ "Unknown", /* 88 */
+ "Unknown", /* 89 */
+ "Unknown", /* 90 */
+ "Unknown", /* 91 */
+ "Priam EDisk", /* 92 */
+ "Unknown", /* 93 */
+ "Unknown", /* 94 */
+ "Unknown", /* 95 */
+ "Unknown", /* 96 */
+ "SpeedStor", /* 97 */
+ "Unknown", /* 98 */
+ "Unix SysV, Mach, GNU Hurd", /* 99 */
+ "PC-ARMOUR, Netware 286", /* 100 */
+ "Netware 386", /* 101 */
+ "Netware SMS", /* 102 */
+ "Novell", /* 103 */
+ "Novell", /* 104 */
+ "Netware NSS", /* 105 */
+ "Unknown", /* 106 */
+ "Unknown", /* 107 */
+ "Unknown", /* 108 */
+ "Unknown", /* 109 */
+ "Unknown", /* 110 */
+ "Unknown", /* 111 */
+ "DiskSecure Multi-Boot", /* 112 */
+ "Reserved", /* 113 */
+ "Unknown", /* 114 */
+ "Reserved", /* 115 */
+ "Scramdisk partition", /* 116 */
+ "IBM PC/IX", /* 117 */
+ "Reserved", /* 118 */
+ "M2FS/M2CS,Netware VNDI", /* 119 */
+ "XOSL FS", /* 120 */
+ "Unknown", /* 121 */
+ "Unknown", /* 122 */
+ "Unknown", /* 123 */
+ "Unknown", /* 124 */
+ "Unknown", /* 125 */
+ "Unused", /* 126 */
+ "Unused", /* 127 */
+ "MINIX until 1.4a", /* 128 */
+ "MINIX since 1.4b, early Linux", /* 129 */
+ "Solaris/Linux swap", /* 130 */
+ "Linux native", /* 131 */
+ "OS/2 hidden,Win Hibernation", /* 132 */
+ "Linux extended", /* 133 */
+ "Old Linux RAID,NT FAT16 RAID", /* 134 */
+ "NTFS volume set", /* 135 */
+ "Linux plaintext part table", /* 136 */
+ "Unknown", /* 137 */
+ "Linux Kernel Partition", /* 138 */
+ "Fault Tolerant FAT32 volume", /* 139 */
+ "Fault Tolerant FAT32 volume", /* 140 */
+ "Free FDISK hidden PDOS FAT12", /* 141 */
+ "Linux LVM partition", /* 142 */
+ "Unknown", /* 143 */
+ "Free FDISK hidden PDOS FAT16", /* 144 */
+ "Free FDISK hidden DOS EXT", /* 145 */
+ "Free FDISK hidden FAT16 Large", /* 146 */
+ "Hidden Linux native, Amoeba", /* 147 */
+ "Amoeba Bad Block Table", /* 148 */
+ "MIT EXOPC Native", /* 149 */
+ "Unknown", /* 150 */
+ "Free FDISK hidden PDOS FAT32", /* 151 */
+ "Free FDISK hidden FAT32 LBA", /* 152 */
+ "DCE376 logical drive", /* 153 */
+ "Free FDISK hidden FAT16 LBA", /* 154 */
+ "Free FDISK hidden DOS EXT", /* 155 */
+ "Unknown", /* 156 */
+ "Unknown", /* 157 */
+ "Unknown", /* 158 */
+ "BSD/OS", /* 159 */
+ "Laptop hibernation", /* 160 */
+ "Laptop hibernate,HP SpeedStor", /* 161 */
+ "Unknown", /* 162 */
+ "HP SpeedStor", /* 163 */
+ "HP SpeedStor", /* 164 */
+ "BSD/386,386BSD,NetBSD,FreeBSD", /* 165 */
+ "OpenBSD,HP SpeedStor", /* 166 */
+ "NeXTStep", /* 167 */
+ "Mac OS-X", /* 168 */
+ "NetBSD", /* 169 */
+ "Olivetti FAT12 1.44MB Service", /* 170 */
+ "Mac OS-X Boot", /* 171 */
+ "Unknown", /* 172 */
+ "Unknown", /* 173 */
+ "ShagOS filesystem", /* 174 */
+ "ShagOS swap", /* 175 */
+ "BootStar Dummy", /* 176 */
+ "HP SpeedStor", /* 177 */
+ "Unknown", /* 178 */
+ "HP SpeedStor", /* 179 */
+ "HP SpeedStor", /* 180 */
+ "Unknown", /* 181 */
+ "Corrupted FAT16 NT Mirror Set", /* 182 */
+ "Corrupted NTFS NT Mirror Set", /* 183 */
+ "Old BSDI BSD/386 swap", /* 184 */
+ "Unknown", /* 185 */
+ "Unknown", /* 186 */
+ "Boot Wizard hidden", /* 187 */
+ "Unknown", /* 188 */
+ "Unknown", /* 189 */
+ "Solaris x86 boot", /* 190 */
+ "Solaris2", /* 191 */
+ "REAL/32 or Novell DOS secured", /* 192 */
+ "DRDOS/secured(FAT12)", /* 193 */
+ "Hidden Linux", /* 194 */
+ "Hidden Linux swap", /* 195 */
+ "DRDOS/secured(FAT16,< 32M)", /* 196 */
+ "DRDOS/secured(Extended)", /* 197 */
+ "NT corrupted FAT16 volume", /* 198 */
+ "NT corrupted NTFS volume", /* 199 */
+ "DRDOS8.0+", /* 200 */
+ "DRDOS8.0+", /* 201 */
+ "DRDOS8.0+", /* 202 */
+ "DRDOS7.04+ secured FAT32(CHS)", /* 203 */
+ "DRDOS7.04+ secured FAT32(LBA)", /* 204 */
+ "CTOS Memdump", /* 205 */
+ "DRDOS7.04+ FAT16X(LBA)", /* 206 */
+ "DRDOS7.04+ secure EXT DOS(LBA)", /* 207 */
+ "REAL/32 secure big, MDOS", /* 208 */
+ "Old MDOS secure FAT12", /* 209 */
+ "Unknown", /* 210 */
+ "Unknown", /* 211 */
+ "Old MDOS secure FAT16 <32M", /* 212 */
+ "Old MDOS secure EXT", /* 213 */
+ "Old MDOS secure FAT16 >=32M", /* 214 */
+ "Unknown", /* 215 */
+ "CP/M-86", /* 216 */
+ "Unknown", /* 217 */
+ "Non-FS Data", /* 218 */
+ "CP/M,Concurrent DOS,CTOS", /* 219 */
+ "Unknown", /* 220 */
+ "Hidden CTOS memdump", /* 221 */
+ "Dell PowerEdge utilities(FAT)", /* 222 */
+ "DG/UX virtual disk manager", /* 223 */
+ "ST AVFS(STMicroelectronics)", /* 224 */
+ "SpeedStor 12-bit FAT EXT", /* 225 */
+ "Unknown", /* 226 */
+ "SpeedStor", /* 227 */
+ "SpeedStor 16-bit FAT EXT", /* 228 */
+ "Tandy MSDOS", /* 229 */
+ "Storage Dimensions SpeedStor", /* 230 */
+ "Unknown", /* 231 */
+ "Unknown", /* 232 */
+ "Unknown", /* 233 */
+ "Unknown", /* 234 */
+ "BeOS BFS", /* 235 */
+ "SkyOS SkyFS", /* 236 */
+ "Unused", /* 237 */
+ "EFI Header Indicator", /* 238 */
+ "EFI Filesystem", /* 239 */
+ "Linux/PA-RISC boot loader", /* 240 */
+ "SpeedStor", /* 241 */
+ "DOS 3.3+ secondary", /* 242 */
+ "SpeedStor Reserved", /* 243 */
+ "SpeedStor Large", /* 244 */
+ "Prologue multi-volume", /* 245 */
+ "SpeedStor", /* 246 */
+ "Unused", /* 247 */
+ "Unknown", /* 248 */
+ "pCache", /* 249 */
+ "Bochs", /* 250 */
+ "VMware File System", /* 251 */
+ "VMware swap", /* 252 */
+ "Linux raid autodetect", /* 253 */
+ "NT Disk Administrator hidden", /* 254 */
+ "Xenix Bad Block Table" /* 255 */
+};
+
+/* Allowed extended partition menu options */
+static char ext_part_menu_opts[] = "adhipr";
+
+/*
+ * Structure holding all information about the extended partition
+ * NOTE : As of now, there will be just one instance of ext_part_t, since most
+ * known systems allow only one extended dos partition per disk.
+ */
+static ext_part_t *epp;
+#endif
+
static void update_disk_and_exit(boolean_t table_changed);
int main(int argc, char *argv[]);
static int read_geom(char *sgeom);
@@ -373,9 +685,41 @@ 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);
+#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 int is_linux_swap(uint32_t part_start, off_t *lsm_offset);
+static void add_logical_drive();
+static void delete_logical_drive();
+static void ext_print_help_menu();
+static void ext_change_logical_drive_id();
+static void ext_print_part_types();
+static void ext_print_logical_drive_layout();
+static void preach_and_continue();
+#ifdef DEBUG
+static void ext_print_logdrive_layout_debug();
+#endif /* DEBUG */
+#endif /* i386 */
+
+/*
+ * This function is called only during the non-interactive mode.
+ * It is touchy and does not tolerate any errors. If there are
+ * mounted logical drives, changes to the partition table
+ * is disallowed.
+ */
static void
update_disk_and_exit(boolean_t table_changed)
{
+#ifdef i386
+ int rval;
+#endif
if (table_changed) {
/*
* Copy the new table back to the sector buffer
@@ -389,11 +733,27 @@ update_disk_and_exit(boolean_t table_changed)
if (io_adjt)
fix_slice();
+#ifdef i386
+ if (!io_readonly) {
+ rval = fdisk_commit_ext_part(epp);
+ switch (rval) {
+ case FDISK_SUCCESS:
+ /* Success */
+ break;
+ case FDISK_ENOEXTPART:
+ /* Nothing to do */
+ break;
+ default:
+ fprintf(stderr, "Error in"
+ " fdisk_commit_ext_part\n");
+ exit(rval);
+ }
+ }
+ libfdisk_fini(&epp);
+#endif
exit(0);
}
-
-
/*
* main
* Process command-line options.
@@ -407,6 +767,10 @@ main(int argc, char *argv[])
int errflg = 0;
int diag_cnt = 0;
int openmode;
+#ifdef i386
+ int rval;
+ int lf_op_flag = 0;
+#endif
setbuf(stderr, 0); /* so all output gets out on exit */
setbuf(stdout, 0);
@@ -805,6 +1169,49 @@ main(int argc, char *argv[])
/* save away a copy of Table in Old_Table for sensing changes */
copy_Table_to_Old_Table();
+#ifdef i386
+ /*
+ * Read extended partition only when the fdisk table is not
+ * supplied from a file
+ */
+ if (!io_ffdisk) {
+ lf_op_flag |= FDISK_READ_DISK;
+ }
+ if ((rval = libfdisk_init(&epp, Dfltdev, &Table[0], lf_op_flag))
+ != FDISK_SUCCESS) {
+ switch (rval) {
+ /*
+ * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
+ * be considered as soft errors and hence
+ * we do not exit
+ */
+ case FDISK_EBADLOGDRIVE:
+ break;
+ case FDISK_ENOLOGDRIVE:
+ break;
+ case FDISK_ENOVGEOM:
+ fprintf(stderr, "Could not get virtual"
+ " geometry for this device\n");
+ exit(1);
+ break;
+ case FDISK_ENOPGEOM:
+ fprintf(stderr, "Could not get physical"
+ " geometry for this device\n");
+ exit(1);
+ break;
+ case FDISK_ENOLGEOM:
+ fprintf(stderr, "Could not get label"
+ " geometry for this device\n");
+ exit(1);
+ break;
+ default:
+ perror("Failed to initialise libfdisk.\n");
+ exit(1);
+ break;
+ }
+ }
+#endif
+
/* Load fdisk table from specified file (-F fdisk_file) */
if (io_ffdisk) {
/* Load and verify user-specified table parameters */
@@ -845,10 +1252,10 @@ main(int argc, char *argv[])
nulltbl();
/* now set up UNIX System partition */
Table[0].bootid = ACTIVE;
- Table[0].relsect = lel(heads * sectors);
+ Table[0].relsect = LE_32(heads * sectors);
Table[0].numsect =
- lel((ulong_t)((Numcyl_usable - 1) *
+ LE_32((ulong_t)((Numcyl_usable - 1) *
heads * sectors));
Table[0].systid = SUNIXOS2; /* Solaris */
@@ -1024,6 +1431,57 @@ dev_mboot_write(off_t sect, char *buff, int bootsiz)
Table[new_pt].systid != SUNIXOS2)
continue;
+#ifdef i386
+
+ /*
+ * Check if a solaris old partition is there in the new table.
+ * If so, this could potentially have been a linux swap.
+ * Check to see if the linux swap magic is there, and destroy
+ * the magic if there is one.
+ */
+ if (Table[new_pt].systid == SUNIXOS) {
+ off_t lsmo;
+ char *lsm_buf;
+
+ if ((lsm_buf = calloc(1, sectsiz)) == NULL) {
+ fprintf(stderr, "Could not allocate memory\n");
+ exit(1);
+ }
+
+ if (is_linux_swap(Table[new_pt].relsect, &lsmo) == 0) {
+ if (lseek(Dev, lsmo, SEEK_SET) < 0) {
+ fprintf(stderr, "Error seeking on "
+ "%s\n", Dfltdev);
+ exit(1);
+ }
+
+ if (read(Dev, lsm_buf, sectsiz) < sectsiz) {
+ fprintf(stderr, "Error reading on "
+ "%s\n", Dfltdev);
+ exit(1);
+ }
+
+ bzero(lsm_buf + sectsiz -
+ LINUX_SWAP_MAGIC_LENGTH,
+ LINUX_SWAP_MAGIC_LENGTH);
+
+ if (lseek(Dev, lsmo, SEEK_SET) < 0) {
+ fprintf(stderr, "Error seeking on "
+ "%s\n", Dfltdev);
+ exit(1);
+ }
+
+ if (write(Dev, lsm_buf, sectsiz) < sectsiz) {
+ fprintf(stderr, "Error writing on "
+ "%s\n", Dfltdev);
+ exit(1);
+ }
+ }
+ free(lsm_buf);
+ }
+
+#endif
+
/* Does the old table have an exact entry for the new entry? */
for (old_pt = 0; old_pt < FD_NUMPART; old_pt++) {
@@ -1167,12 +1625,12 @@ mboot_read(void)
}
/* Is this really a master boot record? */
- if (les(BootCod.signature) != MBB_MAGIC) {
+ 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",
- les(BootCod.signature), MBB_MAGIC);
+ LE_16(BootCod.signature), MBB_MAGIC);
exit(1);
}
@@ -1354,6 +1812,17 @@ load(int funct, char *file)
int i = 0;
int j;
FILE *fp;
+#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, ext_end_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) {
@@ -1380,6 +1849,134 @@ load(int funct, char *file)
&bcyl, &ehead, &esect, &ecyl, &rsect, &numsect)) {
continue;
}
+#ifdef i386
+ part_count++;
+
+ if (fdisk_is_dos_extended((uchar_t)id)) {
+ if (ext_part_present) {
+ fprintf(stderr, "Extended partition"
+ " already exists\n");
+ fprintf(stderr, "fdisk: Error on"
+ " entry \"%s\".\n", line);
+ exit(1);
+ }
+ ext_part_present = 1;
+ /*
+ * If the existing extended partition's start
+ * and size matches the new one, do not
+ * initialize the extended partition EBR
+ * (Extended Boot Record) because there could
+ * be existing logical drives.
+ */
+ for (i = 0; i < FD_NUMPART; i++) {
+ systid = Old_Table[i].systid;
+ if (fdisk_is_dos_extended(systid)) {
+ old_ext_beg_sec =
+ Old_Table[i].relsect;
+ old_ext_num_sec =
+ Old_Table[i].numsect;
+ break;
+ }
+ }
+ new_ext_beg_sec = rsect;
+ new_ext_num_sec = numsect;
+ if ((old_ext_beg_sec != new_ext_beg_sec) ||
+ (old_ext_num_sec != new_ext_num_sec)) {
+ fdisk_init_ext_part(epp,
+ new_ext_beg_sec, new_ext_num_sec);
+ ext_part_inited = 1;
+ }
+ }
+
+ if (part_count > FD_NUMPART) {
+ /* This line should be logical drive info */
+ int offset = MAX_LOGDRIVE_OFFSET;
+ if (!ext_part_present) {
+ /* Erroneous input file */
+ fprintf(stderr, "More than 4 primary"
+ " partitions found in input\n");
+ fprintf(stderr, "Exiting...\n");
+ exit(1);
+ }
+
+ if (numsect == 0) {
+ continue;
+ }
+
+ /*
+ * If the start and size of the existing
+ * extended partition matches the new one and
+ * new logical drives are being defined via
+ * the input file, initialize the EBR.
+ */
+ if (!ext_part_inited) {
+ fdisk_init_ext_part(epp,
+ new_ext_beg_sec, new_ext_num_sec);
+ ext_part_inited = 1;
+ }
+
+ begsec = rsect - offset;
+ if ((ldcnt =
+ fdisk_get_logical_drive_count(epp)) == 0) {
+ /* Adding the first logical drive */
+ /*
+ * Make sure that begsec doesnt wrap
+ * around. This can happen if rsect is
+ * less than offset.
+ */
+ if (rsect < offset) {
+ fprintf(stderr, "Minimum of "
+ "63 free sectors required "
+ "before the beginning of "
+ "a logical drive.");
+ exit(1);
+ }
+ /*
+ * Check if the first logical drive
+ * is out of order. In that case, do
+ * not subtract MAX_LOGDRIVE_OFFSET
+ * from the given start of partition.
+ */
+ if (begsec != new_ext_beg_sec) {
+ begsec = rsect;
+ offset = 0;
+ }
+ }
+ if (ldcnt >= MAX_EXT_PARTS) {
+ fprintf(stderr, "\nError : Number of "
+ "logical drives exceeds limit of "
+ "%d.\n", MAX_EXT_PARTS);
+ exit(1);
+ }
+
+ if (id > FDISK_MAX_VALID_PART_ID) {
+ fprintf(stderr, "Invalid partition "
+ "ID\n");
+ 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) {
+ fprintf(stderr, "EFI "
+ "partitions not supported "
+ "inside extended "
+ "partition\n");
+ exit(1);
+ }
+ fdisk_add_logical_drive(epp, begsec,
+ endsec, id);
+ continue;
+ } else {
+ fprintf(stderr, "fdisk: Error on"
+ " entry \"%s\".\n", line);
+ exit(1);
+ }
+ }
+#endif
/*
* Validate the partition. It cannot start at sector
@@ -1477,8 +2074,8 @@ load(int funct, char *file)
Table[i].endsect == ((esect & 0x3f) |
(uchar_t)((ecyl>>2) & 0xc0)) &&
Table[i].endcyl == (uchar_t)(ecyl & 0xff) &&
- Table[i].relsect == lel(rsect) &&
- Table[i].numsect == lel(numsect)) {
+ Table[i].relsect == LE_32(rsect) &&
+ Table[i].numsect == LE_32(numsect)) {
/*
* Found the entry. Now move rest of
@@ -1507,9 +2104,39 @@ load(int funct, char *file)
Table[FD_NUMPART - 1].systid = UNUSED;
Table[FD_NUMPART - 1].bootid = 0;
+#ifdef i386
+ if (fdisk_is_dos_extended(id)) {
+ 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",
@@ -1571,6 +2198,74 @@ load(int funct, char *file)
}
}
+#ifdef i386
+ if (id > FDISK_MAX_VALID_PART_ID) {
+ 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 <= (ext_end_sec = fdisk_get_ext_end_sec(epp)))) {
+ int offset = MAX_LOGDRIVE_OFFSET;
+
+ /*
+ * Make sure that begsec doesnt wrap around.
+ * This can happen if rsect is less than offset
+ */
+ if (rsect < offset) {
+ return;
+ }
+ begsec = rsect - offset;
+ if ((ldcnt = fdisk_get_logical_drive_count(epp)) == 0) {
+ /*
+ * Adding the first logical drive
+ * Check if the first logical drive
+ * is out of order. In that case, do
+ * not subtract MAX_LOGDRIVE_OFFSET
+ * from the given start of partition.
+ */
+ if (begsec != ext_beg_sec) {
+ begsec = rsect;
+ offset = 0;
+ }
+ }
+
+ if (ldcnt >= MAX_EXT_PARTS) {
+ printf("\nNumber of logical drives exceeds "
+ "limit of %d.\n", MAX_EXT_PARTS);
+ printf("Failing further additions.\n");
+ exit(1);
+ }
+
+ if (numsect == 0) {
+ (void) fprintf(stderr,
+ "fdisk: Partition size cannot be zero:\n"
+ " \"%s\".\n",
+ file);
+ exit(1);
+ }
+ endsec = rsect + numsect - 1;
+ if (fdisk_validate_logical_drive(epp, begsec,
+ offset, numsect) == 0) {
+ /* Valid logical drive */
+ fdisk_add_logical_drive(epp, begsec, endsec,
+ id);
+ return;
+ }
+ }
+#endif
+
/* Find unused entry for use and put entry in table */
if (insert_tbl(id, act, bhead, bsect, bcyl, ehead, esect,
ecyl, rsect, numsect) < 0) {
@@ -1681,8 +2376,8 @@ insert_tbl(
Table[i].systid = (uchar_t)id;
Table[i].bootid = (uchar_t)act;
- Table[i].numsect = lel(numsect);
- Table[i].relsect = lel(rsect);
+ Table[i].numsect = LE_32(numsect);
+ Table[i].relsect = LE_32(rsect);
/*
* If we have been called with a valid geometry, use it
@@ -1824,8 +2519,8 @@ verify_tbl(void)
}
/* make sure the partition isn't larger than the disk */
- rsect = lel(Table[i].relsect);
- numsect = lel(Table[i].numsect);
+ 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)) {
@@ -1836,9 +2531,9 @@ verify_tbl(void)
for (j = i + 1; j < FD_NUMPART; j++) {
if (Table[j].systid != UNUSED) {
uint32_t t_relsect =
- lel(Table[j].relsect);
+ LE_32(Table[j].relsect);
uint32_t t_numsect =
- lel(Table[j].numsect);
+ LE_32(Table[j].numsect);
if (noMoreParts) {
(void) fprintf(stderr,
@@ -1926,6 +2621,10 @@ pars_fdisk(
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';
@@ -1936,6 +2635,25 @@ pars_fdisk(
line[i] = ' ';
}
}
+ strncpy(buf, line, 256);
+ errno = 0;
+ tok = strtok(buf, ": \t\n");
+ while (tok != NULL) {
+ for (p = tok; *p != '\0'; p++) {
+ if (!isdigit(*p)) {
+ 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)) {
+ 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) {
@@ -1957,14 +2675,20 @@ validate_part(int id, uint32_t rsect, uint32_t numsect)
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)))
+ (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) {
+ fprintf(stderr, "Invalid partition ID\n");
+ return (-1);
+ }
+#endif
return (0);
}
@@ -1975,17 +2699,30 @@ validate_part(int id, uint32_t rsect, uint32_t numsect)
static void
stage0(void)
{
+#ifdef i386
+ int rval;
+#endif
dispmenu();
for (;;) {
(void) printf(Q_LINE);
(void) printf("Enter Selection: ");
(void) fgets(s, sizeof (s), stdin);
rm_blanks(s);
+#ifdef i386
+ while (!((s[0] > '0') && (s[0] < '8') &&
+ ((s[1] == '\0') || (s[1] == '\n')))) {
+#else
while (!((s[0] > '0') && (s[0] < '7') &&
((s[1] == '\0') || (s[1] == '\n')))) {
+#endif
(void) printf(E_LINE); /* Clear any previous error */
+#ifdef i386
+ (void) printf(
+ "Enter a one-digit number between 1 and 7.");
+#else
(void) printf(
"Enter a one-digit number between 1 and 6.");
+#endif
(void) printf(Q_LINE);
(void) printf("Enter Selection: ");
(void) fgets(s, sizeof (s), stdin);
@@ -2009,6 +2746,54 @@ stage0(void)
if (ppartid() == -1)
return;
break;
+#ifdef i386
+ case '5':
+ if (fdisk_ext_part_exists(epp)) {
+ ext_part_menu();
+ } else {
+ printf(Q_LINE);
+ printf("\nNo extended partition found"
+ "\n");
+ printf("Press enter to continue\n");
+ ext_read_input(s);
+ }
+ break;
+ case '6':
+ /* update disk partition table, if changed */
+ if (TableChanged() == 1) {
+ copy_Table_to_Bootblk();
+ dev_mboot_write(0, Bootsect, sectsiz);
+ }
+
+ /*
+ * If the VTOC table is wrong fix it
+ * (truncate only)
+ */
+ if (io_adjt) {
+ fix_slice();
+ }
+ if (!io_readonly) {
+ rval = fdisk_commit_ext_part(epp);
+ switch (rval) {
+ case FDISK_SUCCESS:
+ /* Success */
+ /* Fallthrough */
+ case FDISK_ENOEXTPART:
+ /* Nothing to do */
+ break;
+ case FDISK_EMOUNTED:
+ printf(Q_LINE);
+ preach_and_continue();
+ continue;
+ default:
+ perror("Commit failed");
+ exit(1);
+ }
+ libfdisk_fini(&epp);
+ }
+ (void) close(Dev);
+ exit(0);
+#else
case '5':
/* update disk partition table, if changed */
if (TableChanged() == 1) {
@@ -2025,7 +2810,12 @@ stage0(void)
(void) close(Dev);
exit(0);
/* FALLTHRU */
+#endif
+#ifdef i386
+ case '7':
+#else
case '6':
+#endif
/*
* If the VTOC table is wrong fix it
* (truncate only)
@@ -2056,6 +2846,9 @@ pcreate(void)
int i, j;
uint32_t numsect;
int retCode = 0;
+#ifdef i386
+ int ext_part_present = 0;
+#endif
i = 0;
for (;;) {
@@ -2076,8 +2869,14 @@ pcreate(void)
numsect = 0;
for (i = 0; i < FD_NUMPART; i++) {
if (Table[i].systid != UNUSED) {
- numsect += lel(Table[i].numsect);
+ numsect += LE_32(Table[i].numsect);
+ }
+#ifdef i386
+ /* Check if an extended partition already exists */
+ 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"
@@ -2135,6 +2934,17 @@ pcreate(void)
tsystid = DOSOS16; /* DOS 16 bit fat */
break;
case '7':
+#ifdef i386
+ if (ext_part_present) {
+ printf(Q_LINE);
+ printf(E_LINE);
+ fprintf(stderr,
+ "Extended partition already exists\n");
+ fprintf(stderr, "Press enter to continue\n");
+ ext_read_input(s);
+ continue;
+ }
+#endif
tsystid = EXTDOS;
break;
case '8':
@@ -2214,6 +3024,18 @@ pcreate(void)
Table[i].bootid = 0;
}
+#ifdef i386
+ /*
+ * If partition created is an extended partition, null
+ * out the first sector of the first cylinder of the
+ * extended partition
+ */
+ if (fdisk_is_dos_extended(Table[i].systid)) {
+ fdisk_init_ext_part(epp,
+ LE_32(Table[i].relsect),
+ LE_32(Table[i].numsect));
+ }
+#endif
/* set up the return code */
i = 1;
}
@@ -2300,8 +3122,8 @@ specify(uchar_t tsystid)
for (j = i + 1; j < FD_NUMPART; j++) {
if (partition[j]->systid == UNUSED)
break;
- if (lel(partition[j]->relsect) <
- lel(partition[i]->relsect)) {
+ if (LE_32(partition[j]->relsect) <
+ LE_32(partition[i]->relsect)) {
struct ipart *temp = partition[i];
partition[i] = partition[j];
partition[j] = temp;
@@ -2381,8 +3203,8 @@ specify(uchar_t tsystid)
*/
if (i) {
/* Not an empty table */
- first_free = lel(partition[i - 1]->relsect) +
- lel(partition[i - 1]->numsect);
+ first_free = LE_32(partition[i - 1]->relsect) +
+ LE_32(partition[i - 1]->numsect);
} else {
first_free = cyl_size;
}
@@ -2399,9 +3221,9 @@ specify(uchar_t tsystid)
* Make sure free space is not negative.
*/
size_free =
- (lel(partition[i]->relsect > first_free)) ?
- (lel(partition[i]->relsect) - first_free) :
- 0;
+ (LE_32(partition[i]->relsect > first_free))
+ ? (LE_32(partition[i]->relsect) -
+ first_free) : 0;
}
/* save largest free space */
@@ -2475,8 +3297,8 @@ specify(uchar_t tsystid)
if (partition[i]->systid == UNUSED)
break;
- t_relsect = lel(partition[i]->relsect);
- t_numsect = lel(partition[i]->numsect);
+ 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) {
@@ -2551,6 +3373,17 @@ 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"
@@ -2559,6 +3392,7 @@ dispmenu(void)
" 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
}
/*
@@ -2719,16 +3553,46 @@ DEL1: (void) printf(Q_LINE);
return (-1);
}
- (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\"). ");
+#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);
+ (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);
+ }
+ 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;
@@ -2912,6 +3776,9 @@ disptbl(void)
case FDISK_CPM:
type = CPMstr;
break;
+ case FDISK_NOVELL2:
+ type = NOV2str;
+ break;
case FDISK_NOVELL3:
type = NOVstr;
break;
@@ -2947,7 +3814,7 @@ disptbl(void)
break;
case EFI_PMBR:
type = EFIstr;
- if (lel(Table[i].numsect) == DK_MAX_2TB)
+ if (LE_32(Table[i].numsect) == DK_MAX_2TB)
is_pmbr = 1;
break;
@@ -2955,16 +3822,16 @@ disptbl(void)
type = Ostr;
break;
}
- startcyl = lel(Table[i].relsect) /
+ startcyl = LE_32(Table[i].relsect) /
(unsigned long)(heads * sectors);
- if (lel(Table[i].numsect) == DK_MAX_2TB) {
+ if (LE_32(Table[i].numsect) == DK_MAX_2TB) {
endcyl = Numcyl - 1;
length = endcyl - startcyl + 1;
} else {
- length = lel(Table[i].numsect) /
+ length = LE_32(Table[i].numsect) /
(unsigned long)(heads * sectors);
- if (lel(Table[i].numsect) %
+ if (LE_32(Table[i].numsect) %
(unsigned long)(heads * sectors))
length++;
endcyl = startcyl + length - 1;
@@ -3028,8 +3895,8 @@ print_Table(void)
(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 ", lel(Table[i].relsect));
- (void) fprintf(stderr, "%-10u\n", lel(Table[i].numsect));
+ (void) fprintf(stderr, "%-10u ", LE_32(Table[i].relsect));
+ (void) fprintf(stderr, "%-10u\n", LE_32(Table[i].numsect));
}
}
@@ -3061,8 +3928,8 @@ nulltbl(void)
for (i = 0; i < FD_NUMPART; i++) {
Table[i].systid = UNUSED;
- Table[i].numsect = lel(UNUSED);
- Table[i].relsect = lel(UNUSED);
+ Table[i].numsect = LE_32(UNUSED);
+ Table[i].relsect = LE_32(UNUSED);
Table[i].bootid = 0;
skip_verify[i] = 0;
}
@@ -3083,7 +3950,7 @@ copy_Bootblk_to_Table(void)
/* Get an aligned copy of the partition tables */
(void) memcpy(iparts, Bootblk->parts, sizeof (iparts));
bootptr = (char *)iparts; /* Points to start of partition table */
- if (les(Bootblk->signature) != MBB_MAGIC) {
+ if (LE_16(Bootblk->signature) != MBB_MAGIC) {
/* Signature is missing */
nulltbl();
(void) memcpy(Bootblk->bootinst, &BootCod, BOOTSZ);
@@ -3108,8 +3975,8 @@ copy_Bootblk_to_Table(void)
}
for (i = j; i < FD_NUMPART; i++) {
Table[i].systid = UNUSED;
- Table[i].numsect = lel(UNUSED);
- Table[i].relsect = lel(UNUSED);
+ Table[i].numsect = LE_32(UNUSED);
+ Table[i].relsect = LE_32(UNUSED);
Table[i].bootid = 0;
}
@@ -3193,7 +4060,7 @@ copy_Table_to_Bootblk(void)
else
(void) memcpy(boot_ptr, tbl_ptr, sizeof (struct ipart));
}
- Bootblk->signature = les(MBB_MAGIC);
+ Bootblk->signature = LE_16(MBB_MAGIC);
}
/*
@@ -3281,6 +4148,7 @@ ffile_write(char *file)
(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");
@@ -3303,23 +4171,53 @@ ffile_write(char *file)
" Rsect Numsect\n");
for (i = 0; i < FD_NUMPART; i++) {
- if (Table[i].systid != UNUSED)
+ (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 %-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)),
- lel(Table[i].relsect),
- lel(Table[i].numsect));
+ " %-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);
}
@@ -3347,7 +4245,7 @@ fix_slice(void)
* VTOC entries are relative to the start of
* the partition.
*/
- numsect = lel(Table[i].numsect);
+ numsect = LE_32(Table[i].numsect);
break;
}
}
@@ -3717,13 +4615,13 @@ clear_vtoc(int table, int part)
return;
}
- seek_byte = (off_t)(lel(clr_table->relsect) + VTOC_OFFSET) * sectsiz;
+ 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)(lel(clr_table->relsect) + VTOC_OFFSET));
+ (uint64_t)(LE_32(clr_table->relsect) + VTOC_OFFSET));
}
if (lseek(Dev, seek_byte, SEEK_SET) == -1) {
@@ -3779,8 +4677,8 @@ clear_vtoc(int table, int part)
#endif /* DEBUG */
/* Clear backup label */
- pcyl = lel(clr_table->numsect) / (heads * sectors);
- solaris_offset = lel(clr_table->relsect);
+ pcyl = LE_32(clr_table->numsect) / (heads * sectors);
+ solaris_offset = LE_32(clr_table->relsect);
ncyl = pcyl - acyl;
backup_block = ((ncyl + acyl - 1) *
@@ -4024,3 +4922,741 @@ get_node(char *devname)
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);
+}
+
+/*
+ * Convert a given partition ID to an descriptive string.
+ * Just an index into the partition types table.
+ */
+void
+id_to_name(uchar_t sysid, char *buffer)
+{
+ strcpy(buffer, fdisk_part_types[sysid]);
+}
+
+/*
+ * Procedure to check the validity of the extended partition menu option
+ * entered by the user
+ */
+static int
+ext_invalid_option(char ch)
+{
+ char *p;
+
+ p = strchr(ext_part_menu_opts, tolower(ch));
+
+ if (p == NULL) {
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Read 16 bytes of the input (assuming that no valid user input spans more
+ * than that). Flush the input stream, so that the next read does not reap
+ * stale data from the previous input that was not processed.
+ * Note that fgets also reads the trailing '\n'
+ */
+static void
+ext_read_input(char *buf)
+{
+ fgets(buf, 16, stdin);
+ fflush(stdin);
+}
+
+/*
+ * Procedure to read and validate the user option at the extended partition menu
+ */
+static int
+ext_read_options(char *buf)
+{
+ ext_read_input(buf);
+ if ((strlen(buf) != 2) || (ext_invalid_option(buf[0]))) {
+ printf("\nUnknown Command\n");
+ return (-1);
+ }
+ return (0);
+}
+
+/*
+ * Procedure to print the list of known partition types and their IDs
+ */
+static void
+ext_print_part_types()
+{
+ int i, rowmax, rowcount = 1;
+ struct winsize ws;
+ char buf[80];
+
+ /* Get the current window dimensions */
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) < 0) {
+ perror("ioctl");
+ rowmax = 20;
+ } else {
+ /*
+ * Accommodate the initial headings by reducing the number of
+ * partition IDs being printed.
+ */
+ rowmax = ws.ws_row - 5;
+ }
+
+ if (rowmax < 3) {
+ fprintf(stderr, "Window size too small."
+ " Try resizing the window\n");
+ return;
+ }
+
+ printf("List of known partition types : \n");
+ printf("PartID Partition Type\n");
+ printf("====== ==============\n");
+ for (i = 0; i <= FDISK_MAX_VALID_PART_ID; i++) {
+ printf("%-3d %s\n", i, fdisk_part_types[i]);
+ rowcount++;
+ if (rowcount == rowmax) {
+ /*
+ * After the initial screen, use all the rows for
+ * printing the partition IDs, but one.
+ */
+ rowmax = ws.ws_row - 1;
+ 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 (;;) {
+ printf("Enter the partition number : ");
+ ext_read_input(buf);
+
+ len = strlen(buf);
+
+ /* Check length of the input */
+ if ((len < 2) || (len > (FDISK_MAX_VALID_PART_NUM_DIGITS+1))) {
+ goto print_error_and_continue;
+ }
+
+ /* Check if there is a non-digit in the input */
+ 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:
+ printf("Invalid partition number\n");
+ continue;
+ }
+}
+
+static void
+ext_read_valid_part_id(uchar_t *partid)
+{
+ char buf[80];
+ int len, i, id;
+
+ for (;;) {
+ 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))) {
+ printf("Invalid partition ID\n");
+ continue;
+ }
+
+ if ((len == 2) && (toupper(buf[0]) == 'I')) {
+ ext_print_part_types();
+ continue;
+ }
+
+ /* Check if there is a non-digit in the input */
+ for (i = 0; i < len-1; i++) {
+ if (!isdigit(buf[i])) {
+ printf("Invalid partition ID\n");
+ break;
+ }
+ }
+
+ if (i < len - 1) {
+ continue;
+ }
+
+ /* Check if the (now) valid number is greater than the limit */
+ if ((id = atoi(buf)) > FDISK_MAX_VALID_PART_ID) {
+ printf("Invalid partition ID\n");
+ continue;
+ }
+
+ *partid = (uchar_t)id;
+
+ /* Disallow multiple extended partitions */
+ if (fdisk_is_dos_extended(*partid)) {
+ printf("Multiple extended partitions not allowed\n");
+ continue;
+ }
+
+ /* Disallow EFI partitions within extended partition */
+ if (*partid == EFI_PMBR) {
+ printf("EFI partitions within an extended partition"
+ " is not allowed\n");
+ continue;
+ }
+
+ return; /* Valid partition ID is in partid */
+ }
+}
+
+static void
+delete_logical_drive()
+{
+ int pno;
+
+ if (!fdisk_get_logical_drive_count(epp)) {
+ printf("\nNo logical drives defined.\n");
+ return;
+ }
+
+ printf("\n");
+ ext_read_valid_part_num(&pno);
+ fdisk_delete_logical_drive(epp, pno);
+ 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 (;;) {
+ printf("Enter the beginning cylinder (Default - %d) : ",
+ first_free_cyl);
+ ext_read_input(buf);
+ len = strlen(buf);
+ if (len == 1) { /* User accepted the default value */
+ *begsec = first_free_sec;
+ return (FDISK_SUCCESS);
+ }
+
+ if (len > (FDISK_MAX_VALID_CYL_NUM_DIGITS + 1)) {
+ printf("Input too long\n");
+ printf("Invalid beginning cylinder number\n");
+ continue;
+ }
+ /* Check if there is a non-digit in the input */
+ for (i = 0; i < len - 1; i++) {
+ if (!isdigit(buf[i])) {
+ 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:
+ /*
+ * Success.
+ * Valid beginning sector is in begsec
+ */
+ break;
+
+ case FDISK_EOVERLAP:
+ printf("Partition boundary overlaps with ");
+ printf("existing partitions\n");
+ printf("Invalid beginning cylinder number\n");
+ continue;
+
+ case FDISK_EOOBOUND:
+ printf("Cylinder boundary beyond the limits\n");
+ printf("Invalid beginning cylinder number\n");
+ continue;
+ }
+ return (FDISK_SUCCESS);
+ }
+}
+
+/*
+ * Algorithm :
+ * 1. Check if the first character is a +
+ * a) If yes, check if the last character is 'k', 'm' or 'g'
+ * 2. If not, check if there are any non-digits
+ * 3. Check for the length of the numeral string
+ * 4. atoi the numeral string
+ * 5. In case of data entered in KB, MB or GB, convert it to number of cylinders
+ * a) Adjust size to be cylinder boundary aligned
+ * 6. If size specifies is zero, flag error
+ * 7. Check if the size is less than 1 cylinder
+ * a) If yes, default the size FDISK_MIN_PART_SIZE
+ * b) If no, Check if the size is within endcyl - begcyl
+ */
+static void
+ext_read_valid_partition_size(uint32_t begsec, uint32_t *endsec)
+{
+ char buf[80];
+ uint32_t tempcyl;
+ 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) {
+ 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 (;;) {
+ printf("Enter the size in cylinders (Default End Cylinder -");
+ printf(" %u)\n", last_free_cyl);
+ printf("Type +<size>K, +<size>M or +<size>G to enter size in");
+ printf("KB, MB or GB : ");
+ ext_read_input(buf);
+ len = strlen(buf);
+ mbgb = 0;
+ scale = FDISK_SECTS_PER_CYL(epp);
+
+ if (len == 1) { /* User accepted the default value */
+ *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'))) {
+ 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) {
+ printf("Input too long\n");
+ printf("Invalid partition size\n");
+ continue;
+ }
+
+ 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) {
+ printf("Invalid partition size\n");
+ continue;
+ }
+
+ size = (atoll(numbuf) * (scale));
+
+ if (size == 0) {
+ printf("Zero size is invalid\n");
+ printf("Invalid partition size\n");
+ continue;
+ }
+
+ if (mbgb) {
+ size /= sectsize;
+ }
+
+ if (size > (last_free_sec - begsec + 1)) {
+ printf("Cylinder boundary beyond the limits");
+ printf(" or overlaps with existing");
+ printf(" partitions\n");
+ printf("Invalid partition size\n");
+ continue;
+ }
+
+ /*
+ * Adjust the ending sector such that there are no partial
+ * cylinders allocated. But at the same time, make sure it
+ * doesn't over shoot boundaries.
+ */
+ spc = FDISK_SECTS_PER_CYL(epp);
+ poss_end = begsec + size - 1;
+ if (remdr = (poss_end % spc)) {
+ poss_end += spc - remdr - 1;
+ }
+ *endsec = (poss_end > last_free_sec) ? last_free_sec :
+ poss_end;
+
+ return;
+ }
+}
+
+/*
+ * ALGORITHM:
+ * 1. Get the starting and ending sectors/cylinder of the extended partition.
+ * 2. Keep track of the first free sector/cylinder
+ * 3. Allow the user to specify the beginning cylinder of the new partition
+ * 4. Check for the validity of the entered data
+ * a) If it is non-numeric
+ * b) If it is beyond the extended partition limits
+ * c) If it overlaps with the current logical drives
+ * 5. Allow the user to specify the size in cylinders/ human readable form
+ * 6. Check for the validity of the entered data
+ * a) If it is non-numeric
+ * b) If it is beyond the extended partition limits
+ * c) If it overlaps with the current logical drives
+ * d) If it is a number lesser than the starting cylinder
+ * 7. Request partition ID for the new partition.
+ * 8. Update the first free cylinder available
+ * 9. Display Success message
+ */
+
+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) {
+ printf("\nNumber of logical drives exceeds limit of %d.\n",
+ MAX_EXT_PARTS);
+ printf("Command did not succeed. Press enter to continue\n");
+ ext_read_input(buf);
+ return;
+ }
+
+ printf("\n");
+ rval = ext_read_valid_partition_start(&begsec);
+ switch (rval) {
+ case FDISK_SUCCESS:
+ break;
+
+ case FDISK_EOOBOUND:
+ printf("\nNo space left in the extended partition\n");
+ 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);
+
+ 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)) {
+ printf("\nNo logical drives defined.\n");
+ return;
+ }
+
+ printf("\n");
+ ext_read_valid_part_num(&pno);
+ ext_read_valid_part_id(&partid);
+ fdisk_change_logical_drive_id(epp, pno, partid);
+
+ 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)) {
+ printf("\nNo logical drives defined.\n");
+ return;
+ }
+
+ printf("\n\n");
+ puts("# start block end block abs start abs end OSType");
+ for (temp = head, pno = 5; temp != NULL; temp = temp->next, pno++) {
+ /* Print the logical drive details */
+ id_to_name(temp->parts[0].systid, namebuff);
+ 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);
+ printf(" %s\n", namebuff);
+ /*
+ * Print the second entry in the EBR which is information
+ * about the location and the size of the next extended
+ * partition.
+ */
+ id_to_name(temp->parts[1].systid, namebuff);
+ printf("%d: %.10u %.10u %.10s %.10s",
+ pno,
+ LE_32(temp->parts[1].relsect),
+ LE_32(temp->parts[1].numsect),
+ " ", " ");
+ 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;
+ struct ipart *fpart;
+ char namebuff[255];
+ int numcyl = fdisk_get_disk_geom(epp, PHYSGEOM, NCYL);
+ int pno;
+
+ if (numcyl == EINVAL) {
+ fprintf(stderr, "Unsupported geometry statistics.\n");
+ exit(1);
+ }
+
+ if (!fdisk_get_logical_drive_count(epp)) {
+ printf("\nNo logical drives defined.\n");
+ return;
+ }
+
+ printf("\n");
+ printf("Number of cylinders in disk : %u\n", numcyl);
+ printf("Beginning cylinder of extended partition : %u\n",
+ fdisk_get_ext_beg_cyl(epp));
+ printf("Ending cylinder of extended partition : %u\n",
+ fdisk_get_ext_end_cyl(epp));
+ printf("\n");
+ printf("Part# StartCyl EndCyl Length %% "
+ "Part ID (Type)\n");
+ printf("===== ======== ======== ======= ==="
+ " ==============\n");
+ for (temp = fdisk_get_ld_head(epp), pno = 5; temp != NULL;
+ temp = temp->next, pno++) {
+ /* Print the logical drive details */
+ fpart = &temp->parts[0];
+ sysid = fpart->systid;
+ 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) {
+ /* round up */
+ percent++;
+ }
+ /* Else leave the percent as is since it's already */
+ /* rounded down */
+ }
+ if (percent > 100) {
+ percent = 100;
+ }
+ printf("%-5d %-8u %-8u %-7u %-3d %-3d (%-.28s)\n",
+ pno, startcyl, endcyl, length, percent, sysid, namebuff);
+ }
+#ifdef DEBUG
+ ext_print_logdrive_layout_debug();
+#endif
+ printf("\n");
+}
+
+static void
+ext_print_help_menu()
+{
+ printf("\n");
+ printf("a Add a logical drive\n");
+ printf("d Delete a logical drive\n");
+ printf("h Print this help menu\n");
+ printf("i Change the id of the logical drive\n");
+ printf("p Print the logical drive layout\n");
+ printf("r Return to the main fdisk menu\n");
+ printf(" (To commit or cancel the changes)\n");
+ printf("\n");
+}
+
+static void
+ext_part_menu()
+{
+ char buf[80];
+ uchar_t *bbsigp;
+ static int bbsig_disp_flag = 1;
+
+ int i;
+
+ printf(CLR_SCR);
+
+ if (fdisk_corrupt_logical_drives(epp)) {
+ printf("One or more logical drives seem to be corrupt.\n");
+ printf("Displaying only sane logical drives.\n");
+ }
+
+ if (bbsig_disp_flag && fdisk_invalid_bb_sig(epp, &bbsigp)) {
+ printf("The following logical drives have a wrong boot block"
+ " signature :\n\n");
+ for (i = 0; bbsigp[i]; i++) {
+ printf("%d ", bbsigp[i]);
+ }
+ printf("\n\n");
+ printf("They will be corrected when you choose to commit\n");
+ bbsig_disp_flag = 0;
+ }
+
+ printf("Extended partition menu\n");
+
+ for (;;) {
+ printf("\nEnter Command (Type h for help) : ");
+ if ((ext_read_options(buf)) < 0) {
+ 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':
+ printf(CLR_SCR);
+ return;
+ default : /* NOTREACHED */
+ break;
+ }
+ }
+}
+#endif
+
+#ifdef i386
+
+static int
+is_linux_swap(uint32_t part_start, off_t *lsm_offset)
+{
+ int i;
+ int rval = -1;
+ off_t seek_offset;
+ uint32_t linux_pg_size;
+ char *buf, *linux_swap_magic;
+ /*
+ * Known linux kernel page sizes
+ * The linux swap magic is found as the last 10 bytes of a disk chunk
+ * at the beginning of the linux swap partition whose size is that of
+ * kernel page size.
+ */
+ uint32_t linux_pg_size_arr[] = {4096, };
+
+ if ((buf = calloc(1, sectsiz)) == NULL) {
+ return (ENOMEM);
+ }
+
+ linux_swap_magic = buf + sectsiz - LINUX_SWAP_MAGIC_LENGTH;
+
+ for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
+ linux_pg_size = linux_pg_size_arr[i];
+ seek_offset = linux_pg_size/sectsiz - 1;
+ seek_offset += part_start;
+ seek_offset *= sectsiz;
+
+ if ((rval = lseek(Dev, seek_offset, SEEK_SET)) < 0) {
+ break;
+ }
+
+ if ((rval = read(Dev, buf, sectsiz)) < sectsiz) {
+ rval = EIO;
+ break;
+ }
+
+ if ((strncmp(linux_swap_magic, "SWAP-SPACE",
+ LINUX_SWAP_MAGIC_LENGTH) == 0) ||
+ (strncmp(linux_swap_magic, "SWAPSPACE2",
+ LINUX_SWAP_MAGIC_LENGTH) == 0)) {
+ /* Found a linux swap */
+ rval = 0;
+ *lsm_offset = seek_offset;
+ break;
+ }
+ }
+
+ free(buf);
+ return (rval);
+}
+
+#endif
diff --git a/usr/src/cmd/format/Makefile b/usr/src/cmd/format/Makefile
index 1060271ac4..8e475661c1 100644
--- a/usr/src/cmd/format/Makefile
+++ b/usr/src/cmd/format/Makefile
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -53,8 +53,11 @@ $(ROOTETCDATA) := FILEMODE = 0644
$(ROOTETCDATA) := OWNER = root
$(ROOTETCDATA) := GROUP = sys
-LDLIBS += -ladm -lefi -ldiskmgt -lnvpair -ldevid
+LDLIBS_i386= -lfdisk
+LDLIBS_sparc=
+LDLIBS += -ladm -lefi -ldiskmgt -lnvpair -ldevid $(LDLIBS_$(MACH))
+LINTFLAGS += -xerroff=E_NAME_DEF_NOT_USED2
CPPFLAGS += -D_EXTVTOC
.KEEP_STATE:
diff --git a/usr/src/cmd/format/menu_fdisk.c b/usr/src/cmd/format/menu_fdisk.c
index e1affd636a..7970ae778f 100644
--- a/usr/src/cmd/format/menu_fdisk.c
+++ b/usr/src/cmd/format/menu_fdisk.c
@@ -38,6 +38,9 @@
#include <sys/dktp/fdisk.h>
#include <sys/stat.h>
#include <sys/dklabel.h>
+#ifdef i386
+#include <libfdisk.h>
+#endif
#include "main.h"
#include "analyze.h"
@@ -105,6 +108,9 @@ static int get_solaris_part();
#endif /* __STDC__ */
+#ifdef i386
+int extpart_init(ext_part_t **epp);
+#endif
/*
* Handling the alignment problem of struct ipart.
*/
@@ -274,22 +280,23 @@ open_cur_file(int mode)
char pbuf[MAXPATHLEN];
switch (mode) {
- case FD_USE_P0_PATH:
- (void) get_pname(&pbuf[0]);
- dkpath = pbuf;
- break;
- case FD_USE_CUR_DISK_PATH:
- if (cur_disk->fdisk_part.systid == SUNIXOS ||
- cur_disk->fdisk_part.systid == SUNIXOS2) {
- (void) get_sname(&pbuf[0]);
+ case FD_USE_P0_PATH:
+ (void) get_pname(&pbuf[0]);
dkpath = pbuf;
- } else {
- dkpath = cur_disk->disk_path;
- }
- break;
- default:
- err_print("Error: Invalid mode option for opening cur_file\n");
- fullabort();
+ break;
+ case FD_USE_CUR_DISK_PATH:
+ if (cur_disk->fdisk_part.systid == SUNIXOS ||
+ cur_disk->fdisk_part.systid == SUNIXOS2) {
+ (void) get_sname(&pbuf[0]);
+ dkpath = pbuf;
+ } else {
+ dkpath = cur_disk->disk_path;
+ }
+ break;
+ default:
+ err_print("Error: Invalid mode option for opening "
+ "cur_file\n");
+ fullabort();
}
/* Close previous cur_file */
@@ -441,6 +448,12 @@ get_solaris_part(int fd, struct ipart *ipart)
char *mbr;
char *bootptr;
struct dk_label update_label;
+ ushort_t found = 0;
+#ifdef i386
+ uint32_t relsec, numsec;
+ int pno, rval, ext_part_found = 0;
+ ext_part_t *epp;
+#endif
(void) lseek(fd, 0, 0);
@@ -474,6 +487,41 @@ get_solaris_part(int fd, struct ipart *ipart)
bootptr = &boot_sec.parts[ipc];
(void) fill_ipart(bootptr, &ip);
+#ifdef i386
+ if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
+ /* We support only one extended partition per disk */
+ ext_part_found = 1;
+ (void) extpart_init(&epp);
+ rval = fdisk_get_solaris_part(epp, &pno, &relsec,
+ &numsec);
+ if (rval == FDISK_SUCCESS) {
+ /*
+ * Found a solaris partition inside the
+ * extended partition. Update the statistics.
+ */
+ if (nhead != 0 && nsect != 0) {
+ pcyl = numsec / (nhead * nsect);
+ xstart = relsec / (nhead * nsect);
+ ncyl = pcyl - acyl;
+ }
+ solaris_offset = relsec;
+ found = 2;
+ ip.bootid = 0;
+ ip.beghead = ip.begsect = ip.begcyl = 0xff;
+ ip.endhead = ip.endsect = ip.endcyl = 0xff;
+ ip.systid = SUNIXOS2;
+ ip.relsect = relsec;
+ ip.numsect = numsec;
+ ipart->bootid = ip.bootid;
+ status = bcmp(&ip, ipart,
+ sizeof (struct ipart));
+ bcopy(&ip, ipart, sizeof (struct ipart));
+ }
+ libfdisk_fini(&epp);
+ continue;
+ }
+#endif
+
/*
* we are interested in Solaris and EFI partition types
*/
@@ -493,29 +541,31 @@ get_solaris_part(int fd, struct ipart *ipart)
#ifdef DEBUG
else {
err_print("Critical geometry values are zero:\n"
- "\tnhead = %d; nsect = %d\n", nhead,
- nsect);
+ "\tnhead = %d; nsect = %d\n", nhead, nsect);
}
#endif /* DEBUG */
solaris_offset = (uint_t)lel(ip.relsect);
+ found = 1;
break;
}
}
- if (i == FD_NUMPART) {
+ if (!found) {
err_print("Solaris fdisk partition not found\n");
return (-1);
- }
-
- /*
- * compare the previous and current Solaris partition
- * but don't use bootid in determination of Solaris partition changes
- */
- ipart->bootid = ip.bootid;
- status = bcmp(&ip, ipart, sizeof (struct ipart));
+ } else if (found == 1) {
+ /*
+ * Found a primary solaris partition.
+ * compare the previous and current Solaris partition
+ * but don't use bootid in determination of Solaris partition
+ * changes
+ */
+ ipart->bootid = ip.bootid;
+ status = bcmp(&ip, ipart, sizeof (struct ipart));
- bcopy(&ip, ipart, sizeof (struct ipart));
+ bcopy(&ip, ipart, sizeof (struct ipart));
+ }
/* if the disk partitioning has changed - get the VTOC */
if (status) {
@@ -570,7 +620,6 @@ get_solaris_part(int fd, struct ipart *ipart)
nsect = cur_dtype->dtype_nsect;
nhead = cur_dtype->dtype_nhead;
}
-
return (0);
}
@@ -586,6 +635,11 @@ copy_solaris_part(struct ipart *ipart)
char buf[MAXPATHLEN];
char *bootptr;
struct stat statbuf;
+#ifdef i386
+ uint32_t relsec, numsec;
+ int pno, rval, ext_part_found = 0;
+ ext_part_t *epp;
+#endif
(void) get_pname(&buf[0]);
if (stat(buf, &statbuf) == -1 ||
@@ -641,6 +695,36 @@ copy_solaris_part(struct ipart *ipart)
bootptr = &mboot.parts[ipc];
(void) fill_ipart(bootptr, &ip);
+#ifdef i386
+ if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
+ /* We support only one extended partition per disk */
+ ext_part_found = 1;
+ (void) extpart_init(&epp);
+ rval = fdisk_get_solaris_part(epp, &pno, &relsec,
+ &numsec);
+ if (rval == FDISK_SUCCESS) {
+ /*
+ * Found a solaris partition inside the
+ * extended partition. Update the statistics.
+ */
+ if (nhead != 0 && nsect != 0) {
+ pcyl = numsec / (nhead * nsect);
+ ncyl = pcyl - acyl;
+ }
+ solaris_offset = relsec;
+ ip.bootid = 0;
+ ip.beghead = ip.begsect = ip.begcyl = 0xff;
+ ip.endhead = ip.endsect = ip.endcyl = 0xff;
+ ip.systid = SUNIXOS2;
+ ip.relsect = relsec;
+ ip.numsect = numsec;
+ bcopy(&ip, ipart, sizeof (struct ipart));
+ }
+ libfdisk_fini(&epp);
+ continue;
+ }
+#endif
+
if (ip.systid == SUNIXOS ||
ip.systid == SUNIXOS2 ||
ip.systid == EFI_PMBR) {
@@ -660,8 +744,7 @@ copy_solaris_part(struct ipart *ipart)
#ifdef DEBUG
else {
err_print("Critical geometry values are zero:\n"
- "\tnhead = %d; nsect = %d\n", nhead,
- nsect);
+ "\tnhead = %d; nsect = %d\n", nhead, nsect);
}
#endif /* DEBUG */
@@ -685,6 +768,11 @@ auto_solaris_part(struct dk_label *label)
struct ipart ip;
char *bootptr;
char pbuf[MAXPATHLEN];
+#ifdef i386
+ uint32_t relsec, numsec;
+ int pno, rval, ext_part_found = 0;
+ ext_part_t *epp;
+#endif
(void) get_pname(&pbuf[0]);
if ((fd = open_disk(pbuf, O_RDONLY)) < 0) {
@@ -720,6 +808,33 @@ auto_solaris_part(struct dk_label *label)
bootptr = &mboot.parts[ipc];
(void) fill_ipart(bootptr, &ip);
+#ifdef i386
+ if (fdisk_is_dos_extended(ip.systid) && (ext_part_found == 0)) {
+ /* We support only one extended partition per disk */
+ ext_part_found = 1;
+ (void) extpart_init(&epp);
+ rval = fdisk_get_solaris_part(epp, &pno, &relsec,
+ &numsec);
+ if (rval == FDISK_SUCCESS) {
+ /*
+ * Found a solaris partition inside the
+ * extended partition. Update the statistics.
+ */
+ if ((label->dkl_nhead != 0) &&
+ (label->dkl_nsect != 0)) {
+ label->dkl_pcyl =
+ numsec / (label->dkl_nhead *
+ label->dkl_nsect);
+ label->dkl_ncyl = label->dkl_pcyl -
+ label->dkl_acyl;
+ }
+ solaris_offset = relsec;
+ }
+ libfdisk_fini(&epp);
+ continue;
+ }
+#endif
+
/*
* if the disk has an EFI label, the nhead and nsect fields
* the label may be zero. This protects us from FPE's, and
@@ -786,3 +901,49 @@ good_fdisk()
return (0);
}
}
+
+#ifdef i386
+int
+extpart_init(ext_part_t **epp)
+{
+ int rval, lf_op_flag = 0;
+ char p0_path[MAXPATHLEN];
+
+ get_pname(&p0_path[0]);
+ lf_op_flag |= FDISK_READ_DISK;
+ if ((rval = libfdisk_init(epp, p0_path, NULL, lf_op_flag)) !=
+ FDISK_SUCCESS) {
+ switch (rval) {
+ /*
+ * FDISK_EBADLOGDRIVE and FDISK_ENOLOGDRIVE can
+ * be considered as soft errors and hence
+ * we do not exit
+ */
+ case FDISK_EBADLOGDRIVE:
+ break;
+ case FDISK_ENOLOGDRIVE:
+ break;
+ case FDISK_ENOVGEOM:
+ err_print("Could not get virtual geometry for"
+ " this device\n");
+ fullabort();
+ break;
+ case FDISK_ENOPGEOM:
+ err_print("Could not get physical geometry for"
+ " this device\n");
+ fullabort();
+ break;
+ case FDISK_ENOLGEOM:
+ err_print("Could not get label geometry for "
+ " this device\n");
+ fullabort();
+ break;
+ default:
+ err_print("Failed to initialise libfdisk.\n");
+ fullabort();
+ break;
+ }
+ }
+ return (0);
+}
+#endif
diff --git a/usr/src/lib/Makefile b/usr/src/lib/Makefile
index 48fdf92273..934df8f983 100644
--- a/usr/src/lib/Makefile
+++ b/usr/src/lib/Makefile
@@ -263,7 +263,8 @@ SUBDIRS += \
i386_SUBDIRS= \
libntfs \
- libparted
+ libparted \
+ libfdisk
sparc_SUBDIRS= .WAIT \
efcode \
@@ -366,6 +367,8 @@ sparc_MSGSUBDIRS= \
libprtdiag \
libprtdiag_psr
+i386_MSGSUBDIRS= libfdisk
+
HDRSUBDIRS= \
auditd_plugins \
libast \
@@ -491,7 +494,8 @@ $(CLOSED_BUILD)HDRSUBDIRS += \
$(CLOSED)/lib/smartcard
i386_HDRSUBDIRS= \
- libparted
+ libparted \
+ libfdisk
sparc_HDRSUBDIRS= \
libds \
diff --git a/usr/src/lib/libfdisk/Makefile b/usr/src/lib/libfdisk/Makefile
new file mode 100644
index 0000000000..a0b6cf09ca
--- /dev/null
+++ b/usr/src/lib/libfdisk/Makefile
@@ -0,0 +1,64 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+include ../Makefile.lib
+
+LIBRARY= libfdisk.a
+VERS= .1
+
+HDRS= libfdisk.h
+
+HDRDIR= $(MACH)
+
+all:= TARGET= all
+install:= TARGET= install
+clean:= TARGET= clean
+clobber:= TARGET= clobber
+lint:= TARGET= lint
+_msg:= TARGET= _msg
+
+.KEEP_STATE:
+
+SUBDIRS= $(MACH)
+
+all install clean clobber lint: $(SUBDIRS)
+
+
+# install rule for install_h target
+
+install_h: $(ROOTHDRS)
+
+check: $(CHECKHDRS)
+
+_msg: $(MSGSUBDIRS)
+
+$(SUBDIRS): FRC
+ @cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+include ../Makefile.targ
+include ../../Makefile.msg.targ
diff --git a/usr/src/lib/libfdisk/i386/Makefile b/usr/src/lib/libfdisk/i386/Makefile
new file mode 100644
index 0000000000..7063a2d944
--- /dev/null
+++ b/usr/src/lib/libfdisk/i386/Makefile
@@ -0,0 +1,83 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+HDRS = libfdisk.h
+ROOTHDRDIR= $(ROOT)/usr/include
+ROOTHDRS= $(HDRS:%=$(ROOTHDRDIR)/%)
+CHECKDIRS= $(HDRS:%.h=%.check)
+HDRDIR = ./
+
+$(ROOTHDRDIR)/%: %
+ $(INS.file)
+
+all := TARGET = all
+install_h:= TARGET = install_h
+
+install_h: $(ROOTHDRS)
+
+LIBRARY= libfdisk.a
+VERS= .1
+
+PICS= pics/libfdisk.o
+
+pics/%.o: %.c
+ $(COMPILE.c) -o $@ $<
+ $(POST_PROCESS_O)
+
+OBJECTS= \
+libfdisk.o
+
+# include library definitions
+include ../../Makefile.lib
+
+# install this library in the root filesystem
+include ../../Makefile.rootfs
+
+SRCDIR = .
+
+C99MODE= $(C99_DISABLE)
+
+MAPFILES += mapfile-vers
+
+CPPFLAGS += -I.
+LDLIBS += -lc
+
+i386_CFLAGS += -D_LARGEFILE64_SOURCE
+i386_CFLAGS += -D_FILE_OFFSET_BITS=64
+
+.KEEP_STATE:
+
+LIBS= $(DYNLIB) $(LINTLIB)
+
+all: $(LIBS)
+
+lint: lintcheck
+
+install: all $(ROOTLIBS) $(ROOTLINKS) $(ROOTLINT)
+
+
+# include library targets
+include ../../Makefile.targ
diff --git a/usr/src/lib/libfdisk/i386/libfdisk.c b/usr/src/lib/libfdisk/i386/libfdisk.c
new file mode 100644
index 0000000000..fa273753e1
--- /dev/null
+++ b/usr/src/lib/libfdisk/i386/libfdisk.c
@@ -0,0 +1,1372 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.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/vtoc.h>
+#include <sys/tty.h>
+#include <sys/dktp/fdisk.h>
+#include <sys/dkio.h>
+#include <sys/mnttab.h>
+#include "libfdisk.h"
+
+#define DEFAULT_PATH_PREFIX "/dev/rdsk/"
+
+static void fdisk_free_ld_nodes(ext_part_t *epp);
+static void fdisk_ext_place_in_sorted_list(ext_part_t *epp,
+ logical_drive_t *newld);
+static void fdisk_ext_remove_from_sorted_list(ext_part_t *epp,
+ logical_drive_t *delld);
+static int fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec,
+ uint32_t endsec);
+static int fdisk_read_extpart(ext_part_t *epp);
+static void fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part);
+static int fdisk_init_master_part_table(ext_part_t *epp);
+static struct ipart *fdisk_alloc_part_table();
+static int fdisk_read_master_part_table(ext_part_t *epp);
+
+static int
+fdisk_init_disk_geom(ext_part_t *epp)
+{
+ struct dk_geom disk_geom;
+ struct dk_minfo disk_info;
+ int no_virtgeom_ioctl = 0, no_physgeom_ioctl = 0;
+
+ /* Get disk's HBA (virtual) geometry */
+ errno = 0;
+ if (ioctl(epp->dev_fd, DKIOCG_VIRTGEOM, &disk_geom)) {
+ if (errno == ENOTTY) {
+ 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).
+ */
+ epp->disk_geom.virt_cyl = epp->disk_geom.virt_heads =
+ epp->disk_geom.virt_sec = 0;
+ } else {
+ return (FDISK_ENOVGEOM);
+ }
+ } else {
+ /* save virtual geometry values obtained by ioctl */
+ epp->disk_geom.virt_cyl = disk_geom.dkg_ncyl;
+ epp->disk_geom.virt_heads = disk_geom.dkg_nhead;
+ epp->disk_geom.virt_sec = disk_geom.dkg_nsect;
+ }
+
+ errno = 0;
+ if (ioctl(epp->dev_fd, DKIOCG_PHYGEOM, &disk_geom)) {
+ if (errno == ENOTTY) {
+ no_physgeom_ioctl = 1;
+ } else {
+ return (FDISK_ENOPGEOM);
+ }
+ }
+ /*
+ * 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(epp->dev_fd, DKIOCGGEOM, &disk_geom)) {
+ return (FDISK_ENOLGEOM);
+ }
+ }
+
+ epp->disk_geom.phys_cyl = disk_geom.dkg_ncyl;
+ epp->disk_geom.phys_heads = disk_geom.dkg_nhead;
+ epp->disk_geom.phys_sec = disk_geom.dkg_nsect;
+ epp->disk_geom.alt_cyl = disk_geom.dkg_acyl;
+
+ /*
+ * If DKIOCGMEDIAINFO ioctl succeeds, set the dki_lbsize as the
+ * size of the sector, else default to 512
+ */
+ if (ioctl(epp->dev_fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info) < 0) {
+ /* ioctl failed, falling back to default value of 512 bytes */
+ epp->disk_geom.sectsize = 512;
+ } else {
+ epp->disk_geom.sectsize = ((disk_info.dki_lbsize) ?
+ disk_info.dki_lbsize : 512);
+ }
+
+ /*
+ * 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) {
+ epp->disk_geom.virt_sec = MAX_SECT;
+ epp->disk_geom.virt_heads = MAX_HEAD + 1;
+ epp->disk_geom.virt_cyl = (epp->disk_geom.phys_cyl *
+ epp->disk_geom.phys_heads * epp->disk_geom.phys_sec) /
+ (epp->disk_geom.virt_sec * epp->disk_geom.virt_heads);
+ }
+ return (FDISK_SUCCESS);
+}
+
+/*
+ * Initialise important members of the ext_part_t structure and
+ * other data structures vital to functionality of libfdisk
+ */
+int
+libfdisk_init(ext_part_t **epp, char *devstr, struct ipart *parttab, int opflag)
+{
+ ext_part_t *temp;
+ char *canonp;
+ struct stat sbuf;
+ int rval = FDISK_SUCCESS;
+
+ if ((temp = calloc(1, sizeof (ext_part_t))) == NULL) {
+ return (ENOMEM);
+ }
+ canonp = strstr(devstr, DEFAULT_PATH_PREFIX);
+ if (canonp == NULL) {
+ (void) snprintf(temp->device_name, sizeof (temp->device_name),
+ "%s%s", DEFAULT_PATH_PREFIX, devstr);
+ } else {
+ (void) strncpy(temp->device_name, devstr,
+ sizeof (temp->device_name));
+ }
+ /*
+ * In case of an EFI labeled disk, the device name could be cN[tN]dN.
+ * There is no pN. So we add "p0" at the end if we do not find it.
+ */
+ if (strrchr(temp->device_name, 'p') == NULL) {
+ (void) strcat(temp->device_name, "p0");
+ }
+
+ if (stat(temp->device_name, &sbuf) != 0) {
+ free(temp);
+ return (EINVAL);
+ }
+ temp->ld_head = NULL;
+ temp->sorted_ld_head = NULL;
+
+ if ((temp->dev_fd = open(temp->device_name, O_RDWR, 0666)) < 0) {
+ free(temp);
+ return (EINVAL);
+ }
+
+ if ((temp->mtable = parttab) == NULL) {
+ if ((rval = fdisk_init_master_part_table(temp)) !=
+ FDISK_SUCCESS) {
+ return (rval);
+ }
+ }
+
+ temp->op_flag = opflag;
+
+ if ((rval = fdisk_init_disk_geom(temp)) != FDISK_SUCCESS) {
+ return (rval);
+ }
+
+ *epp = temp;
+
+ if (opflag & FDISK_READ_DISK) {
+ rval = fdisk_read_extpart(*epp);
+ }
+ return (rval);
+}
+
+int
+libfdisk_reset(ext_part_t *epp)
+{
+ int rval = FDISK_SUCCESS;
+
+ fdisk_free_ld_nodes(epp);
+ epp->first_ebr_is_null = 1;
+ epp->corrupt_logical_drives = 0;
+ epp->logical_drive_count = 0;
+ epp->invalid_bb_sig[0] = 0;
+ if (epp->op_flag & FDISK_READ_DISK) {
+ rval = fdisk_read_extpart(epp);
+ }
+ return (rval);
+}
+
+void
+libfdisk_fini(ext_part_t **epp)
+{
+ fdisk_free_ld_nodes(*epp);
+ (void) close((*epp)->dev_fd);
+ free(*epp);
+ *epp = NULL;
+}
+
+int
+fdisk_is_linux_swap(ext_part_t *epp, uint32_t part_start, off_t *lsm_offset)
+{
+ int i;
+ int rval = -1;
+ off_t seek_offset;
+ uint32_t linux_pg_size;
+ char *buf, *linux_swap_magic;
+ int sec_sz = fdisk_get_disk_geom(epp, PHYSGEOM, SSIZE);
+ /*
+ * Known linux kernel page sizes
+ * The linux swap magic is found as the last 10 bytes of a disk chunk
+ * at the beginning of the linux swap partition whose size is that of
+ * kernel page size.
+ */
+ uint32_t linux_pg_size_arr[] = {4096, };
+
+ if ((buf = calloc(1, sec_sz)) == NULL) {
+ return (ENOMEM);
+ }
+
+ linux_swap_magic = buf + sec_sz - LINUX_SWAP_MAGIC_LENGTH;
+
+ for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
+ linux_pg_size = linux_pg_size_arr[i];
+ seek_offset = linux_pg_size/sec_sz - 1;
+ seek_offset += part_start;
+ seek_offset *= sec_sz;
+
+ if ((rval = lseek(epp->dev_fd, seek_offset, SEEK_SET)) < 0) {
+ break;
+ }
+
+ if ((rval = read(epp->dev_fd, buf, sec_sz)) < sec_sz) {
+ rval = EIO;
+ break;
+ }
+
+ if ((strncmp(linux_swap_magic, "SWAP-SPACE",
+ LINUX_SWAP_MAGIC_LENGTH) == 0) ||
+ (strncmp(linux_swap_magic, "SWAPSPACE2",
+ LINUX_SWAP_MAGIC_LENGTH) == 0)) {
+ /* Found a linux swap */
+ rval = 0;
+ *lsm_offset = seek_offset;
+ break;
+ }
+ }
+
+ free(buf);
+ return (rval);
+}
+
+int
+fdisk_get_solaris_part(ext_part_t *epp, int *pnum, uint32_t *begsec,
+ uint32_t *numsec)
+{
+ logical_drive_t *temp = fdisk_get_ld_head(epp);
+ uint32_t part_start;
+ int pno;
+ int rval = -1;
+ off_t lsmo = 0;
+
+ for (pno = 5; temp != NULL; temp = temp->next, pno++) {
+ if (fdisk_is_solaris_part(LE_8(temp->parts[0].systid))) {
+ part_start = temp->abs_secnum + temp->logdrive_offset;
+ if (fdisk_is_linux_swap(epp, part_start, &lsmo) == 0) {
+ continue;
+ }
+ *pnum = pno;
+ *begsec = part_start;
+ *numsec = temp->numsect;
+ rval = FDISK_SUCCESS;
+ }
+ }
+ return (rval);
+}
+
+int
+fdisk_get_part_info(ext_part_t *epp, int pnum, uchar_t *sysid, uint32_t *begsec,
+ uint32_t *numsec)
+{
+ logical_drive_t *temp = fdisk_get_ld_head(epp);
+ int pno;
+
+ if ((pnum < 5) || (pnum >= MAX_EXT_PARTS + 5)) {
+ return (EINVAL);
+ }
+
+ for (pno = 5; (pno < pnum) && (temp != NULL); temp = temp->next, pno++)
+ ;
+
+ if (temp == NULL) {
+ return (EINVAL);
+ }
+
+ *sysid = LE_8(temp->parts[0].systid);
+ *begsec = temp->abs_secnum + temp->logdrive_offset;
+ *numsec = temp->numsect;
+ return (FDISK_SUCCESS);
+}
+
+/*
+ * Allocate a node of type logical_drive_t and return the pointer to it
+ */
+static logical_drive_t *
+fdisk_alloc_ld_node()
+{
+ logical_drive_t *temp;
+
+ if ((temp = calloc(1, sizeof (logical_drive_t))) == NULL) {
+ return (NULL);
+ }
+ temp->next = NULL;
+ return (temp);
+}
+
+/*
+ * Free all the logical_drive_t's allocated during the run
+ */
+static void
+fdisk_free_ld_nodes(ext_part_t *epp)
+{
+ logical_drive_t *temp;
+
+ for (temp = epp->ld_head; temp != NULL; ) {
+ temp = epp->ld_head -> next;
+ free(epp->ld_head);
+ epp->ld_head = temp;
+ }
+ epp->ld_head = NULL;
+ epp->sorted_ld_head = NULL;
+}
+
+/*
+ * Find the first free sector within the extended partition
+ */
+int
+fdisk_ext_find_first_free_sec(ext_part_t *epp, uint32_t *first_free_sec)
+{
+ logical_drive_t *temp;
+ uint32_t last_free_sec;
+
+ *first_free_sec = epp->ext_beg_sec;
+
+ if (epp->ld_head == NULL) {
+ return (FDISK_SUCCESS);
+ }
+
+ /*
+ * When the first logical drive is out of order, we need to adjust
+ * first_free_sec accordingly. In this case, the first extended
+ * partition sector is not free even though the actual logical drive
+ * does not occupy space from the beginning of the extended partition.
+ * The next free sector would be the second sector of the extended
+ * partition.
+ */
+ if (epp->ld_head->abs_secnum > epp->ext_beg_sec +
+ MAX_LOGDRIVE_OFFSET) {
+ (*first_free_sec)++;
+ }
+
+ while (*first_free_sec <= epp->ext_end_sec) {
+ for (temp = epp->sorted_ld_head; temp != NULL; temp =
+ temp->sorted_next) {
+ if (temp->abs_secnum == *first_free_sec) {
+ *first_free_sec = temp->abs_secnum +
+ temp->logdrive_offset + temp->numsect;
+ }
+ }
+
+ last_free_sec = fdisk_ext_find_last_free_sec(epp,
+ *first_free_sec);
+
+ if ((last_free_sec - *first_free_sec) < MAX_LOGDRIVE_OFFSET) {
+ /*
+ * Minimum size of a partition assumed to be atleast one
+ * sector.
+ */
+ *first_free_sec = last_free_sec + 1;
+ continue;
+ }
+
+ break;
+ }
+
+ if (*first_free_sec > epp->ext_end_sec) {
+ return (FDISK_EOOBOUND);
+ }
+
+ return (FDISK_SUCCESS);
+}
+
+/*
+ * Find the last free sector within the extended partition given, a beginning
+ * sector (so that the range - "begsec to last_free_sec" is contiguous)
+ */
+uint32_t
+fdisk_ext_find_last_free_sec(ext_part_t *epp, uint32_t begsec)
+{
+ logical_drive_t *temp;
+ uint32_t last_free_sec;
+
+ last_free_sec = epp->ext_end_sec;
+ for (temp = epp->sorted_ld_head; temp != NULL;
+ temp = temp->sorted_next) {
+ if (temp->abs_secnum > begsec) {
+ last_free_sec = temp->abs_secnum - 1;
+ break;
+ }
+ }
+ return (last_free_sec);
+}
+
+/*
+ * Place the given ext_part_t structure in a sorted list, sorted in the
+ * ascending order of their beginning sectors.
+ */
+static void
+fdisk_ext_place_in_sorted_list(ext_part_t *epp, logical_drive_t *newld)
+{
+ logical_drive_t *pre, *cur;
+
+ if (newld->abs_secnum < epp->sorted_ld_head->abs_secnum) {
+ newld->sorted_next = epp->sorted_ld_head;
+ epp->sorted_ld_head = newld;
+ return;
+ }
+ pre = cur = epp->sorted_ld_head;
+
+ for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
+ if (newld->abs_secnum < cur->abs_secnum) {
+ break;
+ }
+ }
+
+ newld->sorted_next = cur;
+ pre->sorted_next = newld;
+}
+
+static void
+fdisk_ext_remove_from_sorted_list(ext_part_t *epp, logical_drive_t *delld)
+{
+ logical_drive_t *pre, *cur;
+
+ if (delld == epp->sorted_ld_head) {
+ epp->sorted_ld_head = delld->sorted_next;
+ return;
+ }
+
+ pre = cur = epp->sorted_ld_head;
+
+ for (; cur != NULL; pre = cur, cur = cur->sorted_next) {
+ if (cur->abs_secnum == delld->abs_secnum) {
+ /* Found */
+ break;
+ }
+ }
+
+ pre->sorted_next = cur->sorted_next;
+}
+
+static int
+fdisk_ext_overlapping_parts(ext_part_t *epp, uint32_t begsec, uint32_t endsec)
+{
+ logical_drive_t *temp;
+ uint32_t firstsec, lastsec, last_free_sec;
+
+ for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
+ firstsec = temp->abs_secnum;
+ lastsec = firstsec + temp->logdrive_offset + temp->numsect - 1;
+ if ((begsec >= firstsec) &&
+ (begsec <= lastsec)) {
+ return (1);
+ }
+ }
+
+ /*
+ * Find the maximum possible end sector value
+ * given a beginning sector value
+ */
+ last_free_sec = fdisk_ext_find_last_free_sec(epp, begsec);
+
+ if (endsec > last_free_sec) {
+ return (1);
+ }
+ return (0);
+}
+
+/*
+ * Check if the logical drive boundaries are sane
+ */
+int
+fdisk_validate_logical_drive(ext_part_t *epp, uint32_t begsec,
+ uint32_t offset, uint32_t numsec)
+{
+ uint32_t endsec;
+
+ endsec = begsec + offset + numsec - 1;
+ if (begsec < epp->ext_beg_sec ||
+ begsec > epp->ext_end_sec ||
+ endsec < epp->ext_beg_sec ||
+ endsec > epp->ext_end_sec ||
+ endsec < begsec ||
+ fdisk_ext_overlapping_parts(epp, begsec, endsec)) {
+ return (1);
+ }
+
+ return (0);
+}
+
+/*
+ * Procedure to walk through the extended partitions and build a Singly
+ * Linked List out of the data.
+ */
+int
+fdisk_read_extpart(ext_part_t *epp)
+{
+ struct ipart *fdp, *ext_fdp;
+ int i = 0, j = 0, ext_part_found = 0, lpart = 5;
+ off_t secnum, offset;
+ logical_drive_t *temp, *ep_ptr;
+ unsigned char *ext_buf;
+ int sectsize = epp->disk_geom.sectsize;
+
+ if ((ext_buf = (uchar_t *)malloc(sectsize)) == NULL) {
+ return (ENOMEM);
+ }
+ fdp = epp->mtable;
+
+ for (i = 0; (i < FD_NUMPART) && (!ext_part_found); i++, fdp++) {
+ if (fdisk_is_dos_extended(LE_8(fdp->systid))) {
+ ext_part_found = 1;
+ secnum = LE_32(fdp->relsect);
+ offset = secnum * sectsize;
+ epp->ext_beg_sec = secnum;
+ epp->ext_end_sec = secnum + LE_32(fdp->numsect) - 1;
+ epp->ext_beg_cyl =
+ FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
+ epp->ext_end_cyl =
+ FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
+
+ /*LINTED*/
+ while (B_TRUE) {
+ if (lseek(epp->dev_fd, offset, SEEK_SET) < 0) {
+ return (EIO);
+ }
+ if (read(epp->dev_fd, ext_buf, sectsize) <
+ sectsize) {
+ return (EIO);
+ }
+ /*LINTED*/
+ ext_fdp = (struct ipart *)
+ (&ext_buf[FDISK_PART_TABLE_START]);
+ if ((LE_32(ext_fdp->relsect) == 0) &&
+ (epp->logical_drive_count == 0)) {
+ /* No logical drives defined */
+ epp->first_ebr_is_null = 0;
+ return (FDISK_ENOLOGDRIVE);
+ }
+
+ temp = fdisk_alloc_ld_node();
+ temp->abs_secnum = secnum;
+ temp->logdrive_offset =
+ LE_32(ext_fdp->relsect);
+ temp ->numsect = LE_32(ext_fdp->numsect);
+ if (epp->ld_head == NULL) {
+ /* adding first logical drive */
+ if (temp->logdrive_offset >
+ MAX_LOGDRIVE_OFFSET) {
+ /* out of order */
+ temp->abs_secnum +=
+ temp->logdrive_offset;
+ temp->logdrive_offset = 0;
+ }
+ }
+ temp->begcyl =
+ FDISK_SECT_TO_CYL(epp, temp->abs_secnum);
+ temp->endcyl = FDISK_SECT_TO_CYL(epp,
+ temp->abs_secnum +
+ temp->logdrive_offset +
+ temp->numsect - 1);
+
+ /*
+ * Check for sanity of logical drives
+ */
+ if (fdisk_validate_logical_drive(epp,
+ temp->abs_secnum, temp->logdrive_offset,
+ temp->numsect)) {
+ epp->corrupt_logical_drives = 1;
+ free(temp);
+ return (FDISK_EBADLOGDRIVE);
+ }
+
+ temp->parts[0] = *ext_fdp;
+ ext_fdp++;
+ temp->parts[1] = *ext_fdp;
+
+ if (epp->ld_head == NULL) {
+ epp->ld_head = temp;
+ epp->sorted_ld_head = temp;
+ ep_ptr = temp;
+ epp->logical_drive_count = 1;
+ } else {
+ ep_ptr->next = temp;
+ ep_ptr = temp;
+ fdisk_ext_place_in_sorted_list(epp,
+ temp);
+ epp->logical_drive_count++;
+ }
+
+ /*LINTED*/
+ if (LE_16((*(uint16_t *)&ext_buf[510])) !=
+ MBB_MAGIC) {
+ epp->invalid_bb_sig[j++] = lpart;
+ temp->modified = FDISK_MINOR_WRITE;
+ }
+
+ if (LE_32(ext_fdp->relsect) == 0)
+ break;
+ else {
+ secnum = LE_32(fdp->relsect) +
+ LE_32(ext_fdp->relsect);
+ offset = secnum * sectsize;
+ }
+ lpart++;
+ }
+ }
+ }
+ return (FDISK_SUCCESS);
+}
+
+static int
+fdisk_init_master_part_table(ext_part_t *epp)
+{
+ int rval;
+ if ((epp->mtable = fdisk_alloc_part_table()) == NULL) {
+ return (ENOMEM);
+ }
+ rval = fdisk_read_master_part_table(epp);
+ if (rval) {
+ return (rval);
+ }
+ return (FDISK_SUCCESS);
+}
+
+static struct ipart *
+fdisk_alloc_part_table()
+{
+ int size = sizeof (struct ipart);
+ struct ipart *table;
+
+ if ((table = calloc(4, size)) == NULL) {
+ return (NULL);
+ }
+
+ return (table);
+}
+
+/*
+ * Reads the master fdisk partition table from the device assuming that it has
+ * a valid table.
+ * MBR is supposed to be of 512 bytes no matter what the device block size is.
+ */
+static int
+fdisk_read_master_part_table(ext_part_t *epp)
+{
+ uchar_t buf[512];
+ int sectsize = 512;
+ int size = sizeof (struct ipart);
+ int cpcnt = FD_NUMPART * size;
+
+ if (lseek(epp->dev_fd, 0, SEEK_SET) < 0) {
+ return (EIO);
+ }
+ if (read(epp->dev_fd, buf, sectsize) < sectsize) {
+ return (EIO);
+ }
+ bcopy(&buf[FDISK_PART_TABLE_START], epp->mtable, cpcnt);
+
+ /*LINTED*/
+ if (LE_16((*(uint16_t *)&buf[510])) != MBB_MAGIC) {
+ return (FDISK_EBADMAGIC);
+ }
+
+ return (FDISK_SUCCESS);
+}
+
+int
+fdisk_ext_part_exists(ext_part_t *epp)
+{
+ int i;
+ struct ipart *part_table = epp->mtable;
+
+ if (part_table == NULL) {
+ /* No extended partition found */
+ return (0);
+ }
+
+ for (i = 0; i < FD_NUMPART; i++) {
+ if (fdisk_is_dos_extended(LE_8(part_table[i].systid))) {
+ break;
+ }
+ }
+
+ if (i == FD_NUMPART) {
+ /* No extended partition found */
+ return (0);
+ }
+ return (1);
+}
+
+int
+fdisk_ext_validate_part_start(ext_part_t *epp, uint32_t begcyl,
+ uint32_t *begsec)
+{
+ logical_drive_t *temp;
+ uint32_t first_free_sec;
+ uint32_t first_free_cyl;
+ int rval;
+
+ rval = fdisk_ext_find_first_free_sec(epp, &first_free_sec);
+ if (rval != FDISK_SUCCESS) {
+ return (rval);
+ }
+
+ first_free_cyl = FDISK_SECT_TO_CYL(epp, first_free_sec);
+ if (begcyl == first_free_cyl) {
+ *begsec = first_free_sec;
+ return (FDISK_SUCCESS);
+ }
+
+ /* Check if the cylinder number is beyond the extended partition */
+ if ((begcyl < epp->ext_beg_cyl) || (begcyl > epp->ext_end_cyl)) {
+ return (FDISK_EOOBOUND);
+ }
+
+ for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
+ if ((begcyl >= temp->begcyl) &&
+ (begcyl <= temp->endcyl)) {
+ return (FDISK_EOVERLAP);
+ }
+ }
+ *begsec = FDISK_CYL_TO_SECT(epp, begcyl);
+
+ return (FDISK_SUCCESS);
+}
+
+void
+fdisk_change_logical_drive_id(ext_part_t *epp, int pno, uchar_t partid)
+{
+ logical_drive_t *temp;
+ int i;
+
+ i = FD_NUMPART + 1;
+ for (temp = epp->ld_head; i < pno; temp = temp->next, i++)
+ ;
+
+ temp->parts[0].systid = LE_8(partid);
+ temp->modified = FDISK_MAJOR_WRITE;
+}
+
+/*
+ * A couple of special scenarios :
+ * 1. Since the first logical drive's EBR is always at the beginning of the
+ * extended partition, any specification that starts the first logical drive
+ * out of order will need to address the following issue :
+ * If the beginning of the drive is not coinciding with the beginning of the
+ * extended partition and :
+ * a) The start is within MAX_LOGDRIVE_OFFSET, the offset changes from the
+ * default of 63 to less than 63.
+ * logdrive_offset is updated to keep track of the space between
+ * the beginning of the logical drive and extended partition. abs_secnum
+ * points to the beginning of the extended partition.
+ * b) The start is greater than MAX_LOGDRIVE_OFFSET, the offset changes from
+ * the default of 63 to greater than 63.
+ * logdrive_offset is set to 0. abs_secnum points to the beginning of the
+ * logical drive, which is at an offset from the extended partition.
+ */
+void
+fdisk_add_logical_drive(ext_part_t *epp, uint32_t begsec, uint32_t endsec,
+ uchar_t partid)
+{
+ logical_drive_t *temp, *pre, *cur;
+ struct ipart *part;
+
+ temp = fdisk_alloc_ld_node();
+ temp->abs_secnum = begsec;
+ temp->logdrive_offset = MAX_LOGDRIVE_OFFSET;
+ temp->numsect = endsec - begsec + 1 - MAX_LOGDRIVE_OFFSET;
+ temp->begcyl = FDISK_SECT_TO_CYL(epp, begsec);
+ temp->endcyl = FDISK_SECT_TO_CYL(epp, endsec);
+ temp->modified = FDISK_MAJOR_WRITE;
+
+ part = &temp->parts[0];
+ part->bootid = 0;
+ part->systid = LE_8(partid);
+ part->relsect = MAX_LOGDRIVE_OFFSET;
+ part->numsect = LE_32(temp->numsect);
+
+ fdisk_set_CHS_values(epp, part);
+
+ if (epp->ld_head == NULL) {
+ epp->corrupt_logical_drives = 0;
+ if (begsec != epp->ext_beg_sec) {
+ part->relsect = LE_32(begsec - epp->ext_beg_sec);
+ temp->numsect = endsec - begsec + 1;
+ part->numsect = LE_32(temp->numsect);
+ if (LE_32(part->relsect) > MAX_LOGDRIVE_OFFSET) {
+ temp->logdrive_offset = 0;
+ } else {
+ temp->abs_secnum = epp->ext_beg_sec;
+ temp->logdrive_offset = LE_32(part->relsect);
+ }
+ }
+ epp->first_ebr_is_null = 0;
+ epp->ld_head = temp;
+ epp->sorted_ld_head = temp;
+ epp->logical_drive_count = 1;
+ return;
+ }
+
+ if (temp->abs_secnum == epp->ext_beg_sec) {
+ part->relsect = LE_32(LE_32(part->relsect) - 1);
+ temp->logdrive_offset--;
+ temp->abs_secnum++;
+ }
+
+ for (pre = cur = epp->ld_head; cur != NULL; pre = cur, cur = cur->next)
+ ;
+
+ part = &pre->parts[1];
+ part->bootid = 0;
+ part->systid = LE_8(EXTDOS);
+ part->relsect = LE_32(temp->abs_secnum - epp->ext_beg_sec);
+ part->numsect = LE_32(temp->numsect + temp->logdrive_offset);
+
+ fdisk_set_CHS_values(epp, part);
+
+ pre->next = temp;
+ pre->modified = FDISK_MAJOR_WRITE;
+ epp->logical_drive_count++;
+ fdisk_ext_place_in_sorted_list(epp, temp);
+}
+
+/*
+ * There are 2 cases that need to be handled.
+ * 1. Deleting the first extended partition :
+ * The peculiarity of this case is that the offset of the first extended
+ * partition is always indicated by the entry in the master boot record.
+ * (MBR). This never changes, unless the extended partition itself is
+ * deleted. Hence, the location of the first EBR is fixed.
+ * It is only the logical drive which is deleted. This first EBR now gives
+ * information of the next logical drive and the info about the subsequent
+ * extended partition. Hence the "relsect" of the first EBR is modified to
+ * point to the next logical drive.
+ *
+ * 2. Deleting an intermediate extended partition.
+ * This is quite normal and follows the semantics of a normal linked list
+ * delete operation. The node being deleted has the information about the
+ * logical drive that it houses and the location and the size of the next
+ * extended partition. This informationis transferred to the node previous
+ * to the node being deleted.
+ *
+ */
+
+void
+fdisk_delete_logical_drive(ext_part_t *epp, int pno)
+{
+ logical_drive_t *pre, *cur;
+ int i;
+
+ i = FD_NUMPART + 1;
+ pre = cur = epp->ld_head;
+ for (; i < pno; i++) {
+ pre = cur;
+ cur = cur->next;
+ }
+
+ if (cur == epp->ld_head) {
+ /* Deleting the first logical drive */
+ if (cur->next == NULL) {
+ /* Deleting the only logical drive left */
+ free(cur);
+ epp->ld_head = NULL;
+ epp->sorted_ld_head = NULL;
+ epp->logical_drive_count = 0;
+ epp->first_ebr_is_null = 1;
+ } else {
+ pre = epp->ld_head;
+ cur = pre->next;
+ cur->parts[0].relsect =
+ LE_32(LE_32(cur->parts[0].relsect) +
+ LE_32(pre->parts[1].relsect));
+ /* Corner case when partitions are out of order */
+ if ((pre->abs_secnum != epp->ext_beg_sec) &&
+ (cur->abs_secnum == epp->ext_beg_sec + 1)) {
+ cur->logdrive_offset++;
+ cur->abs_secnum = epp->ext_beg_sec;
+ } else {
+ cur->abs_secnum = LE_32(cur->parts[0].relsect) +
+ epp->ext_beg_sec;
+ cur->logdrive_offset = 0;
+ }
+ fdisk_ext_remove_from_sorted_list(epp, pre);
+ epp->ld_head = cur;
+ epp->ld_head->modified = FDISK_MAJOR_WRITE;
+ epp->logical_drive_count--;
+ free(pre);
+ }
+ } else {
+ pre->parts[1] = cur->parts[1];
+ pre->next = cur->next;
+ fdisk_ext_remove_from_sorted_list(epp, cur);
+ pre->modified = FDISK_MAJOR_WRITE;
+ free(cur);
+ epp->logical_drive_count--;
+ }
+}
+
+static void
+fdisk_set_CHS_values(ext_part_t *epp, struct ipart *part)
+{
+ uint32_t lba, cy, hd, sc;
+ uint32_t sectors = epp->disk_geom.virt_sec;
+ uint32_t heads = epp->disk_geom.virt_heads;
+
+ lba = LE_32(part->relsect) + epp->ext_beg_sec;
+ if (lba >= heads * 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 / sectors / heads;
+ hd = lba / sectors % heads;
+ sc = lba % sectors + 1;
+ }
+
+ part->begcyl = cy & 0xff;
+ part->beghead = (uchar_t)hd;
+ part->begsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
+
+ /*
+ * This code is identical to the code above
+ * except that it works on ending CHS values
+ */
+ lba += LE_32(part->numsect - 1);
+ if (lba >= heads * sectors * MAX_CYL) {
+ cy = MAX_CYL + 1;
+ hd = MAX_HEAD;
+ sc = MAX_SECT;
+ } else {
+ cy = lba / sectors / heads;
+ hd = lba / sectors % heads;
+ sc = lba % sectors + 1;
+ }
+ part->endcyl = cy & 0xff;
+ part->endhead = (uchar_t)hd;
+ part->endsect = (uchar_t)(((cy >> 2) & 0xc0) | sc);
+}
+
+static int
+read_modify_write_ebr(ext_part_t *epp, unsigned char *ebr_buf,
+ struct ipart *ebr_tab, uint32_t sec_offset)
+{
+ off_t seek_offset;
+ int sectsize = epp->disk_geom.sectsize;
+
+ seek_offset = (off_t)sec_offset * sectsize;
+
+ if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
+ return (EIO);
+ }
+ if (read(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
+ return (EIO);
+ }
+
+ bzero(&ebr_buf[FDISK_PART_TABLE_START], 4 * sizeof (struct ipart));
+ if (ebr_tab != NULL) {
+ bcopy(ebr_tab, &ebr_buf[FDISK_PART_TABLE_START],
+ 2 * sizeof (struct ipart));
+ }
+ ebr_buf[510] = 0x55;
+ ebr_buf[511] = 0xAA;
+ if (lseek(epp->dev_fd, seek_offset, SEEK_SET) < 0) {
+ return (EIO);
+ }
+ if (write(epp->dev_fd, ebr_buf, sectsize) < sectsize) {
+ return (EIO);
+ }
+ return (0);
+}
+
+/*
+ * XXX - ZFS mounts not detected. Needs to come in as a feature.
+ * Currently only /etc/mnttab entries are being checked
+ */
+int
+fdisk_mounted_logical_drives(ext_part_t *epp)
+{
+ char *part_str, *canonp;
+ char compare_pdev_str[PATH_MAX];
+ char compare_sdev_str[PATH_MAX];
+ FILE *fp;
+ struct mnttab mt;
+ int part;
+ int look_for_mounted_slices = 0;
+ uint32_t begsec, numsec;
+
+ if ((fp = fopen(MNTTAB, "r")) == NULL) {
+ return (ENOENT);
+ }
+
+ canonp = epp->device_name + strlen(DEFAULT_PATH_PREFIX);
+ (void) snprintf(compare_pdev_str, PATH_MAX, "%s%s", "/dev/dsk/",
+ canonp);
+ part_str = strrchr(compare_pdev_str, 'p');
+ *(part_str + 1) = '\0';
+ (void) strcpy(compare_sdev_str, compare_pdev_str);
+ part_str = strrchr(compare_sdev_str, 'p');
+ *part_str = 's';
+
+ if (fdisk_get_solaris_part(epp, &part, &begsec, &numsec) ==
+ FDISK_SUCCESS) {
+ if (part > FD_NUMPART) {
+ /*
+ * Solaris partition is on a logical drive. Look for
+ * mounted slices.
+ */
+ look_for_mounted_slices = 1;
+ }
+ }
+
+ while (getmntent(fp, &mt) == 0) {
+ if (strstr(mt.mnt_special, compare_pdev_str) == NULL) {
+ if (strstr(mt.mnt_special, compare_sdev_str) == NULL) {
+ continue;
+ } else {
+ if (look_for_mounted_slices) {
+ return (FDISK_EMOUNTED);
+ }
+ }
+ }
+
+ /*
+ * Get the partition number that is mounted, which would be
+ * found just beyond the last 'p' in the device string.
+ * For example, in /dev/dsk/c0t0d0p12, partition number 12
+ * is just beyond the last 'p'.
+ */
+ part_str = strrchr(mt.mnt_special, 'p');
+ if (part_str != NULL) {
+ part_str++;
+ part = atoi(part_str);
+ /* Extended partition numbers start from 5 */
+ if (part >= 5) {
+ return (FDISK_EMOUNTED);
+ }
+ }
+ }
+ return (0);
+}
+
+int
+fdisk_commit_ext_part(ext_part_t *epp)
+{
+ logical_drive_t *temp;
+ int wflag = 0; /* write flag */
+ int rval;
+ int sectsize = epp->disk_geom.sectsize;
+ unsigned char *ebr_buf;
+ int ld_count;
+ uint32_t abs_secnum;
+ int check_mounts = 0;
+ off_t lsmo;
+ char *lsm_buf;
+
+ if ((ebr_buf = (unsigned char *)malloc(sectsize)) == NULL) {
+ return (ENOMEM);
+ }
+ if ((lsm_buf = calloc(1, sectsize)) == NULL) {
+ return (ENOMEM);
+ }
+
+ if (epp->first_ebr_is_null) {
+ /*
+ * Indicator that the extended partition as a whole was
+ * modifies (either created or deleted. Must check for mounts
+ * and must commit
+ */
+ check_mounts = 1;
+ }
+
+ /*
+ * Pass1 through the logical drives to make sure that commit of minor
+ * written block dont get held up due to mounts.
+ */
+ for (temp = epp->ld_head; temp != NULL; temp = temp->next) {
+ if (temp == epp->ld_head) {
+ abs_secnum = epp->ext_beg_sec;
+ } else {
+ abs_secnum = temp->abs_secnum;
+ }
+ if (temp->modified == FDISK_MINOR_WRITE) {
+ rval = read_modify_write_ebr(epp, ebr_buf,
+ temp->parts, abs_secnum);
+ if (rval) {
+ goto error;
+ }
+ temp->modified = 0;
+ } else if (temp->modified == FDISK_MAJOR_WRITE) {
+ check_mounts = 1;
+ }
+ }
+
+ if (!check_mounts) {
+ goto skip_check_mounts;
+ }
+
+ if ((rval = fdisk_mounted_logical_drives(epp)) != 0) {
+ /* One/more extended partitions are mounted */
+ if (ebr_buf) {
+ free(ebr_buf);
+ }
+ if (lsm_buf) {
+ free(lsm_buf);
+ }
+ return (rval);
+ }
+
+skip_check_mounts:
+
+ if (epp->first_ebr_is_null) {
+ rval = read_modify_write_ebr(epp, ebr_buf, NULL,
+ epp->ext_beg_sec);
+ if (rval) {
+ goto error;
+ }
+ wflag = 1;
+ ld_count = 0;
+ } else {
+ if (epp->logical_drive_count == 0) {
+ /*
+ * Can hit this case when there is just an extended
+ * partition with no logical drives, and the user
+ * committed without making any changes
+ * We dont have anything to commit. Return success
+ */
+ if (ebr_buf) {
+ free(ebr_buf);
+ }
+ if (lsm_buf) {
+ free(lsm_buf);
+ }
+ return (FDISK_SUCCESS);
+ }
+
+ /*
+ * Make sure that the first EBR is written with the first
+ * logical drive's data, which might not be the first in disk
+ * order.
+ */
+ for (temp = epp->ld_head, ld_count = 0; temp != NULL;
+ temp = temp->next, ld_count++) {
+ /*
+ * Check if the current partition is a solaris old
+ * partition. In that case, check if it was previously
+ * a linux swap. If so, overwrite the linux swap magic.
+ */
+ if (temp->parts[0].systid == SUNIXOS) {
+ uint32_t secnum = temp->abs_secnum +
+ temp->logdrive_offset;
+ if (fdisk_is_linux_swap(epp, secnum,
+ &lsmo) == 0) {
+ if ((rval = lseek(epp->dev_fd, lsmo,
+ SEEK_SET)) < 0) {
+ if (ld_count) {
+ break;
+ }
+ goto error;
+ }
+
+ if (read(epp->dev_fd, lsm_buf,
+ sectsize) < sectsize) {
+ rval = EIO;
+ if (ld_count) {
+ break;
+ }
+ goto error;
+ }
+
+ bzero(lsm_buf + sectsize -
+ LINUX_SWAP_MAGIC_LENGTH,
+ LINUX_SWAP_MAGIC_LENGTH);
+
+ if ((rval = lseek(epp->dev_fd, lsmo,
+ SEEK_SET)) < 0) {
+ if (ld_count) {
+ break;
+ }
+ goto error;
+ }
+
+ if ((rval = write(epp->dev_fd, lsm_buf,
+ sectsize)) < sectsize) {
+ rval = EIO;
+ if (ld_count) {
+ break;
+ }
+ goto error;
+ }
+ }
+ }
+
+ if (ld_count == 0) {
+ abs_secnum = epp->ext_beg_sec;
+ } else {
+ abs_secnum = temp->abs_secnum;
+ }
+ if (temp->modified) {
+ rval = read_modify_write_ebr(epp, ebr_buf,
+ temp->parts, abs_secnum);
+ if (rval) {
+ if (ld_count) {
+ /*
+ * There was atleast one
+ * write to the disk before
+ * this failure. Make sure that
+ * the kernel is notified.
+ * Issue the ioctl.
+ */
+ break;
+ }
+ goto error;
+ }
+ if ((!wflag) && (temp->modified ==
+ FDISK_MAJOR_WRITE)) {
+ wflag = 1;
+ }
+ }
+ }
+
+ if (wflag == 0) {
+ /* No changes made */
+ rval = FDISK_SUCCESS;
+ goto error;
+ }
+ }
+
+ /* Issue ioctl to the driver to update extended partition info */
+ rval = ioctl(epp->dev_fd, DKIOCSETEXTPART);
+error:
+ if (ebr_buf) {
+ free(ebr_buf);
+ }
+ if (lsm_buf) {
+ free(lsm_buf);
+ }
+ return (rval);
+}
+
+int
+fdisk_init_ext_part(ext_part_t *epp, uint32_t rsect, uint32_t nsect)
+{
+ epp->first_ebr_is_null = 1;
+ epp->corrupt_logical_drives = 0;
+ epp->logical_drive_count = 0;
+ epp->ext_beg_sec = rsect;
+ epp->ext_end_sec = rsect + nsect - 1;
+ epp->ext_beg_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_beg_sec);
+ epp->ext_end_cyl = FDISK_SECT_TO_CYL(epp, epp->ext_end_sec);
+ epp->invalid_bb_sig[0] = 0;
+ return (0);
+}
+
+int
+fdisk_delete_ext_part(ext_part_t *epp)
+{
+ epp->first_ebr_is_null = 1;
+ /* Clear the logical drive information */
+ fdisk_free_ld_nodes(epp);
+ epp->logical_drive_count = 0;
+ epp->corrupt_logical_drives = 0;
+ epp->invalid_bb_sig[0] = 0;
+ return (0);
+}
+
+int
+fdisk_get_disk_geom(ext_part_t *epp, int type, int what)
+{
+ switch (type) {
+ case PHYSGEOM:
+ switch (what) {
+ case NCYL:
+ return ((int)epp->disk_geom.phys_cyl);
+ case NHEADS:
+ return ((int)epp->disk_geom.phys_heads);
+ case NSECTPT:
+ return ((int)epp->disk_geom.phys_sec);
+ case SSIZE:
+ return ((int)epp->disk_geom.sectsize);
+ case ACYL:
+ return ((int)epp->disk_geom.alt_cyl);
+ default:
+ return (EINVAL);
+ }
+ case VIRTGEOM:
+ switch (what) {
+ case NCYL:
+ return ((int)epp->disk_geom.virt_cyl);
+ case NHEADS:
+ return ((int)epp->disk_geom.virt_heads);
+ case NSECTPT:
+ return ((int)epp->disk_geom.virt_sec);
+ case SSIZE:
+ return ((int)epp->disk_geom.sectsize);
+ case ACYL:
+ return ((int)epp->disk_geom.alt_cyl);
+ default:
+ return (EINVAL);
+ }
+ default:
+ return (EINVAL);
+ }
+}
+
+int
+fdisk_invalid_bb_sig(ext_part_t *epp, uchar_t **bbsig_arr)
+{
+ *bbsig_arr = &(epp->invalid_bb_sig[0]);
+ return (epp->invalid_bb_sig[0]);
+}
diff --git a/usr/src/lib/libfdisk/i386/libfdisk.h b/usr/src/lib/libfdisk/i386/libfdisk.h
new file mode 100644
index 0000000000..46e16f4bf1
--- /dev/null
+++ b/usr/src/lib/libfdisk/i386/libfdisk.h
@@ -0,0 +1,304 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+
+#ifndef _LIBFDISK_H_
+#define _LIBFDISK_H_
+
+#include <limits.h>
+#include <sys/dktp/fdisk.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_LOGDRIVE_OFFSET 63
+
+#define FDISK_ERRNO 200
+#define FDISK_ETOOLONG (FDISK_ERRNO + 0)
+#define FDISK_EOOBOUND (FDISK_ERRNO + 1)
+#define FDISK_EZERO (FDISK_ERRNO + 2)
+#define FDISK_EOVERLAP (FDISK_ERRNO + 3)
+#define FDISK_ENOVGEOM (FDISK_ERRNO + 4)
+#define FDISK_ENOPGEOM (FDISK_ERRNO + 5)
+#define FDISK_ENOLGEOM (FDISK_ERRNO + 6)
+#define FDISK_ENOLOGDRIVE (FDISK_ERRNO + 7)
+#define FDISK_EBADLOGDRIVE (FDISK_ERRNO + 8)
+#define FDISK_ENOEXTPART (FDISK_ERRNO + 9)
+#define FDISK_EBADMAGIC (FDISK_ERRNO + 10)
+#define FDISK_EMOUNTED (FDISK_ERRNO + 11)
+
+#define FDISK_SUCCESS 0
+
+#define FDISK_READ_DISK 0x00000001
+
+#define LINUX_SWAP_MAGIC_LENGTH 10
+enum {
+ PHYSGEOM = 0,
+ VIRTGEOM,
+ NCYL,
+ NHEADS,
+ NSECTPT,
+ SSIZE,
+ ACYL
+};
+
+enum {
+ FDISK_MINOR_WRITE = 1,
+ FDISK_MAJOR_WRITE
+};
+
+#define FDISK_SECTS_PER_CYL(epp) \
+ (epp->disk_geom.phys_heads * epp->disk_geom.phys_sec)
+#define FDISK_SECT_TO_CYL(epp, x) ((x) / (FDISK_SECTS_PER_CYL(epp)))
+#define FDISK_CYL_TO_SECT(epp, x) ((x) * (FDISK_SECTS_PER_CYL(epp)))
+#define FDISK_ABS_CYL_NUM(epp, x) (FDISK_SECT_TO_CYL(x) +\
+ epp->ext_beg_cyl)
+
+#define FDISK_CYL_BNDRY_ALIGN(epp, x) (((x) % (FDISK_SECTS_PER_CYL(epp))) ? \
+ (((x)/(FDISK_SECTS_PER_CYL(epp))) + 1) :\
+ ((x)/(FDISK_SECTS_PER_CYL(epp))))
+
+/*
+ * Extended partition structure :
+ * +--------------+
+ * |+--+ |
+ * || |----------+---> structure at the beginning of the extended partition
+ * ||--| | ( Lets call it the EBR - Extended Boot Record )
+ * || | +---+--->
+ * |+--+ | | Logical drive within the extended partition
+ * |+---------+--+| ( We will plainly call this a logical drive )
+ * || ||
+ * || ||
+ * || ||
+ * |+------------+|
+ * +--------------+
+ *
+ *
+ * EBR is effectively "struct ipart parts[2]".
+ * The picture below shows what the EBR contains. The EBR has
+ * two important pieces of information. The first is the offset and the size
+ * of the logical drive in this extended partition. The second is the offset
+ * and size of the next extended partition. The offsets are relative to
+ * beginning of the first extended partition. These extended partitions are
+ * arranged like a linked list.
+ * Note that (currently) only one extended partition can exist in the MBR.
+ * The system ID of a logical drive within the extended partition cannot be
+ * that of an extended partition.
+ *
+ * +------+
+ * | |
+ * +--------------+ | +-v------------+
+ * |+--+ | | |+--+ |
+ * || |---+ | | || | |
+ * ||--| | | | ||--| |
+ * || |---|------+-+ || | |
+ * |+--+ | | |+--+ |
+ * |+------v-----+| |+------------+|
+ * || || || ||
+ * || || || ||
+ * || || || ||
+ * |+------------+| |+------------+|
+ * +--------------+ +--------------+
+ *
+ */
+
+/*
+ * Main structure used to record changes to the partitions made.
+ * Changes are not written to disk everytime, but maintained in this structure.
+ * This information is used when the user chooses to commit the changes.
+ * A linked list of this structure represents the ondisk partitions.
+ */
+typedef struct logical_drive {
+
+ /* structure holding the EBR data */
+ struct ipart parts[2];
+
+ /*
+ * Absolute beginning sector of the extended partition, and hence an
+ * indicator of where the EBR for this logical drive would go on disk.
+ * NOTE : In case the first logical drive in this extended partition is
+ * out of (disk) order, this indicates the beginning of the logical
+ * drive. The EBR will anyway be at the first sector of the extended
+ * partition, for the first logical drive.
+ */
+ uint32_t abs_secnum;
+
+ /*
+ * Offset of the logical drive from the beginning of its extended
+ * partition
+ */
+ uint32_t logdrive_offset;
+
+ /* Size of the logical drive in sectors */
+ uint32_t numsect;
+
+ /* Beginning and ending cylinders of the extended partition */
+ uint32_t begcyl, endcyl;
+
+ /*
+ * Flag to indicate if this record is to be sync'ed to disk.
+ * It takes two values : FDISK_MAJOR_WRITE and FDISK_MINOR_WRITE
+ * If it is a minor write, there is no need to update the information
+ * in the kernel structures. Example of a minor write is correction of
+ * a corrupt boot signature.
+ */
+ int modified;
+
+ /*
+ * This pointer points to the next extended partition in the order
+ * found on disk.
+ */
+ struct logical_drive *next;
+
+ /*
+ * This pointer points to the next extended partition in a sorted list
+ * sorted in the ascending order of their beginning cylinders.
+ */
+ struct logical_drive *sorted_next;
+
+} logical_drive_t;
+
+typedef struct fdisk_disk_geom {
+ ushort_t phys_cyl;
+ ushort_t phys_sec;
+ ushort_t phys_heads;
+ ushort_t alt_cyl;
+ ushort_t virt_cyl;
+ ushort_t virt_sec;
+ ushort_t virt_heads;
+ ushort_t sectsize;
+} fdisk_disk_geom_t;
+
+typedef struct ext_part
+{
+ /* Structure holding geometry information about the device */
+ fdisk_disk_geom_t disk_geom;
+
+ struct ipart *mtable;
+
+ char device_name[PATH_MAX];
+
+ int dev_fd;
+
+ int op_flag;
+
+ /*
+ * Head of the in memory structure (singly linked list) of extended
+ * partition information.
+ */
+ logical_drive_t *ld_head;
+ logical_drive_t *sorted_ld_head;
+
+ /* Beginning cylinder of the extended partition */
+ uint32_t ext_beg_cyl;
+
+ /* Ending cylinder of the extended partition */
+ uint32_t ext_end_cyl;
+
+ /* Beginning sector of the extended partition */
+ uint32_t ext_beg_sec;
+
+ /* Ending sector of the extended partition */
+ uint32_t ext_end_sec;
+
+ /* Count of the number of logical drives in the extended partition */
+ int logical_drive_count;
+
+ /*
+ * Flag to keep track of the update to be made to the Extended Boot
+ * Record (EBR) when all logical drives are deleted. The EBR is filled
+ * with zeroes in such a case.
+ */
+ int first_ebr_is_null;
+
+ /*
+ * Flag to indicate corrupt logical drives. Can happen when a partition
+ * manager creates an extended partition and does not null the first EBR
+ * or when important ondisk structures are overwritten by a bad program
+ */
+ int corrupt_logical_drives;
+
+ /*
+ * The boot block signature 0xAA55 might not be found on some of the
+ * EBRs. ( Even though the rest of the data might be good )
+ * The following array is used to store the list of such logical drive
+ * numbers.
+ */
+ uchar_t invalid_bb_sig[MAX_EXT_PARTS];
+
+ /*
+ * Can add a "next" pointer here in case support for multiple
+ * extended partitions becomes the standard someday.
+ *
+ * struct ext_part *next;
+ */
+} ext_part_t;
+
+#define fdisk_get_logical_drive_count(epp) ((epp)->logical_drive_count)
+#define fdisk_corrupt_logical_drives(epp) ((epp)->corrupt_logical_drives)
+#define fdisk_get_ext_beg_cyl(epp) ((epp)->ext_beg_cyl)
+#define fdisk_get_ext_end_cyl(epp) ((epp)->ext_end_cyl)
+#define fdisk_get_ext_beg_sec(epp) ((epp)->ext_beg_sec)
+#define fdisk_get_ext_end_sec(epp) ((epp)->ext_end_sec)
+#define fdisk_get_ld_head(epp) ((epp)->ld_head)
+#define fdisk_is_solaris_part(id) (((id) == SUNIXOS) || ((id) == SUNIXOS2))
+#define fdisk_is_dos_extended(id) (((id) == EXTDOS) || ((id) == FDISK_EXTLBA))
+
+extern int fdisk_is_linux_swap(ext_part_t *epp, uint32_t part_start,
+ off_t *lsm_offset);
+extern int libfdisk_init(ext_part_t **epp, char *devstr, struct ipart *parttab,
+ int opflag);
+extern int libfdisk_reset(ext_part_t *epp);
+extern void libfdisk_fini(ext_part_t **epp);
+extern int fdisk_ext_find_first_free_sec(ext_part_t *epp,
+ uint32_t *first_free_sec);
+extern uint32_t fdisk_ext_find_last_free_sec(ext_part_t *epp, uint32_t begsec);
+extern int fdisk_ext_part_exists(ext_part_t *epp);
+extern int fdisk_validate_logical_drive(ext_part_t *epp, uint32_t begsec,
+ uint32_t offset, uint32_t numsec);
+extern int fdisk_ext_validate_part_start(ext_part_t *epp, uint32_t begcyl,
+ uint32_t *begsec);
+extern int fdisk_get_solaris_part(ext_part_t *epp, int *pnum, uint32_t *begsec,
+ uint32_t *numsec);
+extern int fdisk_get_part_info(ext_part_t *epp, int pnum, uchar_t *sysid,
+ uint32_t *begsec, uint32_t *numsec);
+extern int fdisk_commit_ext_part(ext_part_t *epp);
+extern void fdisk_change_logical_drive_id(ext_part_t *epp, int pno,
+ uchar_t partid);
+extern void fdisk_add_logical_drive(ext_part_t *epp, uint32_t begsec,
+ uint32_t endsec, uchar_t partid);
+extern void fdisk_delete_logical_drive(ext_part_t *epp, int pno);
+extern int fdisk_init_ext_part(ext_part_t *epp, uint32_t rsect, uint32_t nsect);
+extern int fdisk_delete_ext_part(ext_part_t *epp);
+extern int fdisk_get_disk_geom(ext_part_t *epp, int type, int what);
+extern int fdisk_invalid_bb_sig(ext_part_t *epp, uchar_t **bbsig_arr);
+extern int fdisk_mounted_logical_drives(ext_part_t *epp);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBFDISK_H_ */
diff --git a/usr/src/lib/libfdisk/i386/llib-lfdisk b/usr/src/lib/libfdisk/i386/llib-lfdisk
new file mode 100644
index 0000000000..ab95e0068d
--- /dev/null
+++ b/usr/src/lib/libfdisk/i386/llib-lfdisk
@@ -0,0 +1,31 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ *
+ * usr/src/lib/libfdisk/llib-lfdisk
+ */
+
+/*LINTLIBRARY*/
+/*PROTOLIB1*/
+
+#include <libfdisk.h>
diff --git a/usr/src/lib/libfdisk/i386/mapfile-vers b/usr/src/lib/libfdisk/i386/mapfile-vers
new file mode 100644
index 0000000000..d135c15ffc
--- /dev/null
+++ b/usr/src/lib/libfdisk/i386/mapfile-vers
@@ -0,0 +1,65 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+#
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
+# Use is subject to license terms.
+#
+#
+
+#
+# MAPFILE HEADER START
+#
+# WARNING: STOP NOW. DO NOT MODIFY THIS FILE.
+# Object versioning must comply with the rules detailed in
+#
+# usr/src/lib/README.mapfiles
+#
+# You should not be making modifications here until you've read the most current
+# copy of that file. If you need help, contact a gatekeeper for guidance.
+#
+# MAPFILE HEADER END
+#
+
+SUNWprivate_1.1 {
+ global:
+ fdisk_ext_validate_part_start;
+ fdisk_commit_ext_part;
+ fdisk_ext_find_last_free_sec;
+ fdisk_ext_find_first_free_sec;
+ fdisk_delete_logical_drive;
+ fdisk_add_logical_drive;
+ fdisk_is_linux_swap;
+ fdisk_get_disk_geom;
+ fdisk_init_ext_part;
+ fdisk_get_solaris_part;
+ fdisk_get_part_info;
+ fdisk_invalid_bb_sig;
+ libfdisk_init;
+ libfdisk_reset;
+ libfdisk_fini;
+ fdisk_validate_logical_drive;
+ fdisk_change_logical_drive_id;
+ fdisk_delete_ext_part;
+ fdisk_ext_part_exists;
+ fdisk_mounted_logical_drives;
+ local:
+ *;
+};
diff --git a/usr/src/pkgdefs/SUNWarc/prototype_i386 b/usr/src/pkgdefs/SUNWarc/prototype_i386
index f88c1eb966..3ed9cf42d8 100644
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -167,3 +167,5 @@ s none usr/ccs/lib/amd64/values-xpg6.o=../../../lib/amd64/values-xpg6.o
d none usr/lib/scsi/amd64 755 root bin
f none usr/lib/scsi/amd64/llib-lscsi.ln 644 root bin
f none usr/lib/scsi/amd64/llib-lses.ln 644 root bin
+s none usr/lib/llib-lfdisk=../../lib/llib-lfdisk
+s none usr/lib/llib-lfdisk.ln=../../lib/llib-lfdisk.ln
diff --git a/usr/src/pkgdefs/SUNWarcr/prototype_i386 b/usr/src/pkgdefs/SUNWarcr/prototype_i386
index 205dccfc54..b1070ea2ac 100644
--- a/usr/src/pkgdefs/SUNWarcr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWarcr/prototype_i386
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
@@ -100,3 +100,5 @@ f none lib/amd64/llib-lumem.ln 644 root bin
f none lib/amd64/llib-luuid.ln 644 root bin
f none lib/amd64/llib-luutil.ln 644 root bin
f none lib/amd64/llib-lxnet.ln 644 root bin
+f none lib/llib-lfdisk 644 root bin
+f none lib/llib-lfdisk.ln 644 root bin
diff --git a/usr/src/pkgdefs/SUNWcsl/prototype_i386 b/usr/src/pkgdefs/SUNWcsl/prototype_i386
index 0facb5caed..056f61982c 100644
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386
@@ -370,6 +370,8 @@ f none usr/lib/amd64/passwdutil.so.1 755 root bin
f none usr/lib/amd64/straddr.so.2 755 root bin
s none usr/lib/amd64/straddr.so=straddr.so.2
f none usr/lib/amd64/watchmalloc.so.1 755 root bin
+s none usr/lib/libfdisk.so.1=../../lib/libfdisk.so.1
+s none usr/lib/libfdisk.so=../../lib/libfdisk.so.1
d none usr/xpg4/lib/amd64 755 root bin
s none usr/xpg4/lib/64=amd64
f none usr/xpg4/lib/amd64/libcurses.so.1 755 root bin
diff --git a/usr/src/pkgdefs/SUNWcslr/prototype_i386 b/usr/src/pkgdefs/SUNWcslr/prototype_i386
index 74a8ccbf30..f43e6202ad 100644
--- a/usr/src/pkgdefs/SUNWcslr/prototype_i386
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_i386
@@ -18,7 +18,7 @@
#
# CDDL HEADER END
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This required package information file contains a list of package contents.
@@ -172,6 +172,8 @@ s none lib/crypto/64=amd64
f none lib/crypto/amd64/kmf_nss.so.1 755 root bin
f none lib/crypto/amd64/kmf_openssl.so.1 755 root bin
f none lib/crypto/amd64/kmf_pkcs11.so.1 755 root bin
+s none lib/libfdisk.so=libfdisk.so.1
+f none lib/libfdisk.so.1 755 root bin
v none lib/libc.so.1 755 root bin
d none lib/secure/amd64 755 root bin
s none lib/secure/64=amd64
diff --git a/usr/src/pkgdefs/SUNWhea/prototype_i386 b/usr/src/pkgdefs/SUNWhea/prototype_i386
index 3a0e88aa20..bc18983d84 100644
--- a/usr/src/pkgdefs/SUNWhea/prototype_i386
+++ b/usr/src/pkgdefs/SUNWhea/prototype_i386
@@ -19,7 +19,7 @@
# CDDL HEADER END
#
#
-# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
# This required package information file contains a list of package contents.
@@ -46,6 +46,7 @@
#
# SUNWhea
#
+f none usr/include/libfdisk.h 644 root bin
f none usr/include/asm/atomic.h 644 root bin
f none usr/include/asm/bitmap.h 644 root bin
f none usr/include/asm/byteorder.h 644 root bin
diff --git a/usr/src/uts/common/io/cmlb.c b/usr/src/uts/common/io/cmlb.c
index 343b1b965c..040b8c56f9 100644
--- a/usr/src/uts/common/io/cmlb.c
+++ b/usr/src/uts/common/io/cmlb.c
@@ -39,6 +39,9 @@
#include <sys/efi_partition.h>
#include <sys/cmlb.h>
#include <sys/cmlb_impl.h>
+#if defined(__i386) || defined(__amd64)
+#include <sys/fs/dv_node.h>
+#endif
#include <sys/ddi_impldefs.h>
/*
@@ -104,6 +107,78 @@ static struct driver_minor_data dk_minor_data[] = {
{0}
};
+#if defined(__i386) || defined(__amd64)
+#if defined(_FIRMWARE_NEEDS_FDISK)
+static struct driver_minor_data dk_ext_minor_data[] = {
+ {"p5", 21, S_IFBLK},
+ {"p6", 22, S_IFBLK},
+ {"p7", 23, S_IFBLK},
+ {"p8", 24, S_IFBLK},
+ {"p9", 25, S_IFBLK},
+ {"p10", 26, S_IFBLK},
+ {"p11", 27, S_IFBLK},
+ {"p12", 28, S_IFBLK},
+ {"p13", 29, S_IFBLK},
+ {"p14", 30, S_IFBLK},
+ {"p15", 31, S_IFBLK},
+ {"p16", 32, S_IFBLK},
+ {"p17", 33, S_IFBLK},
+ {"p18", 34, S_IFBLK},
+ {"p19", 35, S_IFBLK},
+ {"p20", 36, S_IFBLK},
+ {"p21", 37, S_IFBLK},
+ {"p22", 38, S_IFBLK},
+ {"p23", 39, S_IFBLK},
+ {"p24", 40, S_IFBLK},
+ {"p25", 41, S_IFBLK},
+ {"p26", 42, S_IFBLK},
+ {"p27", 43, S_IFBLK},
+ {"p28", 44, S_IFBLK},
+ {"p29", 45, S_IFBLK},
+ {"p30", 46, S_IFBLK},
+ {"p31", 47, S_IFBLK},
+ {"p32", 48, S_IFBLK},
+ {"p33", 49, S_IFBLK},
+ {"p34", 50, S_IFBLK},
+ {"p35", 51, S_IFBLK},
+ {"p36", 52, S_IFBLK},
+ {"p5,raw", 21, S_IFCHR},
+ {"p6,raw", 22, S_IFCHR},
+ {"p7,raw", 23, S_IFCHR},
+ {"p8,raw", 24, S_IFCHR},
+ {"p9,raw", 25, S_IFCHR},
+ {"p10,raw", 26, S_IFCHR},
+ {"p11,raw", 27, S_IFCHR},
+ {"p12,raw", 28, S_IFCHR},
+ {"p13,raw", 29, S_IFCHR},
+ {"p14,raw", 30, S_IFCHR},
+ {"p15,raw", 31, S_IFCHR},
+ {"p16,raw", 32, S_IFCHR},
+ {"p17,raw", 33, S_IFCHR},
+ {"p18,raw", 34, S_IFCHR},
+ {"p19,raw", 35, S_IFCHR},
+ {"p20,raw", 36, S_IFCHR},
+ {"p21,raw", 37, S_IFCHR},
+ {"p22,raw", 38, S_IFCHR},
+ {"p23,raw", 39, S_IFCHR},
+ {"p24,raw", 40, S_IFCHR},
+ {"p25,raw", 41, S_IFCHR},
+ {"p26,raw", 42, S_IFCHR},
+ {"p27,raw", 43, S_IFCHR},
+ {"p28,raw", 44, S_IFCHR},
+ {"p29,raw", 45, S_IFCHR},
+ {"p30,raw", 46, S_IFCHR},
+ {"p31,raw", 47, S_IFCHR},
+ {"p32,raw", 48, S_IFCHR},
+ {"p33,raw", 49, S_IFCHR},
+ {"p34,raw", 50, S_IFCHR},
+ {"p35,raw", 51, S_IFCHR},
+ {"p36,raw", 52, S_IFCHR},
+ {0}
+};
+#endif /* defined(_FIRMWARE_NEEDS_FDISK) */
+#endif /* if defined(__i386) || defined(__amd64) */
+
static struct driver_minor_data dk_minor_data_efi[] = {
{"a", 0, S_IFBLK},
{"b", 1, S_IFBLK},
@@ -267,6 +342,12 @@ static int cmlb_dkio_partition(struct cmlb_lun *cl, caddr_t arg, int flag,
void *tg_cookie);
#if defined(__i386) || defined(__amd64)
+static int cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
+ void *tg_cookie);
+static int cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart,
+ uint32_t start, uint32_t size);
+static int cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start,
+ void *tg_cookie);
static int cmlb_dkio_get_virtgeom(struct cmlb_lun *cl, caddr_t arg, int flag);
static int cmlb_dkio_get_phygeom(struct cmlb_lun *cl, caddr_t arg, int flag);
static int cmlb_dkio_partinfo(struct cmlb_lun *cl, dev_t dev, caddr_t arg,
@@ -614,6 +695,9 @@ cmlb_attach(dev_info_t *devi, cmlb_tg_ops_t *tgopsp, int device_type,
cl->cl_alter_behavior = alter_behavior;
cl->cl_reserved = -1;
cl->cl_msglog_flag |= CMLB_ALLOW_2TB_WARN;
+#if defined(__i386) || defined(__amd64)
+ cl->cl_logical_drive_count = 0;
+#endif
if (!is_removable) {
mutex_exit(CMLB_MUTEX(cl));
@@ -945,6 +1029,9 @@ cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp,
struct cmlb_lun *cl = (struct cmlb_lun *)cmlbhandle;
int rval;
+#if defined(__i386) || defined(__amd64)
+ int ext_part;
+#endif
ASSERT(cl != NULL);
mutex_enter(CMLB_MUTEX(cl));
@@ -986,8 +1073,17 @@ cmlb_partinfo(cmlb_handle_t cmlbhandle, int part, diskaddr_t *nblocksp,
}
/* consistent with behavior of sd for getting minor name */
- if (partnamep != NULL)
+ if (partnamep != NULL) {
+#if defined(__i386) || defined(__amd64)
+#if defined(_FIRMWARE_NEEDS_FDISK)
+ if (part > FDISK_P4) {
+ ext_part = part-FDISK_P4-1;
+ *partnamep = dk_ext_minor_data[ext_part].name;
+ } else
+#endif
+#endif
*partnamep = dk_minor_data[part].name;
+ }
}
@@ -1072,6 +1168,9 @@ cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg,
case DKIOCSGEOM:
case DKIOCSETEFI:
case DKIOCSMBOOT:
+#if defined(__i386) || defined(__amd64)
+ case DKIOCSETEXTPART:
+#endif
break;
case DKIOCSVTOC:
#if defined(__i386) || defined(__amd64)
@@ -1216,7 +1315,12 @@ cmlb_ioctl(cmlb_handle_t cmlbhandle, dev_t dev, int cmd, intptr_t arg,
err = ENOTTY;
#endif
break;
-
+#if defined(__i386) || defined(__amd64)
+ case DKIOCSETEXTPART:
+ cmlb_dbg(CMLB_TRACE, cl, "DKIOCSETEXTPART");
+ err = cmlb_dkio_set_ext_part(cl, (caddr_t)arg, flag, tg_cookie);
+ break;
+#endif
default:
err = ENOTTY;
@@ -1661,7 +1765,7 @@ no_solaris_partition:
* Note that dkl_cylno is not used for the fdisk map entries, so
* we set it to an entirely bogus value.
*/
- for (count = 0; count < FD_NUMPART; count++) {
+ for (count = 0; count < FDISK_PARTS; count++) {
cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT16_MAX;
cl->cl_map[FDISK_P1 + count].dkl_nblk =
cl->cl_fmap[count].fmap_nblk;
@@ -1869,6 +1973,281 @@ cmlb_resync_geom_caches(struct cmlb_lun *cl, diskaddr_t capacity,
}
+#if defined(__i386) || defined(__amd64)
+/*
+ * Function: cmlb_update_ext_minor_nodes
+ *
+ * Description: Routine to add/remove extended partition device nodes
+ *
+ * Arguments:
+ * cl driver soft state (unit) structure
+ * num_parts Number of logical drives found on the LUN
+ *
+ * Should be called with the mutex held
+ *
+ * Return Code: 0 for success
+ *
+ * Context: User and Kernel thread
+ *
+ */
+static int
+cmlb_update_ext_minor_nodes(struct cmlb_lun *cl, int num_parts)
+{
+ int i, count;
+ char name[48];
+ int instance;
+ struct driver_minor_data *demdp, *demdpr;
+ char *devnm;
+ dev_info_t *pdip;
+ boolean_t internal;
+
+ ASSERT(mutex_owned(CMLB_MUTEX(cl)));
+ ASSERT(cl->cl_update_ext_minor_nodes == 1);
+
+ internal = VOID2BOOLEAN(
+ (cl->cl_alter_behavior & (CMLB_INTERNAL_MINOR_NODES)) != 0);
+ instance = ddi_get_instance(CMLB_DEVINFO(cl));
+ demdp = dk_ext_minor_data;
+ demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
+
+
+ if (cl->cl_logical_drive_count) {
+ for (i = 0; i < cl->cl_logical_drive_count; i++) {
+ (void) sprintf(name, "%s", demdp->name);
+ ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
+ (void) sprintf(name, "%s", demdpr->name);
+ ddi_remove_minor_node(CMLB_DEVINFO(cl), name);
+ demdp++;
+ demdpr++;
+ }
+ /* There are existing device nodes. Remove them */
+ devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
+ (void) ddi_deviname(cl->cl_devi, devnm);
+ pdip = ddi_get_parent(cl->cl_devi);
+ (void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
+ kmem_free(devnm, MAXNAMELEN + 1);
+ }
+
+ demdp = dk_ext_minor_data;
+ demdpr = &dk_ext_minor_data[MAX_EXT_PARTS];
+
+ for (i = 0; i < num_parts; i++) {
+ (void) sprintf(name, "%s", demdp->name);
+ if (cmlb_create_minor(CMLB_DEVINFO(cl), name,
+ demdp->type,
+ (instance << CMLBUNIT_SHIFT) | demdp->minor,
+ cl->cl_node_type, NULL, internal) == DDI_FAILURE) {
+ /*
+ * Clean up any nodes that may have been
+ * created, in case this fails in the middle
+ * of the loop.
+ */
+ ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
+ cl->cl_logical_drive_count = 0;
+ return (ENXIO);
+ }
+ (void) sprintf(name, "%s", demdpr->name);
+ if (ddi_create_minor_node(CMLB_DEVINFO(cl), name,
+ demdpr->type,
+ (instance << CMLBUNIT_SHIFT) | demdpr->minor,
+ cl->cl_node_type, NULL) == DDI_FAILURE) {
+ /*
+ * Clean up any nodes that may have been
+ * created, in case this fails in the middle
+ * of the loop.
+ */
+ ddi_remove_minor_node(CMLB_DEVINFO(cl), NULL);
+ cl->cl_logical_drive_count = 0;
+ return (ENXIO);
+ }
+ demdp++;
+ demdpr++;
+ }
+
+ /* Update the cl_map array for logical drives */
+ for (count = 0; count < MAX_EXT_PARTS; count++) {
+ cl->cl_map[FDISK_P4 + 1 + count].dkl_cylno = UINT32_MAX;
+ cl->cl_map[FDISK_P4 + 1 + count].dkl_nblk =
+ cl->cl_fmap[FD_NUMPART + count].fmap_nblk;
+ cl->cl_offset[FDISK_P4 + 1 + count] =
+ cl->cl_fmap[FD_NUMPART + count].fmap_start;
+ }
+
+ cl->cl_logical_drive_count = i;
+ cl->cl_update_ext_minor_nodes = 0;
+ return (0);
+}
+/*
+ * Function: cmlb_validate_ext_part
+ *
+ * Description: utility routine to validate an extended partition's
+ * metadata as found on disk
+ *
+ * Arguments:
+ * cl driver soft state (unit) structure
+ * part partition number of the extended partition
+ * epart partition number of the logical drive
+ * start absolute sector number of the start of the logical
+ * drive being validated
+ * size size of logical drive being validated
+ *
+ * Return Code: 0 for success
+ *
+ * Context: User and Kernel thread
+ *
+ * Algorithm :
+ * Error cases are :
+ * 1. If start block is lesser than or equal to the end block
+ * 2. If either start block or end block is beyond the bounadry
+ * of the extended partition.
+ * 3. start or end block overlap with existing partitions.
+ * To check this, first make sure that the start block doesnt
+ * overlap with existing partitions. Then, calculate the
+ * possible end block for the given start block that doesnt
+ * overlap with existing partitions. This can be calculated by
+ * first setting the possible end block to the end of the
+ * extended partition (optimistic) and then, checking if there
+ * is any other partition that lies after the start of the
+ * partition being validated. If so, set the possible end to
+ * one block less than the beginning of the next nearest partition
+ * If the actual end block is greater than the calculated end
+ * block, we have an overlap.
+ *
+ */
+static int
+cmlb_validate_ext_part(struct cmlb_lun *cl, int part, int epart, uint32_t start,
+ uint32_t size)
+{
+ int i;
+ uint32_t end = start + size - 1;
+ uint32_t ext_start = cl->cl_fmap[part].fmap_start;
+ uint32_t ext_end = ext_start + cl->cl_fmap[part].fmap_nblk - 1;
+ uint32_t ts, te;
+ uint32_t poss_end = ext_end;
+
+ if (end <= start) {
+ return (1);
+ }
+
+ /*
+ * Check if the logical drive boundaries are within that of the
+ * extended partition.
+ */
+ if (start <= ext_start || start > ext_end || end <= ext_start ||
+ end > ext_end) {
+ return (1);
+ }
+
+ /*
+ * epart will be equal to FD_NUMPART if it is the first logical drive.
+ * There is no need to check for overlaps with other logical drives,
+ * since it is the only logical drive that we have come across so far.
+ */
+ if (epart == FD_NUMPART) {
+ return (0);
+ }
+
+ /* Check for overlaps with existing logical drives */
+ i = FD_NUMPART;
+ ts = cl->cl_fmap[FD_NUMPART].fmap_start;
+ te = ts + cl->cl_fmap[FD_NUMPART].fmap_nblk - 1;
+
+ while ((i < epart) && ts && te) {
+ if (start >= ts && start <= te) {
+ return (1);
+ }
+
+ if ((ts < poss_end) && (ts > start)) {
+ poss_end = ts - 1;
+ }
+
+ i++;
+ ts = cl->cl_fmap[i].fmap_start;
+ te = ts + cl->cl_fmap[i].fmap_nblk - 1;
+ }
+
+ if (end > poss_end) {
+ return (1);
+ }
+
+ return (0);
+}
+
+
+/*
+ * Function: cmlb_is_linux_swap
+ *
+ * Description: utility routine to verify if a partition is a linux swap
+ * partition or not.
+ *
+ * Arguments:
+ * cl driver soft state (unit) structure
+ * part_start absolute sector number of the start of the partition
+ * being verified
+ * tg_cookie cookie from target driver to be passed back to target
+ * driver when we call back to it through tg_ops.
+ *
+ * Return Code: 0 for success
+ *
+ * Context: User and Kernel thread
+ *
+ * Notes:
+ * The linux swap magic "SWAP-SPACE" or "SWAPSPACE2" is found as the
+ * last 10 bytes of a disk block whose size is that of the linux page
+ * size. This disk block is found at the beginning of the swap partition.
+ */
+static int
+cmlb_is_linux_swap(struct cmlb_lun *cl, uint32_t part_start, void *tg_cookie)
+{
+ int i;
+ int rval = -1;
+ uint32_t seek_offset;
+ uint32_t linux_pg_size;
+ char *buf, *linux_swap_magic;
+ int sec_sz = cl->cl_sys_blocksize;
+ /* Known linux kernel page sizes */
+ uint32_t linux_pg_size_arr[] = {4096, };
+
+ ASSERT(cl != NULL);
+ ASSERT(mutex_owned(CMLB_MUTEX(cl)));
+
+ if ((buf = kmem_zalloc(sec_sz, KM_NOSLEEP)) == NULL) {
+ return (ENOMEM);
+ }
+
+ linux_swap_magic = buf + sec_sz - 10;
+
+ for (i = 0; i < sizeof (linux_pg_size_arr)/sizeof (uint32_t); i++) {
+ linux_pg_size = linux_pg_size_arr[i];
+ seek_offset = linux_pg_size/sec_sz - 1;
+ seek_offset += part_start;
+
+ mutex_exit(CMLB_MUTEX(cl));
+ rval = DK_TG_READ(cl, buf, seek_offset, sec_sz, tg_cookie);
+ mutex_enter(CMLB_MUTEX(cl));
+
+ if (rval != 0) {
+ cmlb_dbg(CMLB_ERROR, cl,
+ "cmlb_is_linux_swap: disk read err\n");
+ rval = EIO;
+ break;
+ }
+
+ rval = -1;
+
+ if ((strncmp(linux_swap_magic, "SWAP-SPACE", 10) == 0) ||
+ (strncmp(linux_swap_magic, "SWAPSPACE2", 10) == 0)) {
+ /* Found a linux swap */
+ rval = 0;
+ break;
+ }
+ }
+
+ kmem_free(buf, sec_sz);
+ return (rval);
+}
+#endif
+
/*
* Function: cmlb_read_fdisk
*
@@ -1901,7 +2280,7 @@ cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
struct ipart *fdp;
struct mboot *mbp;
struct ipart fdisk[FD_NUMPART];
- int i;
+ int i, k;
char sigbuf[2];
caddr_t bufp;
int uidx;
@@ -1910,6 +2289,13 @@ cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
uint_t solaris_offset; /* offset to solaris part. */
daddr_t solaris_size; /* size of solaris partition */
uint32_t blocksize;
+#if defined(__i386) || defined(__amd64)
+ struct ipart eparts[2];
+ struct ipart *efdp1 = &eparts[0];
+ struct ipart *efdp2 = &eparts[1];
+ int ext_part_exists = 0;
+ int ld_count = 0;
+#endif
ASSERT(cl != NULL);
ASSERT(mutex_owned(CMLB_MUTEX(cl)));
@@ -2024,6 +2410,14 @@ cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
for (fdp = fdisk, i = 0; i < FD_NUMPART; i++, fdp++) {
uint32_t relsect;
uint32_t numsect;
+ uchar_t systid;
+#if defined(__i386) || defined(__amd64)
+ /*
+ * Stores relative block offset from the beginning of the
+ * Extended Partition.
+ */
+ int ext_relsect = 0;
+#endif
if (fdp->numsect == 0) {
cl->cl_fmap[i].fmap_start = 0;
@@ -2039,6 +2433,96 @@ cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
cl->cl_fmap[i].fmap_start = relsect;
cl->cl_fmap[i].fmap_nblk = numsect;
+ cl->cl_fmap[i].fmap_systid = LE_8(fdp->systid);
+
+#if defined(__i386) || defined(__amd64)
+ /* Support only one extended partition per LUN */
+ if ((fdp->systid == EXTDOS || fdp->systid == FDISK_EXTLBA) &&
+ (ext_part_exists == 0)) {
+ int j;
+ uint32_t logdrive_offset;
+ uint32_t ext_numsect;
+ uint32_t abs_secnum;
+ int is_linux_swap;
+
+ ext_part_exists = 1;
+
+ for (j = FD_NUMPART; j < FDISK_PARTS; j++) {
+ mutex_exit(CMLB_MUTEX(cl));
+ rval = DK_TG_READ(cl, bufp,
+ (relsect + ext_relsect), blocksize,
+ tg_cookie);
+ mutex_enter(CMLB_MUTEX(cl));
+
+ if (rval != 0) {
+ cmlb_dbg(CMLB_ERROR, cl,
+ "cmlb_read_fdisk: Extended "
+ "partition read err\n");
+ goto done;
+ }
+ /*
+ * The first ipart entry provides the offset
+ * at which the logical drive starts off from
+ * the beginning of the container partition
+ * and the size of the logical drive.
+ * The second ipart entry provides the offset
+ * of the next container partition from the
+ * beginning of the extended partition.
+ */
+ bcopy(&bufp[FDISK_PART_TABLE_START], eparts,
+ sizeof (eparts));
+ logdrive_offset = LE_32(efdp1->relsect);
+ ext_numsect = LE_32(efdp1->numsect);
+ systid = LE_8(efdp1->systid);
+ if (logdrive_offset <= 0 || ext_numsect <= 0)
+ break;
+ abs_secnum = relsect + ext_relsect +
+ logdrive_offset;
+
+ /* Boundary condition and overlap checking */
+ if (cmlb_validate_ext_part(cl, i, j, abs_secnum,
+ ext_numsect)) {
+ break;
+ }
+
+ if ((cl->cl_fmap[j].fmap_start != abs_secnum) ||
+ (cl->cl_fmap[j].fmap_nblk != ext_numsect) ||
+ (cl->cl_fmap[j].fmap_systid != systid)) {
+ /*
+ * Indicates change from previous
+ * partinfo. Need to recreate
+ * logical device nodes.
+ */
+ cl->cl_update_ext_minor_nodes = 1;
+ }
+ cl->cl_fmap[j].fmap_start = abs_secnum;
+ cl->cl_fmap[j].fmap_nblk = ext_numsect;
+ cl->cl_fmap[j].fmap_systid = systid;
+ ld_count++;
+
+ is_linux_swap = 0;
+ if (efdp1->systid == SUNIXOS) {
+ if (cmlb_is_linux_swap(cl, abs_secnum,
+ tg_cookie) == 0) {
+ is_linux_swap = 1;
+ }
+ }
+
+ if ((efdp1->systid == SUNIXOS) ||
+ (efdp1->systid == SUNIXOS2)) {
+ if ((uidx == -1) && (!is_linux_swap)) {
+ uidx = 0;
+ solaris_offset = abs_secnum;
+ solaris_size = ext_numsect;
+ }
+ }
+
+ if ((ext_relsect = LE_32(efdp2->relsect)) == 0)
+ break;
+ }
+ }
+
+#endif
if (fdp->systid != SUNIXOS &&
fdp->systid != SUNIXOS2 &&
@@ -2054,12 +2538,38 @@ cmlb_read_fdisk(struct cmlb_lun *cl, diskaddr_t capacity, void *tg_cookie)
* then use the first inactive solaris partition id
*/
if ((uidx == -1) || (fdp->bootid == ACTIVE)) {
- uidx = i;
- solaris_offset = relsect;
- solaris_size = numsect;
+#if defined(__i386) || defined(__amd64)
+ if (cmlb_is_linux_swap(cl, relsect, tg_cookie) != 0) {
+#endif
+ uidx = i;
+ solaris_offset = relsect;
+ solaris_size = numsect;
+#if defined(__i386) || defined(__amd64)
+ }
+#endif
}
}
-
+#if defined(__i386) || defined(__amd64)
+ if (ld_count < cl->cl_logical_drive_count) {
+ /*
+ * Some/all logical drives were deleted. Clear out
+ * the fmap entries correspoding to those deleted drives.
+ */
+ for (k = ld_count + FD_NUMPART;
+ k < cl->cl_logical_drive_count + FD_NUMPART; k++) {
+ cl->cl_fmap[k].fmap_start = 0;
+ cl->cl_fmap[k].fmap_nblk = 0;
+ cl->cl_fmap[k].fmap_systid = 0;
+ }
+ cl->cl_update_ext_minor_nodes = 1;
+ }
+ if (cl->cl_update_ext_minor_nodes) {
+ rval = cmlb_update_ext_minor_nodes(cl, ld_count);
+ if (rval != 0) {
+ goto done;
+ }
+ }
+#endif
cmlb_dbg(CMLB_INFO, cl, "fdisk 0x%x 0x%lx",
cl->cl_solaris_offset, cl->cl_solaris_size);
done:
@@ -4532,6 +5042,30 @@ cmlb_dkio_set_mboot(struct cmlb_lun *cl, caddr_t arg, int flag, void *tg_cookie)
}
+#if defined(__i386) || defined(__amd64)
+/*ARGSUSED*/
+static int
+cmlb_dkio_set_ext_part(struct cmlb_lun *cl, caddr_t arg, int flag,
+ void *tg_cookie)
+{
+ int fdisk_rval;
+ diskaddr_t capacity;
+
+ ASSERT(!mutex_owned(CMLB_MUTEX(cl)));
+
+ mutex_enter(CMLB_MUTEX(cl));
+ capacity = cl->cl_blockcount;
+ fdisk_rval = cmlb_read_fdisk(cl, capacity, tg_cookie);
+ if (fdisk_rval != 0) {
+ mutex_exit(CMLB_MUTEX(cl));
+ return (fdisk_rval);
+ }
+
+ mutex_exit(CMLB_MUTEX(cl));
+ return (fdisk_rval);
+}
+#endif
+
/*
* Function: cmlb_setup_default_geometry
*
@@ -4770,7 +5304,7 @@ no_solaris_partition:
* Note that dkl_cylno is not used for the fdisk map entries, so
* we set it to an entirely bogus value.
*/
- for (count = 0; count < FD_NUMPART; count++) {
+ for (count = 0; count < FDISK_PARTS; count++) {
cl->cl_map[FDISK_P1 + count].dkl_cylno = UINT32_MAX;
cl->cl_map[FDISK_P1 + count].dkl_nblk =
cl->cl_fmap[count].fmap_nblk;
diff --git a/usr/src/uts/common/io/scsi/targets/sd.c b/usr/src/uts/common/io/scsi/targets/sd.c
index 8cbc1310a3..eaba50c764 100644
--- a/usr/src/uts/common/io/scsi/targets/sd.c
+++ b/usr/src/uts/common/io/scsi/targets/sd.c
@@ -21762,6 +21762,9 @@ sdioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *cred_p, int *rval_p)
case DKIOCSMBOOT:
case DKIOCG_PHYGEOM:
case DKIOCG_VIRTGEOM:
+#if defined(__i386) || defined(__amd64)
+ case DKIOCSETEXTPART:
+#endif
/* let cmlb handle it */
goto skip_ready_valid;
@@ -21910,6 +21913,9 @@ skip_ready_valid:
case DKIOCSMBOOT:
case DKIOCG_PHYGEOM:
case DKIOCG_VIRTGEOM:
+#if defined(__i386) || defined(__amd64)
+ case DKIOCSETEXTPART:
+#endif
SD_TRACE(SD_LOG_IOCTL, un, "DKIOC %d\n", cmd);
/* TUR should spin up */
diff --git a/usr/src/uts/common/sys/cmlb_impl.h b/usr/src/uts/common/sys/cmlb_impl.h
index b77f6c0239..1927123457 100644
--- a/usr/src/uts/common/sys/cmlb_impl.h
+++ b/usr/src/uts/common/sys/cmlb_impl.h
@@ -35,10 +35,16 @@ extern "C" {
#include <sys/ddi.h>
#include <sys/sunddi.h>
+/*
+ * FDISK partitions - 4 primary and MAX_EXT_PARTS number of Extended
+ * Partitions.
+ */
+#define FDISK_PARTS (FD_NUMPART + MAX_EXT_PARTS)
+
#if defined(_SUNOS_VTOC_8)
#define NSDMAP NDKMAP
#elif defined(_SUNOS_VTOC_16)
-#define NSDMAP (NDKMAP + FD_NUMPART + 1)
+#define NSDMAP (NDKMAP + FDISK_PARTS + 1)
#else
#error "No VTOC format defined."
#endif
@@ -111,6 +117,7 @@ extern "C" {
struct fmap {
ulong_t fmap_start; /* starting block number */
ulong_t fmap_nblk; /* number of blocks */
+ uchar_t fmap_systid; /* systid of the partition */
};
/* for cm_state */
@@ -146,7 +153,7 @@ typedef struct cmlb_lun {
diskaddr_t cl_offset[MAXPART]; /* partition start blocks */
- struct fmap cl_fmap[FD_NUMPART]; /* fdisk partitions */
+ struct fmap cl_fmap[FDISK_PARTS]; /* fdisk partitions */
uchar_t cl_asciilabel[LEN_DKL_ASCII]; /* Disk ASCII label */
@@ -190,6 +197,15 @@ typedef struct cmlb_lun {
int cl_device_type; /* DTYPE_DIRECT,.. */
int cl_reserved; /* reserved efi partition # */
cmlb_tg_ops_t *cmlb_tg_ops;
+#if defined(__i386) || defined(__amd64)
+ /*
+ * Flag indicating whether extended partition nodes should be created
+ * or not. Is set in cmlb_attach. After creating nodes in
+ * cmlb_read_fdisk, it will be unset.
+ */
+ int cl_update_ext_minor_nodes;
+ int cl_logical_drive_count;
+#endif /* __i386 || __amd64 */
uint8_t cl_msglog_flag; /* used to enable/suppress */
/* certain log messages */
} cmlb_lun_t;
diff --git a/usr/src/uts/common/sys/dkio.h b/usr/src/uts/common/sys/dkio.h
index caf7d7976d..8d913d8974 100644
--- a/usr/src/uts/common/sys/dkio.h
+++ b/usr/src/uts/common/sys/dkio.h
@@ -230,6 +230,11 @@ struct dk_callback {
*/
#define DKIOCHOTPLUGGABLE (DKIOC|35) /* is hotpluggable */
+#if defined(__i386) || defined(__amd64)
+/* ioctl to write extended partition structure into the disk */
+#define DKIOCSETEXTPART (DKIOC|46)
+#endif
+
/*
* Ioctl to force driver to re-read the alternate partition and rebuild
* the internal defect map.
diff --git a/usr/src/uts/common/sys/dktp/fdisk.h b/usr/src/uts/common/sys/dktp/fdisk.h
index ea0c1ef3ce..e90135f362 100644
--- a/usr/src/uts/common/sys/dktp/fdisk.h
+++ b/usr/src/uts/common/sys/dktp/fdisk.h
@@ -20,7 +20,7 @@
*/
/*
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/* Copyright (c) 1984, 1986, 1987, 1988 AT&T */
@@ -44,6 +44,18 @@ extern "C" {
*/
/*
+ * 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)
+
+/*
* BOOTSZ was reduced from 446 to 440 bytes to NOT overwrite the Windows
* Vista DISKID. Otherwise Vista won't boot from Solaris GRUB in a dual-boot
* setup.
@@ -80,6 +92,7 @@ struct ipart {
/*
* Values for systid.
*/
+#define UNUSED 0 /* Empty Partition */
#define DOSOS12 1 /* DOS partition, 12-bit FAT */
#define PCIXOS 2 /* PC/IX partition */
#define DOSOS16 4 /* DOS partition, 16-bit FAT */
@@ -103,7 +116,7 @@ struct ipart {
/* raw partition. ID was 0 but conflicted */
/* with DOS 3.3 fdisk */
#define UNIXOS 99 /* UNIX V.x partition */
-#define UNUSED 100 /* unassigned partition */
+#define FDISK_NOVELL2 100 /* Novell Netware 286 */
#define FDISK_NOVELL3 101 /* Novell Netware 3.x and later */
#define FDISK_QNX4 119 /* QNX 4.x */
#define FDISK_QNX42 120 /* QNX 4.x 2nd part */
@@ -139,6 +152,20 @@ struct mboot { /* master boot block */
ushort_t signature;
};
+#if defined(__i386) || defined(__amd64)
+
+/* Byte offset of the start of the partition table within the sector */
+#define FDISK_PART_TABLE_START 446
+
+/* Maximum number of valid partitions assumed as 32 */
+#define MAX_EXT_PARTS 32
+
+#else
+
+#define MAX_EXT_PARTS 0
+
+#endif /* if defined(__i386) || defined(__amd64) */
+
#ifdef __cplusplus
}
#endif
diff --git a/usr/src/uts/common/sys/scsi/targets/sddef.h b/usr/src/uts/common/sys/scsi/targets/sddef.h
index 90129e40c3..93705cc42b 100644
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h
@@ -93,9 +93,17 @@ extern "C" {
#elif defined(_SUNOS_VTOC_16)
+/*
+ * XXX - NSDMAP has multiple definitions, one more in cmlb_impl.h
+ * If they are coalesced into one, this definition will follow suit.
+ * FDISK partitions - 4 primary and MAX_EXT_PARTS number of Extended
+ * Partitions.
+ */
+#define FDISK_PARTS (FD_NUMPART + MAX_EXT_PARTS)
+
#define SDUNIT_SHIFT 6
#define SDPART_MASK 63
-#define NSDMAP (NDKMAP + FD_NUMPART + 1)
+#define NSDMAP (NDKMAP + FDISK_PARTS + 1)
#else
#error "No VTOC format defined."
diff --git a/usr/src/uts/common/xen/io/xdf.c b/usr/src/uts/common/xen/io/xdf.c
index 3e9ccd0b4a..77419266c8 100644
--- a/usr/src/uts/common/xen/io/xdf.c
+++ b/usr/src/uts/common/xen/io/xdf.c
@@ -2578,6 +2578,7 @@ xdf_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
case DKIOCSMBOOT:
case DKIOCGETEFI:
case DKIOCSETEFI:
+ case DKIOCSETEXTPART:
case DKIOCPARTITION:
return (cmlb_ioctl(vdp->xdf_vd_lbl, dev, cmd, arg, mode, credp,
rvalp, NULL));
diff --git a/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c b/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c
index d9557a07cb..6255c5ddaf 100644
--- a/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c
+++ b/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c
@@ -794,8 +794,13 @@ xdfs_ioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp,
rv = xdfs_c_ioctl(xsp, dev, part, cmd, arg, flag, credp, rvalp, &done);
if (done)
return (rv);
- return (ldi_ioctl(xsp->xdfss_tgt_lh[part],
- cmd, arg, flag, credp, rvalp));
+ rv = ldi_ioctl(xsp->xdfss_tgt_lh[part], cmd, arg, flag, credp, rvalp);
+ if (rv == 0) {
+ /* Force Geometry Validation */
+ (void) cmlb_invalidate(xsp->xdfss_cmlbhandle, 0);
+ (void) cmlb_validate(xsp->xdfss_cmlbhandle, 0, 0);
+ }
+ return (rv);
}
static int
diff --git a/usr/src/uts/intel/io/dktp/disk/cmdk.c b/usr/src/uts/intel/io/dktp/disk/cmdk.c
index 36dddd4a7b..8e144b05a9 100644
--- a/usr/src/uts/intel/io/dktp/disk/cmdk.c
+++ b/usr/src/uts/intel/io/dktp/disk/cmdk.c
@@ -1002,6 +1002,7 @@ cmdkioctl(dev_t dev, int cmd, intptr_t arg, int flag, cred_t *credp, int *rvalp)
case DKIOCGETEFI:
case DKIOCSETEFI:
case DKIOCPARTITION:
+ case DKIOCSETEXTPART:
{
int rc;