bsdlabel.c revision 114574
1167857Simp/*
2167857Simp * Copyright (c) 1994, 1995 Gordon W. Ross
3167857Simp * Copyright (c) 1994 Theo de Raadt
4167857Simp * All rights reserved.
5167857Simp * Copyright (c) 1987, 1993
6167857Simp *	The Regents of the University of California.  All rights reserved.
7167857Simp *
8167857Simp * This code is derived from software contributed to Berkeley by
9167857Simp * Symmetric Computer Systems.
10167857Simp *
11167857Simp * Redistribution and use in source and binary forms, with or without
12167857Simp * modification, are permitted provided that the following conditions
13167857Simp * are met:
14167857Simp * 1. Redistributions of source code must retain the above copyright
15167857Simp *    notice, this list of conditions and the following disclaimer.
16167857Simp * 2. Redistributions in binary form must reproduce the above copyright
17167857Simp *    notice, this list of conditions and the following disclaimer in the
18167857Simp *    documentation and/or other materials provided with the distribution.
19167857Simp * 3. All advertising materials mentioning features or use of this software
20167857Simp *    must display the following acknowledgement:
21167857Simp *	This product includes software developed by the University of
22167857Simp *	California, Berkeley and its contributors.
23167857Simp *      This product includes software developed by Theo de Raadt.
24167857Simp * 4. Neither the name of the University nor the names of its contributors
25167857Simp *    may be used to endorse or promote products derived from this software
26167857Simp *    without specific prior written permission.
27167857Simp *
28167857Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29167857Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30289727Sian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31289727Sian * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32289727Sian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33167857Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34167857Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35167857Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36167857Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37167857Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38167857Simp * SUCH DAMAGE.
39167857Simp *
40181305Sjhb *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
41346548Sian */
42167857Simp
43167857Simp#ifndef lint
44289727Sianstatic const char copyright[] =
45289727Sian"@(#) Copyright (c) 1987, 1993\n\
46289727Sian	The Regents of the University of California.  All rights reserved.\n";
47289727Sian#endif /* not lint */
48289727Sian
49289727Sian#ifndef lint
50167857Simp#if 0
51167857Simpstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
52167857Simp/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
53167857Simp#endif
54167857Simp#endif /* not lint */
55289727Sian
56289727Sian#include <sys/cdefs.h>
57289727Sian__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 114574 2003-05-03 09:58:20Z phk $");
58289727Sian
59289727Sian#include <sys/param.h>
60289727Sian#include <stdint.h>
61167857Simp#include <sys/file.h>
62289727Sian#include <sys/stat.h>
63167857Simp#include <sys/wait.h>
64167857Simp#include <sys/disk.h>
65289727Sian#define DKTYPENAMES
66167857Simp#define FSTYPENAMES
67289727Sian#include <sys/disklabel.h>
68167857Simp
69289727Sian#include <unistd.h>
70167857Simp#include <string.h>
71167857Simp#include <stdio.h>
72167857Simp#include <libgeom.h>
73289727Sian#include <stdlib.h>
74289727Sian#include <signal.h>
75289727Sian#include <stdarg.h>
76289727Sian#include <ctype.h>
77289727Sian#include <err.h>
78289727Sian#include <errno.h>
79289727Sian
80289727Sian#include "pathnames.h"
81289727Sian
82289727Sian/* FIX!  These are too low, but are traditional */
83289727Sian#define DEFAULT_NEWFS_BLOCK  8192U
84289727Sian#define DEFAULT_NEWFS_FRAG   1024U
85289727Sian#define DEFAULT_NEWFS_CPG    16U
86289727Sian
87289727Sian#define BIG_NEWFS_BLOCK  16384U
88289727Sian#define BIG_NEWFS_FRAG   2048U
89289727Sian#define BIG_NEWFS_CPG    64U
90289727Sian
91289727Sianstatic void	makelabel(const char *, struct disklabel *);
92289727Sianstatic int	writelabel(void);
93289727Sianstatic int readlabel(int flag);
94289727Sianstatic void	display(FILE *, const struct disklabel *);
95289727Sianstatic int edit(void);
96289727Sianstatic int	editit(void);
97289727Sianstatic char	*skip(char *);
98289727Sianstatic char	*word(char *);
99289727Sianstatic int	getasciilabel(FILE *, struct disklabel *);
100289727Sianstatic int	getasciipartspec(char *, struct disklabel *, int, int);
101289727Sianstatic int	checklabel(struct disklabel *);
102289727Sianstatic void	usage(void);
103289727Sianstatic struct disklabel *getvirginlabel(void);
104289727Sian
105289727Sian#define	DEFEDITOR	_PATH_VI
106289727Sian
107289727Sianstatic char	*dkname;
108289727Sianstatic char	*specname;
109289727Sianstatic char	tmpfil[] = PATH_TMPFILE;
110289727Sian
111167857Simpstatic struct	disklabel lab;
112167857Simpstatic u_char	bootarea[BBSIZE];
113167857Simpstatic off_t	mediasize;
114167857Simpstatic u_int	secsize;
115167857Simpstatic char	blank[] = "";
116167857Simpstatic char	unknown[] = "unknown";
117167857Simp
118167857Simp#define MAX_PART ('z')
119167857Simp#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
120167857Simpstatic char    part_size_type[MAX_NUM_PARTS];
121167857Simpstatic char    part_offset_type[MAX_NUM_PARTS];
122181305Sjhbstatic int     part_set[MAX_NUM_PARTS];
123167857Simp
124167857Simpstatic int	installboot;	/* non-zero if we should install a boot program */
125167857Simpstatic int	allfields;	/* present all fields in edit */
126167857Simpstatic char const *xxboot;	/* primary boot */
127167857Simp
128167857Simpstatic int labeloffset = LABELOFFSET + LABELSECTOR * DEV_BSIZE;
129289727Sianstatic int bbsize = BBSIZE;
130167857Simpstatic int alphacksum =
131167857Simp#if defined(__alpha__)
132167857Simp	1;
133289727Sian#else
134289083Sian	0;
135289727Sian#endif
136289727Sian
137289727Sianenum	{
138289727Sian	UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
139289727Sian} op = UNSPEC;
140289727Sian
141289727Sian
142289727Sianstatic int	disable_write;   /* set to disable writing to disk label */
143289727Sian
144289727Sianint
145289727Sianmain(int argc, char *argv[])
146289727Sian{
147289727Sian	FILE *t;
148289727Sian	int ch, error = 0;
149289727Sian	char const *name = 0;
150289727Sian
151289727Sian	while ((ch = getopt(argc, argv, "ABb:em:nRrs:w")) != -1)
152289727Sian		switch (ch) {
153289727Sian			case 'A':
154289727Sian				allfields = 1;
155289727Sian				break;
156289727Sian			case 'B':
157289727Sian				++installboot;
158289727Sian				break;
159289727Sian			case 'b':
160289727Sian				xxboot = optarg;
161289727Sian				break;
162289727Sian			case 'm':
163289727Sian				if (!strcmp(optarg, "i386")) {
164289727Sian					labeloffset = 512;
165289727Sian					bbsize = 8192;
166167857Simp					alphacksum = 0;
167186833Snwhitehorn				} else if (!strcmp(optarg, "alpha")) {
168167857Simp					labeloffset = 64;
169167857Simp					bbsize = 8192;
170289727Sian					alphacksum = 1;
171289727Sian				} else {
172289727Sian					errx(1, "Unsupported architecture");
173289727Sian				}
174289727Sian				break;
175289727Sian			case 'n':
176289727Sian				disable_write = 1;
177289727Sian				break;
178289727Sian			case 'R':
179289727Sian				if (op != UNSPEC)
180289727Sian					usage();
181289727Sian				op = RESTORE;
182289727Sian				break;
183289727Sian			case 'e':
184167857Simp				if (op != UNSPEC)
185167857Simp					usage();
186167857Simp				op = EDIT;
187167857Simp				break;
188346548Sian			case 'r':
189346548Sian				/*
190167857Simp				 * We accept and ignode -r for compatibility with
191289727Sian				 * historically disklabel usage.
192181325Sstas				 */
193289727Sian				break;
194289727Sian			case 'w':
195289727Sian				if (op != UNSPEC)
196289727Sian					usage();
197289727Sian				op = WRITE;
198289727Sian				break;
199289727Sian			case '?':
200167857Simp			default:
201289727Sian				usage();
202167857Simp		}
203167857Simp	argc -= optind;
204167857Simp	argv += optind;
205167857Simp
206289727Sian	if (argc < 1)
207167857Simp		usage();
208167857Simp
209346548Sian	/* Figure out the names of the thing we're working on */
210346548Sian	if (argv[0][0] != '/') {
211346548Sian		dkname = argv[0];
212346548Sian		asprintf(&specname, "%s%s", _PATH_DEV, argv[0]);
213346548Sian	} else {
214346548Sian		dkname = strrchr(argv[0], '/');
215346548Sian		dkname++;
216346548Sian		specname = argv[0];
217346548Sian	}
218346548Sian
219289727Sian	if (installboot && op == UNSPEC)
220167857Simp		op = WRITEBOOT;
221167857Simp	else if (op == UNSPEC)
222323931Sian		op = READ;
223323931Sian
224323931Sian	switch(op) {
225323931Sian
226323931Sian	case UNSPEC:
227323931Sian		break;
228323931Sian
229323931Sian	case EDIT:
230323931Sian		if (argc != 1)
231167857Simp			usage();
232167857Simp		readlabel(1);
233167857Simp		error = edit();
234323931Sian		break;
235167857Simp
236323931Sian	case READ:
237323931Sian		if (argc != 1)
238323931Sian			usage();
239323931Sian		readlabel(1);
240289083Sian		display(stdout, NULL);
241167857Simp		error = checklabel(NULL);
242167857Simp		break;
243167857Simp
244167857Simp	case RESTORE:
245167857Simp		if (argc != 2)
246323931Sian			usage();
247167857Simp		if (!(t = fopen(argv[1], "r")))
248323931Sian			err(4, "fopen %s", argv[1]);
249323931Sian		readlabel(0);
250167857Simp		if (!getasciilabel(t, &lab))
251167857Simp			exit(1);
252167857Simp		error = writelabel();
253167857Simp		break;
254167857Simp
255167857Simp	case WRITE:
256167857Simp		if (argc == 2)
257167857Simp			name = argv[1];
258167857Simp		else if (argc == 1)
259167857Simp			name = "auto";
260167857Simp		else
261167857Simp			usage();
262167857Simp		readlabel(0);
263167857Simp		makelabel(name, &lab);
264167857Simp		if (checklabel(NULL) == 0)
265167857Simp			error = writelabel();
266167857Simp		break;
267167857Simp
268167857Simp	case WRITEBOOT:
269167857Simp
270167857Simp		readlabel(1);
271167857Simp		if (argc == 2)
272167857Simp			makelabel(argv[1], &lab);
273167857Simp		if (checklabel(NULL) == 0)
274167857Simp			error = writelabel();
275167857Simp		break;
276289727Sian	}
277167857Simp	exit(error);
278167857Simp}
279167857Simp
280167857Simp/*
281167857Simp * Construct a prototype disklabel from /etc/disktab.
282167857Simp */
283167857Simpstatic void
284167857Simpmakelabel(const char *type, struct disklabel *lp)
285167857Simp{
286167857Simp	struct disklabel *dp;
287167857Simp
288167857Simp	if (strcmp(type, "auto") == 0)
289167857Simp		dp = getvirginlabel();
290167857Simp	else
291167857Simp		dp = getdiskbyname(type);
292167857Simp	if (dp == NULL)
293167857Simp		errx(1, "%s: unknown disk type", type);
294167857Simp	*lp = *dp;
295289727Sian	bzero(lp->d_packname, sizeof(lp->d_packname));
296289105Sian}
297289105Sian
298167857Simpstatic void
299289105Sianreadboot(void)
300167857Simp{
301167857Simp	int fd, i;
302167857Simp	struct stat st;
303167857Simp
304167857Simp	if (xxboot == NULL)
305167857Simp		xxboot = "/boot/boot";
306167857Simp	fd = open(xxboot, O_RDONLY);
307167857Simp	if (fd < 0)
308167857Simp		err(1, "cannot open %s", xxboot);
309167857Simp	fstat(fd, &st);
310167857Simp	if (st.st_size == BBSIZE) {
311167857Simp		i = read(fd, bootarea, BBSIZE);
312167857Simp		if (i != BBSIZE)
313167857Simp			err(1, "read error %s", xxboot);
314167857Simp		return;
315167857Simp	}
316167857Simp	if (alphacksum && st.st_size == BBSIZE - 512) {
317167857Simp		i = read(fd, bootarea + 512, BBSIZE - 512);
318167857Simp		if (i != BBSIZE - 512)
319167857Simp			err(1, "read error %s", xxboot);
320167857Simp		return;
321167857Simp	}
322167857Simp	errx(1, "boot code %s is wrong size", xxboot);
323167857Simp}
324167857Simp
325167857Simpstatic int
326167857Simpwritelabel(void)
327167857Simp{
328167857Simp	uint64_t *p, sum;
329167857Simp	int i, fd;
330167857Simp	struct gctl_req *grq;
331289118Sian	char const *errstr;
332167857Simp	struct disklabel *lp = &lab;
333167857Simp
334167857Simp	if (disable_write) {
335167857Simp		warnx("write to disk label supressed - label was as follows:");
336167857Simp		display(stdout, NULL);
337167857Simp		return (0);
338167857Simp	}
339167857Simp
340167857Simp	lp->d_magic = DISKMAGIC;
341167857Simp	lp->d_magic2 = DISKMAGIC;
342167857Simp	lp->d_checksum = 0;
343167857Simp	lp->d_checksum = dkcksum(lp);
344167857Simp	if (installboot)
345167857Simp		readboot();
346167857Simp	bsd_disklabel_le_enc(bootarea + labeloffset, lp);
347167857Simp	if (alphacksum) {
348167857Simp		/* Generate the bootblock checksum for the SRM console.  */
349167857Simp		for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++)
350167857Simp			sum += p[i];
351167857Simp		p[63] = sum;
352167857Simp	}
353167857Simp
354167857Simp	fd = open(specname, O_RDWR);
355289727Sian	if (fd < 0) {
356289105Sian		grq = gctl_get_handle(GCTL_CONFIG_GEOM);
357289105Sian		gctl_ro_param(grq, "class", -1, "BSD");
358167857Simp		gctl_ro_param(grq, "geom", -1, dkname);
359289105Sian		gctl_ro_param(grq, "verb", -1, "write label");
360289083Sian		gctl_ro_param(grq, "label", 148+16*8, bootarea + labeloffset);
361167857Simp		errstr = gctl_issue(grq);
362167857Simp		if (errstr != NULL) {
363289083Sian			warnx("%s", errstr);
364289727Sian			gctl_free(grq);
365289727Sian			return(1);
366167857Simp		}
367289105Sian		gctl_free(grq);
368289105Sian		if (installboot) {
369289083Sian			grq = gctl_get_handle(GCTL_CONFIG_GEOM);
370289105Sian			gctl_ro_param(grq, "class", -1, "BSD");
371167857Simp			gctl_ro_param(grq, "geom", -1, dkname);
372167857Simp			gctl_ro_param(grq, "verb", -1, "write bootcode");
373167857Simp			gctl_ro_param(grq, "bootcode", BBSIZE, bootarea);
374167857Simp			errstr = gctl_issue(grq);
375167857Simp			if (errstr != NULL) {
376167857Simp				warnx("%s", errstr);
377167857Simp				gctl_free(grq);
378323931Sian				return (1);
379167857Simp			}
380246128Ssbz			gctl_free(grq);
381167857Simp		}
382167857Simp	} else {
383167857Simp		if (write(fd, bootarea, bbsize) != bbsize) {
384167857Simp			warn("write %s", specname);
385167857Simp			close (fd);
386167857Simp			return (1);
387167857Simp		}
388167857Simp		close (fd);
389167857Simp	}
390167857Simp	return (0);
391167857Simp}
392167857Simp
393/*
394 * Fetch disklabel for disk.
395 * Use ioctl to get label unless -r flag is given.
396 */
397static int
398readlabel(int flag)
399{
400	int f;
401	int error;
402
403	f = open(specname, O_RDONLY);
404	if (f < 0)
405		err(1, specname);
406	(void)lseek(f, (off_t)0, SEEK_SET);
407	if (read(f, bootarea, BBSIZE) != BBSIZE)
408		err(4, "%s read", specname);
409	close (f);
410	error = bsd_disklabel_le_dec(bootarea + labeloffset, &lab, MAXPARTITIONS);
411	if (flag && error)
412		errx(1, "%s: no valid label found", specname);
413	return (error);
414}
415
416
417static void
418display(FILE *f, const struct disklabel *lp)
419{
420	int i, j;
421	const struct partition *pp;
422
423	if (lp == NULL)
424		lp = &lab;
425
426	fprintf(f, "# %s:\n", specname);
427	if (allfields) {
428		if (lp->d_type < DKMAXTYPES)
429			fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
430		else
431			fprintf(f, "type: %u\n", lp->d_type);
432		fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
433			lp->d_typename);
434		fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
435			lp->d_packname);
436		fprintf(f, "flags:");
437		if (lp->d_flags & D_REMOVABLE)
438			fprintf(f, " removeable");
439		if (lp->d_flags & D_ECC)
440			fprintf(f, " ecc");
441		if (lp->d_flags & D_BADSECT)
442			fprintf(f, " badsect");
443		fprintf(f, "\n");
444		fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
445		fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
446		fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
447		fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
448		fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
449		fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
450		fprintf(f, "rpm: %u\n", lp->d_rpm);
451		fprintf(f, "interleave: %u\n", lp->d_interleave);
452		fprintf(f, "trackskew: %u\n", lp->d_trackskew);
453		fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
454		fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
455		    (u_long)lp->d_headswitch);
456		fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
457		    (u_long)lp->d_trkseek);
458		fprintf(f, "drivedata: ");
459		for (i = NDDATA - 1; i >= 0; i--)
460			if (lp->d_drivedata[i])
461				break;
462		if (i < 0)
463			i = 0;
464		for (j = 0; j <= i; j++)
465			fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
466		fprintf(f, "\n\n");
467	}
468	fprintf(f, "%u partitions:\n", lp->d_npartitions);
469	fprintf(f,
470	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
471	pp = lp->d_partitions;
472	for (i = 0; i < lp->d_npartitions; i++, pp++) {
473		if (pp->p_size) {
474			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
475			   (u_long)pp->p_size, (u_long)pp->p_offset);
476			if (pp->p_fstype < FSMAXTYPES)
477				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
478			else
479				fprintf(f, "%8d", pp->p_fstype);
480			switch (pp->p_fstype) {
481
482			case FS_UNUSED:				/* XXX */
483				fprintf(f, "    %5lu %5lu %5.5s ",
484				    (u_long)pp->p_fsize,
485				    (u_long)(pp->p_fsize * pp->p_frag), "");
486				break;
487
488			case FS_BSDFFS:
489				fprintf(f, "    %5lu %5lu %5u ",
490				    (u_long)pp->p_fsize,
491				    (u_long)(pp->p_fsize * pp->p_frag),
492				    pp->p_cpg);
493				break;
494
495			case FS_BSDLFS:
496				fprintf(f, "    %5lu %5lu %5d",
497				    (u_long)pp->p_fsize,
498				    (u_long)(pp->p_fsize * pp->p_frag),
499				    pp->p_cpg);
500				break;
501
502			default:
503				fprintf(f, "%20.20s", "");
504				break;
505			}
506			if (i == RAW_PART) {
507				fprintf(f, "  # \"raw\" part, don't edit");
508			}
509			fprintf(f, "\n");
510		}
511	}
512	fflush(f);
513}
514
515static int
516edit(void)
517{
518	int c, fd;
519	struct disklabel label;
520	FILE *fp;
521
522	if ((fd = mkstemp(tmpfil)) == -1 ||
523	    (fp = fdopen(fd, "w")) == NULL) {
524		warnx("can't create %s", tmpfil);
525		return (1);
526	}
527	display(fp, NULL);
528	fclose(fp);
529	for (;;) {
530		if (!editit())
531			break;
532		fp = fopen(tmpfil, "r");
533		if (fp == NULL) {
534			warnx("can't reopen %s for reading", tmpfil);
535			break;
536		}
537		bzero((char *)&label, sizeof(label));
538		c = getasciilabel(fp, &label);
539		fclose(fp);
540		if (c) {
541			lab = label;
542			if (writelabel() == 0) {
543				(void) unlink(tmpfil);
544				return (0);
545			}
546		}
547		printf("re-edit the label? [y]: ");
548		fflush(stdout);
549		c = getchar();
550		if (c != EOF && c != (int)'\n')
551			while (getchar() != (int)'\n')
552				;
553		if  (c == (int)'n')
554			break;
555	}
556	(void) unlink(tmpfil);
557	return (1);
558}
559
560static int
561editit(void)
562{
563	int pid, xpid;
564	int locstat, omask;
565	const char *ed;
566
567	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
568	while ((pid = fork()) < 0) {
569		if (errno == EPROCLIM) {
570			warnx("you have too many processes");
571			return(0);
572		}
573		if (errno != EAGAIN) {
574			warn("fork");
575			return(0);
576		}
577		sleep(1);
578	}
579	if (pid == 0) {
580		sigsetmask(omask);
581		setgid(getgid());
582		setuid(getuid());
583		if ((ed = getenv("EDITOR")) == (char *)0)
584			ed = DEFEDITOR;
585		execlp(ed, ed, tmpfil, (char *)0);
586		err(1, "%s", ed);
587	}
588	while ((xpid = wait(&locstat)) >= 0)
589		if (xpid == pid)
590			break;
591	sigsetmask(omask);
592	return(!locstat);
593}
594
595static char *
596skip(char *cp)
597{
598
599	while (*cp != '\0' && isspace(*cp))
600		cp++;
601	if (*cp == '\0' || *cp == '#')
602		return (NULL);
603	return (cp);
604}
605
606static char *
607word(char *cp)
608{
609	char c;
610
611	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
612		cp++;
613	if ((c = *cp) != '\0') {
614		*cp++ = '\0';
615		if (c != '#')
616			return (skip(cp));
617	}
618	return (NULL);
619}
620
621/*
622 * Read an ascii label in from fd f,
623 * in the same format as that put out by display(),
624 * and fill in lp.
625 */
626static int
627getasciilabel(FILE *f, struct disklabel *lp)
628{
629	char *cp;
630	const char **cpp;
631	u_int part;
632	char *tp, line[BUFSIZ];
633	u_long v;
634	int lineno = 0, errors = 0;
635	int i;
636
637	bzero(&part_set, sizeof(part_set));
638	bzero(&part_size_type, sizeof(part_size_type));
639	bzero(&part_offset_type, sizeof(part_offset_type));
640	lp->d_bbsize = BBSIZE;				/* XXX */
641	lp->d_sbsize = 0;				/* XXX */
642	while (fgets(line, sizeof(line) - 1, f)) {
643		lineno++;
644		if ((cp = index(line,'\n')) != 0)
645			*cp = '\0';
646		cp = skip(line);
647		if (cp == NULL)
648			continue;
649		tp = index(cp, ':');
650		if (tp == NULL) {
651			fprintf(stderr, "line %d: syntax error\n", lineno);
652			errors++;
653			continue;
654		}
655		*tp++ = '\0', tp = skip(tp);
656		if (!strcmp(cp, "type")) {
657			if (tp == NULL)
658				tp = unknown;
659			cpp = dktypenames;
660			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
661				if (*cpp && !strcmp(*cpp, tp)) {
662					lp->d_type = cpp - dktypenames;
663					break;
664				}
665			if (cpp < &dktypenames[DKMAXTYPES])
666				continue;
667			v = strtoul(tp, NULL, 10);
668			if (v >= DKMAXTYPES)
669				fprintf(stderr, "line %d:%s %lu\n", lineno,
670				    "Warning, unknown disk type", v);
671			lp->d_type = v;
672			continue;
673		}
674		if (!strcmp(cp, "flags")) {
675			for (v = 0; (cp = tp) && *cp != '\0';) {
676				tp = word(cp);
677				if (!strcmp(cp, "removeable"))
678					v |= D_REMOVABLE;
679				else if (!strcmp(cp, "ecc"))
680					v |= D_ECC;
681				else if (!strcmp(cp, "badsect"))
682					v |= D_BADSECT;
683				else {
684					fprintf(stderr,
685					    "line %d: %s: bad flag\n",
686					    lineno, cp);
687					errors++;
688				}
689			}
690			lp->d_flags = v;
691			continue;
692		}
693		if (!strcmp(cp, "drivedata")) {
694			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
695				lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
696				tp = word(cp);
697			}
698			continue;
699		}
700		if (sscanf(cp, "%lu partitions", &v) == 1) {
701			if (v == 0 || v > MAXPARTITIONS) {
702				fprintf(stderr,
703				    "line %d: bad # of partitions\n", lineno);
704				lp->d_npartitions = MAXPARTITIONS;
705				errors++;
706			} else
707				lp->d_npartitions = v;
708			continue;
709		}
710		if (tp == NULL)
711			tp = blank;
712		if (!strcmp(cp, "disk")) {
713			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
714			continue;
715		}
716		if (!strcmp(cp, "label")) {
717			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
718			continue;
719		}
720		if (!strcmp(cp, "bytes/sector")) {
721			v = strtoul(tp, NULL, 10);
722			if (v == 0 || (v % DEV_BSIZE) != 0) {
723				fprintf(stderr,
724				    "line %d: %s: bad sector size\n",
725				    lineno, tp);
726				errors++;
727			} else
728				lp->d_secsize = v;
729			continue;
730		}
731		if (!strcmp(cp, "sectors/track")) {
732			v = strtoul(tp, NULL, 10);
733#if (ULONG_MAX != 0xffffffffUL)
734			if (v == 0 || v > 0xffffffff) {
735#else
736			if (v == 0) {
737#endif
738				fprintf(stderr, "line %d: %s: bad %s\n",
739				    lineno, tp, cp);
740				errors++;
741			} else
742				lp->d_nsectors = v;
743			continue;
744		}
745		if (!strcmp(cp, "sectors/cylinder")) {
746			v = strtoul(tp, NULL, 10);
747			if (v == 0) {
748				fprintf(stderr, "line %d: %s: bad %s\n",
749				    lineno, tp, cp);
750				errors++;
751			} else
752				lp->d_secpercyl = v;
753			continue;
754		}
755		if (!strcmp(cp, "tracks/cylinder")) {
756			v = strtoul(tp, NULL, 10);
757			if (v == 0) {
758				fprintf(stderr, "line %d: %s: bad %s\n",
759				    lineno, tp, cp);
760				errors++;
761			} else
762				lp->d_ntracks = v;
763			continue;
764		}
765		if (!strcmp(cp, "cylinders")) {
766			v = strtoul(tp, NULL, 10);
767			if (v == 0) {
768				fprintf(stderr, "line %d: %s: bad %s\n",
769				    lineno, tp, cp);
770				errors++;
771			} else
772				lp->d_ncylinders = v;
773			continue;
774		}
775		if (!strcmp(cp, "sectors/unit")) {
776			v = strtoul(tp, NULL, 10);
777			if (v == 0) {
778				fprintf(stderr, "line %d: %s: bad %s\n",
779				    lineno, tp, cp);
780				errors++;
781			} else
782				lp->d_secperunit = v;
783			continue;
784		}
785		if (!strcmp(cp, "rpm")) {
786			v = strtoul(tp, NULL, 10);
787			if (v == 0 || v > USHRT_MAX) {
788				fprintf(stderr, "line %d: %s: bad %s\n",
789				    lineno, tp, cp);
790				errors++;
791			} else
792				lp->d_rpm = v;
793			continue;
794		}
795		if (!strcmp(cp, "interleave")) {
796			v = strtoul(tp, NULL, 10);
797			if (v == 0 || v > USHRT_MAX) {
798				fprintf(stderr, "line %d: %s: bad %s\n",
799				    lineno, tp, cp);
800				errors++;
801			} else
802				lp->d_interleave = v;
803			continue;
804		}
805		if (!strcmp(cp, "trackskew")) {
806			v = strtoul(tp, NULL, 10);
807			if (v > USHRT_MAX) {
808				fprintf(stderr, "line %d: %s: bad %s\n",
809				    lineno, tp, cp);
810				errors++;
811			} else
812				lp->d_trackskew = v;
813			continue;
814		}
815		if (!strcmp(cp, "cylinderskew")) {
816			v = strtoul(tp, NULL, 10);
817			if (v > USHRT_MAX) {
818				fprintf(stderr, "line %d: %s: bad %s\n",
819				    lineno, tp, cp);
820				errors++;
821			} else
822				lp->d_cylskew = v;
823			continue;
824		}
825		if (!strcmp(cp, "headswitch")) {
826			v = strtoul(tp, NULL, 10);
827			lp->d_headswitch = v;
828			continue;
829		}
830		if (!strcmp(cp, "track-to-track seek")) {
831			v = strtoul(tp, NULL, 10);
832			lp->d_trkseek = v;
833			continue;
834		}
835		/* the ':' was removed above */
836		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
837			fprintf(stderr,
838			    "line %d: %s: Unknown disklabel field\n", lineno,
839			    cp);
840			errors++;
841			continue;
842		}
843
844		/* Process a partition specification line. */
845		part = *cp - 'a';
846		if (part >= lp->d_npartitions) {
847			fprintf(stderr,
848			    "line %d: partition name out of range a-%c: %s\n",
849			    lineno, 'a' + lp->d_npartitions - 1, cp);
850			errors++;
851			continue;
852		}
853		part_set[part] = 1;
854
855		if (getasciipartspec(tp, lp, part, lineno) != 0) {
856			errors++;
857			break;
858		}
859	}
860	errors += checklabel(lp);
861	return (errors == 0);
862}
863
864#define NXTNUM(n) do { \
865	if (tp == NULL) { \
866		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
867		return (1); \
868	} else { \
869		cp = tp, tp = word(cp); \
870		(n) = strtoul(cp, NULL, 10); \
871	} \
872} while (0)
873
874/* retain 1 character following number */
875#define NXTWORD(w,n) do { \
876	if (tp == NULL) { \
877		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
878		return (1); \
879	} else { \
880	        char *tmp; \
881		cp = tp, tp = word(cp); \
882	        (n) = strtoul(cp, &tmp, 10); \
883		if (tmp) (w) = *tmp; \
884	} \
885} while (0)
886
887/*
888 * Read a partition line into partition `part' in the specified disklabel.
889 * Return 0 on success, 1 on failure.
890 */
891static int
892getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
893{
894	struct partition *pp;
895	char *cp;
896	const char **cpp;
897	u_long v;
898
899	pp = &lp->d_partitions[part];
900	cp = NULL;
901
902	v = 0;
903	NXTWORD(part_size_type[part],v);
904	if (v == 0 && part_size_type[part] != '*') {
905		fprintf(stderr,
906		    "line %d: %s: bad partition size\n", lineno, cp);
907		return (1);
908	}
909	pp->p_size = v;
910
911	v = 0;
912	NXTWORD(part_offset_type[part],v);
913	if (v == 0 && part_offset_type[part] != '*' &&
914	    part_offset_type[part] != '\0') {
915		fprintf(stderr,
916		    "line %d: %s: bad partition offset\n", lineno, cp);
917		return (1);
918	}
919	pp->p_offset = v;
920	if (tp == NULL) {
921		fprintf(stderr, "line %d: missing file system type\n", lineno);
922		return (1);
923	}
924	cp = tp, tp = word(cp);
925	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
926		if (*cpp && !strcmp(*cpp, cp))
927			break;
928	if (*cpp != NULL) {
929		pp->p_fstype = cpp - fstypenames;
930	} else {
931		if (isdigit(*cp))
932			v = strtoul(cp, NULL, 10);
933		else
934			v = FSMAXTYPES;
935		if (v >= FSMAXTYPES) {
936			fprintf(stderr,
937			    "line %d: Warning, unknown file system type %s\n",
938			    lineno, cp);
939			v = FS_UNUSED;
940		}
941		pp->p_fstype = v;
942	}
943
944	switch (pp->p_fstype) {
945	case FS_UNUSED:
946		/*
947		 * allow us to accept defaults for
948		 * fsize/frag/cpg
949		 */
950		if (tp) {
951			NXTNUM(pp->p_fsize);
952			if (pp->p_fsize == 0)
953				break;
954			NXTNUM(v);
955			pp->p_frag = v / pp->p_fsize;
956		}
957		/* else default to 0's */
958		break;
959
960	/* These happen to be the same */
961	case FS_BSDFFS:
962	case FS_BSDLFS:
963		if (tp) {
964			NXTNUM(pp->p_fsize);
965			if (pp->p_fsize == 0)
966				break;
967			NXTNUM(v);
968			pp->p_frag = v / pp->p_fsize;
969			NXTNUM(pp->p_cpg);
970		} else {
971			/*
972			 * FIX! poor attempt at adaptive
973			 */
974			/* 1 GB */
975			if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
976				/*
977				 * FIX! These are too low, but are traditional
978				 */
979				pp->p_fsize = DEFAULT_NEWFS_FRAG;
980				pp->p_frag = DEFAULT_NEWFS_BLOCK /
981				    DEFAULT_NEWFS_FRAG;
982				pp->p_cpg = DEFAULT_NEWFS_CPG;
983			} else {
984				pp->p_fsize = BIG_NEWFS_FRAG;
985				pp->p_frag = BIG_NEWFS_BLOCK /
986				    BIG_NEWFS_FRAG;
987				pp->p_cpg = BIG_NEWFS_CPG;
988			}
989		}
990	default:
991		break;
992	}
993	return (0);
994}
995
996/*
997 * Check disklabel for errors and fill in
998 * derived fields according to supplied values.
999 */
1000static int
1001checklabel(struct disklabel *lp)
1002{
1003	struct partition *pp;
1004	int i, errors = 0;
1005	char part;
1006	u_long total_size, total_percent, current_offset;
1007	int seen_default_offset;
1008	int hog_part;
1009	int j;
1010	struct partition *pp2;
1011
1012	if (lp == NULL)
1013		lp = &lab;
1014
1015	if (allfields) {
1016
1017		if (lp->d_secsize == 0) {
1018			fprintf(stderr, "sector size 0\n");
1019			return (1);
1020		}
1021		if (lp->d_nsectors == 0) {
1022			fprintf(stderr, "sectors/track 0\n");
1023			return (1);
1024		}
1025		if (lp->d_ntracks == 0) {
1026			fprintf(stderr, "tracks/cylinder 0\n");
1027			return (1);
1028		}
1029		if  (lp->d_ncylinders == 0) {
1030			fprintf(stderr, "cylinders/unit 0\n");
1031			errors++;
1032		}
1033		if (lp->d_rpm == 0)
1034			warnx("revolutions/minute 0");
1035		if (lp->d_secpercyl == 0)
1036			lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1037		if (lp->d_secperunit == 0)
1038			lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1039		if (lp->d_bbsize == 0) {
1040			fprintf(stderr, "boot block size 0\n");
1041			errors++;
1042		} else if (lp->d_bbsize % lp->d_secsize)
1043			warnx("boot block size %% sector-size != 0");
1044		if (lp->d_npartitions > MAXPARTITIONS)
1045			warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
1046			    (u_long)lp->d_npartitions, MAXPARTITIONS);
1047	} else {
1048		struct disklabel *vl;
1049
1050		vl = getvirginlabel();
1051		lp->d_secsize = vl->d_secsize;
1052		lp->d_nsectors = vl->d_nsectors;
1053		lp->d_ntracks = vl->d_ntracks;
1054		lp->d_ncylinders = vl->d_ncylinders;
1055		lp->d_rpm = vl->d_rpm;
1056		lp->d_interleave = vl->d_interleave;
1057		lp->d_secpercyl = vl->d_secpercyl;
1058		lp->d_secperunit = vl->d_secperunit;
1059		lp->d_bbsize = vl->d_bbsize;
1060		lp->d_npartitions = vl->d_npartitions;
1061	}
1062
1063
1064	/* first allocate space to the partitions, then offsets */
1065	total_size = 0; /* in sectors */
1066	total_percent = 0; /* in percent */
1067	hog_part = -1;
1068	/* find all fixed partitions */
1069	for (i = 0; i < lp->d_npartitions; i++) {
1070		pp = &lp->d_partitions[i];
1071		if (part_set[i]) {
1072			if (part_size_type[i] == '*') {
1073				if (i == RAW_PART) {
1074					pp->p_size = lp->d_secperunit;
1075				} else {
1076					if (hog_part != -1)
1077						warnx("Too many '*' partitions (%c and %c)",
1078						    hog_part + 'a',i + 'a');
1079					else
1080						hog_part = i;
1081				}
1082			} else {
1083				off_t size;
1084
1085				size = pp->p_size;
1086				switch (part_size_type[i]) {
1087				case '%':
1088					total_percent += size;
1089					break;
1090				case 'k':
1091				case 'K':
1092					size *= 1024ULL;
1093					break;
1094				case 'm':
1095				case 'M':
1096					size *= 1024ULL * 1024ULL;
1097					break;
1098				case 'g':
1099				case 'G':
1100					size *= 1024ULL * 1024ULL * 1024ULL;
1101					break;
1102				case '\0':
1103					break;
1104				default:
1105					warnx("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1106					break;
1107				}
1108				/* don't count %'s yet */
1109				if (part_size_type[i] != '%') {
1110					/*
1111					 * for all not in sectors, convert to
1112					 * sectors
1113					 */
1114					if (part_size_type[i] != '\0') {
1115						if (size % lp->d_secsize != 0)
1116							warnx("partition %c not an integer number of sectors",
1117							    i + 'a');
1118						size /= lp->d_secsize;
1119						pp->p_size = size;
1120					}
1121					/* else already in sectors */
1122					if (i != RAW_PART)
1123						total_size += size;
1124				}
1125			}
1126		}
1127	}
1128	/* handle % partitions - note %'s don't need to add up to 100! */
1129	if (total_percent != 0) {
1130		long free_space = lp->d_secperunit - total_size;
1131		if (total_percent > 100) {
1132			fprintf(stderr,"total percentage %lu is greater than 100\n",
1133			    total_percent);
1134			errors++;
1135		}
1136
1137		if (free_space > 0) {
1138			for (i = 0; i < lp->d_npartitions; i++) {
1139				pp = &lp->d_partitions[i];
1140				if (part_set[i] && part_size_type[i] == '%') {
1141					/* careful of overflows! and integer roundoff */
1142					pp->p_size = ((double)pp->p_size/100) * free_space;
1143					total_size += pp->p_size;
1144
1145					/* FIX we can lose a sector or so due to roundoff per
1146					   partition.  A more complex algorithm could avoid that */
1147				}
1148			}
1149		} else {
1150			fprintf(stderr,
1151			    "%ld sectors available to give to '*' and '%%' partitions\n",
1152			    free_space);
1153			errors++;
1154			/* fix?  set all % partitions to size 0? */
1155		}
1156	}
1157	/* give anything remaining to the hog partition */
1158	if (hog_part != -1) {
1159		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1160		total_size = lp->d_secperunit;
1161	}
1162
1163	/* Now set the offsets for each partition */
1164	current_offset = 0; /* in sectors */
1165	seen_default_offset = 0;
1166	for (i = 0; i < lp->d_npartitions; i++) {
1167		part = 'a' + i;
1168		pp = &lp->d_partitions[i];
1169		if (part_set[i]) {
1170			if (part_offset_type[i] == '*') {
1171				if (i == RAW_PART) {
1172					pp->p_offset = 0;
1173				} else {
1174					pp->p_offset = current_offset;
1175					seen_default_offset = 1;
1176				}
1177			} else {
1178				/* allow them to be out of order for old-style tables */
1179				if (pp->p_offset < current_offset &&
1180				    seen_default_offset && i != RAW_PART &&
1181				    pp->p_fstype != FS_VINUM) {
1182					fprintf(stderr,
1183"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1184					    (long)pp->p_offset,i+'a',current_offset);
1185					fprintf(stderr,
1186"Labels with any *'s for offset must be in ascending order by sector\n");
1187					errors++;
1188				} else if (pp->p_offset != current_offset &&
1189				    i != RAW_PART && seen_default_offset) {
1190					/*
1191					 * this may give unneeded warnings if
1192					 * partitions are out-of-order
1193					 */
1194					warnx(
1195"Offset %ld for partition %c doesn't match expected value %ld",
1196					    (long)pp->p_offset, i + 'a', current_offset);
1197				}
1198			}
1199			if (i != RAW_PART)
1200				current_offset = pp->p_offset + pp->p_size;
1201		}
1202	}
1203
1204	for (i = 0; i < lp->d_npartitions; i++) {
1205		part = 'a' + i;
1206		pp = &lp->d_partitions[i];
1207		if (pp->p_size == 0 && pp->p_offset != 0)
1208			warnx("partition %c: size 0, but offset %lu",
1209			    part, (u_long)pp->p_offset);
1210#ifdef notdef
1211		if (pp->p_size % lp->d_secpercyl)
1212			warnx("partition %c: size %% cylinder-size != 0",
1213			    part);
1214		if (pp->p_offset % lp->d_secpercyl)
1215			warnx("partition %c: offset %% cylinder-size != 0",
1216			    part);
1217#endif
1218		if (pp->p_offset > lp->d_secperunit) {
1219			fprintf(stderr,
1220			    "partition %c: offset past end of unit\n", part);
1221			errors++;
1222		}
1223		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1224			fprintf(stderr,
1225			"partition %c: partition extends past end of unit\n",
1226			    part);
1227			errors++;
1228		}
1229		if (i == RAW_PART) {
1230			if (pp->p_fstype != FS_UNUSED)
1231				warnx("partition %c is not marked as unused!",part);
1232			if (pp->p_offset != 0)
1233				warnx("partition %c doesn't start at 0!",part);
1234			if (pp->p_size != lp->d_secperunit)
1235				warnx("partition %c doesn't cover the whole unit!",part);
1236
1237			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1238			    (pp->p_size != lp->d_secperunit)) {
1239				warnx("An incorrect partition %c may cause problems for "
1240				    "standard system utilities",part);
1241			}
1242		}
1243
1244		/* check for overlaps */
1245		/* this will check for all possible overlaps once and only once */
1246		for (j = 0; j < i; j++) {
1247			pp2 = &lp->d_partitions[j];
1248			if (j != RAW_PART && i != RAW_PART &&
1249			    pp->p_fstype != FS_VINUM &&
1250			    pp2->p_fstype != FS_VINUM &&
1251			    part_set[i] && part_set[j]) {
1252				if (pp2->p_offset < pp->p_offset + pp->p_size &&
1253				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
1254					pp2->p_offset >= pp->p_offset)) {
1255					fprintf(stderr,"partitions %c and %c overlap!\n",
1256					    j + 'a', i + 'a');
1257					errors++;
1258				}
1259			}
1260		}
1261	}
1262	for (; i < MAXPARTITIONS; i++) {
1263		part = 'a' + i;
1264		pp = &lp->d_partitions[i];
1265		if (pp->p_size || pp->p_offset)
1266			warnx("unused partition %c: size %d offset %lu",
1267			    'a' + i, pp->p_size, (u_long)pp->p_offset);
1268	}
1269	return (errors);
1270}
1271
1272/*
1273 * When operating on a "virgin" disk, try getting an initial label
1274 * from the associated device driver.  This might work for all device
1275 * drivers that are able to fetch some initial device parameters
1276 * without even having access to a (BSD) disklabel, like SCSI disks,
1277 * most IDE drives, or vn devices.
1278 *
1279 * The device name must be given in its "canonical" form.
1280 */
1281static struct disklabel *
1282getvirginlabel(void)
1283{
1284	static struct disklabel loclab;
1285	struct partition *dp;
1286	int f;
1287	u_int u;
1288
1289	if ((f = open(specname, O_RDONLY)) == -1) {
1290		warn("cannot open %s", specname);
1291		return (NULL);
1292	}
1293
1294	/* New world order */
1295	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
1296	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1297		close (f);
1298		return (NULL);
1299	}
1300	memset(&loclab, 0, sizeof loclab);
1301	loclab.d_magic = DISKMAGIC;
1302	loclab.d_magic2 = DISKMAGIC;
1303	loclab.d_secsize = secsize;
1304	loclab.d_secperunit = mediasize / secsize;
1305
1306	/*
1307	 * Nobody in these enligthened days uses the CHS geometry for
1308	 * anything, but nontheless try to get it right.  If we fail
1309	 * to get any good ideas from the device, construct something
1310	 * which is IBM-PC friendly.
1311	 */
1312	if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1313		loclab.d_nsectors = u;
1314	else
1315		loclab.d_nsectors = 63;
1316	if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1317		loclab.d_ntracks = u;
1318	else if (loclab.d_secperunit <= 63*1*1024)
1319		loclab.d_ntracks = 1;
1320	else if (loclab.d_secperunit <= 63*16*1024)
1321		loclab.d_ntracks = 16;
1322	else
1323		loclab.d_ntracks = 255;
1324	loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1325	loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1326	loclab.d_npartitions = MAXPARTITIONS;
1327
1328	/* Various (unneeded) compat stuff */
1329	loclab.d_rpm = 3600;
1330	loclab.d_bbsize = BBSIZE;
1331	loclab.d_interleave = 1;
1332	strncpy(loclab.d_typename, "amnesiac",
1333	    sizeof(loclab.d_typename));
1334
1335	dp = &loclab.d_partitions[RAW_PART];
1336	dp->p_size = loclab.d_secperunit;
1337	loclab.d_checksum = dkcksum(&loclab);
1338	close (f);
1339	return (&loclab);
1340}
1341
1342static void
1343usage(void)
1344{
1345
1346	fprintf(stderr,
1347	"%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",
1348	"usage: bsdlabel disk",
1349	"\t\t(to read label)",
1350	"	bsdlabel -w [-n] [-m machine] disk [type]",
1351	"\t\t(to write label with existing boot program)",
1352	"	bsdlabel -e [-n] [-m machine] disk",
1353	"\t\t(to edit label)",
1354	"	bsdlabel -R [-n] [-m machine] disk protofile",
1355	"\t\t(to restore label with existing boot program)",
1356	"	bsdlabel -B [-b boot] [-m machine] disk",
1357	"\t\t(to install boot program with existing on-disk label)",
1358	"	bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]",
1359	"\t\t(to write label and install boot program)",
1360	"	bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1361		"\t\t(to restore label and install boot program)"
1362	);
1363	exit(1);
1364}
1365