Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 10 Feb 2003 16:48:22 -0800 (PST)
From:      Juli Mallett <jmallett@FreeBSD.org>
To:        Perforce Change Reviews <perforce@freebsd.org>
Subject:   PERFORCE change 24951 for review
Message-ID:  <200302110048.h1B0mMrs006368@repoman.freebsd.org>

next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=24951

Change 24951 by jmallett@jmallett_dalek on 2003/02/10 16:47:29

	Implement fxlabel editing and the necessary abstractions, also a
	few much-needed passing-arounds of a volume header.

Affected files ...

.. //depot/projects/mips/sbin/fxlabel/fxlabel.c#6 edit
.. //depot/projects/mips/sys/sys/diskfx.h#7 edit

Differences ...

==== //depot/projects/mips/sbin/fxlabel/fxlabel.c#6 (text+ko) ====

@@ -27,12 +27,16 @@
 __FBSDID("$FreeBSD$");
 
 #include <sys/types.h>
+#include <sys/disk.h>
 #include <sys/diskfx.h>
 #include <sys/endian.h>
 #include <sys/param.h>
 #include <sys/stat.h>
+#include <sys/wait.h>
+#include <ctype.h>
 #include <err.h>
 #include <fcntl.h>
+#include <paths.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -41,6 +45,7 @@
 
 struct volhdr	label;
 struct volpart	*vhp = &label.vh_part[FX_VOLHDRPART];
+struct volpart	*volp = &label.vh_part[FX_VOLPART];
 static int	bsize = 512;
 
 /*
@@ -48,22 +53,27 @@
  * programmers from shooting off feet.
  */
 static void	addfile(struct volhdr *, int, const char *);
+static int	bytesround2bsize(int);
+static void	clearpart(struct volhdr *);
 static void	defrag(struct volhdr *, int);
 static void	deletefile(struct volhdr *, int, const char *);
 static int	dkopen(const char *, int);
+static int	disksize(int);
 static void	dirlist(struct volhdr *);
+static void	editlabel(struct volhdr *, int, int);
 static void	getfile(struct volhdr *, int, const char *);
 static bool	goodlabel(struct volhdr *, const char **);
 static int32_t	labelsum(struct volhdr *);
-static void	newlabel(struct volhdr *);
-static void	printlabel(struct volhdr *);
-static bool	readlabel(int);
+static void	newlabel(struct volhdr *, int, int);
+static bool	parselabel(struct volhdr *, FILE *);
+static void	printlabel(struct volhdr *, FILE *);
+static bool	readlabel(struct volhdr *, int);
 static void	setpart(struct volhdr *, int, int, int, int);
 static void	sumlabel(struct volhdr *);
 static void	swap_dec_label(struct volhdr *);
 static void	swap_enc_label(struct volhdr *);
-static int	startdisk(const char *, int);
-static bool	writelabel(int);
+static int	startdisk(struct volhdr *, const char *, int);
+static bool	writelabel(struct volhdr *, int);
 
 static void	usage(void);
 
