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