bsdlabel.c revision 101994
1/*
2 * Copyright (c) 1994, 1995 Gordon W. Ross
3 * Copyright (c) 1994 Theo de Raadt
4 * All rights reserved.
5 * Copyright (c) 1987, 1993
6 *	The Regents of the University of California.  All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley by
9 * Symmetric Computer Systems.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 *    notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 *    notice, this list of conditions and the following disclaimer in the
18 *    documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 *    must display the following acknowledgement:
21 *	This product includes software developed by the University of
22 *	California, Berkeley and its contributors.
23 *      This product includes software developed by Theo de Raadt.
24 * 4. Neither the name of the University nor the names of its contributors
25 *    may be used to endorse or promote products derived from this software
26 *    without specific prior written permission.
27 *
28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38 * SUCH DAMAGE.
39 *
40 *	from: $NetBSD: disksubr.c,v 1.13 2000/12/17 22:39:18 pk $
41 */
42
43#ifndef lint
44static const char copyright[] =
45"@(#) Copyright (c) 1987, 1993\n\
46	The Regents of the University of California.  All rights reserved.\n";
47#endif /* not lint */
48
49#ifndef lint
50#if 0
51static char sccsid[] = "@(#)disklabel.c	8.2 (Berkeley) 1/7/94";
52/* from static char sccsid[] = "@(#)disklabel.c	1.2 (Symmetric) 11/28/85"; */
53#endif
54#endif /* not lint */
55
56#include <sys/cdefs.h>
57__FBSDID("$FreeBSD: head/sbin/bsdlabel/bsdlabel.c 101994 2002-08-16 16:08:36Z bmilekic $");
58
59#include <sys/param.h>
60#include <sys/file.h>
61#include <sys/stat.h>
62#include <sys/wait.h>
63#define DKTYPENAMES
64#define FSTYPENAMES
65#include <sys/disklabel.h>
66#ifdef __sparc64__
67#include <sys/sun_disklabel.h>
68#endif
69
70#include <unistd.h>
71#include <string.h>
72#include <stdio.h>
73#include <stdlib.h>
74#include <signal.h>
75#include <stdarg.h>
76#include <ctype.h>
77#include <err.h>
78#include <errno.h>
79
80#include "pathnames.h"
81
82/*
83 * Disklabel: read and write disklabels.
84 * The label is usually placed on one of the first sectors of the disk.
85 * Many machines also place a bootstrap in the same area,
86 * in which case the label is embedded in the bootstrap.
87 * The bootstrap source must leave space at the proper offset
88 * for the label on such machines.
89 */
90
91#ifndef BBSIZE
92#define	BBSIZE	8192			/* size of boot area, with label */
93#endif
94
95/* FIX!  These are too low, but are traditional */
96#define DEFAULT_NEWFS_BLOCK  8192U
97#define DEFAULT_NEWFS_FRAG   1024U
98#define DEFAULT_NEWFS_CPG    16U
99
100#define BIG_NEWFS_BLOCK  16384U
101#define BIG_NEWFS_FRAG   2048U
102#define BIG_NEWFS_CPG    64U
103
104#if defined(__i386__) || defined(__ia64__)
105#define	NUMBOOT	2
106#elif defined(__alpha__) || defined(__sparc64__) || defined(__powerpc__)
107#define	NUMBOOT	1
108#else
109#error	I do not know about this architecture.
110#endif
111
112void	makelabel(const char *, const char *, struct disklabel *);
113int	writelabel(int, const char *, struct disklabel *);
114void	l_perror(const char *);
115struct disklabel *readlabel(int);
116struct disklabel *makebootarea(char *, struct disklabel *, int);
117void	display(FILE *, const struct disklabel *);
118int	edit(struct disklabel *, int);
119int	editit(void);
120char	*skip(char *);
121char	*word(char *);
122int	getasciilabel(FILE *, struct disklabel *);
123int	getasciipartspec(char *, struct disklabel *, int, int);
124int	checklabel(struct disklabel *);
125void	setbootflag(struct disklabel *);
126void	Warning(const char *, ...) __printflike(1, 2);
127void	usage(void);
128struct disklabel *getvirginlabel(void);
129
130#define	DEFEDITOR	_PATH_VI
131#define	streq(a,b)	(strcmp(a,b) == 0)
132
133char	*dkname;
134char	*specname;
135char	tmpfil[] = PATH_TMPFILE;
136
137char	namebuf[BBSIZE], *np = namebuf;
138struct	disklabel lab;
139char	bootarea[BBSIZE];
140char	blank[] = "";
141char	unknown[] = "unknown";
142
143#define MAX_PART ('z')
144#define MAX_NUM_PARTS (1 + MAX_PART - 'a')
145char    part_size_type[MAX_NUM_PARTS];
146char    part_offset_type[MAX_NUM_PARTS];
147int     part_set[MAX_NUM_PARTS];
148
149#if NUMBOOT > 0
150int	installboot;	/* non-zero if we should install a boot program */
151char	*bootbuf;	/* pointer to buffer with remainder of boot prog */
152int	bootsize;	/* size of remaining boot program */
153char	*xxboot;	/* primary boot */
154char	*bootxx;	/* secondary boot */
155char	boot0[MAXPATHLEN];
156char	boot1[MAXPATHLEN];
157#endif
158
159enum	{
160	UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
161} op = UNSPEC;
162
163int	rflag;
164int	disable_write;   /* set to disable writing to disk label */
165
166#define OPTIONS	"BNRWb:enrs:w"
167
168int
169main(int argc, char *argv[])
170{
171	struct disklabel *lp;
172	FILE *t;
173	int ch, f = 0, flag, error = 0;
174	char *name = 0;
175
176	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
177		switch (ch) {
178#if NUMBOOT > 0
179			case 'B':
180				++installboot;
181				break;
182			case 'b':
183				xxboot = optarg;
184				break;
185#if NUMBOOT > 1
186			case 's':
187				bootxx = optarg;
188				break;
189#endif
190#endif
191			case 'N':
192				if (op != UNSPEC)
193					usage();
194				op = NOWRITE;
195				break;
196			case 'n':
197				disable_write = 1;
198				break;
199			case 'R':
200				if (op != UNSPEC)
201					usage();
202				op = RESTORE;
203				break;
204			case 'W':
205				if (op != UNSPEC)
206					usage();
207				op = WRITEABLE;
208				break;
209			case 'e':
210				if (op != UNSPEC)
211					usage();
212				op = EDIT;
213				break;
214			case 'r':
215				++rflag;
216				break;
217			case 'w':
218				if (op != UNSPEC)
219					usage();
220				op = WRITE;
221				break;
222			case '?':
223			default:
224				usage();
225		}
226	argc -= optind;
227	argv += optind;
228#if NUMBOOT > 0
229	if (installboot) {
230		rflag++;
231		if (op == UNSPEC)
232			op = WRITEBOOT;
233	} else {
234		if (op == UNSPEC)
235			op = READ;
236		xxboot = bootxx = 0;
237	}
238#else
239	if (op == UNSPEC)
240		op = READ;
241#endif
242	if (argc < 1)
243		usage();
244
245	dkname = argv[0];
246	if (dkname[0] != '/') {
247		(void)sprintf(np, "%s%s%c", _PATH_DEV, dkname, 'a' + RAW_PART);
248		specname = np;
249		np += strlen(specname) + 1;
250	} else
251		specname = dkname;
252	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
253	if (f < 0 && errno == ENOENT && dkname[0] != '/') {
254		(void)sprintf(specname, "%s%s", _PATH_DEV, dkname);
255		np = namebuf + strlen(specname) + 1;
256		f = open(specname, op == READ ? O_RDONLY : O_RDWR);
257	}
258	if (f < 0)
259		err(4, "%s", specname);
260
261	switch(op) {
262
263	case UNSPEC:
264		break;
265
266	case EDIT:
267		if (argc != 1)
268			usage();
269		lp = readlabel(f);
270		error = edit(lp, f);
271		break;
272
273	case NOWRITE:
274		flag = 0;
275		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
276			err(4, "ioctl DIOCWLABEL");
277		break;
278
279	case READ:
280		if (argc != 1)
281			usage();
282		lp = readlabel(f);
283		display(stdout, lp);
284		error = checklabel(lp);
285		break;
286
287	case RESTORE:
288#if NUMBOOT > 0
289		if (installboot && argc == 3) {
290			makelabel(argv[2], 0, &lab);
291			argc--;
292
293			/*
294			 * We only called makelabel() for its side effect
295			 * of setting the bootstrap file names.  Discard
296			 * all changes to `lab' so that all values in the
297			 * final label come from the ASCII label.
298			 */
299			bzero((char *)&lab, sizeof(lab));
300		}
301#endif
302		if (argc != 2)
303			usage();
304		if (!(t = fopen(argv[1], "r")))
305			err(4, "%s", argv[1]);
306		if (!getasciilabel(t, &lab))
307			exit(1);
308		lp = makebootarea(bootarea, &lab, f);
309		*lp = lab;
310		error = writelabel(f, bootarea, lp);
311		break;
312
313	case WRITE:
314		if (argc == 3) {
315			name = argv[2];
316			argc--;
317		}
318		if (argc != 2)
319			usage();
320		makelabel(argv[1], name, &lab);
321		lp = makebootarea(bootarea, &lab, f);
322		*lp = lab;
323		if (checklabel(lp) == 0)
324			error = writelabel(f, bootarea, lp);
325		break;
326
327	case WRITEABLE:
328		flag = 1;
329		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
330			err(4, "ioctl DIOCWLABEL");
331		break;
332
333#if NUMBOOT > 0
334	case WRITEBOOT:
335	{
336		struct disklabel tlab;
337
338		lp = readlabel(f);
339		tlab = *lp;
340		if (argc == 2)
341			makelabel(argv[1], 0, &lab);
342		lp = makebootarea(bootarea, &lab, f);
343		*lp = tlab;
344		if (checklabel(lp) == 0)
345			error = writelabel(f, bootarea, lp);
346		break;
347	}
348#endif
349	}
350	exit(error);
351}
352
353/*
354 * Construct a prototype disklabel from /etc/disktab.  As a side
355 * effect, set the names of the primary and secondary boot files
356 * if specified.
357 */
358void
359makelabel(const char *type, const char *name, struct disklabel *lp)
360{
361	struct disklabel *dp;
362
363	if (strcmp(type, "auto") == 0)
364		dp = getvirginlabel();
365	else
366		dp = getdiskbyname(type);
367	if (dp == NULL)
368		errx(1, "%s: unknown disk type", type);
369	*lp = *dp;
370	bzero(lp->d_packname, sizeof(lp->d_packname));
371	if (name)
372		(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));
373}
374
375int
376writelabel(int f, const char *boot, struct disklabel *lp)
377{
378	int flag;
379#ifdef __alpha__
380	u_long *p, sum;
381	int i;
382#endif
383#ifdef __sparc64__
384	struct sun_disklabel *sl;
385	u_short cksum, *sp1, *sp2;
386	struct partition *npp;
387	struct sun_dkpart *spp;
388	int i, secpercyl;
389#endif
390
391	if (disable_write) {
392		Warning("write to disk label supressed - label was as follows:");
393		display(stdout, lp);
394		return (0);
395	} else {
396		setbootflag(lp);
397		lp->d_magic = DISKMAGIC;
398		lp->d_magic2 = DISKMAGIC;
399		lp->d_checksum = 0;
400		lp->d_checksum = dkcksum(lp);
401		if (rflag) {
402			/*
403			 * First set the kernel disk label,
404			 * then write a label to the raw disk.
405			 * If the SDINFO ioctl fails because it is unimplemented,
406			 * keep going; otherwise, the kernel consistency checks
407			 * may prevent us from changing the current (in-core)
408			 * label.
409			 */
410			if (ioctl(f, DIOCSDINFO, lp) < 0 &&
411				errno != ENODEV && errno != ENOTTY) {
412				l_perror("ioctl DIOCSDINFO");
413				return (1);
414			}
415			(void)lseek(f, (off_t)0, SEEK_SET);
416
417#ifdef __alpha__
418			/*
419			 * Generate the bootblock checksum for the SRM console.
420			 */
421			for (p = (u_long *)boot, i = 0, sum = 0; i < 63; i++)
422				sum += p[i];
423			p[63] = sum;
424#endif
425#ifdef __sparc64__
426			/*
427			 * Generate a Sun disklabel around the BSD label for
428			 * PROM compatability.
429			 */
430			sl = (struct sun_disklabel *)boot;
431			memcpy(sl->sl_text, lp->d_packname, sizeof(lp->d_packname));
432			sl->sl_rpm = lp->d_rpm;
433			sl->sl_pcylinders = lp->d_ncylinders +
434			    lp->d_acylinders; /* XXX */
435			sl->sl_sparespercyl = lp->d_sparespercyl;
436			sl->sl_interleave = lp->d_interleave;
437			sl->sl_ncylinders = lp->d_ncylinders;
438			sl->sl_acylinders = lp->d_acylinders;
439			sl->sl_ntracks = lp->d_ntracks;
440			sl->sl_nsectors = lp->d_nsectors;
441			sl->sl_magic = SUN_DKMAGIC;
442			secpercyl = sl->sl_nsectors * sl->sl_ntracks;
443			for (i = 0; i < 8; i++) {
444				spp = &sl->sl_part[i];
445				npp = &lp->d_partitions[i];
446				/*
447				 * SunOS partitions must start on a cylinder
448				 * boundary. Note this restriction is forced
449				 * upon FreeBSD/sparc64 labels too, since we
450				 * want to keep both labels synchronised.
451				 */
452				spp->sdkp_cyloffset = npp->p_offset / secpercyl;
453				spp->sdkp_nsectors = npp->p_size;
454			}
455
456			/* Compute the XOR checksum. */
457			sp1 = (u_short *)sl;
458			sp2 = (u_short *)(sl + 1);
459			sl->sl_cksum = cksum = 0;
460			while (sp1 < sp2)
461				cksum ^= *sp1++;
462			sl->sl_cksum = cksum;
463#endif
464			/*
465			 * write enable label sector before write (if necessary),
466			 * disable after writing.
467			 */
468			flag = 1;
469			if (ioctl(f, DIOCWLABEL, &flag) < 0)
470				warn("ioctl DIOCWLABEL");
471			if (write(f, boot, lp->d_bbsize) != (int)lp->d_bbsize) {
472				warn("write");
473				return (1);
474			}
475#if NUMBOOT > 0
476			/*
477			 * Output the remainder of the disklabel
478			 */
479			if (bootbuf && write(f, bootbuf, bootsize) != bootsize) {
480				warn("write");
481				return(1);
482			}
483#endif
484			flag = 0;
485			(void) ioctl(f, DIOCWLABEL, &flag);
486		} else if (ioctl(f, DIOCWDINFO, lp) < 0) {
487			l_perror("ioctl DIOCWDINFO");
488			return (1);
489		}
490	}
491	return (0);
492}
493
494void
495l_perror(const char *s)
496{
497	switch (errno) {
498
499	case ESRCH:
500		warnx("%s: no disk label on disk;", s);
501		fprintf(stderr, "add \"-r\" to install initial label\n");
502		break;
503
504	case EINVAL:
505		warnx("%s: label magic number or checksum is wrong!", s);
506		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
507		break;
508
509	case EBUSY:
510		warnx("%s: open partition would move or shrink", s);
511		break;
512
513	case EXDEV:
514		warnx("%s: '%c' partition must start at beginning of disk",
515		    s, 'a' + RAW_PART);
516		break;
517
518	default:
519		warn((char *)NULL);
520		break;
521	}
522}
523
524/*
525 * Fetch disklabel for disk.
526 * Use ioctl to get label unless -r flag is given.
527 */
528struct disklabel *
529readlabel(int f)
530{
531	struct disklabel *lp;
532
533	if (rflag) {
534		if (read(f, bootarea, BBSIZE) < BBSIZE)
535			err(4, "%s", specname);
536		for (lp = (struct disklabel *)bootarea;
537		    lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));
538		    lp = (struct disklabel *)((char *)lp + 16))
539			if (lp->d_magic == DISKMAGIC &&
540			    lp->d_magic2 == DISKMAGIC)
541				break;
542		if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) ||
543		    lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC ||
544		    dkcksum(lp) != 0)
545			errx(1,
546	    "bad pack magic number (label is damaged, or pack is unlabeled)");
547	} else {
548		lp = &lab;
549		if (ioctl(f, DIOCGDINFO, lp) < 0)
550			err(4, "ioctl DIOCGDINFO");
551	}
552	return (lp);
553}
554
555/*
556 * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot''
557 * Returns a pointer to the disklabel portion of the bootarea.
558 */
559struct disklabel *
560makebootarea(char *boot, struct disklabel *dp, int f)
561{
562	struct disklabel *lp;
563	char *p;
564	int b;
565#if NUMBOOT > 0
566	char *dkbasename;
567	struct stat sb;
568#endif
569#ifdef __alpha__
570	u_long *bootinfo;
571	int n;
572#endif
573#ifdef __i386__
574	char *tmpbuf;
575	int i, found;
576#endif
577
578	/* XXX */
579	if (dp->d_secsize == 0) {
580		dp->d_secsize = DEV_BSIZE;
581		dp->d_bbsize = BBSIZE;
582	}
583	lp = (struct disklabel *)
584		(boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);
585	bzero((char *)lp, sizeof *lp);
586#if NUMBOOT > 0
587	/*
588	 * If we are not installing a boot program but we are installing a
589	 * label on disk then we must read the current bootarea so we don't
590	 * clobber the existing boot.
591	 */
592	if (!installboot) {
593		if (rflag) {
594			if (read(f, boot, BBSIZE) < BBSIZE)
595				err(4, "%s", specname);
596			bzero((char *)lp, sizeof *lp);
597		}
598		return (lp);
599	}
600	/*
601	 * We are installing a boot program.  Determine the name(s) and
602	 * read them into the appropriate places in the boot area.
603	 */
604	if (!xxboot || !bootxx) {
605		dkbasename = np;
606		if ((p = rindex(dkname, '/')) == NULL)
607			p = dkname;
608		else
609			p++;
610		while (*p && !isdigit(*p))
611			*np++ = *p++;
612		*np++ = '\0';
613
614		if (!xxboot) {
615			(void)sprintf(boot0, "%s/boot1", _PATH_BOOTDIR);
616			xxboot = boot0;
617		}
618#if NUMBOOT > 1
619		if (!bootxx) {
620			(void)sprintf(boot1, "%s/boot2", _PATH_BOOTDIR);
621			bootxx = boot1;
622		}
623#endif
624	}
625
626	/*
627	 * Strange rules:
628	 * 1. One-piece bootstrap (hp300/hp800)
629	 * 1. One-piece bootstrap (alpha/sparc64)
630	 *	up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest
631	 *	is remembered and written later following the bootarea.
632	 * 2. Two-piece bootstraps (i386/ia64)
633	 *	up to d_secsize bytes of ``xxboot'' go in first d_secsize
634	 *	bytes of bootarea, remaining d_bbsize-d_secsize filled
635	 *	from ``bootxx''.
636	 */
637	b = open(xxboot, O_RDONLY);
638	if (b < 0)
639		err(4, "%s", xxboot);
640#if NUMBOOT > 1
641#ifdef __i386__
642	/*
643	 * XXX Botch alert.
644	 * The i386 has the so-called fdisk table embedded into the
645	 * primary bootstrap.  We take care to not clobber it, but
646	 * only if it does already contain some data.  (Otherwise,
647	 * the xxboot provides a template.)
648	 */
649	if ((tmpbuf = (char *)malloc((int)dp->d_secsize)) == 0)
650		err(4, "%s", xxboot);
651	memcpy((void *)tmpbuf, (void *)boot, (int)dp->d_secsize);
652#endif /* __i386__ */
653	if (read(b, boot, (int)dp->d_secsize) < 0)
654		err(4, "%s", xxboot);
655	(void)close(b);
656#ifdef __i386__
657	for (i = DOSPARTOFF, found = 0;
658	     !found && i < (int)(DOSPARTOFF + NDOSPART*sizeof(struct dos_partition));
659	     i++)
660		found = tmpbuf[i] != 0;
661	if (found)
662		memcpy((void *)&boot[DOSPARTOFF],
663		       (void *)&tmpbuf[DOSPARTOFF],
664		       NDOSPART * sizeof(struct dos_partition));
665	free(tmpbuf);
666#endif /* __i386__ */
667	b = open(bootxx, O_RDONLY);
668	if (b < 0)
669		err(4, "%s", bootxx);
670	if (fstat(b, &sb) != 0)
671		err(4, "%s", bootxx);
672	if (dp->d_secsize + sb.st_size > dp->d_bbsize)
673		errx(4, "%s too large", bootxx);
674	if (read(b, &boot[dp->d_secsize],
675		 (int)(dp->d_bbsize-dp->d_secsize)) < 0)
676		err(4, "%s", bootxx);
677#else /* !(NUMBOOT > 1) */
678#ifdef __alpha__
679	/*
680	 * On the alpha, the primary bootstrap starts at the
681	 * second sector of the boot area.  The first sector
682	 * contains the label and must be edited to contain the
683	 * size and location of the primary bootstrap.
684	 */
685	n = read(b, boot + dp->d_secsize, (int)dp->d_bbsize);
686	if (n < 0)
687		err(4, "%s", xxboot);
688	bootinfo = (u_long *)(boot + 480);
689	bootinfo[0] = (n + dp->d_secsize - 1) / dp->d_secsize;
690	bootinfo[1] = 1;	/* start at sector 1 */
691	bootinfo[2] = 0;	/* flags (must be zero) */
692#else /* !__alpha__ */
693	if (read(b, boot, (int)dp->d_bbsize) < 0)
694		err(4, "%s", xxboot);
695#endif /* __alpha__ */
696	if (fstat(b, &sb) != 0)
697		err(4, "%s", xxboot);
698	bootsize = (int)sb.st_size - dp->d_bbsize;
699	if (bootsize > 0) {
700		/* XXX assume d_secsize is a power of two */
701		bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);
702		bootbuf = (char *)malloc((size_t)bootsize);
703		if (bootbuf == 0)
704			err(4, "%s", xxboot);
705		if (read(b, bootbuf, bootsize) < 0) {
706			free(bootbuf);
707			err(4, "%s", xxboot);
708		}
709	}
710#endif /* NUMBOOT > 1 */
711	(void)close(b);
712#endif /* NUMBOOT > 0 */
713	/*
714	 * Make sure no part of the bootstrap is written in the area
715	 * reserved for the label.
716	 */
717	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)
718		if (*p)
719			errx(2, "bootstrap doesn't leave room for disk label");
720	return (lp);
721}
722
723void
724display(FILE *f, const struct disklabel *lp)
725{
726	int i, j;
727	const struct partition *pp;
728
729	fprintf(f, "# %s:\n", specname);
730	if ((unsigned) lp->d_type < DKMAXTYPES)
731		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);
732	else
733		fprintf(f, "type: %u\n", lp->d_type);
734	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename),
735		lp->d_typename);
736	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
737		lp->d_packname);
738	fprintf(f, "flags:");
739	if (lp->d_flags & D_REMOVABLE)
740		fprintf(f, " removeable");
741	if (lp->d_flags & D_ECC)
742		fprintf(f, " ecc");
743	if (lp->d_flags & D_BADSECT)
744		fprintf(f, " badsect");
745	fprintf(f, "\n");
746	fprintf(f, "bytes/sector: %lu\n", (u_long)lp->d_secsize);
747	fprintf(f, "sectors/track: %lu\n", (u_long)lp->d_nsectors);
748	fprintf(f, "tracks/cylinder: %lu\n", (u_long)lp->d_ntracks);
749	fprintf(f, "sectors/cylinder: %lu\n", (u_long)lp->d_secpercyl);
750	fprintf(f, "cylinders: %lu\n", (u_long)lp->d_ncylinders);
751	fprintf(f, "sectors/unit: %lu\n", (u_long)lp->d_secperunit);
752	fprintf(f, "rpm: %u\n", lp->d_rpm);
753	fprintf(f, "interleave: %u\n", lp->d_interleave);
754	fprintf(f, "trackskew: %u\n", lp->d_trackskew);
755	fprintf(f, "cylinderskew: %u\n", lp->d_cylskew);
756	fprintf(f, "headswitch: %lu\t\t# milliseconds\n",
757	    (u_long)lp->d_headswitch);
758	fprintf(f, "track-to-track seek: %ld\t# milliseconds\n",
759	    (u_long)lp->d_trkseek);
760	fprintf(f, "drivedata: ");
761	for (i = NDDATA - 1; i >= 0; i--)
762		if (lp->d_drivedata[i])
763			break;
764	if (i < 0)
765		i = 0;
766	for (j = 0; j <= i; j++)
767		fprintf(f, "%lu ", (u_long)lp->d_drivedata[j]);
768	fprintf(f, "\n\n%u partitions:\n", lp->d_npartitions);
769	fprintf(f,
770	    "#        size   offset    fstype   [fsize bsize bps/cpg]\n");
771	pp = lp->d_partitions;
772	for (i = 0; i < lp->d_npartitions; i++, pp++) {
773		if (pp->p_size) {
774			fprintf(f, "  %c: %8lu %8lu  ", 'a' + i,
775			   (u_long)pp->p_size, (u_long)pp->p_offset);
776			if ((unsigned) pp->p_fstype < FSMAXTYPES)
777				fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
778			else
779				fprintf(f, "%8d", pp->p_fstype);
780			switch (pp->p_fstype) {
781
782			case FS_UNUSED:				/* XXX */
783				fprintf(f, "    %5lu %5lu %5.5s ",
784				    (u_long)pp->p_fsize,
785				    (u_long)(pp->p_fsize * pp->p_frag), "");
786				break;
787
788			case FS_BSDFFS:
789				fprintf(f, "    %5lu %5lu %5u ",
790				    (u_long)pp->p_fsize,
791				    (u_long)(pp->p_fsize * pp->p_frag),
792				    pp->p_cpg);
793				break;
794
795			case FS_BSDLFS:
796				fprintf(f, "    %5lu %5lu %5d",
797				    (u_long)pp->p_fsize,
798				    (u_long)(pp->p_fsize * pp->p_frag),
799				    pp->p_cpg);
800				break;
801
802			default:
803				fprintf(f, "%20.20s", "");
804				break;
805			}
806			fprintf(f, "\t# (Cyl. %4lu",
807			    (u_long)(pp->p_offset / lp->d_secpercyl));
808			if (pp->p_offset % lp->d_secpercyl)
809			    putc('*', f);
810			else
811			    putc(' ', f);
812			fprintf(f, "- %lu",
813			    (u_long)((pp->p_offset + pp->p_size +
814			    lp->d_secpercyl - 1) /
815			    lp->d_secpercyl - 1));
816			if (pp->p_size % lp->d_secpercyl)
817			    putc('*', f);
818			fprintf(f, ")\n");
819		}
820	}
821	fflush(f);
822}
823
824int
825edit(struct disklabel *lp, int f)
826{
827	int c, fd;
828	struct disklabel label;
829	FILE *fp;
830
831	if ((fd = mkstemp(tmpfil)) == -1 ||
832	    (fp = fdopen(fd, "w")) == NULL) {
833		warnx("can't create %s", tmpfil);
834		return (1);
835	}
836	display(fp, lp);
837	fclose(fp);
838	for (;;) {
839		if (!editit())
840			break;
841		fp = fopen(tmpfil, "r");
842		if (fp == NULL) {
843			warnx("can't reopen %s for reading", tmpfil);
844			break;
845		}
846		bzero((char *)&label, sizeof(label));
847		if (getasciilabel(fp, &label)) {
848			*lp = label;
849			if (writelabel(f, bootarea, lp) == 0) {
850				fclose(fp);
851				(void) unlink(tmpfil);
852				return (0);
853			}
854		}
855		fclose(fp);
856		printf("re-edit the label? [y]: "); fflush(stdout);
857		c = getchar();
858		if (c != EOF && c != (int)'\n')
859			while (getchar() != (int)'\n')
860				;
861		if  (c == (int)'n')
862			break;
863	}
864	(void) unlink(tmpfil);
865	return (1);
866}
867
868int
869editit(void)
870{
871	int pid, xpid;
872	int locstat, omask;
873	const char *ed;
874
875	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
876	while ((pid = fork()) < 0) {
877		if (errno == EPROCLIM) {
878			warnx("you have too many processes");
879			return(0);
880		}
881		if (errno != EAGAIN) {
882			warn("fork");
883			return(0);
884		}
885		sleep(1);
886	}
887	if (pid == 0) {
888		sigsetmask(omask);
889		setgid(getgid());
890		setuid(getuid());
891		if ((ed = getenv("EDITOR")) == (char *)0)
892			ed = DEFEDITOR;
893		execlp(ed, ed, tmpfil, (char *)0);
894		err(1, "%s", ed);
895	}
896	while ((xpid = wait(&locstat)) >= 0)
897		if (xpid == pid)
898			break;
899	sigsetmask(omask);
900	return(!locstat);
901}
902
903char *
904skip(char *cp)
905{
906
907	while (*cp != '\0' && isspace(*cp))
908		cp++;
909	if (*cp == '\0' || *cp == '#')
910		return (NULL);
911	return (cp);
912}
913
914char *
915word(char *cp)
916{
917	char c;
918
919	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
920		cp++;
921	if ((c = *cp) != '\0') {
922		*cp++ = '\0';
923		if (c != '#')
924			return (skip(cp));
925	}
926	return (NULL);
927}
928
929/*
930 * Read an ascii label in from fd f,
931 * in the same format as that put out by display(),
932 * and fill in lp.
933 */
934int
935getasciilabel(FILE *f, struct disklabel *lp)
936{
937	char *cp;
938	const char **cpp;
939	unsigned int part;
940	char *tp, line[BUFSIZ];
941	int v, lineno = 0, errors = 0;
942	int i;
943
944	lp->d_bbsize = BBSIZE;				/* XXX */
945	lp->d_sbsize = 0;				/* XXX */
946	while (fgets(line, sizeof(line) - 1, f)) {
947		lineno++;
948		if ((cp = index(line,'\n')) != 0)
949			*cp = '\0';
950		cp = skip(line);
951		if (cp == NULL)
952			continue;
953		tp = index(cp, ':');
954		if (tp == NULL) {
955			fprintf(stderr, "line %d: syntax error\n", lineno);
956			errors++;
957			continue;
958		}
959		*tp++ = '\0', tp = skip(tp);
960		if (streq(cp, "type")) {
961			if (tp == NULL)
962				tp = unknown;
963			cpp = dktypenames;
964			for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
965				if (*cpp && streq(*cpp, tp)) {
966					lp->d_type = cpp - dktypenames;
967					break;
968				}
969			if (cpp < &dktypenames[DKMAXTYPES])
970				continue;
971			v = atoi(tp);
972			if ((unsigned)v >= DKMAXTYPES)
973				fprintf(stderr, "line %d:%s %d\n", lineno,
974				    "Warning, unknown disk type", v);
975			lp->d_type = v;
976			continue;
977		}
978		if (streq(cp, "flags")) {
979			for (v = 0; (cp = tp) && *cp != '\0';) {
980				tp = word(cp);
981				if (streq(cp, "removeable"))
982					v |= D_REMOVABLE;
983				else if (streq(cp, "ecc"))
984					v |= D_ECC;
985				else if (streq(cp, "badsect"))
986					v |= D_BADSECT;
987				else {
988					fprintf(stderr,
989					    "line %d: %s: bad flag\n",
990					    lineno, cp);
991					errors++;
992				}
993			}
994			lp->d_flags = v;
995			continue;
996		}
997		if (streq(cp, "drivedata")) {
998			for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
999				lp->d_drivedata[i++] = atoi(cp);
1000				tp = word(cp);
1001			}
1002			continue;
1003		}
1004		if (sscanf(cp, "%d partitions", &v) == 1) {
1005			if (v == 0 || (unsigned)v > MAXPARTITIONS) {
1006				fprintf(stderr,
1007				    "line %d: bad # of partitions\n", lineno);
1008				lp->d_npartitions = MAXPARTITIONS;
1009				errors++;
1010			} else
1011				lp->d_npartitions = v;
1012			continue;
1013		}
1014		if (tp == NULL)
1015			tp = blank;
1016		if (streq(cp, "disk")) {
1017			strncpy(lp->d_typename, tp, sizeof (lp->d_typename));
1018			continue;
1019		}
1020		if (streq(cp, "label")) {
1021			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
1022			continue;
1023		}
1024		if (streq(cp, "bytes/sector")) {
1025			v = atoi(tp);
1026			if (v <= 0 || (v % DEV_BSIZE) != 0) {
1027				fprintf(stderr,
1028				    "line %d: %s: bad sector size\n",
1029				    lineno, tp);
1030				errors++;
1031			} else
1032				lp->d_secsize = v;
1033			continue;
1034		}
1035		if (streq(cp, "sectors/track")) {
1036			v = atoi(tp);
1037			if (v <= 0) {
1038				fprintf(stderr, "line %d: %s: bad %s\n",
1039				    lineno, tp, cp);
1040				errors++;
1041			} else
1042				lp->d_nsectors = v;
1043			continue;
1044		}
1045		if (streq(cp, "sectors/cylinder")) {
1046			v = atoi(tp);
1047			if (v <= 0) {
1048				fprintf(stderr, "line %d: %s: bad %s\n",
1049				    lineno, tp, cp);
1050				errors++;
1051			} else
1052				lp->d_secpercyl = v;
1053			continue;
1054		}
1055		if (streq(cp, "tracks/cylinder")) {
1056			v = atoi(tp);
1057			if (v <= 0) {
1058				fprintf(stderr, "line %d: %s: bad %s\n",
1059				    lineno, tp, cp);
1060				errors++;
1061			} else
1062				lp->d_ntracks = v;
1063			continue;
1064		}
1065		if (streq(cp, "cylinders")) {
1066			v = atoi(tp);
1067			if (v <= 0) {
1068				fprintf(stderr, "line %d: %s: bad %s\n",
1069				    lineno, tp, cp);
1070				errors++;
1071			} else
1072				lp->d_ncylinders = v;
1073			continue;
1074		}
1075		if (streq(cp, "sectors/unit")) {
1076			v = atoi(tp);
1077			if (v <= 0) {
1078				fprintf(stderr, "line %d: %s: bad %s\n",
1079				    lineno, tp, cp);
1080				errors++;
1081			} else
1082				lp->d_secperunit = v;
1083			continue;
1084		}
1085		if (streq(cp, "rpm")) {
1086			v = atoi(tp);
1087			if (v <= 0) {
1088				fprintf(stderr, "line %d: %s: bad %s\n",
1089				    lineno, tp, cp);
1090				errors++;
1091			} else
1092				lp->d_rpm = v;
1093			continue;
1094		}
1095		if (streq(cp, "interleave")) {
1096			v = atoi(tp);
1097			if (v <= 0) {
1098				fprintf(stderr, "line %d: %s: bad %s\n",
1099				    lineno, tp, cp);
1100				errors++;
1101			} else
1102				lp->d_interleave = v;
1103			continue;
1104		}
1105		if (streq(cp, "trackskew")) {
1106			v = atoi(tp);
1107			if (v < 0) {
1108				fprintf(stderr, "line %d: %s: bad %s\n",
1109				    lineno, tp, cp);
1110				errors++;
1111			} else
1112				lp->d_trackskew = v;
1113			continue;
1114		}
1115		if (streq(cp, "cylinderskew")) {
1116			v = atoi(tp);
1117			if (v < 0) {
1118				fprintf(stderr, "line %d: %s: bad %s\n",
1119				    lineno, tp, cp);
1120				errors++;
1121			} else
1122				lp->d_cylskew = v;
1123			continue;
1124		}
1125		if (streq(cp, "headswitch")) {
1126			v = atoi(tp);
1127			if (v < 0) {
1128				fprintf(stderr, "line %d: %s: bad %s\n",
1129				    lineno, tp, cp);
1130				errors++;
1131			} else
1132				lp->d_headswitch = v;
1133			continue;
1134		}
1135		if (streq(cp, "track-to-track seek")) {
1136			v = atoi(tp);
1137			if (v < 0) {
1138				fprintf(stderr, "line %d: %s: bad %s\n",
1139				    lineno, tp, cp);
1140				errors++;
1141			} else
1142				lp->d_trkseek = v;
1143			continue;
1144		}
1145		/* the ':' was removed above */
1146		if (*cp < 'a' || *cp > MAX_PART || cp[1] != '\0') {
1147			fprintf(stderr,
1148			    "line %d: %s: Unknown disklabel field\n", lineno,
1149			    cp);
1150			errors++;
1151			continue;
1152		}
1153
1154		/* Process a partition specification line. */
1155		part = *cp - 'a';
1156		if (part >= lp->d_npartitions) {
1157			fprintf(stderr,
1158			    "line %d: partition name out of range a-%c: %s\n",
1159			    lineno, 'a' + lp->d_npartitions - 1, cp);
1160			errors++;
1161			continue;
1162		}
1163		part_set[part] = 1;
1164
1165		if (getasciipartspec(tp, lp, part, lineno) != 0) {
1166			errors++;
1167			break;
1168		}
1169	}
1170	errors += checklabel(lp);
1171	return (errors == 0);
1172}
1173
1174#define NXTNUM(n) do { \
1175	if (tp == NULL) { \
1176		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1177		return (1); \
1178	} else { \
1179		cp = tp, tp = word(cp); \
1180		(n) = atoi(cp); \
1181	} \
1182} while (0)
1183
1184/* retain 1 character following number */
1185#define NXTWORD(w,n) do { \
1186	if (tp == NULL) { \
1187		fprintf(stderr, "line %d: too few numeric fields\n", lineno); \
1188		return (1); \
1189	} else { \
1190	        char *tmp; \
1191		cp = tp, tp = word(cp); \
1192	        (n) = strtol(cp,&tmp,10); \
1193		if (tmp) (w) = *tmp; \
1194	} \
1195} while (0)
1196
1197/*
1198 * Read a partition line into partition `part' in the specified disklabel.
1199 * Return 0 on success, 1 on failure.
1200 */
1201int
1202getasciipartspec(char *tp, struct disklabel *lp, int part, int lineno)
1203{
1204	struct partition *pp;
1205	char *cp;
1206	const char **cpp;
1207	int v;
1208
1209	pp = &lp->d_partitions[part];
1210	cp = NULL;
1211
1212	v = 0;
1213	NXTWORD(part_size_type[part],v);
1214	if (v < 0 || (v == 0 && part_size_type[part] != '*')) {
1215		fprintf(stderr, "line %d: %s: bad partition size\n", lineno,
1216		    cp);
1217		return (1);
1218	}
1219	pp->p_size = v;
1220
1221	v = 0;
1222	NXTWORD(part_offset_type[part],v);
1223	if (v < 0 || (v == 0 && part_offset_type[part] != '*' &&
1224	    part_offset_type[part] != '\0')) {
1225		fprintf(stderr, "line %d: %s: bad partition offset\n", lineno,
1226		    cp);
1227		return (1);
1228	}
1229	pp->p_offset = v;
1230	cp = tp, tp = word(cp);
1231	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++)
1232		if (*cpp && streq(*cpp, cp))
1233			break;
1234	if (*cpp != NULL) {
1235		pp->p_fstype = cpp - fstypenames;
1236	} else {
1237		if (isdigit(*cp))
1238			v = atoi(cp);
1239		else
1240			v = FSMAXTYPES;
1241		if ((unsigned)v >= FSMAXTYPES) {
1242			fprintf(stderr,
1243			    "line %d: Warning, unknown filesystem type %s\n",
1244			    lineno, cp);
1245			v = FS_UNUSED;
1246		}
1247		pp->p_fstype = v;
1248	}
1249
1250	switch (pp->p_fstype) {
1251	case FS_UNUSED:
1252		/*
1253		 * allow us to accept defaults for
1254		 * fsize/frag/cpg
1255		 */
1256		if (tp) {
1257			NXTNUM(pp->p_fsize);
1258			if (pp->p_fsize == 0)
1259				break;
1260			NXTNUM(v);
1261			pp->p_frag = v / pp->p_fsize;
1262		}
1263		/* else default to 0's */
1264		break;
1265
1266	/* These happen to be the same */
1267	case FS_BSDFFS:
1268	case FS_BSDLFS:
1269		if (tp) {
1270			NXTNUM(pp->p_fsize);
1271			if (pp->p_fsize == 0)
1272				break;
1273			NXTNUM(v);
1274			pp->p_frag = v / pp->p_fsize;
1275			NXTNUM(pp->p_cpg);
1276		} else {
1277			/*
1278			 * FIX! poor attempt at adaptive
1279			 */
1280			/* 1 GB */
1281			if (pp->p_size < 1024*1024*1024 / lp->d_secsize) {
1282				/*
1283				 * FIX! These are too low, but are traditional
1284				 */
1285				pp->p_fsize = DEFAULT_NEWFS_FRAG;
1286				pp->p_frag = DEFAULT_NEWFS_BLOCK /
1287				    DEFAULT_NEWFS_FRAG;
1288				pp->p_cpg = DEFAULT_NEWFS_CPG;
1289			} else {
1290				pp->p_fsize = BIG_NEWFS_FRAG;
1291				pp->p_frag = BIG_NEWFS_BLOCK /
1292				    BIG_NEWFS_FRAG;
1293				pp->p_cpg = BIG_NEWFS_CPG;
1294			}
1295		}
1296	default:
1297		break;
1298	}
1299	return (0);
1300}
1301
1302/*
1303 * Check disklabel for errors and fill in
1304 * derived fields according to supplied values.
1305 */
1306int
1307checklabel(struct disklabel *lp)
1308{
1309	struct partition *pp;
1310	int i, errors = 0;
1311	char part;
1312	unsigned long total_size, total_percent, current_offset;
1313	int seen_default_offset;
1314	int hog_part;
1315	int j;
1316	struct partition *pp2;
1317
1318	if (lp->d_secsize == 0) {
1319		fprintf(stderr, "sector size 0\n");
1320		return (1);
1321	}
1322	if (lp->d_nsectors == 0) {
1323		fprintf(stderr, "sectors/track 0\n");
1324		return (1);
1325	}
1326	if (lp->d_ntracks == 0) {
1327		fprintf(stderr, "tracks/cylinder 0\n");
1328		return (1);
1329	}
1330	if  (lp->d_ncylinders == 0) {
1331		fprintf(stderr, "cylinders/unit 0\n");
1332		errors++;
1333	}
1334	if (lp->d_rpm == 0)
1335		Warning("revolutions/minute 0");
1336	if (lp->d_secpercyl == 0)
1337		lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
1338	if (lp->d_secperunit == 0)
1339		lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
1340	if (lp->d_bbsize == 0) {
1341		fprintf(stderr, "boot block size 0\n");
1342		errors++;
1343	} else if (lp->d_bbsize % lp->d_secsize)
1344		Warning("boot block size %% sector-size != 0");
1345	if (lp->d_npartitions > MAXPARTITIONS)
1346		Warning("number of partitions (%lu) > MAXPARTITIONS (%d)",
1347		    (u_long)lp->d_npartitions, MAXPARTITIONS);
1348
1349	/* first allocate space to the partitions, then offsets */
1350	total_size = 0; /* in sectors */
1351	total_percent = 0; /* in percent */
1352	hog_part = -1;
1353	/* find all fixed partitions */
1354	for (i = 0; i < lp->d_npartitions; i++) {
1355		pp = &lp->d_partitions[i];
1356		if (part_set[i]) {
1357			if (part_size_type[i] == '*') {
1358				if (i == RAW_PART) {
1359					pp->p_size = lp->d_secperunit;
1360				} else {
1361					if (hog_part != -1)
1362						Warning("Too many '*' partitions (%c and %c)",
1363						    hog_part + 'a',i + 'a');
1364					else
1365						hog_part = i;
1366				}
1367			} else {
1368				off_t size;
1369
1370				size = pp->p_size;
1371				switch (part_size_type[i]) {
1372				case '%':
1373					total_percent += size;
1374					break;
1375				case 'k':
1376				case 'K':
1377					size *= 1024ULL;
1378					break;
1379				case 'm':
1380				case 'M':
1381					size *= 1024ULL * 1024ULL;
1382					break;
1383				case 'g':
1384				case 'G':
1385					size *= 1024ULL * 1024ULL * 1024ULL;
1386					break;
1387				case '\0':
1388					break;
1389				default:
1390					Warning("unknown size specifier '%c' (K/M/G are valid)",part_size_type[i]);
1391					break;
1392				}
1393				/* don't count %'s yet */
1394				if (part_size_type[i] != '%') {
1395					/*
1396					 * for all not in sectors, convert to
1397					 * sectors
1398					 */
1399					if (part_size_type[i] != '\0') {
1400						if (size % lp->d_secsize != 0)
1401							Warning("partition %c not an integer number of sectors",
1402							    i + 'a');
1403						size /= lp->d_secsize;
1404						pp->p_size = size;
1405					}
1406					/* else already in sectors */
1407					if (i != RAW_PART)
1408						total_size += size;
1409				}
1410			}
1411		}
1412	}
1413	/* handle % partitions - note %'s don't need to add up to 100! */
1414	if (total_percent != 0) {
1415		long free_space = lp->d_secperunit - total_size;
1416		if (total_percent > 100) {
1417			fprintf(stderr,"total percentage %lu is greater than 100\n",
1418			    total_percent);
1419			errors++;
1420		}
1421
1422		if (free_space > 0) {
1423			for (i = 0; i < lp->d_npartitions; i++) {
1424				pp = &lp->d_partitions[i];
1425				if (part_set[i] && part_size_type[i] == '%') {
1426					/* careful of overflows! and integer roundoff */
1427					pp->p_size = ((double)pp->p_size/100) * free_space;
1428					total_size += pp->p_size;
1429
1430					/* FIX we can lose a sector or so due to roundoff per
1431					   partition.  A more complex algorithm could avoid that */
1432				}
1433			}
1434		} else {
1435			fprintf(stderr,
1436			    "%ld sectors available to give to '*' and '%%' partitions\n",
1437			    free_space);
1438			errors++;
1439			/* fix?  set all % partitions to size 0? */
1440		}
1441	}
1442	/* give anything remaining to the hog partition */
1443	if (hog_part != -1) {
1444		lp->d_partitions[hog_part].p_size = lp->d_secperunit - total_size;
1445		total_size = lp->d_secperunit;
1446	}
1447
1448	/* Now set the offsets for each partition */
1449	current_offset = 0; /* in sectors */
1450	seen_default_offset = 0;
1451	for (i = 0; i < lp->d_npartitions; i++) {
1452		part = 'a' + i;
1453		pp = &lp->d_partitions[i];
1454		if (part_set[i]) {
1455			if (part_offset_type[i] == '*') {
1456				if (i == RAW_PART) {
1457					pp->p_offset = 0;
1458				} else {
1459					pp->p_offset = current_offset;
1460					seen_default_offset = 1;
1461				}
1462			} else {
1463				/* allow them to be out of order for old-style tables */
1464				if (pp->p_offset < current_offset &&
1465				    seen_default_offset && i != RAW_PART) {
1466					fprintf(stderr,
1467"Offset %ld for partition %c overlaps previous partition which ends at %lu\n",
1468					    (long)pp->p_offset,i+'a',current_offset);
1469					fprintf(stderr,
1470"Labels with any *'s for offset must be in ascending order by sector\n");
1471					errors++;
1472				} else if (pp->p_offset != current_offset &&
1473				    i != RAW_PART && seen_default_offset) {
1474					/*
1475					 * this may give unneeded warnings if
1476					 * partitions are out-of-order
1477					 */
1478					Warning(
1479"Offset %ld for partition %c doesn't match expected value %ld",
1480					    (long)pp->p_offset, i + 'a', current_offset);
1481				}
1482			}
1483			if (i != RAW_PART)
1484				current_offset = pp->p_offset + pp->p_size;
1485		}
1486	}
1487
1488	for (i = 0; i < lp->d_npartitions; i++) {
1489		part = 'a' + i;
1490		pp = &lp->d_partitions[i];
1491		if (pp->p_size == 0 && pp->p_offset != 0)
1492			Warning("partition %c: size 0, but offset %lu",
1493			    part, (u_long)pp->p_offset);
1494#ifdef __sparc64__
1495		/* See comment in writelabel(). */
1496		if (pp->p_offset % lp->d_secpercyl != 0) {
1497			fprintf(stderr, "partition %c: does not start on a "
1498			    "cylinder boundary!\n", part);
1499			errors++;
1500		}
1501#endif
1502#ifdef notdef
1503		if (pp->p_size % lp->d_secpercyl)
1504			Warning("partition %c: size %% cylinder-size != 0",
1505			    part);
1506		if (pp->p_offset % lp->d_secpercyl)
1507			Warning("partition %c: offset %% cylinder-size != 0",
1508			    part);
1509#endif
1510		if (pp->p_offset > lp->d_secperunit) {
1511			fprintf(stderr,
1512			    "partition %c: offset past end of unit\n", part);
1513			errors++;
1514		}
1515		if (pp->p_offset + pp->p_size > lp->d_secperunit) {
1516			fprintf(stderr,
1517			"partition %c: partition extends past end of unit\n",
1518			    part);
1519			errors++;
1520		}
1521		if (i == RAW_PART)
1522		{
1523			if (pp->p_fstype != FS_UNUSED)
1524				Warning("partition %c is not marked as unused!",part);
1525			if (pp->p_offset != 0)
1526				Warning("partition %c doesn't start at 0!",part);
1527			if (pp->p_size != lp->d_secperunit)
1528				Warning("partition %c doesn't cover the whole unit!",part);
1529
1530			if ((pp->p_fstype != FS_UNUSED) || (pp->p_offset != 0) ||
1531			    (pp->p_size != lp->d_secperunit)) {
1532				Warning("An incorrect partition %c may cause problems for "
1533				    "standard system utilities",part);
1534			}
1535		}
1536
1537		/* check for overlaps */
1538		/* this will check for all possible overlaps once and only once */
1539		for (j = 0; j < i; j++) {
1540			if (j != RAW_PART && i != RAW_PART &&
1541			    part_set[i] && part_set[j]) {
1542				pp2 = &lp->d_partitions[j];
1543				if (pp2->p_offset < pp->p_offset + pp->p_size &&
1544				    (pp2->p_offset + pp2->p_size > pp->p_offset ||
1545					pp2->p_offset >= pp->p_offset)) {
1546					fprintf(stderr,"partitions %c and %c overlap!\n",
1547					    j + 'a', i + 'a');
1548					errors++;
1549				}
1550			}
1551		}
1552	}
1553	for (; i < MAXPARTITIONS; i++) {
1554		part = 'a' + i;
1555		pp = &lp->d_partitions[i];
1556		if (pp->p_size || pp->p_offset)
1557			Warning("unused partition %c: size %d offset %lu",
1558			    'a' + i, pp->p_size, (u_long)pp->p_offset);
1559	}
1560	return (errors);
1561}
1562
1563/*
1564 * When operating on a "virgin" disk, try getting an initial label
1565 * from the associated device driver.  This might work for all device
1566 * drivers that are able to fetch some initial device parameters
1567 * without even having access to a (BSD) disklabel, like SCSI disks,
1568 * most IDE drives, or vn devices.
1569 *
1570 * The device name must be given in its "canonical" form.
1571 */
1572struct disklabel *
1573getvirginlabel(void)
1574{
1575	static struct disklabel loclab;
1576	char lnamebuf[BBSIZE];
1577	int f;
1578
1579	if (dkname[0] == '/') {
1580		warnx("\"auto\" requires the usage of a canonical disk name");
1581		return (NULL);
1582	}
1583	(void)snprintf(lnamebuf, BBSIZE, "%s%s", _PATH_DEV, dkname);
1584	if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1585		warn("cannot open %s", lnamebuf);
1586		return (NULL);
1587	}
1588
1589	/*
1590	 * Try to use the new get-virgin-label ioctl.  If it fails,
1591	 * fallback to the old get-disdk-info ioctl.
1592	 */
1593	if (ioctl(f, DIOCGDVIRGIN, &loclab) == 0)
1594		goto out;
1595	if (ioctl(f, DIOCGDINFO, &loclab) == 0)
1596		goto out;
1597	close(f);
1598	(void)snprintf(lnamebuf, BBSIZE, "%s%s%c", _PATH_DEV, dkname,
1599	    'a' + RAW_PART);
1600	if ((f = open(lnamebuf, O_RDONLY)) == -1) {
1601		warn("cannot open %s", lnamebuf);
1602		return (NULL);
1603	}
1604	if (ioctl(f, DIOCGDINFO, &loclab) == 0)
1605		goto out;
1606	close(f);
1607	warn("No virgin disklabel found %s", lnamebuf);
1608	return (NULL);
1609    out:
1610	close(f);
1611	return (&loclab);
1612}
1613
1614/*
1615 * If we are installing a boot program that doesn't fit in d_bbsize
1616 * we need to mark those partitions that the boot overflows into.
1617 * This allows newfs to prevent creation of a filesystem where it might
1618 * clobber bootstrap code.
1619 */
1620void
1621setbootflag(struct disklabel *lp)
1622{
1623	struct partition *pp;
1624	int i, errors = 0;
1625	char part;
1626	u_long boffset;
1627
1628	if (bootbuf == 0)
1629		return;
1630	boffset = bootsize / lp->d_secsize;
1631	for (i = 0; i < lp->d_npartitions; i++) {
1632		part = 'a' + i;
1633		pp = &lp->d_partitions[i];
1634		if (pp->p_size == 0)
1635			continue;
1636		if (boffset <= pp->p_offset) {
1637			if (pp->p_fstype == FS_BOOT)
1638				pp->p_fstype = FS_UNUSED;
1639		} else if (pp->p_fstype != FS_BOOT) {
1640			if (pp->p_fstype != FS_UNUSED) {
1641				fprintf(stderr,
1642					"boot overlaps used partition %c\n",
1643					part);
1644				errors++;
1645			} else {
1646				pp->p_fstype = FS_BOOT;
1647				Warning("boot overlaps partition %c, %s",
1648					part, "marked as FS_BOOT");
1649			}
1650		}
1651	}
1652	if (errors)
1653		errx(4, "cannot install boot program");
1654}
1655
1656/*VARARGS1*/
1657void
1658Warning(const char *fmt, ...)
1659{
1660	va_list ap;
1661
1662	fprintf(stderr, "Warning, ");
1663	va_start(ap, fmt);
1664	vfprintf(stderr, fmt, ap);
1665	fprintf(stderr, "\n");
1666	va_end(ap);
1667}
1668
1669void
1670usage(void)
1671{
1672#if NUMBOOT > 0
1673	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1674		"usage: disklabel [-r] disk",
1675		"\t\t(to read label)",
1676		"       disklabel -w [-r] [-n] disk type [ packid ]",
1677		"\t\t(to write label with existing boot program)",
1678		"       disklabel -e [-r] [-n] disk",
1679		"\t\t(to edit label)",
1680		"       disklabel -R [-r] [-n] disk protofile",
1681		"\t\t(to restore label with existing boot program)",
1682#if NUMBOOT > 1
1683		"       disklabel -B [-n] [ -b boot1 [ -s boot2 ] ] disk [ type ]",
1684		"\t\t(to install boot program with existing label)",
1685		"       disklabel -w -B [-n] [ -b boot1 [ -s boot2 ] ] disk type [ packid ]",
1686		"\t\t(to write label and boot program)",
1687		"       disklabel -R -B [-n] [ -b boot1 [ -s boot2 ] ] disk protofile [ type ]",
1688		"\t\t(to restore label and boot program)",
1689#else
1690		"       disklabel -B [-n] [ -b bootprog ] disk [ type ]",
1691		"\t\t(to install boot program with existing on-disk label)",
1692		"       disklabel -w -B [-n] [ -b bootprog ] disk type [ packid ]",
1693		"\t\t(to write label and install boot program)",
1694		"       disklabel -R -B [-n] [ -b bootprog ] disk protofile [ type ]",
1695		"\t\t(to restore label and install boot program)",
1696#endif
1697		"       disklabel [-NW] disk",
1698		"\t\t(to write disable/enable label)");
1699#else
1700	fprintf(stderr, "%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n%s\n",
1701		"usage: disklabel [-r] disk", "(to read label)",
1702		"       disklabel -w [-r] [-n] disk type [ packid ]",
1703		"\t\t(to write label)",
1704		"       disklabel -e [-r] [-n] disk",
1705		"\t\t(to edit label)",
1706		"       disklabel -R [-r] [-n] disk protofile",
1707		"\t\t(to restore label)",
1708		"       disklabel [-NW] disk",
1709		"\t\t(to write disable/enable label)");
1710#endif
1711	exit(1);
1712}
1713