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