bsdlabel.c revision 50476
174462Salfred/*
274462Salfred * Copyright (c) 1987, 1993
31839Swollman *	The Regents of the University of California.  All rights reserved.
41839Swollman *
51839Swollman * This code is derived from software contributed to Berkeley by
61839Swollman * Symmetric Computer Systems.
71839Swollman *
81839Swollman * Redistribution and use in source and binary forms, with or without
91839Swollman * modification, are permitted provided that the following conditions
108858Srgrimes * are met:
111839Swollman * 1. Redistributions of source code must retain the above copyright
1213771Smpp *    notice, this list of conditions and the following disclaimer.
131839Swollman * 2. Redistributions in binary form must reproduce the above copyright
148858Srgrimes *    notice, this list of conditions and the following disclaimer in the
151839Swollman *    documentation and/or other materials provided with the distribution.
161839Swollman * 3. All advertising materials mentioning features or use of this software
171839Swollman *    must display the following acknowledgement:
188858Srgrimes *	This product includes software developed by the University of
191839Swollman *	California, Berkeley and its contributors.
201839Swollman * 4. Neither the name of the University nor the names of its contributors
211839Swollman *    may be used to endorse or promote products derived from this software
228858Srgrimes *    without specific prior written permission.
231839Swollman *
241839Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251839Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
268858Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271839Swollman * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281839Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291839Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301903Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3174462Salfred * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321903Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3350473Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341839Swollman * SUCH DAMAGE.
351839Swollman */
361839Swollman
371839Swollman#ifndef lint
381839Swollmanstatic const char copyright[] =
391839Swollman"@(#) Copyright (c) 1987, 1993\n\
401839Swollman	The Regents of the University of California.  All rights reserved.\n";
411839Swollman#endif /* not lint */
421903Swollman
431903Swollman#ifndef lint
4474462Salfred#if 0
451903Swollmanstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
4674462Salfred/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
4726211Swpaul#endif
481839Swollmanstatic const char rcsid[] =
491839Swollman  "$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 50476 1999-08-28 00:22:10Z peter $";
5074462Salfred#endif /* not lint */
511839Swollman
5274462Salfred#include <sys/param.h>
531839Swollman#include <sys/errno.h>
5474462Salfred#include <sys/file.h>
5574462Salfred#include <sys/stat.h>
5674462Salfred#include <sys/wait.h>
5774462Salfred#define DKTYPENAMES
5874462Salfred#include <sys/disklabel.h>
5974462Salfred#include <ufs/ffs/fs.h>
6074462Salfred#include <unistd.h>
6174462Salfred#include <string.h>
6274462Salfred#include <stdio.h>
6374462Salfred#include <stdlib.h>
6474462Salfred#include <signal.h>
6574462Salfred#include <stdarg.h>
661839Swollman#include <ctype.h>
671839Swollman#include <err.h>
681839Swollman#include "pathnames.h"
691839Swollman
701839Swollman/*
711839Swollman * Disklabel: read and write disklabels.
721839Swollman * The label is usually placed on one of the first sectors of the disk.
7313771Smpp * Many machines also place a bootstrap in the same area,
741839Swollman * in which case the label is embedded in the bootstrap.
751839Swollman * The bootstrap source must leave space at the proper offset
7674462Salfred * for the label on such machines.
7774462Salfred */
781839Swollman
791839Swollman#ifndef BBSIZE
8021059Speter#define	BBSIZE	8192			/* size of boot area, with label */
8121059Speter#endif
821839Swollman
831839Swollman#ifdef tahoe
841839Swollman#define	NUMBOOT	0
851839Swollman#else
861839Swollman#if defined(__alpha__) || defined(hp300) || defined(hp800)
871839Swollman#define	NUMBOOT	1
881839Swollman#else
891839Swollman#define	NUMBOOT	2
901839Swollman#endif
911839Swollman#endif
921839Swollman
9374462Salfredvoid	makelabel	__P((char *, char *, struct disklabel *));
941839Swollmanint	writelabel	__P((int, char *, struct disklabel *));
951839Swollmanvoid	l_perror	__P((char *));
9621059Speterstruct disklabel * readlabel __P((int));
971839Swollmanstruct disklabel * makebootarea __P((char *, struct disklabel *, int));
981839Swollmanvoid	display		__P((FILE *, struct disklabel *));
9921059Speterint	edit		__P((struct disklabel *, int));
10093032Simpint	editit		__P((void));
10195658Sdeschar *	skip		__P((char *));
10295658Sdeschar *	word		__P((char *));
10321059Speterint	getasciilabel	__P((FILE *, struct disklabel *));
10493032Simpint	checklabel	__P((struct disklabel *));
10521059Spetervoid	setbootflag	__P((struct disklabel *));
10693032Simpvoid	Warning		(char *, ...);
10793032Simpvoid	usage		__P((void));
10821059Speterextern	u_short dkcksum __P((struct disklabel *));
10993032Simpstruct disklabel * getvirginlabel __P((void));
11095658Sdes
11121059Speter#define	DEFEDITOR	_PATH_VI
11293032Simp#define	streq(a,b)	(strcmp(a,b) == 0)
11321059Speter
11493032Simpchar	*dkname;
11595658Sdeschar	*specname;
1161839Swollmanchar	tmpfil[] = _PATH_TMP;
11774462Salfred
11874462Salfredchar	namebuf[BBSIZE], *np = namebuf;
11974462Salfredstruct	disklabel lab;
1201839Swollmanstruct	disklabel *readlabel(), *makebootarea();
1211839Swollmanchar	bootarea[BBSIZE];
1221839Swollman
1231839Swollman#if NUMBOOT > 0
12474462Salfredint	installboot;	/* non-zero if we should install a boot program */
12574462Salfredchar	*bootbuf;	/* pointer to buffer with remainder of boot prog */
12674462Salfredint	bootsize;	/* size of remaining boot program */
12774462Salfredchar	*xxboot;	/* primary boot */
12874462Salfredchar	*bootxx;	/* secondary boot */
12974462Salfredchar	boot0[MAXPATHLEN];
13074462Salfredchar	boot1[MAXPATHLEN];
13174462Salfred#endif
13274462Salfred
13374462Salfredenum	{
13474462Salfred	UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
13574462Salfred} op = UNSPEC;
13674462Salfred
13774462Salfredint	rflag;
13874462Salfred
13974462Salfred#ifdef DEBUG
14074462Salfredint	debug;
14174462Salfred#define OPTIONS	"BNRWb:ders:w"
14274462Salfred#else
14374462Salfred#define OPTIONS	"BNRWb:ers:w"
14474462Salfred#endif
14574462Salfred
1461839Swollmanint
1471839Swollmanmain(argc, argv)
1481839Swollman	int argc;
1491839Swollman	char *argv[];
1501839Swollman{
1511839Swollman	register struct disklabel *lp;
1521839Swollman	FILE *t;
1531839Swollman	int ch, f = 0, flag, error = 0;
1541839Swollman	char *name = 0;
1551839Swollman
15674462Salfred	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
1571839Swollman		switch (ch) {
15895658Sdes#if NUMBOOT > 0
1591839Swollman			case 'B':
16095658Sdes				++installboot;
1611839Swollman				break;
1621839Swollman			case 'b':
16374462Salfred				xxboot = optarg;
16474462Salfred				break;
16595658Sdes#if NUMBOOT > 1
16674462Salfred			case 's':
16774462Salfred				bootxx = optarg;
16895658Sdes				break;
1691839Swollman#endif
1701839Swollman#endif
1711839Swollman			case 'N':
1721839Swollman				if (op != UNSPEC)
1731839Swollman					usage();
1741839Swollman				op = NOWRITE;
1751839Swollman				break;
1761839Swollman			case 'R':
1771839Swollman				if (op != UNSPEC)
1781839Swollman					usage();
1791839Swollman				op = RESTORE;
1801839Swollman				break;
1811839Swollman			case 'W':
1821839Swollman				if (op != UNSPEC)
1831839Swollman					usage();
1841839Swollman				op = WRITEABLE;
1851839Swollman				break;
1861839Swollman			case 'e':
1871839Swollman				if (op != UNSPEC)
1881839Swollman					usage();
1891839Swollman				op = EDIT;
1901839Swollman				break;
1911839Swollman			case 'r':
19295658Sdes				++rflag;
1931839Swollman				break;
1941839Swollman			case 'w':
1951839Swollman				if (op != UNSPEC)
1961839Swollman					usage();
1971839Swollman				op = WRITE;
1981839Swollman				break;
1991839Swollman#ifdef DEBUG
2001839Swollman			case 'd':
2011839Swollman				debug++;
2021839Swollman				break;
2031839Swollman#endif
2041839Swollman			case '?':
2051839Swollman			default:
2061839Swollman				usage();
2071839Swollman		}
20874462Salfred	argc -= optind;
2091839Swollman	argv += optind;
21074462Salfred#if NUMBOOT > 0
21174462Salfred	if (installboot) {
21274462Salfred		rflag++;
21374462Salfred		if (op == UNSPEC)
21474462Salfred			op = WRITEBOOT;
21574462Salfred	} else {
21674462Salfred		if (op == UNSPEC)
21774462Salfred			op = READ;
21874462Salfred		xxboot = bootxx = 0;
21974462Salfred	}
22074462Salfred#else
22174462Salfred	if (op == UNSPEC)
22274462Salfred		op = READ;
22374462Salfred#endif
22474462Salfred	if (argc < 1)
22574462Salfred		usage();
2261839Swollman
22774462Salfred	dkname = argv[0];
2281839Swollman	if (dkname[0] != '/') {
2291839Swollman		(void)sprintf(np, "%sr%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
2301839Swollman		specname = np;
23174879Swpaul		np += strlen(specname) + 1;
23278678Siedowse	} else
2331839Swollman		specname = dkname;
2341839Swollman	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2351839Swollman	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
2361839Swollman		(void)sprintf(specname, "%sr%s", _PATH_DEV, dkname);
2371839Swollman		np = namebuf + strlen(specname) + 1;
2381839Swollman		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2391839Swollman	}
2401839Swollman	if (f < 0)
2411839Swollman		err(4, "%s", specname);
2421839Swollman
2431839Swollman	switch(op) {
24413771Smpp
2451839Swollman	case UNSPEC:
2461839Swollman		break;
2471839Swollman
2481839Swollman	case EDIT:
24974462Salfred		if (argc != 1)
25074462Salfred			usage();
25174462Salfred		lp = readlabel(f);
25274462Salfred		error = edit(lp, f);
2531839Swollman		break;
2541839Swollman
2551839Swollman	case NOWRITE:
2561839Swollman		flag = 0;
2571839Swollman		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
25874462Salfred			err(4, "ioctl DIOCWLABEL");
2591839Swollman		break;
2601839Swollman
2611839Swollman	case READ:
2628858Srgrimes		if (argc != 1)
2631839Swollman			usage();
2641839Swollman		lp = readlabel(f);
2651839Swollman		display(stdout, lp);
2661839Swollman		error = checklabel(lp);
26774462Salfred		break;
26874462Salfred
2691839Swollman	case RESTORE:
27074462Salfred#if NUMBOOT > 0
27174462Salfred		if (installboot && argc == 3) {
27274462Salfred			makelabel(argv[2], 0, &lab);
27374462Salfred			argc--;
27474462Salfred
2751839Swollman			/*
2761903Swollman			 * We only called makelabel() for its side effect
27793032Simp			 * of setting the bootstrap file names.  Discard
27893032Simp			 * all changes to `lab' so that all values in the
27974462Salfred			 * final label come from the ASCII label.
28074462Salfred			 */
28174462Salfred			bzero((char *)&lab, sizeof(lab));
28274462Salfred		}
28374462Salfred#endif
28474462Salfred		if (argc != 2)
28574462Salfred			usage();
2861839Swollman		if (!(t = fopen(argv[1], "r")))
2871839Swollman			err(4, "%s", argv[1]);
28874462Salfred		if (!getasciilabel(t, &lab))
28974462Salfred			exit(1);
2901839Swollman		lp = makebootarea(bootarea, &lab, f);
29193032Simp		*lp = lab;
29293032Simp		error = writelabel(f, bootarea, lp);
29393032Simp		break;
29474462Salfred
29574462Salfred	case WRITE:
29674462Salfred		if (argc == 3) {
29774462Salfred			name = argv[2];
29874462Salfred			argc--;
29974462Salfred		}
30074462Salfred		if (argc != 2)
30174462Salfred			usage();
3021839Swollman		makelabel(argv[1], name, &lab);
3031839Swollman		lp = makebootarea(bootarea, &lab, f);
3041839Swollman		*lp = lab;
30574462Salfred		if (checklabel(lp) == 0)
30674462Salfred			error = writelabel(f, bootarea, lp);
3071839Swollman		break;
30893032Simp
30993032Simp	case WRITEABLE:
31074462Salfred		flag = 1;
31174462Salfred		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
31274462Salfred			err(4, "ioctl DIOCWLABEL");
31374462Salfred		break;
31474462Salfred
31574462Salfred#if NUMBOOT > 0
3161839Swollman	case WRITEBOOT:
31774462Salfred	{
31874462Salfred		struct disklabel tlab;
31974462Salfred
3201903Swollman		lp = readlabel(f);
32193032Simp		tlab = *lp;
32293032Simp		if (argc == 2)
32393032Simp			makelabel(argv[1], 0, &lab);
3241839Swollman		lp = makebootarea(bootarea, &lab, f);
32574462Salfred		*lp = tlab;
32674462Salfred		if (checklabel(lp) == 0)
32774462Salfred			error = writelabel(f, bootarea, lp);
32874462Salfred		break;
32974462Salfred	}
33074462Salfred#endif
33174462Salfred	}
3321839Swollman	exit(error);
3331839Swollman}
33474462Salfred
33574462Salfred/*
33674462Salfred * Construct a prototype disklabel from /etc/disktab.  As a side
33793032Simp * effect, set the names of the primary and secondary boot files
33893032Simp * if specified.
33993032Simp */
34074462Salfredvoid
34184487Swpaulmakelabel(type, name, lp)
34284487Swpaul	char *type, *name;
34393032Simp	register struct disklabel *lp;
34493032Simp{
34584487Swpaul	register struct disklabel *dp;
34674462Salfred
34774462Salfred	if (strcmp(type, "auto") == 0)
34874462Salfred		dp = getvirginlabel();
34974462Salfred	else
35074462Salfred		dp = getdiskbyname(type);
35174462Salfred	if (dp == NULL)
35274462Salfred		errx(1, "%s: unknown disk type", type);
3531903Swollman	*lp = *dp;
3541839Swollman#if NUMBOOT > 0
35574462Salfred	/*
35674462Salfred	 * Set bootstrap name(s).
35793032Simp	 * 1. If set from command line, use those,
35893032Simp	 * 2. otherwise, check if disktab specifies them (b0 or b1),
35993032Simp	 * 3. otherwise, makebootarea() will choose ones based on the name
36074462Salfred	 *    of the disk special file. E.g. /dev/ra0 -> raboot, bootra
36174462Salfred	 */
36274462Salfred	if (!xxboot && lp->d_boot0) {
36374462Salfred		if (*lp->d_boot0 != '/')
36474462Salfred			(void)sprintf(boot0, "%s/%s",
36574462Salfred				      _PATH_BOOTDIR, lp->d_boot0);
36674462Salfred		else
36774462Salfred			(void)strcpy(boot0, lp->d_boot0);
36874462Salfred		xxboot = boot0;
36974462Salfred	}
37074462Salfred#if NUMBOOT > 1
37126211Swpaul	if (!bootxx && lp->d_boot1) {
37274462Salfred		if (*lp->d_boot1 != '/')
37326211Swpaul			(void)sprintf(boot1, "%s/%s",
37474462Salfred				      _PATH_BOOTDIR, lp->d_boot1);
37526211Swpaul		else
37693032Simp			(void)strcpy(boot1, lp->d_boot1);
37774462Salfred		bootxx = boot1;
37826211Swpaul	}
37926211Swpaul#endif
38026211Swpaul#endif
38126211Swpaul	/* d_packname is union d_boot[01], so zero */
3821839Swollman	bzero(lp->d_packname, sizeof(lp->d_packname));
3831839Swollman	if (name)
3841903Swollman		(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
38593032Simp}
38693032Simp
3871903Swollmanint
3881839Swollmanwritelabel(f, boot, lp)
3891839Swollman	int f;
3901839Swollman	char *boot;
3918858Srgrimes	register struct disklabel *lp;
3921903Swollman{
39393032Simp	int flag;
39493032Simp#ifdef __alpha__
3951903Swollman	u_long *p, sum;
3961839Swollman	int i;
3971839Swollman#endif
3981839Swollman#ifdef vax
3991839Swollman	register int i;
4001903Swollman#endif
40193032Simp
40293032Simp	setbootflag(lp);
4031903Swollman	lp->d_magic = DISKMAGIC;
4041839Swollman	lp->d_magic2 = DISKMAGIC;
4051903Swollman	lp->d_checksum = 0;
4068858Srgrimes	lp->d_checksum = dkcksum(lp);
4071839Swollman	if (rflag) {
4081839Swollman		/*
4091839Swollman		 * First set the kernel disk label,
4101839Swollman		 * then write a label to the raw disk.
4111839Swollman		 * If the SDINFO ioctl fails because it is unimplemented,
4121839Swollman		 * keep going; otherwise, the kernel consistency checks
4131839Swollman		 * may prevent us from changing the current (in-core)
41474462Salfred		 * label.
41574462Salfred		 */
41693032Simp		if (ioctl(f, DIOCSDINFO, lp) < 0 &&
41774462Salfred		    errno != ENODEV && errno != ENOTTY) {
41874462Salfred			l_perror("ioctl DIOCSDINFO");
41974462Salfred			return (1);
4201839Swollman		}
42174462Salfred		(void)lseek(f, (off_t)0, SEEK_SET);
4221839Swollman
42374462Salfred#ifdef __alpha__
42474462Salfred		/*
42574462Salfred		 * Generate the bootblock checksum for the SRM console.
42674462Salfred		 */
42774462Salfred		for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
42874462Salfred			sum += p[i];
42974462Salfred		p[63] = sum;
43074462Salfred#endif
43174462Salfred
43274462Salfred		/*
43374462Salfred		 * write enable label sector before write (if necessary),
43474462Salfred		 * disable after writing.
43574462Salfred		 */
43674462Salfred		flag = 1;
43793032Simp		if (ioctl(f, DIOCWLABEL, &flag) < 0)
43893032Simp			warn("ioctl DIOCWLABEL");
43993032Simp		if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
44093032Simp			warn("write");
44174462Salfred			return (1);
4421839Swollman		}
44374462Salfred#if NUMBOOT > 0
44474462Salfred		/*
44574462Salfred		 * Output the remainder of the disklabel
44674462Salfred		 */
44774462Salfred		if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
44874462Salfred			warn("write");
44974462Salfred			return(1);
45074462Salfred		}
45174462Salfred#endif
45274462Salfred		flag = 0;
45374462Salfred		(void) ioctl(f, DIOCWLABEL, &flag);
45474462Salfred	} else if (ioctl(f, DIOCWDINFO, lp) < 0) {
45574462Salfred		l_perror("ioctl DIOCWDINFO");
45674462Salfred		return (1);
45774462Salfred	}
45874462Salfred#ifdef vax
45974462Salfred	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
46074462Salfred		daddr_t alt;
46174462Salfred
46274462Salfred		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
46374462Salfred		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
46474462Salfred			(void)lseek(f, (off_t)((alt + i) * lp->d_secsize),
46574462Salfred			    SEEK_SET);
46674462Salfred			if (write(f, boot, lp->d_secsize) < lp->d_secsize)
46774462Salfred				warn("alternate label %d write", i/2);
46874462Salfred		}
46974462Salfred	}
47074462Salfred#endif
47174462Salfred	return (0);
47274462Salfred}
47374462Salfred
47474462Salfredvoid
47574462Salfredl_perror(s)
47674462Salfred	char *s;
47774462Salfred{
47874462Salfred	switch (errno) {
47974462Salfred
48074462Salfred	case ESRCH:
48174462Salfred		warnx("%s: no disk label on disk;", s);
48274462Salfred		fprintf(stderr,
48374462Salfred		    "use \"disklabel -r\" to install initial label\n");
48474462Salfred		break;
48574462Salfred
4861839Swollman	case EINVAL:
48793032Simp		warnx("%s: label magic number or checksum is wrong!", s);
48874462Salfred		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
48974462Salfred		break;
49093032Simp
49193032Simp	case EBUSY:
49293032Simp		warnx("%s: open partition would move or shrink", s);
49393032Simp		break;
49493032Simp
49593032Simp	case EXDEV:
49693032Simp		warnx("%s: '%c' partition must start at beginning of disk",
49793032Simp		    s, 'a' + RAW_PART);
49893032Simp		break;
49974462Salfred
50074462Salfred	default:
50174462Salfred		warn((char *)NULL);
50274462Salfred		break;
50374462Salfred	}
50474462Salfred}
505
506/*
507 * Fetch disklabel for disk.
508 * Use ioctl to get label unless -r flag is given.
509 */
510struct disklabel *
511readlabel(f)
512	int f;
513{
514	register struct disklabel *lp;
515
516	if (rflag) {
517		if (read(f, bootarea, BBSIZE) < BBSIZE)
518			err(4, "%s", specname);
519		for (lp = (struct disklabel *)bootarea;
520		    lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
521		    lp = (struct disklabel *)((char *)lp + 16))
522			if (lp->d_magic == DISKMAGIC &&
523			    lp->d_magic2 == DISKMAGIC)
524				break;
525		if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
526		    lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
527		    dkcksum(lp) != 0)
528			errx(1,
529	    "bad pack magic number (label is damaged, or pack is unlabeled)");
530	} else {
531		lp = &lab;
532		if (ioctl(f, DIOCGDINFO, lp) < 0)
533			err(4, "ioctl DIOCGDINFO");
534	}
535	return (lp);
536}
537
538/*
539 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
540 * Returns a pointer to the disklabel portion of the bootarea.
541 */
542struct disklabel *
543makebootarea(boot, dp, f)
544	char *boot;
545	register struct disklabel *dp;
546	int f;
547{
548	struct disklabel *lp;
549	register char *p;
550	int b;
551#if NUMBOOT > 0
552	char *dkbasename;
553	struct stat sb;
554#endif
555#ifdef __alpha__
556	u_long *bootinfo;
557	int n;
558#endif
559#ifdef __i386__
560	char *tmpbuf;
561	int i, found;
562#endif
563
564	/* XXX */
565	if (dp->d_secsize == 0) {
566		dp->d_secsize = DEV_BSIZE;
567		dp->d_bbsize = BBSIZE;
568	}
569	lp = (struct disklabel *)
570		(boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
571	bzero((char *)lp, sizeof *lp);
572#if NUMBOOT > 0
573	/*
574	 * If we are not installing a boot program but we are installing a
575	 * label on disk then we must read the current bootarea so we don't
576	 * clobber the existing boot.
577	 */
578	if (!installboot) {
579		if (rflag) {
580			if (read(f, boot, BBSIZE) < BBSIZE)
581				err(4, "%s", specname);
582			bzero((char *)lp, sizeof *lp);
583		}
584		return (lp);
585	}
586	/*
587	 * We are installing a boot program.  Determine the name(s) and
588	 * read them into the appropriate places in the boot area.
589	 */
590	if (!xxboot || !bootxx) {
591		dkbasename = np;
592		if ((p = rindex(dkname, '/')) == NULL)
593			p = dkname;
594		else
595			p++;
596		while (*p && !isdigit(*p))
597			*np++ = *p++;
598		*np++ = '\0';
599
600		if (!xxboot) {
601			(void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
602			xxboot = boot0;
603		}
604#if NUMBOOT > 1
605		if (!bootxx) {
606			(void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
607			bootxx = boot1;
608		}
609#endif
610	}
611#ifdef DEBUG
612	if (debug)
613		fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
614			xxboot, bootxx ? bootxx : "NONE");
615#endif
616
617	/*
618	 * Strange rules:
619	 * 1. One-piece bootstrap (hp300/hp800)
620	 *	up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
621	 *	is remembered and written later following the bootarea.
622	 * 2. Two-piece bootstraps (vax/i386?/mips?)
623	 *	up to d_secsize bytes of ``xxboot'' go in first d_secsize
624	 *	bytes of bootarea, remaining d_bbsize-d_secsize filled
625	 *	from ``bootxx''.
626	 */
627	b = open(xxboot, O_RDONLY);
628	if (b < 0)
629		err(4, "%s", xxboot);
630#if NUMBOOT > 1
631#ifdef __i386__
632	/*
633	 * XXX Botch alert.
634	 * The i386 has the so-called fdisk table embedded into the
635	 * primary bootstrap.  We take care to not clobber it, but
636	 * only if it does already contain some data.  (Otherwise,
637	 * the xxboot provides a template.)
638	 */
639	if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
640		err(4, "%s", xxboot);
641	memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
642#endif /* i386 */
643	if (read(b, boot, (int)dp->d_secsize) < 0)
644		err(4, "%s", xxboot);
645	(void)close(b);
646#ifdef __i386__
647	for (i = DOSPARTOFF, found = 0;
648	     !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
649	     i++)
650		found = tmpbuf[i] != 0;
651	if (found)
652		memcpy((void *)&boot[DOSPARTOFF],
653		       (void *)&tmpbuf[DOSPARTOFF],
654		       NDOSPART * sizeof(struct dos_partition));
655	free(tmpbuf);
656#endif /* i386 */
657	b = open(bootxx, O_RDONLY);
658	if (b < 0)
659		err(4, "%s", bootxx);
660	if (fstat(b, &sb) != 0)
661		err(4, "%s", bootxx);
662	if (dp->d_secsize + sb.st_size > dp->d_bbsize)
663		errx(4, "%s too large", bootxx);
664	if (read(b, &boot[dp->d_secsize],
665		 (int)(dp->d_bbsize-dp->d_secsize)) < 0)
666		err(4, "%s", bootxx);
667#else /* !(NUMBOOT > 1) */
668#ifdef __alpha__
669	/*
670	 * On the alpha, the primary bootstrap starts at the
671	 * second sector of the boot area.  The first sector
672	 * contains the label and must be edited to contain the
673	 * size and location of the primary bootstrap.
674	 */
675	n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize);
676	if (n < 0)
677		err(4, "%s", xxboot);
678	bootinfo = (u_long *)(boot + 480);
679	bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
680	bootinfo[1] = 1;	/* start at sector 1 */
681	bootinfo[2] = 0;	/* flags (must be zero) */
682#else /* !__alpha__ */
683	if (read(b, boot, (int)dp->d_bbsize) < 0)
684		err(4, "%s", xxboot);
685#endif /* __alpha__ */
686	if (fstat(b, &sb) != 0)
687		err(4, "%s", xxboot);
688	bootsize = (int)sb.st_size - dp->d_bbsize;
689	if (bootsize > 0) {
690		/* XXX assume d_secsize is a power of two */
691		bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
692		bootbuf = (char *)malloc((size_t)bootsize);
693		if (bootbuf == 0)
694			err(4, "%s", xxboot);
695		if (read(b, bootbuf, bootsize) < 0) {
696			free(bootbuf);
697			err(4, "%s", xxboot);
698		}
699	}
700#endif /* NUMBOOT > 1 */
701	(void)close(b);
702#endif /* NUMBOOT > 0 */
703	/*
704	 * Make sure no part of the bootstrap is written in the area
705	 * reserved for the label.
706	 */
707	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
708		if (*p)
709			errx(2, "bootstrap doesn't leave room for disk label");
710	return (lp);
711}
712
713void
714display(f, lp)
715	FILE *f;
716	register struct disklabel *lp;
717{
718	register int i, j;
719	register struct partition *pp;
720
721	fprintf(f, "# %s:\n", specname);
722	if ((unsigned) lp->d_type < DKMAXTYPES)
723		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
724	else
725		fprintf(f, "type: %u\n", lp->d_type);
726	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
727		lp->d_typename);
728	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
729		lp->d_packname);
730	fprintf(f, "flags:");
731	if (lp->d_flags & D_REMOVABLE)
732		fprintf(f, " removeable");
733	if (lp->d_flags & D_ECC)
734		fprintf(f, " ecc");
735	if (lp->d_flags & D_BADSECT)
736		fprintf(f, " badsect");
737	fprintf(f, "\n");
738	fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
739	fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
740	fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
741	fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
742	fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
743	fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
744	fprintf(f, "rpm: %u\n", lp->d_rpm);
745	fprintf(f, "interleave: %u\n", lp->d_interleave);
746	fprintf(f, "trackskew: %u\n", lp->d_trackskew);
747	fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
748	fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
749	    (u_long)lp->d_headswitch);
750	fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
751	    (u_long)lp->d_trkseek);
752	fprintf(f, "drivedata: ");
753	for (i = NDDATA - 1; i >= 0; i--)
754		if (lp->d_drivedata[i])
755			break;
756	if (i < 0)
757		i = 0;
758	for (j = 0; j <= i; j++)
759		fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
760	fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
761	fprintf(f,
762	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
763	pp = lp->d_partitions;
764	for (i = 0; i < lp->d_npartitions; i++, pp++) {
765		if (pp->p_size) {
766			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
767			   (u_long)pp->p_size, (u_long)pp->p_offset);
768			if ((unsigned) pp->p_fstype < FSMAXTYPES)
769				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
770			else
771				fprintf(f, "%8d", pp->p_fstype);
772			switch (pp->p_fstype) {
773
774			case FS_UNUSED:				/* XXX */
775				fprintf(f, "    %5lu %5lu %5.5s ",
776				    (u_long)pp->p_fsize,
777				    (u_long)(pp->p_fsize * pp->p_frag), "");
778				break;
779
780			case FS_BSDFFS:
781				fprintf(f, "    %5lu %5lu %5u ",
782				    (u_long)pp->p_fsize,
783				    (u_long)(pp->p_fsize * pp->p_frag),
784				    pp->p_cpg);
785				break;
786
787			case FS_BSDLFS:
788				fprintf(f, "    %5lu %5lu %5d",
789				    (u_long)pp->p_fsize,
790				    (u_long)(pp->p_fsize * pp->p_frag),
791				    pp->p_cpg);
792				break;
793
794			default:
795				fprintf(f, "%20.20s", "");
796				break;
797			}
798			fprintf(f, "\t# (Cyl. %4lu",
799			    (u_long)(pp->p_offset / lp->d_secpercyl));
800			if (pp->p_offset % lp->d_secpercyl)
801			    putc('*', f);
802			else
803			    putc(' ', f);
804			fprintf(f, "- %lu",
805			    (u_long)((pp->p_offset + pp->p_size +
806			    lp->d_secpercyl - 1) /
807			    lp->d_secpercyl - 1));
808			if (pp->p_size % lp->d_secpercyl)
809			    putc('*', f);
810			fprintf(f, ")\n");
811		}
812	}
813	fflush(f);
814}
815
816int
817edit(lp, f)
818	struct disklabel *lp;
819	int f;
820{
821	register int c, fd;
822	struct disklabel label;
823	FILE *fp;
824
825	if ((fd = mkstemp(tmpfil)) == -1 ||
826	    (fp = fdopen(fd, "w")) == NULL) {
827		warnx("can't create %s", tmpfil);
828		return (1);
829	}
830	display(fp, lp);
831	fclose(fp);
832	for (;;) {
833		if (!editit())
834			break;
835		fp = fopen(tmpfil, "r");
836		if (fp == NULL) {
837			warnx("can't reopen %s for reading", tmpfil);
838			break;
839		}
840		bzero((char *)&label, sizeof(label));
841		if (getasciilabel(fp, &label)) {
842			*lp = label;
843			if (writelabel(f, bootarea, lp) == 0) {
844				fclose(fp);
845				(void) unlink(tmpfil);
846				return (0);
847			}
848		}
849		fclose(fp);
850		printf("re-edit the label? [y]: "); fflush(stdout);
851		c = getchar();
852		if (c != EOF && c != (int)'\n')
853			while (getchar() != (int)'\n')
854				;
855		if  (c == (int)'n')
856			break;
857	}
858	(void) unlink(tmpfil);
859	return (1);
860}
861
862int
863editit()
864{
865	register int pid, xpid;
866	int stat, omask;
867	extern char *getenv();
868
869	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
870	while ((pid = fork()) < 0) {
871		extern int errno;
872
873		if (errno == EPROCLIM) {
874			warnx("you have too many processes");
875			return(0);
876		}
877		if (errno != EAGAIN) {
878			warn("fork");
879			return(0);
880		}
881		sleep(1);
882	}
883	if (pid == 0) {
884		register char *ed;
885
886		sigsetmask(omask);
887		setgid(getgid());
888		setuid(getuid());
889		if ((ed = getenv("EDITOR")) == (char *)0)
890			ed = DEFEDITOR;
891		execlp(ed, ed, tmpfil, 0);
892		err(1, "%s", ed);
893	}
894	while ((xpid = wait(&stat)) >= 0)
895		if (xpid == pid)
896			break;
897	sigsetmask(omask);
898	return(!stat);
899}
900
901char *
902skip(cp)
903	register char *cp;
904{
905
906	while (*cp != '\0' && isspace(*cp))
907		cp++;
908	if (*cp == '\0' || *cp == '#')
909		return ((char *)NULL);
910	return (cp);
911}
912
913char *
914word(cp)
915	register char *cp;
916{
917	register char c;
918
919	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
920		cp++;
921	if ((c = *cp) != '\0') {
922		*cp++ = '\0';
923		if (c != '#')
924			return (skip(cp));
925	}
926	return ((char *)NULL);
927}
928
929/*
930 * Read an ascii label in from fd f,
931 * in the same format as that put out by display(),
932 * and fill in lp.
933 */
934int
935getasciilabel(f, lp)
936	FILE	*f;
937	register struct disklabel *lp;
938{
939	register char **cpp, *cp;
940	register struct partition *pp;
941	char *tp, *s, line[BUFSIZ];
942	int v, lineno = 0, errors = 0;
943
944	lp->d_bbsize = BBSIZE;				/* XXX */
945	lp->d_sbsize = SBSIZE;				/* XXX */
946	while (fgets(line, sizeof(line) - 1, f)) {
947		lineno++;
948		if ((cp = index(line,'\n')) != 0)
949			*cp = '\0';
950		cp = skip(line);
951		if (cp == NULL)
952			continue;
953		tp = index(cp, ':');
954		if (tp == NULL) {
955			fprintf(stderr, "line %d: syntax error\n", lineno);
956			errors++;
957			continue;
958		}
959		*tp++ = '\0', tp = skip(tp);
960		if (streq(cp, "type")) {
961			if (tp == NULL)
962				tp = "unknown";
963			cpp = dktypenames;
964			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
965				if ((s = *cpp) && streq(s, tp)) {
966					lp->d_type = cpp - dktypenames;
967					goto next;
968				}
969			v = atoi(tp);
970			if ((unsigned)v >= DKMAXTYPES)
971				fprintf(stderr, "line %d:%s %d\n", lineno,
972				    "Warning, unknown disk type", v);
973			lp->d_type = v;
974			continue;
975		}
976		if (streq(cp, "flags")) {
977			for (v = 0; (cp = tp) && *cp != '\0';) {
978				tp = word(cp);
979				if (streq(cp, "removeable"))
980					v |= D_REMOVABLE;
981				else if (streq(cp, "ecc"))
982					v |= D_ECC;
983				else if (streq(cp, "badsect"))
984					v |= D_BADSECT;
985				else {
986					fprintf(stderr,
987					    "line %d: %s: bad flag\n",
988					    lineno, cp);
989					errors++;
990				}
991			}
992			lp->d_flags = v;
993			continue;
994		}
995		if (streq(cp, "drivedata")) {
996			register int i;
997
998			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
999				lp->d_drivedata[i++] = atoi(cp);
1000				tp = word(cp);
1001			}
1002			continue;
1003		}
1004		if (sscanf(cp, "%d partitions", &v) == 1) {
1005			if (v == 0 || (unsigned)v > MAXPARTITIONS) {
1006				fprintf(stderr,
1007				    "line %d: bad # of partitions\n", lineno);
1008				lp->d_npartitions = MAXPARTITIONS;
1009				errors++;
1010			} else
1011				lp->d_npartitions = v;
1012			continue;
1013		}
1014		if (tp == NULL)
1015			tp = "";
1016		if (streq(cp, "disk")) {
1017			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
1018			continue;
1019		}
1020		if (streq(cp, "label")) {
1021			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
1022			continue;
1023		}
1024		if (streq(cp, "bytes/sector")) {
1025			v = atoi(tp);
1026			if (v <= 0 || (v % DEV_BSIZE) != 0) {
1027				fprintf(stderr,
1028				    "line %d: %s: bad sector size\n",
1029				    lineno, tp);
1030				errors++;
1031			} else
1032				lp->d_secsize = v;
1033			continue;
1034		}
1035		if (streq(cp, "sectors/track")) {
1036			v = atoi(tp);
1037			if (v <= 0) {
1038				fprintf(stderr, "line %d: %s: bad %s\n",
1039				    lineno, tp, cp);
1040				errors++;
1041			} else
1042				lp->d_nsectors = v;
1043			continue;
1044		}
1045		if (streq(cp, "sectors/cylinder")) {
1046			v = atoi(tp);
1047			if (v <= 0) {
1048				fprintf(stderr, "line %d: %s: bad %s\n",
1049				    lineno, tp, cp);
1050				errors++;
1051			} else
1052				lp->d_secpercyl = v;
1053			continue;
1054		}
1055		if (streq(cp, "tracks/cylinder")) {
1056			v = atoi(tp);
1057			if (v <= 0) {
1058				fprintf(stderr, "line %d: %s: bad %s\n",
1059				    lineno, tp, cp);
1060				errors++;
1061			} else
1062				lp->d_ntracks = v;
1063			continue;
1064		}
1065		if (streq(cp, "cylinders")) {
1066			v = atoi(tp);
1067			if (v <= 0) {
1068				fprintf(stderr, "line %d: %s: bad %s\n",
1069				    lineno, tp, cp);
1070				errors++;
1071			} else
1072				lp->d_ncylinders = v;
1073			continue;
1074		}
1075		if (streq(cp, "sectors/unit")) {
1076			v = atoi(tp);
1077			if (v <= 0) {
1078				fprintf(stderr, "line %d: %s: bad %s\n",
1079				    lineno, tp, cp);
1080				errors++;
1081			} else
1082				lp->d_secperunit = v;
1083			continue;
1084		}
1085		if (streq(cp, "rpm")) {
1086			v = atoi(tp);
1087			if (v <= 0) {
1088				fprintf(stderr, "line %d: %s: bad %s\n",
1089				    lineno, tp, cp);
1090				errors++;
1091			} else
1092				lp->d_rpm = v;
1093			continue;
1094		}
1095		if (streq(cp, "interleave")) {
1096			v = atoi(tp);
1097			if (v <= 0) {
1098				fprintf(stderr, "line %d: %s: bad %s\n",
1099				    lineno, tp, cp);
1100				errors++;
1101			} else
1102				lp->d_interleave = v;
1103			continue;
1104		}
1105		if (streq(cp, "trackskew")) {
1106			v = atoi(tp);
1107			if (v < 0) {
1108				fprintf(stderr, "line %d: %s: bad %s\n",
1109				    lineno, tp, cp);
1110				errors++;
1111			} else
1112				lp->d_trackskew = v;
1113			continue;
1114		}
1115		if (streq(cp, "cylinderskew")) {
1116			v = atoi(tp);
1117			if (v < 0) {
1118				fprintf(stderr, "line %d: %s: bad %s\n",
1119				    lineno, tp, cp);
1120				errors++;
1121			} else
1122				lp->d_cylskew = v;
1123			continue;
1124		}
1125		if (streq(cp, "headswitch")) {
1126			v = atoi(tp);
1127			if (v < 0) {
1128				fprintf(stderr, "line %d: %s: bad %s\n",
1129				    lineno, tp, cp);
1130				errors++;
1131			} else
1132				lp->d_headswitch = v;
1133			continue;
1134		}
1135		if (streq(cp, "track-to-track seek")) {
1136			v = atoi(tp);
1137			if (v < 0) {
1138				fprintf(stderr, "line %d: %s: bad %s\n",
1139				    lineno, tp, cp);
1140				errors++;
1141			} else
1142				lp->d_trkseek = v;
1143			continue;
1144		}
1145		if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') {
1146			unsigned part = *cp - 'a';
1147
1148			if (part > lp->d_npartitions) {
1149				fprintf(stderr,
1150				    "line %d: bad partition name\n", lineno);
1151				errors++;
1152				continue;
1153			}
1154			pp = &lp->d_partitions[part];
1155#define NXTNUM(n) { \
1156	if (tp == NULL) { \
1157		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1158		errors++; \
1159		break; \
1160	} else { \
1161		cp = tp, tp = word(cp); \
1162		if (tp == NULL) \
1163			tp = cp; \
1164		(n) = atoi(cp); \
1165	} \
1166     }
1167
1168			NXTNUM(v);
1169			if (v < 0) {
1170				fprintf(stderr,
1171				    "line %d: %s: bad partition size\n",
1172				    lineno, cp);
1173				errors++;
1174			} else
1175				pp->p_size = v;
1176			NXTNUM(v);
1177			if (v < 0) {
1178				fprintf(stderr,
1179				    "line %d: %s: bad partition offset\n",
1180				    lineno, cp);
1181				errors++;
1182			} else
1183				pp->p_offset = v;
1184			cp = tp, tp = word(cp);
1185			cpp = fstypenames;
1186			for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1187				if ((s = *cpp) && streq(s, cp)) {
1188					pp->p_fstype = cpp - fstypenames;
1189					goto gottype;
1190				}
1191			if (isdigit(*cp))
1192				v = atoi(cp);
1193			else
1194				v = FSMAXTYPES;
1195			if ((unsigned)v >= FSMAXTYPES) {
1196				fprintf(stderr, "line %d: %s %s\n", lineno,
1197				    "Warning, unknown filesystem type", cp);
1198				v = FS_UNUSED;
1199			}
1200			pp->p_fstype = v;
1201	gottype:
1202
1203			switch (pp->p_fstype) {
1204
1205			case FS_UNUSED:				/* XXX */
1206				NXTNUM(pp->p_fsize);
1207				if (pp->p_fsize == 0)
1208					break;
1209				NXTNUM(v);
1210				pp->p_frag = v / pp->p_fsize;
1211				break;
1212
1213			case FS_BSDFFS:
1214				NXTNUM(pp->p_fsize);
1215				if (pp->p_fsize == 0)
1216					break;
1217				NXTNUM(v);
1218				pp->p_frag = v / pp->p_fsize;
1219				NXTNUM(pp->p_cpg);
1220				break;
1221
1222			case FS_BSDLFS:
1223				NXTNUM(pp->p_fsize);
1224				if (pp->p_fsize == 0)
1225					break;
1226				NXTNUM(v);
1227				pp->p_frag = v / pp->p_fsize;
1228				NXTNUM(pp->p_cpg);
1229				break;
1230
1231			default:
1232				break;
1233			}
1234			continue;
1235		}
1236		fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1237		    lineno, cp);
1238		errors++;
1239	next:
1240		;
1241	}
1242	errors += checklabel(lp);
1243	return (errors == 0);
1244}
1245
1246/*
1247 * Check disklabel for errors and fill in
1248 * derived fields according to supplied values.
1249 */
1250int
1251checklabel(lp)
1252	register struct disklabel *lp;
1253{
1254	register struct partition *pp;
1255	int i, errors = 0;
1256	char part;
1257
1258	if (lp->d_secsize == 0) {
1259		fprintf(stderr, "sector size 0\n");
1260		return (1);
1261	}
1262	if (lp->d_nsectors == 0) {
1263		fprintf(stderr, "sectors/track 0\n");
1264		return (1);
1265	}
1266	if (lp->d_ntracks == 0) {
1267		fprintf(stderr, "tracks/cylinder 0\n");
1268		return (1);
1269	}
1270	if  (lp->d_ncylinders == 0) {
1271		fprintf(stderr, "cylinders/unit 0\n");
1272		errors++;
1273	}
1274	if (lp->d_rpm == 0)
1275		Warning("revolutions/minute 0");
1276	if (lp->d_secpercyl == 0)
1277		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1278	if (lp->d_secperunit == 0)
1279		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1280	if (lp->d_bbsize == 0) {
1281		fprintf(stderr, "boot block size 0\n");
1282		errors++;
1283	} else if (lp->d_bbsize % lp->d_secsize)
1284		Warning("boot block size %% sector-size != 0");
1285	if (lp->d_sbsize == 0) {
1286		fprintf(stderr, "super block size 0\n");
1287		errors++;
1288	} else if (lp->d_sbsize % lp->d_secsize)
1289		Warning("super block size %% sector-size != 0");
1290	if (lp->d_npartitions > MAXPARTITIONS)
1291		Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1292		    (u_long)lp->d_npartitions, MAXPARTITIONS);
1293	for (i = 0; i < lp->d_npartitions; i++) {
1294		part = 'a' + i;
1295		pp = &lp->d_partitions[i];
1296		if (pp->p_size == 0 && pp->p_offset != 0)
1297			Warning("partition %c: size 0, but offset %lu",
1298			    part, (u_long)pp->p_offset);
1299#ifdef notdef
1300		if (pp->p_size % lp->d_secpercyl)
1301			Warning("partition %c: size %% cylinder-size != 0",
1302			    part);
1303		if (pp->p_offset % lp->d_secpercyl)
1304			Warning("partition %c: offset %% cylinder-size != 0",
1305			    part);
1306#endif
1307		if (pp->p_offset > lp->d_secperunit) {
1308			fprintf(stderr,
1309			    "partition %c: offset past end of unit\n", part);
1310			errors++;
1311		}
1312		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1313			fprintf(stderr,
1314			"partition %c: partition extends past end of unit\n",
1315			    part);
1316			errors++;
1317		}
1318	}
1319	for (; i < MAXPARTITIONS; i++) {
1320		part = 'a' + i;
1321		pp = &lp->d_partitions[i];
1322		if (pp->p_size || pp->p_offset)
1323			Warning("unused partition %c: size %d offset %lu",
1324			    'a' + i, pp->p_size, (u_long)pp->p_offset);
1325	}
1326	return (errors);
1327}
1328
1329/*
1330 * When operating on a "virgin" disk, try getting an initial label
1331 * from the associated device driver.  This might work for all device
1332 * drivers that are able to fetch some initial device parameters
1333 * without even having access to a (BSD) disklabel, like SCSI disks,
1334 * most IDE drives, or vn devices.
1335 *
1336 * The device name must be given in its "canonical" form.
1337 */
1338struct disklabel *
1339getvirginlabel(void)
1340{
1341	static struct disklabel lab;
1342	char namebuf[BBSIZE];
1343	int f;
1344
1345	if (dkname[0] == '/') {
1346		warnx("\"auto\" requires the usage of a canonical disk name");
1347		return (NULL);
1348	}
1349	(void)snprintf(namebuf, BBSIZE, "%sr%s", _PATH_DEV, dkname);
1350	if ((f = open(namebuf, O_RDONLY)) == -1) {
1351		warn("cannot open %s", namebuf);
1352		return (NULL);
1353	}
1354	if (ioctl(f, DIOCGDINFO, &lab) < 0) {
1355		warn("ioctl DIOCGDINFO");
1356		close(f);
1357		return (NULL);
1358	}
1359	close(f);
1360	lab.d_boot0 = NULL;
1361	lab.d_boot1 = NULL;
1362	return (&lab);
1363}
1364
1365/*
1366 * If we are installing a boot program that doesn't fit in d_bbsize
1367 * we need to mark those partitions that the boot overflows into.
1368 * This allows newfs to prevent creation of a filesystem where it might
1369 * clobber bootstrap code.
1370 */
1371void
1372setbootflag(lp)
1373	register struct disklabel *lp;
1374{
1375	register struct partition *pp;
1376	int i, errors = 0;
1377	char part;
1378	u_long boffset;
1379
1380	if (bootbuf == 0)
1381		return;
1382	boffset = bootsize / lp->d_secsize;
1383	for (i = 0; i < lp->d_npartitions; i++) {
1384		part = 'a' + i;
1385		pp = &lp->d_partitions[i];
1386		if (pp->p_size == 0)
1387			continue;
1388		if (boffset <= pp->p_offset) {
1389			if (pp->p_fstype == FS_BOOT)
1390				pp->p_fstype = FS_UNUSED;
1391		} else if (pp->p_fstype != FS_BOOT) {
1392			if (pp->p_fstype != FS_UNUSED) {
1393				fprintf(stderr,
1394					"boot overlaps used partition %c\n",
1395					part);
1396				errors++;
1397			} else {
1398				pp->p_fstype = FS_BOOT;
1399				Warning("boot overlaps partition %c, %s",
1400					part, "marked as FS_BOOT");
1401			}
1402		}
1403	}
1404	if (errors)
1405		errx(4, "cannot install boot program");
1406}
1407
1408/*VARARGS1*/
1409void
1410Warning(char *fmt, ...)
1411{
1412	va_list ap;
1413
1414	fprintf(stderr, "Warning, ");
1415	va_start(ap, fmt);
1416	vfprintf(stderr, fmt, ap);
1417	fprintf(stderr, "\n");
1418	va_end(ap);
1419}
1420
1421void
1422usage()
1423{
1424#if NUMBOOT > 0
1425	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%s\n%s\n",
1426		"usage: disklabel [-r] disk",
1427		"\t\t(to read label)",
1428		"       disklabel -w [-r] disk type [ packid ]",
1429		"\t\t(to write label with existing boot program)",
1430		"       disklabel -e [-r] disk",
1431		"\t\t(to edit label)",
1432		"       disklabel -R [-r] disk protofile",
1433		"\t\t(to restore label with existing boot program)",
1434#if NUMBOOT > 1
1435		"       disklabel -B [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1436		"\t\t(to install boot program with existing label)",
1437		"       disklabel -w -B [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1438		"\t\t(to write label and boot program)",
1439		"       disklabel -R -B [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1440		"\t\t(to restore label and boot program)",
1441#else
1442		"       disklabel -B [ -b bootprog ] disk [ type ]",
1443		"\t\t(to install boot program with existing on-disk label)",
1444		"       disklabel -w -B [ -b bootprog ] disk type [ packid ]",
1445		"\t\t(to write label and install boot program)",
1446		"       disklabel -R -B [ -b bootprog ] disk protofile [ type ]",
1447		"\t\t(to restore label and install boot program)",
1448#endif
1449		"       disklabel [-NW] disk",
1450		"\t\t(to write disable/enable label)");
1451#else
1452	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1453		"usage: disklabel [-r] disk", "(to read label)",
1454		"       disklabel -w [-r] disk type [ packid ]",
1455		"\t\t(to write label)",
1456		"       disklabel -e [-r] disk",
1457		"\t\t(to edit label)",
1458		"       disklabel -R [-r] disk protofile",
1459		"\t\t(to restore label)",
1460		"       disklabel [-NW] disk",
1461		"\t\t(to write disable/enable label)");
1462#endif
1463	exit(1);
1464}
1465