Subject: Re: PATCH: disklabel & fdisk regular files
To: None <tech-userlevel@NetBSD.org>
From: David Young <dyoung@pobox.com>
List: tech-userlevel
Date: 03/02/2004 02:11:46
--kXdP64Ggrk/fb43R
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

On Tue, Feb 17, 2004 at 07:39:06PM +1100, Luke Mewburn wrote:
> On Tue, Feb 17, 2004 at 01:46:38AM -0600, David Young wrote:
>   | It's useful sometimes for a privilegeless user to disklabel or fdisk
>   | a file containing a disk image---a file was made by makefs, say. Here
>   | are patches that make it possible. The disklabel patch is pretty simple:
>   | detect that the target is a file and avoid certain steps.  Because fdisk
>   | needs a disklabel to get started, my patch lets you give it a disktab
>   | and disktype with -t and -T options.
> 
> I'd prefer that disklabel(8) took a specific option to use a regular
> file to enable this behaviour; other disk related tools use '-F' for this.

Done. Patches attached.

> As for fdisk; is there a way we can implement '-F' to enable the
> "don't bother disklabeling" stuff, rather than the -t/-T stuff ?

There is a way.  I can provide -F by "faking up" the disk geometry.
Patches attached.

I had used -t/-T because it was expedient, but I would like for it
to stick around. It lets one avoid "faking up" C/H/S for the file,
if one knows the geometry of the device where one will dd(1) the disk
image later.

Dave

-- 
David Young             OJC Technologies
dyoung@ojctech.com      Urbana, IL * (217) 278-3933

--kXdP64Ggrk/fb43R
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="privless-fdisk-n-disklabel.patch"

Index: fdisk/fdisk.8
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.8,v
retrieving revision 1.43
diff -u -r1.43 fdisk.8
--- fdisk/fdisk.8	6 Oct 2003 12:02:52 -0000	1.43
+++ fdisk/fdisk.8	2 Mar 2004 08:10:44 -0000
@@ -8,11 +8,17 @@
 .Nd MS-DOS partition maintenance program
 .Sh SYNOPSIS
 .Nm
-.Op Fl afiuvBS
+.Op Fl afiuvBFS
 .Bk -words
 .Op Fl 0 | 1 | 2 | 3
 .Ek
 .Bk -words
+.Op Fl t Ar disktab
+.Ek
+.Bk -words
+.Op Fl T Ar disktype
+.Ek
+.Bk -words
 .Op Fl E Ar number
 .Ek
 .Bk -words
@@ -182,6 +188,19 @@
 are specified then the details of the specified partition will be changed.
 Any other partitions which overlap the requested part of the disk will be
 silently deleted.
+.It Fl F 
+Indicate that
+.Ar device
+is a regular file.  Unless the geometry of
+.Ar device
+is told to
+.Nm fdisk
+by
+.Fl T Ar disktype ,
+.Nm fdisk
+will count the 512-byte sectors in
+.Ar device
+and produce a fake geometry.
 .It Fl i
 Explicitly request initialisation of the master boot code
 (similar to what
@@ -221,6 +240,18 @@
 .Pa /bin/sh
 commands for setting variables to the partition information.
 This could be used by installation scripts.
+.It Fl t Ar disktab
+Read 
+.Ar disktype
+from the named 
+.Xr disktab 5 
+file instead of from
+.Pa /etc/disktab.
+.It Fl T Ar disktype
+Use the disklabel 
+.Ar disktype
+instead of the disklabel on
+.Ar device .
 .It Fl u
 Display the partitions and interactively ask which one you want to edit.
 .Nm
@@ -445,6 +476,7 @@
 .El
 .Sh SEE ALSO
 .Xr disklabel 8 ,
+.Xr disktab 5 ,
 .Xr mbr 8 ,
 .Xr mbrlabel 8
 .Sh BUGS
Index: fdisk/fdisk.c
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.c,v
retrieving revision 1.74
diff -u -r1.74 fdisk.c
--- fdisk/fdisk.c	5 Jan 2004 23:23:32 -0000	1.74
+++ fdisk/fdisk.c	2 Mar 2004 08:10:44 -0000
@@ -47,6 +47,7 @@
 #include <sys/sysctl.h>
 
 #include <ctype.h>
+#include <disktab.h>
 #include <err.h>
 #include <errno.h>
 #include <fcntl.h>
@@ -114,10 +115,10 @@
 
 #define DEFAULT_ACTIVE	(~(daddr_t)0)
 
-#define OPTIONS			"0123BSafiluvs:b:c:E:r:w:"
+#define OPTIONS			"0123BFSafiluvs:b:c:E:r:w:t:T:"
 #else
 #define change_part(e, p, id, st, sz, bm) change__part(e, p, id, st, sz)
-#define OPTIONS			"0123Safiluvs:b:c:E:r:w:"
+#define OPTIONS			"0123FSafiluvs:b:c:E:r:w:"
 #endif
 
 uint dos_cylinders;
@@ -140,6 +141,7 @@
 
 int fd = -1, wfd = -1, *rfd = &fd;
 char *disk_file;
+char *disk_type = NULL;
 
 int a_flag;		/* set active partition */
 int i_flag;		/* init bootcode */
@@ -152,6 +154,7 @@
 int B_flag;		/* Edit/install bootselect code */
 int E_flag;		/* extended partition number */
 int b_cyl, b_head, b_sec;  /* b_flag values. */
+int F_flag = 0;
 
 struct mbr_sector bootcode[8192 / sizeof (struct mbr_sector)];
 int bootsize;		/* actual size of bootcode */
@@ -382,6 +385,9 @@
 			B_flag = 1;
 			break;
 #endif
+		case 'F':	/* device argument is really a file */
+			F_flag = 1;
+			break;
 		case 'S':	/* Output as shell variables */
 			sh_flag = 1;
 			break;
@@ -445,13 +451,22 @@
 		case 'w':	/* write data to disk_file */
 			disk_file = optarg;
 			break;
-			
+		case 't':
+			if (setdisktab(optarg) == -1)
+				errx(EXIT_FAILURE, "bad disktab");
+			break;
+		case 'T':
+			disk_type = optarg;
+			break;
 		default:
 			usage();
 		}
 	argc -= optind;
 	argv += optind;
 
