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