xref: /dragonfly/sbin/disklabel64/disklabel64.c (revision 33311965)
1 /*
2  * Copyright (c) 2007 The DragonFly Project.  All rights reserved.
3  *
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
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
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 /*
35  * Copyright (c) 1987, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Symmetric Computer Systems.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  * @(#)disklabel.c	1.2 (Symmetric) 11/28/85
66  * @(#)disklabel.c      8.2 (Berkeley) 1/7/94
67  * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $
68  */
69 
70 #include <sys/param.h>
71 #include <sys/file.h>
72 #include <sys/stat.h>
73 #include <sys/wait.h>
74 #define DKTYPENAMES
75 #include <sys/disklabel64.h>
76 #include <sys/diskslice.h>
77 #include <sys/diskmbr.h>
78 #include <sys/dtype.h>
79 #include <sys/sysctl.h>
80 #include <disktab.h>
81 #include <fstab.h>
82 
83 #include <vfs/ufs/dinode.h>
84 #include <vfs/ufs/fs.h>
85 
86 #include <unistd.h>
87 #include <string.h>
88 #include <stdio.h>
89 #include <stdlib.h>
90 #include <signal.h>
91 #include <stdarg.h>
92 #include <stddef.h>
93 #include <ctype.h>
94 #include <err.h>
95 #include <errno.h>
96 #include <uuid.h>
97 #include "pathnames.h"
98 
99 extern uint32_t crc32(const void *buf, size_t size);
100 
101 /*
102  * Disklabel64: read and write 64 bit disklabels.
103  * The label is usually placed on one of the first sectors of the disk.
104  * Many machines also place a bootstrap in the same area,
105  * in which case the label is embedded in the bootstrap.
106  * The bootstrap source must leave space at the proper offset
107  * for the label on such machines.
108  */
109 
110 #define LABELSIZE	((sizeof(struct disklabel64) + 4095) & ~4095)
111 #define BOOTSIZE	32768
112 
113 /* FIX!  These are too low, but are traditional */
114 #define DEFAULT_NEWFS_BLOCK  8192U
115 #define DEFAULT_NEWFS_FRAG   1024U
116 #define DEFAULT_NEWFS_CPG    16U
117 
118 #define BIG_NEWFS_BLOCK  16384U
119 #define BIG_NEWFS_FRAG   2048U
120 #define BIG_NEWFS_CPG    64U
121 
122 void	makelabel(const char *, const char *, struct disklabel64 *);
123 int	writelabel(int, struct disklabel64 *);
124 void	l_perror(const char *);
125 struct disklabel64 *readlabel(int);
126 struct disklabel64 *makebootarea(int);
127 void	display(FILE *, const struct disklabel64 *);
128 int	edit(struct disklabel64 *, int);
129 int	editit(void);
130 char	*skip(char *);
131 char	*word(char *);
132 int	getasciilabel(FILE *, struct disklabel64 *);
133 int	getasciipartspec(char *, struct disklabel64 *, int, int, uint32_t);
134 int	getasciipartuuid(char *, struct disklabel64 *, int, int, uint32_t);
135 int	checklabel(struct disklabel64 *);
136 void	Warning(const char *, ...) __printflike(1, 2);
137 void	usage(void);
138 struct disklabel64 *getvirginlabel(void);
139 
140 #define	DEFEDITOR	_PATH_VI
141 #define	streq(a,b)	(strcmp(a,b) == 0)
142 
143 char	*dkname;
144 char	*specname;
145 char	tmpfil[] = PATH_TMPFILE;
146 
147 struct	disklabel64 lab;
148 
149 #define MAX_PART ('z')
150 #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
151 char    part_size_type[MAX_NUM_PARTS];
152 char    part_offset_type[MAX_NUM_PARTS];
153 int     part_set[MAX_NUM_PARTS];
154 
155 int	installboot;	/* non-zero if we should install a boot program */
156 int	boot1size;
157 int	boot1lsize;
158 int	boot2size;
159 char	*boot1buf;
160 char	*boot2buf;
161 char	*boot1path;
162 char	*boot2path;
163 
164 enum	{
165 	UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT
166 } op = UNSPEC;
167 
168 int	rflag;
169 int	Vflag;
170 int	disable_write;   /* set to disable writing to disk label */
171 u_int32_t slice_start_lba;
172 
173 #ifdef DEBUG
174 int	debug;
175 #define OPTIONS	"BNRWb:denrs:Vw"
176 #else
177 #define OPTIONS	"BNRWb:enrs:Vw"
178 #endif
179 
180 int
181 main(int argc, char *argv[])
182 {
183 	struct disklabel64 *lp;
184 	FILE *t;
185 	int ch, f = 0, flag, error = 0;
186 	char *name = NULL;
187 
188 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
189 		switch (ch) {
190 			case 'B':
191 				++installboot;
192 				break;
193 			case 'b':
194 				boot1path = optarg;
195 				break;
196 
197 			case 's':
198 				boot2path = optarg;
199 				break;
200 			case 'N':
201 				if (op != UNSPEC)
202 					usage();
203 				op = NOWRITE;
204 				break;
205 			case 'n':
206 				disable_write = 1;
207 				break;
208 			case 'R':
209 				if (op != UNSPEC)
210 					usage();
211 				op = RESTORE;
212 				break;
213 			case 'W':
214 				if (op != UNSPEC)
215 					usage();
216 				op = WRITEABLE;
217 				break;
218 			case 'e':
219 				if (op != UNSPEC)
220 					usage();
221 				op = EDIT;
222 				break;
223 			case 'V':
224 				++Vflag;
225 				break;
226 			case 'r':
227 				++rflag;
228 				break;
229 			case 'w':
230 				if (op != UNSPEC)
231 					usage();
232 				op = WRITE;
233 				break;
234 #ifdef DEBUG
235 			case 'd':
236 				debug++;
237 				break;
238 #endif
239 			case '?':
240 			default:
241 				usage();
242 		}
243 	argc -= optind;
244 	argv += optind;
245 	if (installboot) {
246 		rflag++;
247 		if (op == UNSPEC)
248 			op = WRITEBOOT;
249 	} else {
250 		if (op == UNSPEC)
251 			op = READ;
252 		boot1path = NULL;
253 		boot2path = NULL;
254 	}
255 	if (argc < 1)
256 		usage();
257 
258 	dkname = getdevpath(argv[0], 0);
259 	specname = dkname;
260 	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
261 	if (f < 0)
262 		err(4, "%s", specname);
263 
264 	switch(op) {
265 
266 	case UNSPEC:
267 		break;
268 
269 	case EDIT:
270 		if (argc != 1)
271 			usage();
272 		lp = readlabel(f);
273 		error = edit(lp, f);
274 		break;
275 
276 	case NOWRITE:
277 		flag = 0;
278 		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
279 			err(4, "ioctl DIOCWLABEL");
280 		break;
281 
282 	case READ:
283 		if (argc != 1)
284 			usage();
285 		lp = readlabel(f);
286 		display(stdout, lp);
287 		error = checklabel(lp);
288 		break;
289 
290 	case RESTORE:
291 		if (installboot && argc == 3) {
292 			makelabel(argv[2], 0, &lab);
293 			argc--;
294 
295 			/*
296 			 * We only called makelabel() for its side effect
297 			 * of setting the bootstrap file names.  Discard
298 			 * all changes to `lab' so that all values in the
299 			 * final label come from the ASCII label.
300 			 */
301 			bzero((char *)&lab, sizeof(lab));
302 		}
303 		if (argc != 2)
304 			usage();
305 		if (!(t = fopen(argv[1], "r")))
306 			err(4, "%s", argv[1]);
307 		if (!getasciilabel(t, &lab))
308 			exit(1);
309 		lp = makebootarea(f);
310 		bcopy(&lab.d_magic, &lp->d_magic,
311 		      sizeof(lab) - offsetof(struct disklabel64, d_magic));
312 		error = writelabel(f, lp);
313 		break;
314 
315 	case WRITE:
316 		if (argc == 3) {
317 			name = argv[2];
318 			argc--;
319 		}
320 		if (argc != 2)
321 			usage();
322 		makelabel(argv[1], name, &lab);
323 		lp = makebootarea(f);
324 		bcopy(&lab.d_magic, &lp->d_magic,
325 		      sizeof(lab) - offsetof(struct disklabel64, d_magic));
326 		if (checklabel(lp) == 0)
327 			error = writelabel(f, lp);
328 		break;
329 
330 	case WRITEABLE:
331 		flag = 1;
332 		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
333 			err(4, "ioctl DIOCWLABEL");
334 		break;
335 
336 	case WRITEBOOT:
337 	{
338 		struct disklabel64 tlab;
339 
340 		lp = readlabel(f);
341 		tlab = *lp;
342 		if (argc == 2)
343 			makelabel(argv[1], 0, &lab);
344 		lp = makebootarea(f);
345 		bcopy(&tlab.d_magic, &lp->d_magic,
346 		      sizeof(tlab) - offsetof(struct disklabel64, d_magic));
347 		if (checklabel(lp) == 0)
348 			error = writelabel(f, lp);
349 		break;
350 	}
351 	}
352 	exit(error);
353 }
354 
355 /*
356  * Construct a prototype disklabel from /etc/disktab.  As a side
357  * effect, set the names of the primary and secondary boot files
358  * if specified.
359  */
360 void
361 makelabel(const char *type, const char *name, struct disklabel64 *lp)
362 {
363 	struct disklabel64 *dp;
364 
365 	if (strcmp(type, "auto") == 0)
366 		dp = getvirginlabel();
367 	else
368 		dp = NULL;
369 	if (dp == NULL)
370 		errx(1, "%s: unknown disk type", type);
371 	*lp = *dp;
372 
373 	/*
374 	 * NOTE: boot control files may no longer be specified in disktab.
375 	 */
376 	if (name)
377 		strncpy(lp->d_packname, name, sizeof(lp->d_packname));
378 }
379 
380 int
381 writelabel(int f, struct disklabel64 *lp)
382 {
383 	struct disklabel64 *blp;
384 	int flag;
385 	int r;
386 	size_t lpsize;
387 	size_t lpcrcsize;
388 
389 	lpsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
390 	lpcrcsize = lpsize - offsetof(struct disklabel64, d_magic);
391 
392 	if (disable_write) {
393 		Warning("write to disk label suppressed - label was as follows:");
394 		display(stdout, lp);
395 		return (0);
396 	} else {
397 		lp->d_magic = DISKMAGIC64;
398 		lp->d_crc = 0;
399 		lp->d_crc = crc32(&lp->d_magic, lpcrcsize);
400 		if (rflag) {
401 			/*
402 			 * Make sure the boot area is not too large
403 			 */
404 			if (boot2buf) {
405 				int lpbsize = (int)(lp->d_pbase - lp->d_bbase);
406 				if (lp->d_pbase == 0) {
407 					errx(1, "no space was set aside in "
408 						"the disklabel for boot2!");
409 				}
410 				if (boot2size > lpbsize) {
411 					errx(1, "label did not reserve enough "
412 						"space for boot!  %d/%d",
413 					     boot2size, lpbsize);
414 				}
415 			}
416 
417 			/*
418 			 * First set the kernel disk label,
419 			 * then write a label to the raw disk.
420 			 * If the SDINFO ioctl fails because it is
421 			 * unimplemented, keep going; otherwise, the kernel
422 			 * consistency checks may prevent us from changing
423 			 * the current (in-core) label.
424 			 */
425 			if (ioctl(f, DIOCSDINFO64, lp) < 0 &&
426 				errno != ENODEV && errno != ENOTTY) {
427 				l_perror("ioctl DIOCSDINFO");
428 				return (1);
429 			}
430 			lseek(f, (off_t)0, SEEK_SET);
431 
432 			/*
433 			 * The disklabel embeds areas which we may not
434 			 * have wanted to change.  Merge those areas in
435 			 * from disk.
436 			 */
437 			blp = makebootarea(f);
438 			if (blp != lp) {
439 				bcopy(&lp->d_magic, &blp->d_magic,
440 				      sizeof(*lp) -
441 				      offsetof(struct disklabel64, d_magic));
442 			}
443 
444 			/*
445 			 * write enable label sector before write
446 			 * (if necessary), disable after writing.
447 			 */
448 			flag = 1;
449 			if (ioctl(f, DIOCWLABEL, &flag) < 0)
450 				warn("ioctl DIOCWLABEL");
451 
452 			r = write(f, boot1buf, boot1lsize);
453 			if (r != (ssize_t)boot1lsize) {
454 				warn("write");
455 				return (1);
456 			}
457 			/*
458 			 * Output the remainder of the disklabel
459 			 */
460 			if (boot2buf) {
461 				lseek(f, lp->d_bbase, 0);
462 				r = write(f, boot2buf, boot2size);
463 				if (r != boot2size) {
464 					warn("write");
465 					return(1);
466 				}
467 			}
468 			flag = 0;
469 			ioctl(f, DIOCWLABEL, &flag);
470 		} else if (ioctl(f, DIOCWDINFO64, lp) < 0) {
471 			l_perror("ioctl DIOCWDINFO64");
472 			return (1);
473 		}
474 	}
475 	return (0);
476 }
477 
478 void
479 l_perror(const char *s)
480 {
481 	switch (errno) {
482 
483 	case ESRCH:
484 		warnx("%s: no disk label on disk;", s);
485 		fprintf(stderr, "add \"-r\" to install initial label\n");
486 		break;
487 
488 	case EINVAL:
489 		warnx("%s: label magic number or checksum is wrong!", s);
490 		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
491 		break;
492 
493 	case EBUSY:
494 		warnx("%s: open partition would move or shrink", s);
495 		break;
496 
497 	case ENOATTR:
498 		warnx("%s: the disk already has a label of a different type,\n"
499 		      "probably a 32 bit disklabel.  It must be cleaned out "
500 		      "first.\n", s);
501 		break;
502 
503 	default:
504 		warn(NULL);
505 		break;
506 	}
507 }
508 
509 /*
510  * Fetch disklabel for disk.
511  * Use ioctl to get label unless -r flag is given.
512  */
513 struct disklabel64 *
514 readlabel(int f)
515 {
516 	struct disklabel64 *lp;
517 	u_int32_t savecrc;
518 	size_t lpcrcsize;
519 
520 	if (rflag) {
521 		/*
522 		 * Allocate space for the label.  The boot1 code, if any,
523 		 * is embedded in the label.  The label overlaps the boot1
524 		 * code.
525 		 */
526 		lp = makebootarea(f);
527 		lpcrcsize = offsetof(struct disklabel64,
528 				     d_partitions[lp->d_npartitions]) -
529 			    offsetof(struct disklabel64, d_magic);
530 		savecrc = lp->d_crc;
531 		lp->d_crc = 0;
532 		if (lp->d_magic != DISKMAGIC64)
533 			errx(1, "bad pack magic number");
534 		if (lp->d_npartitions > MAXPARTITIONS64 ||
535 		    savecrc != crc32(&lp->d_magic, lpcrcsize)
536 		) {
537 			errx(1, "corrupted disklabel64");
538 		}
539 		lp->d_crc = savecrc;
540 	} else {
541 		/*
542 		 * Just use a static structure to hold the label.  Note
543 		 * that DIOCSDINFO64 does not overwrite the boot1 area
544 		 * even though it is part of the disklabel64 structure.
545 		 */
546 		lp = &lab;
547 		if (Vflag) {
548 			if (ioctl(f, DIOCGDVIRGIN64, lp) < 0) {
549 				l_perror("ioctl DIOCGDVIRGIN64");
550 				exit(4);
551 			}
552 		} else {
553 			if (ioctl(f, DIOCGDINFO64, lp) < 0) {
554 				l_perror("ioctl DIOCGDINFO64");
555 				exit(4);
556 			}
557 		}
558 	}
559 	return (lp);
560 }
561 
562 /*
563  * Construct a boot area for boot1 and boot2 and return the location of
564  * the label within the area.  The caller will overwrite the label so
565  * we don't actually have to read it.
566  */
567 struct disklabel64 *
568 makebootarea(int f)
569 {
570 	struct disklabel64 *lp;
571 	struct partinfo info;
572 	u_int32_t secsize;
573 	struct stat st;
574 	int fd;
575 	int r;
576 
577 	if (ioctl(f, DIOCGPART, &info) == 0)
578 		secsize = info.media_blksize;
579 	else
580 		secsize = 512;
581 
582 	if (boot1buf == NULL) {
583 		size_t rsize;
584 
585 		rsize = (sizeof(struct disklabel64) + secsize - 1) &
586 			~(secsize - 1);
587 		boot1size = offsetof(struct disklabel64, d_magic);
588 		boot1lsize = rsize;
589 		boot1buf = malloc(rsize);
590 		bzero(boot1buf, rsize);
591 		r = read(f, boot1buf, rsize);
592 		if (r != (int)rsize)
593 			err(4, "%s", specname);
594 	}
595 	lp = (void *)boot1buf;
596 
597 	if (installboot == 0)
598 		return(lp);
599 
600 	if (boot2buf == NULL) {
601 		boot2size = 32768;
602 		boot2buf = malloc(boot2size);
603 		bzero(boot2buf, boot2size);
604 	}
605 
606 	/*
607 	 * If installing the boot code, read it into the appropriate portions
608 	 * of the buffer(s)
609 	 */
610 	if (boot1path == NULL)
611 		asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR);
612 	if (boot2path == NULL)
613 		asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR);
614 
615 	if ((fd = open(boot1path, O_RDONLY)) < 0)
616 		err(4, "%s", boot1path);
617 	if (fstat(fd, &st) < 0)
618 		err(4, "%s", boot1path);
619 	if (st.st_size > boot1size)
620 		err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
621 	if (read(fd, boot1buf, boot1size) != boot1size)
622 		err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
623 	close(fd);
624 
625 	if ((fd = open(boot2path, O_RDONLY)) < 0)
626 		err(4, "%s", boot2path);
627 	if (fstat(fd, &st) < 0)
628 		err(4, "%s", boot2path);
629 	if (st.st_size > boot2size)
630 		err(4, "%s must be <= %d bytes!", boot2path, boot2size);
631 	if ((r = read(fd, boot2buf, boot2size)) < 1)
632 		err(4, "%s is empty!", boot2path);
633 	boot2size = (r + secsize - 1) & ~(secsize - 1);
634 	close(fd);
635 
636 	/*
637 	 * XXX dangerously dedicated support goes here XXX
638 	 */
639 	return (lp);
640 }
641 
642 void
643 display(FILE *f, const struct disklabel64 *lp)
644 {
645 	const struct partition64 *pp;
646 	char *str;
647 	unsigned int part;
648 	int didany;
649 	uint32_t blksize;
650 
651 	/*
652 	 * Use a human readable block size if possible.  This is for
653 	 * display and editing purposes only.
654 	 */
655 	if (lp->d_align > 1024)
656 		blksize = 1024;
657 	else
658 		blksize = lp->d_align;
659 
660 	fprintf(f, "# %s:\n", specname);
661 	fprintf(f, "#\n");
662 	fprintf(f, "# Informational fields calculated from the above\n");
663 	fprintf(f, "# All byte equivalent offsets must be aligned\n");
664 	fprintf(f, "#\n");
665 	fprintf(f, "# boot space: %10ju bytes\n",
666 		(intmax_t)(lp->d_pbase - lp->d_bbase));
667 	fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n",
668 			(intmax_t)(lp->d_pstop - lp->d_pbase) / blksize,
669 			(double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0,
670 			(intmax_t)(lp->d_pstop - lp->d_pbase));
671 	fprintf(f, "#\n");
672 	fprintf(f, "# NOTE: If the partition data base looks odd it may be\n");
673 	fprintf(f, "#       physically aligned instead of slice-aligned\n");
674 	fprintf(f, "#\n");
675 
676 	uuid_to_string(&lp->d_stor_uuid, &str, NULL);
677 	fprintf(f, "diskid: %s\n", str ? str : "<unknown>");
678 	free(str);
679 
680 	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname),
681 		lp->d_packname);
682 	fprintf(f, "boot2 data base:      0x%012jx\n", (intmax_t)lp->d_bbase);
683 	fprintf(f, "partitions data base: 0x%012jx\n", (intmax_t)lp->d_pbase);
684 	fprintf(f, "partitions data stop: 0x%012jx\n", (intmax_t)lp->d_pstop);
685 	fprintf(f, "backup label:         0x%012jx\n", (intmax_t)lp->d_abase);
686 	fprintf(f, "total size:           0x%012jx\t# %6.2f MB\n",
687 		(intmax_t)lp->d_total_size,
688 		(double)lp->d_total_size / 1024.0 / 1024.0);
689 	fprintf(f, "alignment: %u\n", lp->d_align);
690 	fprintf(f, "display block size: %u\t# for partition display only\n",
691 		blksize);
692 
693 	fprintf(f, "\n");
694 	fprintf(f, "%u partitions:\n", lp->d_npartitions);
695 	fprintf(f, "#          size     offset    fstype   fsuuid\n");
696 	didany = 0;
697 	for (part = 0; part < lp->d_npartitions; part++) {
698 		pp = &lp->d_partitions[part];
699 		const u_long onemeg = 1024 * 1024;
700 
701 		if (pp->p_bsize == 0)
702 			continue;
703 		didany = 1;
704 		fprintf(f, "  %c: ", 'a' + part);
705 
706 		if (pp->p_bsize % lp->d_align)
707 		    fprintf(f, "%10s  ", "ILLEGAL");
708 		else
709 		    fprintf(f, "%10ju ", (intmax_t)pp->p_bsize / blksize);
710 
711 		if ((pp->p_boffset - lp->d_pbase) % lp->d_align)
712 		    fprintf(f, "%10s  ", "ILLEGAL");
713 		else
714 		    fprintf(f, "%10ju  ",
715 			    (intmax_t)(pp->p_boffset - lp->d_pbase) / blksize);
716 
717 		if (pp->p_fstype < FSMAXTYPES)
718 			fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
719 		else
720 			fprintf(f, "%8d", pp->p_fstype);
721 		fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg);
722 		fprintf(f, "\n");
723 	}
724 	for (part = 0; part < lp->d_npartitions; part++) {
725 		pp = &lp->d_partitions[part];
726 
727 		if (pp->p_bsize == 0)
728 			continue;
729 
730 		if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) {
731 			fprintf(f, "  %c-stor_uuid: ", 'a' + part);
732 			str = NULL;
733 			uuid_to_string(&pp->p_stor_uuid, &str, NULL);
734 			if (str) {
735 				fprintf(f, "%s", str);
736 				free(str);
737 			}
738 			fprintf(f, "\n");
739 		}
740 	}
741 	if (didany == 0) {
742 		fprintf(f, "# EXAMPLE\n");
743 		fprintf(f, "#a:          4g          0    4.2BSD\n");
744 		fprintf(f, "#a:          *           *    4.2BSD\n");
745 
746 	}
747 	fflush(f);
748 }
749 
750 int
751 edit(struct disklabel64 *lp, int f)
752 {
753 	int c, fd;
754 	struct disklabel64 label;
755 	FILE *fp;
756 
757 	if ((fd = mkstemp(tmpfil)) == -1 ||
758 	    (fp = fdopen(fd, "w")) == NULL) {
759 		warnx("can't create %s", tmpfil);
760 		return (1);
761 	}
762 	display(fp, lp);
763 	fclose(fp);
764 	for (;;) {
765 		if (!editit())
766 			break;
767 		fp = fopen(tmpfil, "r");
768 		if (fp == NULL) {
769 			warnx("can't reopen %s for reading", tmpfil);
770 			break;
771 		}
772 		bzero((char *)&label, sizeof(label));
773 		if (getasciilabel(fp, &label)) {
774 			*lp = label;
775 			if (writelabel(f, lp) == 0) {
776 				fclose(fp);
777 				unlink(tmpfil);
778 				return (0);
779 			}
780 		}
781 		fclose(fp);
782 		printf("re-edit the label? [y]: "); fflush(stdout);
783 		c = getchar();
784 		if (c != EOF && c != (int)'\n')
785 			while (getchar() != (int)'\n')
786 				;
787 		if  (c == (int)'n')
788 			break;
789 	}
790 	unlink(tmpfil);
791 	return (1);
792 }
793 
794 int
795 editit(void)
796 {
797 	int pid, xpid;
798 	int status, omask;
799 	const char *ed;
800 
801 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
802 	while ((pid = fork()) < 0) {
803 		if (errno == EPROCLIM) {
804 			warnx("you have too many processes");
805 			return(0);
806 		}
807 		if (errno != EAGAIN) {
808 			warn("fork");
809 			return(0);
810 		}
811 		sleep(1);
812 	}
813 	if (pid == 0) {
814 		sigsetmask(omask);
815 		setgid(getgid());
816 		setuid(getuid());
817 		if ((ed = getenv("EDITOR")) == NULL)
818 			ed = DEFEDITOR;
819 		execlp(ed, ed, tmpfil, NULL);
820 		err(1, "%s", ed);
821 	}
822 	while ((xpid = wait(&status)) >= 0)
823 		if (xpid == pid)
824 			break;
825 	sigsetmask(omask);
826 	return(!status);
827 }
828 
829 char *
830 skip(char *cp)
831 {
832 
833 	while (*cp != '\0' && isspace(*cp))
834 		cp++;
835 	if (*cp == '\0' || *cp == '#')
836 		return (NULL);
837 	return (cp);
838 }
839 
840 char *
841 word(char *cp)
842 {
843 	char c;
844 
845 	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
846 		cp++;
847 	if ((c = *cp) != '\0') {
848 		*cp++ = '\0';
849 		if (c != '#')
850 			return (skip(cp));
851 	}
852 	return (NULL);
853 }
854 
855 /*
856  * Read an ascii label in from fd f,
857  * in the same format as that put out by display(),
858  * and fill in lp.
859  */
860 int
861 getasciilabel(FILE *f, struct disklabel64 *lp)
862 {
863 	char *cp;
864 	u_int part;
865 	char *tp, line[BUFSIZ];
866 	u_long v;
867 	uint32_t blksize = 0;
868 	uint64_t vv;
869 	int lineno = 0, errors = 0;
870 	char empty[] = "";
871 
872 	bzero(&part_set, sizeof(part_set));
873 	bzero(&part_size_type, sizeof(part_size_type));
874 	bzero(&part_offset_type, sizeof(part_offset_type));
875 	while (fgets(line, sizeof(line) - 1, f)) {
876 		lineno++;
877 		if ((cp = strchr(line,'\n')) != NULL)
878 			*cp = '\0';
879 		cp = skip(line);
880 		if (cp == NULL)
881 			continue;
882 		tp = strchr(cp, ':');
883 		if (tp == NULL) {
884 			fprintf(stderr, "line %d: syntax error\n", lineno);
885 			errors++;
886 			continue;
887 		}
888 		*tp++ = '\0', tp = skip(tp);
889 		if (sscanf(cp, "%lu partitions", &v) == 1) {
890 			if (v == 0 || v > MAXPARTITIONS64) {
891 				fprintf(stderr,
892 				    "line %d: bad # of partitions\n", lineno);
893 				lp->d_npartitions = MAXPARTITIONS64;
894 				errors++;
895 			} else
896 				lp->d_npartitions = v;
897 			continue;
898 		}
899 		if (tp == NULL)
900 			tp = empty;
901 
902 		if (streq(cp, "diskid")) {
903 			uint32_t status = 0;
904 			uuid_from_string(tp, &lp->d_stor_uuid, &status);
905 			if (status != uuid_s_ok) {
906 				fprintf(stderr,
907 				    "line %d: %s: illegal UUID\n",
908 				    lineno, tp);
909 				errors++;
910 			}
911 			continue;
912 		}
913 		if (streq(cp, "label")) {
914 			strncpy(lp->d_packname, tp, sizeof (lp->d_packname));
915 			continue;
916 		}
917 
918 		if (streq(cp, "alignment")) {
919 			v = strtoul(tp, NULL, 0);
920 			if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
921 				fprintf(stderr,
922 				    "line %d: %s: bad alignment\n",
923 				    lineno, tp);
924 				errors++;
925 			} else {
926 				lp->d_align = v;
927 			}
928 			continue;
929 		}
930 		if (streq(cp, "total size")) {
931 			vv = strtoull(tp, NULL, 0);
932 			if (vv == 0 || vv == (uint64_t)-1) {
933 				fprintf(stderr, "line %d: %s: bad %s\n",
934 				    lineno, tp, cp);
935 				errors++;
936 			} else {
937 				lp->d_total_size = vv;
938 			}
939 			continue;
940 		}
941 		if (streq(cp, "boot2 data base")) {
942 			vv = strtoull(tp, NULL, 0);
943 			if (vv == 0 || vv == (uint64_t)-1) {
944 				fprintf(stderr, "line %d: %s: bad %s\n",
945 				    lineno, tp, cp);
946 				errors++;
947 			} else {
948 				lp->d_bbase = vv;
949 			}
950 			continue;
951 		}
952 		if (streq(cp, "partitions data base")) {
953 			vv = strtoull(tp, NULL, 0);
954 			if (vv == 0 || vv == (uint64_t)-1) {
955 				fprintf(stderr, "line %d: %s: bad %s\n",
956 				    lineno, tp, cp);
957 				errors++;
958 			} else {
959 				lp->d_pbase = vv;
960 			}
961 			continue;
962 		}
963 		if (streq(cp, "partitions data stop")) {
964 			vv = strtoull(tp, NULL, 0);
965 			if (vv == 0 || vv == (uint64_t)-1) {
966 				fprintf(stderr, "line %d: %s: bad %s\n",
967 				    lineno, tp, cp);
968 				errors++;
969 			} else {
970 				lp->d_pstop = vv;
971 			}
972 			continue;
973 		}
974 		if (streq(cp, "backup label")) {
975 			vv = strtoull(tp, NULL, 0);
976 			if (vv == 0 || vv == (uint64_t)-1) {
977 				fprintf(stderr, "line %d: %s: bad %s\n",
978 				    lineno, tp, cp);
979 				errors++;
980 			} else {
981 				lp->d_abase = vv;
982 			}
983 			continue;
984 		}
985 		if (streq(cp, "display block size")) {
986 			v = strtoul(tp, NULL, 0);
987 			if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
988 				fprintf(stderr,
989 				    "line %d: %s: bad alignment\n",
990 				    lineno, tp);
991 				errors++;
992 			} else {
993 				blksize = v;
994 			}
995 			continue;
996 		}
997 
998 		/* the ':' was removed above */
999 
1000 		/*
1001 		 * Handle main partition data, e.g. a:, b:, etc.
1002 		 */
1003 		if (*cp < 'a' || *cp > MAX_PART) {
1004 			fprintf(stderr,
1005 			    "line %d: %s: Unknown disklabel field\n", lineno,
1006 			    cp);
1007 			errors++;
1008 			continue;
1009 		}
1010 
1011 		/* Process a partition specification line. */
1012 		part = *cp - 'a';
1013 		if (part >= lp->d_npartitions) {
1014 			fprintf(stderr,
1015 			    "line %d: partition name out of range a-%c: %s\n",
1016 			    lineno, 'a' + lp->d_npartitions - 1, cp);
1017 			errors++;
1018 			continue;
1019 		}
1020 
1021 		if (blksize == 0) {
1022 			fprintf(stderr, "block size to use for partition "
1023 					"display was not specified!\n");
1024 			errors++;
1025 			continue;
1026 		}
1027 
1028 		if (strcmp(cp + 1, "-stor_uuid") == 0) {
1029 			if (getasciipartuuid(tp, lp, part, lineno, blksize)) {
1030 				errors++;
1031 				break;
1032 			}
1033 			continue;
1034 		} else if (cp[1] == 0) {
1035 			part_set[part] = 1;
1036 			if (getasciipartspec(tp, lp, part, lineno, blksize)) {
1037 				errors++;
1038 				break;
1039 			}
1040 			continue;
1041 		}
1042 		fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1043 			lineno, cp);
1044 		errors++;
1045 		continue;
1046 	}
1047 	errors += checklabel(lp);
1048 	return (errors == 0);
1049 }
1050 
1051 static
1052 int
1053 parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno)
1054 {
1055 	char *tmp;
1056 
1057 	if (*tp == NULL || **tp == 0) {
1058 		fprintf(stderr, "line %d: too few numeric fields\n", lineno);
1059 		return(-1);
1060 	}
1061 	*cp = *tp;
1062 	*tp = word(*cp);
1063 	*vv = strtoull(*cp, &tmp, 0);
1064 	if (*vv == ULLONG_MAX) {
1065 		fprintf(stderr, "line %d: illegal number\n", lineno);
1066 		return(-1);
1067 	}
1068 	if (tmp)
1069 		return(*tmp);
1070 	else
1071 		return(0);
1072 }
1073 
1074 /*
1075  * Read a partition line into partition `part' in the specified disklabel.
1076  * Return 0 on success, 1 on failure.
1077  */
1078 int
1079 getasciipartspec(char *tp, struct disklabel64 *lp, int part,
1080 		 int lineno, uint32_t blksize)
1081 {
1082 	struct partition64 *pp;
1083 	char *cp;
1084 	const char **cpp;
1085 	int r;
1086 	u_long v;
1087 	uint64_t vv;
1088 	uint64_t mpx;
1089 
1090 	pp = &lp->d_partitions[part];
1091 	cp = NULL;
1092 
1093 	/*
1094 	 * size
1095 	 */
1096 	r = parse_field_val(&tp, &cp, &vv, lineno);
1097 	if (r < 0)
1098 		return (1);
1099 
1100 	mpx = 1;
1101 	switch(r) {
1102 	case 0:
1103 		mpx = blksize;
1104 		break;
1105 	case '%':
1106 		/* mpx = 1; */
1107 		break;
1108 	case '*':
1109 		mpx = 0;
1110 		break;
1111 	case 't':
1112 	case 'T':
1113 		mpx *= 1024ULL;
1114 		/* fall through */
1115 	case 'g':
1116 	case 'G':
1117 		mpx *= 1024ULL;
1118 		/* fall through */
1119 	case 'm':
1120 	case 'M':
1121 		mpx *= 1024ULL;
1122 		/* fall through */
1123 	case 'k':
1124 	case 'K':
1125 		mpx *= 1024ULL;
1126 		r = 0;			/* eat the suffix */
1127 		break;
1128 	default:
1129 		Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)",
1130 			r);
1131 		return(1);
1132 	}
1133 
1134 	part_size_type[part] = r;
1135 	if (vv == 0 && r != '*') {
1136 		fprintf(stderr,
1137 		    "line %d: %s: bad partition size (0)\n", lineno, cp);
1138 		return (1);
1139 	}
1140 	pp->p_bsize = vv * mpx;
1141 
1142 	/*
1143 	 * offset
1144 	 */
1145 	r = parse_field_val(&tp, &cp, &vv, lineno);
1146 	if (r < 0)
1147 		return (1);
1148 	part_offset_type[part] = r;
1149 	switch(r) {
1150 	case '*':
1151 		pp->p_boffset = 0;
1152 		break;
1153 	case 0:
1154 		pp->p_boffset = vv * blksize + lp->d_pbase;
1155 		break;
1156 	default:
1157 		fprintf(stderr,
1158 		    "line %d: %s: bad suffix on partition offset (%c)\n",
1159 		    lineno, cp, r);
1160 		return (1);
1161 	}
1162 
1163 	/*
1164 	 * fstype
1165 	 */
1166 	if (tp == NULL) {
1167 		fprintf(stderr,
1168 		    "line %d: no filesystem type was specified\n", lineno);
1169 		return(1);
1170 	}
1171 	cp = tp;
1172 	tp = word(cp);
1173 	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) {
1174 		if (*cpp && strcasecmp(*cpp, cp) == 0)
1175 			break;
1176 	}
1177 	if (*cpp != NULL) {
1178 		pp->p_fstype = cpp - fstypenames;
1179 	} else {
1180 		if (isdigit(*cp))
1181 			v = strtoul(cp, NULL, 0);
1182 		else
1183 			v = FSMAXTYPES;
1184 		if (v >= FSMAXTYPES) {
1185 			fprintf(stderr,
1186 			    "line %d: Warning, unknown filesystem type %s\n",
1187 			    lineno, cp);
1188 			v = FS_UNUSED;
1189 		}
1190 		pp->p_fstype = v;
1191 	}
1192 
1193 	cp = tp;
1194 	if (tp) {
1195 		fprintf(stderr, "line %d: Warning, extra data on line\n",
1196 			lineno);
1197 	}
1198 	return(0);
1199 }
1200 
1201 int
1202 getasciipartuuid(char *tp, struct disklabel64 *lp, int part,
1203 		 int lineno, uint32_t blksize __unused)
1204 {
1205 	struct partition64 *pp;
1206 	uint32_t status;
1207 	char *cp;
1208 
1209 	pp = &lp->d_partitions[part];
1210 
1211 	cp = tp;
1212 	tp = word(cp);
1213 	uuid_from_string(cp, &pp->p_stor_uuid, &status);
1214 	if (status != uuid_s_ok) {
1215 		fprintf(stderr, "line %d: Illegal storage uuid specification\n",
1216 			lineno);
1217 		return(1);
1218 	}
1219 	return(0);
1220 }
1221 
1222 /*
1223  * Check disklabel for errors and fill in
1224  * derived fields according to supplied values.
1225  */
1226 int
1227 checklabel(struct disklabel64 *lp)
1228 {
1229 	struct partition64 *pp;
1230 	int errors = 0;
1231 	char part;
1232 	u_int64_t total_size;
1233 	u_int64_t current_offset;
1234 	u_long total_percent;
1235 	int seen_default_offset;
1236 	int hog_part;
1237 	int i, j;
1238 	struct partition64 *pp2;
1239 	u_int64_t off;
1240 
1241 	if (lp->d_align < 512 ||
1242 	    (lp->d_align ^ (lp->d_align - 1)) != lp->d_align * 2 - 1) {
1243 		Warning("Illegal alignment specified: %u\n", lp->d_align);
1244 		return (1);
1245 	}
1246 	if (lp->d_npartitions > MAXPARTITIONS64) {
1247 		Warning("number of partitions (%u) > MAXPARTITIONS (%d)",
1248 			lp->d_npartitions, MAXPARTITIONS64);
1249 		return (1);
1250 	}
1251 	off = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
1252 	off = (off + lp->d_align - 1) & ~(int64_t)(lp->d_align - 1);
1253 
1254 	if (lp->d_bbase < off || lp->d_bbase % lp->d_align) {
1255 		Warning("illegal boot2 data base ");
1256 		return (1);
1257 	}
1258 
1259 	/*
1260 	 * pbase can be unaligned slice-relative but will be
1261 	 * aligned physically.
1262 	 */
1263 	if (lp->d_pbase < lp->d_bbase) {
1264 		Warning("illegal partition data base");
1265 		return (1);
1266 	}
1267 	if (lp->d_pstop < lp->d_pbase) {
1268 		Warning("illegal partition data stop");
1269 		return (1);
1270 	}
1271 	if (lp->d_pstop > lp->d_total_size) {
1272 		printf("%012jx\n%012jx\n",
1273 			(intmax_t)lp->d_pstop, (intmax_t)lp->d_total_size);
1274 		Warning("disklabel control info is beyond the total size");
1275 		return (1);
1276 	}
1277 	if (lp->d_abase &&
1278 	    (lp->d_abase < lp->d_pstop ||
1279 	     lp->d_abase > lp->d_total_size - off)) {
1280 		Warning("illegal backup label location");
1281 		return (1);
1282 	}
1283 
1284 	/* first allocate space to the partitions, then offsets */
1285 	total_size = 0;		/* in bytes */
1286 	total_percent = 0;	/* in percent */
1287 	hog_part = -1;
1288 	/* find all fixed partitions */
1289 	for (i = 0; i < (int)lp->d_npartitions; i++) {
1290 		pp = &lp->d_partitions[i];
1291 		if (part_set[i]) {
1292 			if (part_size_type[i] == '*') {
1293 				if (part_offset_type[i] != '*') {
1294 					if (total_size < pp->p_boffset)
1295 						total_size = pp->p_boffset;
1296 				}
1297 				if (hog_part != -1) {
1298 					Warning("Too many '*' partitions (%c and %c)",
1299 					    hog_part + 'a',i + 'a');
1300 				} else {
1301 					hog_part = i;
1302 				}
1303 			} else {
1304 				off_t size;
1305 
1306 				size = pp->p_bsize;
1307 				if (part_size_type[i] == '%') {
1308 					/*
1309 					 * don't count %'s yet
1310 					 */
1311 					total_percent += size;
1312 				} else {
1313 					/*
1314 					 * Value has already been converted
1315 					 * to bytes.
1316 					 */
1317 					if (size % lp->d_align != 0) {
1318 						Warning("partition %c's size is not properly aligned",
1319 							i + 'a');
1320 					}
1321 					total_size += size;
1322 				}
1323 			}
1324 		}
1325 	}
1326 	/* handle % partitions - note %'s don't need to add up to 100! */
1327 	if (total_percent != 0) {
1328 		int64_t free_space;
1329 		int64_t space_left;
1330 
1331 		free_space = (int64_t)(lp->d_pstop - lp->d_pbase - total_size);
1332 		free_space &= ~(u_int64_t)(lp->d_align - 1);
1333 
1334 		space_left = free_space;
1335 		if (total_percent > 100) {
1336 			fprintf(stderr,"total percentage %lu is greater than 100\n",
1337 			    total_percent);
1338 			errors++;
1339 		}
1340 
1341 		if (free_space > 0) {
1342 			for (i = 0; i < (int)lp->d_npartitions; i++) {
1343 				pp = &lp->d_partitions[i];
1344 				if (part_set[i] && part_size_type[i] == '%') {
1345 					/* careful of overflows! and integer roundoff */
1346 					pp->p_bsize = ((double)pp->p_bsize/100) * free_space;
1347 					pp->p_bsize = (pp->p_bsize + lp->d_align - 1) & ~(u_int64_t)(lp->d_align - 1);
1348 					if ((int64_t)pp->p_bsize > space_left)
1349 						pp->p_bsize = (u_int64_t)space_left;
1350 					total_size += pp->p_bsize;
1351 					space_left -= pp->p_bsize;
1352 				}
1353 			}
1354 		} else {
1355 			fprintf(stderr, "%jd bytes available to give to "
1356 					"'*' and '%%' partitions\n",
1357 				(intmax_t)free_space);
1358 			errors++;
1359 			/* fix?  set all % partitions to size 0? */
1360 		}
1361 	}
1362 	/* give anything remaining to the hog partition */
1363 	if (hog_part != -1) {
1364 		off = lp->d_pstop - lp->d_pbase - total_size;
1365 		off &= ~(u_int64_t)(lp->d_align - 1);
1366 		lp->d_partitions[hog_part].p_bsize = off;
1367 		total_size = lp->d_pstop - lp->d_pbase;
1368 	}
1369 
1370 	/* Now set the offsets for each partition */
1371 	current_offset = lp->d_pbase;
1372 	seen_default_offset = 0;
1373 	for (i = 0; i < (int)lp->d_npartitions; i++) {
1374 		part = 'a' + i;
1375 		pp = &lp->d_partitions[i];
1376 		if (pp->p_bsize == 0)
1377 			continue;
1378 		if (part_set[i]) {
1379 			if (part_offset_type[i] == '*') {
1380 				pp->p_boffset = current_offset;
1381 				seen_default_offset = 1;
1382 			} else {
1383 				/* allow them to be out of order for old-style tables */
1384 				if (pp->p_boffset < current_offset &&
1385 				    seen_default_offset &&
1386 				    pp->p_fstype != FS_VINUM) {
1387 					fprintf(stderr,
1388 "Offset 0x%012jx for partition %c overlaps previous partition which ends at 0x%012jx\n",
1389 					    (intmax_t)pp->p_boffset,
1390 					    i + 'a',
1391 					    (intmax_t)current_offset);
1392 					fprintf(stderr,
1393 "Labels with any *'s for offset must be in ascending order by sector\n");
1394 					errors++;
1395 				} else if (pp->p_boffset != current_offset &&
1396 					   seen_default_offset) {
1397 					/*
1398 					 * this may give unneeded warnings if
1399 					 * partitions are out-of-order
1400 					 */
1401 					Warning(
1402 "Offset 0x%012jx for partition %c doesn't match expected value 0x%012jx",
1403 					    pp->p_boffset, i + 'a',
1404 					    (intmax_t)current_offset);
1405 				}
1406 			}
1407 			current_offset = pp->p_boffset + pp->p_bsize;
1408 		}
1409 	}
1410 
1411 	for (i = 0; i < (int)lp->d_npartitions; i++) {
1412 		part = 'a' + i;
1413 		pp = &lp->d_partitions[i];
1414 		if (pp->p_bsize == 0 && pp->p_boffset != 0)
1415 			Warning("partition %c: size 0, but offset 0x%012jx",
1416 				part, (intmax_t)pp->p_boffset);
1417 		if (pp->p_bsize == 0) {
1418 			pp->p_boffset = 0;
1419 			continue;
1420 		}
1421 		if (uuid_is_nil(&pp->p_stor_uuid, NULL))
1422 			uuid_create(&pp->p_stor_uuid, NULL);
1423 
1424 		if (pp->p_boffset < lp->d_pbase) {
1425 			fprintf(stderr,
1426 			    "partition %c: offset out of bounds (%jd)\n",
1427 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1428 			errors++;
1429 		}
1430 		if (pp->p_boffset > lp->d_pstop) {
1431 			fprintf(stderr,
1432 			    "partition %c: offset out of bounds (%jd)\n",
1433 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1434 			errors++;
1435 		}
1436 		if (pp->p_boffset + pp->p_bsize > lp->d_pstop) {
1437 			fprintf(stderr,
1438 			    "partition %c: size out of bounds (%jd)\n",
1439 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
1440 			errors++;
1441 		}
1442 
1443 		/* check for overlaps */
1444 		/* this will check for all possible overlaps once and only once */
1445 		for (j = 0; j < i; j++) {
1446 			pp2 = &lp->d_partitions[j];
1447 			if (pp->p_fstype != FS_VINUM &&
1448 			    pp2->p_fstype != FS_VINUM &&
1449 			    part_set[i] && part_set[j]) {
1450 				if (pp2->p_boffset < pp->p_boffset + pp->p_bsize &&
1451 				    (pp2->p_boffset + pp2->p_bsize > pp->p_boffset ||
1452 					pp2->p_boffset >= pp->p_boffset)) {
1453 					fprintf(stderr,"partitions %c and %c overlap!\n",
1454 					    j + 'a', i + 'a');
1455 					errors++;
1456 				}
1457 			}
1458 		}
1459 	}
1460 	for (; i < (int)lp->d_npartitions; i++) {
1461 		part = 'a' + i;
1462 		pp = &lp->d_partitions[i];
1463 		if (pp->p_bsize || pp->p_boffset)
1464 			Warning("unused partition %c: size 0x%012jx "
1465 				"offset 0x%012jx",
1466 				'a' + i, (intmax_t)pp->p_bsize,
1467 				(intmax_t)pp->p_boffset);
1468 	}
1469 	return (errors);
1470 }
1471 
1472 /*
1473  * When operating on a "virgin" disk, try getting an initial label
1474  * from the associated device driver.  This might work for all device
1475  * drivers that are able to fetch some initial device parameters
1476  * without even having access to a (BSD) disklabel, like SCSI disks,
1477  * most IDE drives, or vn devices.
1478  *
1479  * The device name must be given in its "canonical" form.
1480  */
1481 static struct disklabel64 dlab;
1482 
1483 struct disklabel64 *
1484 getvirginlabel(void)
1485 {
1486 	struct disklabel64 *dl = &dlab;
1487 	int f;
1488 
1489 	if ((f = open(dkname, O_RDONLY)) == -1) {
1490 		warn("cannot open %s", dkname);
1491 		return (NULL);
1492 	}
1493 
1494 	/*
1495 	 * Try to use the new get-virgin-label ioctl.  If it fails,
1496 	 * fallback to the old get-disk-info ioctl.
1497 	 */
1498 	if (ioctl(f, DIOCGDVIRGIN64, dl) < 0) {
1499 		l_perror("ioctl DIOCGDVIRGIN64");
1500 		close(f);
1501 		return (NULL);
1502 	}
1503 	close(f);
1504 	return (dl);
1505 }
1506 
1507 /*VARARGS1*/
1508 void
1509 Warning(const char *fmt, ...)
1510 {
1511 	va_list ap;
1512 
1513 	fprintf(stderr, "Warning, ");
1514 	va_start(ap, fmt);
1515 	vfprintf(stderr, fmt, ap);
1516 	fprintf(stderr, "\n");
1517 	va_end(ap);
1518 }
1519 
1520 void
1521 usage(void)
1522 {
1523 	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",
1524 		"usage: disklabel64 [-r] disk",
1525 		"\t\t(to read label)",
1526 		"       disklabel64 -w [-r] [-n] disk type [packid]",
1527 		"\t\t(to write label with existing boot program)",
1528 		"       disklabel64 -e [-r] [-n] disk",
1529 		"\t\t(to edit label)",
1530 		"       disklabel64 -R [-r] [-n] disk protofile",
1531 		"\t\t(to restore label with existing boot program)",
1532 		"       disklabel64 -B [-n] [-b boot1 -s boot2] disk [type]",
1533 		"\t\t(to install boot program with existing label)",
1534 		"       disklabel64 -w -B [-n] [-b boot1 -s boot2] disk type [packid]",
1535 		"\t\t(to write label and boot program)",
1536 		"       disklabel64 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]",
1537 		"\t\t(to restore label and boot program)",
1538 		"       disklabel64 [-NW] disk",
1539 		"\t\t(to write disable/enable label)");
1540 	exit(1);
1541 }
1542