changeset 10021:a41c569bdaca

PSARC/2006/379 Solaris on Extended partition 6644364 Extended partitions need to be supported on Solaris 6713308 Macro UNUSED in fdisk.h needs to be changed since id 100 is Novell Netware 286's partition ID 6713318 Need to differentiate between solaris old partition and Linux swap 6745175 Partitions can be created using fdisk table with invalid partition line by "fdisk -F" 6745740 Multiple extended partition can be created by "fdisk -A" 6824622 Logical device node can't be created in HVM host
author Sheshadri Vasudevan <Sheshadri.Vasudevan@Sun.COM>
date Thu, 02 Jul 2009 08:59:40 +0530
parents ff5f2b3729b6
children be0be0d86e3c
files usr/src/Makefile.lint usr/src/Targetdirs usr/src/cmd/boot/installgrub/Makefile usr/src/cmd/boot/installgrub/installgrub.c usr/src/cmd/boot/installgrub/message.h usr/src/cmd/devfsadm/disk_link.c usr/src/cmd/fdisk/Makefile usr/src/cmd/fdisk/fdisk.c usr/src/cmd/format/Makefile usr/src/cmd/format/menu_fdisk.c usr/src/lib/Makefile usr/src/lib/libfdisk/Makefile usr/src/lib/libfdisk/i386/Makefile usr/src/lib/libfdisk/i386/libfdisk.c usr/src/lib/libfdisk/i386/libfdisk.h usr/src/lib/libfdisk/i386/llib-lfdisk usr/src/lib/libfdisk/i386/mapfile-vers usr/src/pkgdefs/SUNWarc/prototype_i386 usr/src/pkgdefs/SUNWarcr/prototype_i386 usr/src/pkgdefs/SUNWcsl/prototype_i386 usr/src/pkgdefs/SUNWcslr/prototype_i386 usr/src/pkgdefs/SUNWhea/prototype_i386 usr/src/uts/common/io/cmlb.c usr/src/uts/common/io/scsi/targets/sd.c usr/src/uts/common/sys/cmlb_impl.h usr/src/uts/common/sys/dkio.h usr/src/uts/common/sys/dktp/fdisk.h usr/src/uts/common/sys/scsi/targets/sddef.h usr/src/uts/common/xen/io/xdf.c usr/src/uts/i86pc/i86hvm/io/xdf_shell.c usr/src/uts/intel/io/dktp/disk/cmdk.c
diffstat 31 files changed, 4599 insertions(+), 140 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/Makefile.lint	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/Makefile.lint	Thu Jul 02 08:59:40 2009 +0530
@@ -475,7 +475,8 @@
 	cmd/rtc \
 	cmd/ucodeadm \
 	lib/brand/lx \
-	lib/cfgadm_plugins/sata
+	lib/cfgadm_plugins/sata \
+	lib/libfdisk
 
 sparc_SUBDIRS= \
 	cmd/datadm \
--- a/usr/src/Targetdirs	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/Targetdirs	Thu Jul 02 08:59:40 2009 +0530
@@ -925,6 +925,8 @@
 $(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:=		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_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 \
--- a/usr/src/cmd/boot/installgrub/Makefile	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/boot/installgrub/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 
 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:
 
--- a/usr/src/cmd/boot/installgrub/installgrub.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/boot/installgrub/installgrub.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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 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 @@
 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 @@
 		}
 	}
 
+	/* 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 @@
 				(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 @@
 		}
 	}
 
-	if (i == FD_NUMPART) {
+	if ((i == FD_NUMPART) && (!ext_sol_part_found)) {
 		(void) fprintf(stderr, BOOTPAR);
 		exit(-1);
 	}
@@ -294,12 +336,18 @@
 		}
 	}
 
-	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 @@
 	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 @@
 
 	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];
--- a/usr/src/cmd/boot/installgrub/message.h	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/boot/installgrub/message.h	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 
 #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
--- a/usr/src/cmd/devfsadm/disk_link.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/devfsadm/disk_link.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 	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 @@
 		/* For EFI label */
 		(void) sprintf(slice, SLICE_EFI);
 	}
+#if defined(__i386) || defined(__amd64)
+	}
+#endif
 
 	nflags = 0;
 	if (system_labeled) {
--- a/usr/src/cmd/fdisk/Makefile	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/fdisk/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 
 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)
 
