Subject: changes to Fdisk to support extended partitions
To: None <tech-userlevel@netbsd.org>
From: Rafal Boni <rafal@raptor.com>
List: tech-userlevel
Date: 06/10/1999 18:12:19
This is a multi-part message in MIME format.
--------------D322C0970868C0867E5D83B6
Content-Type: text/plain; charset=us-ascii
Content-Transfer-Encoding: 7bit

Folks:
	I've hacked together some changes to fdisk to make it support
	editing/viewing of extended partitions.  It still probably needs
	support for adding new extended partitions (It will most likely
	fail to initialize the new extended partitions' partition table),
	but otherwise should be functional.

	I'd like people to take a look at it and comment on the 
	following:
		(1) Is this something that we would want to put in
		    the tree?
		(2) Missing functionality related to extended 
		    partitions
		(3) Incorrect results.

	If you've got a machine to play around with this on, please do
	and send any feedback you have.  

	I've got this to the point where it does what I want, but I'd 
	like to finish out the functionality set and submit it to TNF.

	The diffs vs. rev 1.37 of src/sbin/fdisk.c are attached.

Thanks!
--rafal

-- 
Rafal Boni                                                  rafal@raptor.com
Raptor Systems, Waltham, MA      http://www.raptor.com/         781.530.2200
--------------D322C0970868C0867E5D83B6
Content-Type: text/plain; charset=us-ascii;
 name="fdisk.diffs"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="fdisk.diffs"

--- fdisk.c	Sat Jun  5 04:12:24 1999
+++ fdisk.c.new	Thu Jun 10 14:55:01 1999
@@ -29,7 +29,7 @@
 #include <sys/cdefs.h>
 
 #ifndef lint
-__RCSID("$NetBSD: fdisk.c,v 1.37 1999/06/04 18:59:15 thorpej Exp $");
+__RCSID("$NetBSD: fdisk.c,v 1.36 1999/05/02 12:17:48 fvdl Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -69,6 +69,7 @@
 
 struct disklabel disklabel;		/* disk parameters */
 
+unsigned long ext_offset = 0;
 int cylinders, sectors, heads, cylindersectors, disksectors;
 
 struct mboot {
@@ -77,7 +78,11 @@
 	struct mbr_partition parts[NMBRPART];
 	u_int16_t	signature;
 };
-struct mboot mboot;
+
+#define MAX_PARTITION 100
+#define get_part_ptr(num)  (&(ptbl[(num) / NMBRPART].parts[(num) % NMBRPART]))
+#define IS_EXTENDED(type)  ((type) == 0x05 || (type) == 0x0F || ((type) == 0x85))
+struct mboot ptbl[MAX_PARTITION];
 
 #ifdef	__i386__
 
@@ -99,9 +104,9 @@
 
 #define	DEFAULT_BOOTCODE	"/usr/mdec/mbr"
 #define DEFAULT_BOOTSELCODE	"/usr/mdec/mbr_bootsel"
-#define OPTIONS			"0123BSafius:b:c:"
+#define OPTIONS			"0123BSafirus:b:c:"
 #else
-#define OPTIONS			"0123Safius:b:c:"
+#define OPTIONS			"0123Safirus:b:c:"
 #endif
 
 #define ACTIVE 0x80
@@ -115,6 +120,7 @@
 #define DOSCYL(c)	((c) & 0xff)
 
 #define	MAXCYL	1024
+int maxpart = 4;
 int partition = -1;
 
 int a_flag;		/* set active partition */
@@ -122,6 +128,7 @@
 int u_flag;		/* update partition data */
 int sh_flag;		/* Output data as shell defines */
 int f_flag;		/* force --not interactive */
+int r_flag;		/* recurse on extended partition types */
 int s_flag;		/* set id,offset,size */
 int b_flag;		/* Set cyl, heads, secs (as c/h/s) */
 int B_flag;		/* Edit/install bootselect code */
@@ -264,17 +271,20 @@
 int	try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t,
 		       quad_t));
 int	try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t));
-void	change_part __P((int, int, int, int));
+void	change_part __P((int, unsigned long, unsigned long, unsigned long));
 void	print_params __P((void));
 void	change_active __P((int));
 void	get_params_to_use __P((void));
 void	dos __P((int, unsigned char *, unsigned char *, unsigned char *));
 int	open_disk __P((int));
-int	read_disk __P((int, void *));
-int	write_disk __P((int, void *));
+int	read_disk __P((unsigned long, void *));
+int	write_disk __P((unsigned long, void *));
 int	get_params __P((void));
 int	read_s0 __P((void));
