Subject: PATCH: disklabel & fdisk regular files
To: None <tech-userlevel@netbsd.org, dyoung@netbsd.org>
From: David Young <dyoung@pobox.com>
List: tech-userlevel
Date: 02/17/2004 01:46:38
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.

Please leave me on the To: line; I do not subscribe to tech-userlevel.

Dave

Index: sbin/disklabel/disklabel.c
===================================================================
RCS file: /cvsroot/src/sbin/disklabel/disklabel.c,v
retrieving revision 1.126
diff -u -r1.126 disklabel.c
--- sbin/disklabel/disklabel.c	18 Jan 2004 22:34:22 -0000	1.126
+++ sbin/disklabel/disklabel.c	17 Feb 2004 07:20:52 -0000
@@ -122,6 +122,7 @@
 	UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, WRITE, WRITEBOOT, INTERACT
 } op = UNSPEC;
 
+static	int	is_file;
 static	int	rflag;
 static	int	tflag;
 	int	Cflag;
@@ -171,6 +172,7 @@
 main(int argc, char *argv[])
 {
 	struct disklabel *lp;
+	struct stat st;
 	FILE	*t;
 	int	 ch, f, writable, error;
 
@@ -271,6 +273,9 @@
 		usage();
 
 	dkname = argv[0];
+	if (stat(dkname, &st) == -1)
+		err(EXIT_FAILURE, "stat");
+	is_file = ((st.st_mode & S_IFMT) == S_IFREG);
 	f = opendisk(dkname, op == READ ? O_RDONLY : O_RDWR, np, MAXPATHLEN, 0);
 	specname = np;
 	np += strlen(specname) + 1;
@@ -472,7 +477,7 @@
 	lp->d_checksum = 0;
 	lp->d_checksum = dkcksum(lp);
 
-	if (rflag || Iflag)
+	if (is_file || rflag || Iflag)
 	{
 #ifdef USE_MBR
 		struct partition *pp = &lp->d_partitions[2];
@@ -523,7 +528,7 @@
 		 * disable after writing.
 		 */
 		writable = 1;
-		if (ioctl(f, DIOCWLABEL, &writable) < 0)
+		if (!is_file && ioctl(f, DIOCWLABEL, &writable) < 0)
 			perror("ioctl DIOCWLABEL");
 
 #ifdef __alpha__
@@ -555,13 +560,13 @@
 #endif	/* NUMBOOT > 0 */
 
 		writable = 0;
-		if (ioctl(f, DIOCWLABEL, &writable) < 0)
+		if (!is_file && 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 (!is_file && ioctl(f, DIOCWDINFO, lp) < 0) {
 			l_perror("ioctl DIOCWDINFO");
 			return (1);
 		}
@@ -870,7 +875,7 @@
 {
 	struct disklabel *lp;
 
-	if (rflag || Iflag) {
+	if (is_file || rflag || Iflag) {
 		const char *msg;
 		off_t	 sectoffset;
 
Index: sbin/fdisk/fdisk.8
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.8,v
retrieving revision 1.43
diff -u -r1.43 fdisk.8
--- sbin/fdisk/fdisk.8	6 Oct 2003 12:02:52 -0000	1.43
+++ sbin/fdisk/fdisk.8	17 Feb 2004 07:20:52 -0000
@@ -13,6 +13,12 @@
 .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
Index: sbin/fdisk/fdisk.c
===================================================================
RCS file: /cvsroot/src/sbin/fdisk/fdisk.c,v
retrieving revision 1.74
diff -u -r1.74 fdisk.c
--- sbin/fdisk/fdisk.c	5 Jan 2004 23:23:32 -0000	1.74
+++ sbin/fdisk/fdisk.c	17 Feb 2004 07:20:55 -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,7 +115,7 @@
 
 #define DEFAULT_ACTIVE	(~(daddr_t)0)
 
-#define OPTIONS			"0123BSafiluvs:b:c:E:r:w:"
+#define OPTIONS			"0123BSafiluvs: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:"
@@ -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 is_file = 0;
 
 struct mbr_sector bootcode[8192 / sizeof (struct mbr_sector)];
 int bootsize;		/* actual size of bootcode */
@@ -445,13 +448,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();
 
@@ -470,8 +482,15 @@
 		usage();
 	}
 
-	if (argc > 0)
+	if (argc > 0) {
 		disk = argv[0];
+		if (stat(disk, &sb) == -1)
+			err(EXIT_FAILURE, "stat(%s,)", disk);
+		if ((sb.st_mode & S_IFMT) == S_IFREG)
+			is_file = 1;
+		else if ((sb.st_mode & S_IFMT) != S_IFCHR)
+			errx(EXIT_FAILURE, "bad filetype for %s", disk);
+	}
 
 	if (open_disk(B_flag || a_flag || i_flag || u_flag) < 0)
 		exit(1);
@@ -563,6 +582,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"
@@ -572,7 +592,7 @@
 		"\t-v verbose output, -v -v more verbose still\n"
 		"\t-B update bootselect options\n"
 		"\t-S output as shell defines\n",
-		getprogname(), indent, "", indent, "");
+		getprogname(), indent, "", indent, "", indent, "");
 	exit(1);
 }
 
@@ -2216,8 +2236,15 @@
 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 (ioctl(fd, DIOCGDEFLABEL, &disklabel) == -1) {
 		warn("DIOCGDEFLABEL");
 		if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
 			warn("DIOCGDINFO");
@@ -2279,7 +2306,7 @@
 	 * sector 0. (e.g. empty disk)
 	 */
 	flag = 1;
-	if (wfd == fd && ioctl(wfd, DIOCWLABEL, &flag) < 0)
+	if (wfd == fd && is_file == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
 	if (write_disk(0, &mboot) == -1) {
 		warn("Can't write fdisk partition table");
@@ -2301,7 +2328,7 @@
 	rval = 0;
     protect_label:
 	flag = 0;
-	if (wfd == fd && ioctl(wfd, DIOCWLABEL, &flag) < 0)
+	if (wfd == fd && is_file == 0 && ioctl(wfd, DIOCWLABEL, &flag) < 0)
 		warn("DIOCWLABEL");
 	return rval;
 }

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