xref: /freebsd/sbin/bsdlabel/bsdlabel.c (revision 7660b554bc59a07be0431c17e0e33815818baa69)
1 /*
2  * Copyright (c) 1994, 1995 Gordon W. Ross
3  * Copyright (c) 1994 Theo de Raadt
4  * All rights reserved.
5  * Copyright (c) 1987, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Symmetric Computer Systems.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by the University of
22  *	California, Berkeley and its contributors.
23  *      This product includes software developed by Theo de Raadt.
24  * 4. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
41  */
42 
43 #if 0
44 #ifndef lint
45 static const char copyright[] =
46 "@(#) Copyright (c) 1987, 1993\n\
47 	The Regents of the University of California.  All rights reserved.\n";
48 #endif /* not lint */
49 
50 #ifndef lint
51 static char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
52 /* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
53 #endif /* not lint */
54 #endif
55 #include <sys/cdefs.h>
56 __FBSDID("$FreeBSD$");
57 
58 #include <sys/param.h>
59 #include <stdint.h>
60 #include <sys/file.h>
61 #include <sys/stat.h>
62 #include <sys/wait.h>
63 #include <sys/disk.h>
64 #define DKTYPENAMES
65 #define FSTYPENAMES
66 #include <sys/disklabel.h>
67 
68 #include <unistd.h>
69 #include <string.h>
70 #include <stdio.h>
71 #include <libgeom.h>
72 #include <stdlib.h>
73 #include <signal.h>
74 #include <stdarg.h>
75 #include <ctype.h>
76 #include <err.h>
77 #include <errno.h>
78 
79 #include "pathnames.h"
80 
81 /* FIX!  These are too low, but are traditional */
82 #define DEFAULT_NEWFS_BLOCK  8192U
83 #define DEFAULT_NEWFS_FRAG   1024U
84 #define DEFAULT_NEWFS_CPG    16U
85 
86 #define BIG_NEWFS_BLOCK  16384U
87 #define BIG_NEWFS_FRAG   2048U
88 #define BIG_NEWFS_CPG    64U
89 
90 static void	makelabel(const char *, struct disklabel *);
91 static int	writelabel(void);
92 static int readlabel(int flag);
93 static void	display(FILE *, const struct disklabel *);
94 static int edit(void);
95 static int	editit(void);
96 static char	*skip(char *);
97 static char	*word(char *);
98 static int	getasciilabel(FILE *, struct disklabel *);
99 static int	getasciipartspec(char *, struct disklabel *, int, int);
100 static int	checklabel(struct disklabel *);
101 static void	usage(void);
102 static struct disklabel *getvirginlabel(void);
103 
104 #define	DEFEDITOR	_PATH_VI
105 
106 static char	*dkname;
107 static char	*specname;
108 static char	tmpfil[] = PATH_TMPFILE;
109 
110 static struct	disklabel lab;
111 static u_char	bootarea[BBSIZE];
112 static off_t	mediasize;
113 static u_int	secsize;
114 static char	blank[] = "";
115 static char	unknown[] = "unknown";
116 
117 #define MAX_PART ('z')
118 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
119 static char    part_size_type[MAX_NUM_PARTS];
120 static char    part_offset_type[MAX_NUM_PARTS];
121 static int     part_set[MAX_NUM_PARTS];
122 
123 static int	installboot;	/* non-zero if we should install a boot program */
124 static int	allfields;	/* present all fields in edit */
125 static char const *xxboot;	/* primary boot */
126 
127 static off_t mbroffset;
128 #ifndef LABELSECTOR
129 #define LABELSECTOR -1
130 #endif
131 #ifndef LABELOFFSET
132 #define LABELOFFSET -1
133 #endif
134 static int labelsoffset = LABELSECTOR;
135 static int labeloffset = LABELOFFSET;
136 static int bbsize = BBSIZE;
137 static int alphacksum =
138 #if defined(__alpha__)
139 	1;
140 #else
141 	0;
142 #endif
143 
144 enum	{
145 	UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
146 } op = UNSPEC;
147 
148 
149 static int	disable_write;   /* set to disable writing to disk label */
150 
151 int
152 main(int argc, char *argv[])
153 {
154 	FILE *t;
155 	int ch, error = 0;
156 	char const *name = 0;
157 
158 	while ((ch = getopt(argc, argv, "ABb:em:nRrs:w")) != -1)
159 		switch (ch) {
160 			case 'A':
161 				allfields = 1;
162 				break;
163 			case 'B':
164 				++installboot;
165 				break;
166 			case 'b':
167 				xxboot = optarg;
168 				break;
169 			case 'm':
170 				if (!strcmp(optarg, "i386") ||
171 				    !strcmp(optarg, "amd64") ||
172 				    !strcmp(optarg, "ia64") ||
173 				    !strcmp(optarg, "pc98")) {
174 					labelsoffset = 1;
175 					labeloffset = 0;
176 					bbsize = 8192;
177 					alphacksum = 0;
178 				} else if (!strcmp(optarg, "alpha")) {
179 					labelsoffset = 0;
180 					labeloffset = 64;
181 					bbsize = 8192;
182 					alphacksum = 1;
183 				} else {
184 					errx(1, "Unsupported architecture");
185 				}
186 				break;
187 			case 'n':
188 				disable_write = 1;
189 				break;
190 			case 'R':
191 				if (op != UNSPEC)
192 					usage();
193 				op = RESTORE;
194 				break;
195 			case 'e':
196 				if (op != UNSPEC)
197 					usage();
198 				op = EDIT;
199 				break;
200 			case 'r':
201 				/*
202 				 * We accept and ignode -r for compatibility with
203 				 * historically disklabel usage.
204 				 */
205 				break;
206 			case 'w':
207 				if (op != UNSPEC)
208 					usage();
209 				op = WRITE;
210 				break;
211 			case '?':
212 			default:
213 				usage();
214 		}
215 	argc -= optind;
216 	argv += optind;
217 
218 	if (argc < 1)
219 		usage();
220 	if (labelsoffset < 0 || labeloffset < 0)
221 		errx(1, "a -m <architecture> option must be specified");
222 
223 	/* Figure out the names of the thing we're working on */
224 	if (argv[0][0] != '/') {
225 		dkname = argv[0];
226 		asprintf(&specname, "%s%s", _PATH_DEV, argv[0]);
227 	} else {
228 		dkname = strrchr(argv[0], '/');
229 		dkname++;
230 		specname = argv[0];
231 	}
232 
233 	if (installboot && op == UNSPEC)
234 		op = WRITEBOOT;
235 	else if (op == UNSPEC)
236 		op = READ;
237 
238 	switch(op) {
239 
240 	case UNSPEC:
241 		break;
242 
243 	case EDIT:
244 		if (argc != 1)
245 			usage();
246 		readlabel(1);
247 		error = edit();
248 		break;
249 
250 	case READ:
251 		if (argc != 1)
252 			usage();
253 		readlabel(1);
254 		display(stdout, NULL);
255 		error = checklabel(NULL);
256 		break;
257 
258 	case RESTORE:
259 		if (argc != 2)
260 			usage();
261 		if (!(t = fopen(argv[1], "r")))
262 			err(4, "fopen %s", argv[1]);
263 		readlabel(0);
264 		if (!getasciilabel(t, &lab))
265 			exit(1);
266 		error = writelabel();
267 		break;
268 
269 	case WRITE:
270 		if (argc == 2)
271 			name = argv[1];
272 		else if (argc == 1)
273 			name = "auto";
274 		else
275 			usage();
276 		readlabel(0);
277 		makelabel(name, &lab);
278 		if (checklabel(NULL) == 0)
279 			error = writelabel();
280 		break;
281 
282 	case WRITEBOOT:
283 
284 		readlabel(1);
285 		if (argc == 2)
286 			makelabel(argv[1], &lab);
287 		if (checklabel(NULL) == 0)
288 			error = writelabel();
289 		break;
290 	}
291 	exit(error);
292 }
293 
294 /*
295  * Construct a prototype disklabel from /etc/disktab.
296  */
297 static void
298 makelabel(const char *type, struct disklabel *lp)
299 {
300 	struct disklabel *dp;
301 
302 	if (strcmp(type, "auto") == 0)
303 		dp = getvirginlabel();
304 	else
305 		dp = getdiskbyname(type);
306 	if (dp == NULL)
307 		errx(1, "%s: unknown disk type", type);
308 	*lp = *dp;
309 	bzero(lp->d_packname, sizeof(lp->d_packname));
310 }
311 
312 static void
313 readboot(void)
314 {
315 	int fd, i;
316 	struct stat st;
317 
318 	if (xxboot == NULL)
319 		xxboot = "/boot/boot";
320 	fd = open(xxboot, O_RDONLY);
321 	if (fd < 0)
322 		err(1, "cannot open %s", xxboot);
323 	fstat(fd, &st);
324 	if (alphacksum && st.st_size <= BBSIZE - 512) {
325 		i = read(fd, bootarea + 512, st.st_size);
326 		if (i != st.st_size)
327 			err(1, "read error %s", xxboot);
328 		return;
329 	} else if ((!alphacksum) && st.st_size <= BBSIZE) {
330 		i = read(fd, bootarea, st.st_size);
331 		if (i != st.st_size)
332 			err(1, "read error %s", xxboot);
333 		return;
334 	}
335 	errx(1, "boot code %s is wrong size", xxboot);
336 }
337 
338 static int
339 writelabel(void)
340 {
341 	uint64_t *p, sum;
342 	int i, fd;
343 	struct gctl_req *grq;
344 	char const *errstr;
345 	struct disklabel *lp = &lab;
346 
347 	if (disable_write) {
348 		warnx("write to disk label supressed - label was as follows:");
349 		display(stdout, NULL);
350 		return (0);
351 	}
352 
353 	lp->d_magic = DISKMAGIC;
354 	lp->d_magic2 = DISKMAGIC;
355 	lp->d_checksum = 0;
356 	lp->d_checksum = dkcksum(lp);
357 	if (installboot)
358 		readboot();
359 	for (i = 0; i < lab.d_npartitions; i++)
360 		if (lab.d_partitions[i].p_size)
361 			lab.d_partitions[i].p_offset += mbroffset;
362 	bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize,
363 	    lp);
364 	if (alphacksum) {
365 		/* Generate the bootblock checksum for the SRM console.  */
366 		for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++)
367 			sum += p[i];
368 		p[63] = sum;
369 	}
370 
371 	fd = open(specname, O_RDWR);
372 	if (fd < 0) {
373 		grq = gctl_get_handle();
374 		gctl_ro_param(grq, "verb", -1, "write label");
375 		gctl_ro_param(grq, "class", -1, "BSD");
376 		gctl_ro_param(grq, "geom", -1, dkname);
377 		gctl_ro_param(grq, "label", 148+16*8,
378 			bootarea + labeloffset + labelsoffset * secsize);
379 		errstr = gctl_issue(grq);
380 		if (errstr != NULL) {
381 			warnx("%s", errstr);
382 			gctl_free(grq);
383 			return(1);
384 		}
385 		gctl_free(grq);
386 		if (installboot) {
387 			grq = gctl_get_handle();
388 			gctl_ro_param(grq, "verb", -1, "write bootcode");
389 			gctl_ro_param(grq, "class", -1, "BSD");
390 			gctl_ro_param(grq, "geom", -1, dkname);
391 			gctl_ro_param(grq, "bootcode", BBSIZE, bootarea);
392 			errstr = gctl_issue(grq);
393 			if (errstr != NULL) {
394 				warnx("%s", errstr);
395 				gctl_free(grq);
396 				return (1);
397 			}
398 			gctl_free(grq);
399 		}
400 	} else {
401 		if (write(fd, bootarea, bbsize) != bbsize) {
402 			warn("write %s", specname);
403 			close (fd);
404 			return (1);
405 		}
406 		close (fd);
407 	}
408 	return (0);
409 }
410 
411 /*
412  * Fetch disklabel for disk.
413  * Use ioctl to get label unless -r flag is given.
414  */
415 static int
416 readlabel(int flag)
417 {
418 	int f, i;
419 	int error;
420 	struct gctl_req *grq;
421 	char const *errstr;
422 
423 	f = open(specname, O_RDONLY);
424 	if (f < 0)
425 		err(1, specname);
426 	/* New world order */
427 	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
428 	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
429 		err(4, "cannot get disk geometry");
430 	}
431 	(void)lseek(f, (off_t)0, SEEK_SET);
432 	if (read(f, bootarea, BBSIZE) != BBSIZE)
433 		err(4, "%s read", specname);
434 	close (f);
435 	error = bsd_disklabel_le_dec(
436 	    bootarea + (labeloffset + labelsoffset * secsize),
437 	    &lab, MAXPARTITIONS);
438 	if (flag && error)
439 		errx(1, "%s: no valid label found", specname);
440 
441 	grq = gctl_get_handle();
442 	gctl_ro_param(grq, "verb", -1, "read mbroffset");
443 	gctl_ro_param(grq, "class", -1, "BSD");
444 	gctl_ro_param(grq, "geom", -1, dkname);
445 	gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset);
446 	errstr = gctl_issue(grq);
447 	if (errstr != NULL) {
448 		mbroffset = 0;
449 		gctl_free(grq);
450 		return (error);
451 	}
452 	mbroffset /= lab.d_secsize;
453 	if (lab.d_partitions[RAW_PART].p_offset == mbroffset)
454 		for (i = 0; i < lab.d_npartitions; i++)
455 			if (lab.d_partitions[i].p_size)
456 				lab.d_partitions[i].p_offset -= mbroffset;
457 	return (error);
458 }
459 
460 
461 static void
462 display(FILE *f, const struct disklabel *lp)
463 {
464 	int i, j;
465 	const struct partition *pp;
466 
467 	if (lp == NULL)
468 		lp = &lab;
469 
470 	fprintf(f, "# %s:\n", specname);
471 	if (allfields) {
472 		if (lp->d_type < DKMAXTYPES)
473 			fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
474 		else
475 			fprintf(f, "type: %u\n", lp->d_type);
476 		fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
477 			lp->d_typename);
478 		fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
479 			lp->d_packname);
480 		fprintf(f, "flags:");
481 		if (lp->d_flags & D_REMOVABLE)
482 			fprintf(f, " removeable");
483 		if (lp->d_flags & D_ECC)
484 			fprintf(f, " ecc");
485 		if (lp->d_flags & D_BADSECT)
486 			fprintf(f, " badsect");
487 		fprintf(f, "\n");
488 		fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
489 		fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
490 		fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
491 		fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
492 		fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
493 		fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
494 		fprintf(f, "rpm: %u\n", lp->d_rpm);
495 		fprintf(f, "interleave: %u\n", lp->d_interleave);
496 		fprintf(f, "trackskew: %u\n", lp->d_trackskew);
497 		fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
498 		fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
499 		    (u_long)lp->d_headswitch);
500 		fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
501 		    (u_long)lp->d_trkseek);
502 		fprintf(f, "drivedata: ");
503 		for (i = NDDATA - 1; i >= 0; i--)
504 			if (lp->d_drivedata[i])
505 				break;
506 		if (i < 0)
507 			i = 0;
508 		for (j = 0; j <= i; j++)
509 			fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
510 		fprintf(f, "\n\n");
511 	}
512 	fprintf(f, "%u partitions:\n", lp->d_npartitions);
513 	fprintf(f,
514 	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
515 	pp = lp->d_partitions;
516 	for (i = 0; i < lp->d_npartitions; i++, pp++) {
517 		if (pp->p_size) {
518 			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
519 			   (u_long)pp->p_size, (u_long)pp->p_offset);
520 			if (pp->p_fstype < FSMAXTYPES)
521 				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
522 			else
523 				fprintf(f, "%8d", pp->p_fstype);
524 			switch (pp->p_fstype) {
525 
526 			case FS_UNUSED:				/* XXX */
527 				fprintf(f, "    %5lu %5lu %5.5s ",
528 				    (u_long)pp->p_fsize,
529 				    (u_long)(pp->p_fsize * pp->p_frag), "");
530 				break;
531 
532 			case FS_BSDFFS:
533 				fprintf(f, "    %5lu %5lu %5u ",
534 				    (u_long)pp->p_fsize,
535 				    (u_long)(pp->p_fsize * pp->p_frag),
536 				    pp->p_cpg);
537 				break;
538 
539 			case FS_BSDLFS:
540 				fprintf(f, "    %5lu %5lu %5d",
541 				    (u_long)pp->p_fsize,
542 				    (u_long)(pp->p_fsize * pp->p_frag),
543 				    pp->p_cpg);
544 				break;
545 
546 			default:
547 				fprintf(f, "%20.20s", "");
548 				break;
549 			}
550 			if (i == RAW_PART) {
551 				fprintf(f, "  # \"raw\" part, don't edit");
552 			}
553 			fprintf(f, "\n");
554 		}
555 	}
556 	fflush(f);
557 }
558 
559 static int
560 edit(void)
561 {
562 	int c, fd;
563 	struct disklabel label;
564 	FILE *fp;
565 
566 	if ((fd = mkstemp(tmpfil)) == -1 ||
567 	    (fp = fdopen(fd, "w")) == NULL) {
568 		warnx("can't create %s", tmpfil);
569 		return (1);
570 	}
571 	display(fp, NULL);
572 	fclose(fp);
573 	for (;;) {
574 		if (!editit())
575 			break;
576 		fp = fopen(tmpfil, "r");
577 		if (fp == NULL) {
578 			warnx("can't reopen %s for reading", tmpfil);
579 			break;
580 		}
581 		bzero((char *)&label, sizeof(label));
582 		c = getasciilabel(fp, &label);
583 		fclose(fp);
584 		if (c) {
585 			lab = label;
586 			if (writelabel() == 0) {
587 				(void) unlink(tmpfil);
588 				return (0);
589 			}
590 		}
591 		printf("re-edit the label? [y]: ");
592 		fflush(stdout);
593 		c = getchar();
594 		if (c != EOF && c != (int)'\n')
595 			while (getchar() != (int)'\n')
596 				;
597 		if  (c == (int)'n')
598 			break;
599 	}
600 	(void) unlink(tmpfil);
601 	return (1);
602 }
603 
604 static int
605 editit(void)
606 {
607 	int pid, xpid;
608 	int locstat, omask;
609 	const char *ed;
610 
611 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
612 	while ((pid = fork()) < 0) {
613 		if (errno == EPROCLIM) {
614 			warnx("you have too many processes");
615 			return(0);
616 		}
617 		if (errno != EAGAIN) {
618 			warn("fork");
619 			return(0);
620 		}
621 		sleep(1);
622 	}
623 	if (pid == 0) {
624 		sigsetmask(omask);
625 		setgid(getgid());
626 		setuid(getuid());
627 		if ((ed = getenv("EDITOR")) == (char *)0)
628 			ed = DEFEDITOR;
629 		execlp(ed, ed, tmpfil, (char *)0);
630 		err(1, "%s", ed);
631 	}
632 	while ((xpid = wait(&locstat)) >= 0)
633 		if (xpid == pid)
634 			break;
635 	sigsetmask(omask);
636 	return(!locstat);
637 }
638 
639 static char *
640 skip(char *cp)
641 {
642 
643 	while (*cp != '\0' && isspace(*cp))
644 		cp++;
645 	if (*cp == '\0' || *cp == '#')
646 		return (NULL);
647 	return (cp);
648 }
649 
650 static char *
651 word(char *cp)
652 {
653 	char c;
654 
655 	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
656 		cp++;
657 	if ((c = *cp) != '\0') {
658 		*cp++ = '\0';
659 		if (c != '#')
660 			return (skip(cp));
661 	}
662 	return (NULL);
663 }
664 
665 /*
666  * Read an ascii label in from fd f,
667  * in the same format as that put out by display(),
668  * and fill in lp.
669  */
670 static int
671 getasciilabel(FILE *f, struct disklabel *lp)
672 {
673 	char *cp;
674 	const char **cpp;
675 	u_int part;
676 	char *tp, line[BUFSIZ];
677 	u_long v;
678 	int lineno = 0, errors = 0;
679 	int i;
680 
681 	makelabel("auto", lp);
682 	bzero(&part_set, sizeof(part_set));
683 	bzero(&part_size_type, sizeof(part_size_type));
684 	bzero(&part_offset_type, sizeof(part_offset_type));
685 	lp->d_bbsize = BBSIZE;				/* XXX */
686 	lp->d_sbsize = 0;				/* XXX */
687 	while (fgets(line, sizeof(line) - 1, f)) {
688 		lineno++;
689 		if ((cp = index(line,'\n')) != 0)
690 			*cp = '\0';
691 		cp = skip(line);
692 		if (cp == NULL)
693 			continue;
694 		tp = index(cp, ':');
695 		if (tp == NULL) {
696 			fprintf(stderr, "line %d: syntax error\n", lineno);
697 			errors++;
698 			continue;
699 		}
700 		*tp++ = '\0', tp = skip(tp);
701 		if (!strcmp(cp, "type")) {
702 			if (tp == NULL)
703 				tp = unknown;
704 			cpp = dktypenames;
705 			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
706 				if (*cpp && !strcmp(*cpp, tp)) {
707 					lp->d_type = cpp - dktypenames;
708 					break;
709 				}
710 			if (cpp < &dktypenames[DKMAXTYPES])
711 				continue;
712 			v = strtoul(tp, NULL, 10);
713 			if (v >= DKMAXTYPES)
714 				fprintf(stderr, "line %d:%s %lu\n", lineno,
715 				    "Warning, unknown disk type", v);
716 			lp->d_type = v;
717 			continue;
718 		}
719 		if (!strcmp(cp, "flags")) {
720 			for (v = 0; (cp = tp) && *cp != '\0';) {
721 				tp = word(cp);
722 				if (!strcmp(cp, "removeable"))
723 					v |= D_REMOVABLE;
724 				else if (!strcmp(cp, "ecc"))
725 					v |= D_ECC;
726 				else if (!strcmp(cp, "badsect"))
727 					v |= D_BADSECT;
728 				else {
729 					fprintf(stderr,
730 					    "line %d: %s: bad flag\n",
731 					    lineno, cp);
732 					errors++;
733 				}
734 			}
735 			lp->d_flags = v;
736 			continue;
737 		}
738 		if (!strcmp(cp, "drivedata")) {
739 			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
740 				lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
741 				tp = word(cp);
742 			}
743 			continue;
744 		}
745 		if (sscanf(cp, "%lu partitions", &v) == 1) {
746 			if (v == 0 || v > MAXPARTITIONS) {
747 				fprintf(stderr,
748 				    "line %d: bad # of partitions\n", lineno);
749 				lp->d_npartitions = MAXPARTITIONS;
750 				errors++;
751 			} else
752 				lp->d_npartitions = v;
753 			continue;
754 		}
755 		if (tp == NULL)
756 			tp = blank;
757 		if (!strcmp(cp, "disk")) {
758 			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
759 			continue;
760 		}
761 		if (!strcmp(cp, "label")) {
762 			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
763 			continue;
764 		}
765 		if (!strcmp(cp, "bytes/sector")) {
766 			v = strtoul(tp, NULL, 10);
767 			if (v == 0 || (v % DEV_BSIZE) != 0) {
768 				fprintf(stderr,
769 				    "line %d: %s: bad sector size\n",
770 				    lineno, tp);
771 				errors++;
772 			} else
773 				lp->d_secsize = v;
774 			continue;
775 		}
776 		if (!strcmp(cp, "sectors/track")) {
777 			v = strtoul(tp, NULL, 10);
778 #if (ULONG_MAX != 0xffffffffUL)
779 			if (v == 0 || v > 0xffffffff) {
780 #else
781 			if (v == 0) {
782 #endif
783 				fprintf(stderr, "line %d: %s: bad %s\n",
784 				    lineno, tp, cp);
785 				errors++;
786 			} else
787 				lp->d_nsectors = v;
788 			continue;
789 		}
790 		if (!strcmp(cp, "sectors/cylinder")) {
791 			v = strtoul(tp, NULL, 10);
792 			if (v == 0) {
793 				fprintf(stderr, "line %d: %s: bad %s\n",
794 				    lineno, tp, cp);
795 				errors++;
796 			} else
797 				lp->d_secpercyl = v;
798 			continue;
799 		}
800 		if (!strcmp(cp, "tracks/cylinder")) {
801 			v = strtoul(tp, NULL, 10);
802 			if (v == 0) {
803 				fprintf(stderr, "line %d: %s: bad %s\n",
804 				    lineno, tp, cp);
805 				errors++;
806 			} else
807 				lp->d_ntracks = v;
808 			continue;
809 		}
810 		if (!strcmp(cp, "cylinders")) {
811 			v = strtoul(tp, NULL, 10);
812 			if (v == 0) {
813 				fprintf(stderr, "line %d: %s: bad %s\n",
814 				    lineno, tp, cp);
815 				errors++;
816 			} else
817 				lp->d_ncylinders = v;
818 			continue;
819 		}
820 		if (!strcmp(cp, "sectors/unit")) {
821 			v = strtoul(tp, NULL, 10);
822 			if (v == 0) {
823 				fprintf(stderr, "line %d: %s: bad %s\n",
824 				    lineno, tp, cp);
825 				errors++;
826 			} else
827 				lp->d_secperunit = v;
828 			continue;
829 		}
830 		if (!strcmp(cp, "rpm")) {
831 			v = strtoul(tp, NULL, 10);
832 			if (v == 0 || v > USHRT_MAX) {
833 				fprintf(stderr, "line %d: %s: bad %s\n",
834 				    lineno, tp, cp);
835 				errors++;
836 			} else
837 				lp->d_rpm = v;
838 			continue;
839 		}
840 		if (!strcmp(cp, "interleave")) {
841 			v = strtoul(tp, NULL, 10);
842 			if (v == 0 || v > USHRT_MAX) {
843 				fprintf(stderr, "line %d: %s: bad %s\n",
844 				    lineno, tp, cp);
845 				errors++;
846 			} else
847 				lp->d_interleave = v;
848 			continue;
849 		}
850 		if (!strcmp(cp, "trackskew")) {
851 			v = strtoul(tp, NULL, 10);
852 			if (v > USHRT_MAX) {
853 				fprintf(stderr, "line %d: %s: bad %s\n",
854 				    lineno, tp, cp);
855 				errors++;
856 			} else
857 				lp->d_trackskew = v;
858 			continue;
859 		}
860 		if (!strcmp(cp, "cylinderskew")) {
861 			v = strtoul(tp, NULL, 10);
862 			if (v > USHRT_MAX) {
863 				fprintf(stderr, "line %d: %s: bad %s\n",
864 				    lineno, tp, cp);
865 				errors++;
866 			} else
867 				lp->d_cylskew = v;
868 			continue;
869 		}
870 		if (!strcmp(cp, "headswitch")) {
871 			v = strtoul(tp, NULL, 10);
872 			lp->d_headswitch = v;
873 			continue;
874 		}
875 		if (!strcmp(cp, "track-to-track seek")) {
876 			v = strtoul(tp, NULL, 10);
877 			lp->d_trkseek = v;
878 			continue;
879 		}
880 		/* the ':' was removed above */
881 		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
882 			fprintf(stderr,
883 			    "line %d: %s: Unknown disklabel field\n", lineno,
884 			    cp);
885 			errors++;
886 			continue;
887 		}
888 
889 		/* Process a partition specification line. */
890 		part = *cp - 'a';
891 		if (part >= lp->d_npartitions) {
892 			fprintf(stderr,
893 			    "line %d: partition name out of range a-%c: %s\n",
894 			    lineno, 'a' + lp->d_npartitions - 1, cp);
895 			errors++;
896 			continue;
897 		}
898 		part_set[part] = 1;
899 
900 		if (getasciipartspec(tp, lp, part, lineno) != 0) {
901 			errors++;
902 			break;
903 		}
904 	}
905 	errors += checklabel(lp);
906 	return (errors == 0);
907 }
908 
909 #define NXTNUM(n) do { \
910 	if (tp == NULL) { \
911 		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
912 		return (1); \
913 	} else { \
914 		cp = tp, tp = word(cp); \
915 		(n) = strtoul(cp, NULL, 10); \
916 	} \
917 } while (0)
918 
919 /* retain 1 character following number */
920 #define NXTWORD(w,n) do { \
921 	if (tp == NULL) { \
922 		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
923 		return (1); \
924 	} else { \
925 	        char *tmp; \
926 		cp = tp, tp = word(cp); \
927 	        (n) = strtoul(cp, &tmp, 10); \
928 		if (tmp) (w) = *tmp; \
929 	} \
930 } while (0)
931 
932 /*
933  * Read a partition line into partition `part' in the specified disklabel.
934  * Return 0 on success, 1 on failure.
935  */
936 static int
937 getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
938 {
939 	struct partition *pp;
940 	char *cp;
941 	const char **cpp;
942 	u_long v;
943 
944 	pp = &lp->d_partitions[part];
945 	cp = NULL;
946 
947 	v = 0;
948 	NXTWORD(part_size_type[part],v);
949 	if (v == 0 && part_size_type[part] != '*') {
950 		fprintf(stderr,
951 		    "line %d: %s: bad partition size\n", lineno, cp);
952 		return (1);
953 	}
954 	pp->p_size = v;
955 
956 	v = 0;
957 	NXTWORD(part_offset_type[part],v);
958 	if (v == 0 && part_offset_type[part] != '*' &&
959 	    part_offset_type[part] != '\0') {
960 		fprintf(stderr,
961 		    "line %d: %s: bad partition offset\n", lineno, cp);
962 		return (1);
963 	}
964 	pp->p_offset = v;
965 	if (tp == NULL) {
966 		fprintf(stderr, "line %d: missing file system type\n", lineno);
967 		return (1);
968 	}
969 	cp = tp, tp = word(cp);
970 	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
971 		if (*cpp && !strcmp(*cpp, cp))
972 			break;
973 	if (*cpp != NULL) {
974 		pp->p_fstype = cpp - fstypenames;
975 	} else {
976 		if (isdigit(*cp))
977 			v = strtoul(cp, NULL, 10);
978 		else
979 			v = FSMAXTYPES;
980 		if (v >= FSMAXTYPES) {
981 			fprintf(stderr,
982 			    "line %d: Warning, unknown file system type %s\n",
983 			    lineno, cp);
984 			v = FS_UNUSED;
985 		}
986 		pp->p_fstype = v;
987 	}
988 
989 	switch (pp->p_fstype) {
990 	case FS_UNUSED:
991 		/*
992 		 * allow us to accept defaults for
993 		 * fsize/frag/cpg
994 		 */
995 		if (tp) {
996 			NXTNUM(pp->p_fsize);
997 			if (pp->p_fsize == 0)
998 				break;
999 			NXTNUM(v);
1000 			pp->p_frag = v / pp->p_fsize;
1001 		}
1002 		/* else default to 0's */
1003 		break;
1004 
1005 	/* These happen to be the same */
1006 	case FS_BSDFFS:
1007 	case FS_BSDLFS:
1008 		if (tp) {
1009 			NXTNUM(pp->p_fsize);
1010 			if (pp->p_fsize == 0)
1011 				break;
1012 			NXTNUM(v);
1013 			pp->p_frag = v / pp->p_fsize;
1014 			NXTNUM(pp->p_cpg);
1015 		} else {
1016 			/*
1017 			 * FIX! poor attempt at adaptive
1018 			 */
1019 			/* 1 GB */
1020 			if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
1021 				/*
1022 				 * FIX! These are too low, but are traditional
1023 				 */
1024 				pp->p_fsize = DEFAULT_NEWFS_FRAG;
1025 				pp->p_frag = DEFAULT_NEWFS_BLOCK /
1026 				    DEFAULT_NEWFS_FRAG;
1027 				pp->p_cpg = DEFAULT_NEWFS_CPG;
1028 			} else {
1029 				pp->p_fsize = BIG_NEWFS_FRAG;
1030 				pp->p_frag = BIG_NEWFS_BLOCK /
1031 				    BIG_NEWFS_FRAG;
1032 				pp->p_cpg = BIG_NEWFS_CPG;
1033 			}
1034 		}
1035 	default:
1036 		break;
1037 	}
1038 	return (0);
1039 }
1040 
1041 /*
1042  * Check disklabel for errors and fill in
1043  * derived fields according to supplied values.
1044  */
1045 static int
1046 checklabel(struct disklabel *lp)
1047 {
1048 	struct partition *pp;
1049 	int i, errors = 0;
1050 	char part;
1051 	u_long total_size, total_percent, current_offset;
1052 	int seen_default_offset;
1053 	int hog_part;
1054 	int j;
1055 	struct partition *pp2;
1056 
1057 	if (lp == NULL)
1058 		lp = &lab;
1059 
1060 	if (allfields) {
1061 
1062 		if (lp->d_secsize == 0) {
1063 			fprintf(stderr, "sector size 0\n");
1064 			return (1);
1065 		}
1066 		if (lp->d_nsectors == 0) {
1067 			fprintf(stderr, "sectors/track 0\n");
1068 			return (1);
1069 		}
1070 		if (lp->d_ntracks == 0) {
1071 			fprintf(stderr, "tracks/cylinder 0\n");
1072 			return (1);
1073 		}
1074 		if  (lp->d_ncylinders == 0) {
1075 			fprintf(stderr, "cylinders/unit 0\n");
1076 			errors++;
1077 		}
1078 		if (lp->d_rpm == 0)
1079 			warnx("revolutions/minute 0");
1080 		if (lp->d_secpercyl == 0)
1081 			lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1082 		if (lp->d_secperunit == 0)
1083 			lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1084 		if (lp->d_bbsize == 0) {
1085 			fprintf(stderr, "boot block size 0\n");
1086 			errors++;
1087 		} else if (lp->d_bbsize % lp->d_secsize)
1088 			warnx("boot block size %% sector-size != 0");
1089 		if (lp->d_npartitions > MAXPARTITIONS)
1090 			warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
1091 			    (u_long)lp->d_npartitions, MAXPARTITIONS);
1092 	} else {
1093 		struct disklabel *vl;
1094 
1095 		vl = getvirginlabel();
1096 		lp->d_secsize = vl->d_secsize;
1097 		lp->d_nsectors = vl->d_nsectors;
1098 		lp->d_ntracks = vl->d_ntracks;
1099 		lp->d_ncylinders = vl->d_ncylinders;
1100 		lp->d_rpm = vl->d_rpm;
1101 		lp->d_interleave = vl->d_interleave;
1102 		lp->d_secpercyl = vl->d_secpercyl;
1103 		lp->d_secperunit = vl->d_secperunit;
1104 		lp->d_bbsize = vl->d_bbsize;
1105 		lp->d_npartitions = vl->d_npartitions;
1106 	}
1107 
1108 
1109 	/* first allocate space to the partitions, then offsets */
1110 	total_size = 0; /* in sectors */
1111 	total_percent = 0; /* in percent */
1112 	hog_part = -1;
1113 	/* find all fixed partitions */
1114 	for (i = 0; i < lp->d_npartitions; i++) {
1115 		pp = &lp->d_partitions[i];
1116 		if (part_set[i]) {
1117 			if (part_size_type[i] == '*') {
1118 				if (i == RAW_PART) {
1119 					pp->p_size = lp->d_secperunit;
1120 				} else {
1121 					if (hog_part != -1)
1122 						warnx("Too many '*' partitions (%c and %c)",
1123 						    hog_part + 'a',i + 'a');
1124 					else
1125 						hog_part = i;
1126 				}
1127 			} else {
1128 				off_t size;
1129 
1130 				size = pp->p_size;
1131 				switch (part_size_type[i]) {
1132 				case '%':
1133 					total_percent += size;
1134 					break;
1135 				case 'k':
1136 				case 'K':
1137 					size *= 1024ULL;
1138 					break;
1139 				case 'm':
1140 				case 'M':
1141 					size *= 1024ULL * 1024ULL;
1142 					break;
1143 				case 'g':
1144 				case 'G':
1145 					size *= 1024ULL * 1024ULL * 1024ULL;
1146 					break;
1147 				case '\0':
1148 					break;
1149 				default:
1150 					warnx("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1151 					break;
1152 				}
1153 				/* don't count %'s yet */
1154 				if (part_size_type[i] != '%') {
1155 					/*
1156 					 * for all not in sectors, convert to
1157 					 * sectors
1158 					 */
1159 					if (part_size_type[i] != '\0') {
1160 						if (size % lp->d_secsize != 0)
1161 							warnx("partition %c not an integer number of sectors",
1162 							    i + 'a');
1163 						size /= lp->d_secsize;
1164 						pp->p_size = size;
1165 					}
1166 					/* else already in sectors */
1167 					if (i != RAW_PART)
1168 						total_size += size;
1169 				}
1170 			}
1171 		}
1172 	}
1173 	/* handle % partitions - note %'s don't need to add up to 100! */
1174 	if (total_percent != 0) {
1175 		long free_space = lp->d_secperunit - total_size;
1176 		if (total_percent > 100) {
1177 			fprintf(stderr,"total percentage %lu is greater than 100\n",
1178 			    total_percent);
1179 			errors++;
1180 		}
1181 
1182 		if (free_space > 0) {
1183 			for (i = 0; i < lp->d_npartitions; i++) {
1184 				pp = &lp->d_partitions[i];
1185 				if (part_set[i] && part_size_type[i] == '%') {
1186 					/* careful of overflows! and integer roundoff */
1187 					pp->p_size = ((double)pp->p_size/100) * free_space;
1188 					total_size += pp->p_size;
1189 
1190 					/* FIX we can lose a sector or so due to roundoff per
1191 					   partition.  A more complex algorithm could avoid that */
1192 				}
1193 			}
1194 		} else {
1195 			fprintf(stderr,
1196 			    "%ld sectors available to give to '*' and '%%' partitions\n",
1197 			    free_space);
1198 			errors++;
1199 			/* fix?  set all % partitions to size 0? */
1200 		}
1201 	}
1202 	/* give anything remaining to the hog partition */
1203 	if (hog_part != -1) {
1204 		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1205 		total_size = lp->d_secperunit;
1206 	}
1207 
1208 	/* Now set the offsets for each partition */
1209 	current_offset = 0; /* in sectors */
1210 	seen_default_offset = 0;
1211 	for (i = 0; i < lp->d_npartitions; i++) {
1212 		part = 'a' + i;
1213 		pp = &lp->d_partitions[i];
1214 		if (part_set[i]) {
1215 			if (part_offset_type[i] == '*') {
1216 				if (i == RAW_PART) {
1217 					pp->p_offset = 0;
1218 				} else {
1219 					pp->p_offset = current_offset;
1220 					seen_default_offset = 1;
1221 				}
1222 			} else {
1223 				/* allow them to be out of order for old-style tables */
1224 				if (pp->p_offset < current_offset &&
1225 				    seen_default_offset && i != RAW_PART &&
1226 				    pp->p_fstype != FS_VINUM) {
1227 					fprintf(stderr,
1228 "Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1229 					    (long)pp->p_offset,i+'a',current_offset);
1230 					fprintf(stderr,
1231 "Labels with any *'s for offset must be in ascending order by sector\n");
1232 					errors++;
1233 				} else if (pp->p_offset != current_offset &&
1234 				    i != RAW_PART && seen_default_offset) {
1235 					/*
1236 					 * this may give unneeded warnings if
1237 					 * partitions are out-of-order
1238 					 */
1239 					warnx(
1240 "Offset %ld for partition %c doesn't match expected value %ld",
1241 					    (long)pp->p_offset, i + 'a', current_offset);
1242 				}
1243 			}
1244 			if (i != RAW_PART)
1245 				current_offset = pp->p_offset + pp->p_size;
1246 		}
1247 	}
1248 
1249 	for (i = 0; i < lp->d_npartitions; i++) {
1250 		part = 'a' + i;
1251 		pp = &lp->d_partitions[i];
1252 		if (pp->p_size == 0 && pp->p_offset != 0)
1253 			warnx("partition %c: size 0, but offset %lu",
1254 			    part, (u_long)pp->p_offset);
1255 #ifdef notdef
1256 		if (pp->p_size % lp->d_secpercyl)
1257 			warnx("partition %c: size %% cylinder-size != 0",
1258 			    part);
1259 		if (pp->p_offset % lp->d_secpercyl)
1260 			warnx("partition %c: offset %% cylinder-size != 0",
1261 			    part);
1262 #endif
1263 		if (pp->p_offset > lp->d_secperunit) {
1264 			fprintf(stderr,
1265 			    "partition %c: offset past end of unit\n", part);
1266 			errors++;
1267 		}
1268 		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1269 			fprintf(stderr,
1270 			"partition %c: partition extends past end of unit\n",
1271 			    part);
1272 			errors++;
1273 		}
1274 		if (i == RAW_PART) {
1275 			if (pp->p_fstype != FS_UNUSED)
1276 				warnx("partition %c is not marked as unused!",part);
1277 			if (pp->p_offset != 0)
1278 				warnx("partition %c doesn't start at 0!",part);
1279 			if (pp->p_size != lp->d_secperunit)
1280 				warnx("partition %c doesn't cover the whole unit!",part);
1281 
1282 			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1283 			    (pp->p_size != lp->d_secperunit)) {
1284 				warnx("An incorrect partition %c may cause problems for "
1285 				    "standard system utilities",part);
1286 			}
1287 		}
1288 
1289 		/* check for overlaps */
1290 		/* this will check for all possible overlaps once and only once */
1291 		for (j = 0; j < i; j++) {
1292 			pp2 = &lp->d_partitions[j];
1293 			if (j != RAW_PART && i != RAW_PART &&
1294 			    pp->p_fstype != FS_VINUM &&
1295 			    pp2->p_fstype != FS_VINUM &&
1296 			    part_set[i] && part_set[j]) {
1297 				if (pp2->p_offset < pp->p_offset + pp->p_size &&
1298 				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
1299 					pp2->p_offset >= pp->p_offset)) {
1300 					fprintf(stderr,"partitions %c and %c overlap!\n",
1301 					    j + 'a', i + 'a');
1302 					errors++;
1303 				}
1304 			}
1305 		}
1306 	}
1307 	for (; i < MAXPARTITIONS; i++) {
1308 		part = 'a' + i;
1309 		pp = &lp->d_partitions[i];
1310 		if (pp->p_size || pp->p_offset)
1311 			warnx("unused partition %c: size %d offset %lu",
1312 			    'a' + i, pp->p_size, (u_long)pp->p_offset);
1313 	}
1314 	return (errors);
1315 }
1316 
1317 /*
1318  * When operating on a "virgin" disk, try getting an initial label
1319  * from the associated device driver.  This might work for all device
1320  * drivers that are able to fetch some initial device parameters
1321  * without even having access to a (BSD) disklabel, like SCSI disks,
1322  * most IDE drives, or vn devices.
1323  *
1324  * The device name must be given in its "canonical" form.
1325  */
1326 static struct disklabel *
1327 getvirginlabel(void)
1328 {
1329 	static struct disklabel loclab;
1330 	struct partition *dp;
1331 	int f;
1332 	u_int u;
1333 
1334 	if ((f = open(specname, O_RDONLY)) == -1) {
1335 		warn("cannot open %s", specname);
1336 		return (NULL);
1337 	}
1338 
1339 	/* New world order */
1340 	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
1341 	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1342 		close (f);
1343 		return (NULL);
1344 	}
1345 	memset(&loclab, 0, sizeof loclab);
1346 	loclab.d_magic = DISKMAGIC;
1347 	loclab.d_magic2 = DISKMAGIC;
1348 	loclab.d_secsize = secsize;
1349 	loclab.d_secperunit = mediasize / secsize;
1350 
1351 	/*
1352 	 * Nobody in these enligthened days uses the CHS geometry for
1353 	 * anything, but nontheless try to get it right.  If we fail
1354 	 * to get any good ideas from the device, construct something
1355 	 * which is IBM-PC friendly.
1356 	 */
1357 	if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1358 		loclab.d_nsectors = u;
1359 	else
1360 		loclab.d_nsectors = 63;
1361 	if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1362 		loclab.d_ntracks = u;
1363 	else if (loclab.d_secperunit <= 63*1*1024)
1364 		loclab.d_ntracks = 1;
1365 	else if (loclab.d_secperunit <= 63*16*1024)
1366 		loclab.d_ntracks = 16;
1367 	else
1368 		loclab.d_ntracks = 255;
1369 	loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1370 	loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1371 	loclab.d_npartitions = MAXPARTITIONS;
1372 
1373 	/* Various (unneeded) compat stuff */
1374 	loclab.d_rpm = 3600;
1375 	loclab.d_bbsize = BBSIZE;
1376 	loclab.d_interleave = 1;
1377 	strncpy(loclab.d_typename, "amnesiac",
1378 	    sizeof(loclab.d_typename));
1379 
1380 	dp = &loclab.d_partitions[0];
1381 	dp->p_offset = BBSIZE / secsize;
1382 	dp->p_size = loclab.d_secperunit - dp->p_offset;
1383 
1384 	dp = &loclab.d_partitions[RAW_PART];
1385 	dp->p_size = loclab.d_secperunit;
1386 	loclab.d_checksum = dkcksum(&loclab);
1387 	close (f);
1388 	return (&loclab);
1389 }
1390 
1391 static void
1392 usage(void)
1393 {
1394 
1395 	fprintf(stderr,
1396 	"%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1397 	"usage: bsdlabel disk",
1398 	"\t\t(to read label)",
1399 	"	bsdlabel -w [-n] [-m machine] disk [type]",
1400 	"\t\t(to write label with existing boot program)",
1401 	"	bsdlabel -e [-n] [-m machine] disk",
1402 	"\t\t(to edit label)",
1403 	"	bsdlabel -R [-n] [-m machine] disk protofile",
1404 	"\t\t(to restore label with existing boot program)",
1405 	"	bsdlabel -B [-b boot] [-m machine] disk",
1406 	"\t\t(to install boot program with existing on-disk label)",
1407 	"	bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]",
1408 	"\t\t(to write label and install boot program)",
1409 	"	bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1410 		"\t\t(to restore label and install boot program)"
1411 	);
1412 	exit(1);
1413 }
1414