--- a/usr/src/cmd/fdisk/fdisk.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/fdisk/fdisk.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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 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 @@
 #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 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 @@
 	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 @@
 	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 @@
 	/* 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 @@
 				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 @@
 		    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 @@
 	}
 
 	/* 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 @@
 	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 @@
 			    &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 @@
 			    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 @@
 
 				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 @@
 			}
 		}
 
+#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 @@
 
 	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 @@
 			}
 
 			/* 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 @@
 			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 @@
     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 @@
 			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 @@
 	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 @@
 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 @@
 				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 @@
 				(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 @@
 	int i, j;
 	uint32_t numsect;
 	int retCode = 0;
+#ifdef i386
+	int ext_part_present = 0;
+#endif
 
 	i = 0;
 	for (;;) {
@@ -2076,8 +2869,14 @@
 	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 @@
 			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 @@
 				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 @@
 		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 @@
 			 */
 			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 @@
 				 * 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 @@
 
 			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 @@
 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 @@
 	    "   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 @@
 		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\"). ");
-
-	(void) printf(E_LINE);
-	if (! yesno()) {
-		return (1);
+#ifdef i386
+	if (fdisk_is_dos_extended(Table[i].systid) &&
+	    (Table[i].relsect == fdisk_get_ext_beg_sec(epp)) &&
+	    fdisk_get_logical_drive_count(epp)) {
+		(void) printf(Q_LINE);
+		(void) printf("There are logical drives inside the"
+		    " extended partition\n");
+		(void) printf("Are you sure of proceeding with deletion ?"
+		    " (type \"y\" or \"n\") ");
+
+		(void) printf(E_LINE);
+		if (! yesno()) {
+			return (1);
+		}
+		if (fdisk_mounted_logical_drives(epp) == FDISK_EMOUNTED) {
+			(void) printf(Q_LINE);
+			(void) printf("There are mounted logical drives. "
+			    "Committing changes now can cause data loss or "
+			    "corruption. Unmount all logical drives and then "
+			    "try committing the changes again.\n");
+			(void) printf("Press enter to continue.\n");
+			ext_read_input(s);
+			return (1);
+		}
+		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 @@
 		case FDISK_CPM:
 			type = CPMstr;
 			break;
+		case FDISK_NOVELL2:
+			type = NOV2str;
+			break;
 		case FDISK_NOVELL3:
 			type = NOVstr;
 			break;
@@ -2947,7 +3814,7 @@
 			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 @@
 			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 @@
 		(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 @@
 
 	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 @@
 	/* 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 @@
 	}
 	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 @@
 		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 @@
 	(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 @@
 	    "    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 @@
 			 * 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 @@
 		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 @@
 #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 @@
 
 	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
--- a/usr/src/cmd/format/Makefile	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/format/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -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) := 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:
--- a/usr/src/cmd/format/menu_fdisk.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/cmd/format/menu_fdisk.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 
 #endif	/* __STDC__ */
 
+#ifdef i386
+int extpart_init(ext_part_t **epp);
+#endif
 /*
  * Handling the alignment problem of struct ipart.
  */
@@ -274,22 +280,23 @@
 	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 @@
 	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 @@
 		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 @@
 #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);
-	}
+	} 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));
 
-	/*
-	 * 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 @@
 		nsect = cur_dtype->dtype_nsect;
 		nhead = cur_dtype->dtype_nhead;
 	}
-
 	return (0);
 }
 
@@ -586,6 +635,11 @@
 	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 @@
 		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 @@
 #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 @@
 	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 @@
 		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 @@
 		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
--- a/usr/src/lib/Makefile	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/lib/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -263,7 +263,8 @@
 
 i386_SUBDIRS=		\
 	libntfs		\
-	libparted
+	libparted	\
+	libfdisk
 
 sparc_SUBDIRS= .WAIT	\
 	efcode		\
@@ -366,6 +367,8 @@
 	libprtdiag	\
 	libprtdiag_psr
 
+i386_MSGSUBDIRS= libfdisk
+
 HDRSUBDIRS=		\
 	auditd_plugins	\
 	libast		\
@@ -491,7 +494,8 @@
 	$(CLOSED)/lib/smartcard
 
 i386_HDRSUBDIRS=	\
-	libparted
+	libparted	\
+	libfdisk
 
 sparc_HDRSUBDIRS=	\
 	libds		\
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/i386/Makefile	Thu Jul 02 08:59:40 2009 +0530
@@ -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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/i386/libfdisk.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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]);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/i386/libfdisk.h	Thu Jul 02 08:59:40 2009 +0530
@@ -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_ */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/i386/llib-lfdisk	Thu Jul 02 08:59:40 2009 +0530
@@ -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>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libfdisk/i386/mapfile-vers	Thu Jul 02 08:59:40 2009 +0530
@@ -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:
+	*;
+};
--- a/usr/src/pkgdefs/SUNWarc/prototype_i386	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/pkgdefs/SUNWarc/prototype_i386	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 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
--- a/usr/src/pkgdefs/SUNWarcr/prototype_i386	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/pkgdefs/SUNWarcr/prototype_i386	Thu Jul 02 08:59:40 2009 +0530
@@ -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-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
--- a/usr/src/pkgdefs/SUNWcsl/prototype_i386	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/pkgdefs/SUNWcsl/prototype_i386	Thu Jul 02 08:59:40 2009 +0530
@@ -370,6 +370,8 @@
 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
