bsdlabel.c revision 111286
11558Srgrimes/*
292058Sobrien * Copyright (c) 1994, 1995 Gordon W. Ross
392058Sobrien * Copyright (c) 1994 Theo de Raadt
492058Sobrien * All rights reserved.
51558Srgrimes * Copyright (c) 1987, 1993
61558Srgrimes *	The Regents of the University of California.  All rights reserved.
71558Srgrimes *
81558Srgrimes * This code is derived from software contributed to Berkeley by
91558Srgrimes * Symmetric Computer Systems.
101558Srgrimes *
111558Srgrimes * Redistribution and use in source and binary forms, with or without
121558Srgrimes * modification, are permitted provided that the following conditions
131558Srgrimes * are met:
141558Srgrimes * 1. Redistributions of source code must retain the above copyright
151558Srgrimes *    notice, this list of conditions and the following disclaimer.
161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171558Srgrimes *    notice, this list of conditions and the following disclaimer in the
181558Srgrimes *    documentation and/or other materials provided with the distribution.
191558Srgrimes * 3. All advertising materials mentioning features or use of this software
201558Srgrimes *    must display the following acknowledgement:
211558Srgrimes *	This product includes software developed by the University of
221558Srgrimes *	California, Berkeley and its contributors.
2392058Sobrien *      This product includes software developed by Theo de Raadt.
241558Srgrimes * 4. Neither the name of the University nor the names of its contributors
251558Srgrimes *    may be used to endorse or promote products derived from this software
261558Srgrimes *    without specific prior written permission.
271558Srgrimes *
281558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
291558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
301558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
311558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
321558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
331558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
341558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
351558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
361558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
371558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
381558Srgrimes * SUCH DAMAGE.
3992058Sobrien *
4092058Sobrien *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
411558Srgrimes */
421558Srgrimes
431558Srgrimes#ifndef lint
4436632Scharnierstatic const char copyright[] =
451558Srgrimes"@(#) Copyright (c) 1987, 1993\n\
461558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
471558Srgrimes#endif /* not lint */
481558Srgrimes
491558Srgrimes#ifndef lint
5036632Scharnier#if 0
511558Srgrimesstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
521558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
5336632Scharnier#endif
541558Srgrimes#endif /* not lint */
551558Srgrimes
5699365Smarkm#include <sys/cdefs.h>
5799365Smarkm__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 111286 2003-02-23 01:48:42Z ru $");
5899365Smarkm
591558Srgrimes#include <sys/param.h>
601558Srgrimes#include <sys/file.h>
611558Srgrimes#include <sys/stat.h>
6213544Sjoerg#include <sys/wait.h>
63103669Sphk#include <sys/disk.h>
641558Srgrimes#define DKTYPENAMES
65101994Sbmilekic#define FSTYPENAMES
661558Srgrimes#include <sys/disklabel.h>
67104674Snyan#ifdef PC98
68104674Snyan#include <sys/diskpc98.h>
69104674Snyan#else
70104272Sphk#include <sys/diskmbr.h>
71104674Snyan#endif
7299365Smarkm
731558Srgrimes#include <unistd.h>
741558Srgrimes#include <string.h>
751558Srgrimes#include <stdio.h>
7613544Sjoerg#include <stdlib.h>
7713544Sjoerg#include <signal.h>
7813544Sjoerg#include <stdarg.h>
791558Srgrimes#include <ctype.h>
8026542Scharnier#include <err.h>
8159216Simp#include <errno.h>
8299365Smarkm
831558Srgrimes#include "pathnames.h"
841558Srgrimes
851558Srgrimes/*
861558Srgrimes * Disklabel: read and write disklabels.
871558Srgrimes * The label is usually placed on one of the first sectors of the disk.
881558Srgrimes * Many machines also place a bootstrap in the same area,
891558Srgrimes * in which case the label is embedded in the bootstrap.
901558Srgrimes * The bootstrap source must leave space at the proper offset
911558Srgrimes * for the label on such machines.
921558Srgrimes */
931558Srgrimes
941558Srgrimes#ifndef BBSIZE
951558Srgrimes#define	BBSIZE	8192			/* size of boot area, with label */
961558Srgrimes#endif
971558Srgrimes
9873034Sjwd/* FIX!  These are too low, but are traditional */
9973034Sjwd#define DEFAULT_NEWFS_BLOCK  8192U
10073034Sjwd#define DEFAULT_NEWFS_FRAG   1024U
10173034Sjwd#define DEFAULT_NEWFS_CPG    16U
10273034Sjwd
10373034Sjwd#define BIG_NEWFS_BLOCK  16384U
10497535Siedowse#define BIG_NEWFS_FRAG   2048U
10573034Sjwd#define BIG_NEWFS_CPG    64U
10673034Sjwd
107109882Sphk#if defined(__i386__)
108109882Sphk#elif defined(__alpha__)
109109891Sphk#elif defined(__ia64__)
1101558Srgrimes#else
111109884Sphk#error	I do not know about this architecture, and shall probably not be compiled for it.
1121558Srgrimes#endif
1131558Srgrimes
11492541Simpvoid	makelabel(const char *, const char *, struct disklabel *);
11592541Simpint	writelabel(int, const char *, struct disklabel *);
11692541Simpvoid	l_perror(const char *);
11792541Simpstruct disklabel *readlabel(int);
11892541Simpstruct disklabel *makebootarea(char *, struct disklabel *, int);
11992541Simpvoid	display(FILE *, const struct disklabel *);
12092541Simpint	edit(struct disklabel *, int);
12192541Simpint	editit(void);
12292541Simpchar	*skip(char *);
12392541Simpchar	*word(char *);
12492541Simpint	getasciilabel(FILE *, struct disklabel *);
12597534Siedowseint	getasciipartspec(char *, struct disklabel *, int, int);
12692541Simpint	checklabel(struct disklabel *);
12792541Simpvoid	Warning(const char *, ...) __printflike(1, 2);
12892541Simpvoid	usage(void);
12992541Simpstruct disklabel *getvirginlabel(void);
13013544Sjoerg
1311558Srgrimes#define	DEFEDITOR	_PATH_VI
1321558Srgrimes#define	streq(a,b)	(strcmp(a,b) == 0)
1331558Srgrimes
1341558Srgrimeschar	*dkname;
1351558Srgrimeschar	*specname;
13655742Skrischar	tmpfil[] = PATH_TMPFILE;
1371558Srgrimes
1381558Srgrimeschar	namebuf[BBSIZE], *np = namebuf;
1391558Srgrimesstruct	disklabel lab;
1401558Srgrimeschar	bootarea[BBSIZE];
14199365Smarkmchar	blank[] = "";
14299365Smarkmchar	unknown[] = "unknown";
1431558Srgrimes
14473034Sjwd#define MAX_PART ('z')
14573034Sjwd#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
14673034Sjwdchar    part_size_type[MAX_NUM_PARTS];
14773034Sjwdchar    part_offset_type[MAX_NUM_PARTS];
14873034Sjwdint     part_set[MAX_NUM_PARTS];
14973034Sjwd
1501558Srgrimesint	installboot;	/* non-zero if we should install a boot program */
1511558Srgrimeschar	*xxboot;	/* primary boot */
1521558Srgrimeschar	boot0[MAXPATHLEN];
1531558Srgrimes
1541558Srgrimesenum	{
155109872Sphk	UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
1561558Srgrimes} op = UNSPEC;
1571558Srgrimes
1581558Srgrimesint	rflag;
15973034Sjwdint	disable_write;   /* set to disable writing to disk label */
1601558Srgrimes
161109872Sphk#define OPTIONS	"BRb:enrs:w"
1621558Srgrimes
16313544Sjoergint
16492541Simpmain(int argc, char *argv[])
1651558Srgrimes{
16692715Simp	struct disklabel *lp;
1671558Srgrimes	FILE *t;
168109872Sphk	int ch, f = 0, error = 0;
1691558Srgrimes	char *name = 0;
1701558Srgrimes
17124359Simp	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
1721558Srgrimes		switch (ch) {
1731558Srgrimes			case 'B':
1741558Srgrimes				++installboot;
1751558Srgrimes				break;
1761558Srgrimes			case 'b':
1771558Srgrimes				xxboot = optarg;
1781558Srgrimes				break;
17973034Sjwd			case 'n':
18073034Sjwd				disable_write = 1;
18173034Sjwd				break;
1821558Srgrimes			case 'R':
1831558Srgrimes				if (op != UNSPEC)
1841558Srgrimes					usage();
1851558Srgrimes				op = RESTORE;
1861558Srgrimes				break;
1871558Srgrimes			case 'e':
1881558Srgrimes				if (op != UNSPEC)
1891558Srgrimes					usage();
1901558Srgrimes				op = EDIT;
1911558Srgrimes				break;
1921558Srgrimes			case 'r':
1931558Srgrimes				++rflag;
1941558Srgrimes				break;
1951558Srgrimes			case 'w':
1961558Srgrimes				if (op != UNSPEC)
1971558Srgrimes					usage();
1981558Srgrimes				op = WRITE;
1991558Srgrimes				break;
2001558Srgrimes			case '?':
2011558Srgrimes			default:
2021558Srgrimes				usage();
2031558Srgrimes		}
2041558Srgrimes	argc -= optind;
2051558Srgrimes	argv += optind;
2061558Srgrimes	if (installboot) {
2071558Srgrimes		rflag++;
2081558Srgrimes		if (op == UNSPEC)
2091558Srgrimes			op = WRITEBOOT;
2101558Srgrimes	} else {
2111558Srgrimes		if (op == UNSPEC)
2121558Srgrimes			op = READ;
213109889Sphk		xxboot = 0;
2141558Srgrimes	}
2151558Srgrimes	if (argc < 1)
2161558Srgrimes		usage();
2171558Srgrimes
2181558Srgrimes	dkname = argv[0];
2191558Srgrimes	if (dkname[0] != '/') {
22059114Sobrien		(void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
2211558Srgrimes		specname = np;
2221558Srgrimes		np += strlen(specname) + 1;
2231558Srgrimes	} else
2241558Srgrimes		specname = dkname;
2251558Srgrimes	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2261558Srgrimes	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
22759429Sobrien		(void)sprintf(specname, "%s%s", _PATH_DEV, dkname);
2281558Srgrimes		np = namebuf + strlen(specname) + 1;
2291558Srgrimes		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2301558Srgrimes	}
231109901Sphk	if (f < 0 && errno == EBUSY) {
232109901Sphk		/* lets try to get by with ioctls */
233109901Sphk		f = open(specname, O_RDONLY);
234109901Sphk	}
2351558Srgrimes	if (f < 0)
23626542Scharnier		err(4, "%s", specname);
2371558Srgrimes
2381558Srgrimes	switch(op) {
2391558Srgrimes
24048957Sbillf	case UNSPEC:
24148957Sbillf		break;
24248957Sbillf
2431558Srgrimes	case EDIT:
2441558Srgrimes		if (argc != 1)
2451558Srgrimes			usage();
2461558Srgrimes		lp = readlabel(f);
2471558Srgrimes		error = edit(lp, f);
2481558Srgrimes		break;
2491558Srgrimes
2501558Srgrimes	case READ:
2511558Srgrimes		if (argc != 1)
2521558Srgrimes			usage();
2531558Srgrimes		lp = readlabel(f);
2541558Srgrimes		display(stdout, lp);
2551558Srgrimes		error = checklabel(lp);
2561558Srgrimes		break;
2571558Srgrimes
2581558Srgrimes	case RESTORE:
2591558Srgrimes		if (argc != 2)
2601558Srgrimes			usage();
2611558Srgrimes		if (!(t = fopen(argv[1], "r")))
26226542Scharnier			err(4, "%s", argv[1]);
26337865Sbde		if (!getasciilabel(t, &lab))
26437865Sbde			exit(1);
26537865Sbde		lp = makebootarea(bootarea, &lab, f);
26637865Sbde		*lp = lab;
26737865Sbde		error = writelabel(f, bootarea, lp);
2681558Srgrimes		break;
2691558Srgrimes
2701558Srgrimes	case WRITE:
2711558Srgrimes		if (argc == 3) {
2721558Srgrimes			name = argv[2];
2731558Srgrimes			argc--;
2741558Srgrimes		}
2751558Srgrimes		if (argc != 2)
2761558Srgrimes			usage();
2771558Srgrimes		makelabel(argv[1], name, &lab);
2781558Srgrimes		lp = makebootarea(bootarea, &lab, f);
2791558Srgrimes		*lp = lab;
2801558Srgrimes		if (checklabel(lp) == 0)
2811558Srgrimes			error = writelabel(f, bootarea, lp);
2821558Srgrimes		break;
2831558Srgrimes
2841558Srgrimes	case WRITEBOOT:
2851558Srgrimes	{
2861558Srgrimes		struct disklabel tlab;
2871558Srgrimes
2881558Srgrimes		lp = readlabel(f);
2891558Srgrimes		tlab = *lp;
2901558Srgrimes		if (argc == 2)
2911558Srgrimes			makelabel(argv[1], 0, &lab);
2921558Srgrimes		lp = makebootarea(bootarea, &lab, f);
2931558Srgrimes		*lp = tlab;
2941558Srgrimes		if (checklabel(lp) == 0)
2951558Srgrimes			error = writelabel(f, bootarea, lp);
2961558Srgrimes		break;
2971558Srgrimes	}
2981558Srgrimes	}
2991558Srgrimes	exit(error);
3001558Srgrimes}
3011558Srgrimes
3021558Srgrimes/*
303111286Sru * Construct a prototype disklabel from /etc/disktab.
3041558Srgrimes */
30513544Sjoergvoid
30692541Simpmakelabel(const char *type, const char *name, struct disklabel *lp)
3071558Srgrimes{
30892541Simp	struct disklabel *dp;
30913550Sjoerg
31013550Sjoerg	if (strcmp(type, "auto") == 0)
31113550Sjoerg		dp = getvirginlabel();
31213550Sjoerg	else
31313544Sjoerg		dp = getdiskbyname(type);
31436632Scharnier	if (dp == NULL)
31536632Scharnier		errx(1, "%s: unknown disk type", type);
3161558Srgrimes	*lp = *dp;
3171558Srgrimes	bzero(lp->d_packname, sizeof(lp->d_packname));
3181558Srgrimes	if (name)
3191558Srgrimes		(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
3201558Srgrimes}
3211558Srgrimes
32213544Sjoergint
32392541Simpwritelabel(int f, const char *boot, struct disklabel *lp)
3241558Srgrimes{
32538384Sdfr#ifdef __alpha__
32638384Sdfr	u_long *p, sum;
32738384Sdfr	int i;
32838384Sdfr#endif
32938384Sdfr
33073034Sjwd	if (disable_write) {
33173034Sjwd		Warning("write to disk label supressed - label was as follows:");
33273034Sjwd		display(stdout, lp);
33373034Sjwd		return (0);
334109878Sphk	}
335109878Sphk
336109878Sphk	lp->d_magic = DISKMAGIC;
337109878Sphk	lp->d_magic2 = DISKMAGIC;
338109878Sphk	lp->d_checksum = 0;
339109878Sphk	lp->d_checksum = dkcksum(lp);
340109878Sphk	if (!rflag) {
341109878Sphk		if (ioctl(f, DIOCWDINFO, lp) < 0) {
342109878Sphk			l_perror("ioctl DIOCWDINFO");
343109878Sphk			return (1);
344109878Sphk		}
345109878Sphk		return (0);
346109878Sphk	}
347109878Sphk
348109878Sphk	/*
349109878Sphk	 * First set the kernel disk label,
350109878Sphk	 * then write a label to the raw disk.
351109878Sphk	 * If the SDINFO ioctl fails because it is unimplemented,
352109878Sphk	 * keep going; otherwise, the kernel consistency checks
353109878Sphk	 * may prevent us from changing the current (in-core)
354109878Sphk	 * label.
355109878Sphk	 */
356109878Sphk	if (ioctl(f, DIOCSDINFO, lp) < 0 &&
357109878Sphk		errno != ENODEV && errno != ENOTTY) {
358109878Sphk		l_perror("ioctl DIOCSDINFO");
359109878Sphk		return (1);
360109878Sphk	}
361109878Sphk	(void)lseek(f, (off_t)0, SEEK_SET);
362109878Sphk
36338411Sbde#ifdef __alpha__
364109878Sphk	/*
365109878Sphk	 * Generate the bootblock checksum for the SRM console.
366109878Sphk	 */
367109878Sphk	for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
368109878Sphk		sum += p[i];
369109878Sphk	p[63] = sum;
37038384Sdfr#endif
371109901Sphk	if (ioctl(f, DIOCBSDBB, &boot) == 0)
372109901Sphk		return (0);
373109878Sphk	if (write(f, boot, lp->d_bbsize) != (int)lp->d_bbsize) {
374109878Sphk		warn("write");
375109878Sphk		return (1);
376109878Sphk	}
3771558Srgrimes	return (0);
3781558Srgrimes}
3791558Srgrimes
38013544Sjoergvoid
38192541Simpl_perror(const char *s)
3821558Srgrimes{
38336632Scharnier	switch (errno) {
3841558Srgrimes
3851558Srgrimes	case ESRCH:
38636756Scharnier		warnx("%s: no disk label on disk;", s);
38775915Simp		fprintf(stderr, "add \"-r\" to install initial label\n");
3881558Srgrimes		break;
3891558Srgrimes
3901558Srgrimes	case EINVAL:
39136756Scharnier		warnx("%s: label magic number or checksum is wrong!", s);
39236756Scharnier		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
3931558Srgrimes		break;
3941558Srgrimes
3951558Srgrimes	case EBUSY:
39636632Scharnier		warnx("%s: open partition would move or shrink", s);
3971558Srgrimes		break;
3981558Srgrimes
3991558Srgrimes	case EXDEV:
40040475Sbde		warnx("%s: '%c' partition must start at beginning of disk",
40140475Sbde		    s, 'a' + RAW_PART);
4021558Srgrimes		break;
4031558Srgrimes
4041558Srgrimes	default:
40536632Scharnier		warn((char *)NULL);
4061558Srgrimes		break;
4071558Srgrimes	}
4081558Srgrimes}
4091558Srgrimes
4101558Srgrimes/*
4111558Srgrimes * Fetch disklabel for disk.
4121558Srgrimes * Use ioctl to get label unless -r flag is given.
4131558Srgrimes */
4141558Srgrimesstruct disklabel *
41592541Simpreadlabel(int f)
4161558Srgrimes{
41792541Simp	struct disklabel *lp;
4181558Srgrimes
4191558Srgrimes	if (rflag) {
4201558Srgrimes		if (read(f, bootarea, BBSIZE) < BBSIZE)
42126542Scharnier			err(4, "%s", specname);
4221558Srgrimes		for (lp = (struct disklabel *)bootarea;
4231558Srgrimes		    lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
4241558Srgrimes		    lp = (struct disklabel *)((char *)lp + 16))
4251558Srgrimes			if (lp->d_magic == DISKMAGIC &&
4261558Srgrimes			    lp->d_magic2 == DISKMAGIC)
4271558Srgrimes				break;
4281558Srgrimes		if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
4291558Srgrimes		    lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
43036756Scharnier		    dkcksum(lp) != 0)
43136756Scharnier			errx(1,
43236756Scharnier	    "bad pack magic number (label is damaged, or pack is unlabeled)");
4331558Srgrimes	} else {
4341558Srgrimes		lp = &lab;
4351558Srgrimes		if (ioctl(f, DIOCGDINFO, lp) < 0)
43626542Scharnier			err(4, "ioctl DIOCGDINFO");
4371558Srgrimes	}
4381558Srgrimes	return (lp);
4391558Srgrimes}
4401558Srgrimes
4411558Srgrimes/*
4421558Srgrimes * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
4431558Srgrimes * Returns a pointer to the disklabel portion of the bootarea.
4441558Srgrimes */
4451558Srgrimesstruct disklabel *
44692541Simpmakebootarea(char *boot, struct disklabel *dp, int f)
4471558Srgrimes{
44838483Sbde	struct disklabel *lp;
44992541Simp	char *p;
4501558Srgrimes	int b;
4511558Srgrimes	char *dkbasename;
4521558Srgrimes	struct stat sb;
45338411Sbde#ifdef __alpha__
45438483Sbde	u_long *bootinfo;
45538411Sbde	int n;
45638411Sbde#endif
45713892Sjoerg#ifdef __i386__
45813892Sjoerg	char *tmpbuf;
459109889Sphk	int i, found, dps;
46013544Sjoerg#endif
4611558Srgrimes
4621558Srgrimes	/* XXX */
4631558Srgrimes	if (dp->d_secsize == 0) {
4641558Srgrimes		dp->d_secsize = DEV_BSIZE;
4651558Srgrimes		dp->d_bbsize = BBSIZE;
4661558Srgrimes	}
4671558Srgrimes	lp = (struct disklabel *)
4681558Srgrimes		(boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
4691558Srgrimes	bzero((char *)lp, sizeof *lp);
4701558Srgrimes	/*
4711558Srgrimes	 * If we are not installing a boot program but we are installing a
4721558Srgrimes	 * label on disk then we must read the current bootarea so we don't
4731558Srgrimes	 * clobber the existing boot.
4741558Srgrimes	 */
4751558Srgrimes	if (!installboot) {
4761558Srgrimes		if (rflag) {
4771558Srgrimes			if (read(f, boot, BBSIZE) < BBSIZE)
47826542Scharnier				err(4, "%s", specname);
4791558Srgrimes			bzero((char *)lp, sizeof *lp);
4801558Srgrimes		}
4811558Srgrimes		return (lp);
4821558Srgrimes	}
4831558Srgrimes	/*
4841558Srgrimes	 * We are installing a boot program.  Determine the name(s) and
4851558Srgrimes	 * read them into the appropriate places in the boot area.
4861558Srgrimes	 */
487109889Sphk	if (!xxboot) {
4881558Srgrimes		dkbasename = np;
4891558Srgrimes		if ((p = rindex(dkname, '/')) == NULL)
4901558Srgrimes			p = dkname;
4911558Srgrimes		else
4921558Srgrimes			p++;
4931558Srgrimes		while (*p && !isdigit(*p))
4941558Srgrimes			*np++ = *p++;
4951558Srgrimes		*np++ = '\0';
4961558Srgrimes
4971558Srgrimes		if (!xxboot) {
498109889Sphk			(void)sprintf(boot0, "%s/boot", _PATH_BOOTDIR);
49941901Sjkh			xxboot = boot0;
5001558Srgrimes		}
5011558Srgrimes	}
5021558Srgrimes
5031558Srgrimes	b = open(xxboot, O_RDONLY);
5041558Srgrimes	if (b < 0)
50526542Scharnier		err(4, "%s", xxboot);
506109889Sphk	if (fstat(b, &sb) != 0)
507109889Sphk		err(4, "%s", xxboot);
50813892Sjoerg#ifdef __i386__
509109889Sphk	if (sb.st_size > BBSIZE)
510109889Sphk		errx(4, "%s too large", xxboot);
51113892Sjoerg	/*
51213892Sjoerg	 * XXX Botch alert.
513109889Sphk	 * The i386/PC98 has the so-called fdisk table embedded into the
51413892Sjoerg	 * primary bootstrap.  We take care to not clobber it, but
51513892Sjoerg	 * only if it does already contain some data.  (Otherwise,
51613892Sjoerg	 * the xxboot provides a template.)
51713892Sjoerg	 */
51813892Sjoerg	if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
51926542Scharnier		err(4, "%s", xxboot);
52013892Sjoerg	memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
521109889Sphk
522109889Sphk	if (read(b, boot, BBSIZE) < 0)
52326542Scharnier		err(4, "%s", xxboot);
524109889Sphk
525109889Sphk	/* XXX: rely on some very precise overlaps in definitions */
526108650Snyan#ifdef PC98
527109889Sphk	dps = sizeof(struct pc98_partition);
528109889Sphk#else
529109889Sphk	dps = sizeof(struct dos_partition);
530109889Sphk#endif
53113892Sjoerg	for (i = DOSPARTOFF, found = 0;
532109889Sphk	     !found && i < (int)(DOSPARTOFF + NDOSPART * dps);
533108650Snyan	     i++)
534108650Snyan		found = tmpbuf[i] != 0;
535108650Snyan	if (found)
536108650Snyan		memcpy((void *)&boot[DOSPARTOFF],
537108650Snyan		       (void *)&tmpbuf[DOSPARTOFF],
538109889Sphk		       NDOSPART * dps);
539108650Snyan	free(tmpbuf);
54097553Salfred#endif /* __i386__ */
541109889Sphk
54238384Sdfr#ifdef __alpha__
543109889Sphk	if (sb.st_size > BBSIZE - dp->d_secsize)
544109889Sphk		errx(4, "%s too large", xxboot);
54538411Sbde	/*
54638411Sbde	 * On the alpha, the primary bootstrap starts at the
54738411Sbde	 * second sector of the boot area.  The first sector
54838411Sbde	 * contains the label and must be edited to contain the
54938411Sbde	 * size and location of the primary bootstrap.
55038411Sbde	 */
551109889Sphk	n = read(b, boot + dp->d_secsize, BBSIZE - dp->d_secsize);
55238411Sbde	if (n < 0)
55338384Sdfr		err(4, "%s", xxboot);
55438483Sbde	bootinfo = (u_long *)(boot + 480);
55538483Sbde	bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
55638483Sbde	bootinfo[1] = 1;	/* start at sector 1 */
55738483Sbde	bootinfo[2] = 0;	/* flags (must be zero) */
55838411Sbde#endif /* __alpha__ */
559109889Sphk
5601558Srgrimes	(void)close(b);
5611558Srgrimes	/*
5621558Srgrimes	 * Make sure no part of the bootstrap is written in the area
5631558Srgrimes	 * reserved for the label.
5641558Srgrimes	 */
5651558Srgrimes	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
56636632Scharnier		if (*p)
56736632Scharnier			errx(2, "bootstrap doesn't leave room for disk label");
5681558Srgrimes	return (lp);
5691558Srgrimes}
5701558Srgrimes
57113544Sjoergvoid
57292541Simpdisplay(FILE *f, const struct disklabel *lp)
5731558Srgrimes{
57492541Simp	int i, j;
57592541Simp	const struct partition *pp;
5761558Srgrimes
5771558Srgrimes	fprintf(f, "# %s:\n", specname);
578107041Sjulian	if (lp->d_type < DKMAXTYPES)
5791558Srgrimes		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
5801558Srgrimes	else
58137234Sbde		fprintf(f, "type: %u\n", lp->d_type);
58213544Sjoerg	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
58313544Sjoerg		lp->d_typename);
58413544Sjoerg	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
58513544Sjoerg		lp->d_packname);
5861558Srgrimes	fprintf(f, "flags:");
5871558Srgrimes	if (lp->d_flags & D_REMOVABLE)
5881558Srgrimes		fprintf(f, " removeable");
5891558Srgrimes	if (lp->d_flags & D_ECC)
5901558Srgrimes		fprintf(f, " ecc");
5911558Srgrimes	if (lp->d_flags & D_BADSECT)
5921558Srgrimes		fprintf(f, " badsect");
5931558Srgrimes	fprintf(f, "\n");
59437234Sbde	fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
59537234Sbde	fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
59637234Sbde	fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
59737234Sbde	fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
59837234Sbde	fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
59937234Sbde	fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
60037234Sbde	fprintf(f, "rpm: %u\n", lp->d_rpm);
60137234Sbde	fprintf(f, "interleave: %u\n", lp->d_interleave);
60237234Sbde	fprintf(f, "trackskew: %u\n", lp->d_trackskew);
60337234Sbde	fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
60437234Sbde	fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
60537234Sbde	    (u_long)lp->d_headswitch);
60613544Sjoerg	fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
60737234Sbde	    (u_long)lp->d_trkseek);
6081558Srgrimes	fprintf(f, "drivedata: ");
6091558Srgrimes	for (i = NDDATA - 1; i >= 0; i--)
6101558Srgrimes		if (lp->d_drivedata[i])
6111558Srgrimes			break;
6121558Srgrimes	if (i < 0)
6131558Srgrimes		i = 0;
6141558Srgrimes	for (j = 0; j <= i; j++)
61537234Sbde		fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
61637234Sbde	fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
6171558Srgrimes	fprintf(f,
6185393Sgibbs	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
6191558Srgrimes	pp = lp->d_partitions;
6201558Srgrimes	for (i = 0; i < lp->d_npartitions; i++, pp++) {
6211558Srgrimes		if (pp->p_size) {
62237234Sbde			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
62337234Sbde			   (u_long)pp->p_size, (u_long)pp->p_offset);
624107041Sjulian			if (pp->p_fstype < FSMAXTYPES)
6251558Srgrimes				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
6261558Srgrimes			else
6271558Srgrimes				fprintf(f, "%8d", pp->p_fstype);
6281558Srgrimes			switch (pp->p_fstype) {
6291558Srgrimes
6301558Srgrimes			case FS_UNUSED:				/* XXX */
63137234Sbde				fprintf(f, "    %5lu %5lu %5.5s ",
63237234Sbde				    (u_long)pp->p_fsize,
63337234Sbde				    (u_long)(pp->p_fsize * pp->p_frag), "");
6341558Srgrimes				break;
6351558Srgrimes
6361558Srgrimes			case FS_BSDFFS:
63737234Sbde				fprintf(f, "    %5lu %5lu %5u ",
63837234Sbde				    (u_long)pp->p_fsize,
63937234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
6401558Srgrimes				    pp->p_cpg);
6411558Srgrimes				break;
6421558Srgrimes
6435393Sgibbs			case FS_BSDLFS:
64437234Sbde				fprintf(f, "    %5lu %5lu %5d",
64537234Sbde				    (u_long)pp->p_fsize,
64637234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
6475393Sgibbs				    pp->p_cpg);
6485393Sgibbs				break;
6495393Sgibbs
6501558Srgrimes			default:
6511558Srgrimes				fprintf(f, "%20.20s", "");
6521558Srgrimes				break;
6531558Srgrimes			}
65437234Sbde			fprintf(f, "\t# (Cyl. %4lu",
65537234Sbde			    (u_long)(pp->p_offset / lp->d_secpercyl));
6561558Srgrimes			if (pp->p_offset % lp->d_secpercyl)
6571558Srgrimes			    putc('*', f);
6581558Srgrimes			else
6591558Srgrimes			    putc(' ', f);
66037234Sbde			fprintf(f, "- %lu",
66137234Sbde			    (u_long)((pp->p_offset + pp->p_size +
66237234Sbde			    lp->d_secpercyl - 1) /
66337234Sbde			    lp->d_secpercyl - 1));
6641558Srgrimes			if (pp->p_size % lp->d_secpercyl)
6651558Srgrimes			    putc('*', f);
6661558Srgrimes			fprintf(f, ")\n");
6671558Srgrimes		}
6681558Srgrimes	}
6691558Srgrimes	fflush(f);
6701558Srgrimes}
6711558Srgrimes
67213544Sjoergint
67392541Simpedit(struct disklabel *lp, int f)
6741558Srgrimes{
67592541Simp	int c, fd;
6761558Srgrimes	struct disklabel label;
67724180Simp	FILE *fp;
6781558Srgrimes
67924180Simp	if ((fd = mkstemp(tmpfil)) == -1 ||
68024180Simp	    (fp = fdopen(fd, "w")) == NULL) {
68136632Scharnier		warnx("can't create %s", tmpfil);
6821558Srgrimes		return (1);
6831558Srgrimes	}
68424180Simp	display(fp, lp);
68524180Simp	fclose(fp);
6861558Srgrimes	for (;;) {
6871558Srgrimes		if (!editit())
6881558Srgrimes			break;
68924180Simp		fp = fopen(tmpfil, "r");
69024180Simp		if (fp == NULL) {
69136632Scharnier			warnx("can't reopen %s for reading", tmpfil);
6921558Srgrimes			break;
6931558Srgrimes		}
6941558Srgrimes		bzero((char *)&label, sizeof(label));
69524180Simp		if (getasciilabel(fp, &label)) {
6961558Srgrimes			*lp = label;
6971558Srgrimes			if (writelabel(f, bootarea, lp) == 0) {
69824180Simp				fclose(fp);
6991558Srgrimes				(void) unlink(tmpfil);
7001558Srgrimes				return (0);
7011558Srgrimes			}
7021558Srgrimes		}
70324180Simp		fclose(fp);
7041558Srgrimes		printf("re-edit the label? [y]: "); fflush(stdout);
7051558Srgrimes		c = getchar();
7061558Srgrimes		if (c != EOF && c != (int)'\n')
7071558Srgrimes			while (getchar() != (int)'\n')
7081558Srgrimes				;
7091558Srgrimes		if  (c == (int)'n')
7101558Srgrimes			break;
7111558Srgrimes	}
7121558Srgrimes	(void) unlink(tmpfil);
7131558Srgrimes	return (1);
7141558Srgrimes}
7151558Srgrimes
71613544Sjoergint
71792541Simpeditit(void)
7181558Srgrimes{
71992541Simp	int pid, xpid;
72099365Smarkm	int locstat, omask;
72199365Smarkm	const char *ed;
7221558Srgrimes
7231558Srgrimes	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
7241558Srgrimes	while ((pid = fork()) < 0) {
7251558Srgrimes		if (errno == EPROCLIM) {
72636632Scharnier			warnx("you have too many processes");
7271558Srgrimes			return(0);
7281558Srgrimes		}
7291558Srgrimes		if (errno != EAGAIN) {
73036632Scharnier			warn("fork");
7311558Srgrimes			return(0);
7321558Srgrimes		}
7331558Srgrimes		sleep(1);
7341558Srgrimes	}
7351558Srgrimes	if (pid == 0) {
7361558Srgrimes		sigsetmask(omask);
7371558Srgrimes		setgid(getgid());
7381558Srgrimes		setuid(getuid());
7391558Srgrimes		if ((ed = getenv("EDITOR")) == (char *)0)
7401558Srgrimes			ed = DEFEDITOR;
74179452Sbrian		execlp(ed, ed, tmpfil, (char *)0);
74236632Scharnier		err(1, "%s", ed);
7431558Srgrimes	}
74499365Smarkm	while ((xpid = wait(&locstat)) >= 0)
7451558Srgrimes		if (xpid == pid)
7461558Srgrimes			break;
7471558Srgrimes	sigsetmask(omask);
74899365Smarkm	return(!locstat);
7491558Srgrimes}
7501558Srgrimes
7511558Srgrimeschar *
75292541Simpskip(char *cp)
7531558Srgrimes{
7541558Srgrimes
7551558Srgrimes	while (*cp != '\0' && isspace(*cp))
7561558Srgrimes		cp++;
7571558Srgrimes	if (*cp == '\0' || *cp == '#')
75892541Simp		return (NULL);
7591558Srgrimes	return (cp);
7601558Srgrimes}
7611558Srgrimes
7621558Srgrimeschar *
76392541Simpword(char *cp)
7641558Srgrimes{
76592541Simp	char c;
7661558Srgrimes
7671558Srgrimes	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
7681558Srgrimes		cp++;
7691558Srgrimes	if ((c = *cp) != '\0') {
7701558Srgrimes		*cp++ = '\0';
7711558Srgrimes		if (c != '#')
7721558Srgrimes			return (skip(cp));
7731558Srgrimes	}
77492541Simp	return (NULL);
7751558Srgrimes}
7761558Srgrimes
7771558Srgrimes/*
7781558Srgrimes * Read an ascii label in from fd f,
7791558Srgrimes * in the same format as that put out by display(),
7801558Srgrimes * and fill in lp.
7811558Srgrimes */
78213544Sjoergint
78392541Simpgetasciilabel(FILE *f, struct disklabel *lp)
7841558Srgrimes{
78594065Sphk	char *cp;
78694065Sphk	const char **cpp;
787107041Sjulian	u_int part;
78894065Sphk	char *tp, line[BUFSIZ];
789107041Sjulian	u_long v;
790107041Sjulian	int lineno = 0, errors = 0;
79192541Simp	int i;
7921558Srgrimes
793109378Sdes	bzero(&part_set, sizeof(part_set));
794109378Sdes	bzero(&part_size_type, sizeof(part_size_type));
795109378Sdes	bzero(&part_offset_type, sizeof(part_offset_type));
7961558Srgrimes	lp->d_bbsize = BBSIZE;				/* XXX */
79796475Sphk	lp->d_sbsize = 0;				/* XXX */
7981558Srgrimes	while (fgets(line, sizeof(line) - 1, f)) {
7991558Srgrimes		lineno++;
80013544Sjoerg		if ((cp = index(line,'\n')) != 0)
8011558Srgrimes			*cp = '\0';
8021558Srgrimes		cp = skip(line);
8031558Srgrimes		if (cp == NULL)
8041558Srgrimes			continue;
8051558Srgrimes		tp = index(cp, ':');
8061558Srgrimes		if (tp == NULL) {
8071558Srgrimes			fprintf(stderr, "line %d: syntax error\n", lineno);
8081558Srgrimes			errors++;
8091558Srgrimes			continue;
8101558Srgrimes		}
8111558Srgrimes		*tp++ = '\0', tp = skip(tp);
8121558Srgrimes		if (streq(cp, "type")) {
8131558Srgrimes			if (tp == NULL)
81499365Smarkm				tp = unknown;
8151558Srgrimes			cpp = dktypenames;
8161558Srgrimes			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
81794065Sphk				if (*cpp && streq(*cpp, tp)) {
8181558Srgrimes					lp->d_type = cpp - dktypenames;
81997855Siedowse					break;
8201558Srgrimes				}
82197855Siedowse			if (cpp < &dktypenames[DKMAXTYPES])
82297855Siedowse				continue;
823107041Sjulian			v = strtoul(tp, NULL, 10);
824107041Sjulian			if (v >= DKMAXTYPES)
825107041Sjulian				fprintf(stderr, "line %d:%s %lu\n", lineno,
8261558Srgrimes				    "Warning, unknown disk type", v);
8271558Srgrimes			lp->d_type = v;
8281558Srgrimes			continue;
8291558Srgrimes		}
8301558Srgrimes		if (streq(cp, "flags")) {
8311558Srgrimes			for (v = 0; (cp = tp) && *cp != '\0';) {
8321558Srgrimes				tp = word(cp);
8331558Srgrimes				if (streq(cp, "removeable"))
8341558Srgrimes					v |= D_REMOVABLE;
8351558Srgrimes				else if (streq(cp, "ecc"))
8361558Srgrimes					v |= D_ECC;
8371558Srgrimes				else if (streq(cp, "badsect"))
8381558Srgrimes					v |= D_BADSECT;
8391558Srgrimes				else {
8401558Srgrimes					fprintf(stderr,
8411558Srgrimes					    "line %d: %s: bad flag\n",
8421558Srgrimes					    lineno, cp);
8431558Srgrimes					errors++;
8441558Srgrimes				}
8451558Srgrimes			}
8461558Srgrimes			lp->d_flags = v;
8471558Srgrimes			continue;
8481558Srgrimes		}
8491558Srgrimes		if (streq(cp, "drivedata")) {
8501558Srgrimes			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
851107041Sjulian				lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
8521558Srgrimes				tp = word(cp);
8531558Srgrimes			}
8541558Srgrimes			continue;
8551558Srgrimes		}
856107041Sjulian		if (sscanf(cp, "%lu partitions", &v) == 1) {
857107041Sjulian			if (v == 0 || v > MAXPARTITIONS) {
8581558Srgrimes				fprintf(stderr,
8591558Srgrimes				    "line %d: bad # of partitions\n", lineno);
8601558Srgrimes				lp->d_npartitions = MAXPARTITIONS;
8611558Srgrimes				errors++;
8621558Srgrimes			} else
8631558Srgrimes				lp->d_npartitions = v;
8641558Srgrimes			continue;
8651558Srgrimes		}
8661558Srgrimes		if (tp == NULL)
86799365Smarkm			tp = blank;
8681558Srgrimes		if (streq(cp, "disk")) {
8691558Srgrimes			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
8701558Srgrimes			continue;
8711558Srgrimes		}
8721558Srgrimes		if (streq(cp, "label")) {
8731558Srgrimes			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
8741558Srgrimes			continue;
8751558Srgrimes		}
8761558Srgrimes		if (streq(cp, "bytes/sector")) {
877107041Sjulian			v = strtoul(tp, NULL, 10);
878107041Sjulian			if (v == 0 || (v % DEV_BSIZE) != 0) {
8791558Srgrimes				fprintf(stderr,
8801558Srgrimes				    "line %d: %s: bad sector size\n",
8811558Srgrimes				    lineno, tp);
8821558Srgrimes				errors++;
8831558Srgrimes			} else
8841558Srgrimes				lp->d_secsize = v;
8851558Srgrimes			continue;
8861558Srgrimes		}
8871558Srgrimes		if (streq(cp, "sectors/track")) {
888107041Sjulian			v = strtoul(tp, NULL, 10);
889107041Sjulian#if (ULONG_MAX != 0xffffffffUL)
890107041Sjulian			if (v == 0 || v > 0xffffffff) {
891107041Sjulian#else
892107041Sjulian			if (v == 0) {
893107041Sjulian#endif
8941558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8951558Srgrimes				    lineno, tp, cp);
8961558Srgrimes				errors++;
8971558Srgrimes			} else
8981558Srgrimes				lp->d_nsectors = v;
8991558Srgrimes			continue;
9001558Srgrimes		}
9011558Srgrimes		if (streq(cp, "sectors/cylinder")) {
902107041Sjulian			v = strtoul(tp, NULL, 10);
903107041Sjulian			if (v == 0) {
9041558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9051558Srgrimes				    lineno, tp, cp);
9061558Srgrimes				errors++;
9071558Srgrimes			} else
9081558Srgrimes				lp->d_secpercyl = v;
9091558Srgrimes			continue;
9101558Srgrimes		}
9111558Srgrimes		if (streq(cp, "tracks/cylinder")) {
912107041Sjulian			v = strtoul(tp, NULL, 10);
913107041Sjulian			if (v == 0) {
9141558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9151558Srgrimes				    lineno, tp, cp);
9161558Srgrimes				errors++;
9171558Srgrimes			} else
9181558Srgrimes				lp->d_ntracks = v;
9191558Srgrimes			continue;
9201558Srgrimes		}
9211558Srgrimes		if (streq(cp, "cylinders")) {
922107041Sjulian			v = strtoul(tp, NULL, 10);
923107041Sjulian			if (v == 0) {
9241558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9251558Srgrimes				    lineno, tp, cp);
9261558Srgrimes				errors++;
9271558Srgrimes			} else
9281558Srgrimes				lp->d_ncylinders = v;
9291558Srgrimes			continue;
9301558Srgrimes		}
9316643Sbde		if (streq(cp, "sectors/unit")) {
932107041Sjulian			v = strtoul(tp, NULL, 10);
933107041Sjulian			if (v == 0) {
9346643Sbde				fprintf(stderr, "line %d: %s: bad %s\n",
9356643Sbde				    lineno, tp, cp);
9366643Sbde				errors++;
9376643Sbde			} else
9386643Sbde				lp->d_secperunit = v;
9396643Sbde			continue;
9406643Sbde		}
9411558Srgrimes		if (streq(cp, "rpm")) {
942107041Sjulian			v = strtoul(tp, NULL, 10);
943107041Sjulian			if (v == 0 || v > USHRT_MAX) {
9441558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9451558Srgrimes				    lineno, tp, cp);
9461558Srgrimes				errors++;
9471558Srgrimes			} else
9481558Srgrimes				lp->d_rpm = v;
9491558Srgrimes			continue;
9501558Srgrimes		}
9511558Srgrimes		if (streq(cp, "interleave")) {
952107041Sjulian			v = strtoul(tp, NULL, 10);
953107041Sjulian			if (v == 0 || v > USHRT_MAX) {
9541558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9551558Srgrimes				    lineno, tp, cp);
9561558Srgrimes				errors++;
9571558Srgrimes			} else
9581558Srgrimes				lp->d_interleave = v;
9591558Srgrimes			continue;
9601558Srgrimes		}
9611558Srgrimes		if (streq(cp, "trackskew")) {
962107041Sjulian			v = strtoul(tp, NULL, 10);
963107041Sjulian			if (v > USHRT_MAX) {
9641558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9651558Srgrimes				    lineno, tp, cp);
9661558Srgrimes				errors++;
9671558Srgrimes			} else
9681558Srgrimes				lp->d_trackskew = v;
9691558Srgrimes			continue;
9701558Srgrimes		}
9711558Srgrimes		if (streq(cp, "cylinderskew")) {
972107041Sjulian			v = strtoul(tp, NULL, 10);
973107041Sjulian			if (v > USHRT_MAX) {
9741558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9751558Srgrimes				    lineno, tp, cp);
9761558Srgrimes				errors++;
9771558Srgrimes			} else
9781558Srgrimes				lp->d_cylskew = v;
9791558Srgrimes			continue;
9801558Srgrimes		}
9811558Srgrimes		if (streq(cp, "headswitch")) {
982107041Sjulian			v = strtoul(tp, NULL, 10);
983107041Sjulian			lp->d_headswitch = v;
9841558Srgrimes			continue;
9851558Srgrimes		}
9861558Srgrimes		if (streq(cp, "track-to-track seek")) {
987107041Sjulian			v = strtoul(tp, NULL, 10);
988107041Sjulian			lp->d_trkseek = v;
9891558Srgrimes			continue;
9901558Srgrimes		}
99173034Sjwd		/* the ':' was removed above */
99297534Siedowse		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
99397534Siedowse			fprintf(stderr,
99497534Siedowse			    "line %d: %s: Unknown disklabel field\n", lineno,
99597534Siedowse			    cp);
99697534Siedowse			errors++;
99797534Siedowse			continue;
99897534Siedowse		}
99997534Siedowse
100097534Siedowse		/* Process a partition specification line. */
100197534Siedowse		part = *cp - 'a';
100297534Siedowse		if (part >= lp->d_npartitions) {
100397534Siedowse			fprintf(stderr,
100497534Siedowse			    "line %d: partition name out of range a-%c: %s\n",
100597534Siedowse			    lineno, 'a' + lp->d_npartitions - 1, cp);
100697534Siedowse			errors++;
100797534Siedowse			continue;
100897534Siedowse		}
100997534Siedowse		part_set[part] = 1;
101097534Siedowse
101197534Siedowse		if (getasciipartspec(tp, lp, part, lineno) != 0) {
101297534Siedowse			errors++;
101397534Siedowse			break;
101497534Siedowse		}
101597534Siedowse	}
101697534Siedowse	errors += checklabel(lp);
101797534Siedowse	return (errors == 0);
101897534Siedowse}
101997534Siedowse
102097534Siedowse#define NXTNUM(n) do { \
10213111Spst	if (tp == NULL) { \
10223111Spst		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
102397534Siedowse		return (1); \
10243111Spst	} else { \
10253111Spst		cp = tp, tp = word(cp); \
1026107041Sjulian		(n) = strtoul(cp, NULL, 10); \
10273111Spst	} \
102897534Siedowse} while (0)
102997534Siedowse
103073034Sjwd/* retain 1 character following number */
103197534Siedowse#define NXTWORD(w,n) do { \
103273034Sjwd	if (tp == NULL) { \
103373034Sjwd		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
103497534Siedowse		return (1); \
103573034Sjwd	} else { \
103673034Sjwd	        char *tmp; \
103773034Sjwd		cp = tp, tp = word(cp); \
1038107041Sjulian	        (n) = strtoul(cp, &tmp, 10); \
103973034Sjwd		if (tmp) (w) = *tmp; \
104073034Sjwd	} \
104197534Siedowse} while (0)
10421558Srgrimes
104397534Siedowse/*
104497534Siedowse * Read a partition line into partition `part' in the specified disklabel.
104597534Siedowse * Return 0 on success, 1 on failure.
104697534Siedowse */
104797534Siedowseint
104897534Siedowsegetasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
104997534Siedowse{
105097534Siedowse	struct partition *pp;
105197534Siedowse	char *cp;
105297534Siedowse	const char **cpp;
1053107041Sjulian	u_long v;
10541558Srgrimes
105597534Siedowse	pp = &lp->d_partitions[part];
105697534Siedowse	cp = NULL;
10571558Srgrimes
105897534Siedowse	v = 0;
105997534Siedowse	NXTWORD(part_size_type[part],v);
1060107041Sjulian	if (v == 0 && part_size_type[part] != '*') {
1061107041Sjulian		fprintf(stderr,
1062107041Sjulian		    "line %d: %s: bad partition size\n", lineno, cp);
106397534Siedowse		return (1);
106497534Siedowse	}
106597534Siedowse	pp->p_size = v;
106697534Siedowse
106797534Siedowse	v = 0;
106897534Siedowse	NXTWORD(part_offset_type[part],v);
1069107041Sjulian	if (v == 0 && part_offset_type[part] != '*' &&
1070107041Sjulian	    part_offset_type[part] != '\0') {
1071107041Sjulian		fprintf(stderr,
1072107041Sjulian		    "line %d: %s: bad partition offset\n", lineno, cp);
107397534Siedowse		return (1);
107497534Siedowse	}
107597534Siedowse	pp->p_offset = v;
107697534Siedowse	cp = tp, tp = word(cp);
107797534Siedowse	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
107897534Siedowse		if (*cpp && streq(*cpp, cp))
107997534Siedowse			break;
108097534Siedowse	if (*cpp != NULL) {
108197534Siedowse		pp->p_fstype = cpp - fstypenames;
108297534Siedowse	} else {
108397534Siedowse		if (isdigit(*cp))
1084107041Sjulian			v = strtoul(cp, NULL, 10);
108597534Siedowse		else
108697534Siedowse			v = FSMAXTYPES;
1087107041Sjulian		if (v >= FSMAXTYPES) {
108897534Siedowse			fprintf(stderr,
1089102231Strhodes			    "line %d: Warning, unknown file system type %s\n",
109097534Siedowse			    lineno, cp);
109197534Siedowse			v = FS_UNUSED;
109297534Siedowse		}
109397534Siedowse		pp->p_fstype = v;
109497534Siedowse	}
109597534Siedowse
109697534Siedowse	switch (pp->p_fstype) {
109797534Siedowse	case FS_UNUSED:
109897534Siedowse		/*
109997534Siedowse		 * allow us to accept defaults for
110097534Siedowse		 * fsize/frag/cpg
110197534Siedowse		 */
110297534Siedowse		if (tp) {
110397534Siedowse			NXTNUM(pp->p_fsize);
110497534Siedowse			if (pp->p_fsize == 0)
110597534Siedowse				break;
110697534Siedowse			NXTNUM(v);
110797534Siedowse			pp->p_frag = v / pp->p_fsize;
110897534Siedowse		}
110997534Siedowse		/* else default to 0's */
111097534Siedowse		break;
111197534Siedowse
111297534Siedowse	/* These happen to be the same */
111397534Siedowse	case FS_BSDFFS:
111497534Siedowse	case FS_BSDLFS:
111597534Siedowse		if (tp) {
111697534Siedowse			NXTNUM(pp->p_fsize);
111797534Siedowse			if (pp->p_fsize == 0)
111897534Siedowse				break;
111997534Siedowse			NXTNUM(v);
112097534Siedowse			pp->p_frag = v / pp->p_fsize;
112197534Siedowse			NXTNUM(pp->p_cpg);
112297534Siedowse		} else {
112397534Siedowse			/*
112497534Siedowse			 * FIX! poor attempt at adaptive
112597534Siedowse			 */
112697534Siedowse			/* 1 GB */
112797534Siedowse			if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
112897534Siedowse				/*
112997534Siedowse				 * FIX! These are too low, but are traditional
113097534Siedowse				 */
113197535Siedowse				pp->p_fsize = DEFAULT_NEWFS_FRAG;
113297535Siedowse				pp->p_frag = DEFAULT_NEWFS_BLOCK /
113397535Siedowse				    DEFAULT_NEWFS_FRAG;
113497534Siedowse				pp->p_cpg = DEFAULT_NEWFS_CPG;
113597534Siedowse			} else {
113697535Siedowse				pp->p_fsize = BIG_NEWFS_FRAG;
113797535Siedowse				pp->p_frag = BIG_NEWFS_BLOCK /
113897535Siedowse				    BIG_NEWFS_FRAG;
113997534Siedowse				pp->p_cpg = BIG_NEWFS_CPG;
11401558Srgrimes			}
11411558Srgrimes		}
114297534Siedowse	default:
114397534Siedowse		break;
11441558Srgrimes	}
114597534Siedowse	return (0);
11461558Srgrimes}
11471558Srgrimes
11481558Srgrimes/*
11491558Srgrimes * Check disklabel for errors and fill in
11501558Srgrimes * derived fields according to supplied values.
11511558Srgrimes */
115213544Sjoergint
115392541Simpchecklabel(struct disklabel *lp)
11541558Srgrimes{
115592541Simp	struct partition *pp;
11561558Srgrimes	int i, errors = 0;
11571558Srgrimes	char part;
1158107041Sjulian	u_long total_size, total_percent, current_offset;
115973034Sjwd	int seen_default_offset;
116073034Sjwd	int hog_part;
116173034Sjwd	int j;
116273034Sjwd	struct partition *pp2;
11631558Srgrimes
11641558Srgrimes	if (lp->d_secsize == 0) {
116537234Sbde		fprintf(stderr, "sector size 0\n");
11661558Srgrimes		return (1);
11671558Srgrimes	}
11681558Srgrimes	if (lp->d_nsectors == 0) {
116937234Sbde		fprintf(stderr, "sectors/track 0\n");
11701558Srgrimes		return (1);
11711558Srgrimes	}
11721558Srgrimes	if (lp->d_ntracks == 0) {
117337234Sbde		fprintf(stderr, "tracks/cylinder 0\n");
11741558Srgrimes		return (1);
11751558Srgrimes	}
11761558Srgrimes	if  (lp->d_ncylinders == 0) {
117737234Sbde		fprintf(stderr, "cylinders/unit 0\n");
11781558Srgrimes		errors++;
11791558Srgrimes	}
11801558Srgrimes	if (lp->d_rpm == 0)
118137234Sbde		Warning("revolutions/minute 0");
11821558Srgrimes	if (lp->d_secpercyl == 0)
11831558Srgrimes		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
11841558Srgrimes	if (lp->d_secperunit == 0)
11851558Srgrimes		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
11861558Srgrimes	if (lp->d_bbsize == 0) {
118737234Sbde		fprintf(stderr, "boot block size 0\n");
11881558Srgrimes		errors++;
11891558Srgrimes	} else if (lp->d_bbsize % lp->d_secsize)
11901558Srgrimes		Warning("boot block size %% sector-size != 0");
11911558Srgrimes	if (lp->d_npartitions > MAXPARTITIONS)
119237234Sbde		Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
119337234Sbde		    (u_long)lp->d_npartitions, MAXPARTITIONS);
119473034Sjwd
119573034Sjwd	/* first allocate space to the partitions, then offsets */
119673034Sjwd	total_size = 0; /* in sectors */
119773034Sjwd	total_percent = 0; /* in percent */
119873034Sjwd	hog_part = -1;
119973034Sjwd	/* find all fixed partitions */
12001558Srgrimes	for (i = 0; i < lp->d_npartitions; i++) {
120173034Sjwd		pp = &lp->d_partitions[i];
120273034Sjwd		if (part_set[i]) {
120373034Sjwd			if (part_size_type[i] == '*') {
120494065Sphk				if (i == RAW_PART) {
120573034Sjwd					pp->p_size = lp->d_secperunit;
120673034Sjwd				} else {
120773034Sjwd					if (hog_part != -1)
120873034Sjwd						Warning("Too many '*' partitions (%c and %c)",
120973034Sjwd						    hog_part + 'a',i + 'a');
121073034Sjwd					else
121173034Sjwd						hog_part = i;
121273034Sjwd				}
121373034Sjwd			} else {
121473573Simp				off_t size;
121573034Sjwd
121673034Sjwd				size = pp->p_size;
121773034Sjwd				switch (part_size_type[i]) {
121873034Sjwd				case '%':
121973034Sjwd					total_percent += size;
122073034Sjwd					break;
122173034Sjwd				case 'k':
122273034Sjwd				case 'K':
122373573Simp					size *= 1024ULL;
122473034Sjwd					break;
122573034Sjwd				case 'm':
122673034Sjwd				case 'M':
122773573Simp					size *= 1024ULL * 1024ULL;
122873034Sjwd					break;
122973034Sjwd				case 'g':
123073034Sjwd				case 'G':
123173573Simp					size *= 1024ULL * 1024ULL * 1024ULL;
123273034Sjwd					break;
123373034Sjwd				case '\0':
123473034Sjwd					break;
123573034Sjwd				default:
123673034Sjwd					Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
123773034Sjwd					break;
123873034Sjwd				}
123973034Sjwd				/* don't count %'s yet */
124073034Sjwd				if (part_size_type[i] != '%') {
124173034Sjwd					/*
124273034Sjwd					 * for all not in sectors, convert to
124373034Sjwd					 * sectors
124473034Sjwd					 */
124573034Sjwd					if (part_size_type[i] != '\0') {
124673034Sjwd						if (size % lp->d_secsize != 0)
124773034Sjwd							Warning("partition %c not an integer number of sectors",
124873034Sjwd							    i + 'a');
124973034Sjwd						size /= lp->d_secsize;
125073034Sjwd						pp->p_size = size;
125173034Sjwd					}
125273034Sjwd					/* else already in sectors */
125394065Sphk					if (i != RAW_PART)
125473034Sjwd						total_size += size;
125573034Sjwd				}
125673034Sjwd			}
125773034Sjwd		}
125873034Sjwd	}
125973034Sjwd	/* handle % partitions - note %'s don't need to add up to 100! */
126073034Sjwd	if (total_percent != 0) {
126173034Sjwd		long free_space = lp->d_secperunit - total_size;
126273034Sjwd		if (total_percent > 100) {
126394065Sphk			fprintf(stderr,"total percentage %lu is greater than 100\n",
126473034Sjwd			    total_percent);
126573034Sjwd			errors++;
126673034Sjwd		}
126773034Sjwd
126873034Sjwd		if (free_space > 0) {
126973034Sjwd			for (i = 0; i < lp->d_npartitions; i++) {
127073034Sjwd				pp = &lp->d_partitions[i];
127173034Sjwd				if (part_set[i] && part_size_type[i] == '%') {
127273034Sjwd					/* careful of overflows! and integer roundoff */
127373034Sjwd					pp->p_size = ((double)pp->p_size/100) * free_space;
127473034Sjwd					total_size += pp->p_size;
127573034Sjwd
127673034Sjwd					/* FIX we can lose a sector or so due to roundoff per
127773034Sjwd					   partition.  A more complex algorithm could avoid that */
127873034Sjwd				}
127973034Sjwd			}
128073034Sjwd		} else {
128173034Sjwd			fprintf(stderr,
128294065Sphk			    "%ld sectors available to give to '*' and '%%' partitions\n",
128373034Sjwd			    free_space);
128473034Sjwd			errors++;
128573034Sjwd			/* fix?  set all % partitions to size 0? */
128673034Sjwd		}
128773034Sjwd	}
128873034Sjwd	/* give anything remaining to the hog partition */
128973034Sjwd	if (hog_part != -1) {
129073034Sjwd		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
129173034Sjwd		total_size = lp->d_secperunit;
129273034Sjwd	}
129373034Sjwd
129473034Sjwd	/* Now set the offsets for each partition */
129573034Sjwd	current_offset = 0; /* in sectors */
129673034Sjwd	seen_default_offset = 0;
129773034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
12981558Srgrimes		part = 'a' + i;
12991558Srgrimes		pp = &lp->d_partitions[i];
130073034Sjwd		if (part_set[i]) {
130173034Sjwd			if (part_offset_type[i] == '*') {
130294065Sphk				if (i == RAW_PART) {
130373034Sjwd					pp->p_offset = 0;
130473034Sjwd				} else {
130573034Sjwd					pp->p_offset = current_offset;
130673034Sjwd					seen_default_offset = 1;
130773034Sjwd				}
130873034Sjwd			} else {
130973034Sjwd				/* allow them to be out of order for old-style tables */
131073034Sjwd				if (pp->p_offset < current_offset &&
1311107534Sgrog				    seen_default_offset && i != RAW_PART &&
1312107534Sgrog				    pp->p_fstype != FS_VINUM) {
131373034Sjwd					fprintf(stderr,
131494065Sphk"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
131594065Sphk					    (long)pp->p_offset,i+'a',current_offset);
131673034Sjwd					fprintf(stderr,
131773034Sjwd"Labels with any *'s for offset must be in ascending order by sector\n");
131873034Sjwd					errors++;
131973034Sjwd				} else if (pp->p_offset != current_offset &&
132094065Sphk				    i != RAW_PART && seen_default_offset) {
132173034Sjwd					/*
132273034Sjwd					 * this may give unneeded warnings if
132373034Sjwd					 * partitions are out-of-order
132473034Sjwd					 */
132573034Sjwd					Warning(
132673034Sjwd"Offset %ld for partition %c doesn't match expected value %ld",
132794065Sphk					    (long)pp->p_offset, i + 'a', current_offset);
132873034Sjwd				}
132973034Sjwd			}
133094065Sphk			if (i != RAW_PART)
133173034Sjwd				current_offset = pp->p_offset + pp->p_size;
133273034Sjwd		}
133373034Sjwd	}
133473034Sjwd
133573034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
133673034Sjwd		part = 'a' + i;
133773034Sjwd		pp = &lp->d_partitions[i];
13381558Srgrimes		if (pp->p_size == 0 && pp->p_offset != 0)
133937234Sbde			Warning("partition %c: size 0, but offset %lu",
134037234Sbde			    part, (u_long)pp->p_offset);
13411558Srgrimes#ifdef notdef
13421558Srgrimes		if (pp->p_size % lp->d_secpercyl)
13431558Srgrimes			Warning("partition %c: size %% cylinder-size != 0",
13441558Srgrimes			    part);
13451558Srgrimes		if (pp->p_offset % lp->d_secpercyl)
13461558Srgrimes			Warning("partition %c: offset %% cylinder-size != 0",
13471558Srgrimes			    part);
13481558Srgrimes#endif
13491558Srgrimes		if (pp->p_offset > lp->d_secperunit) {
13501558Srgrimes			fprintf(stderr,
13511558Srgrimes			    "partition %c: offset past end of unit\n", part);
13521558Srgrimes			errors++;
13531558Srgrimes		}
13541558Srgrimes		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
13551558Srgrimes			fprintf(stderr,
135613544Sjoerg			"partition %c: partition extends past end of unit\n",
13571558Srgrimes			    part);
13581558Srgrimes			errors++;
13591558Srgrimes		}
136094065Sphk		if (i == RAW_PART)
136173034Sjwd		{
136273034Sjwd			if (pp->p_fstype != FS_UNUSED)
136373034Sjwd				Warning("partition %c is not marked as unused!",part);
136473034Sjwd			if (pp->p_offset != 0)
136573034Sjwd				Warning("partition %c doesn't start at 0!",part);
136673034Sjwd			if (pp->p_size != lp->d_secperunit)
136773034Sjwd				Warning("partition %c doesn't cover the whole unit!",part);
136873034Sjwd
136973034Sjwd			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
137073034Sjwd			    (pp->p_size != lp->d_secperunit)) {
137173034Sjwd				Warning("An incorrect partition %c may cause problems for "
137273034Sjwd				    "standard system utilities",part);
137373034Sjwd			}
137473034Sjwd		}
137573034Sjwd
137673034Sjwd		/* check for overlaps */
137773034Sjwd		/* this will check for all possible overlaps once and only once */
137873034Sjwd		for (j = 0; j < i; j++) {
1379107534Sgrog			pp2 = &lp->d_partitions[j];
1380107534Sgrog			if (j != RAW_PART && i != RAW_PART &&
1381107534Sgrog			    pp->p_fstype != FS_VINUM &&
1382107534Sgrog			    pp2->p_fstype != FS_VINUM &&
138373034Sjwd			    part_set[i] && part_set[j]) {
138473034Sjwd				if (pp2->p_offset < pp->p_offset + pp->p_size &&
138573034Sjwd				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
138673034Sjwd					pp2->p_offset >= pp->p_offset)) {
138773034Sjwd					fprintf(stderr,"partitions %c and %c overlap!\n",
138873034Sjwd					    j + 'a', i + 'a');
138973034Sjwd					errors++;
139073034Sjwd				}
139173034Sjwd			}
139273034Sjwd		}
13931558Srgrimes	}
13941558Srgrimes	for (; i < MAXPARTITIONS; i++) {
13951558Srgrimes		part = 'a' + i;
13961558Srgrimes		pp = &lp->d_partitions[i];
13971558Srgrimes		if (pp->p_size || pp->p_offset)
139837234Sbde			Warning("unused partition %c: size %d offset %lu",
139937234Sbde			    'a' + i, pp->p_size, (u_long)pp->p_offset);
14001558Srgrimes	}
14011558Srgrimes	return (errors);
14021558Srgrimes}
14031558Srgrimes
14041558Srgrimes/*
140513550Sjoerg * When operating on a "virgin" disk, try getting an initial label
140613550Sjoerg * from the associated device driver.  This might work for all device
140713550Sjoerg * drivers that are able to fetch some initial device parameters
140813550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks,
140913550Sjoerg * most IDE drives, or vn devices.
141013550Sjoerg *
141113550Sjoerg * The device name must be given in its "canonical" form.
141213550Sjoerg */
141313550Sjoergstruct disklabel *
141413550Sjoerggetvirginlabel(void)
141513550Sjoerg{
141699365Smarkm	static struct disklabel loclab;
1417103669Sphk	struct partition *dp;
141899365Smarkm	char lnamebuf[BBSIZE];
141913550Sjoerg	int f;
1420103669Sphk	u_int secsize, u;
1421103669Sphk	off_t mediasize;
142213550Sjoerg
142313550Sjoerg	if (dkname[0] == '/') {
142437773Sbde		warnx("\"auto\" requires the usage of a canonical disk name");
142516431Sbde		return (NULL);
142613550Sjoerg	}
142799365Smarkm	(void)snprintf(lnamebuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
142899365Smarkm	if ((f = open(lnamebuf, O_RDONLY)) == -1) {
142999365Smarkm		warn("cannot open %s", lnamebuf);
143016431Sbde		return (NULL);
143113550Sjoerg	}
143268044Sjkh
1433103669Sphk	/* New world order */
1434103669Sphk	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
1435103669Sphk	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1436103669Sphk		close (f);
1437103669Sphk		return (NULL);
1438103669Sphk	}
1439103669Sphk	memset(&loclab, 0, sizeof loclab);
1440103669Sphk	loclab.d_magic = DISKMAGIC;
1441103669Sphk	loclab.d_magic2 = DISKMAGIC;
1442103669Sphk	loclab.d_secsize = secsize;
1443103669Sphk	loclab.d_secperunit = mediasize / secsize;
1444103669Sphk
144568044Sjkh	/*
1446103669Sphk	 * Nobody in these enligthened days uses the CHS geometry for
1447103669Sphk	 * anything, but nontheless try to get it right.  If we fail
1448103669Sphk	 * to get any good ideas from the device, construct something
1449103669Sphk	 * which is IBM-PC friendly.
145068044Sjkh	 */
1451103669Sphk	if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1452103669Sphk		loclab.d_nsectors = u;
1453103669Sphk	else
1454103669Sphk		loclab.d_nsectors = 63;
1455103669Sphk	if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1456103669Sphk		loclab.d_ntracks = u;
1457103669Sphk	else if (loclab.d_secperunit <= 63*1*1024)
1458103669Sphk		loclab.d_ntracks = 1;
1459103669Sphk	else if (loclab.d_secperunit <= 63*16*1024)
1460103669Sphk		loclab.d_ntracks = 16;
1461103669Sphk	else
1462103669Sphk		loclab.d_ntracks = 255;
1463103669Sphk	loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1464103669Sphk	loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1465103669Sphk	loclab.d_npartitions = MAXPARTITIONS;
1466103669Sphk
1467103669Sphk	/* Various (unneeded) compat stuff */
1468103669Sphk	loclab.d_rpm = 3600;
1469103669Sphk	loclab.d_bbsize = BBSIZE;
1470103669Sphk	loclab.d_interleave = 1;;
1471103669Sphk	strncpy(loclab.d_typename, "amnesiac",
1472103669Sphk	    sizeof(loclab.d_typename));
1473103669Sphk
1474103669Sphk	dp = &loclab.d_partitions[RAW_PART];
1475103669Sphk	dp->p_size = loclab.d_secperunit;
1476103669Sphk	loclab.d_checksum = dkcksum(&loclab);
1477103669Sphk	close (f);
147899365Smarkm	return (&loclab);
147913550Sjoerg}
148013550Sjoerg
14811558Srgrimes
14821558Srgrimes/*VARARGS1*/
148313544Sjoergvoid
148492541SimpWarning(const char *fmt, ...)
14851558Srgrimes{
148613544Sjoerg	va_list ap;
14871558Srgrimes
14881558Srgrimes	fprintf(stderr, "Warning, ");
148913544Sjoerg	va_start(ap, fmt);
149013544Sjoerg	vfprintf(stderr, fmt, ap);
14911558Srgrimes	fprintf(stderr, "\n");
149213544Sjoerg	va_end(ap);
14931558Srgrimes}
14941558Srgrimes
149513544Sjoergvoid
149692541Simpusage(void)
14971558Srgrimes{
1498109878Sphk	fprintf(stderr, "%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",
149926542Scharnier		"usage: disklabel [-r] disk",
150026542Scharnier		"\t\t(to read label)",
150173034Sjwd		"       disklabel -w [-r] [-n] disk type [ packid ]",
150226542Scharnier		"\t\t(to write label with existing boot program)",
150373034Sjwd		"       disklabel -e [-r] [-n] disk",
150426542Scharnier		"\t\t(to edit label)",
150573034Sjwd		"       disklabel -R [-r] [-n] disk protofile",
150626542Scharnier		"\t\t(to restore label with existing boot program)",
150773034Sjwd		"       disklabel -B [-n] [ -b bootprog ] disk [ type ]",
150826542Scharnier		"\t\t(to install boot program with existing on-disk label)",
150973034Sjwd		"       disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
151026542Scharnier		"\t\t(to write label and install boot program)",
1511111286Sru		"       disklabel -R -B [-n] [ -b bootprog ] disk protofile",
1512109878Sphk		"\t\t(to restore label and install boot program)"
1513109878Sphk	);
15141558Srgrimes	exit(1);
15151558Srgrimes}
1516