+	if (disk_type != NULL && getdiskbyname(disk_type) == NULL)
+		errx(EXIT_FAILURE, "bad disktype");
+
 	if (sh_flag && (a_flag || i_flag || u_flag || f_flag || s_flag))
 		usage();
 
@@ -563,6 +578,7 @@
 		"[-b cylinders/heads/sectors] \\\n"
 		"%*s[-0123 | -E num "
 		"[-s id/start/size[/bootmenu]]] \\\n"
+		"%*s[-t disktab] [-T disktype] \\\n"
 		"%*s[-c bootcode] [-r|-w file] [device]\n"
 		"\t-a change active partition\n"
 		"\t-f force - not interactive\n"
@@ -571,8 +587,9 @@
 		"\t-u update partition data\n"
 		"\t-v verbose output, -v -v more verbose still\n"
 		"\t-B update bootselect options\n"
+		"\t-F treat device as a regular file\n"
 		"\t-S output as shell defines\n",
-		getprogname(), indent, "", indent, "");
+		getprogname(), indent, "", indent, "", indent, "");
 	exit(1);
 }
 
@@ -2213,36 +2230,63 @@
 	return (write(wfd, buf, 512));
 }
 
+static void
+guess_geometry(daddr_t _sectors)
+{
+	/* guess - has to better than the above */
+	dos_sectors = MAXSECTOR;
+	dos_heads = MAXHEAD - 1;	/* some BIOS might use 256 */
+	dos_cylinders = _sectors / (MAXSECTOR * (MAXHEAD - 1));
+	if (dos_cylinders > MAXCYL - 1)
+		dos_cylinders = MAXCYL - 1;
+}
+
 int
 get_params(void)
 {
+	if (disk_type != NULL) {
+		struct disklabel *tmplabel;
 
-	if (ioctl(fd, DIOCGDEFLABEL, &disklabel) == -1) {
+		if ((tmplabel = getdiskbyname(disk_type)) == NULL) {
+			warn("bad disktype");
+			return (-1);
+		}
+		disklabel = *tmplabel;
+	} else if (F_flag) {
+		struct stat st;
+		if (fstat(fd, &st) == -1) {
+			warn("fstat");
+			return (-1);
+		}
+		if (st.st_size % 512 != 0) {
+			warnx("%s size (%lld) is not divisible "
+			    "by sector size (%d)", disk, (long long)st.st_size,
+			    512);
+		}
+		disklabel.d_secperunit = st.st_size / 512;
+		guess_geometry(disklabel.d_secperunit);
+		disklabel.d_ncylinders = dos_cylinders;
+		disklabel.d_ntracks = dos_heads;
+		disklabel.d_nsectors = dos_sectors;
+	} else if (ioctl(fd, DIOCGDEFLABEL, &disklabel) == -1) {
 		warn("DIOCGDEFLABEL");
 		if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
 			warn("DIOCGDINFO");
 			return (-1);
 		}
 	}
-
+	disksectors = disklabel.d_secperunit;
 	cylinders = disklabel.d_ncylinders;
 	heads = disklabel.d_ntracks;
 	sectors = disklabel.d_nsectors;
-	disksectors = disklabel.d_secperunit;
 
 	/* pick up some defaults for the BIOS sizes */
 	if (sectors <= MAXSECTOR) {
 		dos_cylinders = cylinders;
 		dos_heads = heads;
 		dos_sectors = sectors;
-	} else {
-		/* guess - has to better than the above */
-		dos_sectors = MAXSECTOR;
-		dos_heads = MAXHEAD - 1;	/* some BIOS might use 256 */
-		dos_cylinders = disksectors / (MAXSECTOR * (MAXHEAD - 1));
-		if (dos_cylinders > MAXCYL - 1)
-			dos_cylinders = MAXCYL - 1;
-	}
+	} else
+		guess_geometry(disksectors);
 	dos_disksectors = disksectors;
 
 	return (0);