+int	read_extended_partitions __P((void));
+int	read_chain __P((struct mboot*, int, unsigned long));
 int	write_s0 __P((void));
+int	write_chain __P((struct mboot*, int, unsigned long));
 int	yesno __P((char *));
 void	decimal __P((char *, int *));
 int	type_match __P((const void *, const void *));
@@ -302,7 +312,8 @@
 
 	int csysid, cstart, csize;	/* For the b_flag. */
 
-	a_flag = i_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0;
+	r_flag = a_flag = i_flag = u_flag = sh_flag = f_flag = 
+	    s_flag = b_flag = 0;
 	csysid = cstart = csize = 0;
 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
 		switch (ch) {
@@ -335,6 +346,9 @@
 		case 'i':
 			i_flag = 1;
 			break;
+		case 'r':
+			r_flag = 1;
+			break;
 		case 'u':
 			u_flag = 1;
 			break;
@@ -396,6 +410,8 @@
 	intuit_translated_geometry();
 #endif
 
+	if (r_flag)
+		read_extended_partitions();
 
 	if ((i_flag || u_flag) && (!f_flag || b_flag))
 		get_params_to_use();
@@ -407,8 +423,9 @@
 	if (u_flag) {
 		if (!f_flag)
 			printf("Partition table:\n");
+
 		if (partition == -1)
-			for (part = 0; part < NMBRPART; part++)
+			for (part = 0; part < maxpart; part++)
 				change_part(part,-1, -1, -1);
 		else
 			change_part(partition, csysid, cstart, csize);
@@ -459,7 +476,10 @@
 	if (!sh_flag)
 		printf("Partition table:\n");
 	if (which == -1) {
-		for (part = 0; part < NMBRPART; part++) {
+		for (part = 0; part < maxpart; part++) {
+			if (!sh_flag && part && part % NMBRPART == 0) {
+				printf("\nExtended partition %d\n", part / NMBRPART);
+			}
 			if (!sh_flag)
 				printf("%d: ", part);
 			print_part(part);
@@ -517,7 +537,7 @@
 	struct mbr_partition *partp;
 	int empty;
 
-	partp = &mboot.parts[part];
+	partp = get_part_ptr(part);
 	empty = (partp->mbrp_typ == 0);
 
 	if (sh_flag) {
@@ -602,12 +622,12 @@
 		    sizeof bootcode);
 #endif
 
-	memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst));
-	putshort(&mboot.signature, MBR_MAGIC);
+	memcpy(ptbl[0].bootinst, bootcode, sizeof(ptbl[0].bootinst));
+	putshort(&ptbl[0].signature, MBR_MAGIC);
 	
 	if (dopart)
 		for (i=0; i<4; i++) 
-			memset(&mboot.parts[i], 0, sizeof(struct mbr_partition));
+			memset(get_part_ptr(i), 0, sizeof(struct mbr_partition));
 
 }
 
@@ -709,13 +729,13 @@
 configure_bootsel()
 {
 	struct mbr_bootsel *mbs =
-	    (struct mbr_bootsel *)&mboot.bootinst[MBR_BOOTSELOFF];
+	    (struct mbr_bootsel *)&ptbl[0].bootinst[MBR_BOOTSELOFF];
 	int i, nused, firstpart = -1, item;
 	char desc[10], *p;
 	int timo, entry_changed = 0;
 
 	for (i = nused = 0; i < NMBRPART; i++) {
-		if (mboot.parts[i].mbrp_typ != 0) {
+		if (ptbl[0].parts[i].mbrp_typ != 0) {
 			if (firstpart == -1)
 				firstpart = i;
 			nused++;
@@ -734,7 +754,7 @@
 		}
 		bootsize = read_boot(DEFAULT_BOOTSELCODE, bootcode,
 		    sizeof bootcode);
-		memcpy(mboot.bootinst, bootcode, sizeof(mboot.bootinst));
+		memcpy(ptbl[0].bootinst, bootcode, sizeof(ptbl[0].bootinst));
 		bootsel_modified = 1;
 		mbs->flags |= BFL_SELACTIVE;
 	} else {
@@ -760,7 +780,7 @@
 	}
 
 	printf("\n\nPartition table:\n");
-	for (i = 0; i < NMBRPART; i++) {
+	for (i = 0; i < maxpart; i++) {
 		printf("%d: ", i);
 		print_part(i);
 	}
@@ -785,7 +805,7 @@
 			printf("Invalid entry number\n");
 			continue;
 		}
-		if (mboot.parts[item].mbrp_typ == 0) {
+		if (ptbl[0].parts[item].mbrp_typ == 0) {
 			printf("The matching partition entry is unused\n");
 			continue;
 		}
@@ -870,8 +890,8 @@
 
 done:
 	for (i = 0; i < NMBRPART; i++) {
-		if (mboot.parts[i].mbrp_typ != 0 &&
-		   mboot.parts[i].mbrp_start >=
+		if (ptbl[0].parts[i].mbrp_typ != 0 &&
+		   ptbl[0].parts[i].mbrp_start >=
 		     (dos_cylinders * dos_heads * dos_sectors)) {
 			mbs->flags |= BFL_EXTINT13;
 			break;
@@ -975,7 +995,7 @@
 	int i, *cylinder, *head, *sector;
 	long *absolute;
 {
-	struct mbr_partition *part = &mboot.parts[i / 2];
+	struct mbr_partition *part = &ptbl[0].parts[i / 2];
 
 	if (part->mbrp_typ == 0)
 		return -1;
@@ -996,11 +1016,12 @@
 
 void
 change_part(part, csysid, cstart, csize)
-	int part, csysid, cstart, csize;
+	int part;
+	unsigned long csysid, cstart, csize;
 {
 	struct mbr_partition *partp;
 
-	partp = &mboot.parts[part];
+	partp = get_part_ptr(part);
 
 	if (s_flag) {
 		if (csysid == 0 && cstart == 0 && csize == 0)
@@ -1116,35 +1137,50 @@
 change_active(which)
 	int which;
 {
+	int i, active, gotactive;
 	struct mbr_partition *partp;
-	int part;
-	int active = 4;
-
-	partp = &mboot.parts[0];
 
 	if (a_flag && which != -1)
 		active = which;
 	else {
-		for (part = 0; part < NMBRPART; part++)
-			if (partp[part].mbrp_flag & ACTIVE)
-				active = part;
+		printf ("Choosing -1 will leave active flags unchanged.\n");
+		do {
+			decimal("Partition number to change", &active);
+
+			if (active < 0)
+				return;
+
+			if (active > maxpart - 1)
+				printf("Partition number must be between 0 and %d!\n", maxpart - 1);
+		} while (1);
 	}
+
 	if (!f_flag) {
-		if (yesno("Do you want to change the active partition?")) {
-			printf ("Choosing 4 will make no partition active.\n");
-			do {
-				decimal("active partition", &active);
-			} while (!yesno("Are you happy with this choice?"));
-		} else
+		if (!yesno("Are you happy with this choice?"))
 			return;
-	} else
-		if (active != 4)
+	} 
+
+	partp = get_part_ptr(active);
+
+	if (partp->mbrp_flag & ACTIVE) {
+		printf ("De-activating partition %d.\n", active);
+		partp->mbrp_flag &= ~ACTIVE;
+	} else {
 			printf ("Making partition %d active.\n", active);
+		partp->mbrp_flag |= ACTIVE;
+	}
 
-	for (part = 0; part < NMBRPART; part++)
-		partp[part].mbrp_flag &= ~ACTIVE;
-	if (active < 4)
-		partp[active].mbrp_flag |= ACTIVE;
+	if (active < 4) {
+		partp = get_part_ptr(0);
+		for (i = 0, gotactive = 0; i < NMBRPART; i++) {
+			if (partp[i].mbrp_flag & ACTIVE) {
+				if (gotactive++)
+					warnx("More than one active"
+					      "partition in master boot"
+					      "record!");
+			}
+		}
+	}
 }
 
 void
@@ -1239,10 +1275,20 @@
 
 int
 read_disk(sector, buf)
-	int sector;
+	unsigned long sector;
 	void *buf;
 {
+	unsigned long dos_size, size;
 
+	size = cylinders * heads * sectors;
+	dos_size = dos_cylinders * dos_heads * dos_sectors;
+
+#if 0
+	if (sector > size && sector > dos_size) {
+		warnx("attempt to read outside of disk boundary!");
+		return (-1);
+	}
+#endif
 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
 		return (-1);
 	return (read(fd, buf, 512));
@@ -1250,10 +1296,20 @@
 
 int
 write_disk(sector, buf)
-	int sector;
+	unsigned long sector;
 	void *buf;
 {
+	unsigned long dos_size, size;
 
+	size = cylinders * heads * sectors;
+	dos_size = dos_cylinders * dos_heads * dos_sectors;
+
+#if 0
+	if (sector > size && sector > dos_size) {
+		warnx("attempt to write outside of disk boundary!");
+		return (-1);
+	}
+#endif
 	if (lseek(fd, (off_t)(sector * 512), 0) == -1)
 		return (-1);
 	return (write(fd, buf, 512));
@@ -1280,15 +1336,37 @@
 int
 read_s0()
 {
-
-	if (read_disk(0, mboot.bootinst) == -1) {
+	if (read_disk(0, ptbl[0].bootinst) == -1) {
 		warn("can't read fdisk partition table");
 		return (-1);
 	}
-	if (getshort(&mboot.signature) != MBR_MAGIC) {
+	if (getshort(&ptbl[0].signature) != MBR_MAGIC) {
 		warnx("invalid fdisk partition table found");
 		return (-1);
 	}
+
+	return (0);
+}
+
+int
+read_extended_partitions()
+{
+	int part;
+	int gotext = 0;
+	struct mbr_partition *partp;
+
+	partp = get_part_ptr(0);
+	for(part = 0; part < NMBRPART; part++) {
+		if (IS_EXTENDED(partp[part].mbrp_typ)) {
+			if (!gotext) {
+				ext_offset = getlong(&partp[part].mbrp_start);
+				read_chain(ptbl, part, 0);
+				gotext++;
+			} else
+				warnx("multiple extended partition table chains");
+		}
+	}
+
 	return (0);
 }
 
@@ -1296,6 +1374,7 @@
 write_s0()
 {
 	int flag, i;
+	struct mbr_partition *partp;
 
 	/*
 	 * write enable label sector before write (if necessary),
@@ -1306,7 +1385,7 @@
 	flag = 1;
 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
-	if (write_disk(0, mboot.bootinst) == -1) {
+	if (write_disk(0, ptbl[0].bootinst) == -1) {
 		warn("can't write fdisk partition table");
 		return -1;
 	}
@@ -1318,6 +1397,15 @@
 	flag = 0;
 	if (ioctl(fd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
+
+	if (r_flag && ext_offset) {
+		partp = get_part_ptr(0);
+		for(i = 0; i < NMBRPART; i++) {
+			if (IS_EXTENDED(partp[i].mbrp_typ))
+				write_chain(&ptbl[0], i, 0);
+		}
+	}
+
 	return 0;
 }
 
@@ -1394,4 +1482,80 @@
 	if (ptr == 0)
 		return ("unknown");
 	return (ptr->name);
+}
+
+int
+read_chain(parent, which, offset)
+	struct mboot* parent;
+	int which;
+	unsigned long offset;
+{
+	int i, gotext;
+        unsigned long myoffset;
+	struct mbr_partition *partp;
+        struct mboot* ptable = parent + 1;
+
+	if (maxpart + 4 > MAX_PARTITION)
+		warn("more than %d partitions, dropping extra partitions", MAX_PARTITION);
+
+	printf("read_chain: parent = %p, ptable = %p, offset = %lu\n", 
+		parent, ptable, offset + ext_offset);
+
+	if (read_disk(ext_offset + offset, &ptable->bootinst) == -1) {
+		warn("can't read extended partition table");
+		return (-1);
+	}
+	
+	if (getshort(&ptable->signature) != MBR_MAGIC) {
+		warnx("invalid fdisk partition table found");
+		return (-1);
+	}
+
+	/* We've read in the table sucesfully, up partition count */
+	maxpart += NMBRPART;
+
+	/* The assumption is that if we've gotten here, -r has been specified */
+	gotext = 0;
+	partp = &ptable->parts[0];
+	for(i = 0; i < NMBRPART; i++) {
+		if (IS_EXTENDED(partp[i].mbrp_typ)) {
+			if (!gotext) {
+                                myoffset = getlong(&partp[i].mbrp_start);
+				read_chain(ptable, i, myoffset);
+				gotext++;
+			} else
+				warnx("multiple extended partition table chains");
+		}
+	}
+
+	return 0;
+}
+
+int
+write_chain(parent, which, offset)
+	struct mboot* parent;
+	int which;
+	unsigned long offset;
+{
+	int i;
+        unsigned long myoffset;
+	struct mbr_partition *partp;
+        struct mboot* ptable = parent + 1;
+
+	printf("write_chain: parent = %p, ptable = %p, offset = %lu\n", 
+		parent, ptable, offset + ext_offset);
+
+	if (write_disk(offset + ext_offset, &ptable->bootinst) == -1)
+		errx(1, "can't write extended partition table");
+	
+	partp = &ptable->parts[0];
+	for(i = 0; i < NMBRPART; i++) {
+		if (IS_EXTENDED(partp[i].mbrp_typ)) {
+                        myoffset = getlong(&partp[i].mbrp_start);
+			if (write_chain(ptable, i, myoffset) < 0)
+				errx(1, "failed to write extended partitions");
+		}
+	}
+
+	return 0;
 }

--------------D322C0970868C0867E5D83B6--