bsdlabel.c revision 114551
11558Srgrimes/*
292058Sobrien * Copyright (c) 1994, 1995 Gordon W. Ross
392058Sobrien * Copyright (c) 1994 Theo de Raadt
492058Sobrien * All rights reserved.
51558Srgrimes * Copyright (c) 1987, 1993
61558Srgrimes *	The Regents of the University of California.  All rights reserved.
71558Srgrimes *
81558Srgrimes * This code is derived from software contributed to Berkeley by
91558Srgrimes * Symmetric Computer Systems.
101558Srgrimes *
111558Srgrimes * Redistribution and use in source and binary forms, with or without
121558Srgrimes * modification, are permitted provided that the following conditions
131558Srgrimes * are met:
141558Srgrimes * 1. Redistributions of source code must retain the above copyright
151558Srgrimes *    notice, this list of conditions and the following disclaimer.
161558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
171558Srgrimes *    notice, this list of conditions and the following disclaimer in the
181558Srgrimes *    documentation and/or other materials provided with the distribution.
191558Srgrimes * 3. All advertising materials mentioning features or use of this software
201558Srgrimes *    must display the following acknowledgement:
211558Srgrimes *	This product includes software developed by the University of
221558Srgrimes *	California, Berkeley and its contributors.
2392058Sobrien *      This product includes software developed by Theo de Raadt.
241558Srgrimes * 4. Neither the name of the University nor the names of its contributors
251558Srgrimes *    may be used to endorse or promote products derived from this software
261558Srgrimes *    without specific prior written permission.
271558Srgrimes *
281558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
291558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
301558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
311558Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
321558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
331558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
341558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
351558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
361558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
371558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
381558Srgrimes * SUCH DAMAGE.
3992058Sobrien *
4092058Sobrien *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
411558Srgrimes */
421558Srgrimes
431558Srgrimes#ifndef lint
4436632Scharnierstatic const char copyright[] =
451558Srgrimes"@(#) Copyright (c) 1987, 1993\n\
461558Srgrimes	The Regents of the University of California.  All rights reserved.\n";
471558Srgrimes#endif /* not lint */
481558Srgrimes
491558Srgrimes#ifndef lint
5036632Scharnier#if 0
511558Srgrimesstatic char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
521558Srgrimes/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
5336632Scharnier#endif
541558Srgrimes#endif /* not lint */
551558Srgrimes
5699365Smarkm#include <sys/cdefs.h>
5799365Smarkm__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 114551 2003-05-02 20:02:11Z phk $");
5899365Smarkm
591558Srgrimes#include <sys/param.h>
601558Srgrimes#include <sys/file.h>
611558Srgrimes#include <sys/stat.h>
6213544Sjoerg#include <sys/wait.h>
63103669Sphk#include <sys/disk.h>
641558Srgrimes#define DKTYPENAMES
65101994Sbmilekic#define FSTYPENAMES
661558Srgrimes#include <sys/disklabel.h>
67112307Sru
68112307Sru#include <sys/diskmbr.h>
69112307Sru#if (DOSPARTOFF != 446 || NDOSPART != 4 || DOSPTYP_386BSD != 0xa5)
70112307Sru#error	<sys/diskmbr.h> has changed
71112307Sru#else
72112307Sru#define	I386_DOSPARTOFF		446
73112307Sru#define	I386_NDOSPART		4
74112307Sru#define	I386_DOSPTYP_386BSD	0xa5
75112307Sru#endif
76112307Sru#undef DOSPARTOFF
77112307Sru#undef NDOSPART
78112307Sru#undef DOSPTYP_386BSD
79112307Sru
80104674Snyan#include <sys/diskpc98.h>
81112307Sru#if (DOSPARTOFF != 0 || NDOSPART != 16 || DOSPTYP_386BSD != 0x94)
82112307Sru#error	<sys/diskpc98.h> has changed
83104674Snyan#else
84112307Sru#define	PC98_DOSPARTOFF		0
85112307Sru#define	PC98_NDOSPART		16
86112307Sru#define	PC98_DOSPTYP_386BSD	0x94
87104674Snyan#endif
88112307Sru#undef DOSPARTOFF
89112307Sru#undef NDOSPART
90112307Sru#undef DOSPTYP_386BSD
9199365Smarkm
92112307Sru#define	IS_PC98	(arch->mach == MACH_PC98)
93112307Sru#define	DOSPARTOFF	(IS_PC98 ? PC98_DOSPARTOFF : I386_DOSPARTOFF)
94112307Sru#define	NDOSPART	(IS_PC98 ? PC98_NDOSPART : I386_NDOSPART)
95112307Sru#define	DOSPTYP_386BSD	(IS_PC98 ? PC98_DOSPTYP_386BSD : I386_DOSPTYP_386BSD)
96112307Sru
971558Srgrimes#include <unistd.h>
981558Srgrimes#include <string.h>
991558Srgrimes#include <stdio.h>
10013544Sjoerg#include <stdlib.h>
10113544Sjoerg#include <signal.h>
10213544Sjoerg#include <stdarg.h>
1031558Srgrimes#include <ctype.h>
10426542Scharnier#include <err.h>
10559216Simp#include <errno.h>
10699365Smarkm
1071558Srgrimes#include "pathnames.h"
1081558Srgrimes
1091558Srgrimes/*
110113680Sphk * Disklabel: read and write bsdlabels.
1111558Srgrimes * The label is usually placed on one of the first sectors of the disk.
1121558Srgrimes * Many machines also place a bootstrap in the same area,
1131558Srgrimes * in which case the label is embedded in the bootstrap.
1141558Srgrimes * The bootstrap source must leave space at the proper offset
1151558Srgrimes * for the label on such machines.
1161558Srgrimes */
1171558Srgrimes
1181558Srgrimes#ifndef BBSIZE
1191558Srgrimes#define	BBSIZE	8192			/* size of boot area, with label */
1201558Srgrimes#endif
1211558Srgrimes
12273034Sjwd/* FIX!  These are too low, but are traditional */
12373034Sjwd#define DEFAULT_NEWFS_BLOCK  8192U
12473034Sjwd#define DEFAULT_NEWFS_FRAG   1024U
12573034Sjwd#define DEFAULT_NEWFS_CPG    16U
12673034Sjwd
12773034Sjwd#define BIG_NEWFS_BLOCK  16384U
12897535Siedowse#define BIG_NEWFS_FRAG   2048U
12973034Sjwd#define BIG_NEWFS_CPG    64U
13073034Sjwd
13192541Simpvoid	makelabel(const char *, const char *, struct disklabel *);
132112307Sruint	writelabel(int, void *, struct disklabel *);
13392541Simpvoid	l_perror(const char *);
13492541Simpstruct disklabel *readlabel(int);
135112307Srustruct disklabel *makebootarea(void *, struct disklabel *, int);
13692541Simpvoid	display(FILE *, const struct disklabel *);
13792541Simpint	edit(struct disklabel *, int);
13892541Simpint	editit(void);
13992541Simpchar	*skip(char *);
14092541Simpchar	*word(char *);
14192541Simpint	getasciilabel(FILE *, struct disklabel *);
14297534Siedowseint	getasciipartspec(char *, struct disklabel *, int, int);
14392541Simpint	checklabel(struct disklabel *);
14492541Simpvoid	Warning(const char *, ...) __printflike(1, 2);
14592541Simpvoid	usage(void);
14692541Simpstruct disklabel *getvirginlabel(void);
14713544Sjoerg
1481558Srgrimes#define	DEFEDITOR	_PATH_VI
1491558Srgrimes#define	streq(a,b)	(strcmp(a,b) == 0)
1501558Srgrimes
1511558Srgrimeschar	*dkname;
1521558Srgrimeschar	*specname;
15355742Skrischar	tmpfil[] = PATH_TMPFILE;
1541558Srgrimes
1551558Srgrimeschar	namebuf[BBSIZE], *np = namebuf;
1561558Srgrimesstruct	disklabel lab;
157112307Sruint64_t	bootarea[BBSIZE / 8];
15899365Smarkmchar	blank[] = "";
15999365Smarkmchar	unknown[] = "unknown";
1601558Srgrimes
16173034Sjwd#define MAX_PART ('z')
16273034Sjwd#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
16373034Sjwdchar    part_size_type[MAX_NUM_PARTS];
16473034Sjwdchar    part_offset_type[MAX_NUM_PARTS];
16573034Sjwdint     part_set[MAX_NUM_PARTS];
16673034Sjwd
1671558Srgrimesint	installboot;	/* non-zero if we should install a boot program */
1681558Srgrimeschar	*xxboot;	/* primary boot */
1691558Srgrimeschar	boot0[MAXPATHLEN];
1701558Srgrimes
171114551Sphkstatic int labeloffset = LABELOFFSET;
172114551Sphkstatic int bbsize = BBSIZE;
173114551Sphkstatic int alphacksum =
174114551Sphk#if defined(__alpha__)
175114551Sphk	1;
176114551Sphk#else
177114551Sphk	0;
178114551Sphk#endif
179114550Sphk
1801558Srgrimesenum	{
181109872Sphk	UNSPEC, EDIT, READ, RESTORE, WRITE, WRITEBOOT
1821558Srgrimes} op = UNSPEC;
1831558Srgrimes
184112307Sruenum { ARCH_I386, ARCH_ALPHA, ARCH_IA64 };
185112307Sru
186112307Sruenum { MACH_I386, MACH_PC98 };
187112307Sru
188112307Srustruct {
189112307Sru	const char	*name;
190112307Sru	int		arch;
191112307Sru	int		mach;
192112307Sru	off_t		label_sector;
193112307Sru	off_t		label_offset;
194112307Sru} arches[] = {
195112307Sru	{ "i386", ARCH_I386, MACH_I386, 1, 0 },
196112307Sru	{ "pc98", ARCH_I386, MACH_PC98, 1, 0 },
197112307Sru	{ "alpha", ARCH_ALPHA, ARCH_ALPHA, 0, 64 },
198112307Sru	{ "ia64", ARCH_IA64, ARCH_IA64, 1, 0 },
199112307Sru}, *arch;
200112307Sru#define	NARCHES	(int)(sizeof(arches) / sizeof(*arches))
201112307Sru
2021558Srgrimesint	rflag;
20373034Sjwdint	disable_write;   /* set to disable writing to disk label */
2041558Srgrimes
20513544Sjoergint
20692541Simpmain(int argc, char *argv[])
2071558Srgrimes{
20892715Simp	struct disklabel *lp;
2091558Srgrimes	FILE *t;
210112307Sru	int ch, f = 0, error = 0, i;
2111558Srgrimes	char *name = 0;
2121558Srgrimes
213112307Sru	while ((ch = getopt(argc, argv, "Bb:em:nRrs:w")) != -1)
2141558Srgrimes		switch (ch) {
2151558Srgrimes			case 'B':
2161558Srgrimes				++installboot;
2171558Srgrimes				break;
2181558Srgrimes			case 'b':
2191558Srgrimes				xxboot = optarg;
2201558Srgrimes				break;
221112307Sru			case 'm':
222114550Sphk				if (!strcmp(optarg, "i386")) {
223114550Sphk					labeloffset = 512;
224114550Sphk					bbsize = 8192;
225114551Sphk					alphacksum = 0;
226114550Sphk				} else if (!strcmp(optarg, "alpha")) {
227114550Sphk					labeloffset = 64;
228114550Sphk					bbsize = 8192;
229114550Sphk					alphacksum = 1;
230114550Sphk				}
231112307Sru				for (i = 0; i < NARCHES &&
232112307Sru				    strcmp(arches[i].name, optarg) != 0;
233112307Sru				    i++);
234112307Sru				if (i == NARCHES)
235112307Sru					errx(1, "%s: unknown architecture",
236112307Sru					    optarg);
237112307Sru				arch = &arches[i];
238112307Sru				break;
23973034Sjwd			case 'n':
24073034Sjwd				disable_write = 1;
24173034Sjwd				break;
2421558Srgrimes			case 'R':
2431558Srgrimes				if (op != UNSPEC)
2441558Srgrimes					usage();
2451558Srgrimes				op = RESTORE;
2461558Srgrimes				break;
2471558Srgrimes			case 'e':
2481558Srgrimes				if (op != UNSPEC)
2491558Srgrimes					usage();
2501558Srgrimes				op = EDIT;
2511558Srgrimes				break;
2521558Srgrimes			case 'r':
2531558Srgrimes				++rflag;
2541558Srgrimes				break;
2551558Srgrimes			case 'w':
2561558Srgrimes				if (op != UNSPEC)
2571558Srgrimes					usage();
2581558Srgrimes				op = WRITE;
2591558Srgrimes				break;
2601558Srgrimes			case '?':
2611558Srgrimes			default:
2621558Srgrimes				usage();
2631558Srgrimes		}
2641558Srgrimes	argc -= optind;
2651558Srgrimes	argv += optind;
2661558Srgrimes	if (installboot) {
2671558Srgrimes		rflag++;
2681558Srgrimes		if (op == UNSPEC)
2691558Srgrimes			op = WRITEBOOT;
2701558Srgrimes	} else {
2711558Srgrimes		if (op == UNSPEC)
2721558Srgrimes			op = READ;
273109889Sphk		xxboot = 0;
2741558Srgrimes	}
2751558Srgrimes	if (argc < 1)
2761558Srgrimes		usage();
2771558Srgrimes
278112307Sru	if (arch == NULL) {
279112307Sru		for (i = 0; i < NARCHES; i++)
280112307Sru			if (strcmp(arches[i].name,
281112307Sru#if defined(__i386__)
282112307Sru#ifdef PC98
283112307Sru			    "pc98"
284112307Sru#else
285112307Sru			    "i386"
286112307Sru#endif
287112307Sru#elif defined(__alpha__)
288112307Sru			    "alpha"
289112307Sru#elif defined(__ia64__)
290112307Sru			    "ia64"
291112307Sru#else
292112307Sru			    "unknown"
293112307Sru#endif
294112307Sru			    ) == 0) {
295112307Sru				arch = &arches[i];
296112307Sru				break;
297112307Sru			}
298112307Sru		if (i == NARCHES)
299112307Sru			errx(1, "unsupported architecture");
300112307Sru	}
301112307Sru
3021558Srgrimes	dkname = argv[0];
3031558Srgrimes	if (dkname[0] != '/') {
30459114Sobrien		(void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
3051558Srgrimes		specname = np;
3061558Srgrimes		np += strlen(specname) + 1;
3071558Srgrimes	} else
3081558Srgrimes		specname = dkname;
3091558Srgrimes	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
3101558Srgrimes	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
31159429Sobrien		(void)sprintf(specname, "%s%s", _PATH_DEV, dkname);
3121558Srgrimes		np = namebuf + strlen(specname) + 1;
3131558Srgrimes		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
3141558Srgrimes	}
315109901Sphk	if (f < 0 && errno == EBUSY) {
316109901Sphk		/* lets try to get by with ioctls */
317109901Sphk		f = open(specname, O_RDONLY);
318109901Sphk	}
3191558Srgrimes	if (f < 0)
32026542Scharnier		err(4, "%s", specname);
3211558Srgrimes
3221558Srgrimes	switch(op) {
3231558Srgrimes
32448957Sbillf	case UNSPEC:
32548957Sbillf		break;
32648957Sbillf
3271558Srgrimes	case EDIT:
3281558Srgrimes		if (argc != 1)
3291558Srgrimes			usage();
3301558Srgrimes		lp = readlabel(f);
3311558Srgrimes		error = edit(lp, f);
3321558Srgrimes		break;
3331558Srgrimes
3341558Srgrimes	case READ:
3351558Srgrimes		if (argc != 1)
3361558Srgrimes			usage();
3371558Srgrimes		lp = readlabel(f);
3381558Srgrimes		display(stdout, lp);
3391558Srgrimes		error = checklabel(lp);
3401558Srgrimes		break;
3411558Srgrimes
3421558Srgrimes	case RESTORE:
3431558Srgrimes		if (argc != 2)
3441558Srgrimes			usage();
3451558Srgrimes		if (!(t = fopen(argv[1], "r")))
34626542Scharnier			err(4, "%s", argv[1]);
34737865Sbde		if (!getasciilabel(t, &lab))
34837865Sbde			exit(1);
34937865Sbde		lp = makebootarea(bootarea, &lab, f);
35037865Sbde		*lp = lab;
35137865Sbde		error = writelabel(f, bootarea, lp);
3521558Srgrimes		break;
3531558Srgrimes
3541558Srgrimes	case WRITE:
3551558Srgrimes		if (argc == 3) {
3561558Srgrimes			name = argv[2];
3571558Srgrimes			argc--;
3581558Srgrimes		}
3591558Srgrimes		if (argc != 2)
3601558Srgrimes			usage();
3611558Srgrimes		makelabel(argv[1], name, &lab);
3621558Srgrimes		lp = makebootarea(bootarea, &lab, f);
3631558Srgrimes		*lp = lab;
3641558Srgrimes		if (checklabel(lp) == 0)
3651558Srgrimes			error = writelabel(f, bootarea, lp);
3661558Srgrimes		break;
3671558Srgrimes
3681558Srgrimes	case WRITEBOOT:
3691558Srgrimes	{
3701558Srgrimes		struct disklabel tlab;
3711558Srgrimes
3721558Srgrimes		lp = readlabel(f);
3731558Srgrimes		tlab = *lp;
3741558Srgrimes		if (argc == 2)
3751558Srgrimes			makelabel(argv[1], 0, &lab);
3761558Srgrimes		lp = makebootarea(bootarea, &lab, f);
3771558Srgrimes		*lp = tlab;
3781558Srgrimes		if (checklabel(lp) == 0)
3791558Srgrimes			error = writelabel(f, bootarea, lp);
3801558Srgrimes		break;
3811558Srgrimes	}
3821558Srgrimes	}
3831558Srgrimes	exit(error);
3841558Srgrimes}
3851558Srgrimes
3861558Srgrimes/*
387111286Sru * Construct a prototype disklabel from /etc/disktab.
3881558Srgrimes */
38913544Sjoergvoid
39092541Simpmakelabel(const char *type, const char *name, struct disklabel *lp)
3911558Srgrimes{
39292541Simp	struct disklabel *dp;
39313550Sjoerg
39413550Sjoerg	if (strcmp(type, "auto") == 0)
39513550Sjoerg		dp = getvirginlabel();
39613550Sjoerg	else
39713544Sjoerg		dp = getdiskbyname(type);
39836632Scharnier	if (dp == NULL)
39936632Scharnier		errx(1, "%s: unknown disk type", type);
4001558Srgrimes	*lp = *dp;
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
407112307Sruwritelabel(int f, void *boot, struct disklabel *lp)
4081558Srgrimes{
409112307Sru	uint64_t *p, sum;
41038384Sdfr	int i;
41138384Sdfr
41273034Sjwd	if (disable_write) {
41373034Sjwd		Warning("write to disk label supressed - label was as follows:");
41473034Sjwd		display(stdout, lp);
41573034Sjwd		return (0);
416109878Sphk	}
417109878Sphk
418109878Sphk	lp->d_magic = DISKMAGIC;
419109878Sphk	lp->d_magic2 = DISKMAGIC;
420109878Sphk	lp->d_checksum = 0;
421109878Sphk	lp->d_checksum = dkcksum(lp);
422109878Sphk	if (!rflag) {
423109878Sphk		if (ioctl(f, DIOCWDINFO, lp) < 0) {
424109878Sphk			l_perror("ioctl DIOCWDINFO");
425109878Sphk			return (1);
426109878Sphk		}
427109878Sphk		return (0);
428109878Sphk	}
429109878Sphk
430114550Sphk	bsd_disklabel_le_enc((u_char *)boot + labeloffset, lp);
431114550Sphk
432109878Sphk	(void)lseek(f, (off_t)0, SEEK_SET);
433109878Sphk
434112307Sru	if (arch->arch == ARCH_ALPHA) {
435112307Sru		/*
436112307Sru		 * Generate the bootblock checksum for the SRM console.
437112307Sru		 */
438112307Sru		for (p = (uint64_t *)boot, i = 0, sum = 0; i < 63; i++)
439112307Sru			sum += p[i];
440112307Sru		p[63] = sum;
441112307Sru	}
442109901Sphk	if (ioctl(f, DIOCBSDBB, &boot) == 0)
443109901Sphk		return (0);
444114550Sphk	if (write(f, boot, bbsize) != bbsize) {
445109878Sphk		warn("write");
446109878Sphk		return (1);
447109878Sphk	}
4481558Srgrimes	return (0);
4491558Srgrimes}
4501558Srgrimes
45113544Sjoergvoid
45292541Simpl_perror(const char *s)
4531558Srgrimes{
45436632Scharnier	switch (errno) {
4551558Srgrimes
4561558Srgrimes	case ESRCH:
45736756Scharnier		warnx("%s: no disk label on disk;", s);
45875915Simp		fprintf(stderr, "add \"-r\" to install initial label\n");
4591558Srgrimes		break;
4601558Srgrimes
4611558Srgrimes	case EINVAL:
46236756Scharnier		warnx("%s: label magic number or checksum is wrong!", s);
46336756Scharnier		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
4641558Srgrimes		break;
4651558Srgrimes
4661558Srgrimes	case EBUSY:
46736632Scharnier		warnx("%s: open partition would move or shrink", s);
4681558Srgrimes		break;
4691558Srgrimes
4701558Srgrimes	case EXDEV:
47140475Sbde		warnx("%s: '%c' partition must start at beginning of disk",
47240475Sbde		    s, 'a' + RAW_PART);
4731558Srgrimes		break;
4741558Srgrimes
4751558Srgrimes	default:
47636632Scharnier		warn((char *)NULL);
4771558Srgrimes		break;
4781558Srgrimes	}
4791558Srgrimes}
4801558Srgrimes
4811558Srgrimes/*
4821558Srgrimes * Fetch disklabel for disk.
4831558Srgrimes * Use ioctl to get label unless -r flag is given.
4841558Srgrimes */
4851558Srgrimesstruct disklabel *
48692541Simpreadlabel(int f)
4871558Srgrimes{
4881558Srgrimes
489114550Sphk	(void)lseek(f, (off_t)0, SEEK_SET);
490114550Sphk	if (read(f, bootarea, BBSIZE) < BBSIZE)
491114550Sphk		err(4, "%s", specname);
492114550Sphk	bsd_disklabel_le_dec((u_char *)bootarea + labeloffset, &lab);
493114550Sphk	return (&lab);
4941558Srgrimes}
4951558Srgrimes
4961558Srgrimes/*
4971558Srgrimes * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
4981558Srgrimes * Returns a pointer to the disklabel portion of the bootarea.
4991558Srgrimes */
5001558Srgrimesstruct disklabel *
501112307Srumakebootarea(void *boot, struct disklabel *dp, int f)
5021558Srgrimes{
50338483Sbde	struct disklabel *lp;
50492541Simp	char *p;
5051558Srgrimes	int b;
5061558Srgrimes	char *dkbasename;
5071558Srgrimes	struct stat sb;
508112307Sru	uint64_t *bootinfo;
50938411Sbde	int n;
51013892Sjoerg	char *tmpbuf;
511109889Sphk	int i, found, dps;
5121558Srgrimes
5131558Srgrimes	/* XXX */
5141558Srgrimes	if (dp->d_secsize == 0) {
5151558Srgrimes		dp->d_secsize = DEV_BSIZE;
5161558Srgrimes		dp->d_bbsize = BBSIZE;
5171558Srgrimes	}
5181558Srgrimes	lp = (struct disklabel *)
519112307Sru	    ((char *)boot + (arch->label_sector * dp->d_secsize) +
520112307Sru	    arch->label_offset);
5211558Srgrimes	bzero((char *)lp, sizeof *lp);
5221558Srgrimes	/*
5231558Srgrimes	 * If we are not installing a boot program but we are installing a
5241558Srgrimes	 * label on disk then we must read the current bootarea so we don't
5251558Srgrimes	 * clobber the existing boot.
5261558Srgrimes	 */
5271558Srgrimes	if (!installboot) {
5281558Srgrimes		if (rflag) {
5291558Srgrimes			if (read(f, boot, BBSIZE) < BBSIZE)
53026542Scharnier				err(4, "%s", specname);
5311558Srgrimes			bzero((char *)lp, sizeof *lp);
5321558Srgrimes		}
5331558Srgrimes		return (lp);
5341558Srgrimes	}
5351558Srgrimes	/*
5361558Srgrimes	 * We are installing a boot program.  Determine the name(s) and
5371558Srgrimes	 * read them into the appropriate places in the boot area.
5381558Srgrimes	 */
539109889Sphk	if (!xxboot) {
5401558Srgrimes		dkbasename = np;
5411558Srgrimes		if ((p = rindex(dkname, '/')) == NULL)
5421558Srgrimes			p = dkname;
5431558Srgrimes		else
5441558Srgrimes			p++;
5451558Srgrimes		while (*p && !isdigit(*p))
5461558Srgrimes			*np++ = *p++;
5471558Srgrimes		*np++ = '\0';
5481558Srgrimes
5491558Srgrimes		if (!xxboot) {
550109889Sphk			(void)sprintf(boot0, "%s/boot", _PATH_BOOTDIR);
55141901Sjkh			xxboot = boot0;
5521558Srgrimes		}
5531558Srgrimes	}
5541558Srgrimes
5551558Srgrimes	b = open(xxboot, O_RDONLY);
5561558Srgrimes	if (b < 0)
55726542Scharnier		err(4, "%s", xxboot);
558109889Sphk	if (fstat(b, &sb) != 0)
559109889Sphk		err(4, "%s", xxboot);
560112307Sru	if (arch->arch == ARCH_I386) {
561112307Sru		if (sb.st_size > BBSIZE)
562112307Sru			errx(4, "%s too large", xxboot);
563112307Sru		/*
564112307Sru		 * XXX Botch alert.
565112307Sru		 * The i386/PC98 has the so-called fdisk table embedded into the
566112307Sru		 * primary bootstrap.  We take care to not clobber it, but
567112307Sru		 * only if it does already contain some data.  (Otherwise,
568112307Sru		 * the xxboot provides a template.)
569112307Sru		 */
570112307Sru		if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
571112307Sru			err(4, "%s", xxboot);
572112307Sru		memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
573109889Sphk
574112307Sru		if (read(b, boot, BBSIZE) < 0)
575112307Sru			err(4, "%s", xxboot);
576109889Sphk
577112307Sru		/* XXX: rely on some very precise overlaps in definitions */
578112307Sru		dps = IS_PC98 ? sizeof(struct pc98_partition) :
579112307Sru		    sizeof(struct dos_partition);
580112307Sru		for (i = DOSPARTOFF, found = 0;
581112307Sru		     !found && i < (int)(DOSPARTOFF + NDOSPART * dps);
582112307Sru		     i++)
583112307Sru			found = tmpbuf[i] != 0;
584112307Sru		if (found)
585112307Sru			memcpy((void *)&((char *)boot)[DOSPARTOFF],
586112307Sru			       (void *)&tmpbuf[DOSPARTOFF],
587112307Sru			       NDOSPART * dps);
588112307Sru		free(tmpbuf);
589112307Sru	}
590109889Sphk
591112307Sru	if (arch->arch == ARCH_ALPHA) {
592112307Sru		if (sb.st_size > BBSIZE - dp->d_secsize)
593112307Sru			errx(4, "%s too large", xxboot);
594112307Sru		/*
595112307Sru		 * On the alpha, the primary bootstrap starts at the
596112307Sru		 * second sector of the boot area.  The first sector
597112307Sru		 * contains the label and must be edited to contain the
598112307Sru		 * size and location of the primary bootstrap.
599112307Sru		 */
600112307Sru		n = read(b, (char *)boot + dp->d_secsize,
601112307Sru		    BBSIZE - dp->d_secsize);
602112307Sru		if (n < 0)
603112307Sru			err(4, "%s", xxboot);
604112307Sru		bootinfo = (uint64_t *)((char *)boot + 480);
605112307Sru		bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
606112307Sru		bootinfo[1] = 1;	/* start at sector 1 */
607112307Sru		bootinfo[2] = 0;	/* flags (must be zero) */
608112307Sru	}
609109889Sphk
6101558Srgrimes	(void)close(b);
6111558Srgrimes	return (lp);
6121558Srgrimes}
6131558Srgrimes
61413544Sjoergvoid
61592541Simpdisplay(FILE *f, const struct disklabel *lp)
6161558Srgrimes{
61792541Simp	int i, j;
61892541Simp	const struct partition *pp;
6191558Srgrimes
6201558Srgrimes	fprintf(f, "# %s:\n", specname);
621107041Sjulian	if (lp->d_type < DKMAXTYPES)
6221558Srgrimes		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
6231558Srgrimes	else
62437234Sbde		fprintf(f, "type: %u\n", lp->d_type);
62513544Sjoerg	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
62613544Sjoerg		lp->d_typename);
62713544Sjoerg	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
62813544Sjoerg		lp->d_packname);
6291558Srgrimes	fprintf(f, "flags:");
6301558Srgrimes	if (lp->d_flags & D_REMOVABLE)
6311558Srgrimes		fprintf(f, " removeable");
6321558Srgrimes	if (lp->d_flags & D_ECC)
6331558Srgrimes		fprintf(f, " ecc");
6341558Srgrimes	if (lp->d_flags & D_BADSECT)
6351558Srgrimes		fprintf(f, " badsect");
6361558Srgrimes	fprintf(f, "\n");
63737234Sbde	fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
63837234Sbde	fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
63937234Sbde	fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
64037234Sbde	fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
64137234Sbde	fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
64237234Sbde	fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
64337234Sbde	fprintf(f, "rpm: %u\n", lp->d_rpm);
64437234Sbde	fprintf(f, "interleave: %u\n", lp->d_interleave);
64537234Sbde	fprintf(f, "trackskew: %u\n", lp->d_trackskew);
64637234Sbde	fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
64737234Sbde	fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
64837234Sbde	    (u_long)lp->d_headswitch);
64913544Sjoerg	fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
65037234Sbde	    (u_long)lp->d_trkseek);
6511558Srgrimes	fprintf(f, "drivedata: ");
6521558Srgrimes	for (i = NDDATA - 1; i >= 0; i--)
6531558Srgrimes		if (lp->d_drivedata[i])
6541558Srgrimes			break;
6551558Srgrimes	if (i < 0)
6561558Srgrimes		i = 0;
6571558Srgrimes	for (j = 0; j <= i; j++)
65837234Sbde		fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
65937234Sbde	fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
6601558Srgrimes	fprintf(f,
6615393Sgibbs	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
6621558Srgrimes	pp = lp->d_partitions;
6631558Srgrimes	for (i = 0; i < lp->d_npartitions; i++, pp++) {
6641558Srgrimes		if (pp->p_size) {
66537234Sbde			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
66637234Sbde			   (u_long)pp->p_size, (u_long)pp->p_offset);
667107041Sjulian			if (pp->p_fstype < FSMAXTYPES)
6681558Srgrimes				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
6691558Srgrimes			else
6701558Srgrimes				fprintf(f, "%8d", pp->p_fstype);
6711558Srgrimes			switch (pp->p_fstype) {
6721558Srgrimes
6731558Srgrimes			case FS_UNUSED:				/* XXX */
67437234Sbde				fprintf(f, "    %5lu %5lu %5.5s ",
67537234Sbde				    (u_long)pp->p_fsize,
67637234Sbde				    (u_long)(pp->p_fsize * pp->p_frag), "");
6771558Srgrimes				break;
6781558Srgrimes
6791558Srgrimes			case FS_BSDFFS:
68037234Sbde				fprintf(f, "    %5lu %5lu %5u ",
68137234Sbde				    (u_long)pp->p_fsize,
68237234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
6831558Srgrimes				    pp->p_cpg);
6841558Srgrimes				break;
6851558Srgrimes
6865393Sgibbs			case FS_BSDLFS:
68737234Sbde				fprintf(f, "    %5lu %5lu %5d",
68837234Sbde				    (u_long)pp->p_fsize,
68937234Sbde				    (u_long)(pp->p_fsize * pp->p_frag),
6905393Sgibbs				    pp->p_cpg);
6915393Sgibbs				break;
6925393Sgibbs
6931558Srgrimes			default:
6941558Srgrimes				fprintf(f, "%20.20s", "");
6951558Srgrimes				break;
6961558Srgrimes			}
69737234Sbde			fprintf(f, "\t# (Cyl. %4lu",
69837234Sbde			    (u_long)(pp->p_offset / lp->d_secpercyl));
6991558Srgrimes			if (pp->p_offset % lp->d_secpercyl)
7001558Srgrimes			    putc('*', f);
7011558Srgrimes			else
7021558Srgrimes			    putc(' ', f);
70337234Sbde			fprintf(f, "- %lu",
70437234Sbde			    (u_long)((pp->p_offset + pp->p_size +
70537234Sbde			    lp->d_secpercyl - 1) /
70637234Sbde			    lp->d_secpercyl - 1));
7071558Srgrimes			if (pp->p_size % lp->d_secpercyl)
7081558Srgrimes			    putc('*', f);
7091558Srgrimes			fprintf(f, ")\n");
7101558Srgrimes		}
7111558Srgrimes	}
7121558Srgrimes	fflush(f);
7131558Srgrimes}
7141558Srgrimes
71513544Sjoergint
71692541Simpedit(struct disklabel *lp, int f)
7171558Srgrimes{
71892541Simp	int c, fd;
7191558Srgrimes	struct disklabel label;
72024180Simp	FILE *fp;
7211558Srgrimes
72224180Simp	if ((fd = mkstemp(tmpfil)) == -1 ||
72324180Simp	    (fp = fdopen(fd, "w")) == NULL) {
72436632Scharnier		warnx("can't create %s", tmpfil);
7251558Srgrimes		return (1);
7261558Srgrimes	}
72724180Simp	display(fp, lp);
72824180Simp	fclose(fp);
7291558Srgrimes	for (;;) {
7301558Srgrimes		if (!editit())
7311558Srgrimes			break;
73224180Simp		fp = fopen(tmpfil, "r");
73324180Simp		if (fp == NULL) {
73436632Scharnier			warnx("can't reopen %s for reading", tmpfil);
7351558Srgrimes			break;
7361558Srgrimes		}
7371558Srgrimes		bzero((char *)&label, sizeof(label));
73824180Simp		if (getasciilabel(fp, &label)) {
7391558Srgrimes			*lp = label;
7401558Srgrimes			if (writelabel(f, bootarea, lp) == 0) {
74124180Simp				fclose(fp);
7421558Srgrimes				(void) unlink(tmpfil);
7431558Srgrimes				return (0);
7441558Srgrimes			}
7451558Srgrimes		}
74624180Simp		fclose(fp);
7471558Srgrimes		printf("re-edit the label? [y]: "); fflush(stdout);
7481558Srgrimes		c = getchar();
7491558Srgrimes		if (c != EOF && c != (int)'\n')
7501558Srgrimes			while (getchar() != (int)'\n')
7511558Srgrimes				;
7521558Srgrimes		if  (c == (int)'n')
7531558Srgrimes			break;
7541558Srgrimes	}
7551558Srgrimes	(void) unlink(tmpfil);
7561558Srgrimes	return (1);
7571558Srgrimes}
7581558Srgrimes
75913544Sjoergint
76092541Simpeditit(void)
7611558Srgrimes{
76292541Simp	int pid, xpid;
76399365Smarkm	int locstat, omask;
76499365Smarkm	const char *ed;
7651558Srgrimes
7661558Srgrimes	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
7671558Srgrimes	while ((pid = fork()) < 0) {
7681558Srgrimes		if (errno == EPROCLIM) {
76936632Scharnier			warnx("you have too many processes");
7701558Srgrimes			return(0);
7711558Srgrimes		}
7721558Srgrimes		if (errno != EAGAIN) {
77336632Scharnier			warn("fork");
7741558Srgrimes			return(0);
7751558Srgrimes		}
7761558Srgrimes		sleep(1);
7771558Srgrimes	}
7781558Srgrimes	if (pid == 0) {
7791558Srgrimes		sigsetmask(omask);
7801558Srgrimes		setgid(getgid());
7811558Srgrimes		setuid(getuid());
7821558Srgrimes		if ((ed = getenv("EDITOR")) == (char *)0)
7831558Srgrimes			ed = DEFEDITOR;
78479452Sbrian		execlp(ed, ed, tmpfil, (char *)0);
78536632Scharnier		err(1, "%s", ed);
7861558Srgrimes	}
78799365Smarkm	while ((xpid = wait(&locstat)) >= 0)
7881558Srgrimes		if (xpid == pid)
7891558Srgrimes			break;
7901558Srgrimes	sigsetmask(omask);
79199365Smarkm	return(!locstat);
7921558Srgrimes}
7931558Srgrimes
7941558Srgrimeschar *
79592541Simpskip(char *cp)
7961558Srgrimes{
7971558Srgrimes
7981558Srgrimes	while (*cp != '\0' && isspace(*cp))
7991558Srgrimes		cp++;
8001558Srgrimes	if (*cp == '\0' || *cp == '#')
80192541Simp		return (NULL);
8021558Srgrimes	return (cp);
8031558Srgrimes}
8041558Srgrimes
8051558Srgrimeschar *
80692541Simpword(char *cp)
8071558Srgrimes{
80892541Simp	char c;
8091558Srgrimes
8101558Srgrimes	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
8111558Srgrimes		cp++;
8121558Srgrimes	if ((c = *cp) != '\0') {
8131558Srgrimes		*cp++ = '\0';
8141558Srgrimes		if (c != '#')
8151558Srgrimes			return (skip(cp));
8161558Srgrimes	}
81792541Simp	return (NULL);
8181558Srgrimes}
8191558Srgrimes
8201558Srgrimes/*
8211558Srgrimes * Read an ascii label in from fd f,
8221558Srgrimes * in the same format as that put out by display(),
8231558Srgrimes * and fill in lp.
8241558Srgrimes */
82513544Sjoergint
82692541Simpgetasciilabel(FILE *f, struct disklabel *lp)
8271558Srgrimes{
82894065Sphk	char *cp;
82994065Sphk	const char **cpp;
830107041Sjulian	u_int part;
83194065Sphk	char *tp, line[BUFSIZ];
832107041Sjulian	u_long v;
833107041Sjulian	int lineno = 0, errors = 0;
83492541Simp	int i;
8351558Srgrimes
836109378Sdes	bzero(&part_set, sizeof(part_set));
837109378Sdes	bzero(&part_size_type, sizeof(part_size_type));
838109378Sdes	bzero(&part_offset_type, sizeof(part_offset_type));
8391558Srgrimes	lp->d_bbsize = BBSIZE;				/* XXX */
84096475Sphk	lp->d_sbsize = 0;				/* XXX */
8411558Srgrimes	while (fgets(line, sizeof(line) - 1, f)) {
8421558Srgrimes		lineno++;
84313544Sjoerg		if ((cp = index(line,'\n')) != 0)
8441558Srgrimes			*cp = '\0';
8451558Srgrimes		cp = skip(line);
8461558Srgrimes		if (cp == NULL)
8471558Srgrimes			continue;
8481558Srgrimes		tp = index(cp, ':');
8491558Srgrimes		if (tp == NULL) {
8501558Srgrimes			fprintf(stderr, "line %d: syntax error\n", lineno);
8511558Srgrimes			errors++;
8521558Srgrimes			continue;
8531558Srgrimes		}
8541558Srgrimes		*tp++ = '\0', tp = skip(tp);
8551558Srgrimes		if (streq(cp, "type")) {
8561558Srgrimes			if (tp == NULL)
85799365Smarkm				tp = unknown;
8581558Srgrimes			cpp = dktypenames;
8591558Srgrimes			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
86094065Sphk				if (*cpp && streq(*cpp, tp)) {
8611558Srgrimes					lp->d_type = cpp - dktypenames;
86297855Siedowse					break;
8631558Srgrimes				}
86497855Siedowse			if (cpp < &dktypenames[DKMAXTYPES])
86597855Siedowse				continue;
866107041Sjulian			v = strtoul(tp, NULL, 10);
867107041Sjulian			if (v >= DKMAXTYPES)
868107041Sjulian				fprintf(stderr, "line %d:%s %lu\n", lineno,
8691558Srgrimes				    "Warning, unknown disk type", v);
8701558Srgrimes			lp->d_type = v;
8711558Srgrimes			continue;
8721558Srgrimes		}
8731558Srgrimes		if (streq(cp, "flags")) {
8741558Srgrimes			for (v = 0; (cp = tp) && *cp != '\0';) {
8751558Srgrimes				tp = word(cp);
8761558Srgrimes				if (streq(cp, "removeable"))
8771558Srgrimes					v |= D_REMOVABLE;
8781558Srgrimes				else if (streq(cp, "ecc"))
8791558Srgrimes					v |= D_ECC;
8801558Srgrimes				else if (streq(cp, "badsect"))
8811558Srgrimes					v |= D_BADSECT;
8821558Srgrimes				else {
8831558Srgrimes					fprintf(stderr,
8841558Srgrimes					    "line %d: %s: bad flag\n",
8851558Srgrimes					    lineno, cp);
8861558Srgrimes					errors++;
8871558Srgrimes				}
8881558Srgrimes			}
8891558Srgrimes			lp->d_flags = v;
8901558Srgrimes			continue;
8911558Srgrimes		}
8921558Srgrimes		if (streq(cp, "drivedata")) {
8931558Srgrimes			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
894107041Sjulian				lp->d_drivedata[i++] = strtoul(cp, NULL, 10);
8951558Srgrimes				tp = word(cp);
8961558Srgrimes			}
8971558Srgrimes			continue;
8981558Srgrimes		}
899107041Sjulian		if (sscanf(cp, "%lu partitions", &v) == 1) {
900107041Sjulian			if (v == 0 || v > MAXPARTITIONS) {
9011558Srgrimes				fprintf(stderr,
9021558Srgrimes				    "line %d: bad # of partitions\n", lineno);
9031558Srgrimes				lp->d_npartitions = MAXPARTITIONS;
9041558Srgrimes				errors++;
9051558Srgrimes			} else
9061558Srgrimes				lp->d_npartitions = v;
9071558Srgrimes			continue;
9081558Srgrimes		}
9091558Srgrimes		if (tp == NULL)
91099365Smarkm			tp = blank;
9111558Srgrimes		if (streq(cp, "disk")) {
9121558Srgrimes			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
9131558Srgrimes			continue;
9141558Srgrimes		}
9151558Srgrimes		if (streq(cp, "label")) {
9161558Srgrimes			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
9171558Srgrimes			continue;
9181558Srgrimes		}
9191558Srgrimes		if (streq(cp, "bytes/sector")) {
920107041Sjulian			v = strtoul(tp, NULL, 10);
921107041Sjulian			if (v == 0 || (v % DEV_BSIZE) != 0) {
9221558Srgrimes				fprintf(stderr,
9231558Srgrimes				    "line %d: %s: bad sector size\n",
9241558Srgrimes				    lineno, tp);
9251558Srgrimes				errors++;
9261558Srgrimes			} else
9271558Srgrimes				lp->d_secsize = v;
9281558Srgrimes			continue;
9291558Srgrimes		}
9301558Srgrimes		if (streq(cp, "sectors/track")) {
931107041Sjulian			v = strtoul(tp, NULL, 10);
932107041Sjulian#if (ULONG_MAX != 0xffffffffUL)
933107041Sjulian			if (v == 0 || v > 0xffffffff) {
934107041Sjulian#else
935107041Sjulian			if (v == 0) {
936107041Sjulian#endif
9371558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9381558Srgrimes				    lineno, tp, cp);
9391558Srgrimes				errors++;
9401558Srgrimes			} else
9411558Srgrimes				lp->d_nsectors = v;
9421558Srgrimes			continue;
9431558Srgrimes		}
9441558Srgrimes		if (streq(cp, "sectors/cylinder")) {
945107041Sjulian			v = strtoul(tp, NULL, 10);
946107041Sjulian			if (v == 0) {
9471558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9481558Srgrimes				    lineno, tp, cp);
9491558Srgrimes				errors++;
9501558Srgrimes			} else
9511558Srgrimes				lp->d_secpercyl = v;
9521558Srgrimes			continue;
9531558Srgrimes		}
9541558Srgrimes		if (streq(cp, "tracks/cylinder")) {
955107041Sjulian			v = strtoul(tp, NULL, 10);
956107041Sjulian			if (v == 0) {
9571558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9581558Srgrimes				    lineno, tp, cp);
9591558Srgrimes				errors++;
9601558Srgrimes			} else
9611558Srgrimes				lp->d_ntracks = v;
9621558Srgrimes			continue;
9631558Srgrimes		}
9641558Srgrimes		if (streq(cp, "cylinders")) {
965107041Sjulian			v = strtoul(tp, NULL, 10);
966107041Sjulian			if (v == 0) {
9671558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9681558Srgrimes				    lineno, tp, cp);
9691558Srgrimes				errors++;
9701558Srgrimes			} else
9711558Srgrimes				lp->d_ncylinders = v;
9721558Srgrimes			continue;
9731558Srgrimes		}
9746643Sbde		if (streq(cp, "sectors/unit")) {
975107041Sjulian			v = strtoul(tp, NULL, 10);
976107041Sjulian			if (v == 0) {
9776643Sbde				fprintf(stderr, "line %d: %s: bad %s\n",
9786643Sbde				    lineno, tp, cp);
9796643Sbde				errors++;
9806643Sbde			} else
9816643Sbde				lp->d_secperunit = v;
9826643Sbde			continue;
9836643Sbde		}
9841558Srgrimes		if (streq(cp, "rpm")) {
985107041Sjulian			v = strtoul(tp, NULL, 10);
986107041Sjulian			if (v == 0 || v > USHRT_MAX) {
9871558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9881558Srgrimes				    lineno, tp, cp);
9891558Srgrimes				errors++;
9901558Srgrimes			} else
9911558Srgrimes				lp->d_rpm = v;
9921558Srgrimes			continue;
9931558Srgrimes		}
9941558Srgrimes		if (streq(cp, "interleave")) {
995107041Sjulian			v = strtoul(tp, NULL, 10);
996107041Sjulian			if (v == 0 || v > USHRT_MAX) {
9971558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
9981558Srgrimes				    lineno, tp, cp);
9991558Srgrimes				errors++;
10001558Srgrimes			} else
10011558Srgrimes				lp->d_interleave = v;
10021558Srgrimes			continue;
10031558Srgrimes		}
10041558Srgrimes		if (streq(cp, "trackskew")) {
1005107041Sjulian			v = strtoul(tp, NULL, 10);
1006107041Sjulian			if (v > USHRT_MAX) {
10071558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10081558Srgrimes				    lineno, tp, cp);
10091558Srgrimes				errors++;
10101558Srgrimes			} else
10111558Srgrimes				lp->d_trackskew = v;
10121558Srgrimes			continue;
10131558Srgrimes		}
10141558Srgrimes		if (streq(cp, "cylinderskew")) {
1015107041Sjulian			v = strtoul(tp, NULL, 10);
1016107041Sjulian			if (v > USHRT_MAX) {
10171558Srgrimes				fprintf(stderr, "line %d: %s: bad %s\n",
10181558Srgrimes				    lineno, tp, cp);
10191558Srgrimes				errors++;
10201558Srgrimes			} else
10211558Srgrimes				lp->d_cylskew = v;
10221558Srgrimes			continue;
10231558Srgrimes		}
10241558Srgrimes		if (streq(cp, "headswitch")) {
1025107041Sjulian			v = strtoul(tp, NULL, 10);
1026107041Sjulian			lp->d_headswitch = v;
10271558Srgrimes			continue;
10281558Srgrimes		}
10291558Srgrimes		if (streq(cp, "track-to-track seek")) {
1030107041Sjulian			v = strtoul(tp, NULL, 10);
1031107041Sjulian			lp->d_trkseek = v;
10321558Srgrimes			continue;
10331558Srgrimes		}
103473034Sjwd		/* the ':' was removed above */
103597534Siedowse		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
103697534Siedowse			fprintf(stderr,
103797534Siedowse			    "line %d: %s: Unknown disklabel field\n", lineno,
103897534Siedowse			    cp);
103997534Siedowse			errors++;
104097534Siedowse			continue;
104197534Siedowse		}
104297534Siedowse
104397534Siedowse		/* Process a partition specification line. */
104497534Siedowse		part = *cp - 'a';
104597534Siedowse		if (part >= lp->d_npartitions) {
104697534Siedowse			fprintf(stderr,
104797534Siedowse			    "line %d: partition name out of range a-%c: %s\n",
104897534Siedowse			    lineno, 'a' + lp->d_npartitions - 1, cp);
104997534Siedowse			errors++;
105097534Siedowse			continue;
105197534Siedowse		}
105297534Siedowse		part_set[part] = 1;
105397534Siedowse
105497534Siedowse		if (getasciipartspec(tp, lp, part, lineno) != 0) {
105597534Siedowse			errors++;
105697534Siedowse			break;
105797534Siedowse		}
105897534Siedowse	}
105997534Siedowse	errors += checklabel(lp);
106097534Siedowse	return (errors == 0);
106197534Siedowse}
106297534Siedowse
106397534Siedowse#define NXTNUM(n) do { \
10643111Spst	if (tp == NULL) { \
10653111Spst		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
106697534Siedowse		return (1); \
10673111Spst	} else { \
10683111Spst		cp = tp, tp = word(cp); \
1069107041Sjulian		(n) = strtoul(cp, NULL, 10); \
10703111Spst	} \
107197534Siedowse} while (0)
107297534Siedowse
107373034Sjwd/* retain 1 character following number */
107497534Siedowse#define NXTWORD(w,n) do { \
107573034Sjwd	if (tp == NULL) { \
107673034Sjwd		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
107797534Siedowse		return (1); \
107873034Sjwd	} else { \
107973034Sjwd	        char *tmp; \
108073034Sjwd		cp = tp, tp = word(cp); \
1081107041Sjulian	        (n) = strtoul(cp, &tmp, 10); \
108273034Sjwd		if (tmp) (w) = *tmp; \
108373034Sjwd	} \
108497534Siedowse} while (0)
10851558Srgrimes
108697534Siedowse/*
108797534Siedowse * Read a partition line into partition `part' in the specified disklabel.
108897534Siedowse * Return 0 on success, 1 on failure.
108997534Siedowse */
109097534Siedowseint
109197534Siedowsegetasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
109297534Siedowse{
109397534Siedowse	struct partition *pp;
109497534Siedowse	char *cp;
109597534Siedowse	const char **cpp;
1096107041Sjulian	u_long v;
10971558Srgrimes
109897534Siedowse	pp = &lp->d_partitions[part];
109997534Siedowse	cp = NULL;
11001558Srgrimes
110197534Siedowse	v = 0;
110297534Siedowse	NXTWORD(part_size_type[part],v);
1103107041Sjulian	if (v == 0 && part_size_type[part] != '*') {
1104107041Sjulian		fprintf(stderr,
1105107041Sjulian		    "line %d: %s: bad partition size\n", lineno, cp);
110697534Siedowse		return (1);
110797534Siedowse	}
110897534Siedowse	pp->p_size = v;
110997534Siedowse
111097534Siedowse	v = 0;
111197534Siedowse	NXTWORD(part_offset_type[part],v);
1112107041Sjulian	if (v == 0 && part_offset_type[part] != '*' &&
1113107041Sjulian	    part_offset_type[part] != '\0') {
1114107041Sjulian		fprintf(stderr,
1115107041Sjulian		    "line %d: %s: bad partition offset\n", lineno, cp);
111697534Siedowse		return (1);
111797534Siedowse	}
111897534Siedowse	pp->p_offset = v;
1119112945Syar	if (tp == NULL) {
1120112945Syar		fprintf(stderr, "line %d: missing file system type\n", lineno);
1121112945Syar		return (1);
1122112945Syar	}
112397534Siedowse	cp = tp, tp = word(cp);
112497534Siedowse	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
112597534Siedowse		if (*cpp && streq(*cpp, cp))
112697534Siedowse			break;
112797534Siedowse	if (*cpp != NULL) {
112897534Siedowse		pp->p_fstype = cpp - fstypenames;
112997534Siedowse	} else {
113097534Siedowse		if (isdigit(*cp))
1131107041Sjulian			v = strtoul(cp, NULL, 10);
113297534Siedowse		else
113397534Siedowse			v = FSMAXTYPES;
1134107041Sjulian		if (v >= FSMAXTYPES) {
113597534Siedowse			fprintf(stderr,
1136102231Strhodes			    "line %d: Warning, unknown file system type %s\n",
113797534Siedowse			    lineno, cp);
113897534Siedowse			v = FS_UNUSED;
113997534Siedowse		}
114097534Siedowse		pp->p_fstype = v;
114197534Siedowse	}
114297534Siedowse
114397534Siedowse	switch (pp->p_fstype) {
114497534Siedowse	case FS_UNUSED:
114597534Siedowse		/*
114697534Siedowse		 * allow us to accept defaults for
114797534Siedowse		 * fsize/frag/cpg
114897534Siedowse		 */
114997534Siedowse		if (tp) {
115097534Siedowse			NXTNUM(pp->p_fsize);
115197534Siedowse			if (pp->p_fsize == 0)
115297534Siedowse				break;
115397534Siedowse			NXTNUM(v);
115497534Siedowse			pp->p_frag = v / pp->p_fsize;
115597534Siedowse		}
115697534Siedowse		/* else default to 0's */
115797534Siedowse		break;
115897534Siedowse
115997534Siedowse	/* These happen to be the same */
116097534Siedowse	case FS_BSDFFS:
116197534Siedowse	case FS_BSDLFS:
116297534Siedowse		if (tp) {
116397534Siedowse			NXTNUM(pp->p_fsize);
116497534Siedowse			if (pp->p_fsize == 0)
116597534Siedowse				break;
116697534Siedowse			NXTNUM(v);
116797534Siedowse			pp->p_frag = v / pp->p_fsize;
116897534Siedowse			NXTNUM(pp->p_cpg);
116997534Siedowse		} else {
117097534Siedowse			/*
117197534Siedowse			 * FIX! poor attempt at adaptive
117297534Siedowse			 */
117397534Siedowse			/* 1 GB */
117497534Siedowse			if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
117597534Siedowse				/*
117697534Siedowse				 * FIX! These are too low, but are traditional
117797534Siedowse				 */
117897535Siedowse				pp->p_fsize = DEFAULT_NEWFS_FRAG;
117997535Siedowse				pp->p_frag = DEFAULT_NEWFS_BLOCK /
118097535Siedowse				    DEFAULT_NEWFS_FRAG;
118197534Siedowse				pp->p_cpg = DEFAULT_NEWFS_CPG;
118297534Siedowse			} else {
118397535Siedowse				pp->p_fsize = BIG_NEWFS_FRAG;
118497535Siedowse				pp->p_frag = BIG_NEWFS_BLOCK /
118597535Siedowse				    BIG_NEWFS_FRAG;
118697534Siedowse				pp->p_cpg = BIG_NEWFS_CPG;
11871558Srgrimes			}
11881558Srgrimes		}
118997534Siedowse	default:
119097534Siedowse		break;
11911558Srgrimes	}
119297534Siedowse	return (0);
11931558Srgrimes}
11941558Srgrimes
11951558Srgrimes/*
11961558Srgrimes * Check disklabel for errors and fill in
11971558Srgrimes * derived fields according to supplied values.
11981558Srgrimes */
119913544Sjoergint
120092541Simpchecklabel(struct disklabel *lp)
12011558Srgrimes{
120292541Simp	struct partition *pp;
12031558Srgrimes	int i, errors = 0;
12041558Srgrimes	char part;
1205107041Sjulian	u_long total_size, total_percent, current_offset;
120673034Sjwd	int seen_default_offset;
120773034Sjwd	int hog_part;
120873034Sjwd	int j;
120973034Sjwd	struct partition *pp2;
12101558Srgrimes
12111558Srgrimes	if (lp->d_secsize == 0) {
121237234Sbde		fprintf(stderr, "sector size 0\n");
12131558Srgrimes		return (1);
12141558Srgrimes	}
12151558Srgrimes	if (lp->d_nsectors == 0) {
121637234Sbde		fprintf(stderr, "sectors/track 0\n");
12171558Srgrimes		return (1);
12181558Srgrimes	}
12191558Srgrimes	if (lp->d_ntracks == 0) {
122037234Sbde		fprintf(stderr, "tracks/cylinder 0\n");
12211558Srgrimes		return (1);
12221558Srgrimes	}
12231558Srgrimes	if  (lp->d_ncylinders == 0) {
122437234Sbde		fprintf(stderr, "cylinders/unit 0\n");
12251558Srgrimes		errors++;
12261558Srgrimes	}
12271558Srgrimes	if (lp->d_rpm == 0)
122837234Sbde		Warning("revolutions/minute 0");
12291558Srgrimes	if (lp->d_secpercyl == 0)
12301558Srgrimes		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
12311558Srgrimes	if (lp->d_secperunit == 0)
12321558Srgrimes		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
12331558Srgrimes	if (lp->d_bbsize == 0) {
123437234Sbde		fprintf(stderr, "boot block size 0\n");
12351558Srgrimes		errors++;
12361558Srgrimes	} else if (lp->d_bbsize % lp->d_secsize)
12371558Srgrimes		Warning("boot block size %% sector-size != 0");
12381558Srgrimes	if (lp->d_npartitions > MAXPARTITIONS)
123937234Sbde		Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
124037234Sbde		    (u_long)lp->d_npartitions, MAXPARTITIONS);
124173034Sjwd
124273034Sjwd	/* first allocate space to the partitions, then offsets */
124373034Sjwd	total_size = 0; /* in sectors */
124473034Sjwd	total_percent = 0; /* in percent */
124573034Sjwd	hog_part = -1;
124673034Sjwd	/* find all fixed partitions */
12471558Srgrimes	for (i = 0; i < lp->d_npartitions; i++) {
124873034Sjwd		pp = &lp->d_partitions[i];
124973034Sjwd		if (part_set[i]) {
125073034Sjwd			if (part_size_type[i] == '*') {
125194065Sphk				if (i == RAW_PART) {
125273034Sjwd					pp->p_size = lp->d_secperunit;
125373034Sjwd				} else {
125473034Sjwd					if (hog_part != -1)
125573034Sjwd						Warning("Too many '*' partitions (%c and %c)",
125673034Sjwd						    hog_part + 'a',i + 'a');
125773034Sjwd					else
125873034Sjwd						hog_part = i;
125973034Sjwd				}
126073034Sjwd			} else {
126173573Simp				off_t size;
126273034Sjwd
126373034Sjwd				size = pp->p_size;
126473034Sjwd				switch (part_size_type[i]) {
126573034Sjwd				case '%':
126673034Sjwd					total_percent += size;
126773034Sjwd					break;
126873034Sjwd				case 'k':
126973034Sjwd				case 'K':
127073573Simp					size *= 1024ULL;
127173034Sjwd					break;
127273034Sjwd				case 'm':
127373034Sjwd				case 'M':
127473573Simp					size *= 1024ULL * 1024ULL;
127573034Sjwd					break;
127673034Sjwd				case 'g':
127773034Sjwd				case 'G':
127873573Simp					size *= 1024ULL * 1024ULL * 1024ULL;
127973034Sjwd					break;
128073034Sjwd				case '\0':
128173034Sjwd					break;
128273034Sjwd				default:
128373034Sjwd					Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
128473034Sjwd					break;
128573034Sjwd				}
128673034Sjwd				/* don't count %'s yet */
128773034Sjwd				if (part_size_type[i] != '%') {
128873034Sjwd					/*
128973034Sjwd					 * for all not in sectors, convert to
129073034Sjwd					 * sectors
129173034Sjwd					 */
129273034Sjwd					if (part_size_type[i] != '\0') {
129373034Sjwd						if (size % lp->d_secsize != 0)
129473034Sjwd							Warning("partition %c not an integer number of sectors",
129573034Sjwd							    i + 'a');
129673034Sjwd						size /= lp->d_secsize;
129773034Sjwd						pp->p_size = size;
129873034Sjwd					}
129973034Sjwd					/* else already in sectors */
130094065Sphk					if (i != RAW_PART)
130173034Sjwd						total_size += size;
130273034Sjwd				}
130373034Sjwd			}
130473034Sjwd		}
130573034Sjwd	}
130673034Sjwd	/* handle % partitions - note %'s don't need to add up to 100! */
130773034Sjwd	if (total_percent != 0) {
130873034Sjwd		long free_space = lp->d_secperunit - total_size;
130973034Sjwd		if (total_percent > 100) {
131094065Sphk			fprintf(stderr,"total percentage %lu is greater than 100\n",
131173034Sjwd			    total_percent);
131273034Sjwd			errors++;
131373034Sjwd		}
131473034Sjwd
131573034Sjwd		if (free_space > 0) {
131673034Sjwd			for (i = 0; i < lp->d_npartitions; i++) {
131773034Sjwd				pp = &lp->d_partitions[i];
131873034Sjwd				if (part_set[i] && part_size_type[i] == '%') {
131973034Sjwd					/* careful of overflows! and integer roundoff */
132073034Sjwd					pp->p_size = ((double)pp->p_size/100) * free_space;
132173034Sjwd					total_size += pp->p_size;
132273034Sjwd
132373034Sjwd					/* FIX we can lose a sector or so due to roundoff per
132473034Sjwd					   partition.  A more complex algorithm could avoid that */
132573034Sjwd				}
132673034Sjwd			}
132773034Sjwd		} else {
132873034Sjwd			fprintf(stderr,
132994065Sphk			    "%ld sectors available to give to '*' and '%%' partitions\n",
133073034Sjwd			    free_space);
133173034Sjwd			errors++;
133273034Sjwd			/* fix?  set all % partitions to size 0? */
133373034Sjwd		}
133473034Sjwd	}
133573034Sjwd	/* give anything remaining to the hog partition */
133673034Sjwd	if (hog_part != -1) {
133773034Sjwd		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
133873034Sjwd		total_size = lp->d_secperunit;
133973034Sjwd	}
134073034Sjwd
134173034Sjwd	/* Now set the offsets for each partition */
134273034Sjwd	current_offset = 0; /* in sectors */
134373034Sjwd	seen_default_offset = 0;
134473034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
13451558Srgrimes		part = 'a' + i;
13461558Srgrimes		pp = &lp->d_partitions[i];
134773034Sjwd		if (part_set[i]) {
134873034Sjwd			if (part_offset_type[i] == '*') {
134994065Sphk				if (i == RAW_PART) {
135073034Sjwd					pp->p_offset = 0;
135173034Sjwd				} else {
135273034Sjwd					pp->p_offset = current_offset;
135373034Sjwd					seen_default_offset = 1;
135473034Sjwd				}
135573034Sjwd			} else {
135673034Sjwd				/* allow them to be out of order for old-style tables */
135773034Sjwd				if (pp->p_offset < current_offset &&
1358107534Sgrog				    seen_default_offset && i != RAW_PART &&
1359107534Sgrog				    pp->p_fstype != FS_VINUM) {
136073034Sjwd					fprintf(stderr,
136194065Sphk"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
136294065Sphk					    (long)pp->p_offset,i+'a',current_offset);
136373034Sjwd					fprintf(stderr,
136473034Sjwd"Labels with any *'s for offset must be in ascending order by sector\n");
136573034Sjwd					errors++;
136673034Sjwd				} else if (pp->p_offset != current_offset &&
136794065Sphk				    i != RAW_PART && seen_default_offset) {
136873034Sjwd					/*
136973034Sjwd					 * this may give unneeded warnings if
137073034Sjwd					 * partitions are out-of-order
137173034Sjwd					 */
137273034Sjwd					Warning(
137373034Sjwd"Offset %ld for partition %c doesn't match expected value %ld",
137494065Sphk					    (long)pp->p_offset, i + 'a', current_offset);
137573034Sjwd				}
137673034Sjwd			}
137794065Sphk			if (i != RAW_PART)
137873034Sjwd				current_offset = pp->p_offset + pp->p_size;
137973034Sjwd		}
138073034Sjwd	}
138173034Sjwd
138273034Sjwd	for (i = 0; i < lp->d_npartitions; i++) {
138373034Sjwd		part = 'a' + i;
138473034Sjwd		pp = &lp->d_partitions[i];
13851558Srgrimes		if (pp->p_size == 0 && pp->p_offset != 0)
138637234Sbde			Warning("partition %c: size 0, but offset %lu",
138737234Sbde			    part, (u_long)pp->p_offset);
13881558Srgrimes#ifdef notdef
13891558Srgrimes		if (pp->p_size % lp->d_secpercyl)
13901558Srgrimes			Warning("partition %c: size %% cylinder-size != 0",
13911558Srgrimes			    part);
13921558Srgrimes		if (pp->p_offset % lp->d_secpercyl)
13931558Srgrimes			Warning("partition %c: offset %% cylinder-size != 0",
13941558Srgrimes			    part);
13951558Srgrimes#endif
13961558Srgrimes		if (pp->p_offset > lp->d_secperunit) {
13971558Srgrimes			fprintf(stderr,
13981558Srgrimes			    "partition %c: offset past end of unit\n", part);
13991558Srgrimes			errors++;
14001558Srgrimes		}
14011558Srgrimes		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
14021558Srgrimes			fprintf(stderr,
140313544Sjoerg			"partition %c: partition extends past end of unit\n",
14041558Srgrimes			    part);
14051558Srgrimes			errors++;
14061558Srgrimes		}
140794065Sphk		if (i == RAW_PART)
140873034Sjwd		{
140973034Sjwd			if (pp->p_fstype != FS_UNUSED)
141073034Sjwd				Warning("partition %c is not marked as unused!",part);
141173034Sjwd			if (pp->p_offset != 0)
141273034Sjwd				Warning("partition %c doesn't start at 0!",part);
141373034Sjwd			if (pp->p_size != lp->d_secperunit)
141473034Sjwd				Warning("partition %c doesn't cover the whole unit!",part);
141573034Sjwd
141673034Sjwd			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
141773034Sjwd			    (pp->p_size != lp->d_secperunit)) {
141873034Sjwd				Warning("An incorrect partition %c may cause problems for "
141973034Sjwd				    "standard system utilities",part);
142073034Sjwd			}
142173034Sjwd		}
142273034Sjwd
142373034Sjwd		/* check for overlaps */
142473034Sjwd		/* this will check for all possible overlaps once and only once */
142573034Sjwd		for (j = 0; j < i; j++) {
1426107534Sgrog			pp2 = &lp->d_partitions[j];
1427107534Sgrog			if (j != RAW_PART && i != RAW_PART &&
1428107534Sgrog			    pp->p_fstype != FS_VINUM &&
1429107534Sgrog			    pp2->p_fstype != FS_VINUM &&
143073034Sjwd			    part_set[i] && part_set[j]) {
143173034Sjwd				if (pp2->p_offset < pp->p_offset + pp->p_size &&
143273034Sjwd				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
143373034Sjwd					pp2->p_offset >= pp->p_offset)) {
143473034Sjwd					fprintf(stderr,"partitions %c and %c overlap!\n",
143573034Sjwd					    j + 'a', i + 'a');
143673034Sjwd					errors++;
143773034Sjwd				}
143873034Sjwd			}
143973034Sjwd		}
14401558Srgrimes	}
14411558Srgrimes	for (; i < MAXPARTITIONS; i++) {
14421558Srgrimes		part = 'a' + i;
14431558Srgrimes		pp = &lp->d_partitions[i];
14441558Srgrimes		if (pp->p_size || pp->p_offset)
144537234Sbde			Warning("unused partition %c: size %d offset %lu",
144637234Sbde			    'a' + i, pp->p_size, (u_long)pp->p_offset);
14471558Srgrimes	}
14481558Srgrimes	return (errors);
14491558Srgrimes}
14501558Srgrimes
14511558Srgrimes/*
145213550Sjoerg * When operating on a "virgin" disk, try getting an initial label
145313550Sjoerg * from the associated device driver.  This might work for all device
145413550Sjoerg * drivers that are able to fetch some initial device parameters
145513550Sjoerg * without even having access to a (BSD) disklabel, like SCSI disks,
145613550Sjoerg * most IDE drives, or vn devices.
145713550Sjoerg *
145813550Sjoerg * The device name must be given in its "canonical" form.
145913550Sjoerg */
146013550Sjoergstruct disklabel *
146113550Sjoerggetvirginlabel(void)
146213550Sjoerg{
146399365Smarkm	static struct disklabel loclab;
1464103669Sphk	struct partition *dp;
146599365Smarkm	char lnamebuf[BBSIZE];
146613550Sjoerg	int f;
1467103669Sphk	u_int secsize, u;
1468103669Sphk	off_t mediasize;
146913550Sjoerg
147013550Sjoerg	if (dkname[0] == '/') {
147137773Sbde		warnx("\"auto\" requires the usage of a canonical disk name");
147216431Sbde		return (NULL);
147313550Sjoerg	}
147499365Smarkm	(void)snprintf(lnamebuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
147599365Smarkm	if ((f = open(lnamebuf, O_RDONLY)) == -1) {
147699365Smarkm		warn("cannot open %s", lnamebuf);
147716431Sbde		return (NULL);
147813550Sjoerg	}
147968044Sjkh
1480103669Sphk	/* New world order */
1481103669Sphk	if ((ioctl(f, DIOCGMEDIASIZE, &mediasize) != 0) ||
1482103669Sphk	    (ioctl(f, DIOCGSECTORSIZE, &secsize) != 0)) {
1483103669Sphk		close (f);
1484103669Sphk		return (NULL);
1485103669Sphk	}
1486103669Sphk	memset(&loclab, 0, sizeof loclab);
1487103669Sphk	loclab.d_magic = DISKMAGIC;
1488103669Sphk	loclab.d_magic2 = DISKMAGIC;
1489103669Sphk	loclab.d_secsize = secsize;
1490103669Sphk	loclab.d_secperunit = mediasize / secsize;
1491103669Sphk
149268044Sjkh	/*
1493103669Sphk	 * Nobody in these enligthened days uses the CHS geometry for
1494103669Sphk	 * anything, but nontheless try to get it right.  If we fail
1495103669Sphk	 * to get any good ideas from the device, construct something
1496103669Sphk	 * which is IBM-PC friendly.
149768044Sjkh	 */
1498103669Sphk	if (ioctl(f, DIOCGFWSECTORS, &u) == 0)
1499103669Sphk		loclab.d_nsectors = u;
1500103669Sphk	else
1501103669Sphk		loclab.d_nsectors = 63;
1502103669Sphk	if (ioctl(f, DIOCGFWHEADS, &u) == 0)
1503103669Sphk		loclab.d_ntracks = u;
1504103669Sphk	else if (loclab.d_secperunit <= 63*1*1024)
1505103669Sphk		loclab.d_ntracks = 1;
1506103669Sphk	else if (loclab.d_secperunit <= 63*16*1024)
1507103669Sphk		loclab.d_ntracks = 16;
1508103669Sphk	else
1509103669Sphk		loclab.d_ntracks = 255;
1510103669Sphk	loclab.d_secpercyl = loclab.d_ntracks * loclab.d_nsectors;
1511103669Sphk	loclab.d_ncylinders = loclab.d_secperunit / loclab.d_secpercyl;
1512103669Sphk	loclab.d_npartitions = MAXPARTITIONS;
1513103669Sphk
1514103669Sphk	/* Various (unneeded) compat stuff */
1515103669Sphk	loclab.d_rpm = 3600;
1516103669Sphk	loclab.d_bbsize = BBSIZE;
1517103669Sphk	loclab.d_interleave = 1;;
1518103669Sphk	strncpy(loclab.d_typename, "amnesiac",
1519103669Sphk	    sizeof(loclab.d_typename));
1520103669Sphk
1521103669Sphk	dp = &loclab.d_partitions[RAW_PART];
1522103669Sphk	dp->p_size = loclab.d_secperunit;
1523103669Sphk	loclab.d_checksum = dkcksum(&loclab);
1524103669Sphk	close (f);
152599365Smarkm	return (&loclab);
152613550Sjoerg}
152713550Sjoerg
15281558Srgrimes
15291558Srgrimes/*VARARGS1*/
153013544Sjoergvoid
153192541SimpWarning(const char *fmt, ...)
15321558Srgrimes{
153313544Sjoerg	va_list ap;
15341558Srgrimes
15351558Srgrimes	fprintf(stderr, "Warning, ");
153613544Sjoerg	va_start(ap, fmt);
153713544Sjoerg	vfprintf(stderr, fmt, ap);
15381558Srgrimes	fprintf(stderr, "\n");
153913544Sjoerg	va_end(ap);
15401558Srgrimes}
15411558Srgrimes
154213544Sjoergvoid
154392541Simpusage(void)
15441558Srgrimes{
1545112307Sru
1546112307Sru	fprintf(stderr,
1547112307Sru	"%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",
1548113680Sphk	"usage: bsdlabel [-r] disk",
1549112307Sru	"\t\t(to read label)",
1550113680Sphk	"	bsdlabel -w [-nr] [-m machine] disk type [packid]",
1551112307Sru	"\t\t(to write label with existing boot program)",
1552113680Sphk	"	bsdlabel -e [-nr] [-m machine] disk",
1553112307Sru	"\t\t(to edit label)",
1554113680Sphk	"	bsdlabel -R [-nr] [-m machine] disk protofile",
1555112307Sru	"\t\t(to restore label with existing boot program)",
1556113680Sphk	"	bsdlabel -B [-b boot] [-m machine] disk",
1557112307Sru	"\t\t(to install boot program with existing on-disk label)",
1558113680Sphk	"	bsdlabel -w -B [-n] [-b boot] [-m machine] disk type [packid]",
1559112307Sru	"\t\t(to write label and install boot program)",
1560113680Sphk	"	bsdlabel -R -B [-n] [-b boot] [-m machine] disk protofile",
1561109878Sphk		"\t\t(to restore label and install boot program)"
1562109878Sphk	);
15631558Srgrimes	exit(1);
15641558Srgrimes}
1565