bsdlabel.c revision 73034
11558Srgrimes/*
21558Srgrimes * Copyright (c) 1987, 1993
31558Srgrimes *	The Regents of the University of California.  All rights reserved.
41558Srgrimes *
51558Srgrimes * This code is derived from software contributed to Berkeley by
61558Srgrimes * Symmetric Computer Systems.
71558Srgrimes *
81558Srgrimes * Redistribution and use in source and binary forms, with or without
91558Srgrimes * modification, are permitted provided that the following conditions
101558Srgrimes * are met:
111558Srgrimes * 1. Redistributions of source code must retain the above copyright
121558Srgrimes *    notice, this list of conditions and the following disclaimer.
131558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141558Srgrimes *    notice, this list of conditions and the following disclaimer in the
151558Srgrimes *    documentation and/or other materials provided with the distribution.
161558Srgrimes * 3. All advertising materials mentioning features or use of this software
171558Srgrimes *    must display the following acknowledgement:
181558Srgrimes *	This product includes software developed by the University of
191558Srgrimes *	California, Berkeley and its contributors.
201558Srgrimes * 4. Neither the name of the University nor the names of its contributors
211558Srgrimes *    may be used to endorse or promote products derived from this software
221558Srgrimes *    without specific prior written permission.
231558Srgrimes *
241558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341558Srgrimes * SUCH DAMAGE.
351558Srgrimes */
361558Srgrimes
371558Srgrimes#ifndef lint
3836632Scharnierstatic const char copyright[] =
391558Srgrimes"@(#) Copyright (c) 1987, 1993\n\
401558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
411558Srgrimes#endif /* not lint */
421558Srgrimes
431558Srgrimes#ifndef lint
4436632Scharnier#if 0
451558Srgrimesstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
461558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
4736632Scharnier#endif
4836632Scharnierstatic const char rcsid[] =
4950476Speter  "$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 73034 2001-02-25 16:47:44Z jwd $";
501558Srgrimes#endif /* not lint */
511558Srgrimes
521558Srgrimes#include <sys/param.h>
531558Srgrimes#include <sys/file.h>
541558Srgrimes#include <sys/stat.h>
5513544Sjoerg#include <sys/wait.h>
561558Srgrimes#define DKTYPENAMES
571558Srgrimes#include <sys/disklabel.h>
581558Srgrimes#include <ufs/ffs/fs.h>
591558Srgrimes#include <unistd.h>
601558Srgrimes#include <string.h>
611558Srgrimes#include <stdio.h>
6213544Sjoerg#include <stdlib.h>
6313544Sjoerg#include <signal.h>
6413544Sjoerg#include <stdarg.h>
651558Srgrimes#include <ctype.h>
6626542Scharnier#include <err.h>
6759216Simp#include <errno.h>
681558Srgrimes#include "pathnames.h"
691558Srgrimes
701558Srgrimes/*
711558Srgrimes * Disklabel: read and write disklabels.
721558Srgrimes * The label is usually placed on one of the first sectors of the disk.
731558Srgrimes * Many machines also place a bootstrap in the same area,
741558Srgrimes * in which case the label is embedded in the bootstrap.
751558Srgrimes * The bootstrap source must leave space at the proper offset
761558Srgrimes * for the label on such machines.
771558Srgrimes */
781558Srgrimes
791558Srgrimes#ifndef BBSIZE
801558Srgrimes#define	BBSIZE	8192			/* size of boot area, with label */
811558Srgrimes#endif
821558Srgrimes
8373034Sjwd/* FIX!  These are too low, but are traditional */
8473034Sjwd#define DEFAULT_NEWFS_BLOCK  8192U
8573034Sjwd#define DEFAULT_NEWFS_FRAG   1024U
8673034Sjwd#define DEFAULT_NEWFS_CPG    16U
8773034Sjwd
8873034Sjwd#define BIG_NEWFS_BLOCK  16384U
8973034Sjwd#define BIG_NEWFS_FRAG   4096U
9073034Sjwd#define BIG_NEWFS_CPG    64U
9173034Sjwd
921558Srgrimes#ifdef tahoe
931558Srgrimes#define	NUMBOOT	0
941558Srgrimes#else
9538411Sbde#if defined(__alpha__) || defined(hp300) || defined(hp800)
961558Srgrimes#define	NUMBOOT	1
971558Srgrimes#else
981558Srgrimes#define	NUMBOOT	2
991558Srgrimes#endif
1001558Srgrimes#endif
1011558Srgrimes
10213544Sjoergvoid	makelabel	__P((char *, char *, struct disklabel *));
10313544Sjoergint	writelabel	__P((int, char *, struct disklabel *));
10413544Sjoergvoid	l_perror	__P((char *));
10513544Sjoergstruct disklabel * readlabel __P((int));
10613544Sjoergstruct disklabel * makebootarea __P((char *, struct disklabel *, int));
10713544Sjoergvoid	display		__P((FILE *, struct disklabel *));
10813544Sjoergint	edit		__P((struct disklabel *, int));
10913544Sjoergint	editit		__P((void));
11013544Sjoergchar *	skip		__P((char *));
11113544Sjoergchar *	word		__P((char *));
11213544Sjoergint	getasciilabel	__P((FILE *, struct disklabel *));
11313544Sjoergint	checklabel	__P((struct disklabel *));
11413544Sjoergvoid	setbootflag	__P((struct disklabel *));
11513544Sjoergvoid	Warning		(char *, ...);
11613544Sjoergvoid	usage		__P((void));
11713550Sjoergstruct disklabel * getvirginlabel __P((void));
11813544Sjoerg
1191558Srgrimes#define	DEFEDITOR	_PATH_VI
1201558Srgrimes#define	streq(a,b)	(strcmp(a,b) == 0)
1211558Srgrimes
1221558Srgrimeschar	*dkname;
1231558Srgrimeschar	*specname;
12455742Skrischar	tmpfil[] = PATH_TMPFILE;
1251558Srgrimes
1261558Srgrimeschar	namebuf[BBSIZE], *np = namebuf;
1271558Srgrimesstruct	disklabel lab;
1281558Srgrimeschar	bootarea[BBSIZE];
1291558Srgrimes
13073034Sjwd/* partition 'c' is the full disk and is special */
13173034Sjwd#define FULL_DISK_PART 2
13273034Sjwd#define MAX_PART ('z')
13373034Sjwd#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
13473034Sjwdchar    part_size_type[MAX_NUM_PARTS];
13573034Sjwdchar    part_offset_type[MAX_NUM_PARTS];
13673034Sjwdint     part_set[MAX_NUM_PARTS];
13773034Sjwd
1381558Srgrimes#if NUMBOOT > 0
1391558Srgrimesint	installboot;	/* non-zero if we should install a boot program */
1401558Srgrimeschar	*bootbuf;	/* pointer to buffer with remainder of boot prog */
1411558Srgrimesint	bootsize;	/* size of remaining boot program */
1421558Srgrimeschar	*xxboot;	/* primary boot */
1431558Srgrimeschar	*bootxx;	/* secondary boot */
1441558Srgrimeschar	boot0[MAXPATHLEN];
1451558Srgrimeschar	boot1[MAXPATHLEN];
1461558Srgrimes#endif
1471558Srgrimes
1481558Srgrimesenum	{
1491558Srgrimes	UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
1501558Srgrimes} op = UNSPEC;
1511558Srgrimes
1521558Srgrimesint	rflag;
15373034Sjwdint	disable_write;   /* set to disable writing to disk label */
1541558Srgrimes
1551558Srgrimes#ifdef DEBUG
1561558Srgrimesint	debug;
15773034Sjwd#define OPTIONS	"BNRWb:denrs:w"
1581558Srgrimes#else
15973034Sjwd#define OPTIONS	"BNRWb:enrs:w"
1601558Srgrimes#endif
1611558Srgrimes
16213544Sjoergint
1631558Srgrimesmain(argc, argv)
1641558Srgrimes	int argc;
1651558Srgrimes	char *argv[];
1661558Srgrimes{
1671558Srgrimes	register struct disklabel *lp;
1681558Srgrimes	FILE *t;
16948957Sbillf	int ch, f = 0, flag, error = 0;
1701558Srgrimes	char *name = 0;
1711558Srgrimes
17224359Simp	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
1731558Srgrimes		switch (ch) {
1741558Srgrimes#if NUMBOOT > 0
1751558Srgrimes			case 'B':
1761558Srgrimes				++installboot;
1771558Srgrimes				break;
1781558Srgrimes			case 'b':
1791558Srgrimes				xxboot = optarg;
1801558Srgrimes				break;
1811558Srgrimes#if NUMBOOT > 1
1821558Srgrimes			case 's':
1831558Srgrimes				bootxx = optarg;
1841558Srgrimes				break;
1851558Srgrimes#endif
1861558Srgrimes#endif
1871558Srgrimes			case 'N':
1881558Srgrimes				if (op != UNSPEC)
1891558Srgrimes					usage();
1901558Srgrimes				op = NOWRITE;
1911558Srgrimes				break;
19273034Sjwd			case 'n':
19373034Sjwd				disable_write = 1;
19473034Sjwd				break;
1951558Srgrimes			case 'R':
1961558Srgrimes				if (op != UNSPEC)
1971558Srgrimes					usage();
1981558Srgrimes				op = RESTORE;
1991558Srgrimes				break;
2001558Srgrimes			case 'W':
2011558Srgrimes				if (op != UNSPEC)
2021558Srgrimes					usage();
2031558Srgrimes				op = WRITEABLE;
2041558Srgrimes				break;
2051558Srgrimes			case 'e':
2061558Srgrimes				if (op != UNSPEC)
2071558Srgrimes					usage();
2081558Srgrimes				op = EDIT;
2091558Srgrimes				break;
2101558Srgrimes			case 'r':
2111558Srgrimes				++rflag;
2121558Srgrimes				break;
2131558Srgrimes			case 'w':
2141558Srgrimes				if (op != UNSPEC)
2151558Srgrimes					usage();
2161558Srgrimes				op = WRITE;
2171558Srgrimes				break;
2181558Srgrimes#ifdef DEBUG
2191558Srgrimes			case 'd':
2201558Srgrimes				debug++;
2211558Srgrimes				break;
2221558Srgrimes#endif
2231558Srgrimes			case '?':
2241558Srgrimes			default:
2251558Srgrimes				usage();
2261558Srgrimes		}
2271558Srgrimes	argc -= optind;
2281558Srgrimes	argv += optind;
2291558Srgrimes#if NUMBOOT > 0
2301558Srgrimes	if (installboot) {
2311558Srgrimes		rflag++;
2321558Srgrimes		if (op == UNSPEC)
2331558Srgrimes			op = WRITEBOOT;
2341558Srgrimes	} else {
2351558Srgrimes		if (op == UNSPEC)
2361558Srgrimes			op = READ;
2371558Srgrimes		xxboot = bootxx = 0;
2381558Srgrimes	}
2391558Srgrimes#else
2401558Srgrimes	if (op == UNSPEC)
2411558Srgrimes		op = READ;
2421558Srgrimes#endif
2431558Srgrimes	if (argc < 1)
2441558Srgrimes		usage();
2451558Srgrimes
2461558Srgrimes	dkname = argv[0];
2471558Srgrimes	if (dkname[0] != '/') {
24859114Sobrien		(void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
2491558Srgrimes		specname = np;
2501558Srgrimes		np += strlen(specname) + 1;
2511558Srgrimes	} else
2521558Srgrimes		specname = dkname;
2531558Srgrimes	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2541558Srgrimes	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
25559429Sobrien		(void)sprintf(specname, "%s%s", _PATH_DEV, dkname);
2561558Srgrimes		np = namebuf + strlen(specname) + 1;
2571558Srgrimes		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2581558Srgrimes	}
2591558Srgrimes	if (f < 0)
26026542Scharnier		err(4, "%s", specname);
2611558Srgrimes
2621558Srgrimes	switch(op) {
2631558Srgrimes
26448957Sbillf	case UNSPEC:
26548957Sbillf		break;
26648957Sbillf
2671558Srgrimes	case EDIT:
2681558Srgrimes		if (argc != 1)
2691558Srgrimes			usage();
2701558Srgrimes		lp = readlabel(f);
2711558Srgrimes		error = edit(lp, f);
2721558Srgrimes		break;
2731558Srgrimes
2741558Srgrimes	case NOWRITE:
2751558Srgrimes		flag = 0;
2761558Srgrimes		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
27726542Scharnier			err(4, "ioctl DIOCWLABEL");
2781558Srgrimes		break;
2791558Srgrimes
2801558Srgrimes	case READ:
2811558Srgrimes		if (argc != 1)
2821558Srgrimes			usage();
2831558Srgrimes		lp = readlabel(f);
2841558Srgrimes		display(stdout, lp);
2851558Srgrimes		error = checklabel(lp);
2861558Srgrimes		break;
2871558Srgrimes
2881558Srgrimes	case RESTORE:
2891558Srgrimes#if NUMBOOT > 0
2901558Srgrimes		if (installboot && argc == 3) {
2911558Srgrimes			makelabel(argv[2], 0, &lab);
2921558Srgrimes			argc--;
29337865Sbde
29437865Sbde			/*
29537865Sbde			 * We only called makelabel() for its side effect
29637865Sbde			 * of setting the bootstrap file names.  Discard
29737865Sbde			 * all changes to `lab' so that all values in the
29837865Sbde			 * final label come from the ASCII label.
29937865Sbde			 */
30037865Sbde			bzero((char *)&lab, sizeof(lab));
3011558Srgrimes		}
3021558Srgrimes#endif
3031558Srgrimes		if (argc != 2)
3041558Srgrimes			usage();
3051558Srgrimes		if (!(t = fopen(argv[1], "r")))
30626542Scharnier			err(4, "%s", argv[1]);
30737865Sbde		if (!getasciilabel(t, &lab))
30837865Sbde			exit(1);
30937865Sbde		lp = makebootarea(bootarea, &lab, f);
31037865Sbde		*lp = lab;
31137865Sbde		error = writelabel(f, bootarea, lp);
3121558Srgrimes		break;
3131558Srgrimes
3141558Srgrimes	case WRITE:
3151558Srgrimes		if (argc == 3) {
3161558Srgrimes			name = argv[2];
3171558Srgrimes			argc--;
3181558Srgrimes		}
3191558Srgrimes		if (argc != 2)
3201558Srgrimes			usage();
3211558Srgrimes		makelabel(argv[1], name, &lab);
3221558Srgrimes		lp = makebootarea(bootarea, &lab, f);
3231558Srgrimes		*lp = lab;
3241558Srgrimes		if (checklabel(lp) == 0)
3251558Srgrimes			error = writelabel(f, bootarea, lp);
3261558Srgrimes		break;
3271558Srgrimes
3281558Srgrimes	case WRITEABLE:
3291558Srgrimes		flag = 1;
3301558Srgrimes		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
33126542Scharnier			err(4, "ioctl DIOCWLABEL");
3321558Srgrimes		break;
3331558Srgrimes
3341558Srgrimes#if NUMBOOT > 0
3351558Srgrimes	case WRITEBOOT:
3361558Srgrimes	{
3371558Srgrimes		struct disklabel tlab;
3381558Srgrimes
3391558Srgrimes		lp = readlabel(f);
3401558Srgrimes		tlab = *lp;
3411558Srgrimes		if (argc == 2)
3421558Srgrimes			makelabel(argv[1], 0, &lab);
3431558Srgrimes		lp = makebootarea(bootarea, &lab, f);
3441558Srgrimes		*lp = tlab;
3451558Srgrimes		if (checklabel(lp) == 0)
3461558Srgrimes			error = writelabel(f, bootarea, lp);
3471558Srgrimes		break;
3481558Srgrimes	}
3491558Srgrimes#endif
3501558Srgrimes	}
3511558Srgrimes	exit(error);
3521558Srgrimes}
3531558Srgrimes
3541558Srgrimes/*
3551558Srgrimes * Construct a prototype disklabel from /etc/disktab.  As a side
3561558Srgrimes * effect, set the names of the primary and secondary boot files
3571558Srgrimes * if specified.
3581558Srgrimes */
35913544Sjoergvoid
3601558Srgrimesmakelabel(type, name, lp)
3611558Srgrimes	char *type, *name;
3621558Srgrimes	register struct disklabel *lp;
3631558Srgrimes{
3641558Srgrimes	register struct disklabel *dp;
36513550Sjoerg
36613550Sjoerg	if (strcmp(type, "auto") == 0)
36713550Sjoerg		dp = getvirginlabel();
36813550Sjoerg	else
36913544Sjoerg		dp = getdiskbyname(type);
37036632Scharnier	if (dp == NULL)
37136632Scharnier		errx(1, "%s: unknown disk type", type);
3721558Srgrimes	*lp = *dp;
3731558Srgrimes#if NUMBOOT > 0
3741558Srgrimes	/*
3751558Srgrimes	 * Set bootstrap name(s).
3761558Srgrimes	 * 1. If set from command line, use those,
3771558Srgrimes	 * 2. otherwise, check if disktab specifies them (b0 or b1),
3781558Srgrimes	 * 3. otherwise, makebootarea() will choose ones based on the name
3791558Srgrimes	 *    of the disk special file. E.g. /dev/ra0 -> raboot, bootra
3801558Srgrimes	 */
3811558Srgrimes	if (!xxboot && lp->d_boot0) {
3821558Srgrimes		if (*lp->d_boot0 != '/')
3831558Srgrimes			(void)sprintf(boot0, "%s/%s",
3841558Srgrimes				      _PATH_BOOTDIR, lp->d_boot0);
3851558Srgrimes		else
3861558Srgrimes			(void)strcpy(boot0, lp->d_boot0);
3871558Srgrimes		xxboot = boot0;
3881558Srgrimes	}
3891558Srgrimes#if NUMBOOT > 1
3901558Srgrimes	if (!bootxx && lp->d_boot1) {
3911558Srgrimes		if (*lp->d_boot1 != '/')
3921558Srgrimes			(void)sprintf(boot1, "%s/%s",
3931558Srgrimes				      _PATH_BOOTDIR, lp->d_boot1);
3941558Srgrimes		else
3951558Srgrimes			(void)strcpy(boot1, lp->d_boot1);
3961558Srgrimes		bootxx = boot1;
3971558Srgrimes	}
3981558Srgrimes#endif
3991558Srgrimes#endif
4001558Srgrimes	/* d_packname is union d_boot[01], so zero */
4011558Srgrimes	bzero(lp->d_packname, sizeof(lp->d_packname));
4021558Srgrimes	if (name)
4031558Srgrimes		(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
4041558Srgrimes}
4051558Srgrimes
40613544Sjoergint
4071558Srgrimeswritelabel(f, boot, lp)
4081558Srgrimes	int f;
4091558Srgrimes	char *boot;
4101558Srgrimes	register struct disklabel *lp;
4111558Srgrimes{
4121558Srgrimes	int flag;
41338384Sdfr#ifdef __alpha__
41438384Sdfr	u_long *p, sum;
41538384Sdfr	int i;
41638384Sdfr#endif
41738411Sbde#ifdef vax
41838411Sbde	register int i;
41938411Sbde#endif
42038384Sdfr
42173034Sjwd	if (disable_write) {
42273034Sjwd		Warning("write to disk label supressed - label was as follows:");
42373034Sjwd		display(stdout, lp);
42473034Sjwd		return (0);
42573034Sjwd	} else {
42673034Sjwd		setbootflag(lp);
42773034Sjwd		lp->d_magic = DISKMAGIC;
42873034Sjwd		lp->d_magic2 = DISKMAGIC;
42973034Sjwd		lp->d_checksum = 0;
43073034Sjwd		lp->d_checksum = dkcksum(lp);
43173034Sjwd		if (rflag) {
43273034Sjwd			/*
43373034Sjwd			 * First set the kernel disk label,
43473034Sjwd			 * then write a label to the raw disk.
43573034Sjwd			 * If the SDINFO ioctl fails because it is unimplemented,
43673034Sjwd			 * keep going; otherwise, the kernel consistency checks
43773034Sjwd			 * may prevent us from changing the current (in-core)
43873034Sjwd			 * label.
43973034Sjwd			 */
44073034Sjwd			if (ioctl(f, DIOCSDINFO, lp) < 0 &&
44173034Sjwd				errno != ENODEV && errno != ENOTTY) {
44273034Sjwd				l_perror("ioctl DIOCSDINFO");
44373034Sjwd				return (1);
44473034Sjwd			}
44573034Sjwd			(void)lseek(f, (off_t)0, SEEK_SET);
44673034Sjwd
44738411Sbde#ifdef __alpha__
44873034Sjwd			/*
44973034Sjwd			 * Generate the bootblock checksum for the SRM console.
45073034Sjwd			 */
45173034Sjwd			for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
45273034Sjwd				sum += p[i];
45373034Sjwd			p[63] = sum;
45438384Sdfr#endif
45573034Sjwd
45673034Sjwd			/*
45773034Sjwd			 * write enable label sector before write (if necessary),
45873034Sjwd			 * disable after writing.
45973034Sjwd			 */
46073034Sjwd			flag = 1;
46173034Sjwd			if (ioctl(f, DIOCWLABEL, &flag) < 0)
46273034Sjwd				warn("ioctl DIOCWLABEL");
46373034Sjwd			if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {
46473034Sjwd				warn("write");
46573034Sjwd				return (1);
46673034Sjwd			}
46773034Sjwd#if NUMBOOT > 0
46873034Sjwd			/*
46973034Sjwd			 * Output the remainder of the disklabel
47073034Sjwd			 */
47173034Sjwd			if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
47273034Sjwd				warn("write");
47373034Sjwd				return(1);
47473034Sjwd			}
47573034Sjwd#endif
47673034Sjwd			flag = 0;
47773034Sjwd			(void) ioctl(f, DIOCWLABEL, &flag);
47873034Sjwd		} else if (ioctl(f, DIOCWDINFO, lp) < 0) {
47973034Sjwd			l_perror("ioctl DIOCWDINFO");
4801558Srgrimes			return (1);
4811558Srgrimes		}
48273034Sjwd#ifdef vax
48373034Sjwd		if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {
48473034Sjwd			daddr_t alt;
48573034Sjwd
48673034Sjwd			alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;
48773034Sjwd			for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {
48873034Sjwd				(void)lseek(f, (off_t)((alt + i) * lp->d_secsize),
48973034Sjwd							SEEK_SET);
49073034Sjwd				if (write(f, boot, lp->d_secsize) < lp->d_secsize)
49173034Sjwd					warn("alternate label %d write", i/2);
49273034Sjwd			}
4931558Srgrimes		}
4941558Srgrimes#endif
4951558Srgrimes	}
4961558Srgrimes	return (0);
4971558Srgrimes}
4981558Srgrimes
49913544Sjoergvoid
5001558Srgrimesl_perror(s)
5011558Srgrimes	char *s;
5021558Srgrimes{
50336632Scharnier	switch (errno) {
5041558Srgrimes
5051558Srgrimes	case ESRCH:
50636756Scharnier		warnx("%s: no disk label on disk;", s);
50736756Scharnier		fprintf(stderr,
50840475Sbde		    "use \"disklabel -r\" to install initial label\n");
5091558Srgrimes		break;
5101558Srgrimes
5111558Srgrimes	case EINVAL:
51236756Scharnier		warnx("%s: label magic number or checksum is wrong!", s);
51336756Scharnier		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
5141558Srgrimes		break;
5151558Srgrimes
5161558Srgrimes	case EBUSY:
51736632Scharnier		warnx("%s: open partition would move or shrink", s);
5181558Srgrimes		break;
5191558Srgrimes
5201558Srgrimes	case EXDEV:
52140475Sbde		warnx("%s: '%c' partition must start at beginning of disk",
52240475Sbde		    s, 'a' + RAW_PART);
5231558Srgrimes		break;
5241558Srgrimes
5251558Srgrimes	default:
52636632Scharnier		warn((char *)NULL);
5271558Srgrimes		break;
5281558Srgrimes	}
5291558Srgrimes}
5301558Srgrimes
5311558Srgrimes/*
5321558Srgrimes * Fetch disklabel for disk.
5331558Srgrimes * Use ioctl to get label unless -r flag is given.
5341558Srgrimes */
5351558Srgrimesstruct disklabel *
5361558Srgrimesreadlabel(f)
5371558Srgrimes	int f;
5381558Srgrimes{
5391558Srgrimes	register struct disklabel *lp;
5401558Srgrimes
5411558Srgrimes	if (rflag) {
5421558Srgrimes		if (read(f, bootarea, BBSIZE) < BBSIZE)
54326542Scharnier			err(4, "%s", specname);
5441558Srgrimes		for (lp = (struct disklabel *)bootarea;
5451558Srgrimes		    lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
5461558Srgrimes		    lp = (struct disklabel *)((char *)lp + 16))
5471558Srgrimes			if (lp->d_magic == DISKMAGIC &&
5481558Srgrimes			    lp->d_magic2 == DISKMAGIC)
5491558Srgrimes				break;
5501558Srgrimes		if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
5511558Srgrimes		    lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
55236756Scharnier		    dkcksum(lp) != 0)
55336756Scharnier			errx(1,
55436756Scharnier	    "bad pack magic number (label is damaged, or pack is unlabeled)");
5551558Srgrimes	} else {
5561558Srgrimes		lp = &lab;
5571558Srgrimes		if (ioctl(f, DIOCGDINFO, lp) < 0)
55826542Scharnier			err(4, "ioctl DIOCGDINFO");
5591558Srgrimes	}
5601558Srgrimes	return (lp);
5611558Srgrimes}
5621558Srgrimes
5631558Srgrimes/*
5641558Srgrimes * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
5651558Srgrimes * Returns a pointer to the disklabel portion of the bootarea.
5661558Srgrimes */
5671558Srgrimesstruct disklabel *
5681558Srgrimesmakebootarea(boot, dp, f)
5691558Srgrimes	char *boot;
5701558Srgrimes	register struct disklabel *dp;
5711558Srgrimes	int f;
5721558Srgrimes{
57338483Sbde	struct disklabel *lp;
5741558Srgrimes	register char *p;
5751558Srgrimes	int b;
5761558Srgrimes#if NUMBOOT > 0
5771558Srgrimes	char *dkbasename;
5781558Srgrimes	struct stat sb;
57938411Sbde#endif
58038411Sbde#ifdef __alpha__
58138483Sbde	u_long *bootinfo;
58238411Sbde	int n;
58338411Sbde#endif
58413892Sjoerg#ifdef __i386__
58513892Sjoerg	char *tmpbuf;
58613892Sjoerg	int i, found;
58713544Sjoerg#endif
5881558Srgrimes
5891558Srgrimes	/* XXX */
5901558Srgrimes	if (dp->d_secsize == 0) {
5911558Srgrimes		dp->d_secsize = DEV_BSIZE;
5921558Srgrimes		dp->d_bbsize = BBSIZE;
5931558Srgrimes	}
5941558Srgrimes	lp = (struct disklabel *)
5951558Srgrimes		(boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
5961558Srgrimes	bzero((char *)lp, sizeof *lp);
5971558Srgrimes#if NUMBOOT > 0
5981558Srgrimes	/*
5991558Srgrimes	 * If we are not installing a boot program but we are installing a
6001558Srgrimes	 * label on disk then we must read the current bootarea so we don't
6011558Srgrimes	 * clobber the existing boot.
6021558Srgrimes	 */
6031558Srgrimes	if (!installboot) {
6041558Srgrimes		if (rflag) {
6051558Srgrimes			if (read(f, boot, BBSIZE) < BBSIZE)
60626542Scharnier				err(4, "%s", specname);
6071558Srgrimes			bzero((char *)lp, sizeof *lp);
6081558Srgrimes		}
6091558Srgrimes		return (lp);
6101558Srgrimes	}
6111558Srgrimes	/*
6121558Srgrimes	 * We are installing a boot program.  Determine the name(s) and
6131558Srgrimes	 * read them into the appropriate places in the boot area.
6141558Srgrimes	 */
6151558Srgrimes	if (!xxboot || !bootxx) {
6161558Srgrimes		dkbasename = np;
6171558Srgrimes		if ((p = rindex(dkname, '/')) == NULL)
6181558Srgrimes			p = dkname;
6191558Srgrimes		else
6201558Srgrimes			p++;
6211558Srgrimes		while (*p && !isdigit(*p))
6221558Srgrimes			*np++ = *p++;
6231558Srgrimes		*np++ = '\0';
6241558Srgrimes
6251558Srgrimes		if (!xxboot) {
62641901Sjkh			(void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
62741901Sjkh			xxboot = boot0;
6281558Srgrimes		}
6291558Srgrimes#if NUMBOOT > 1
6301558Srgrimes		if (!bootxx) {
63141901Sjkh			(void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
63241901Sjkh			bootxx = boot1;
6331558Srgrimes		}
6341558Srgrimes#endif
6351558Srgrimes	}
6361558Srgrimes#ifdef DEBUG
6371558Srgrimes	if (debug)
6381558Srgrimes		fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n",
6391558Srgrimes			xxboot, bootxx ? bootxx : "NONE");
6401558Srgrimes#endif
6411558Srgrimes
6421558Srgrimes	/*
6431558Srgrimes	 * Strange rules:
6441558Srgrimes	 * 1. One-piece bootstrap (hp300/hp800)
6451558Srgrimes	 *	up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
6461558Srgrimes	 *	is remembered and written later following the bootarea.
6471558Srgrimes	 * 2. Two-piece bootstraps (vax/i386?/mips?)
6481558Srgrimes	 *	up to d_secsize bytes of ``xxboot'' go in first d_secsize
6491558Srgrimes	 *	bytes of bootarea, remaining d_bbsize-d_secsize filled
6501558Srgrimes	 *	from ``bootxx''.
6511558Srgrimes	 */
6521558Srgrimes	b = open(xxboot, O_RDONLY);
6531558Srgrimes	if (b < 0)
65426542Scharnier		err(4, "%s", xxboot);
6551558Srgrimes#if NUMBOOT > 1
65613892Sjoerg#ifdef __i386__
65713892Sjoerg	/*
65813892Sjoerg	 * XXX Botch alert.
65913892Sjoerg	 * The i386 has the so-called fdisk table embedded into the
66013892Sjoerg	 * primary bootstrap.  We take care to not clobber it, but
66113892Sjoerg	 * only if it does already contain some data.  (Otherwise,
66213892Sjoerg	 * the xxboot provides a template.)
66313892Sjoerg	 */
66413892Sjoerg	if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
66526542Scharnier		err(4, "%s", xxboot);
66613892Sjoerg	memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
66713892Sjoerg#endif /* i386 */
6681558Srgrimes	if (read(b, boot, (int)dp->d_secsize) < 0)
66926542Scharnier		err(4, "%s", xxboot);
6701558Srgrimes	(void)close(b);
67113892Sjoerg#ifdef __i386__
67213892Sjoerg	for (i = DOSPARTOFF, found = 0;
67313892Sjoerg	     !found && i < DOSPARTOFF + NDOSPART*sizeof(struct dos_partition);
67413892Sjoerg	     i++)
67513892Sjoerg		found = tmpbuf[i] != 0;
67613892Sjoerg	if (found)
67713892Sjoerg		memcpy((void *)&boot[DOSPARTOFF],
67813892Sjoerg		       (void *)&tmpbuf[DOSPARTOFF],
67913892Sjoerg		       NDOSPART * sizeof(struct dos_partition));
68013892Sjoerg	free(tmpbuf);
68113892Sjoerg#endif /* i386 */
6821558Srgrimes	b = open(bootxx, O_RDONLY);
6831558Srgrimes	if (b < 0)
68426542Scharnier		err(4, "%s", bootxx);
68537865Sbde	if (fstat(b, &sb) != 0)
68637865Sbde		err(4, "%s", bootxx);
68737865Sbde	if (dp->d_secsize + sb.st_size > dp->d_bbsize)
68837865Sbde		errx(4, "%s too large", bootxx);
68913544Sjoerg	if (read(b, &boot[dp->d_secsize],
69013544Sjoerg		 (int)(dp->d_bbsize-dp->d_secsize)) < 0)
69126542Scharnier		err(4, "%s", bootxx);
69238411Sbde#else /* !(NUMBOOT > 1) */
69338384Sdfr#ifdef __alpha__
69438411Sbde	/*
69538411Sbde	 * On the alpha, the primary bootstrap starts at the
69638411Sbde	 * second sector of the boot area.  The first sector
69738411Sbde	 * contains the label and must be edited to contain the
69838411Sbde	 * size and location of the primary bootstrap.
69938411Sbde	 */
70038411Sbde	n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize);
70138411Sbde	if (n < 0)
70238384Sdfr		err(4, "%s", xxboot);
70338483Sbde	bootinfo = (u_long *)(boot + 480);
70438483Sbde	bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
70538483Sbde	bootinfo[1] = 1;	/* start at sector 1 */
70638483Sbde	bootinfo[2] = 0;	/* flags (must be zero) */
70738411Sbde#else /* !__alpha__ */
7081558Srgrimes	if (read(b, boot, (int)dp->d_bbsize) < 0)
70926542Scharnier		err(4, "%s", xxboot);
71038411Sbde#endif /* __alpha__ */
71137865Sbde	if (fstat(b, &sb) != 0)
71237865Sbde		err(4, "%s", xxboot);
7131558Srgrimes	bootsize = (int)sb.st_size - dp->d_bbsize;
7141558Srgrimes	if (bootsize > 0) {
7151558Srgrimes		/* XXX assume d_secsize is a power of two */
7161558Srgrimes		bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
7171558Srgrimes		bootbuf = (char *)malloc((size_t)bootsize);
7181558Srgrimes		if (bootbuf == 0)
71926542Scharnier			err(4, "%s", xxboot);
7201558Srgrimes		if (read(b, bootbuf, bootsize) < 0) {
7211558Srgrimes			free(bootbuf);
72226542Scharnier			err(4, "%s", xxboot);
7231558Srgrimes		}
7241558Srgrimes	}
72538411Sbde#endif /* NUMBOOT > 1 */
7261558Srgrimes	(void)close(b);
72738411Sbde#endif /* NUMBOOT > 0 */
7281558Srgrimes	/*
7291558Srgrimes	 * Make sure no part of the bootstrap is written in the area
7301558Srgrimes	 * reserved for the label.
7311558Srgrimes	 */
7321558Srgrimes	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
73336632Scharnier		if (*p)
73436632Scharnier			errx(2, "bootstrap doesn't leave room for disk label");
7351558Srgrimes	return (lp);
7361558Srgrimes}
7371558Srgrimes
73813544Sjoergvoid
7391558Srgrimesdisplay(f, lp)
7401558Srgrimes	FILE *f;
7411558Srgrimes	register struct disklabel *lp;
7421558Srgrimes{
7431558Srgrimes	register int i, j;
7441558Srgrimes	register struct partition *pp;
7451558Srgrimes
7461558Srgrimes	fprintf(f, "# %s:\n", specname);
7471558Srgrimes	if ((unsigned) lp->d_type < DKMAXTYPES)
7481558Srgrimes		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
7491558Srgrimes	else
75037234Sbde		fprintf(f, "type: %u\n", lp->d_type);
75113544Sjoerg	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
75213544Sjoerg		lp->d_typename);
75313544Sjoerg	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
75413544Sjoerg		lp->d_packname);
7551558Srgrimes	fprintf(f, "flags:");
7561558Srgrimes	if (lp->d_flags & D_REMOVABLE)
7571558Srgrimes		fprintf(f, " removeable");
7581558Srgrimes	if (lp->d_flags & D_ECC)
7591558Srgrimes		fprintf(f, " ecc");
7601558Srgrimes	if (lp->d_flags & D_BADSECT)
7611558Srgrimes		fprintf(f, " badsect");
7621558Srgrimes	fprintf(f, "\n");
76337234Sbde	fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
76437234Sbde	fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
76537234Sbde	fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
76637234Sbde	fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
76737234Sbde	fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
76837234Sbde	fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
76937234Sbde	fprintf(f, "rpm: %u\n", lp->d_rpm);
77037234Sbde	fprintf(f, "interleave: %u\n", lp->d_interleave);
77137234Sbde	fprintf(f, "trackskew: %u\n", lp->d_trackskew);
77237234Sbde	fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
77337234Sbde	fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
77437234Sbde	    (u_long)lp->d_headswitch);
77513544Sjoerg	fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
77637234Sbde	    (u_long)lp->d_trkseek);
7771558Srgrimes	fprintf(f, "drivedata: ");
7781558Srgrimes	for (i = NDDATA - 1; i >= 0; i--)
7791558Srgrimes		if (lp->d_drivedata[i])
7801558Srgrimes			break;
7811558Srgrimes	if (i < 0)
7821558Srgrimes		i = 0;
7831558Srgrimes	for (j = 0; j <= i; j++)
78437234Sbde		fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
78537234Sbde	fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
7861558Srgrimes	fprintf(f,
7875393Sgibbs	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
7881558Srgrimes	pp = lp->d_partitions;
7891558Srgrimes	for (i = 0; i < lp->d_npartitions; i++, pp++) {
7901558Srgrimes		if (pp->p_size) {
79137234Sbde			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
79237234Sbde			   (u_long)pp->p_size, (u_long)pp->p_offset);
7931558Srgrimes			if ((unsigned) pp->p_fstype < FSMAXTYPES)
7941558Srgrimes				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
7951558Srgrimes			else
7961558Srgrimes				fprintf(f, "%8d", pp->p_fstype);
7971558Srgrimes			switch (pp->p_fstype) {
7981558Srgrimes
7991558Srgrimes			case FS_UNUSED:				/* XXX */
80037234Sbde				fprintf(f, "    %5lu %5lu %5.5s ",
80137234Sbde				    (u_long)pp->p_fsize,
80237234Sbde				    (u_long)(pp->p_fsize * pp->p_frag), "");
8031558Srgrimes				break;
8041558Srgrimes
8051558Srgrimes			case FS_BSDFFS:
80637234Sbde				fprintf(f, "    %5lu %5lu %5u ",
80737234Sbde				    (u_long)pp->p_fsize,
80837234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
8091558Srgrimes				    pp->p_cpg);
8101558Srgrimes				break;
8111558Srgrimes
8125393Sgibbs			case FS_BSDLFS:
81337234Sbde				fprintf(f, "    %5lu %5lu %5d",
81437234Sbde				    (u_long)pp->p_fsize,
81537234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
8165393Sgibbs				    pp->p_cpg);
8175393Sgibbs				break;
8185393Sgibbs
8191558Srgrimes			default:
8201558Srgrimes				fprintf(f, "%20.20s", "");
8211558Srgrimes				break;
8221558Srgrimes			}
82337234Sbde			fprintf(f, "\t# (Cyl. %4lu",
82437234Sbde			    (u_long)(pp->p_offset / lp->d_secpercyl));
8251558Srgrimes			if (pp->p_offset % lp->d_secpercyl)
8261558Srgrimes			    putc('*', f);
8271558Srgrimes			else
8281558Srgrimes			    putc(' ', f);
82937234Sbde			fprintf(f, "- %lu",
83037234Sbde			    (u_long)((pp->p_offset + pp->p_size +
83137234Sbde			    lp->d_secpercyl - 1) /
83237234Sbde			    lp->d_secpercyl - 1));
8331558Srgrimes			if (pp->p_size % lp->d_secpercyl)
8341558Srgrimes			    putc('*', f);
8351558Srgrimes			fprintf(f, ")\n");
8361558Srgrimes		}
8371558Srgrimes	}
8381558Srgrimes	fflush(f);
8391558Srgrimes}
8401558Srgrimes
84113544Sjoergint
8421558Srgrimesedit(lp, f)
8431558Srgrimes	struct disklabel *lp;
8441558Srgrimes	int f;
8451558Srgrimes{
84624180Simp	register int c, fd;
8471558Srgrimes	struct disklabel label;
84824180Simp	FILE *fp;
8491558Srgrimes
85024180Simp	if ((fd = mkstemp(tmpfil)) == -1 ||
85124180Simp	    (fp = fdopen(fd, "w")) == NULL) {
85236632Scharnier		warnx("can't create %s", tmpfil);
8531558Srgrimes		return (1);
8541558Srgrimes	}
85524180Simp	display(fp, lp);
85624180Simp	fclose(fp);
8571558Srgrimes	for (;;) {
8581558Srgrimes		if (!editit())
8591558Srgrimes			break;
86024180Simp		fp = fopen(tmpfil, "r");
86124180Simp		if (fp == NULL) {
86236632Scharnier			warnx("can't reopen %s for reading", tmpfil);
8631558Srgrimes			break;
8641558Srgrimes		}
8651558Srgrimes		bzero((char *)&label, sizeof(label));
86624180Simp		if (getasciilabel(fp, &label)) {
8671558Srgrimes			*lp = label;
8681558Srgrimes			if (writelabel(f, bootarea, lp) == 0) {
86924180Simp				fclose(fp);
8701558Srgrimes				(void) unlink(tmpfil);
8711558Srgrimes				return (0);
8721558Srgrimes			}
8731558Srgrimes		}
87424180Simp		fclose(fp);
8751558Srgrimes		printf("re-edit the label? [y]: "); fflush(stdout);
8761558Srgrimes		c = getchar();
8771558Srgrimes		if (c != EOF && c != (int)'\n')
8781558Srgrimes			while (getchar() != (int)'\n')
8791558Srgrimes				;
8801558Srgrimes		if  (c == (int)'n')
8811558Srgrimes			break;
8821558Srgrimes	}
8831558Srgrimes	(void) unlink(tmpfil);
8841558Srgrimes	return (1);
8851558Srgrimes}
8861558Srgrimes
88713544Sjoergint
8881558Srgrimeseditit()
8891558Srgrimes{
8901558Srgrimes	register int pid, xpid;
8911558Srgrimes	int stat, omask;
8921558Srgrimes
8931558Srgrimes	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
8941558Srgrimes	while ((pid = fork()) < 0) {
8951558Srgrimes		if (errno == EPROCLIM) {
89636632Scharnier			warnx("you have too many processes");
8971558Srgrimes			return(0);
8981558Srgrimes		}
8991558Srgrimes		if (errno != EAGAIN) {
90036632Scharnier			warn("fork");
9011558Srgrimes			return(0);
9021558Srgrimes		}
9031558Srgrimes		sleep(1);
9041558Srgrimes	}
9051558Srgrimes	if (pid == 0) {
9061558Srgrimes		register char *ed;
9071558Srgrimes
9081558Srgrimes		sigsetmask(omask);
9091558Srgrimes		setgid(getgid());
9101558Srgrimes		setuid(getuid());
9111558Srgrimes		if ((ed = getenv("EDITOR")) == (char *)0)
9121558Srgrimes			ed = DEFEDITOR;
9131558Srgrimes		execlp(ed, ed, tmpfil, 0);
91436632Scharnier		err(1, "%s", ed);
9151558Srgrimes	}
9161558Srgrimes	while ((xpid = wait(&stat)) >= 0)
9171558Srgrimes		if (xpid == pid)
9181558Srgrimes			break;
9191558Srgrimes	sigsetmask(omask);
9201558Srgrimes	return(!stat);
9211558Srgrimes}
9221558Srgrimes
9231558Srgrimeschar *
9241558Srgrimesskip(cp)
9251558Srgrimes	register char *cp;
9261558Srgrimes{
9271558Srgrimes
9281558Srgrimes	while (*cp != '\0' && isspace(*cp))
9291558Srgrimes		cp++;
9301558Srgrimes	if (*cp == '\0' || *cp == '#')
9311558Srgrimes		return ((char *)NULL);
9321558Srgrimes	return (cp);
9331558Srgrimes}
9341558Srgrimes
9351558Srgrimeschar *
9361558Srgrimesword(cp)
9371558Srgrimes	register char *cp;
9381558Srgrimes{
9391558Srgrimes	register char c;
9401558Srgrimes
9411558Srgrimes	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
9421558Srgrimes		cp++;
9431558Srgrimes	if ((c = *cp) != '\0') {
9441558Srgrimes		*cp++ = '\0';
9451558Srgrimes		if (c != '#')
9461558Srgrimes			return (skip(cp));
9471558Srgrimes	}
9481558Srgrimes	return ((char *)NULL);
9491558Srgrimes}
9501558Srgrimes
9511558Srgrimes/*
9521558Srgrimes * Read an ascii label in from fd f,
9531558Srgrimes * in the same format as that put out by display(),
9541558Srgrimes * and fill in lp.
9551558Srgrimes */
95613544Sjoergint
9571558Srgrimesgetasciilabel(f, lp)
9581558Srgrimes	FILE	*f;
9591558Srgrimes	register struct disklabel *lp;
9601558Srgrimes{
9611558Srgrimes	register char **cpp, *cp;
9621558Srgrimes	register struct partition *pp;
96373034Sjwd	int i;
96473034Sjwd	unsigned int part;
9651558Srgrimes	char *tp, *s, line[BUFSIZ];
9661558Srgrimes	int v, lineno = 0, errors = 0;
9671558Srgrimes
9681558Srgrimes	lp->d_bbsize = BBSIZE;				/* XXX */
9691558Srgrimes	lp->d_sbsize = SBSIZE;				/* XXX */
9701558Srgrimes	while (fgets(line, sizeof(line) - 1, f)) {
9711558Srgrimes		lineno++;
97213544Sjoerg		if ((cp = index(line,'\n')) != 0)
9731558Srgrimes			*cp = '\0';
9741558Srgrimes		cp = skip(line);
9751558Srgrimes		if (cp == NULL)
9761558Srgrimes			continue;
9771558Srgrimes		tp = index(cp, ':');
9781558Srgrimes		if (tp == NULL) {
9791558Srgrimes			fprintf(stderr, "line %d: syntax error\n", lineno);
9801558Srgrimes			errors++;
9811558Srgrimes			continue;
9821558Srgrimes		}
9831558Srgrimes		*tp++ = '\0', tp = skip(tp);
9841558Srgrimes		if (streq(cp, "type")) {
9851558Srgrimes			if (tp == NULL)
9861558Srgrimes				tp = "unknown";
9871558Srgrimes			cpp = dktypenames;
9881558Srgrimes			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
9891558Srgrimes				if ((s = *cpp) && streq(s, tp)) {
9901558Srgrimes					lp->d_type = cpp - dktypenames;
9911558Srgrimes					goto next;
9921558Srgrimes				}
9931558Srgrimes			v = atoi(tp);
9941558Srgrimes			if ((unsigned)v >= DKMAXTYPES)
9951558Srgrimes				fprintf(stderr, "line %d:%s %d\n", lineno,
9961558Srgrimes				    "Warning, unknown disk type", v);
9971558Srgrimes			lp->d_type = v;
9981558Srgrimes			continue;
9991558Srgrimes		}
10001558Srgrimes		if (streq(cp, "flags")) {
10011558Srgrimes			for (v = 0; (cp = tp) && *cp != '\0';) {
10021558Srgrimes				tp = word(cp);
10031558Srgrimes				if (streq(cp, "removeable"))
10041558Srgrimes					v |= D_REMOVABLE;
10051558Srgrimes				else if (streq(cp, "ecc"))
10061558Srgrimes					v |= D_ECC;
10071558Srgrimes				else if (streq(cp, "badsect"))
10081558Srgrimes					v |= D_BADSECT;
10091558Srgrimes				else {
10101558Srgrimes					fprintf(stderr,
10111558Srgrimes					    "line %d: %s: bad flag\n",
10121558Srgrimes					    lineno, cp);
10131558Srgrimes					errors++;
10141558Srgrimes				}
10151558Srgrimes			}
10161558Srgrimes			lp->d_flags = v;
10171558Srgrimes			continue;
10181558Srgrimes		}
10191558Srgrimes		if (streq(cp, "drivedata")) {
10201558Srgrimes			register int i;
10211558Srgrimes
10221558Srgrimes			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
10231558Srgrimes				lp->d_drivedata[i++] = atoi(cp);
10241558Srgrimes				tp = word(cp);
10251558Srgrimes			}
10261558Srgrimes			continue;
10271558Srgrimes		}
10281558Srgrimes		if (sscanf(cp, "%d partitions", &v) == 1) {
10291558Srgrimes			if (v == 0 || (unsigned)v > MAXPARTITIONS) {
10301558Srgrimes				fprintf(stderr,
10311558Srgrimes				    "line %d: bad # of partitions\n", lineno);
10321558Srgrimes				lp->d_npartitions = MAXPARTITIONS;
10331558Srgrimes				errors++;
10341558Srgrimes			} else
10351558Srgrimes				lp->d_npartitions = v;
10361558Srgrimes			continue;
10371558Srgrimes		}
10381558Srgrimes		if (tp == NULL)
10391558Srgrimes			tp = "";
10401558Srgrimes		if (streq(cp, "disk")) {
10411558Srgrimes			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
10421558Srgrimes			continue;
10431558Srgrimes		}
10441558Srgrimes		if (streq(cp, "label")) {
10451558Srgrimes			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
10461558Srgrimes			continue;
10471558Srgrimes		}
10481558Srgrimes		if (streq(cp, "bytes/sector")) {
10491558Srgrimes			v = atoi(tp);
105037865Sbde			if (v <= 0 || (v % DEV_BSIZE) != 0) {
10511558Srgrimes				fprintf(stderr,
10521558Srgrimes				    "line %d: %s: bad sector size\n",
10531558Srgrimes				    lineno, tp);
10541558Srgrimes				errors++;
10551558Srgrimes			} else
10561558Srgrimes				lp->d_secsize = v;
10571558Srgrimes			continue;
10581558Srgrimes		}
10591558Srgrimes		if (streq(cp, "sectors/track")) {
10601558Srgrimes			v = atoi(tp);
10611558Srgrimes			if (v <= 0) {
10621558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10631558Srgrimes				    lineno, tp, cp);
10641558Srgrimes				errors++;
10651558Srgrimes			} else
10661558Srgrimes				lp->d_nsectors = v;
10671558Srgrimes			continue;
10681558Srgrimes		}
10691558Srgrimes		if (streq(cp, "sectors/cylinder")) {
10701558Srgrimes			v = atoi(tp);
10711558Srgrimes			if (v <= 0) {
10721558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10731558Srgrimes				    lineno, tp, cp);
10741558Srgrimes				errors++;
10751558Srgrimes			} else
10761558Srgrimes				lp->d_secpercyl = v;
10771558Srgrimes			continue;
10781558Srgrimes		}
10791558Srgrimes		if (streq(cp, "tracks/cylinder")) {
10801558Srgrimes			v = atoi(tp);
10811558Srgrimes			if (v <= 0) {
10821558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10831558Srgrimes				    lineno, tp, cp);
10841558Srgrimes				errors++;
10851558Srgrimes			} else
10861558Srgrimes				lp->d_ntracks = v;
10871558Srgrimes			continue;
10881558Srgrimes		}
10891558Srgrimes		if (streq(cp, "cylinders")) {
10901558Srgrimes			v = atoi(tp);
10911558Srgrimes			if (v <= 0) {
10921558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10931558Srgrimes				    lineno, tp, cp);
10941558Srgrimes				errors++;
10951558Srgrimes			} else
10961558Srgrimes				lp->d_ncylinders = v;
10971558Srgrimes			continue;
10981558Srgrimes		}
10996643Sbde		if (streq(cp, "sectors/unit")) {
11006643Sbde			v = atoi(tp);
11016643Sbde			if (v <= 0) {
11026643Sbde				fprintf(stderr, "line %d: %s: bad %s\n",
11036643Sbde				    lineno, tp, cp);
11046643Sbde				errors++;
11056643Sbde			} else
11066643Sbde				lp->d_secperunit = v;
11076643Sbde			continue;
11086643Sbde		}
11091558Srgrimes		if (streq(cp, "rpm")) {
11101558Srgrimes			v = atoi(tp);
11111558Srgrimes			if (v <= 0) {
11121558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11131558Srgrimes				    lineno, tp, cp);
11141558Srgrimes				errors++;
11151558Srgrimes			} else
11161558Srgrimes				lp->d_rpm = v;
11171558Srgrimes			continue;
11181558Srgrimes		}
11191558Srgrimes		if (streq(cp, "interleave")) {
11201558Srgrimes			v = atoi(tp);
11211558Srgrimes			if (v <= 0) {
11221558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11231558Srgrimes				    lineno, tp, cp);
11241558Srgrimes				errors++;
11251558Srgrimes			} else
11261558Srgrimes				lp->d_interleave = v;
11271558Srgrimes			continue;
11281558Srgrimes		}
11291558Srgrimes		if (streq(cp, "trackskew")) {
11301558Srgrimes			v = atoi(tp);
11311558Srgrimes			if (v < 0) {
11321558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11331558Srgrimes				    lineno, tp, cp);
11341558Srgrimes				errors++;
11351558Srgrimes			} else
11361558Srgrimes				lp->d_trackskew = v;
11371558Srgrimes			continue;
11381558Srgrimes		}
11391558Srgrimes		if (streq(cp, "cylinderskew")) {
11401558Srgrimes			v = atoi(tp);
11411558Srgrimes			if (v < 0) {
11421558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11431558Srgrimes				    lineno, tp, cp);
11441558Srgrimes				errors++;
11451558Srgrimes			} else
11461558Srgrimes				lp->d_cylskew = v;
11471558Srgrimes			continue;
11481558Srgrimes		}
11491558Srgrimes		if (streq(cp, "headswitch")) {
11501558Srgrimes			v = atoi(tp);
11511558Srgrimes			if (v < 0) {
11521558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11531558Srgrimes				    lineno, tp, cp);
11541558Srgrimes				errors++;
11551558Srgrimes			} else
11561558Srgrimes				lp->d_headswitch = v;
11571558Srgrimes			continue;
11581558Srgrimes		}
11591558Srgrimes		if (streq(cp, "track-to-track seek")) {
11601558Srgrimes			v = atoi(tp);
11611558Srgrimes			if (v < 0) {
11621558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
11631558Srgrimes				    lineno, tp, cp);
11641558Srgrimes				errors++;
11651558Srgrimes			} else
11661558Srgrimes				lp->d_trkseek = v;
11671558Srgrimes			continue;
11681558Srgrimes		}
116973034Sjwd		/* the ':' was removed above */
117073034Sjwd		if ('a' <= *cp && *cp <= MAX_PART && cp[1] == '\0') {
117173034Sjwd			part = *cp - 'a';
117273034Sjwd			if (part >= lp->d_npartitions) {
11731558Srgrimes				fprintf(stderr,
117473034Sjwd				    "line %d: partition name out of range a-%c: %s\n",
117573034Sjwd				    lineno, 'a' + lp->d_npartitions - 1, cp);
11761558Srgrimes				errors++;
11771558Srgrimes				continue;
11781558Srgrimes			}
11791558Srgrimes			pp = &lp->d_partitions[part];
118073034Sjwd			part_set[part] = 1;
11811558Srgrimes#define NXTNUM(n) { \
11823111Spst	if (tp == NULL) { \
11833111Spst		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
11843111Spst		errors++; \
11853111Spst		break; \
11863111Spst	} else { \
11873111Spst		cp = tp, tp = word(cp); \
11883111Spst		if (tp == NULL) \
11893111Spst			tp = cp; \
11903111Spst		(n) = atoi(cp); \
11913111Spst	} \
11921558Srgrimes     }
119373034Sjwd/* retain 1 character following number */
119473034Sjwd#define NXTWORD(w,n) { \
119573034Sjwd	if (tp == NULL) { \
119673034Sjwd		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
119773034Sjwd		errors++; \
119873034Sjwd		break; \
119973034Sjwd	} else { \
120073034Sjwd	        char *tmp; \
120173034Sjwd		cp = tp, tp = word(cp); \
120273034Sjwd		if (tp == NULL) \
120373034Sjwd			tp = cp; \
120473034Sjwd	        (n) = strtol(cp,&tmp,10); \
120573034Sjwd		if (tmp) (w) = *tmp; \
120673034Sjwd	} \
120773034Sjwd     }
120873034Sjwd			v = 0;
120973034Sjwd			NXTWORD(part_size_type[part],v);
121073034Sjwd			if (v < 0 || (v == 0 && part_size_type[part] != '*')) {
12111558Srgrimes				fprintf(stderr,
12121558Srgrimes				    "line %d: %s: bad partition size\n",
12131558Srgrimes				    lineno, cp);
12141558Srgrimes				errors++;
121573034Sjwd				break;
121673034Sjwd			} else {
12171558Srgrimes				pp->p_size = v;
12181558Srgrimes
121973034Sjwd				v = 0;
122073034Sjwd				NXTWORD(part_offset_type[part],v);
122173034Sjwd				if (v < 0 || (v == 0 &&
122273034Sjwd				    part_offset_type[part] != '*' &&
122373034Sjwd				    part_offset_type[part] != '\0')) {
122473034Sjwd					fprintf(stderr,
122573034Sjwd					    "line %d: %s: bad partition offset\n",
122673034Sjwd					    lineno, cp);
122773034Sjwd					errors++;
12281558Srgrimes					break;
122973034Sjwd				} else {
123073034Sjwd					pp->p_offset = v;
123173034Sjwd					cp = tp, tp = word(cp);
123273034Sjwd					cpp = fstypenames;
123373034Sjwd					for (; cpp < &fstypenames[FSMAXTYPES]; cpp++)
123473034Sjwd						if ((s = *cpp) && streq(s, cp)) {
123573034Sjwd							pp->p_fstype = cpp -
123673034Sjwd							    fstypenames;
123773034Sjwd							goto gottype;
123873034Sjwd						}
123973034Sjwd					if (isdigit(*cp))
124073034Sjwd						v = atoi(cp);
124173034Sjwd					else
124273034Sjwd						v = FSMAXTYPES;
124373034Sjwd					if ((unsigned)v >= FSMAXTYPES) {
124473034Sjwd						fprintf(stderr,
124573034Sjwd						    "line %d: Warning, unknown "
124673034Sjwd						    "filesystem type %s\n",
124773034Sjwd						    lineno, cp);
124873034Sjwd						v = FS_UNUSED;
124973034Sjwd					}
125073034Sjwd					pp->p_fstype = v;
125173034Sjwd				gottype:;
125273034Sjwd					/*
125373034Sjwd					 * Note: NXTNUM will break us out of the
125473034Sjwd					 * switch only!
125573034Sjwd					 */
125673034Sjwd					switch (pp->p_fstype) {
125773034Sjwd					case FS_UNUSED:
125873034Sjwd						/*
125973034Sjwd						 * allow us to accept defaults for
126073034Sjwd						 * fsize/frag/cpg
126173034Sjwd						 */
126273034Sjwd						if (tp) {
126373034Sjwd							NXTNUM(pp->p_fsize);
126473034Sjwd							if (pp->p_fsize == 0)
126573034Sjwd								break;
126673034Sjwd							NXTNUM(v);
126773034Sjwd							pp->p_frag = v / pp->p_fsize;
126873034Sjwd						}
126973034Sjwd						/* else default to 0's */
127073034Sjwd						break;
12711558Srgrimes
127273034Sjwd					/* These happen to be the same */
127373034Sjwd					case FS_BSDFFS:
127473034Sjwd					case FS_BSDLFS:
127573034Sjwd						if (tp) {
127673034Sjwd							NXTNUM(pp->p_fsize);
127773034Sjwd							if (pp->p_fsize == 0)
127873034Sjwd								break;
127973034Sjwd							NXTNUM(v);
128073034Sjwd							pp->p_frag = v / pp->p_fsize;
128173034Sjwd							NXTNUM(pp->p_cpg);
128273034Sjwd						} else {
128373034Sjwd							/*
128473034Sjwd							 * FIX! poor attempt at
128573034Sjwd							 * adaptive
128673034Sjwd							 */
128773034Sjwd							/* 1 GB */
128873034Sjwd							if (pp->p_size < 1*1024*1024*1024/lp->d_secsize) {
128973034Sjwd/* FIX!  These are too low, but are traditional */
129073034Sjwd								pp->p_fsize = DEFAULT_NEWFS_BLOCK;
129173034Sjwd								pp->p_frag  = (unsigned char) DEFAULT_NEWFS_FRAG;
129273034Sjwd								pp->p_cpg   = DEFAULT_NEWFS_CPG;
129373034Sjwd							} else {
129473034Sjwd								pp->p_fsize = BIG_NEWFS_BLOCK;
129573034Sjwd								pp->p_frag  = (unsigned char) BIG_NEWFS_FRAG;
129673034Sjwd								pp->p_cpg   = BIG_NEWFS_CPG;
129773034Sjwd							}
129873034Sjwd						}
129973034Sjwd						break;
130073034Sjwd					default:
130173034Sjwd						break;
130273034Sjwd					}
13031558Srgrimes
130473034Sjwd					/*
130573034Sjwd					 * note: we may not have
130673034Sjwd					 * gotten all the entries for
130773034Sjwd					 * the fs though if we didn't,
130873034Sjwd					 * errors will be set.
130973034Sjwd					 */
131073034Sjwd				}
13111558Srgrimes			}
13121558Srgrimes			continue;
13131558Srgrimes		}
13141558Srgrimes		fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
13151558Srgrimes		    lineno, cp);
13161558Srgrimes		errors++;
131773034Sjwd	next:;
13181558Srgrimes	}
13191558Srgrimes	errors += checklabel(lp);
13201558Srgrimes	return (errors == 0);
13211558Srgrimes}
13221558Srgrimes
13231558Srgrimes/*
13241558Srgrimes * Check disklabel for errors and fill in
13251558Srgrimes * derived fields according to supplied values.
13261558Srgrimes */
132713544Sjoergint
13281558Srgrimeschecklabel(lp)
13291558Srgrimes	register struct disklabel *lp;
13301558Srgrimes{
13311558Srgrimes	register struct partition *pp;
13321558Srgrimes	int i, errors = 0;
13331558Srgrimes	char part;
133473034Sjwd	unsigned long total_size,total_percent,current_offset;
133573034Sjwd	int seen_default_offset;
133673034Sjwd	int hog_part;
133773034Sjwd	int j;
133873034Sjwd	struct partition *pp2;
13391558Srgrimes
13401558Srgrimes	if (lp->d_secsize == 0) {
134137234Sbde		fprintf(stderr, "sector size 0\n");
13421558Srgrimes		return (1);
13431558Srgrimes	}
13441558Srgrimes	if (lp->d_nsectors == 0) {
134537234Sbde		fprintf(stderr, "sectors/track 0\n");
13461558Srgrimes		return (1);
13471558Srgrimes	}
13481558Srgrimes	if (lp->d_ntracks == 0) {
134937234Sbde		fprintf(stderr, "tracks/cylinder 0\n");
13501558Srgrimes		return (1);
13511558Srgrimes	}
13521558Srgrimes	if  (lp->d_ncylinders == 0) {
135337234Sbde		fprintf(stderr, "cylinders/unit 0\n");
13541558Srgrimes		errors++;
13551558Srgrimes	}
13561558Srgrimes	if (lp->d_rpm == 0)
135737234Sbde		Warning("revolutions/minute 0");
13581558Srgrimes	if (lp->d_secpercyl == 0)
13591558Srgrimes		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
13601558Srgrimes	if (lp->d_secperunit == 0)
13611558Srgrimes		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
13621558Srgrimes	if (lp->d_bbsize == 0) {
136337234Sbde		fprintf(stderr, "boot block size 0\n");
13641558Srgrimes		errors++;
13651558Srgrimes	} else if (lp->d_bbsize % lp->d_secsize)
13661558Srgrimes		Warning("boot block size %% sector-size != 0");
13671558Srgrimes	if (lp->d_sbsize == 0) {
136837234Sbde		fprintf(stderr, "super block size 0\n");
13691558Srgrimes		errors++;
13701558Srgrimes	} else if (lp->d_sbsize % lp->d_secsize)
13711558Srgrimes		Warning("super block size %% sector-size != 0");
13721558Srgrimes	if (lp->d_npartitions > MAXPARTITIONS)
137337234Sbde		Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
137437234Sbde		    (u_long)lp->d_npartitions, MAXPARTITIONS);
137573034Sjwd
137673034Sjwd	/* first allocate space to the partitions, then offsets */
137773034Sjwd	total_size = 0; /* in sectors */
137873034Sjwd	total_percent = 0; /* in percent */
137973034Sjwd	hog_part = -1;
138073034Sjwd	/* find all fixed partitions */
13811558Srgrimes	for (i = 0; i < lp->d_npartitions; i++) {
138273034Sjwd		pp = &lp->d_partitions[i];
138373034Sjwd		if (part_set[i]) {
138473034Sjwd			if (part_size_type[i] == '*') {
138573034Sjwd				/* partition 2 ('c') is special */
138673034Sjwd				if (i == FULL_DISK_PART) {
138773034Sjwd					pp->p_size = lp->d_secperunit;
138873034Sjwd				} else {
138973034Sjwd					if (hog_part != -1)
139073034Sjwd						Warning("Too many '*' partitions (%c and %c)",
139173034Sjwd						    hog_part + 'a',i + 'a');
139273034Sjwd					else
139373034Sjwd						hog_part = i;
139473034Sjwd				}
139573034Sjwd			} else {
139673034Sjwd				char *type;
139773034Sjwd				unsigned long size;
139873034Sjwd
139973034Sjwd				size = pp->p_size;
140073034Sjwd				switch (part_size_type[i]) {
140173034Sjwd				case '%':
140273034Sjwd					total_percent += size;
140373034Sjwd					break;
140473034Sjwd				case 'k':
140573034Sjwd				case 'K':
140673034Sjwd					size *= 1024UL;
140773034Sjwd					break;
140873034Sjwd				case 'm':
140973034Sjwd				case 'M':
141073034Sjwd					size *= ((unsigned long) 1024*1024);
141173034Sjwd					break;
141273034Sjwd				case 'g':
141373034Sjwd				case 'G':
141473034Sjwd					size *= ((unsigned long) 1024*1024*1024);
141573034Sjwd					break;
141673034Sjwd				case '\0':
141773034Sjwd					break;
141873034Sjwd				default:
141973034Sjwd					Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
142073034Sjwd					break;
142173034Sjwd				}
142273034Sjwd				/* don't count %'s yet */
142373034Sjwd				if (part_size_type[i] != '%') {
142473034Sjwd					/*
142573034Sjwd					 * for all not in sectors, convert to
142673034Sjwd					 * sectors
142773034Sjwd					 */
142873034Sjwd					if (part_size_type[i] != '\0') {
142973034Sjwd						if (size % lp->d_secsize != 0)
143073034Sjwd							Warning("partition %c not an integer number of sectors",
143173034Sjwd							    i + 'a');
143273034Sjwd						size /= lp->d_secsize;
143373034Sjwd						pp->p_size = size;
143473034Sjwd					}
143573034Sjwd					/* else already in sectors */
143673034Sjwd					/* partition 2 ('c') is special */
143773034Sjwd					if (i != FULL_DISK_PART)
143873034Sjwd						total_size += size;
143973034Sjwd				}
144073034Sjwd			}
144173034Sjwd		}
144273034Sjwd	}
144373034Sjwd	/* handle % partitions - note %'s don't need to add up to 100! */
144473034Sjwd	if (total_percent != 0) {
144573034Sjwd		long free_space = lp->d_secperunit - total_size;
144673034Sjwd		if (total_percent > 100) {
144773034Sjwd			fprintf(stderr,"total percentage %d is greater than 100\n",
144873034Sjwd			    total_percent);
144973034Sjwd			errors++;
145073034Sjwd		}
145173034Sjwd
145273034Sjwd		if (free_space > 0) {
145373034Sjwd			for (i = 0; i < lp->d_npartitions; i++) {
145473034Sjwd				pp = &lp->d_partitions[i];
145573034Sjwd				if (part_set[i] && part_size_type[i] == '%') {
145673034Sjwd					unsigned long old_size = pp->p_size;
145773034Sjwd					/* careful of overflows! and integer roundoff */
145873034Sjwd					pp->p_size = ((double)pp->p_size/100) * free_space;
145973034Sjwd					total_size += pp->p_size;
146073034Sjwd
146173034Sjwd					/* FIX we can lose a sector or so due to roundoff per
146273034Sjwd					   partition.  A more complex algorithm could avoid that */
146373034Sjwd				}
146473034Sjwd			}
146573034Sjwd		} else {
146673034Sjwd			fprintf(stderr,
146773034Sjwd			    "%ld sectors available to give to '*' and '%' partitions\n",
146873034Sjwd			    free_space);
146973034Sjwd			errors++;
147073034Sjwd			/* fix?  set all % partitions to size 0? */
147173034Sjwd		}
147273034Sjwd	}
147373034Sjwd	/* give anything remaining to the hog partition */
147473034Sjwd	if (hog_part != -1) {
147573034Sjwd		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
147673034Sjwd		total_size = lp->d_secperunit;
147773034Sjwd	}
147873034Sjwd
147973034Sjwd	/* Now set the offsets for each partition */
148073034Sjwd	current_offset = 0; /* in sectors */
148173034Sjwd	seen_default_offset = 0;
148273034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
14831558Srgrimes		part = 'a' + i;
14841558Srgrimes		pp = &lp->d_partitions[i];
148573034Sjwd		if (part_set[i]) {
148673034Sjwd			if (part_offset_type[i] == '*') {
148773034Sjwd				/* partition 2 ('c') is special */
148873034Sjwd				if (i == FULL_DISK_PART) {
148973034Sjwd					pp->p_offset = 0;
149073034Sjwd				} else {
149173034Sjwd					pp->p_offset = current_offset;
149273034Sjwd					seen_default_offset = 1;
149373034Sjwd				}
149473034Sjwd			} else {
149573034Sjwd				/* allow them to be out of order for old-style tables */
149673034Sjwd				/* partition 2 ('c') is special */
149773034Sjwd				if (pp->p_offset < current_offset &&
149873034Sjwd				    seen_default_offset && i != FULL_DISK_PART) {
149973034Sjwd					fprintf(stderr,
150073034Sjwd"Offset %ld for partition %c overlaps previous partition which ends at %ld\n",
150173034Sjwd					    pp->p_offset,i+'a',current_offset);
150273034Sjwd					fprintf(stderr,
150373034Sjwd"Labels with any *'s for offset must be in ascending order by sector\n");
150473034Sjwd					errors++;
150573034Sjwd				} else if (pp->p_offset != current_offset &&
150673034Sjwd				    i != FULL_DISK_PART && seen_default_offset) {
150773034Sjwd					/*
150873034Sjwd					 * this may give unneeded warnings if
150973034Sjwd					 * partitions are out-of-order
151073034Sjwd					 */
151173034Sjwd					Warning(
151273034Sjwd"Offset %ld for partition %c doesn't match expected value %ld",
151373034Sjwd					    pp->p_offset, i + 'a', current_offset);
151473034Sjwd				}
151573034Sjwd			}
151673034Sjwd			/* partition 2 ('c') is special */
151773034Sjwd			if (i != FULL_DISK_PART)
151873034Sjwd				current_offset = pp->p_offset + pp->p_size;
151973034Sjwd		}
152073034Sjwd	}
152173034Sjwd
152273034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
152373034Sjwd		part = 'a' + i;
152473034Sjwd		pp = &lp->d_partitions[i];
15251558Srgrimes		if (pp->p_size == 0 && pp->p_offset != 0)
152637234Sbde			Warning("partition %c: size 0, but offset %lu",
152737234Sbde			    part, (u_long)pp->p_offset);
15281558Srgrimes#ifdef notdef
15291558Srgrimes		if (pp->p_size % lp->d_secpercyl)
15301558Srgrimes			Warning("partition %c: size %% cylinder-size != 0",
15311558Srgrimes			    part);
15321558Srgrimes		if (pp->p_offset % lp->d_secpercyl)
15331558Srgrimes			Warning("partition %c: offset %% cylinder-size != 0",
15341558Srgrimes			    part);
15351558Srgrimes#endif
15361558Srgrimes		if (pp->p_offset > lp->d_secperunit) {
15371558Srgrimes			fprintf(stderr,
15381558Srgrimes			    "partition %c: offset past end of unit\n", part);
15391558Srgrimes			errors++;
15401558Srgrimes		}
15411558Srgrimes		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
15421558Srgrimes			fprintf(stderr,
154313544Sjoerg			"partition %c: partition extends past end of unit\n",
15441558Srgrimes			    part);
15451558Srgrimes			errors++;
15461558Srgrimes		}
154773034Sjwd		if (i == FULL_DISK_PART)
154873034Sjwd		{
154973034Sjwd			if (pp->p_fstype != FS_UNUSED)
155073034Sjwd				Warning("partition %c is not marked as unused!",part);
155173034Sjwd			if (pp->p_offset != 0)
155273034Sjwd				Warning("partition %c doesn't start at 0!",part);
155373034Sjwd			if (pp->p_size != lp->d_secperunit)
155473034Sjwd				Warning("partition %c doesn't cover the whole unit!",part);
155573034Sjwd
155673034Sjwd			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
155773034Sjwd			    (pp->p_size != lp->d_secperunit)) {
155873034Sjwd				Warning("An incorrect partition %c may cause problems for "
155973034Sjwd				    "standard system utilities",part);
156073034Sjwd			}
156173034Sjwd		}
156273034Sjwd
156373034Sjwd		/* check for overlaps */
156473034Sjwd		/* this will check for all possible overlaps once and only once */
156573034Sjwd		for (j = 0; j < i; j++) {
156673034Sjwd			/* partition 2 ('c') is special */
156773034Sjwd			if (j != FULL_DISK_PART && i != FULL_DISK_PART &&
156873034Sjwd			    part_set[i] && part_set[j]) {
156973034Sjwd				pp2 = &lp->d_partitions[j];
157073034Sjwd				if (pp2->p_offset < pp->p_offset + pp->p_size &&
157173034Sjwd				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
157273034Sjwd					pp2->p_offset >= pp->p_offset)) {
157373034Sjwd					fprintf(stderr,"partitions %c and %c overlap!\n",
157473034Sjwd					    j + 'a', i + 'a');
157573034Sjwd					errors++;
157673034Sjwd				}
157773034Sjwd			}
157873034Sjwd		}
15791558Srgrimes	}
15801558Srgrimes	for (; i < MAXPARTITIONS; i++) {
15811558Srgrimes		part = 'a' + i;
15821558Srgrimes		pp = &lp->d_partitions[i];
15831558Srgrimes		if (pp->p_size || pp->p_offset)
158437234Sbde			Warning("unused partition %c: size %d offset %lu",
158537234Sbde			    'a' + i, pp->p_size, (u_long)pp->p_offset);
15861558Srgrimes	}
15871558Srgrimes	return (errors);
15881558Srgrimes}
15891558Srgrimes
15901558Srgrimes/*
159113550Sjoerg * When operating on a "virgin" disk, try getting an initial label
159213550Sjoerg * from the associated device driver.  This might work for all device
159313550Sjoerg * drivers that are able to fetch some initial device parameters
159413550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks,
159513550Sjoerg * most IDE drives, or vn devices.
159613550Sjoerg *
159713550Sjoerg * The device name must be given in its "canonical" form.
159813550Sjoerg */
159913550Sjoergstruct disklabel *
160013550Sjoerggetvirginlabel(void)
160113550Sjoerg{
160213550Sjoerg	static struct disklabel lab;
160313550Sjoerg	char namebuf[BBSIZE];
160413550Sjoerg	int f;
160513550Sjoerg
160613550Sjoerg	if (dkname[0] == '/') {
160737773Sbde		warnx("\"auto\" requires the usage of a canonical disk name");
160816431Sbde		return (NULL);
160913550Sjoerg	}
161059429Sobrien	(void)snprintf(namebuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
161137773Sbde	if ((f = open(namebuf, O_RDONLY)) == -1) {
161237773Sbde		warn("cannot open %s", namebuf);
161316431Sbde		return (NULL);
161413550Sjoerg	}
161568044Sjkh
161668044Sjkh	/*
161768044Sjkh	 * Try to use the new get-virgin-label ioctl.  If it fails,
161868044Sjkh	 * fallback to the old get-disdk-info ioctl.
161968044Sjkh	 */
162068044Sjkh	if (ioctl(f, DIOCGDVIRGIN, &lab) < 0) {
162173034Sjwd		if (ioctl(f, DIOCGDINFO, &lab) < 0) {
162273034Sjwd			warn("ioctl DIOCGDINFO");
162373034Sjwd			close(f);
162473034Sjwd			return (NULL);
162573034Sjwd		}
162613550Sjoerg	}
162713550Sjoerg	close(f);
162837773Sbde	lab.d_boot0 = NULL;
162937773Sbde	lab.d_boot1 = NULL;
163016431Sbde	return (&lab);
163113550Sjoerg}
163213550Sjoerg
163313550Sjoerg/*
16341558Srgrimes * If we are installing a boot program that doesn't fit in d_bbsize
16351558Srgrimes * we need to mark those partitions that the boot overflows into.
16361558Srgrimes * This allows newfs to prevent creation of a filesystem where it might
16371558Srgrimes * clobber bootstrap code.
16381558Srgrimes */
163913544Sjoergvoid
16401558Srgrimessetbootflag(lp)
16411558Srgrimes	register struct disklabel *lp;
16421558Srgrimes{
16431558Srgrimes	register struct partition *pp;
16441558Srgrimes	int i, errors = 0;
16451558Srgrimes	char part;
16461558Srgrimes	u_long boffset;
16471558Srgrimes
16481558Srgrimes	if (bootbuf == 0)
16491558Srgrimes		return;
16501558Srgrimes	boffset = bootsize / lp->d_secsize;
16511558Srgrimes	for (i = 0; i < lp->d_npartitions; i++) {
16521558Srgrimes		part = 'a' + i;
16531558Srgrimes		pp = &lp->d_partitions[i];
16541558Srgrimes		if (pp->p_size == 0)
16551558Srgrimes			continue;
16561558Srgrimes		if (boffset <= pp->p_offset) {
16571558Srgrimes			if (pp->p_fstype == FS_BOOT)
16581558Srgrimes				pp->p_fstype = FS_UNUSED;
16591558Srgrimes		} else if (pp->p_fstype != FS_BOOT) {
16601558Srgrimes			if (pp->p_fstype != FS_UNUSED) {
16611558Srgrimes				fprintf(stderr,
16621558Srgrimes					"boot overlaps used partition %c\n",
16631558Srgrimes					part);
16641558Srgrimes				errors++;
16651558Srgrimes			} else {
16661558Srgrimes				pp->p_fstype = FS_BOOT;
16671558Srgrimes				Warning("boot overlaps partition %c, %s",
16681558Srgrimes					part, "marked as FS_BOOT");
16691558Srgrimes			}
16701558Srgrimes		}
16711558Srgrimes	}
167236632Scharnier	if (errors)
167336632Scharnier		errx(4, "cannot install boot program");
16741558Srgrimes}
16751558Srgrimes
16761558Srgrimes/*VARARGS1*/
167713544Sjoergvoid
167813544SjoergWarning(char *fmt, ...)
16791558Srgrimes{
168013544Sjoerg	va_list ap;
16811558Srgrimes
16821558Srgrimes	fprintf(stderr, "Warning, ");
168313544Sjoerg	va_start(ap, fmt);
168413544Sjoerg	vfprintf(stderr, fmt, ap);
16851558Srgrimes	fprintf(stderr, "\n");
168613544Sjoerg	va_end(ap);
16871558Srgrimes}
16881558Srgrimes
168913544Sjoergvoid
16901558Srgrimesusage()
16911558Srgrimes{
16921558Srgrimes#if NUMBOOT > 0
169326542Scharnier	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",
169426542Scharnier		"usage: disklabel [-r] disk",
169526542Scharnier		"\t\t(to read label)",
169673034Sjwd		"       disklabel -w [-r] [-n] disk type [ packid ]",
169726542Scharnier		"\t\t(to write label with existing boot program)",
169873034Sjwd		"       disklabel -e [-r] [-n] disk",
169926542Scharnier		"\t\t(to edit label)",
170073034Sjwd		"       disklabel -R [-r] [-n] disk protofile",
170126542Scharnier		"\t\t(to restore label with existing boot program)",
17021558Srgrimes#if NUMBOOT > 1
170373034Sjwd		"       disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]",
170426542Scharnier		"\t\t(to install boot program with existing label)",
170573034Sjwd		"       disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
170626542Scharnier		"\t\t(to write label and boot program)",
170773034Sjwd		"       disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
170826542Scharnier		"\t\t(to restore label and boot program)",
17091558Srgrimes#else
171073034Sjwd		"       disklabel -B [-n] [ -b bootprog ] disk [ type ]",
171126542Scharnier		"\t\t(to install boot program with existing on-disk label)",
171273034Sjwd		"       disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
171326542Scharnier		"\t\t(to write label and install boot program)",
171473034Sjwd		"       disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]",
171526542Scharnier		"\t\t(to restore label and install boot program)",
17161558Srgrimes#endif
171726542Scharnier		"       disklabel [-NW] disk",
171826542Scharnier		"\t\t(to write disable/enable label)");
17191558Srgrimes#else
172026542Scharnier	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
172126542Scharnier		"usage: disklabel [-r] disk", "(to read label)",
172273034Sjwd		"       disklabel -w [-r] [-n] disk type [ packid ]",
172326542Scharnier		"\t\t(to write label)",
172473034Sjwd		"       disklabel -e [-r] [-n] disk",
172526542Scharnier		"\t\t(to edit label)",
172673034Sjwd		"       disklabel -R [-r] [-n] disk protofile",
172726542Scharnier		"\t\t(to restore label)",
172826542Scharnier		"       disklabel [-NW] disk",
172926542Scharnier		"\t\t(to write disable/enable label)");
17301558Srgrimes#endif
17311558Srgrimes	exit(1);
17321558Srgrimes}
1733