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