@@ -2279,7 +2323,7 @@
 	 * sector 0. (e.g. empty disk)
 	 */
 	flag = 1;
-	if (wfd == fd && ioctl(wfd, DIOCWLABEL, &flag) < 0)
+	if (wfd == fd && F_flag == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
 	if (write_disk(0, &mboot) == -1) {
 		warn("Can't write fdisk partition table");
@@ -2301,7 +2345,7 @@
 	rval = 0;
     protect_label:
 	flag = 0;
-	if (wfd == fd && ioctl(wfd, DIOCWLABEL, &flag) < 0)
+	if (wfd == fd && F_flag == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
 	return rval;
 }
Index: disklabel/disklabel.8
===================================================================
RCS file: /cvsroot/src/sbin/disklabel/disklabel.8,v
retrieving revision 1.49
diff -u -r1.49 disklabel.8
--- disklabel/disklabel.8	10 Nov 2003 09:22:09 -0000	1.49
+++ disklabel/disklabel.8	2 Mar 2004 08:10:45 -0000
@@ -42,10 +42,12 @@
 .Nm
 .Op Fl rt
 .Op Fl C
+.Op Fl F
 .Ar disk
 .Nm
 .Fl w
 .Op Fl r
+.Op Fl F
 .Op Fl f Ar disktab
 .Ar disk Ar disktype
 .Oo Ar packid Oc
@@ -54,15 +56,18 @@
 .Op Fl r
 .Op Fl I
 .Op Fl C
+.Op Fl F
 .Ar disk
 .Nm
 .Fl i
 .Op Fl I
 .Op Fl r
+.Op Fl F
 .Ar disk
 .Nm
 .Fl R
 .Op Fl r
+.Op Fl F
 .Ar disk Ar protofile
 .Nm
 .Op Fl NW
@@ -70,6 +75,7 @@
 .sp
 .Nm
 .Fl B
+.Op Fl F
 .Op Fl f Ar disktab
 .Oo
 .Fl b Ar boot1
@@ -80,6 +86,7 @@
 .Nm
 .Fl w
 .Fl B
+.Op Fl F
 .Op Fl f Ar disktab
 .Oo
 .Fl b Ar boot1
@@ -90,6 +97,7 @@
 .Nm
 .Fl R
 .Fl B
+.Op Fl F
 .Op Fl f Ar disktab
 .Oo
 .Fl b Ar boot1
@@ -122,6 +130,15 @@
 flag are described with the affected commands.
 .Pp
 The
+.Fl F
+option indicates that
+.Nm
+should treat
+.Ar disk 
+as if it is a regular file, instead of as if it is a block device,
+for the purposes of reading and writing a disklabel.
+.Pp
+The
 .Fl I
 option is similar to the
 .Fl r
Index: disklabel/disklabel.c
===================================================================
RCS file: /cvsroot/src/sbin/disklabel/disklabel.c,v
retrieving revision 1.127
diff -u -r1.127 disklabel.c
--- disklabel/disklabel.c	29 Feb 2004 21:31:14 -0000	1.127
+++ disklabel/disklabel.c	2 Mar 2004 08:10:45 -0000
@@ -122,16 +122,19 @@
 	UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, WRITE, WRITEBOOT, INTERACT
 } op = UNSPEC;
 
+static	int	Fflag;
 static	int	rflag;
 static	int	tflag;
 	int	Cflag;
 static	int	Iflag;
 
+#define COMMON_OPTIONS	"BCFINRWb:ef:irs:tw"
+
 #ifdef DEBUG
 static int	debug;
-#define OPTIONS	"BCINRWb:def:irs:tw"
+#define OPTIONS	COMMON_OPTIONS "d"
 #else	/* ! DEBUG */
-#define OPTIONS	"BCINRWb:ef:irs:tw"
+#define OPTIONS	COMMON_OPTIONS
 #endif	/* ! DEBUG */
 
 #ifdef USE_MBR
@@ -194,6 +197,9 @@
 		case 'C':
 			++Cflag;
 			break;
+		case 'F':
+			++Fflag;
+			break;
 		case 'I':
 			++Iflag;
 			break;
@@ -473,7 +479,7 @@
 	lp->d_checksum = 0;
 	lp->d_checksum = dkcksum(lp);
 
-	if (rflag || Iflag)
+	if (Fflag || rflag || Iflag)
 	{
 #ifdef USE_MBR
 		struct partition *pp = &lp->d_partitions[2];
@@ -524,7 +530,7 @@
 		 * disable after writing.
 		 */
 		writable = 1;
-		if (ioctl(f, DIOCWLABEL, &writable) < 0)
+		if (!Fflag && ioctl(f, DIOCWLABEL, &writable) < 0)
 			perror("ioctl DIOCWLABEL");
 
 #ifdef __alpha__
@@ -556,13 +562,13 @@
 #endif	/* NUMBOOT > 0 */
 
 		writable = 0;
-		if (ioctl(f, DIOCWLABEL, &writable) < 0)
+		if (!Fflag && ioctl(f, DIOCWLABEL, &writable) < 0)
 			perror("ioctl DIOCWLABEL");
 		/* 
 		 * Now issue a DIOCWDINFO. This will let the kernel convert the
 		 * disklabel to some machdep format if needed.
 		 */
-		if (ioctl(f, DIOCWDINFO, lp) < 0) {
+		if (!Fflag && ioctl(f, DIOCWDINFO, lp) < 0) {
 			l_perror("ioctl DIOCWDINFO");
 			return (1);
 		}
@@ -871,7 +877,7 @@
 {
 	struct disklabel *lp;
 
-	if (rflag || Iflag) {
+	if (Fflag || rflag || Iflag) {
 		const char *msg;
 		off_t	 sectoffset;
 
@@ -1827,20 +1833,20 @@
 		const char *name;
 		const char *expn;
 	} usages[] = {
-	{ "[-rt] [-C] disk",
+	{ "[-rt] [-C] [-F] disk",
 	    "(to read label)" },
-	{ "-w [-r] [-f disktab] disk type [ packid ]",
+	{ "-w [-r] [-F] [-f disktab] disk type [ packid ]",
 #if NUMBOOT > 0
 	    "(to write label with existing boot program)"
 #else
 	    "(to write label)"
 #endif
 	},
-	{ "-e [-r] [-I] [-C] disk",
+	{ "-e [-r] [-I] [-C] [-F] disk",
 	    "(to edit label)" },
-	{ "-i [-I] [-r] disk",
+	{ "-i [-I] [-r] [-F] disk",
 	    "(to create a label interactively)" },
-	{ "-R [-r] disk protofile",
+	{ "-R [-r] [-F] disk protofile",
 #if NUMBOOT > 0
 	    "(to restore label with existing boot program)"
 #else
@@ -1851,16 +1857,16 @@
 # if NUMBOOT > 1
 	{ "-B [-f disktab] [ -b xxboot [ -s bootxx ] ] disk [ type ]",
 	    "(to install boot program with existing label)" },
-	{ "-w -B [-f disktab] [ -b xxboot [ -s bootxx ] ] disk type [ packid ]",
+	{ "-w -B [-F] [-f disktab] [ -b xxboot [ -s bootxx ] ] disk type [ packid ]",
 	    "(to write label and boot program)" },
-	{ "-R -B [-f disktab] [ -b xxboot [ -s bootxx ] ] disk protofile [ type ]",
+	{ "-R -B [-F] [-f disktab] [ -b xxboot [ -s bootxx ] ] disk protofile [ type ]",
 	    "(to restore label and boot program)" },
 # else
-	{ "-B [-f disktab] [ -b bootprog ] disk [ type ]",
+	{ "-B [-F] [-f disktab] [ -b bootprog ] disk [ type ]",
 	    "(to install boot program with existing on-disk label)" },
-	{ "-w -B [-f disktab] [ -b bootprog ] disk type [ packid ]",
+	{ "-w -B [-F] [-f disktab] [ -b bootprog ] disk type [ packid ]",
 	    "(to write label and install boot program)" },
-	{ "-R -B [-f disktab] [ -b bootprog ] disk protofile [ type ]",
+	{ "-R -B [-F] [-f disktab] [ -b bootprog ] disk protofile [ type ]",
 	    "(to restore label and install boot program)" },
 # endif
 #endif

--kXdP64Ggrk/fb43R--