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