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