xref: /csrg-svn/sbin/disklabel/disklabel.c (revision 31401)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)disklabel.c	5.8 (Berkeley) 06/04/87";
9 /* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
10 #endif
11 
12 #include <stdio.h>
13 #include <ctype.h>
14 #include <sys/param.h>
15 #include <sys/signal.h>
16 #include <sys/errno.h>
17 #include <sys/file.h>
18 #include <sys/ioctl.h>
19 #include <sys/fs.h>
20 #include <strings.h>
21 #define DKTYPENAMES
22 #include <sys/disklabel.h>
23 
24 /*
25  * Disklabel: read and write disklabels.
26  * The label is usually placed on one of the first sectors of the disk.
27  * Many machines (VAX 11/750) also place a bootstrap in the same area,
28  * in which case the label is embedded in the bootstrap.
29  * The bootstrap source must leave space at the proper offset
30  * for the label on such machines.
31  */
32 
33 #ifdef vax
34 #define RAWPARTITION	'c'
35 #else
36 #define RAWPARTITION	'a'
37 #endif
38 
39 #ifndef BBSIZE
40 #define	BBSIZE	8192			/* size of boot area, with label */
41 #endif
42 
43 #ifdef vax
44 #define	BOOT				/* also have bootstrap in "boot area" */
45 #define	BOOTDIR	"/usr/mdec"		/* source of boot binaries */
46 #else
47 #ifdef lint
48 #define	BOOT
49 #endif
50 #endif
51 
52 #define	DEFEDITOR	"/usr/ucb/vi"
53 #define	streq(a,b)	(strcmp(a,b) == 0)
54 
55 char	*dkname;
56 #ifdef BOOT
57 char	*xxboot;
58 char	*bootxx;
59 #endif
60 char	*specname;
61 char	tmpfil[] = "/tmp/EdDk.aXXXXXX";
62 char	*sprintf();
63 
64 extern	int errno;
65 char	namebuf[BBSIZE], *np = namebuf;
66 char	bootarea[BBSIZE];
67 struct	disklabel lab;
68 struct	disklabel *readlabel(), *getbootarea();
69 
70 enum	{ READ, WRITE, EDIT, RESTORE } op = READ;
71 
72 int	rflag;
73 
74 main(argc, argv)
75 	int argc;
76 	char *argv[];
77 {
78 	extern int	optind;
79 	register struct disklabel *lp;
80 	FILE	*t;
81 	int	ch, f;
82 	char *name = 0, *type;
83 
84 	while ((ch = getopt(argc, argv, "Rerw")) != EOF)
85 		switch((char)ch) {
86 			case 'R':
87 				op = RESTORE;
88 				break;
89 			case 'e':
90 				op = EDIT;
91 				break;
92 			case 'r':
93 				++rflag;
94 				break;
95 			case 'w':
96 				op = WRITE;
97 				break;
98 			case '?':
99 			default:
100 				usage();
101 		}
102 	argc -= optind;
103 	argv += optind;
104 	if (argc < 1)
105 		usage();
106 
107 	dkname = argv[0];
108 	if (dkname[0] != '/') {
109 		sprintf(np, "/dev/r%s%c", dkname, RAWPARTITION);
110 		specname = np;
111 		np += strlen(specname) + 1;
112 	} else
113 		specname = dkname;
114 	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
115 	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
116 		sprintf(specname, "/dev/r%s", dkname);
117 		np = namebuf + strlen(specname) + 1;
118 		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
119 	}
120 	if (f < 0)
121 		Perror(specname);
122 
123 	switch(op) {
124 	case EDIT:
125 		if (argc != 1)
126 			usage();
127 		lp = readlabel(f, bootarea);
128 		if (edit(lp))
129 			writelabel(f, bootarea, lp);
130 		break;
131 	case READ:
132 		if (argc != 1)
133 			usage();
134 		lp = readlabel(f, (char *)0);
135 		display(stdout, lp);
136 		(void) checklabel(lp);
137 		break;
138 	case RESTORE:
139 #ifdef BOOT
140 		if (argc == 4) {
141 			xxboot = argv[2];
142 			bootxx = argv[3];
143 		}
144 		else
145 #else
146 		if (argc != 2)
147 			usage();
148 #endif
149 		lab.d_secsize = DEV_BSIZE;			/* XXX */
150 		lab.d_bbsize = BBSIZE;				/* XXX */
151 		lp = getbootarea(bootarea, &lab);
152 		if (!(t = fopen(argv[1],"r")))
153 			Perror(argv[1]);
154 #ifdef BOOT
155 		rflag = 1;		/* force bootstrap to be written */
156 #endif
157 		if (getasciilabel(t, lp))
158 			writelabel(f, bootarea, lp);
159 		break;
160 	case WRITE:
161 		type = argv[1];
162 #ifdef BOOT
163 		if (argc > 5 || argc < 2)
164 			usage();
165 		if (argc > 3) {
166 			bootxx = argv[--argc];
167 			xxboot = argv[--argc];
168 		}
169 #else
170 		if (argc > 3 || argc < 2)
171 			usage();
172 #endif
173 		if (argc > 2)
174 			name = argv[--argc];
175 		makelabel(type, name, &lab);
176 		lp = getbootarea(bootarea, &lab);
177 		*lp = lab;
178 #ifdef BOOT
179 		rflag = 1;		/* force bootstrap to be written */
180 #endif
181 		if (checklabel(lp) == 0)
182 			writelabel(f, bootarea, lp);
183 		break;
184 	}
185 	exit(0);
186 }
187 
188 makelabel(type, name, lp)
189 	char *type, *name;
190 	register struct disklabel *lp;
191 {
192 	register struct disklabel *dp;
193 
194 	dp = getdiskbyname(type);
195 	if (dp == NULL) {
196 		fprintf(stderr, "%s: unknown disk type\n", type);
197 		exit(1);
198 	}
199 	*lp = *dp;
200 	if (name)
201 		(void)strncpy(lp->d_name, name, sizeof(lp->d_name));
202 }
203 
204 writelabel(f, boot, lp)
205 	int f;
206 	char *boot;
207 	register struct disklabel *lp;
208 {
209 	register int i;
210 	long	lseek();
211 
212 	lp->d_magic = DISKMAGIC;
213 	lp->d_magic2 = DISKMAGIC;
214 	lp->d_checksum = 0;
215 	lp->d_checksum = dkcksum(lp);
216 	(void)lseek(f, (off_t)0, L_SET);
217 	if (rflag) {
218 		if (write(f, boot, lp->d_bbsize) < lp->d_bbsize)
219 			Perror("write");
220 		if (ioctl(f, DIOCSDINFO, lp) < 0)
221 			Perror("ioctl DIOCSDINFO");
222 	} else if (ioctl(f, DIOCWDINFO, lp) < 0)
223 		Perror("ioctl DIOCWDINFO");
224 #if vax
225 	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
226 		daddr_t alt;
227 
228 		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
229 		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
230 			(void)lseek(f, (off_t)((alt + i) * lp->d_secsize), L_SET);
231 			if (write(f, boot, lp->d_secsize) < lp->d_secsize) {
232 				int oerrno = errno;
233 				fprintf(stderr, "alternate label %d ", i/2);
234 				errno = oerrno;
235 				perror("write");
236 			}
237 		}
238 	}
239 #endif
240 }
241 
242 /*
243  * Read disklabel from disk.
244  * If boot is given, need bootstrap too.
245  * If boot not needed, use ioctl to get label
246  * unless -r flag is given.
247  */
248 struct disklabel *
249 readlabel(f, boot)
250 	int f;
251 	char *boot;
252 {
253 	register struct disklabel *lp;
254 	register char *buf;
255 
256 	if (boot)
257 		buf = boot;
258 	else
259 		buf = bootarea;
260 	lp = (struct disklabel *)(buf + LABELOFFSET);
261 	if (boot || rflag)
262 		if (read(f, buf, BBSIZE) < BBSIZE)
263 			Perror(specname);
264 	if (rflag == 0) {
265 		if (ioctl(f, DIOCGDINFO, lp) < 0)
266 			Perror("ioctl DIOCGDINFO");
267 	} else {
268 		for (lp = (struct disklabel *)buf;
269 		    lp <= (struct disklabel *)(buf + BBSIZE - sizeof(*lp));
270 		    lp = (struct disklabel *)((char *)lp + 16))
271 			if (lp->d_magic == DISKMAGIC &&
272 			    lp->d_magic2 == DISKMAGIC)
273 				break;
274 		if (lp > (struct disklabel *)(buf + BBSIZE - sizeof(*lp)) ||
275 		    lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
276 		    dkcksum(lp) != 0) {
277 			fprintf(stderr,
278 	"Bad pack magic number (label is damaged, or pack is unlabeled)\n");
279 			exit(1);
280 		}
281 	}
282 	return (lp);
283 }
284 
285 struct disklabel *
286 getbootarea(boot, dp)
287 	char *boot;
288 	register struct disklabel *dp;
289 {
290 	struct disklabel *lp;
291 	register char *p;
292 	int b;
293 
294 #ifdef BOOT
295 	char	*dkbasename;
296 
297 	if (xxboot == NULL) {
298 		dkbasename = np;
299 		if ((p = rindex(dkname, '/')) == NULL)
300 			p = dkname;
301 		else
302 			p++;
303 		while (*p && !isdigit(*p))
304 			*np++ = *p++;
305 		*np++ = '\0';
306 
307 		sprintf(np, "%s/%sboot", BOOTDIR, dkbasename);
308 		if (access(np, F_OK) < 0 && dkbasename[0] == 'r')
309 			dkbasename++;
310 		xxboot = np;
311 		sprintf(xxboot, "%s/%sboot", BOOTDIR, dkbasename);
312 		np += strlen(xxboot) + 1;
313 
314 		bootxx = np;
315 		sprintf(bootxx, "%s/boot%s", BOOTDIR, dkbasename);
316 		np += strlen(bootxx) + 1;
317 	}
318 
319 	b = open(xxboot, O_RDONLY);
320 	if (b < 0)
321 		Perror(xxboot);
322 	if (read(b, boot, (int)dp->d_secsize) < 0)
323 		Perror(xxboot);
324 	close(b);
325 	b = open(bootxx, O_RDONLY);
326 	if (b < 0)
327 		Perror(bootxx);
328 	if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0)
329 		Perror(bootxx);
330 	(void)close(b);
331 #endif
332 
333 	lp = (struct disklabel *)(boot + (LABELSECTOR * dp->d_secsize) +
334 	    LABELOFFSET);
335 	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
336 		if (*p) {
337 			fprintf(stderr,
338 			    "Bootstrap doesn't leave room for disk label\n");
339 			exit(2);
340 		}
341 	return (lp);
342 }
343 
344 display(f, lp)
345 	FILE *f;
346 	register struct disklabel *lp;
347 {
348 	register int i, j;
349 	register struct partition *pp;
350 
351 	fprintf(f, "# %s:\n", specname);
352 	if ((unsigned) lp->d_type < DKMAXTYPES)
353 		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
354 	else
355 		fprintf(f, "type: %d\n", lp->d_type);
356 	fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename);
357 	fprintf(f, "label: %.*s\n", sizeof(lp->d_name), lp->d_name);
358 	fprintf(f, "flags:");
359 	if (lp->d_flags & D_REMOVABLE)
360 		fprintf(f, " removeable");
361 	if (lp->d_flags & D_ECC)
362 		fprintf(f, " ecc");
363 	if (lp->d_flags & D_BADSECT)
364 		fprintf(f, " badsect");
365 	fprintf(f, "\n");
366 	fprintf(f, "bytes/sector: %d\n", lp->d_secsize);
367 	fprintf(f, "sectors/track: %d\n", lp->d_nsectors);
368 	fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks);
369 	fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl);
370 	fprintf(f, "cylinders: %d\n", lp->d_ncylinders);
371 	fprintf(f, "rpm: %d\n", lp->d_rpm);
372 	fprintf(f, "interleave: %d\n", lp->d_interleave);
373 	fprintf(f, "trackskew: %d\n", lp->d_trackskew);
374 	fprintf(f, "cylinderskew: %d\n", lp->d_cylskew);
375 	fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch);
376 	fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek);
377 	fprintf(f, "drivedata: ");
378 	for (i = NDDATA - 1; i >= 0; i--)
379 		if (lp->d_drivedata[i])
380 			break;
381 	if (i < 0)
382 		i = 0;
383 	for (j = 0; j <= i; j++)
384 		fprintf(f, "%d ", lp->d_drivedata[j]);
385 	fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions);
386 	fprintf(f,
387 	    "#        size   offset    fstype   [fsize bsize   cpg]\n");
388 	pp = lp->d_partitions;
389 	for (i = 0; i < lp->d_npartitions; i++, pp++) {
390 		if (pp->p_size) {
391 			fprintf(f, "  %c: %8d %8d  ", 'a' + i,
392 			   pp->p_size, pp->p_offset);
393 			if ((unsigned) pp->p_fstype < FSMAXTYPES)
394 				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
395 			else
396 				fprintf(f, "%8d", pp->p_fstype);
397 			switch (pp->p_fstype) {
398 
399 			case FS_UNUSED:				/* XXX */
400 				fprintf(f, "    %5d %5d %5.5s ",
401 				    pp->p_fsize, pp->p_fsize * pp->p_frag, "");
402 				break;
403 
404 			case FS_BSDFFS:
405 				fprintf(f, "    %5d %5d %5d ",
406 				    pp->p_fsize, pp->p_fsize * pp->p_frag,
407 				    pp->p_cpg);
408 				break;
409 
410 			default:
411 				fprintf(f, "%20.20s", "");
412 				break;
413 			}
414 			fprintf(f, "\t# (Cyl. %4d",
415 			    pp->p_offset / lp->d_secpercyl);
416 			if (pp->p_offset % lp->d_secpercyl)
417 			    putc('*', f);
418 			else
419 			    putc(' ', f);
420 			fprintf(f, "- %d",
421 			    (pp->p_offset +
422 			    pp->p_size + lp->d_secpercyl - 1) /
423 			    lp->d_secpercyl - 1);
424 			if (pp->p_size % lp->d_secpercyl)
425 			    putc('*', f);
426 			fprintf(f, ")\n");
427 		}
428 	}
429 }
430 
431 edit(lp)
432 	struct disklabel *lp;
433 {
434 	register int c;
435 	struct disklabel label;
436 	FILE *fd;
437 	char *mktemp();
438 
439 	(void) mktemp(tmpfil);
440 	fd = fopen(tmpfil, "w");
441 	if (fd == NULL) {
442 		fprintf(stderr, "%s: Can't create\n", tmpfil);
443 		return (0);
444 	}
445 	(void)fchmod(fd, 0600);
446 	display(fd, lp);
447 	fclose(fd);
448 	for (;;) {
449 		if (!editit())
450 			break;
451 		fd = fopen(tmpfil, "r");
452 		if (fd == NULL) {
453 			fprintf(stderr, "%s: Can't reopen for reading\n");
454 			break;
455 		}
456 		bzero((char *)&label, sizeof(label));
457 		if (getasciilabel(fd, &label)) {
458 			*lp = label;
459 			(void) unlink(tmpfil);
460 			return (1);
461 		}
462 		printf("re-edit the label? [y]: "); fflush(stdout);
463 		c = getchar();
464 		if (c != EOF && c != (int)'\n')
465 			while (getchar() != (int)'\n')
466 				;
467 		if  (c == (int)'n')
468 			break;
469 	}
470 	(void) unlink(tmpfil);
471 	return (0);
472 }
473 
474 editit()
475 {
476 	register int pid, xpid;
477 	int stat, omask;
478 	extern char *getenv();
479 
480 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
481 	while ((pid = fork()) < 0) {
482 		extern int errno;
483 
484 		if (errno == EPROCLIM) {
485 			fprintf(stderr, "You have too many processes\n");
486 			return(0);
487 		}
488 		if (errno != EAGAIN) {
489 			perror("fork");
490 			return(0);
491 		}
492 		sleep(1);
493 	}
494 	if (pid == 0) {
495 		register char *ed;
496 
497 		sigsetmask(omask);
498 		setgid(getgid());
499 		setuid(getuid());
500 		if ((ed = getenv("EDITOR")) == (char *)0)
501 			ed = DEFEDITOR;
502 		execlp(ed, ed, tmpfil, 0);
503 		perror(ed);
504 		exit(1);
505 	}
506 	while ((xpid = wait(&stat)) >= 0)
507 		if (xpid == pid)
508 			break;
509 	sigsetmask(omask);
510 	return(!stat);
511 }
512 
513 char *
514 skip(cp)
515 	register char *cp;
516 {
517 
518 	while (*cp != '\0' && isspace(*cp))
519 		cp++;
520 	if (*cp == '\0' || *cp == '#')
521 		return ((char *)NULL);
522 	return (cp);
523 }
524 
525 char *
526 word(cp)
527 	register char *cp;
528 {
529 	register char c;
530 
531 	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
532 		cp++;
533 	if ((c = *cp) != '\0') {
534 		*cp++ = '\0';
535 		if (c != '#')
536 			return (skip(cp));
537 	}
538 	return ((char *)NULL);
539 }
540 
541 /*
542  * Read an ascii label in from fd f,
543  * in the same format as that put out by display(),
544  * and fill in lp.
545  */
546 getasciilabel(f, lp)
547 	FILE	*f;
548 	register struct disklabel *lp;
549 {
550 	register char **cpp, *cp;
551 	register struct partition *pp;
552 	char *tp, *s, line[BUFSIZ];
553 	int v, lineno = 0, errors = 0;
554 
555 	lp->d_bbsize = BBSIZE;				/* XXX */
556 	lp->d_sbsize = SBSIZE;				/* XXX */
557 	while (fgets(line, sizeof(line) - 1, f)) {
558 		lineno++;
559 		if (cp = index(line,'\n'))
560 			*cp = '\0';
561 		cp = skip(line);
562 		if (cp == NULL)
563 			continue;
564 		tp = index(cp, ':');
565 		if (tp == NULL) {
566 			fprintf(stderr, "line %d: syntax error\n", lineno);
567 			errors++;
568 			continue;
569 		}
570 		*tp++ = '\0', tp = skip(tp);
571 		if (streq(cp, "type")) {
572 			if (tp == NULL)
573 				tp = "unknown";
574 			cpp = dktypenames;
575 			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
576 				if ((s = *cpp) && streq(s, tp)) {
577 					lp->d_type = cpp - dktypenames;
578 					goto next;
579 				}
580 			v = atoi(tp);
581 			if ((unsigned)v >= DKMAXTYPES)
582 				fprintf(stderr, "line %d:%s %d\n", lineno,
583 				    "Warning, unknown disk type", v);
584 			lp->d_type = v;
585 			continue;
586 		}
587 		if (streq(cp, "flags")) {
588 			for (v = 0; (cp = tp) && *cp != '\0'; tp = word(cp)) {
589 				if (streq(cp, "removeable"))
590 					v |= D_REMOVABLE;
591 				else if (streq(cp, "ecc"))
592 					v |= D_ECC;
593 				else if (streq(cp, "badsect"))
594 					v |= D_BADSECT;
595 				else {
596 					fprintf(stderr,
597 					    "line %d: %s: bad flag\n",
598 					    lineno, cp);
599 					errors++;
600 				}
601 			}
602 			lp->d_flags = v;
603 			continue;
604 		}
605 		if (streq(cp, "drivedata")) {
606 			register int i;
607 
608 			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
609 				lp->d_drivedata[i++] = atoi(cp);
610 				tp = word(cp);
611 			}
612 			continue;
613 		}
614 		if (sscanf(cp, "%d partitions", &v) == 1) {
615 			if (v == 0 || (unsigned)v > MAXPARTITIONS) {
616 				fprintf(stderr,
617 				    "line %d: bad # of partitions\n", lineno);
618 				lp->d_npartitions = MAXPARTITIONS;
619 				errors++;
620 			} else
621 				lp->d_npartitions = v;
622 			continue;
623 		}
624 		if (tp == NULL)
625 			tp = "";
626 		if (streq(cp, "disk")) {
627 			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
628 			continue;
629 		}
630 		if (streq(cp, "label")) {
631 			strncpy(lp->d_name, tp, sizeof (lp->d_name));
632 			continue;
633 		}
634 		if (streq(cp, "bytes/sector")) {
635 			v = atoi(tp);
636 			if (v <= 0 || (v % 512) != 0) {
637 				fprintf(stderr,
638 				    "line %d: %s: bad sector size\n",
639 				    lineno, tp);
640 				errors++;
641 			} else
642 				lp->d_secsize = v;
643 			continue;
644 		}
645 		if (streq(cp, "sectors/track")) {
646 			v = atoi(tp);
647 			if (v <= 0) {
648 				fprintf(stderr, "line %d: %s: bad %s\n",
649 				    lineno, tp, cp);
650 				errors++;
651 			} else
652 				lp->d_nsectors = v;
653 			continue;
654 		}
655 		if (streq(cp, "sectors/cylinder")) {
656 			v = atoi(tp);
657 			if (v <= 0) {
658 				fprintf(stderr, "line %d: %s: bad %s\n",
659 				    lineno, tp, cp);
660 				errors++;
661 			} else
662 				lp->d_secpercyl = v;
663 			continue;
664 		}
665 		if (streq(cp, "tracks/cylinder")) {
666 			v = atoi(tp);
667 			if (v <= 0) {
668 				fprintf(stderr, "line %d: %s: bad %s\n",
669 				    lineno, tp, cp);
670 				errors++;
671 			} else
672 				lp->d_ntracks = v;
673 			continue;
674 		}
675 		if (streq(cp, "cylinders")) {
676 			v = atoi(tp);
677 			if (v <= 0) {
678 				fprintf(stderr, "line %d: %s: bad %s\n",
679 				    lineno, tp, cp);
680 				errors++;
681 			} else
682 				lp->d_ncylinders = v;
683 			continue;
684 		}
685 		if (streq(cp, "rpm")) {
686 			v = atoi(tp);
687 			if (v <= 0) {
688 				fprintf(stderr, "line %d: %s: bad %s\n",
689 				    lineno, tp, cp);
690 				errors++;
691 			} else
692 				lp->d_rpm = v;
693 			continue;
694 		}
695 		if (streq(cp, "interleave")) {
696 			v = atoi(tp);
697 			if (v <= 0) {
698 				fprintf(stderr, "line %d: %s: bad %s\n",
699 				    lineno, tp, cp);
700 				errors++;
701 			} else
702 				lp->d_interleave = v;
703 			continue;
704 		}
705 		if (streq(cp, "trackskew")) {
706 			v = atoi(tp);
707 			if (v < 0) {
708 				fprintf(stderr, "line %d: %s: bad %s\n",
709 				    lineno, tp, cp);
710 				errors++;
711 			} else
712 				lp->d_trackskew = v;
713 			continue;
714 		}
715 		if (streq(cp, "cylinderskew")) {
716 			v = atoi(tp);
717 			if (v < 0) {
718 				fprintf(stderr, "line %d: %s: bad %s\n",
719 				    lineno, tp, cp);
720 				errors++;
721 			} else
722 				lp->d_cylskew = v;
723 			continue;
724 		}
725 		if (streq(cp, "headswitch")) {
726 			v = atoi(tp);
727 			if (v < 0) {
728 				fprintf(stderr, "line %d: %s: bad %s\n",
729 				    lineno, tp, cp);
730 				errors++;
731 			} else
732 				lp->d_headswitch = v;
733 			continue;
734 		}
735 		if (streq(cp, "track-to-track seek")) {
736 			v = atoi(tp);
737 			if (v < 0) {
738 				fprintf(stderr, "line %d: %s: bad %s\n",
739 				    lineno, tp, cp);
740 				errors++;
741 			} else
742 				lp->d_trkseek = v;
743 			continue;
744 		}
745 		if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
746 			unsigned part = *cp - 'a';
747 
748 			if (part > lp->d_npartitions) {
749 				fprintf(stderr,
750 				    "line %d: bad partition name\n", lineno);
751 				errors++;
752 				continue;
753 			}
754 			pp = &lp->d_partitions[part];
755 #define NXTNUM(n) { \
756 	cp = tp, tp = word(cp); \
757 	if (tp == NULL) \
758 		tp = cp; \
759 	(n) = atoi(cp); \
760      }
761 
762 			NXTNUM(v);
763 			if (v < 0) {
764 				fprintf(stderr,
765 				    "line %d: %s: bad partition size\n",
766 				    lineno, cp);
767 				errors++;
768 			} else
769 				pp->p_size = v;
770 			NXTNUM(v);
771 			if (v < 0) {
772 				fprintf(stderr,
773 				    "line %d: %s: bad partition offset\n",
774 				    lineno, cp);
775 				errors++;
776 			} else
777 				pp->p_offset = v;
778 			cp = tp, tp = word(cp);
779 			cpp = fstypenames;
780 			for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
781 				if ((s = *cpp) && streq(s, cp)) {
782 					pp->p_fstype = cpp - fstypenames;
783 					goto gottype;
784 				}
785 			v = atoi(cp);
786 			if ((unsigned)v >= FSMAXTYPES)
787 				fprintf(stderr, "line %d: %s %s\n", lineno,
788 				    "Warning, unknown filesystem type", cp);
789 			pp->p_fstype = v;
790 	gottype:
791 
792 			switch (pp->p_fstype) {
793 
794 			case FS_UNUSED:				/* XXX */
795 				NXTNUM(pp->p_fsize);
796 				if (pp->p_fsize == 0)
797 					break;
798 				NXTNUM(v);
799 				pp->p_frag = v / pp->p_fsize;
800 				break;
801 
802 			case FS_BSDFFS:
803 				NXTNUM(pp->p_fsize);
804 				if (pp->p_fsize == 0)
805 					break;
806 				NXTNUM(v);
807 				pp->p_frag = v / pp->p_fsize;
808 				NXTNUM(pp->p_cpg);
809 				break;
810 
811 			default:
812 				break;
813 			}
814 			continue;
815 		}
816 		fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
817 		    lineno, cp);
818 		errors++;
819 	next:
820 		;
821 	}
822 	errors += checklabel(lp);
823 	return (errors == 0);
824 }
825 
826 /*
827  * Check disklabel for errors and fill in
828  * derived fields according to supplied values.
829  */
830 checklabel(lp)
831 	register struct disklabel *lp;
832 {
833 	register struct partition *pp;
834 	int i, errors = 0;
835 	char part;
836 
837 	if (lp->d_secsize == 0) {
838 		fprintf(stderr, "sector size %d\n", lp->d_secsize);
839 		return (1);
840 	}
841 	if (lp->d_nsectors == 0) {
842 		fprintf(stderr, "sectors/track %d\n", lp->d_nsectors);
843 		return (1);
844 	}
845 	if (lp->d_ntracks == 0) {
846 		fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks);
847 		return (1);
848 	}
849 	if  (lp->d_ncylinders == 0) {
850 		fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders);
851 		errors++;
852 	}
853 	if (lp->d_rpm == 0)
854 		Warning("revolutions/minute %d\n", lp->d_rpm);
855 	if (lp->d_secpercyl == 0)
856 		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
857 	if (lp->d_secperunit == 0)
858 		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
859 	if (lp->d_bbsize == 0) {
860 		fprintf(stderr, "boot block size %d\n", lp->d_bbsize);
861 		errors++;
862 	} else if (lp->d_bbsize % lp->d_secsize)
863 		Warning("boot block size %% sector-size != 0\n");
864 	if (lp->d_sbsize == 0) {
865 		fprintf(stderr, "super block size %d\n", lp->d_sbsize);
866 		errors++;
867 	} else if (lp->d_sbsize % lp->d_secsize)
868 		Warning("super block size %% sector-size != 0\n");
869 	if (lp->d_npartitions > MAXPARTITIONS)
870 		Warning("number of partitions (%d) > MAXPARTITIONS (%d)\n",
871 		    lp->d_npartitions, MAXPARTITIONS);
872 	for (i = 0; i < lp->d_npartitions; i++) {
873 		part = 'a' + i;
874 		pp = &lp->d_partitions[i];
875 		if (pp->p_size == 0 && pp->p_offset != 0)
876 			Warning("partition %c: size 0, but offset %d\n",
877 			    part, pp->p_offset);
878 #ifdef notdef
879 		if (pp->p_size % lp->d_secpercyl)
880 			Warning("partition %c: size %% cylinder-size != 0\n",
881 			    part);
882 		if (pp->p_offset % lp->d_secpercyl)
883 			Warning("partition %c: offset %% cylinder-size != 0\n",
884 			    part);
885 #endif
886 		if (pp->p_offset > lp->d_secperunit) {
887 			fprintf(stderr,
888 			    "partition %c: offset past end of unit\n", part);
889 			errors++;
890 		}
891 		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
892 			fprintf(stderr,
893 			    "partition %c: partition extends past end of unit\n",
894 			    part);
895 			errors++;
896 		}
897 	}
898 	for (; i < MAXPARTITIONS; i++) {
899 		part = 'a' + i;
900 		pp = &lp->d_partitions[i];
901 		if (pp->p_size || pp->p_offset)
902 			Warning("unused partition %c: size %d offset %d\n",
903 			    pp->p_size, pp->p_offset);
904 	}
905 	return (errors);
906 }
907 
908 /*VARARGS1*/
909 Warning(fmt, a1, a2, a3, a4, a5)
910 	char *fmt;
911 {
912 
913 	fprintf(stderr, "Warning, ");
914 	fprintf(stderr, fmt, a1, a2, a3, a4, a5);
915 	fprintf(stderr, "\n");
916 }
917 
918 Perror(str)
919 	char *str;
920 {
921 	fputs("disklabel: ", stderr); perror(str);
922 	exit(4);
923 }
924 
925 usage()
926 {
927 #ifdef BOOT
928 	fprintf(stderr, "%-64s%s\n%-64s%s\n%-64s%s\n%-64s%s\n",
929 "usage: disklabel [-r] disk", "(to read label)",
930 "or disklabel -w [-r] disk type [ packid ] [ xxboot bootxx ]", "(to write label)",
931 "or disklabel -e [-r] disk", "(to edit label)",
932 "or disklabel -R [-r] disk protofile [ xxboot bootxx ]", "(to restore label)");
933 #else
934 	fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n",
935 "usage: disklabel [-r] disk", "(to read label)",
936 "or disklabel -w [-r] disk type [ packid ]", "(to write label)",
937 "or disklabel -e [-r] disk", "(to edit label)",
938 "or disklabel -R [-r] disk protofile", "(to restore label)");
939 #endif
940 	exit(1);
941 }
942