--- a/usr/src/pkgdefs/SUNWcslr/prototype_i386	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/pkgdefs/SUNWcslr/prototype_i386	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 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
--- a/usr/src/pkgdefs/SUNWhea/prototype_i386	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/pkgdefs/SUNWhea/prototype_i386	Thu Jul 02 08:59:40 2009 +0530
@@ -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
--- a/usr/src/uts/common/io/cmlb.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/io/cmlb.c	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
 	{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 @@
     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 @@
 	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 @@
 
 	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 @@
 		}
 
 		/* 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 @@
 		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 @@
 		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 @@
 	 * 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 @@
 }
 
 
+#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 @@
 	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 @@
 	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 @@
 	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 @@
 
 		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 @@
 		 * 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 @@
 }
 
 
+#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 @@
 	 * 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;
--- a/usr/src/uts/common/io/scsi/targets/sd.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/io/scsi/targets/sd.c	Thu Jul 02 08:59:40 2009 +0530
@@ -21762,6 +21762,9 @@
 		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 @@
 	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 */
--- a/usr/src/uts/common/sys/cmlb_impl.h	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/sys/cmlb_impl.h	Thu Jul 02 08:59:40 2009 +0530
@@ -35,10 +35,16 @@
 #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 @@
 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 @@
 
 	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 @@
 	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;
--- a/usr/src/uts/common/sys/dkio.h	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/sys/dkio.h	Thu Jul 02 08:59:40 2009 +0530
@@ -230,6 +230,11 @@
  */
 #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.
--- a/usr/src/uts/common/sys/dktp/fdisk.h	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/sys/dktp/fdisk.h	Thu Jul 02 08:59:40 2009 +0530
@@ -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 @@
  */
 
 /*
+ * 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 @@
 /*
  * 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 @@
 				/* 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 @@
 	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
--- a/usr/src/uts/common/sys/scsi/targets/sddef.h	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/sys/scsi/targets/sddef.h	Thu Jul 02 08:59:40 2009 +0530
@@ -93,9 +93,17 @@
 
 #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."
--- a/usr/src/uts/common/xen/io/xdf.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/common/xen/io/xdf.c	Thu Jul 02 08:59:40 2009 +0530
@@ -2578,6 +2578,7 @@
 	case DKIOCSMBOOT:
 	case DKIOCGETEFI:
 	case DKIOCSETEFI:
+	case DKIOCSETEXTPART:
 	case DKIOCPARTITION:
 		return (cmlb_ioctl(vdp->xdf_vd_lbl, dev, cmd, arg, mode, credp,
 		    rvalp, NULL));
--- a/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/i86pc/i86hvm/io/xdf_shell.c	Thu Jul 02 08:59:40 2009 +0530
@@ -794,8 +794,13 @@
 	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
--- a/usr/src/uts/intel/io/dktp/disk/cmdk.c	Thu Jul 02 15:13:49 2009 +0200
+++ b/usr/src/uts/intel/io/dktp/disk/cmdk.c	Thu Jul 02 08:59:40 2009 +0530
@@ -1002,6 +1002,7 @@
 	case DKIOCGETEFI:
 	case DKIOCSETEFI:
 	case DKIOCPARTITION:
+	case DKIOCSETEXTPART:
 	{
 		int rc;