bsdlabel.c revision 121222
11558Srgrimes/*
292058Sobrien * Copyright (c) 1994, 1995 Gordon W. Ross
392058Sobrien * Copyright (c) 1994 Theo de Raadt
492058Sobrien * All rights reserved.
51558Srgrimes * Copyright (c) 1987, 1993
61558Srgrimes *	The Regents of the University of California.  All rights reserved.
71558Srgrimes *
81558Srgrimes * This code is derived from software contributed to Berkeley by
91558Srgrimes * Symmetric Computer Systems.
101558Srgrimes *
111558Srgrimes * Redistribution and use in source and binary forms, with or without
121558Srgrimes * modification, are permitted provided that the following conditions
131558Srgrimes * are met:
141558Srgrimes * 1. Redistributions of source code must retain the above copyright
151558Srgrimes *    notice, this list of conditions and the following disclaimer.
161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171558Srgrimes *    notice, this list of conditions and the following disclaimer in the
181558Srgrimes *    documentation and/or other materials provided with the distribution.
191558Srgrimes * 3. All advertising materials mentioning features or use of this software
201558Srgrimes *    must display the following acknowledgement:
211558Srgrimes *	This product includes software developed by the University of
221558Srgrimes *	California, Berkeley and its contributors.
2392058Sobrien *      This product includes software developed by Theo de Raadt.
241558Srgrimes * 4. Neither the name of the University nor the names of its contributors
251558Srgrimes *    may be used to endorse or promote products derived from this software
261558Srgrimes *    without specific prior written permission.
271558Srgrimes *
281558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
291558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
301558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
311558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
321558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
331558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
341558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
351558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
361558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
371558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
381558Srgrimes * SUCH DAMAGE.
3992058Sobrien *
4092058Sobrien *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
411558Srgrimes */
421558Srgrimes
43115449Sobrien#if 0
441558Srgrimes#ifndef lint
4536632Scharnierstatic const char copyright[] =
461558Srgrimes"@(#) Copyright (c) 1987, 1993\n\
471558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
481558Srgrimes#endif /* not lint */
491558Srgrimes
501558Srgrimes#ifndef lint
511558Srgrimesstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
521558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
53115449Sobrien#endif /* not lint */
5436632Scharnier#endif
5599365Smarkm#include <sys/cdefs.h>
5699365Smarkm__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 121222 2003-10-18 19:32:35Z phk $");
5799365Smarkm
581558Srgrimes#include <sys/param.h>
59114552Sphk#include <stdint.h>
601558Srgrimes#include <sys/file.h>
611558Srgrimes#include <sys/stat.h>
6213544Sjoerg#include <sys/wait.h>
63103669Sphk#include <sys/disk.h>
641558Srgrimes#define DKTYPENAMES
65101994Sbmilekic#define FSTYPENAMES
661558Srgrimes#include <sys/disklabel.h>
67112307Sru
681558Srgrimes#include <unistd.h>
691558Srgrimes#include <string.h>
701558Srgrimes#include <stdio.h>
71114569Sphk#include <libgeom.h>
7213544Sjoerg#include <stdlib.h>
7313544Sjoerg#include <signal.h>
7413544Sjoerg#include <stdarg.h>
751558Srgrimes#include <ctype.h>
7626542Scharnier#include <err.h>
7759216Simp#include <errno.h>
7899365Smarkm
791558Srgrimes#include "pathnames.h"
801558Srgrimes
81114571Sphkstatic void	makelabel(const char *, struct disklabel *);
82114571Sphkstatic int	writelabel(void);
83114571Sphkstatic int readlabel(int flag);
84114571Sphkstatic void	display(FILE *, const struct disklabel *);
85114571Sphkstatic int edit(void);
86114571Sphkstatic int	editit(void);
87121222Sphkstatic void	fixlabel(struct disklabel *);
88114571Sphkstatic char	*skip(char *);
89114571Sphkstatic char	*word(char *);
90114571Sphkstatic int	getasciilabel(FILE *, struct disklabel *);
91114571Sphkstatic int	getasciipartspec(char *, struct disklabel *, int, int);
92114571Sphkstatic int	checklabel(struct disklabel *);
93114571Sphkstatic void	usage(void);
94114571Sphkstatic struct disklabel *getvirginlabel(void);
9513544Sjoerg
961558Srgrimes#define	DEFEDITOR	_PATH_VI
971558Srgrimes
98114571Sphkstatic char	*dkname;
99114571Sphkstatic char	*specname;
100114571Sphkstatic char	tmpfil[] = PATH_TMPFILE;
1011558Srgrimes
102114571Sphkstatic struct	disklabel lab;
103114571Sphkstatic u_char	bootarea[BBSIZE];
104114574Sphkstatic off_t	mediasize;
105114574Sphkstatic u_int	secsize;
106114571Sphkstatic char	blank[] = "";
107114571Sphkstatic char	unknown[] = "unknown";
1081558Srgrimes
10973034Sjwd#define MAX_PART ('z')
11073034Sjwd#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
111114571Sphkstatic char    part_size_type[MAX_NUM_PARTS];
112114571Sphkstatic char    part_offset_type[MAX_NUM_PARTS];
113114571Sphkstatic int     part_set[MAX_NUM_PARTS];
11473034Sjwd
115114571Sphkstatic int	installboot;	/* non-zero if we should install a boot program */
116114574Sphkstatic int	allfields;	/* present all fields in edit */
117114571Sphkstatic char const *xxboot;	/* primary boot */
1181558Srgrimes
119114673Sphkstatic off_t mbroffset;
120115995Sphk#ifndef LABELSECTOR
121115995Sphk#define LABELSECTOR -1
122115995Sphk#endif
123115995Sphk#ifndef LABELOFFSET
124115995Sphk#define LABELOFFSET -1
125115995Sphk#endif
126115696Sphkstatic int labelsoffset = LABELSECTOR;
127115696Sphkstatic int labeloffset = LABELOFFSET;
128114551Sphkstatic int bbsize = BBSIZE;
129114551Sphkstatic int alphacksum =
130114551Sphk#if defined(__alpha__)
131114551Sphk	1;
132114551Sphk#else
133114551Sphk	0;
134114551Sphk#endif
135114550Sphk
1361558Srgrimesenum	{
137109872Sphk	UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
1381558Srgrimes} op = UNSPEC;
1391558Srgrimes
140112307Sru
141114571Sphkstatic int	disable_write;   /* set to disable writing to disk label */
1421558Srgrimes
14313544Sjoergint
14492541Simpmain(int argc, char *argv[])
1451558Srgrimes{
1461558Srgrimes	FILE *t;
147114569Sphk	int ch, error = 0;
148114571Sphk	char const *name = 0;
1491558Srgrimes
150114574Sphk	while ((ch = getopt(argc, argv, "ABb:em:nRrs:w")) != -1)
1511558Srgrimes		switch (ch) {
152114574Sphk			case 'A':
153114574Sphk				allfields = 1;
154114574Sphk				break;
1551558Srgrimes			case 'B':
1561558Srgrimes				++installboot;
1571558Srgrimes				break;
1581558Srgrimes			case 'b':
1591558Srgrimes				xxboot = optarg;
1601558Srgrimes				break;
161112307Sru			case 'm':
162115948Sphk				if (!strcmp(optarg, "i386") ||
163115948Sphk				    !strcmp(optarg, "amd64") ||
164115948Sphk				    !strcmp(optarg, "ia64") ||
165115948Sphk				    !strcmp(optarg, "pc98")) {
166115696Sphk					labelsoffset = 1;
167115696Sphk					labeloffset = 0;
168114550Sphk					bbsize = 8192;
169114551Sphk					alphacksum = 0;
170114550Sphk				} else if (!strcmp(optarg, "alpha")) {
171115696Sphk					labelsoffset = 0;
172114550Sphk					labeloffset = 64;
173114550Sphk					bbsize = 8192;
174114550Sphk					alphacksum = 1;
175114571Sphk				} else {
176114571Sphk					errx(1, "Unsupported architecture");
177114550Sphk				}
178112307Sru				break;
17973034Sjwd			case 'n':
18073034Sjwd				disable_write = 1;
18173034Sjwd				break;
1821558Srgrimes			case 'R':
1831558Srgrimes				if (op != UNSPEC)
1841558Srgrimes					usage();
1851558Srgrimes				op = RESTORE;
1861558Srgrimes				break;
1871558Srgrimes			case 'e':
1881558Srgrimes				if (op != UNSPEC)
1891558Srgrimes					usage();
1901558Srgrimes				op = EDIT;
1911558Srgrimes				break;
1921558Srgrimes			case 'r':
193114571Sphk				/*
194114571Sphk				 * We accept and ignode -r for compatibility with
195114571Sphk				 * historically disklabel usage.
196114571Sphk				 */
1971558Srgrimes				break;
1981558Srgrimes			case 'w':
1991558Srgrimes				if (op != UNSPEC)
2001558Srgrimes					usage();
2011558Srgrimes				op = WRITE;
2021558Srgrimes				break;
2031558Srgrimes			case '?':
2041558Srgrimes			default:
2051558Srgrimes				usage();
2061558Srgrimes		}
2071558Srgrimes	argc -= optind;
2081558Srgrimes	argv += optind;
209114571Sphk
2101558Srgrimes	if (argc < 1)
2111558Srgrimes		usage();
212115995Sphk	if (labelsoffset < 0 || labeloffset < 0)
213115995Sphk		errx(1, "a -m <architecture> option must be specified");
2141558Srgrimes
215114569Sphk	/* Figure out the names of the thing we're working on */
216114569Sphk	if (argv[0][0] != '/') {
217114569Sphk		dkname = argv[0];
218114569Sphk		asprintf(&specname, "%s%s", _PATH_DEV, argv[0]);
219114569Sphk	} else {
220114569Sphk		dkname = strrchr(argv[0], '/');
221114569Sphk		dkname++;
222114569Sphk		specname = argv[0];
2231558Srgrimes	}
2241558Srgrimes
225114571Sphk	if (installboot && op == UNSPEC)
226114571Sphk		op = WRITEBOOT;
227114571Sphk	else if (op == UNSPEC)
228114571Sphk		op = READ;
229114571Sphk
2301558Srgrimes	switch(op) {
2311558Srgrimes
23248957Sbillf	case UNSPEC:
23348957Sbillf		break;
23448957Sbillf
2351558Srgrimes	case EDIT:
2361558Srgrimes		if (argc != 1)
2371558Srgrimes			usage();
238114571Sphk		readlabel(1);
239121222Sphk		fixlabel(&lab);
240114571Sphk		error = edit();
2411558Srgrimes		break;
2421558Srgrimes
2431558Srgrimes	case READ:
2441558Srgrimes		if (argc != 1)
2451558Srgrimes			usage();
246114571Sphk		readlabel(1);
247114571Sphk		display(stdout, NULL);
248114571Sphk		error = checklabel(NULL);
2491558Srgrimes		break;
2501558Srgrimes
2511558Srgrimes	case RESTORE:
2521558Srgrimes		if (argc != 2)
2531558Srgrimes			usage();
2541558Srgrimes		if (!(t = fopen(argv[1], "r")))
255114569Sphk			err(4, "fopen %s", argv[1]);
256114571Sphk		readlabel(0);
25737865Sbde		if (!getasciilabel(t, &lab))
25837865Sbde			exit(1);
259114571Sphk		error = writelabel();
2601558Srgrimes		break;
2611558Srgrimes
2621558Srgrimes	case WRITE:
263114571Sphk		if (argc == 2)
264114571Sphk			name = argv[1];
265114571Sphk		else if (argc == 1)
266114571Sphk			name = "auto";
267114571Sphk		else
2681558Srgrimes			usage();
269114571Sphk		readlabel(0);
270114571Sphk		makelabel(name, &lab);
271121222Sphk		fixlabel(&lab);
272114571Sphk		if (checklabel(NULL) == 0)
273114571Sphk			error = writelabel();
2741558Srgrimes		break;
2751558Srgrimes
2761558Srgrimes	case WRITEBOOT:
2771558Srgrimes
278114571Sphk		readlabel(1);
279121222Sphk		fixlabel(&lab);
2801558Srgrimes		if (argc == 2)
281114571Sphk			makelabel(argv[1], &lab);
282114571Sphk		if (checklabel(NULL) == 0)
283114571Sphk			error = writelabel();
2841558Srgrimes		break;
2851558Srgrimes	}
2861558Srgrimes	exit(error);
2871558Srgrimes}
2881558Srgrimes
289121222Sphkstatic void
290121222Sphkfixlabel(struct disklabel *lp)
291121222Sphk{
292121222Sphk	struct partition *dp;
293121222Sphk	int i;
294121222Sphk
295121222Sphk	for (i = 0; i < MAXPARTITIONS; i++) {
296121222Sphk		if (i == RAW_PART)
297121222Sphk			continue;
298121222Sphk		if (lp->d_partitions[i].p_size)
299121222Sphk			return;
300121222Sphk	}
301121222Sphk
302121222Sphk	dp = &lp->d_partitions[0];
303121222Sphk	dp->p_offset = BBSIZE / secsize;
304121222Sphk	dp->p_size = lp->d_secperunit - dp->p_offset;
305121222Sphk}
306121222Sphk
3071558Srgrimes/*
308111286Sru * Construct a prototype disklabel from /etc/disktab.
3091558Srgrimes */
310114571Sphkstatic void
311114571Sphkmakelabel(const char *type, struct disklabel *lp)
3121558Srgrimes{
31392541Simp	struct disklabel *dp;
31413550Sjoerg
31513550Sjoerg	if (strcmp(type, "auto") == 0)
31613550Sjoerg		dp = getvirginlabel();
31713550Sjoerg	else
31813544Sjoerg		dp = getdiskbyname(type);
31936632Scharnier	if (dp == NULL)
32036632Scharnier		errx(1, "%s: unknown disk type", type);
3211558Srgrimes	*lp = *dp;
3221558Srgrimes	bzero(lp->d_packname, sizeof(lp->d_packname));
3231558Srgrimes}
3241558Srgrimes
325114571Sphkstatic void
326114571Sphkreadboot(void)
3271558Srgrimes{
328114571Sphk	int fd, i;
329114571Sphk	struct stat st;
330114571Sphk
331114571Sphk	if (xxboot == NULL)
332114571Sphk		xxboot = "/boot/boot";
333114571Sphk	fd = open(xxboot, O_RDONLY);
334114571Sphk	if (fd < 0)
335114571Sphk		err(1, "cannot open %s", xxboot);
336114571Sphk	fstat(fd, &st);
337114860Sphk	if (alphacksum && st.st_size <= BBSIZE - 512) {
338114860Sphk		i = read(fd, bootarea + 512, st.st_size);
339114860Sphk		if (i != st.st_size)
340114571Sphk			err(1, "read error %s", xxboot);
341114571Sphk		return;
342114860Sphk	} else if ((!alphacksum) && st.st_size <= BBSIZE) {
343114860Sphk		i = read(fd, bootarea, st.st_size);
344114860Sphk		if (i != st.st_size)
345114571Sphk			err(1, "read error %s", xxboot);
346114571Sphk		return;
347114860Sphk	}
348114571Sphk	errx(1, "boot code %s is wrong size", xxboot);
349114571Sphk}
350114571Sphk
351114571Sphkstatic int
352114571Sphkwritelabel(void)
353114571Sphk{
354112307Sru	uint64_t *p, sum;
355114569Sphk	int i, fd;
356114569Sphk	struct gctl_req *grq;
357114569Sphk	char const *errstr;
358114571Sphk	struct disklabel *lp = &lab;
35938384Sdfr
36073034Sjwd	if (disable_write) {
361114574Sphk		warnx("write to disk label supressed - label was as follows:");
362114571Sphk		display(stdout, NULL);
36373034Sjwd		return (0);
364109878Sphk	}
365109878Sphk
366109878Sphk	lp->d_magic = DISKMAGIC;
367109878Sphk	lp->d_magic2 = DISKMAGIC;
368109878Sphk	lp->d_checksum = 0;
369109878Sphk	lp->d_checksum = dkcksum(lp);
370114571Sphk	if (installboot)
371114571Sphk		readboot();
372114673Sphk	for (i = 0; i < lab.d_npartitions; i++)
373114673Sphk		if (lab.d_partitions[i].p_size)
374114673Sphk			lab.d_partitions[i].p_offset += mbroffset;
375115696Sphk	bsd_disklabel_le_enc(bootarea + labeloffset + labelsoffset * secsize,
376115696Sphk	    lp);
377114552Sphk	if (alphacksum) {
378114569Sphk		/* Generate the bootblock checksum for the SRM console.  */
379114571Sphk		for (p = (uint64_t *)bootarea, i = 0, sum = 0; i < 63; i++)
380112307Sru			sum += p[i];
381112307Sru		p[63] = sum;
382112307Sru	}
383114569Sphk
384114569Sphk	fd = open(specname, O_RDWR);
385114569Sphk	if (fd < 0) {
386115624Sphk		grq = gctl_get_handle();
387115624Sphk		gctl_ro_param(grq, "verb", -1, "write label");
388114569Sphk		gctl_ro_param(grq, "class", -1, "BSD");
389114569Sphk		gctl_ro_param(grq, "geom", -1, dkname);
390115696Sphk		gctl_ro_param(grq, "label", 148+16*8,
391115696Sphk			bootarea + labeloffset + labelsoffset * secsize);
392114569Sphk		errstr = gctl_issue(grq);
393114571Sphk		if (errstr != NULL) {
394114571Sphk			warnx("%s", errstr);
395114571Sphk			gctl_free(grq);
396114571Sphk			return(1);
397114571Sphk		}
398114569Sphk		gctl_free(grq);
399114569Sphk		if (installboot) {
400115624Sphk			grq = gctl_get_handle();
401115624Sphk			gctl_ro_param(grq, "verb", -1, "write bootcode");
402114569Sphk			gctl_ro_param(grq, "class", -1, "BSD");
403114569Sphk			gctl_ro_param(grq, "geom", -1, dkname);
404114571Sphk			gctl_ro_param(grq, "bootcode", BBSIZE, bootarea);
405114569Sphk			errstr = gctl_issue(grq);
406114571Sphk			if (errstr != NULL) {
407114571Sphk				warnx("%s", errstr);
408114571Sphk				gctl_free(grq);
409114571Sphk				return (1);
410114571Sphk			}
411114569Sphk			gctl_free(grq);
412114569Sphk		}
413114569Sphk	} else {
414114571Sphk		if (write(fd, bootarea, bbsize) != bbsize) {
415114569Sphk			warn("write %s", specname);
416114569Sphk			close (fd);
417114569Sphk			return (1);
418114569Sphk		}
419114569Sphk		close (fd);
420109878Sphk	}
4211558Srgrimes	return (0);
4221558Srgrimes}
4231558Srgrimes
4241558Srgrimes/*
4251558Srgrimes * Fetch disklabel for disk.
4261558Srgrimes * Use ioctl to get label unless -r flag is given.
4271558Srgrimes */
428114571Sphkstatic int
429114571Sphkreadlabel(int flag)
4301558Srgrimes{
431114673Sphk	int f, i;
432114569Sphk	int error;
433114673Sphk	struct gctl_req *grq;
434114673Sphk	char const *errstr;
4351558Srgrimes
436114569Sphk	f = open(specname, O_RDONLY);
437114569Sphk	if (f < 0)
438114569Sphk		err(1, specname);
439115696Sphk	/* New world order */
440115696Sphk	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
441115696Sphk	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
442115696Sphk		err(4, "cannot get disk geometry");
443115696Sphk	}
444114550Sphk	(void)lseek(f, (off_t)0, SEEK_SET);
445114571Sphk	if (read(f, bootarea, BBSIZE) != BBSIZE)
446114569Sphk		err(4, "%s read", specname);
447114569Sphk	close (f);
448115696Sphk	error = bsd_disklabel_le_dec(
449115696Sphk	    bootarea + (labeloffset + labelsoffset * secsize),
450115696Sphk	    &lab, MAXPARTITIONS);
451114571Sphk	if (flag && error)
452114571Sphk		errx(1, "%s: no valid label found", specname);
453114673Sphk
454115624Sphk	grq = gctl_get_handle();
455115624Sphk	gctl_ro_param(grq, "verb", -1, "read mbroffset");
456114673Sphk	gctl_ro_param(grq, "class", -1, "BSD");
457114673Sphk	gctl_ro_param(grq, "geom", -1, dkname);
458114673Sphk	gctl_rw_param(grq, "mbroffset", sizeof(mbroffset), &mbroffset);
459114673Sphk	errstr = gctl_issue(grq);
460114673Sphk	if (errstr != NULL) {
461114673Sphk		mbroffset = 0;
462114673Sphk		gctl_free(grq);
463114673Sphk		return (error);
464114673Sphk	}
465114673Sphk	mbroffset /= lab.d_secsize;
466114673Sphk	if (lab.d_partitions[RAW_PART].p_offset == mbroffset)
467114673Sphk		for (i = 0; i < lab.d_npartitions; i++)
468114673Sphk			if (lab.d_partitions[i].p_size)
469114673Sphk				lab.d_partitions[i].p_offset -= mbroffset;
470114571Sphk	return (error);
4711558Srgrimes}
4721558Srgrimes
4731558Srgrimes
474114571Sphkstatic void
47592541Simpdisplay(FILE *f, const struct disklabel *lp)
4761558Srgrimes{
47792541Simp	int i, j;
47892541Simp	const struct partition *pp;
4791558Srgrimes
480114571Sphk	if (lp == NULL)
481114571Sphk		lp = &lab;
482114571Sphk
4831558Srgrimes	fprintf(f, "# %s:\n", specname);
484114574Sphk	if (allfields) {
485114574Sphk		if (lp->d_type < DKMAXTYPES)
486114574Sphk			fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
487114574Sphk		else
488114574Sphk			fprintf(f, "type: %u\n", lp->d_type);
489114574Sphk		fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
490114574Sphk			lp->d_typename);
491114574Sphk		fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
492114574Sphk			lp->d_packname);
493114574Sphk		fprintf(f, "flags:");
494114574Sphk		if (lp->d_flags & D_REMOVABLE)
495114574Sphk			fprintf(f, " removeable");
496114574Sphk		if (lp->d_flags & D_ECC)
497114574Sphk			fprintf(f, " ecc");
498114574Sphk		if (lp->d_flags & D_BADSECT)
499114574Sphk			fprintf(f, " badsect");
500114574Sphk		fprintf(f, "\n");
501114574Sphk		fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
502114574Sphk		fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
503114574Sphk		fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
504114574Sphk		fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
505114574Sphk		fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
506114574Sphk		fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
507114574Sphk		fprintf(f, "rpm: %u\n", lp->d_rpm);
508114574Sphk		fprintf(f, "interleave: %u\n", lp->d_interleave);
509114574Sphk		fprintf(f, "trackskew: %u\n", lp->d_trackskew);
510114574Sphk		fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
511114574Sphk		fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
512114574Sphk		    (u_long)lp->d_headswitch);
513114574Sphk		fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
514114574Sphk		    (u_long)lp->d_trkseek);
515114574Sphk		fprintf(f, "drivedata: ");
516114574Sphk		for (i = NDDATA - 1; i >= 0; i--)
517114574Sphk			if (lp->d_drivedata[i])
518114574Sphk				break;
519114574Sphk		if (i < 0)
520114574Sphk			i = 0;
521114574Sphk		for (j = 0; j <= i; j++)
522114574Sphk			fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
523114574Sphk		fprintf(f, "\n\n");
524114574Sphk	}
525114574Sphk	fprintf(f, "%u partitions:\n", lp->d_npartitions);
5261558Srgrimes	fprintf(f,
5275393Sgibbs	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
5281558Srgrimes	pp = lp->d_partitions;
5291558Srgrimes	for (i = 0; i < lp->d_npartitions; i++, pp++) {
5301558Srgrimes		if (pp->p_size) {
53137234Sbde			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
53237234Sbde			   (u_long)pp->p_size, (u_long)pp->p_offset);
533107041Sjulian			if (pp->p_fstype < FSMAXTYPES)
5341558Srgrimes				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
5351558Srgrimes			else
5361558Srgrimes				fprintf(f, "%8d", pp->p_fstype);
5371558Srgrimes			switch (pp->p_fstype) {
5381558Srgrimes
5391558Srgrimes			case FS_UNUSED:				/* XXX */
54037234Sbde				fprintf(f, "    %5lu %5lu %5.5s ",
54137234Sbde				    (u_long)pp->p_fsize,
54237234Sbde				    (u_long)(pp->p_fsize * pp->p_frag), "");
5431558Srgrimes				break;
5441558Srgrimes
5451558Srgrimes			case FS_BSDFFS:
54637234Sbde				fprintf(f, "    %5lu %5lu %5u ",
54737234Sbde				    (u_long)pp->p_fsize,
54837234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
5491558Srgrimes				    pp->p_cpg);
5501558Srgrimes				break;
5511558Srgrimes
5525393Sgibbs			case FS_BSDLFS:
55337234Sbde				fprintf(f, "    %5lu %5lu %5d",
55437234Sbde				    (u_long)pp->p_fsize,
55537234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
5565393Sgibbs				    pp->p_cpg);
5575393Sgibbs				break;
5585393Sgibbs
5591558Srgrimes			default:
5601558Srgrimes				fprintf(f, "%20.20s", "");
5611558Srgrimes				break;
5621558Srgrimes			}
563114574Sphk			if (i == RAW_PART) {
564114574Sphk				fprintf(f, "  # \"raw\" part, don't edit");
565114574Sphk			}
566114571Sphk			fprintf(f, "\n");
5671558Srgrimes		}
5681558Srgrimes	}
5691558Srgrimes	fflush(f);
5701558Srgrimes}
5711558Srgrimes
572114571Sphkstatic int
573114571Sphkedit(void)
5741558Srgrimes{
57592541Simp	int c, fd;
5761558Srgrimes	struct disklabel label;
57724180Simp	FILE *fp;
5781558Srgrimes
57924180Simp	if ((fd = mkstemp(tmpfil)) == -1 ||
58024180Simp	    (fp = fdopen(fd, "w")) == NULL) {
58136632Scharnier		warnx("can't create %s", tmpfil);
5821558Srgrimes		return (1);
5831558Srgrimes	}
584114571Sphk	display(fp, NULL);
58524180Simp	fclose(fp);
5861558Srgrimes	for (;;) {
5871558Srgrimes		if (!editit())
5881558Srgrimes			break;
58924180Simp		fp = fopen(tmpfil, "r");
59024180Simp		if (fp == NULL) {
59136632Scharnier			warnx("can't reopen %s for reading", tmpfil);
5921558Srgrimes			break;
5931558Srgrimes		}
5941558Srgrimes		bzero((char *)&label, sizeof(label));
595114571Sphk		c = getasciilabel(fp, &label);
596114571Sphk		fclose(fp);
597114571Sphk		if (c) {
598114571Sphk			lab = label;
599114571Sphk			if (writelabel() == 0) {
6001558Srgrimes				(void) unlink(tmpfil);
6011558Srgrimes				return (0);
6021558Srgrimes			}
6031558Srgrimes		}
604114571Sphk		printf("re-edit the label? [y]: ");
605114571Sphk		fflush(stdout);
6061558Srgrimes		c = getchar();
6071558Srgrimes		if (c != EOF && c != (int)'\n')
6081558Srgrimes			while (getchar() != (int)'\n')
6091558Srgrimes				;
6101558Srgrimes		if  (c == (int)'n')
6111558Srgrimes			break;
6121558Srgrimes	}
6131558Srgrimes	(void) unlink(tmpfil);
6141558Srgrimes	return (1);
6151558Srgrimes}
6161558Srgrimes
617114571Sphkstatic int
61892541Simpeditit(void)
6191558Srgrimes{
62092541Simp	int pid, xpid;
62199365Smarkm	int locstat, omask;
62299365Smarkm	const char *ed;
6231558Srgrimes
6241558Srgrimes	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
6251558Srgrimes	while ((pid = fork()) < 0) {
6261558Srgrimes		if (errno == EPROCLIM) {
62736632Scharnier			warnx("you have too many processes");
6281558Srgrimes			return(0);
6291558Srgrimes		}
6301558Srgrimes		if (errno != EAGAIN) {
63136632Scharnier			warn("fork");
6321558Srgrimes			return(0);
6331558Srgrimes		}
6341558Srgrimes		sleep(1);
6351558Srgrimes	}
6361558Srgrimes	if (pid == 0) {
6371558Srgrimes		sigsetmask(omask);
6381558Srgrimes		setgid(getgid());
6391558Srgrimes		setuid(getuid());
6401558Srgrimes		if ((ed = getenv("EDITOR")) == (char *)0)
6411558Srgrimes			ed = DEFEDITOR;
64279452Sbrian		execlp(ed, ed, tmpfil, (char *)0);
64336632Scharnier		err(1, "%s", ed);
6441558Srgrimes	}
64599365Smarkm	while ((xpid = wait(&locstat)) >= 0)
6461558Srgrimes		if (xpid == pid)
6471558Srgrimes			break;
6481558Srgrimes	sigsetmask(omask);
64999365Smarkm	return(!locstat);
6501558Srgrimes}
6511558Srgrimes
652114571Sphkstatic char *
65392541Simpskip(char *cp)
6541558Srgrimes{
6551558Srgrimes
6561558Srgrimes	while (*cp != '\0' && isspace(*cp))
6571558Srgrimes		cp++;
6581558Srgrimes	if (*cp == '\0' || *cp == '#')
65992541Simp		return (NULL);
6601558Srgrimes	return (cp);
6611558Srgrimes}
6621558Srgrimes
663114571Sphkstatic char *
66492541Simpword(char *cp)
6651558Srgrimes{
66692541Simp	char c;
6671558Srgrimes
6681558Srgrimes	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
6691558Srgrimes		cp++;
6701558Srgrimes	if ((c = *cp) != '\0') {
6711558Srgrimes		*cp++ = '\0';
6721558Srgrimes		if (c != '#')
6731558Srgrimes			return (skip(cp));
6741558Srgrimes	}
67592541Simp	return (NULL);
6761558Srgrimes}
6771558Srgrimes
6781558Srgrimes/*
6791558Srgrimes * Read an ascii label in from fd f,
6801558Srgrimes * in the same format as that put out by display(),
6811558Srgrimes * and fill in lp.
6821558Srgrimes */
683114571Sphkstatic int
68492541Simpgetasciilabel(FILE *f, struct disklabel *lp)
6851558Srgrimes{
68694065Sphk	char *cp;
68794065Sphk	const char **cpp;
688107041Sjulian	u_int part;
68994065Sphk	char *tp, line[BUFSIZ];
690107041Sjulian	u_long v;
691107041Sjulian	int lineno = 0, errors = 0;
69292541Simp	int i;
6931558Srgrimes
694114862Sphk	makelabel("auto", lp);
695109378Sdes	bzero(&part_set, sizeof(part_set));
696109378Sdes	bzero(&part_size_type, sizeof(part_size_type));
697109378Sdes	bzero(&part_offset_type, sizeof(part_offset_type));
6981558Srgrimes	lp->d_bbsize = BBSIZE;				/* XXX */
69996475Sphk	lp->d_sbsize = 0;				/* XXX */
7001558Srgrimes	while (fgets(line, sizeof(line) - 1, f)) {
7011558Srgrimes		lineno++;
70213544Sjoerg		if ((cp = index(line,'\n')) != 0)
7031558Srgrimes			*cp = '\0';
7041558Srgrimes		cp = skip(line);
7051558Srgrimes		if (cp == NULL)
7061558Srgrimes			continue;
7071558Srgrimes		tp = index(cp, ':');
7081558Srgrimes		if (tp == NULL) {
7091558Srgrimes			fprintf(stderr, "line %d: syntax error\n", lineno);
7101558Srgrimes			errors++;
7111558Srgrimes			continue;
7121558Srgrimes		}
7131558Srgrimes		*tp++ = '\0', tp = skip(tp);
714114571Sphk		if (!strcmp(cp, "type")) {
7151558Srgrimes			if (tp == NULL)
71699365Smarkm				tp = unknown;
7171558Srgrimes			cpp = dktypenames;
7181558Srgrimes			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
719114571Sphk				if (*cpp && !strcmp(*cpp, tp)) {
7201558Srgrimes					lp->d_type = cpp - dktypenames;
72197855Siedowse					break;
7221558Srgrimes				}
72397855Siedowse			if (cpp < &dktypenames[DKMAXTYPES])
72497855Siedowse				continue;
725107041Sjulian			v = strtoul(tp, NULL, 10);
726107041Sjulian			if (v >= DKMAXTYPES)
727107041Sjulian				fprintf(stderr, "line %d:%s %lu\n", lineno,
7281558Srgrimes				    "Warning, unknown disk type", v);
7291558Srgrimes			lp->d_type = v;
7301558Srgrimes			continue;
7311558Srgrimes		}
732114571Sphk		if (!strcmp(cp, "flags")) {
7331558Srgrimes			for (v = 0; (cp = tp) && *cp != '\0';) {
7341558Srgrimes				tp = word(cp);
735114571Sphk				if (!strcmp(cp, "removeable"))
7361558Srgrimes					v |= D_REMOVABLE;
737114571Sphk				else if (!strcmp(cp, "ecc"))
7381558Srgrimes					v |= D_ECC;
739114571Sphk				else if (!strcmp(cp, "badsect"))
7401558Srgrimes					v |= D_BADSECT;
7411558Srgrimes				else {
7421558Srgrimes					fprintf(stderr,
7431558Srgrimes					    "line %d: %s: bad flag\n",
7441558Srgrimes					    lineno, cp);
7451558Srgrimes					errors++;
7461558Srgrimes				}
7471558Srgrimes			}
7481558Srgrimes			lp->d_flags = v;
7491558Srgrimes			continue;
7501558Srgrimes		}
751114571Sphk		if (!strcmp(cp, "drivedata")) {
7521558Srgrimes			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
753107041Sjulian				lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
7541558Srgrimes				tp = word(cp);
7551558Srgrimes			}
7561558Srgrimes			continue;
7571558Srgrimes		}
758107041Sjulian		if (sscanf(cp, "%lu partitions", &v) == 1) {
759107041Sjulian			if (v == 0 || v > MAXPARTITIONS) {
7601558Srgrimes				fprintf(stderr,
7611558Srgrimes				    "line %d: bad # of partitions\n", lineno);
7621558Srgrimes				lp->d_npartitions = MAXPARTITIONS;
7631558Srgrimes				errors++;
7641558Srgrimes			} else
7651558Srgrimes				lp->d_npartitions = v;
7661558Srgrimes			continue;
7671558Srgrimes		}
7681558Srgrimes		if (tp == NULL)
76999365Smarkm			tp = blank;
770114571Sphk		if (!strcmp(cp, "disk")) {
7711558Srgrimes			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
7721558Srgrimes			continue;
7731558Srgrimes		}
774114571Sphk		if (!strcmp(cp, "label")) {
7751558Srgrimes			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
7761558Srgrimes			continue;
7771558Srgrimes		}
778114571Sphk		if (!strcmp(cp, "bytes/sector")) {
779107041Sjulian			v = strtoul(tp, NULL, 10);
780107041Sjulian			if (v == 0 || (v % DEV_BSIZE) != 0) {
7811558Srgrimes				fprintf(stderr,
7821558Srgrimes				    "line %d: %s: bad sector size\n",
7831558Srgrimes				    lineno, tp);
7841558Srgrimes				errors++;
7851558Srgrimes			} else
7861558Srgrimes				lp->d_secsize = v;
7871558Srgrimes			continue;
7881558Srgrimes		}
789114571Sphk		if (!strcmp(cp, "sectors/track")) {
790107041Sjulian			v = strtoul(tp, NULL, 10);
791107041Sjulian#if (ULONG_MAX != 0xffffffffUL)
792107041Sjulian			if (v == 0 || v > 0xffffffff) {
793107041Sjulian#else
794107041Sjulian			if (v == 0) {
795107041Sjulian#endif
7961558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
7971558Srgrimes				    lineno, tp, cp);
7981558Srgrimes				errors++;
7991558Srgrimes			} else
8001558Srgrimes				lp->d_nsectors = v;
8011558Srgrimes			continue;
8021558Srgrimes		}
803114571Sphk		if (!strcmp(cp, "sectors/cylinder")) {
804107041Sjulian			v = strtoul(tp, NULL, 10);
805107041Sjulian			if (v == 0) {
8061558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8071558Srgrimes				    lineno, tp, cp);
8081558Srgrimes				errors++;
8091558Srgrimes			} else
8101558Srgrimes				lp->d_secpercyl = v;
8111558Srgrimes			continue;
8121558Srgrimes		}
813114571Sphk		if (!strcmp(cp, "tracks/cylinder")) {
814107041Sjulian			v = strtoul(tp, NULL, 10);
815107041Sjulian			if (v == 0) {
8161558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8171558Srgrimes				    lineno, tp, cp);
8181558Srgrimes				errors++;
8191558Srgrimes			} else
8201558Srgrimes				lp->d_ntracks = v;
8211558Srgrimes			continue;
8221558Srgrimes		}
823114571Sphk		if (!strcmp(cp, "cylinders")) {
824107041Sjulian			v = strtoul(tp, NULL, 10);
825107041Sjulian			if (v == 0) {
8261558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8271558Srgrimes				    lineno, tp, cp);
8281558Srgrimes				errors++;
8291558Srgrimes			} else
8301558Srgrimes				lp->d_ncylinders = v;
8311558Srgrimes			continue;
8321558Srgrimes		}
833114571Sphk		if (!strcmp(cp, "sectors/unit")) {
834107041Sjulian			v = strtoul(tp, NULL, 10);
835107041Sjulian			if (v == 0) {
8366643Sbde				fprintf(stderr, "line %d: %s: bad %s\n",
8376643Sbde				    lineno, tp, cp);
8386643Sbde				errors++;
8396643Sbde			} else
8406643Sbde				lp->d_secperunit = v;
8416643Sbde			continue;
8426643Sbde		}
843114571Sphk		if (!strcmp(cp, "rpm")) {
844107041Sjulian			v = strtoul(tp, NULL, 10);
845107041Sjulian			if (v == 0 || v > USHRT_MAX) {
8461558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8471558Srgrimes				    lineno, tp, cp);
8481558Srgrimes				errors++;
8491558Srgrimes			} else
8501558Srgrimes				lp->d_rpm = v;
8511558Srgrimes			continue;
8521558Srgrimes		}
853114571Sphk		if (!strcmp(cp, "interleave")) {
854107041Sjulian			v = strtoul(tp, NULL, 10);
855107041Sjulian			if (v == 0 || v > USHRT_MAX) {
8561558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8571558Srgrimes				    lineno, tp, cp);
8581558Srgrimes				errors++;
8591558Srgrimes			} else
8601558Srgrimes				lp->d_interleave = v;
8611558Srgrimes			continue;
8621558Srgrimes		}
863114571Sphk		if (!strcmp(cp, "trackskew")) {
864107041Sjulian			v = strtoul(tp, NULL, 10);
865107041Sjulian			if (v > USHRT_MAX) {
8661558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8671558Srgrimes				    lineno, tp, cp);
8681558Srgrimes				errors++;
8691558Srgrimes			} else
8701558Srgrimes				lp->d_trackskew = v;
8711558Srgrimes			continue;
8721558Srgrimes		}
873114571Sphk		if (!strcmp(cp, "cylinderskew")) {
874107041Sjulian			v = strtoul(tp, NULL, 10);
875107041Sjulian			if (v > USHRT_MAX) {
8761558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
8771558Srgrimes				    lineno, tp, cp);
8781558Srgrimes				errors++;
8791558Srgrimes			} else
8801558Srgrimes				lp->d_cylskew = v;
8811558Srgrimes			continue;
8821558Srgrimes		}
883114571Sphk		if (!strcmp(cp, "headswitch")) {
884107041Sjulian			v = strtoul(tp, NULL, 10);
885107041Sjulian			lp->d_headswitch = v;
8861558Srgrimes			continue;
8871558Srgrimes		}
888114571Sphk		if (!strcmp(cp, "track-to-track seek")) {
889107041Sjulian			v = strtoul(tp, NULL, 10);
890107041Sjulian			lp->d_trkseek = v;
8911558Srgrimes			continue;
8921558Srgrimes		}
89373034Sjwd		/* the ':' was removed above */
89497534Siedowse		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
89597534Siedowse			fprintf(stderr,
89697534Siedowse			    "line %d: %s: Unknown disklabel field\n", lineno,
89797534Siedowse			    cp);
89897534Siedowse			errors++;
89997534Siedowse			continue;
90097534Siedowse		}
90197534Siedowse
90297534Siedowse		/* Process a partition specification line. */
90397534Siedowse		part = *cp - 'a';
90497534Siedowse		if (part >= lp->d_npartitions) {
90597534Siedowse			fprintf(stderr,
90697534Siedowse			    "line %d: partition name out of range a-%c: %s\n",
90797534Siedowse			    lineno, 'a' + lp->d_npartitions - 1, cp);
90897534Siedowse			errors++;
90997534Siedowse			continue;
91097534Siedowse		}
91197534Siedowse		part_set[part] = 1;
91297534Siedowse
91397534Siedowse		if (getasciipartspec(tp, lp, part, lineno) != 0) {
91497534Siedowse			errors++;
91597534Siedowse			break;
91697534Siedowse		}
91797534Siedowse	}
91897534Siedowse	errors += checklabel(lp);
91997534Siedowse	return (errors == 0);
92097534Siedowse}
92197534Siedowse
92297534Siedowse#define NXTNUM(n) do { \
9233111Spst	if (tp == NULL) { \
9243111Spst		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
92597534Siedowse		return (1); \
9263111Spst	} else { \
9273111Spst		cp = tp, tp = word(cp); \
928107041Sjulian		(n) = strtoul(cp, NULL, 10); \
9293111Spst	} \
93097534Siedowse} while (0)
93197534Siedowse
93273034Sjwd/* retain 1 character following number */
93397534Siedowse#define NXTWORD(w,n) do { \
93473034Sjwd	if (tp == NULL) { \
93573034Sjwd		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
93697534Siedowse		return (1); \
93773034Sjwd	} else { \
93873034Sjwd	        char *tmp; \
93973034Sjwd		cp = tp, tp = word(cp); \
940107041Sjulian	        (n) = strtoul(cp, &tmp, 10); \
94173034Sjwd		if (tmp) (w) = *tmp; \
94273034Sjwd	} \
94397534Siedowse} while (0)
9441558Srgrimes
94597534Siedowse/*
94697534Siedowse * Read a partition line into partition `part' in the specified disklabel.
94797534Siedowse * Return 0 on success, 1 on failure.
94897534Siedowse */
949114571Sphkstatic int
95097534Siedowsegetasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
95197534Siedowse{
95297534Siedowse	struct partition *pp;
95397534Siedowse	char *cp;
95497534Siedowse	const char **cpp;
955107041Sjulian	u_long v;
9561558Srgrimes
95797534Siedowse	pp = &lp->d_partitions[part];
95897534Siedowse	cp = NULL;
9591558Srgrimes
96097534Siedowse	v = 0;
96197534Siedowse	NXTWORD(part_size_type[part],v);
962107041Sjulian	if (v == 0 && part_size_type[part] != '*') {
963107041Sjulian		fprintf(stderr,
964107041Sjulian		    "line %d: %s: bad partition size\n", lineno, cp);
96597534Siedowse		return (1);
96697534Siedowse	}
96797534Siedowse	pp->p_size = v;
96897534Siedowse
96997534Siedowse	v = 0;
97097534Siedowse	NXTWORD(part_offset_type[part],v);
971107041Sjulian	if (v == 0 && part_offset_type[part] != '*' &&
972107041Sjulian	    part_offset_type[part] != '\0') {
973107041Sjulian		fprintf(stderr,
974107041Sjulian		    "line %d: %s: bad partition offset\n", lineno, cp);
97597534Siedowse		return (1);
97697534Siedowse	}
97797534Siedowse	pp->p_offset = v;
978112945Syar	if (tp == NULL) {
979112945Syar		fprintf(stderr, "line %d: missing file system type\n", lineno);
980112945Syar		return (1);
981112945Syar	}
98297534Siedowse	cp = tp, tp = word(cp);
98397534Siedowse	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
984114571Sphk		if (*cpp && !strcmp(*cpp, cp))
98597534Siedowse			break;
98697534Siedowse	if (*cpp != NULL) {
98797534Siedowse		pp->p_fstype = cpp - fstypenames;
98897534Siedowse	} else {
98997534Siedowse		if (isdigit(*cp))
990107041Sjulian			v = strtoul(cp, NULL, 10);
99197534Siedowse		else
99297534Siedowse			v = FSMAXTYPES;
993107041Sjulian		if (v >= FSMAXTYPES) {
99497534Siedowse			fprintf(stderr,
995102231Strhodes			    "line %d: Warning, unknown file system type %s\n",
99697534Siedowse			    lineno, cp);
99797534Siedowse			v = FS_UNUSED;
99897534Siedowse		}
99997534Siedowse		pp->p_fstype = v;
100097534Siedowse	}
100197534Siedowse
100297534Siedowse	switch (pp->p_fstype) {
100397534Siedowse	case FS_UNUSED:
1004120821Siedowse	case FS_BSDFFS:
1005120821Siedowse	case FS_BSDLFS:
1006120821Siedowse		/* accept defaults for fsize/frag/cpg */
100797534Siedowse		if (tp) {
100897534Siedowse			NXTNUM(pp->p_fsize);
100997534Siedowse			if (pp->p_fsize == 0)
101097534Siedowse				break;
101197534Siedowse			NXTNUM(v);
101297534Siedowse			pp->p_frag = v / pp->p_fsize;
1013120821Siedowse			if (tp != NULL)
1014120821Siedowse				NXTNUM(pp->p_cpg);
101597534Siedowse		}
101697534Siedowse		/* else default to 0's */
101797534Siedowse		break;
101897534Siedowse	default:
101997534Siedowse		break;
10201558Srgrimes	}
102197534Siedowse	return (0);
10221558Srgrimes}
10231558Srgrimes
10241558Srgrimes/*
10251558Srgrimes * Check disklabel for errors and fill in
10261558Srgrimes * derived fields according to supplied values.
10271558Srgrimes */
1028114571Sphkstatic int
102992541Simpchecklabel(struct disklabel *lp)
10301558Srgrimes{
103192541Simp	struct partition *pp;
10321558Srgrimes	int i, errors = 0;
10331558Srgrimes	char part;
1034107041Sjulian	u_long total_size, total_percent, current_offset;
103573034Sjwd	int seen_default_offset;
103673034Sjwd	int hog_part;
103773034Sjwd	int j;
103873034Sjwd	struct partition *pp2;
10391558Srgrimes
1040114571Sphk	if (lp == NULL)
1041114571Sphk		lp = &lab;
1042114571Sphk
1043114574Sphk	if (allfields) {
1044114574Sphk
1045114574Sphk		if (lp->d_secsize == 0) {
1046114574Sphk			fprintf(stderr, "sector size 0\n");
1047114574Sphk			return (1);
1048114574Sphk		}
1049114574Sphk		if (lp->d_nsectors == 0) {
1050114574Sphk			fprintf(stderr, "sectors/track 0\n");
1051114574Sphk			return (1);
1052114574Sphk		}
1053114574Sphk		if (lp->d_ntracks == 0) {
1054114574Sphk			fprintf(stderr, "tracks/cylinder 0\n");
1055114574Sphk			return (1);
1056114574Sphk		}
1057114574Sphk		if  (lp->d_ncylinders == 0) {
1058114574Sphk			fprintf(stderr, "cylinders/unit 0\n");
1059114574Sphk			errors++;
1060114574Sphk		}
1061114574Sphk		if (lp->d_rpm == 0)
1062114574Sphk			warnx("revolutions/minute 0");
1063114574Sphk		if (lp->d_secpercyl == 0)
1064114574Sphk			lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1065114574Sphk		if (lp->d_secperunit == 0)
1066114574Sphk			lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1067114574Sphk		if (lp->d_bbsize == 0) {
1068114574Sphk			fprintf(stderr, "boot block size 0\n");
1069114574Sphk			errors++;
1070114574Sphk		} else if (lp->d_bbsize % lp->d_secsize)
1071114574Sphk			warnx("boot block size %% sector-size != 0");
1072114574Sphk		if (lp->d_npartitions > MAXPARTITIONS)
1073114574Sphk			warnx("number of partitions (%lu) > MAXPARTITIONS (%d)",
1074114574Sphk			    (u_long)lp->d_npartitions, MAXPARTITIONS);
1075114574Sphk	} else {
1076114574Sphk		struct disklabel *vl;
1077114574Sphk
1078114574Sphk		vl = getvirginlabel();
1079114574Sphk		lp->d_secsize = vl->d_secsize;
1080114574Sphk		lp->d_nsectors = vl->d_nsectors;
1081114574Sphk		lp->d_ntracks = vl->d_ntracks;
1082114574Sphk		lp->d_ncylinders = vl->d_ncylinders;
1083114574Sphk		lp->d_rpm = vl->d_rpm;
1084114574Sphk		lp->d_interleave = vl->d_interleave;
1085114574Sphk		lp->d_secpercyl = vl->d_secpercyl;
1086114574Sphk		lp->d_secperunit = vl->d_secperunit;
1087114574Sphk		lp->d_bbsize = vl->d_bbsize;
1088114574Sphk		lp->d_npartitions = vl->d_npartitions;
10891558Srgrimes	}
109073034Sjwd
1091114574Sphk
109273034Sjwd	/* first allocate space to the partitions, then offsets */
109373034Sjwd	total_size = 0; /* in sectors */
109473034Sjwd	total_percent = 0; /* in percent */
109573034Sjwd	hog_part = -1;
109673034Sjwd	/* find all fixed partitions */
10971558Srgrimes	for (i = 0; i < lp->d_npartitions; i++) {
109873034Sjwd		pp = &lp->d_partitions[i];
109973034Sjwd		if (part_set[i]) {
110073034Sjwd			if (part_size_type[i] == '*') {
110194065Sphk				if (i == RAW_PART) {
110273034Sjwd					pp->p_size = lp->d_secperunit;
110373034Sjwd				} else {
110473034Sjwd					if (hog_part != -1)
1105114574Sphk						warnx("Too many '*' partitions (%c and %c)",
110673034Sjwd						    hog_part + 'a',i + 'a');
110773034Sjwd					else
110873034Sjwd						hog_part = i;
110973034Sjwd				}
111073034Sjwd			} else {
111173573Simp				off_t size;
111273034Sjwd
111373034Sjwd				size = pp->p_size;
111473034Sjwd				switch (part_size_type[i]) {
111573034Sjwd				case '%':
111673034Sjwd					total_percent += size;
111773034Sjwd					break;
111873034Sjwd				case 'k':
111973034Sjwd				case 'K':
112073573Simp					size *= 1024ULL;
112173034Sjwd					break;
112273034Sjwd				case 'm':
112373034Sjwd				case 'M':
112473573Simp					size *= 1024ULL * 1024ULL;
112573034Sjwd					break;
112673034Sjwd				case 'g':
112773034Sjwd				case 'G':
112873573Simp					size *= 1024ULL * 1024ULL * 1024ULL;
112973034Sjwd					break;
113073034Sjwd				case '\0':
113173034Sjwd					break;
113273034Sjwd				default:
1133114574Sphk					warnx("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
113473034Sjwd					break;
113573034Sjwd				}
113673034Sjwd				/* don't count %'s yet */
113773034Sjwd				if (part_size_type[i] != '%') {
113873034Sjwd					/*
113973034Sjwd					 * for all not in sectors, convert to
114073034Sjwd					 * sectors
114173034Sjwd					 */
114273034Sjwd					if (part_size_type[i] != '\0') {
114373034Sjwd						if (size % lp->d_secsize != 0)
1144114574Sphk							warnx("partition %c not an integer number of sectors",
114573034Sjwd							    i + 'a');
114673034Sjwd						size /= lp->d_secsize;
114773034Sjwd						pp->p_size = size;
114873034Sjwd					}
114973034Sjwd					/* else already in sectors */
115094065Sphk					if (i != RAW_PART)
115173034Sjwd						total_size += size;
115273034Sjwd				}
115373034Sjwd			}
115473034Sjwd		}
115573034Sjwd	}
115673034Sjwd	/* handle % partitions - note %'s don't need to add up to 100! */
115773034Sjwd	if (total_percent != 0) {
115873034Sjwd		long free_space = lp->d_secperunit - total_size;
115973034Sjwd		if (total_percent > 100) {
116094065Sphk			fprintf(stderr,"total percentage %lu is greater than 100\n",
116173034Sjwd			    total_percent);
116273034Sjwd			errors++;
116373034Sjwd		}
116473034Sjwd
116573034Sjwd		if (free_space > 0) {
116673034Sjwd			for (i = 0; i < lp->d_npartitions; i++) {
116773034Sjwd				pp = &lp->d_partitions[i];
116873034Sjwd				if (part_set[i] && part_size_type[i] == '%') {
116973034Sjwd					/* careful of overflows! and integer roundoff */
117073034Sjwd					pp->p_size = ((double)pp->p_size/100) * free_space;
117173034Sjwd					total_size += pp->p_size;
117273034Sjwd
117373034Sjwd					/* FIX we can lose a sector or so due to roundoff per
117473034Sjwd					   partition.  A more complex algorithm could avoid that */
117573034Sjwd				}
117673034Sjwd			}
117773034Sjwd		} else {
117873034Sjwd			fprintf(stderr,
117994065Sphk			    "%ld sectors available to give to '*' and '%%' partitions\n",
118073034Sjwd			    free_space);
118173034Sjwd			errors++;
118273034Sjwd			/* fix?  set all % partitions to size 0? */
118373034Sjwd		}
118473034Sjwd	}
118573034Sjwd	/* give anything remaining to the hog partition */
118673034Sjwd	if (hog_part != -1) {
118773034Sjwd		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
118873034Sjwd		total_size = lp->d_secperunit;
118973034Sjwd	}
119073034Sjwd
119173034Sjwd	/* Now set the offsets for each partition */
119273034Sjwd	current_offset = 0; /* in sectors */
119373034Sjwd	seen_default_offset = 0;
119473034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
11951558Srgrimes		part = 'a' + i;
11961558Srgrimes		pp = &lp->d_partitions[i];
119773034Sjwd		if (part_set[i]) {
119873034Sjwd			if (part_offset_type[i] == '*') {
119994065Sphk				if (i == RAW_PART) {
120073034Sjwd					pp->p_offset = 0;
120173034Sjwd				} else {
120273034Sjwd					pp->p_offset = current_offset;
120373034Sjwd					seen_default_offset = 1;
120473034Sjwd				}
120573034Sjwd			} else {
120673034Sjwd				/* allow them to be out of order for old-style tables */
120773034Sjwd				if (pp->p_offset < current_offset &&
1208107534Sgrog				    seen_default_offset && i != RAW_PART &&
1209107534Sgrog				    pp->p_fstype != FS_VINUM) {
121073034Sjwd					fprintf(stderr,
121194065Sphk"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
121294065Sphk					    (long)pp->p_offset,i+'a',current_offset);
121373034Sjwd					fprintf(stderr,
121473034Sjwd"Labels with any *'s for offset must be in ascending order by sector\n");
121573034Sjwd					errors++;
121673034Sjwd				} else if (pp->p_offset != current_offset &&
121794065Sphk				    i != RAW_PART && seen_default_offset) {
121873034Sjwd					/*
121973034Sjwd					 * this may give unneeded warnings if
122073034Sjwd					 * partitions are out-of-order
122173034Sjwd					 */
1222114574Sphk					warnx(
122373034Sjwd"Offset %ld for partition %c doesn't match expected value %ld",
122494065Sphk					    (long)pp->p_offset, i + 'a', current_offset);
122573034Sjwd				}
122673034Sjwd			}
122794065Sphk			if (i != RAW_PART)
122873034Sjwd				current_offset = pp->p_offset + pp->p_size;
122973034Sjwd		}
123073034Sjwd	}
123173034Sjwd
123273034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
123373034Sjwd		part = 'a' + i;
123473034Sjwd		pp = &lp->d_partitions[i];
12351558Srgrimes		if (pp->p_size == 0 && pp->p_offset != 0)
1236114574Sphk			warnx("partition %c: size 0, but offset %lu",
123737234Sbde			    part, (u_long)pp->p_offset);
12381558Srgrimes#ifdef notdef
12391558Srgrimes		if (pp->p_size % lp->d_secpercyl)
1240114574Sphk			warnx("partition %c: size %% cylinder-size != 0",
12411558Srgrimes			    part);
12421558Srgrimes		if (pp->p_offset % lp->d_secpercyl)
1243114574Sphk			warnx("partition %c: offset %% cylinder-size != 0",
12441558Srgrimes			    part);
12451558Srgrimes#endif
12461558Srgrimes		if (pp->p_offset > lp->d_secperunit) {
12471558Srgrimes			fprintf(stderr,
12481558Srgrimes			    "partition %c: offset past end of unit\n", part);
12491558Srgrimes			errors++;
12501558Srgrimes		}
12511558Srgrimes		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
12521558Srgrimes			fprintf(stderr,
125313544Sjoerg			"partition %c: partition extends past end of unit\n",
12541558Srgrimes			    part);
12551558Srgrimes			errors++;
12561558Srgrimes		}
1257114574Sphk		if (i == RAW_PART) {
125873034Sjwd			if (pp->p_fstype != FS_UNUSED)
1259114574Sphk				warnx("partition %c is not marked as unused!",part);
126073034Sjwd			if (pp->p_offset != 0)
1261114574Sphk				warnx("partition %c doesn't start at 0!",part);
126273034Sjwd			if (pp->p_size != lp->d_secperunit)
1263114574Sphk				warnx("partition %c doesn't cover the whole unit!",part);
126473034Sjwd
126573034Sjwd			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
126673034Sjwd			    (pp->p_size != lp->d_secperunit)) {
1267114574Sphk				warnx("An incorrect partition %c may cause problems for "
126873034Sjwd				    "standard system utilities",part);
126973034Sjwd			}
127073034Sjwd		}
127173034Sjwd
127273034Sjwd		/* check for overlaps */
127373034Sjwd		/* this will check for all possible overlaps once and only once */
127473034Sjwd		for (j = 0; j < i; j++) {
1275107534Sgrog			pp2 = &lp->d_partitions[j];
1276107534Sgrog			if (j != RAW_PART && i != RAW_PART &&
1277107534Sgrog			    pp->p_fstype != FS_VINUM &&
1278107534Sgrog			    pp2->p_fstype != FS_VINUM &&
127973034Sjwd			    part_set[i] && part_set[j]) {
128073034Sjwd				if (pp2->p_offset < pp->p_offset + pp->p_size &&
128173034Sjwd				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
128273034Sjwd					pp2->p_offset >= pp->p_offset)) {
128373034Sjwd					fprintf(stderr,"partitions %c and %c overlap!\n",
128473034Sjwd					    j + 'a', i + 'a');
128573034Sjwd					errors++;
128673034Sjwd				}
128773034Sjwd			}
128873034Sjwd		}
12891558Srgrimes	}
12901558Srgrimes	for (; i < MAXPARTITIONS; i++) {
12911558Srgrimes		part = 'a' + i;
12921558Srgrimes		pp = &lp->d_partitions[i];
12931558Srgrimes		if (pp->p_size || pp->p_offset)
1294114574Sphk			warnx("unused partition %c: size %d offset %lu",
129537234Sbde			    'a' + i, pp->p_size, (u_long)pp->p_offset);
12961558Srgrimes	}
12971558Srgrimes	return (errors);
12981558Srgrimes}
12991558Srgrimes
13001558Srgrimes/*
130113550Sjoerg * When operating on a "virgin" disk, try getting an initial label
130213550Sjoerg * from the associated device driver.  This might work for all device
130313550Sjoerg * drivers that are able to fetch some initial device parameters
130413550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks,
130513550Sjoerg * most IDE drives, or vn devices.
130613550Sjoerg *
130713550Sjoerg * The device name must be given in its "canonical" form.
130813550Sjoerg */
1309114571Sphkstatic struct disklabel *
131013550Sjoerggetvirginlabel(void)
131113550Sjoerg{
131299365Smarkm	static struct disklabel loclab;
1313103669Sphk	struct partition *dp;
131413550Sjoerg	int f;
1315114574Sphk	u_int u;
131613550Sjoerg
1317114571Sphk	if ((f = open(specname, O_RDONLY)) == -1) {
1318114571Sphk		warn("cannot open %s", specname);
131916431Sbde		return (NULL);
132013550Sjoerg	}
132168044Sjkh
1322103669Sphk	/* New world order */
1323103669Sphk	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
1324103669Sphk	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1325103669Sphk		close (f);
1326103669Sphk		return (NULL);
1327103669Sphk	}
1328103669Sphk	memset(&loclab, 0, sizeof loclab);
1329103669Sphk	loclab.d_magic = DISKMAGIC;
1330103669Sphk	loclab.d_magic2 = DISKMAGIC;
1331103669Sphk	loclab.d_secsize = secsize;
1332103669Sphk	loclab.d_secperunit = mediasize / secsize;
1333103669Sphk
133468044Sjkh	/*
1335103669Sphk	 * Nobody in these enligthened days uses the CHS geometry for
1336103669Sphk	 * anything, but nontheless try to get it right.  If we fail
1337103669Sphk	 * to get any good ideas from the device, construct something
1338103669Sphk	 * which is IBM-PC friendly.
133968044Sjkh	 */
1340103669Sphk	if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1341103669Sphk		loclab.d_nsectors = u;
1342103669Sphk	else
1343103669Sphk		loclab.d_nsectors = 63;
1344103669Sphk	if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1345103669Sphk		loclab.d_ntracks = u;
1346103669Sphk	else if (loclab.d_secperunit <= 63*1*1024)
1347103669Sphk		loclab.d_ntracks = 1;
1348103669Sphk	else if (loclab.d_secperunit <= 63*16*1024)
1349103669Sphk		loclab.d_ntracks = 16;
1350103669Sphk	else
1351103669Sphk		loclab.d_ntracks = 255;
1352103669Sphk	loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1353103669Sphk	loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1354103669Sphk	loclab.d_npartitions = MAXPARTITIONS;
1355103669Sphk
1356103669Sphk	/* Various (unneeded) compat stuff */
1357103669Sphk	loclab.d_rpm = 3600;
1358103669Sphk	loclab.d_bbsize = BBSIZE;
1359114574Sphk	loclab.d_interleave = 1;
1360103669Sphk	strncpy(loclab.d_typename, "amnesiac",
1361103669Sphk	    sizeof(loclab.d_typename));
1362103669Sphk
1363103669Sphk	dp = &loclab.d_partitions[RAW_PART];
1364103669Sphk	dp->p_size = loclab.d_secperunit;
1365103669Sphk	loclab.d_checksum = dkcksum(&loclab);
1366103669Sphk	close (f);
136799365Smarkm	return (&loclab);
136813550Sjoerg}
136913550Sjoerg
1370114571Sphkstatic void
137192541Simpusage(void)
13721558Srgrimes{
1373112307Sru
1374112307Sru	fprintf(stderr,
1375112307Sru	"%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",
1376114569Sphk	"usage: bsdlabel disk",
1377112307Sru	"\t\t(to read label)",
1378114571Sphk	"	bsdlabel -w [-n] [-m machine] disk [type]",
1379112307Sru	"\t\t(to write label with existing boot program)",
1380114569Sphk	"	bsdlabel -e [-n] [-m machine] disk",
1381112307Sru	"\t\t(to edit label)",
1382114569Sphk	"	bsdlabel -R [-n] [-m machine] disk protofile",
1383112307Sru	"\t\t(to restore label with existing boot program)",
1384113680Sphk	"	bsdlabel -B [-b boot] [-m machine] disk",
1385112307Sru	"\t\t(to install boot program with existing on-disk label)",
1386114571Sphk	"	bsdlabel -w -B [-n] [-b boot] [-m machine] disk [type]",
1387112307Sru	"\t\t(to write label and install boot program)",
1388113680Sphk	"	bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1389109878Sphk		"\t\t(to restore label and install boot program)"
1390109878Sphk	);
13911558Srgrimes	exit(1);
13921558Srgrimes}
1393