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