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