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