@@ -78,16 +88,17 @@
 main(int argc, char *argv[])
 {
 	const char *aflag, *dflag, *disk, *gflag;
-	bool pflag, wflag;
+	bool eflag, pflag, wflag;
+	int dksize;
 	int sflag;
 	int ch;
 	int fd;
 
 	aflag = dflag = gflag = NULL;
-	pflag = wflag = false;
-	sflag = 0;
+	eflag = pflag = wflag = false;
+	dksize = sflag = 0;
 
-	while ((ch = getopt(argc, argv, "a:d:g:ps:w")) != -1) {
+	while ((ch = getopt(argc, argv, "a:d:eg:ps:w")) != -1) {
 		switch (ch) {
 		case 'a':
 			aflag = optarg;
@@ -95,6 +106,9 @@
 		case 'd':
 			dflag = optarg;
 			break;
+		case 'e':
+			eflag = true;
+			break;
 		case 'g':
 			gflag = optarg;
 			break;
@@ -109,7 +123,7 @@
 				warnx("volume header size not >= %d", bsize);
 				usage();
 			}
-			sflag = ((sflag + 511) / bsize) * bsize;
+			sflag = bytesround2bsize(sflag);
 			break;
 		case 'w':
 			if (pflag)
@@ -124,7 +138,8 @@
 	argc -= optind;
 	argv += optind;
 
-	if (aflag == NULL && dflag == NULL && gflag == NULL && !pflag && !wflag)
+	if (aflag == NULL && dflag == NULL && !eflag && gflag == NULL &&
+	    !pflag && !wflag)
 		pflag = true;
 
 	if (!sflag)
@@ -132,32 +147,42 @@
 
 	while ((disk = *argv++) != NULL) {
 		if (aflag != NULL) {
-			fd = startdisk(disk, O_RDWR);
+			fd = startdisk(&label, disk, O_RDWR);
 			defrag(&label, fd);
 			addfile(&label, fd, aflag);
-			if (writelabel(fd))
+			if (writelabel(&label, fd))
 				err(1, "%s (label write)", disk);
 			close(fd);
 			continue;
 		}
 		if (dflag != NULL) {
-			fd = startdisk(disk, O_RDWR);
+			fd = startdisk(&label, disk, O_RDWR);
 			deletefile(&label, fd, dflag);
 			defrag(&label, fd);
-			if (writelabel(fd))
+			if (writelabel(&label, fd))
 				err(1, "%s (label write)", disk);
 			close(fd);
 			continue;
 		}
+		if (eflag) {
+			fd = dkopen(disk, O_RDWR);
+			if (fd == -1)
+				err(1, "%s (open)", disk);
+			editlabel(&label, fd, sflag);
+			if (writelabel(&label, fd))
+				err(1, "%s (label write)", disk);
+			continue;
+		}
 		if (gflag != NULL) {
-			fd = startdisk(disk, O_RDONLY);
+			fd = startdisk(&label, disk, O_RDONLY);
 			getfile(&label, fd, gflag);
 			close(fd);
 			continue;
 		}
 		if (pflag) {
-			fd = startdisk(disk, O_RDONLY);
-			printlabel(&label);
+			fd = startdisk(&label, disk, O_RDONLY);
+			printlabel(&label, stdout);
+			dirlist(&label);
 			close(fd);
 			continue;
 		}
@@ -165,9 +190,11 @@
 			fd = dkopen(disk, O_WRONLY);
 			if (fd == -1)
 				err(1, "%s (open)", disk);
-			newlabel(&label);
-			setpart(&label, FX_VOLHDRPART, FX_TYPEVOLHDR, 0, sflag);
-			if (writelabel(fd))
+			dksize = disksize(fd);
+			if (dksize == -1)
+				err(1, "%s (disk size)", disk);
+			newlabel(&label, sflag, dksize);
+			if (writelabel(&label, fd))
 				err(1, "%s (label write)", disk);
 			close(fd);
 			continue;
@@ -228,7 +255,7 @@
 	strncpy(dp->vd_name, file, FX_NAMELEN);
 	dp->vd_addr = himark + 1;
 	dp->vd_size = st.st_size;
-	rounded = ((st.st_size + 511) / bsize) * bsize;
+	rounded = bytesround2bsize(st.st_size);
 	buf = malloc(rounded);
 	if (buf == NULL)
 		errx(1, "malloc failed");
@@ -241,6 +268,26 @@
 		err(1, "%s (input write)", file);
 }
 
+static int
+bytesround2bsize(int bytes)
+{
+	return (((bytes + (bsize - 1)) / bsize) * bsize);
+}
+
+static void
+clearpart(struct volhdr *vp)
+{
+	struct volpart *part;
+	int i;
+
+	for (i = 0; i < FX_NPARTS; i++) {
+		part = &vp->vh_part[i];
+		part->vp_type = 0;
+		part->vp_begin = 0;
+		part->vp_size = 0;
+	}
+}
+
 static void
 defrag(struct volhdr *vp, int fd)
 {
@@ -304,6 +351,105 @@
 	}
 }
 
+static int
+disksize(int fd)
+{
+	off_t mediasize;
+	struct stat st;
+	int rv;
+
+	rv = fstat(fd, &st);
+	if (rv == -1 || st.st_size <= 0) {
+		rv = ioctl(fd, DIOCGMEDIASIZE, &mediasize);
+		if (rv == -1)
+			return (-1);
+	} else
+		mediasize = st.st_size;
+
+	rv = mediasize;
+
+	return (rv);
+}
+
+static void
+editlabel(struct volhdr *vp, int fd, int hdrsize)
+{
+	char buf[] = "/tmp/fxlabel.XXXXXXX";
+	const char *editor;
+	int dksize;
+	int status;
+	pid_t pid, xpid;
+	FILE *fp;
+	int efd;
+	int ch;
+	int rv;
+
+	if (readlabel(vp, fd))
+		err(1, "%d (label read)", fd);
+
+	dksize = disksize(fd);
+	if (dksize == -1)
+		err(1, "%d (disk size)", fd);
+
+	efd = mkstemp(buf);
+	if (efd == -1)
+		err(1, "make temp file");
+	fp = fdopen(efd, "w+");
+	if (fp == NULL)
+		err(1, "make temp file stream");
+	if (goodlabel(vp, NULL)) {
+		newlabel(vp, hdrsize, dksize);
+		fputs("# Below is a new disk label, edit it wisely.\n", fp);
+	} else {
+		swap_dec_label(vp);
+		fputs("# Below is your disk label, edit it wisely.\n", fp);
+	}
+	printlabel(vp, fp);
+	clearpart(vp);
+	editor = getenv("EDITOR");
+	if (editor == NULL)
+		editor = _PATH_VI;
+	pid = fork();
+	if (pid < 0)
+		err(1, "%d (editor fork)", fd);
+	if (pid == 0) {
+		setgid(getgid());
+		setuid(getuid());
+		execlp(editor, editor, buf, NULL);
+		err(1, "%s", editor);
+	}
+	while ((xpid = wait(&status)) >= 0)
+		if (xpid == pid)
+			break;
+	rewind(fp);
+
+	if (parselabel(vp, fp)) {
+		printf("WARNING: Possible errors detected.  Write? [yN] ");
+		while ((ch = getc(stdin)) != EOF) {
+			switch (ch) {
+			case 'Y':
+			case 'y':
+				goto write;
+			case '\n':
+			case 'N':
+			case 'n':
+				break;
+			default:
+				continue;
+			}
+			break;
+		}
+		printf("NOT WRITING DISK LABEL, SAVED IN %s\n", buf);
+		exit(1);
+	}
+write:	printf("WRITING DISK LABEL TO DISK:\n");
+	printlabel(vp, stdout);
+	rv = unlink(buf);
+	if (rv == -1)
+		warn("unlink %s", buf);
+	return;
+}
+
 static void
 getfile(struct volhdr *vp, int fd, const char *file)
 {
@@ -326,7 +472,7 @@
 		buf = malloc(dp->vd_size);
 		if (buf == NULL)
 			errx(1, "malloc failed");
-		rounded = ((dp->vd_size + 511) / bsize) * bsize;
+		rounded = bytesround2bsize(dp->vd_size);
 		cnt = pread(fd, buf, rounded, dp->vd_addr * bsize);
 		if (cnt != rounded)
 			err(1, "%s (file read)", file);
@@ -342,18 +488,25 @@
 static bool
 goodlabel(struct volhdr *vp, const char **errorp)
 {
+	const char *error;
 	int32_t sum;
 
 	if (be32toh(vp->vh_magic) != FX_LABEL_MAGIC) {
-		*errorp = "bad magic";
-		return (true);
+		if (vp->vh_magic == FX_LABEL_MAGIC)
+			error = "wrong endianness";
+		else
+			error = "bad magick";
+		goto bad;
 	}
 	sum = labelsum(vp);
 	if (sum != 0) {
-		*errorp = "bad checksum";
-		return (true);
+		error = "bad checksum";
+		goto bad;
 	}
 	return (false);
+bad:	if (errorp != NULL)
+		*errorp = error;
+	return (true);
 }
 
 static int32_t
@@ -369,14 +522,18 @@
 	for (i = 0; i < sizeof *vp / sizeof *words; i++)
 		sum -= be32toh(words[i]);
 
-	return sum;
+	return (sum);
 }
 
 static void
-newlabel(struct volhdr *vp)
+newlabel(struct volhdr *vp, int volhdrsize, int dksize)
 {
 	memset(vp, 0, sizeof *vp);
 	vp->vh_magic = FX_LABEL_MAGIC;
+	if (volhdrsize > dksize)
+		errx(1, "volume header extends beyond volume");
+	setpart(vp, FX_VOLHDRPART, FX_TYPEVOLHDR, 0, volhdrsize);
+	setpart(vp, FX_VOLPART, FX_TYPEVOL, 0, dksize);
 }
 
 static const char *
@@ -390,41 +547,169 @@
 	return (fx_typename[vp->vp_type]);
 }
 
+static bool
+parselabel(struct volhdr *vp, FILE *fp)
+{
+	const char *r;
+	char *p, *q;
+	char *line;
+	size_t len;
+	int inparts, foundparts;
+	int part, type, begin, size;
+	char partch;
+	int errors;
+	int i;
+
+	errors = inparts = foundparts = 0;
+
+	while (!feof(fp) && !ferror(fp) && (line = fgetln(fp, &len)) != NULL) {
+		if (len == 0)
+			continue;
+		line[len - 1] = '\0';
+		if (strstr(line, "--- PARTITION TABLE ---") == line) {
+			inparts = 1;
+			continue;
+		}
+		if (strstr(line, "--- FOUND") == line) {
+			inparts = 0;
+			foundparts = 1;
+			continue;
+		}
+		if (inparts) {
+			p = q = line;
+			while (isspace((unsigned char)*p))
+				p++;
+			if (strstr(p, "PART") == p)
+				continue;
+			part = *p++ - 'a';
+			if (part < 0 || part >= FX_NPARTS) {
+				printf("PARTITION NUMBER %d INVALID.\n", part);
+				goto badpart;
+			}
+			if (!isspace((unsigned char)*p)) {
+				printf("WHITESPACE SHOULD FOLLOW PARTITION.\n");
+				goto badpart;
+			}
+			type = (int)strtoul(p, &q, 0);
+			/*
+			 * If we could not read a partition type number, or
+			 * if the end of it is not a space, look for a type
+			 * name.  The latter is for a case like "4.2BSD" for
+			 * the type name.
+			 */
+			if (q == p || !isspace((unsigned char)*q)) {
+				type = -1;
+				while (isspace((unsigned char)*p))
+					p++;
+				for (i = 0; i < FX_TYPEMAX; i++) {
+					r = fx_typename[i];
+					if (strcasestr(p, r) == NULL)
+						continue;
+					type = i;
+					break;
+				}
+				if (type == -1) {
+					printf("INVALID PARTITION TYPE.\n");
+					goto badpart;
+				}
+				p += strlen(r);
+			} else {
+				p = q;
+				/*
+				 * We had a type number, if a type name follows
+				 * we must SKIP it.
+				 */
+				r = fx_typename[type];
+				if ((q = strstr(p, r)) != NULL)
+					p = q + strlen(r);
+			}
+			begin = (int)strtoul(p, &q, 0);
+			if (q == p) {
+				printf("NO BEGIN LBN.\n");
+				goto badpart;
+			} else
+				p = q;
+			size = (int)strtoul(p, &q, 0);
+			if (q == p) {
+				printf("NO SIZE.\n");
+				goto badpart;
+			}
+			if (!isspace((unsigned char)*q) && *q != '\0') {
+				printf("JUNK AFTER PARTITION DEFINITION.\n");
+				goto badpart;
+			}
+			/*
+			 * We need to add this partition w/ size in blocks.
+			 */
+			size = bytesround2bsize(size) / bsize;
+			setpart(vp, part, type, begin, size);
+			continue;
+badpart:		printf("INVALID PARTITION: %s\n", line);
+			errors++;
+			continue;
+		}
+		if (foundparts) {
+			if (strstr(line, "root at") == line) {
+				sscanf(line, "root at %c", &partch);
+				part = partch - 'a';
+				vp->vh_root = part;
+				continue;
+			}
+			if (strstr(line, "swap at") == line) {
+				sscanf(line, "swap at %c", &partch);
+				part = partch - 'a';
+				vp->vh_swap = part;
+				continue;
+			}
+			if (strstr(line, "boots from") == line) {
+				/* XXX h0h0magic number inline. */
+				sscanf(line, "boots from %16c", vp->vh_kernel);
+				continue;
+			}
+		}
+	}
+	if (errors) {
+		printf("DISK LABEL HAS %d ERRORS\n", errors);
+		return true;
+	}
+	return false;
+}
+
 static void
-printlabel(struct volhdr *vp)
+printlabel(struct volhdr *vp, FILE *fp)
 {
 	struct volpart *part;
 	int i, nparts;
 
 	nparts = 0;
-	printf("--- PARTITION TABLE ---\n");
-	printf("%8s %-5s %-20s %-18s %s\n",
+	fprintf(fp, "--- PARTITION TABLE ---\n");
+	fprintf(fp, "%8s %-5s %-20s %-18s %s\n",
 	       "PART", "TYPE", "(TYPE NAME)", "BEGIN LBN", "SIZE");
 	for (i = 0; i < FX_NPARTS; i++) {
 		part = &vp->vh_part[i];
 		if (!part->vp_size)
 			continue;
 		nparts++;
-		printf("%8c %-5d %-20s %-18d %d\n", 'a' + i, part->vp_type,
+		fprintf(fp, "%8c %-5d %-20s %-18d %d\n", 'a' + i, part->vp_type,
 		       parttype(part), part->vp_begin, part->vp_size);
 	}
-	printf("--- FOUND %d PARTITIONS ---\n", nparts);
-	printf("root at %c\n", 'a' + vp->vh_root);
-	printf("swap at %c\n", 'a' + vp->vh_swap);
+	fprintf(fp, "--- FOUND %d PARTITIONS ---\n", nparts);
+	fprintf(fp, "root at %c\n", 'a' + vp->vh_root);
+	fprintf(fp, "swap at %c\n", 'a' + vp->vh_swap);
 	if (vp->vh_kernel[0] != '\0')
-		printf("boots from %s\n", vp->vh_kernel);
+		fprintf(fp, "boots from %s\n", vp->vh_kernel);
 	else
-		printf("no kernel set\n");
-	dirlist(vp);
+		fprintf(fp, "no kernel set\n");
+	fflush(fp);
 }
 
 static bool
-readlabel(int fd)
+readlabel(struct volhdr *vp, int fd)
 {
 	ssize_t cnt;
 
-	cnt = pread(fd, &label, sizeof label, 0);
-	if (cnt < 0 || (size_t)cnt != sizeof label) {
+	cnt = pread(fd, vp, sizeof *vp, 0);
+	if (cnt < 0 || (size_t)cnt != sizeof *vp) {
 		return (true);
 	} else {
 		return (false);
@@ -443,7 +728,7 @@
 }
 
 static int
-startdisk(const char *disk, int flags)
+startdisk(struct volhdr *vp, const char *disk, int flags)
 {
 	const char *error;
 	int fd;
@@ -451,11 +736,11 @@
 	fd = dkopen(disk, flags);
 	if (fd == -1)
 		err(1, "%s (open)", disk);
-	if (readlabel(fd))
+	if (readlabel(vp, fd))
 		err(1, "%s (label read)", disk);
-	if (goodlabel(&label, &error))
+	if (goodlabel(vp, &error))
 		errx(1, "%s (label check): %s", disk, error);
-	swap_dec_label(&label);
+	swap_dec_label(vp);
 
 	return (fd);
 }
@@ -525,14 +810,11 @@
 }
 
 static bool
-writelabel(int fd)
+writelabel(struct volhdr *vp, int fd)
 {
 	const char *error;
-	struct volhdr *vp;
 	ssize_t cnt;
 
-	vp = &label;
-
 	swap_enc_label(vp);
 	sumlabel(vp);
 	if (goodlabel(vp, &error))
@@ -553,6 +835,7 @@
 "       fxlabel [-d file] disk [...]\n"
 "       fxlabel [-g file] disk [...]\n"
 "       fxlabel [-p] disk [...]\n"
+"       fxlabel [-e] [-s size] disk [...]\n"
 "       fxlabel [-w] [-s size] disk [...]\n");
 	exit(-1);
 }

==== //depot/projects/mips/sys/sys/diskfx.h#7 (text+ko) ====

@@ -32,6 +32,7 @@
 #define	FX_DIRSIZE	15
 #define	FX_NPARTS	16
 #define	FX_VOLHDRPART	8
+#define	FX_VOLPART	9
 #define	FX_NAMELEN	8
 
 static const char *fx_typename[] = {

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe p4-projects" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200302110048.h1B0mMrs006368>