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