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