xref: /dflybsd-src/sbin/disklabel64/disklabel64.c (revision e04444f90cdc669c716a17ac94d82b7be1bcc8e7)
10ffe40b3SMatthew Dillon /*
235a9ab8aSMatthew Dillon  * Copyright (c) 2007,2020 The DragonFly Project.  All rights reserved.
30ffe40b3SMatthew Dillon  *
40ffe40b3SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
50ffe40b3SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
60ffe40b3SMatthew Dillon  *
70ffe40b3SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
80ffe40b3SMatthew Dillon  * modification, are permitted provided that the following conditions
90ffe40b3SMatthew Dillon  * are met:
100ffe40b3SMatthew Dillon  *
110ffe40b3SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
120ffe40b3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
130ffe40b3SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
140ffe40b3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
150ffe40b3SMatthew Dillon  *    the documentation and/or other materials provided with the
160ffe40b3SMatthew Dillon  *    distribution.
170ffe40b3SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
180ffe40b3SMatthew Dillon  *    contributors may be used to endorse or promote products derived
190ffe40b3SMatthew Dillon  *    from this software without specific, prior written permission.
200ffe40b3SMatthew Dillon  *
210ffe40b3SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
220ffe40b3SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
230ffe40b3SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
240ffe40b3SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
250ffe40b3SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
260ffe40b3SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
270ffe40b3SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
280ffe40b3SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
290ffe40b3SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
300ffe40b3SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
310ffe40b3SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
320ffe40b3SMatthew Dillon  * SUCH DAMAGE.
330ffe40b3SMatthew Dillon  */
340ffe40b3SMatthew Dillon /*
350ffe40b3SMatthew Dillon  * Copyright (c) 1987, 1993
360ffe40b3SMatthew Dillon  *	The Regents of the University of California.  All rights reserved.
370ffe40b3SMatthew Dillon  *
380ffe40b3SMatthew Dillon  * This code is derived from software contributed to Berkeley by
390ffe40b3SMatthew Dillon  * Symmetric Computer Systems.
400ffe40b3SMatthew Dillon  *
410ffe40b3SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
420ffe40b3SMatthew Dillon  * modification, are permitted provided that the following conditions
430ffe40b3SMatthew Dillon  * are met:
440ffe40b3SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
450ffe40b3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
460ffe40b3SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
470ffe40b3SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
480ffe40b3SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
49dc71b7abSJustin C. Sherrill  * 3. Neither the name of the University nor the names of its contributors
500ffe40b3SMatthew Dillon  *    may be used to endorse or promote products derived from this software
510ffe40b3SMatthew Dillon  *    without specific prior written permission.
520ffe40b3SMatthew Dillon  *
530ffe40b3SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
540ffe40b3SMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
550ffe40b3SMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
560ffe40b3SMatthew Dillon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
570ffe40b3SMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
580ffe40b3SMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
590ffe40b3SMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
600ffe40b3SMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
610ffe40b3SMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
620ffe40b3SMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
630ffe40b3SMatthew Dillon  * SUCH DAMAGE.
640ffe40b3SMatthew Dillon  *
650ffe40b3SMatthew Dillon  * @(#)disklabel.c	1.2 (Symmetric) 11/28/85
660ffe40b3SMatthew Dillon  * @(#)disklabel.c      8.2 (Berkeley) 1/7/94
670ffe40b3SMatthew Dillon  * $FreeBSD: src/sbin/disklabel/disklabel.c,v 1.28.2.15 2003/01/24 16:18:16 des Exp $
680ffe40b3SMatthew Dillon  */
690ffe40b3SMatthew Dillon 
700ffe40b3SMatthew Dillon #include <sys/param.h>
710ffe40b3SMatthew Dillon #include <sys/stat.h>
720ffe40b3SMatthew Dillon #include <sys/wait.h>
730ffe40b3SMatthew Dillon #define DKTYPENAMES
740ffe40b3SMatthew Dillon #include <sys/disklabel64.h>
750ffe40b3SMatthew Dillon #include <sys/diskslice.h>
760ffe40b3SMatthew Dillon #include <sys/diskmbr.h>
770ffe40b3SMatthew Dillon #include <sys/dtype.h>
780ffe40b3SMatthew Dillon #include <sys/sysctl.h>
790ffe40b3SMatthew Dillon #include <disktab.h>
802c3b1d1bSSascha Wildner #include <fcntl.h>
81d736a600SMatthew Dillon #include <fstab.h>
820ffe40b3SMatthew Dillon 
830ffe40b3SMatthew Dillon #include <vfs/ufs/dinode.h>
840ffe40b3SMatthew Dillon #include <vfs/ufs/fs.h>
850ffe40b3SMatthew Dillon 
860ffe40b3SMatthew Dillon #include <unistd.h>
870ffe40b3SMatthew Dillon #include <string.h>
880ffe40b3SMatthew Dillon #include <stdio.h>
890ffe40b3SMatthew Dillon #include <stdlib.h>
900ffe40b3SMatthew Dillon #include <signal.h>
910ffe40b3SMatthew Dillon #include <stdarg.h>
920ffe40b3SMatthew Dillon #include <stddef.h>
930ffe40b3SMatthew Dillon #include <ctype.h>
940ffe40b3SMatthew Dillon #include <err.h>
950ffe40b3SMatthew Dillon #include <errno.h>
960ffe40b3SMatthew Dillon #include <uuid.h>
970ffe40b3SMatthew Dillon #include "pathnames.h"
980ffe40b3SMatthew Dillon 
990ffe40b3SMatthew Dillon extern uint32_t crc32(const void *buf, size_t size);
1000ffe40b3SMatthew Dillon 
1010a319615SMatthew Dillon static void	makelabel(const char *, const char *, struct disklabel64 *);
1020a319615SMatthew Dillon static int	writelabel(int, struct disklabel64 *);
10335a9ab8aSMatthew Dillon static int	expandlabel(int f, struct disklabel64 *lp, int *wbackp);
1040a319615SMatthew Dillon static void	l_perror(const char *);
1050a319615SMatthew Dillon static void	display(FILE *, const struct disklabel64 *);
1060a319615SMatthew Dillon static int	edit(struct disklabel64 *, int);
1070a319615SMatthew Dillon static int	editit(void);
1080a319615SMatthew Dillon static char	*skip(char *);
1090a319615SMatthew Dillon static char	*word(char *);
1100a319615SMatthew Dillon static int	parse_field_val(char **, char **, u_int64_t *, int);
1110a319615SMatthew Dillon static int	getasciilabel(FILE *, struct disklabel64 *);
1120a319615SMatthew Dillon static int	getasciipartspec(char *, struct disklabel64 *, int, int, uint32_t);
1130a319615SMatthew Dillon static int	getasciipartuuid(char *, struct disklabel64 *, int, int, uint32_t);
1140a319615SMatthew Dillon static int	checklabel(struct disklabel64 *);
1150a319615SMatthew Dillon static void	Warning(const char *, ...) __printflike(1, 2);
1160a319615SMatthew Dillon static void	usage(void);
1170a319615SMatthew Dillon static struct disklabel64 *getvirginlabel(void);
1180a319615SMatthew Dillon static struct disklabel64 *readlabel(int);
1190a319615SMatthew Dillon static struct disklabel64 *makebootarea(int);
1200ffe40b3SMatthew Dillon 
1210ffe40b3SMatthew Dillon #define	DEFEDITOR	_PATH_VI
1220ffe40b3SMatthew Dillon #define	streq(a,b)	(strcmp(a,b) == 0)
1230ffe40b3SMatthew Dillon 
1240a319615SMatthew Dillon static char	*dkname;
1250a319615SMatthew Dillon static char	*specname;
1260a319615SMatthew Dillon static char	tmpfil[] = PATH_TMPFILE;
1270ffe40b3SMatthew Dillon 
1280a319615SMatthew Dillon static struct	disklabel64 lab;
1290ffe40b3SMatthew Dillon 
1300ffe40b3SMatthew Dillon #define MAX_PART ('z')
1310ffe40b3SMatthew Dillon #define MAX_NUM_PARTS (1 + MAX_PART - 'a')
1320a319615SMatthew Dillon static char	part_size_type[MAX_NUM_PARTS];
1330a319615SMatthew Dillon static char	part_offset_type[MAX_NUM_PARTS];
1340a319615SMatthew Dillon static int	part_set[MAX_NUM_PARTS];
1350ffe40b3SMatthew Dillon 
13635a9ab8aSMatthew Dillon static int	installboot;
13735a9ab8aSMatthew Dillon static int	expandopt;
1380a319615SMatthew Dillon static int	boot1size;
1390a319615SMatthew Dillon static int	boot1lsize;
1400a319615SMatthew Dillon static int	boot2size;
1410a319615SMatthew Dillon static char	*boot1buf;
1420a319615SMatthew Dillon static char	*boot2buf;
1430a319615SMatthew Dillon static char	*boot1path;
1440a319615SMatthew Dillon static char	*boot2path;
1450ffe40b3SMatthew Dillon 
1460a319615SMatthew Dillon static enum {
14735a9ab8aSMatthew Dillon 	UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE, WRITEBOOT,
14835a9ab8aSMatthew Dillon 	EXPAND
1490ffe40b3SMatthew Dillon } op = UNSPEC;
1500ffe40b3SMatthew Dillon 
1510a319615SMatthew Dillon static int	rflag;
1520a319615SMatthew Dillon static int	Vflag;
1530a319615SMatthew Dillon static int	disable_write;   /* set to disable writing to disk label */
1540ffe40b3SMatthew Dillon 
1550ffe40b3SMatthew Dillon #ifdef DEBUG
1560a319615SMatthew Dillon static int	debug;
15735a9ab8aSMatthew Dillon #define OPTIONS	"BNRWb:denrs:Vwx"
1580ffe40b3SMatthew Dillon #else
15935a9ab8aSMatthew Dillon #define OPTIONS	"BNRWb:enrs:Vwx"
1600ffe40b3SMatthew Dillon #endif
1610ffe40b3SMatthew Dillon 
1620ffe40b3SMatthew Dillon int
main(int argc,char * argv[])1630ffe40b3SMatthew Dillon main(int argc, char *argv[])
1640ffe40b3SMatthew Dillon {
1650ffe40b3SMatthew Dillon 	struct disklabel64 *lp;
1660ffe40b3SMatthew Dillon 	FILE *t;
1670ffe40b3SMatthew Dillon 	int ch, f = 0, flag, error = 0;
1680a319615SMatthew Dillon 	const char *name = NULL;
1690a319615SMatthew Dillon 	const char *dtype = NULL;
1700ffe40b3SMatthew Dillon 
1710ffe40b3SMatthew Dillon 	while ((ch = getopt(argc, argv, OPTIONS)) != -1)
1720ffe40b3SMatthew Dillon 		switch (ch) {
1730ffe40b3SMatthew Dillon 			case 'B':
1740ffe40b3SMatthew Dillon 				++installboot;
1750ffe40b3SMatthew Dillon 				break;
1760ffe40b3SMatthew Dillon 			case 'b':
1770ffe40b3SMatthew Dillon 				boot1path = optarg;
1780ffe40b3SMatthew Dillon 				break;
1790ffe40b3SMatthew Dillon 
1800ffe40b3SMatthew Dillon 			case 's':
1810ffe40b3SMatthew Dillon 				boot2path = optarg;
1820ffe40b3SMatthew Dillon 				break;
1830ffe40b3SMatthew Dillon 			case 'N':
1840ffe40b3SMatthew Dillon 				if (op != UNSPEC)
1850ffe40b3SMatthew Dillon 					usage();
1860ffe40b3SMatthew Dillon 				op = NOWRITE;
1870ffe40b3SMatthew Dillon 				break;
1880ffe40b3SMatthew Dillon 			case 'n':
1890ffe40b3SMatthew Dillon 				disable_write = 1;
1900ffe40b3SMatthew Dillon 				break;
1910ffe40b3SMatthew Dillon 			case 'R':
1920ffe40b3SMatthew Dillon 				if (op != UNSPEC)
1930ffe40b3SMatthew Dillon 					usage();
1940ffe40b3SMatthew Dillon 				op = RESTORE;
1950ffe40b3SMatthew Dillon 				break;
1960ffe40b3SMatthew Dillon 			case 'W':
1970ffe40b3SMatthew Dillon 				if (op != UNSPEC)
1980ffe40b3SMatthew Dillon 					usage();
1990ffe40b3SMatthew Dillon 				op = WRITEABLE;
2000ffe40b3SMatthew Dillon 				break;
2010ffe40b3SMatthew Dillon 			case 'e':
2020ffe40b3SMatthew Dillon 				if (op != UNSPEC)
2030ffe40b3SMatthew Dillon 					usage();
2040ffe40b3SMatthew Dillon 				op = EDIT;
2050ffe40b3SMatthew Dillon 				break;
2060ffe40b3SMatthew Dillon 			case 'V':
2070ffe40b3SMatthew Dillon 				++Vflag;
2080ffe40b3SMatthew Dillon 				break;
2090ffe40b3SMatthew Dillon 			case 'r':
2100ffe40b3SMatthew Dillon 				++rflag;
2110ffe40b3SMatthew Dillon 				break;
2120ffe40b3SMatthew Dillon 			case 'w':
2130ffe40b3SMatthew Dillon 				if (op != UNSPEC)
2140ffe40b3SMatthew Dillon 					usage();
2150ffe40b3SMatthew Dillon 				op = WRITE;
2160ffe40b3SMatthew Dillon 				break;
21735a9ab8aSMatthew Dillon 			case 'x':
21835a9ab8aSMatthew Dillon 				expandopt++;
21935a9ab8aSMatthew Dillon 				op = EXPAND;
22035a9ab8aSMatthew Dillon 				break;
2210ffe40b3SMatthew Dillon #ifdef DEBUG
2220ffe40b3SMatthew Dillon 			case 'd':
2230ffe40b3SMatthew Dillon 				debug++;
2240ffe40b3SMatthew Dillon 				break;
2250ffe40b3SMatthew Dillon #endif
2260ffe40b3SMatthew Dillon 			case '?':
2270ffe40b3SMatthew Dillon 			default:
2280ffe40b3SMatthew Dillon 				usage();
2290ffe40b3SMatthew Dillon 		}
2300ffe40b3SMatthew Dillon 	argc -= optind;
2310ffe40b3SMatthew Dillon 	argv += optind;
2320ffe40b3SMatthew Dillon 	if (installboot) {
2330ffe40b3SMatthew Dillon 		rflag++;
2340ffe40b3SMatthew Dillon 		if (op == UNSPEC)
2350ffe40b3SMatthew Dillon 			op = WRITEBOOT;
2360ffe40b3SMatthew Dillon 	} else {
2370ffe40b3SMatthew Dillon 		if (op == UNSPEC)
2380ffe40b3SMatthew Dillon 			op = READ;
2390ffe40b3SMatthew Dillon 		boot1path = NULL;
2400ffe40b3SMatthew Dillon 		boot2path = NULL;
2410ffe40b3SMatthew Dillon 	}
2420ffe40b3SMatthew Dillon 	if (argc < 1)
2430ffe40b3SMatthew Dillon 		usage();
2440ffe40b3SMatthew Dillon 
245d736a600SMatthew Dillon 	dkname = getdevpath(argv[0], 0);
2460ffe40b3SMatthew Dillon 	specname = dkname;
2470ffe40b3SMatthew Dillon 	f = open(specname, op == READ ? O_RDONLY : O_RDWR);
2480ffe40b3SMatthew Dillon 	if (f < 0)
2490ffe40b3SMatthew Dillon 		err(4, "%s", specname);
2500ffe40b3SMatthew Dillon 
2510ffe40b3SMatthew Dillon 	switch(op) {
2520ffe40b3SMatthew Dillon 
2530ffe40b3SMatthew Dillon 	case UNSPEC:
2540ffe40b3SMatthew Dillon 		break;
2550ffe40b3SMatthew Dillon 
2560ffe40b3SMatthew Dillon 	case EDIT:
2570ffe40b3SMatthew Dillon 		if (argc != 1)
2580ffe40b3SMatthew Dillon 			usage();
2590ffe40b3SMatthew Dillon 		lp = readlabel(f);
2600ffe40b3SMatthew Dillon 		error = edit(lp, f);
2610ffe40b3SMatthew Dillon 		break;
2620ffe40b3SMatthew Dillon 
2630ffe40b3SMatthew Dillon 	case NOWRITE:
2640ffe40b3SMatthew Dillon 		flag = 0;
2650ffe40b3SMatthew Dillon 		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
2660ffe40b3SMatthew Dillon 			err(4, "ioctl DIOCWLABEL");
2670ffe40b3SMatthew Dillon 		break;
2680ffe40b3SMatthew Dillon 
2690ffe40b3SMatthew Dillon 	case READ:
2700ffe40b3SMatthew Dillon 		if (argc != 1)
2710ffe40b3SMatthew Dillon 			usage();
2720ffe40b3SMatthew Dillon 		lp = readlabel(f);
2730ffe40b3SMatthew Dillon 		display(stdout, lp);
2740ffe40b3SMatthew Dillon 		error = checklabel(lp);
2750ffe40b3SMatthew Dillon 		break;
2760ffe40b3SMatthew Dillon 
27735a9ab8aSMatthew Dillon 	case EXPAND:
27835a9ab8aSMatthew Dillon 		{
27935a9ab8aSMatthew Dillon 			int wback = 0;
28035a9ab8aSMatthew Dillon 
28135a9ab8aSMatthew Dillon 			lp = readlabel(f);
28235a9ab8aSMatthew Dillon 			error = expandlabel(f, lp, &wback);
28335a9ab8aSMatthew Dillon 			if (checklabel(lp) == 0 && wback)
28435a9ab8aSMatthew Dillon 				error = writelabel(f, lp);
28535a9ab8aSMatthew Dillon 		}
28635a9ab8aSMatthew Dillon 		break;
28735a9ab8aSMatthew Dillon 
2880ffe40b3SMatthew Dillon 	case RESTORE:
2890ffe40b3SMatthew Dillon 		if (installboot && argc == 3) {
2900ffe40b3SMatthew Dillon 			makelabel(argv[2], 0, &lab);
2910ffe40b3SMatthew Dillon 			argc--;
2920ffe40b3SMatthew Dillon 
2930ffe40b3SMatthew Dillon 			/*
2940ffe40b3SMatthew Dillon 			 * We only called makelabel() for its side effect
2950ffe40b3SMatthew Dillon 			 * of setting the bootstrap file names.  Discard
2960ffe40b3SMatthew Dillon 			 * all changes to `lab' so that all values in the
2970ffe40b3SMatthew Dillon 			 * final label come from the ASCII label.
2980ffe40b3SMatthew Dillon 			 */
2990ffe40b3SMatthew Dillon 			bzero((char *)&lab, sizeof(lab));
3000ffe40b3SMatthew Dillon 		}
3010ffe40b3SMatthew Dillon 		if (argc != 2)
3020ffe40b3SMatthew Dillon 			usage();
3030ffe40b3SMatthew Dillon 		if (!(t = fopen(argv[1], "r")))
3040ffe40b3SMatthew Dillon 			err(4, "%s", argv[1]);
3050ffe40b3SMatthew Dillon 		if (!getasciilabel(t, &lab))
3060ffe40b3SMatthew Dillon 			exit(1);
3070ffe40b3SMatthew Dillon 		lp = makebootarea(f);
3080ffe40b3SMatthew Dillon 		bcopy(&lab.d_magic, &lp->d_magic,
3090ffe40b3SMatthew Dillon 		      sizeof(lab) - offsetof(struct disklabel64, d_magic));
3100ffe40b3SMatthew Dillon 		error = writelabel(f, lp);
3110ffe40b3SMatthew Dillon 		break;
3120ffe40b3SMatthew Dillon 
3130ffe40b3SMatthew Dillon 	case WRITE:
3140ffe40b3SMatthew Dillon 		if (argc == 3) {
3150ffe40b3SMatthew Dillon 			name = argv[2];
3160ffe40b3SMatthew Dillon 			argc--;
3170ffe40b3SMatthew Dillon 		}
3180a319615SMatthew Dillon 		if (argc == 2)
3190a319615SMatthew Dillon 			dtype = argv[1];
3200a319615SMatthew Dillon 		else if (argc == 1)
3210a319615SMatthew Dillon 			dtype = "auto";
3220a319615SMatthew Dillon 		else
3230ffe40b3SMatthew Dillon 			usage();
3240a319615SMatthew Dillon 		makelabel(dtype, name, &lab);
3250ffe40b3SMatthew Dillon 		lp = makebootarea(f);
3260ffe40b3SMatthew Dillon 		bcopy(&lab.d_magic, &lp->d_magic,
3270ffe40b3SMatthew Dillon 		      sizeof(lab) - offsetof(struct disklabel64, d_magic));
3280ffe40b3SMatthew Dillon 		if (checklabel(lp) == 0)
3290ffe40b3SMatthew Dillon 			error = writelabel(f, lp);
3300ffe40b3SMatthew Dillon 		break;
3310ffe40b3SMatthew Dillon 
3320ffe40b3SMatthew Dillon 	case WRITEABLE:
3330ffe40b3SMatthew Dillon 		flag = 1;
3340ffe40b3SMatthew Dillon 		if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0)
3350ffe40b3SMatthew Dillon 			err(4, "ioctl DIOCWLABEL");
3360ffe40b3SMatthew Dillon 		break;
3370ffe40b3SMatthew Dillon 
3380ffe40b3SMatthew Dillon 	case WRITEBOOT:
3390ffe40b3SMatthew Dillon 	{
3400ffe40b3SMatthew Dillon 		struct disklabel64 tlab;
3410ffe40b3SMatthew Dillon 
3420ffe40b3SMatthew Dillon 		lp = readlabel(f);
3430ffe40b3SMatthew Dillon 		tlab = *lp;
3440ffe40b3SMatthew Dillon 		if (argc == 2)
3450ffe40b3SMatthew Dillon 			makelabel(argv[1], 0, &lab);
3460ffe40b3SMatthew Dillon 		lp = makebootarea(f);
3470ffe40b3SMatthew Dillon 		bcopy(&tlab.d_magic, &lp->d_magic,
3480ffe40b3SMatthew Dillon 		      sizeof(tlab) - offsetof(struct disklabel64, d_magic));
3490ffe40b3SMatthew Dillon 		if (checklabel(lp) == 0)
3500ffe40b3SMatthew Dillon 			error = writelabel(f, lp);
3510ffe40b3SMatthew Dillon 		break;
3520ffe40b3SMatthew Dillon 	}
3530ffe40b3SMatthew Dillon 	}
3540ffe40b3SMatthew Dillon 	exit(error);
3550ffe40b3SMatthew Dillon }
3560ffe40b3SMatthew Dillon 
3570ffe40b3SMatthew Dillon /*
3580ffe40b3SMatthew Dillon  * Construct a prototype disklabel from /etc/disktab.  As a side
3590ffe40b3SMatthew Dillon  * effect, set the names of the primary and secondary boot files
3600ffe40b3SMatthew Dillon  * if specified.
3610ffe40b3SMatthew Dillon  */
3620a319615SMatthew Dillon static void
makelabel(const char * type,const char * name,struct disklabel64 * lp)3630ffe40b3SMatthew Dillon makelabel(const char *type, const char *name, struct disklabel64 *lp)
3640ffe40b3SMatthew Dillon {
3650ffe40b3SMatthew Dillon 	struct disklabel64 *dp;
3660ffe40b3SMatthew Dillon 
36787b121bbSAaron LI 	if (streq(type, "auto"))
3680ffe40b3SMatthew Dillon 		dp = getvirginlabel();
3690ffe40b3SMatthew Dillon 	else
3700a319615SMatthew Dillon 		errx(1, "no disktab(5) support yet; only 'auto' allowed");
3710ffe40b3SMatthew Dillon 	*lp = *dp;
3720ffe40b3SMatthew Dillon 
3730ffe40b3SMatthew Dillon 	if (name)
3740a319615SMatthew Dillon 		strlcpy((char *)lp->d_packname, name, sizeof(lp->d_packname));
3750ffe40b3SMatthew Dillon }
3760ffe40b3SMatthew Dillon 
3770a319615SMatthew Dillon static int
writelabel(int f,struct disklabel64 * lp)3780ffe40b3SMatthew Dillon writelabel(int f, struct disklabel64 *lp)
3790ffe40b3SMatthew Dillon {
3800ffe40b3SMatthew Dillon 	struct disklabel64 *blp;
3810ffe40b3SMatthew Dillon 	int flag;
3820ffe40b3SMatthew Dillon 	int r;
3830ffe40b3SMatthew Dillon 	size_t lpsize;
3840ffe40b3SMatthew Dillon 	size_t lpcrcsize;
3850ffe40b3SMatthew Dillon 
3860ffe40b3SMatthew Dillon 	lpsize = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
3870ffe40b3SMatthew Dillon 	lpcrcsize = lpsize - offsetof(struct disklabel64, d_magic);
3880ffe40b3SMatthew Dillon 
3890ffe40b3SMatthew Dillon 	if (disable_write) {
3900ca0cd25SSascha Wildner 		Warning("write to disk label suppressed - label was as follows:");
3910ffe40b3SMatthew Dillon 		display(stdout, lp);
3920ffe40b3SMatthew Dillon 		return (0);
3930ffe40b3SMatthew Dillon 	} else {
3940ffe40b3SMatthew Dillon 		lp->d_magic = DISKMAGIC64;
3950ffe40b3SMatthew Dillon 		lp->d_crc = 0;
3960ffe40b3SMatthew Dillon 		lp->d_crc = crc32(&lp->d_magic, lpcrcsize);
3970ffe40b3SMatthew Dillon 		if (rflag) {
3980ffe40b3SMatthew Dillon 			/*
3990ffe40b3SMatthew Dillon 			 * Make sure the boot area is not too large
4000ffe40b3SMatthew Dillon 			 */
4010ffe40b3SMatthew Dillon 			if (boot2buf) {
4020ffe40b3SMatthew Dillon 				int lpbsize = (int)(lp->d_pbase - lp->d_bbase);
4030ffe40b3SMatthew Dillon 				if (lp->d_pbase == 0) {
4040ffe40b3SMatthew Dillon 					errx(1, "no space was set aside in "
4050ffe40b3SMatthew Dillon 						"the disklabel for boot2!");
4060ffe40b3SMatthew Dillon 				}
4070ffe40b3SMatthew Dillon 				if (boot2size > lpbsize) {
4080ffe40b3SMatthew Dillon 					errx(1, "label did not reserve enough "
4090ffe40b3SMatthew Dillon 						"space for boot!  %d/%d",
4100ffe40b3SMatthew Dillon 					     boot2size, lpbsize);
4110ffe40b3SMatthew Dillon 				}
4120ffe40b3SMatthew Dillon 			}
4130ffe40b3SMatthew Dillon 
4140ffe40b3SMatthew Dillon 			/*
4150ffe40b3SMatthew Dillon 			 * First set the kernel disk label,
4160ffe40b3SMatthew Dillon 			 * then write a label to the raw disk.
4170ffe40b3SMatthew Dillon 			 * If the SDINFO ioctl fails because it is
4180ffe40b3SMatthew Dillon 			 * unimplemented, keep going; otherwise, the kernel
4190ffe40b3SMatthew Dillon 			 * consistency checks may prevent us from changing
4200ffe40b3SMatthew Dillon 			 * the current (in-core) label.
4210ffe40b3SMatthew Dillon 			 */
4220ffe40b3SMatthew Dillon 			if (ioctl(f, DIOCSDINFO64, lp) < 0 &&
4230ffe40b3SMatthew Dillon 				errno != ENODEV && errno != ENOTTY) {
4240ffe40b3SMatthew Dillon 				l_perror("ioctl DIOCSDINFO");
4250ffe40b3SMatthew Dillon 				return (1);
4260ffe40b3SMatthew Dillon 			}
4270ffe40b3SMatthew Dillon 			lseek(f, (off_t)0, SEEK_SET);
4280ffe40b3SMatthew Dillon 
4290ffe40b3SMatthew Dillon 			/*
4300ffe40b3SMatthew Dillon 			 * The disklabel embeds areas which we may not
4310ffe40b3SMatthew Dillon 			 * have wanted to change.  Merge those areas in
4320ffe40b3SMatthew Dillon 			 * from disk.
4330ffe40b3SMatthew Dillon 			 */
4340ffe40b3SMatthew Dillon 			blp = makebootarea(f);
4350ffe40b3SMatthew Dillon 			if (blp != lp) {
4360ffe40b3SMatthew Dillon 				bcopy(&lp->d_magic, &blp->d_magic,
4370ffe40b3SMatthew Dillon 				      sizeof(*lp) -
4380ffe40b3SMatthew Dillon 				      offsetof(struct disklabel64, d_magic));
4390ffe40b3SMatthew Dillon 			}
4400ffe40b3SMatthew Dillon 
4410ffe40b3SMatthew Dillon 			/*
4420ffe40b3SMatthew Dillon 			 * write enable label sector before write
4430ffe40b3SMatthew Dillon 			 * (if necessary), disable after writing.
4440ffe40b3SMatthew Dillon 			 */
4450ffe40b3SMatthew Dillon 			flag = 1;
4460ffe40b3SMatthew Dillon 			if (ioctl(f, DIOCWLABEL, &flag) < 0)
4470ffe40b3SMatthew Dillon 				warn("ioctl DIOCWLABEL");
4480ffe40b3SMatthew Dillon 
4490ffe40b3SMatthew Dillon 			r = write(f, boot1buf, boot1lsize);
4500ffe40b3SMatthew Dillon 			if (r != (ssize_t)boot1lsize) {
4510ffe40b3SMatthew Dillon 				warn("write");
4520ffe40b3SMatthew Dillon 				return (1);
4530ffe40b3SMatthew Dillon 			}
4540ffe40b3SMatthew Dillon 			/*
4550ffe40b3SMatthew Dillon 			 * Output the remainder of the disklabel
4560ffe40b3SMatthew Dillon 			 */
4570ffe40b3SMatthew Dillon 			if (boot2buf) {
4580ffe40b3SMatthew Dillon 				lseek(f, lp->d_bbase, 0);
4590ffe40b3SMatthew Dillon 				r = write(f, boot2buf, boot2size);
4600ffe40b3SMatthew Dillon 				if (r != boot2size) {
4610ffe40b3SMatthew Dillon 					warn("write");
4620ffe40b3SMatthew Dillon 					return(1);
4630ffe40b3SMatthew Dillon 				}
4640ffe40b3SMatthew Dillon 			}
4650ffe40b3SMatthew Dillon 			flag = 0;
4660ffe40b3SMatthew Dillon 			ioctl(f, DIOCWLABEL, &flag);
4670ffe40b3SMatthew Dillon 		} else if (ioctl(f, DIOCWDINFO64, lp) < 0) {
4680ffe40b3SMatthew Dillon 			l_perror("ioctl DIOCWDINFO64");
4690ffe40b3SMatthew Dillon 			return (1);
4700ffe40b3SMatthew Dillon 		}
4710ffe40b3SMatthew Dillon 	}
4720ffe40b3SMatthew Dillon 	return (0);
4730ffe40b3SMatthew Dillon }
4740ffe40b3SMatthew Dillon 
4750a319615SMatthew Dillon static void
l_perror(const char * s)4760ffe40b3SMatthew Dillon l_perror(const char *s)
4770ffe40b3SMatthew Dillon {
4780ffe40b3SMatthew Dillon 	switch (errno) {
4790ffe40b3SMatthew Dillon 
4800ffe40b3SMatthew Dillon 	case ESRCH:
4810ffe40b3SMatthew Dillon 		warnx("%s: no disk label on disk;", s);
4820ffe40b3SMatthew Dillon 		fprintf(stderr, "add \"-r\" to install initial label\n");
4830ffe40b3SMatthew Dillon 		break;
4840ffe40b3SMatthew Dillon 
4850ffe40b3SMatthew Dillon 	case EINVAL:
4860ffe40b3SMatthew Dillon 		warnx("%s: label magic number or checksum is wrong!", s);
4870ffe40b3SMatthew Dillon 		fprintf(stderr, "(disklabel or kernel is out of date?)\n");
4880ffe40b3SMatthew Dillon 		break;
4890ffe40b3SMatthew Dillon 
4900ffe40b3SMatthew Dillon 	case EBUSY:
4910ffe40b3SMatthew Dillon 		warnx("%s: open partition would move or shrink", s);
4920ffe40b3SMatthew Dillon 		break;
4930ffe40b3SMatthew Dillon 
4940ffe40b3SMatthew Dillon 	case ENOATTR:
4950ffe40b3SMatthew Dillon 		warnx("%s: the disk already has a label of a different type,\n"
4960ffe40b3SMatthew Dillon 		      "probably a 32 bit disklabel.  It must be cleaned out "
4970ffe40b3SMatthew Dillon 		      "first.\n", s);
4980ffe40b3SMatthew Dillon 		break;
4990ffe40b3SMatthew Dillon 
5000ffe40b3SMatthew Dillon 	default:
5012038fb68SSascha Wildner 		warn(NULL);
5020ffe40b3SMatthew Dillon 		break;
5030ffe40b3SMatthew Dillon 	}
5040ffe40b3SMatthew Dillon }
5050ffe40b3SMatthew Dillon 
5060ffe40b3SMatthew Dillon /*
5070ffe40b3SMatthew Dillon  * Fetch disklabel for disk.
5080ffe40b3SMatthew Dillon  * Use ioctl to get label unless -r flag is given.
5090ffe40b3SMatthew Dillon  */
5100a319615SMatthew Dillon static struct disklabel64 *
readlabel(int f)5110ffe40b3SMatthew Dillon readlabel(int f)
5120ffe40b3SMatthew Dillon {
5130ffe40b3SMatthew Dillon 	struct disklabel64 *lp;
5140ffe40b3SMatthew Dillon 	u_int32_t savecrc;
5150ffe40b3SMatthew Dillon 	size_t lpcrcsize;
5160ffe40b3SMatthew Dillon 
5170ffe40b3SMatthew Dillon 	if (rflag) {
5180ffe40b3SMatthew Dillon 		/*
5190ffe40b3SMatthew Dillon 		 * Allocate space for the label.  The boot1 code, if any,
5200ffe40b3SMatthew Dillon 		 * is embedded in the label.  The label overlaps the boot1
5210ffe40b3SMatthew Dillon 		 * code.
5220ffe40b3SMatthew Dillon 		 */
5230ffe40b3SMatthew Dillon 		lp = makebootarea(f);
5240ffe40b3SMatthew Dillon 		lpcrcsize = offsetof(struct disklabel64,
5250ffe40b3SMatthew Dillon 				     d_partitions[lp->d_npartitions]) -
5260ffe40b3SMatthew Dillon 			    offsetof(struct disklabel64, d_magic);
5270ffe40b3SMatthew Dillon 		savecrc = lp->d_crc;
5280ffe40b3SMatthew Dillon 		lp->d_crc = 0;
5290ffe40b3SMatthew Dillon 		if (lp->d_magic != DISKMAGIC64)
5300ffe40b3SMatthew Dillon 			errx(1, "bad pack magic number");
5310ffe40b3SMatthew Dillon 		if (lp->d_npartitions > MAXPARTITIONS64 ||
5320ffe40b3SMatthew Dillon 		    savecrc != crc32(&lp->d_magic, lpcrcsize)
5330ffe40b3SMatthew Dillon 		) {
5340ffe40b3SMatthew Dillon 			errx(1, "corrupted disklabel64");
5350ffe40b3SMatthew Dillon 		}
5360ffe40b3SMatthew Dillon 		lp->d_crc = savecrc;
5370ffe40b3SMatthew Dillon 	} else {
5380ffe40b3SMatthew Dillon 		/*
5390ffe40b3SMatthew Dillon 		 * Just use a static structure to hold the label.  Note
5400ffe40b3SMatthew Dillon 		 * that DIOCSDINFO64 does not overwrite the boot1 area
5410ffe40b3SMatthew Dillon 		 * even though it is part of the disklabel64 structure.
5420ffe40b3SMatthew Dillon 		 */
5430ffe40b3SMatthew Dillon 		lp = &lab;
5440ffe40b3SMatthew Dillon 		if (Vflag) {
5450ffe40b3SMatthew Dillon 			if (ioctl(f, DIOCGDVIRGIN64, lp) < 0) {
5460ffe40b3SMatthew Dillon 				l_perror("ioctl DIOCGDVIRGIN64");
5470ffe40b3SMatthew Dillon 				exit(4);
5480ffe40b3SMatthew Dillon 			}
5490ffe40b3SMatthew Dillon 		} else {
5500ffe40b3SMatthew Dillon 			if (ioctl(f, DIOCGDINFO64, lp) < 0) {
5510ffe40b3SMatthew Dillon 				l_perror("ioctl DIOCGDINFO64");
5520ffe40b3SMatthew Dillon 				exit(4);
5530ffe40b3SMatthew Dillon 			}
5540ffe40b3SMatthew Dillon 		}
5550ffe40b3SMatthew Dillon 	}
5560ffe40b3SMatthew Dillon 	return (lp);
5570ffe40b3SMatthew Dillon }
5580ffe40b3SMatthew Dillon 
5590ffe40b3SMatthew Dillon /*
5600ffe40b3SMatthew Dillon  * Construct a boot area for boot1 and boot2 and return the location of
5610ffe40b3SMatthew Dillon  * the label within the area.  The caller will overwrite the label so
5620ffe40b3SMatthew Dillon  * we don't actually have to read it.
5630ffe40b3SMatthew Dillon  */
5640a319615SMatthew Dillon static struct disklabel64 *
makebootarea(int f)5650ffe40b3SMatthew Dillon makebootarea(int f)
5660ffe40b3SMatthew Dillon {
5670ffe40b3SMatthew Dillon 	struct disklabel64 *lp;
5680ffe40b3SMatthew Dillon 	struct partinfo info;
5690ffe40b3SMatthew Dillon 	u_int32_t secsize;
5700ffe40b3SMatthew Dillon 	struct stat st;
5710ffe40b3SMatthew Dillon 	int fd;
5720ffe40b3SMatthew Dillon 	int r;
5730ffe40b3SMatthew Dillon 
5740ffe40b3SMatthew Dillon 	if (ioctl(f, DIOCGPART, &info) == 0)
5750ffe40b3SMatthew Dillon 		secsize = info.media_blksize;
5760ffe40b3SMatthew Dillon 	else
5770ffe40b3SMatthew Dillon 		secsize = 512;
5780ffe40b3SMatthew Dillon 
5790ffe40b3SMatthew Dillon 	if (boot1buf == NULL) {
5800ffe40b3SMatthew Dillon 		size_t rsize;
5810ffe40b3SMatthew Dillon 
582965b839fSSascha Wildner 		rsize = roundup2(sizeof(struct disklabel64), secsize);
5830ffe40b3SMatthew Dillon 		boot1size = offsetof(struct disklabel64, d_magic);
5840ffe40b3SMatthew Dillon 		boot1lsize = rsize;
5850ffe40b3SMatthew Dillon 		boot1buf = malloc(rsize);
5860ffe40b3SMatthew Dillon 		bzero(boot1buf, rsize);
5870ffe40b3SMatthew Dillon 		r = read(f, boot1buf, rsize);
5880a319615SMatthew Dillon 		if (r != (int)rsize) {
5890a319615SMatthew Dillon 			free(boot1buf);
5900ffe40b3SMatthew Dillon 			err(4, "%s", specname);
5910ffe40b3SMatthew Dillon 		}
5920a319615SMatthew Dillon 	}
5930ffe40b3SMatthew Dillon 	lp = (void *)boot1buf;
5940ffe40b3SMatthew Dillon 
5950ffe40b3SMatthew Dillon 	if (installboot == 0)
5960ffe40b3SMatthew Dillon 		return(lp);
5970ffe40b3SMatthew Dillon 
5980ffe40b3SMatthew Dillon 	if (boot2buf == NULL) {
5990a319615SMatthew Dillon 		boot2size = BOOT2SIZE64;
6000ffe40b3SMatthew Dillon 		boot2buf = malloc(boot2size);
6010ffe40b3SMatthew Dillon 		bzero(boot2buf, boot2size);
6020ffe40b3SMatthew Dillon 	}
6030ffe40b3SMatthew Dillon 
6040ffe40b3SMatthew Dillon 	/*
6050ffe40b3SMatthew Dillon 	 * If installing the boot code, read it into the appropriate portions
6060ffe40b3SMatthew Dillon 	 * of the buffer(s)
6070ffe40b3SMatthew Dillon 	 */
6080ffe40b3SMatthew Dillon 	if (boot1path == NULL)
6090ffe40b3SMatthew Dillon 		asprintf(&boot1path, "%s/boot1_64", _PATH_BOOTDIR);
6100ffe40b3SMatthew Dillon 	if (boot2path == NULL)
6110ffe40b3SMatthew Dillon 		asprintf(&boot2path, "%s/boot2_64", _PATH_BOOTDIR);
6120ffe40b3SMatthew Dillon 
6130ffe40b3SMatthew Dillon 	if ((fd = open(boot1path, O_RDONLY)) < 0)
6140ffe40b3SMatthew Dillon 		err(4, "%s", boot1path);
6150ffe40b3SMatthew Dillon 	if (fstat(fd, &st) < 0)
6160ffe40b3SMatthew Dillon 		err(4, "%s", boot1path);
6170ffe40b3SMatthew Dillon 	if (st.st_size > boot1size)
6180ffe40b3SMatthew Dillon 		err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
6190ffe40b3SMatthew Dillon 	if (read(fd, boot1buf, boot1size) != boot1size)
6200ffe40b3SMatthew Dillon 		err(4, "%s must be exactly %d bytes!", boot1path, boot1size);
6210ffe40b3SMatthew Dillon 	close(fd);
6220ffe40b3SMatthew Dillon 
6230ffe40b3SMatthew Dillon 	if ((fd = open(boot2path, O_RDONLY)) < 0)
6240ffe40b3SMatthew Dillon 		err(4, "%s", boot2path);
6250ffe40b3SMatthew Dillon 	if (fstat(fd, &st) < 0)
6260ffe40b3SMatthew Dillon 		err(4, "%s", boot2path);
6270ffe40b3SMatthew Dillon 	if (st.st_size > boot2size)
6280ffe40b3SMatthew Dillon 		err(4, "%s must be <= %d bytes!", boot2path, boot2size);
6290ffe40b3SMatthew Dillon 	if ((r = read(fd, boot2buf, boot2size)) < 1)
6300ffe40b3SMatthew Dillon 		err(4, "%s is empty!", boot2path);
631965b839fSSascha Wildner 	boot2size = roundup2(r, secsize);
6320ffe40b3SMatthew Dillon 	close(fd);
6330ffe40b3SMatthew Dillon 
6340ffe40b3SMatthew Dillon 	/*
6350ffe40b3SMatthew Dillon 	 * XXX dangerously dedicated support goes here XXX
6360ffe40b3SMatthew Dillon 	 */
6370ffe40b3SMatthew Dillon 	return (lp);
6380ffe40b3SMatthew Dillon }
6390ffe40b3SMatthew Dillon 
6400a319615SMatthew Dillon static void
display(FILE * f,const struct disklabel64 * lp)6410ffe40b3SMatthew Dillon display(FILE *f, const struct disklabel64 *lp)
6420ffe40b3SMatthew Dillon {
6430ffe40b3SMatthew Dillon 	const struct partition64 *pp;
6440ffe40b3SMatthew Dillon 	char *str;
6450ffe40b3SMatthew Dillon 	unsigned int part;
6460ffe40b3SMatthew Dillon 	int didany;
6470ffe40b3SMatthew Dillon 	uint32_t blksize;
6480ffe40b3SMatthew Dillon 
6490ffe40b3SMatthew Dillon 	/*
6500ffe40b3SMatthew Dillon 	 * Use a human readable block size if possible.  This is for
6510ffe40b3SMatthew Dillon 	 * display and editing purposes only.
6520ffe40b3SMatthew Dillon 	 */
6530ffe40b3SMatthew Dillon 	if (lp->d_align > 1024)
6540ffe40b3SMatthew Dillon 		blksize = 1024;
6550ffe40b3SMatthew Dillon 	else
6560ffe40b3SMatthew Dillon 		blksize = lp->d_align;
6570ffe40b3SMatthew Dillon 
6580ffe40b3SMatthew Dillon 	fprintf(f, "# %s:\n", specname);
6590ffe40b3SMatthew Dillon 	fprintf(f, "#\n");
6600a319615SMatthew Dillon 	fprintf(f, "# Calculated informational fields for the slice:\n");
6610ffe40b3SMatthew Dillon 	fprintf(f, "#\n");
662a276dc6bSMatthew Dillon 	fprintf(f, "# boot space: %10ju bytes\n",
6631f5e0b99SSascha Wildner 		(uintmax_t)(lp->d_pbase - lp->d_bbase));
664a276dc6bSMatthew Dillon 	fprintf(f, "# data space: %10ju blocks\t# %6.2f MB (%ju bytes)\n",
6651f5e0b99SSascha Wildner 			(uintmax_t)(lp->d_pstop - lp->d_pbase) / blksize,
6660ffe40b3SMatthew Dillon 			(double)(lp->d_pstop - lp->d_pbase) / 1024.0 / 1024.0,
6671f5e0b99SSascha Wildner 			(uintmax_t)(lp->d_pstop - lp->d_pbase));
6680ffe40b3SMatthew Dillon 	fprintf(f, "#\n");
6690a319615SMatthew Dillon 	fprintf(f, "# NOTE: The partition data base and stop are physically\n");
6700a319615SMatthew Dillon 	fprintf(f, "#       aligned instead of slice-relative aligned.\n");
6710a319615SMatthew Dillon 	fprintf(f, "#\n");
6720a319615SMatthew Dillon 	fprintf(f, "# All byte equivalent offsets must be aligned.\n");
6735179f0c5SMatthew Dillon 	fprintf(f, "#\n");
6740ffe40b3SMatthew Dillon 
675529d55c9SMatthew Dillon 	uuid_to_string(&lp->d_stor_uuid, &str, NULL);
6760ffe40b3SMatthew Dillon 	fprintf(f, "diskid: %s\n", str ? str : "<unknown>");
6770ffe40b3SMatthew Dillon 	free(str);
6780ffe40b3SMatthew Dillon 
6790a319615SMatthew Dillon 	fprintf(f, "label: %s\n", lp->d_packname);
6801f5e0b99SSascha Wildner 	fprintf(f, "boot2 data base:      0x%012jx\n", (uintmax_t)lp->d_bbase);
6811f5e0b99SSascha Wildner 	fprintf(f, "partitions data base: 0x%012jx\n", (uintmax_t)lp->d_pbase);
6821f5e0b99SSascha Wildner 	fprintf(f, "partitions data stop: 0x%012jx\n", (uintmax_t)lp->d_pstop);
6831f5e0b99SSascha Wildner 	fprintf(f, "backup label:         0x%012jx\n", (uintmax_t)lp->d_abase);
684a276dc6bSMatthew Dillon 	fprintf(f, "total size:           0x%012jx\t# %6.2f MB\n",
6851f5e0b99SSascha Wildner 		(uintmax_t)lp->d_total_size,
6860ffe40b3SMatthew Dillon 		(double)lp->d_total_size / 1024.0 / 1024.0);
6870ffe40b3SMatthew Dillon 	fprintf(f, "alignment: %u\n", lp->d_align);
6880a319615SMatthew Dillon 	fprintf(f, "display block size: %u\t# for partition display and edit only\n",
6890ffe40b3SMatthew Dillon 		blksize);
6900ffe40b3SMatthew Dillon 
6910ffe40b3SMatthew Dillon 	fprintf(f, "\n");
6920ffe40b3SMatthew Dillon 	fprintf(f, "%u partitions:\n", lp->d_npartitions);
6930ffe40b3SMatthew Dillon 	fprintf(f, "#          size     offset    fstype   fsuuid\n");
6940ffe40b3SMatthew Dillon 	didany = 0;
695529d55c9SMatthew Dillon 	for (part = 0; part < lp->d_npartitions; part++) {
696529d55c9SMatthew Dillon 		pp = &lp->d_partitions[part];
6970ffe40b3SMatthew Dillon 		const u_long onemeg = 1024 * 1024;
698529d55c9SMatthew Dillon 
6990ffe40b3SMatthew Dillon 		if (pp->p_bsize == 0)
7000ffe40b3SMatthew Dillon 			continue;
7010ffe40b3SMatthew Dillon 		didany = 1;
7020ffe40b3SMatthew Dillon 		fprintf(f, "  %c: ", 'a' + part);
7030ffe40b3SMatthew Dillon 
7040ffe40b3SMatthew Dillon 		if (pp->p_bsize % lp->d_align)
7050ffe40b3SMatthew Dillon 		    fprintf(f, "%10s  ", "ILLEGAL");
7060ffe40b3SMatthew Dillon 		else
7071f5e0b99SSascha Wildner 		    fprintf(f, "%10ju ", (uintmax_t)pp->p_bsize / blksize);
7085179f0c5SMatthew Dillon 
7095179f0c5SMatthew Dillon 		if ((pp->p_boffset - lp->d_pbase) % lp->d_align)
7100ffe40b3SMatthew Dillon 		    fprintf(f, "%10s  ", "ILLEGAL");
7110ffe40b3SMatthew Dillon 		else
712a276dc6bSMatthew Dillon 		    fprintf(f, "%10ju  ",
7131f5e0b99SSascha Wildner 			    (uintmax_t)(pp->p_boffset - lp->d_pbase) / blksize);
7145179f0c5SMatthew Dillon 
7150ffe40b3SMatthew Dillon 		if (pp->p_fstype < FSMAXTYPES)
7160ffe40b3SMatthew Dillon 			fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);
7170ffe40b3SMatthew Dillon 		else
7180ffe40b3SMatthew Dillon 			fprintf(f, "%8d", pp->p_fstype);
71980818344SThomas Nikolajsen 		fprintf(f, "\t# %11.3fMB", (double)pp->p_bsize / onemeg);
7200ffe40b3SMatthew Dillon 		fprintf(f, "\n");
7210ffe40b3SMatthew Dillon 	}
722529d55c9SMatthew Dillon 	for (part = 0; part < lp->d_npartitions; part++) {
723529d55c9SMatthew Dillon 		pp = &lp->d_partitions[part];
724529d55c9SMatthew Dillon 
725529d55c9SMatthew Dillon 		if (pp->p_bsize == 0)
726529d55c9SMatthew Dillon 			continue;
727529d55c9SMatthew Dillon 
728529d55c9SMatthew Dillon 		if (uuid_is_nil(&lp->d_stor_uuid, NULL) == 0) {
729529d55c9SMatthew Dillon 			fprintf(f, "  %c-stor_uuid: ", 'a' + part);
730529d55c9SMatthew Dillon 			str = NULL;
731529d55c9SMatthew Dillon 			uuid_to_string(&pp->p_stor_uuid, &str, NULL);
732529d55c9SMatthew Dillon 			if (str) {
733529d55c9SMatthew Dillon 				fprintf(f, "%s", str);
734529d55c9SMatthew Dillon 				free(str);
735529d55c9SMatthew Dillon 			}
736529d55c9SMatthew Dillon 			fprintf(f, "\n");
737529d55c9SMatthew Dillon 		}
738529d55c9SMatthew Dillon 	}
7390ffe40b3SMatthew Dillon 	if (didany == 0) {
7400ffe40b3SMatthew Dillon 		fprintf(f, "# EXAMPLE\n");
7410ffe40b3SMatthew Dillon 		fprintf(f, "#a:          4g          0    4.2BSD\n");
742529d55c9SMatthew Dillon 		fprintf(f, "#a:          *           *    4.2BSD\n");
7430ffe40b3SMatthew Dillon 
7440ffe40b3SMatthew Dillon 	}
7450ffe40b3SMatthew Dillon 	fflush(f);
7460ffe40b3SMatthew Dillon }
7470ffe40b3SMatthew Dillon 
7480a319615SMatthew Dillon static int
edit(struct disklabel64 * lp,int f)7490ffe40b3SMatthew Dillon edit(struct disklabel64 *lp, int f)
7500ffe40b3SMatthew Dillon {
7510ffe40b3SMatthew Dillon 	int c, fd;
7520ffe40b3SMatthew Dillon 	struct disklabel64 label;
7530ffe40b3SMatthew Dillon 	FILE *fp;
7540ffe40b3SMatthew Dillon 
7550ffe40b3SMatthew Dillon 	if ((fd = mkstemp(tmpfil)) == -1 ||
7560ffe40b3SMatthew Dillon 	    (fp = fdopen(fd, "w")) == NULL) {
7570ffe40b3SMatthew Dillon 		warnx("can't create %s", tmpfil);
7580ffe40b3SMatthew Dillon 		return (1);
7590ffe40b3SMatthew Dillon 	}
7600ffe40b3SMatthew Dillon 	display(fp, lp);
7610ffe40b3SMatthew Dillon 	fclose(fp);
7620ffe40b3SMatthew Dillon 	for (;;) {
7630ffe40b3SMatthew Dillon 		if (!editit())
7640ffe40b3SMatthew Dillon 			break;
7650ffe40b3SMatthew Dillon 		fp = fopen(tmpfil, "r");
7660ffe40b3SMatthew Dillon 		if (fp == NULL) {
7670ffe40b3SMatthew Dillon 			warnx("can't reopen %s for reading", tmpfil);
7680ffe40b3SMatthew Dillon 			break;
7690ffe40b3SMatthew Dillon 		}
7700ffe40b3SMatthew Dillon 		bzero((char *)&label, sizeof(label));
7710ffe40b3SMatthew Dillon 		if (getasciilabel(fp, &label)) {
7720ffe40b3SMatthew Dillon 			*lp = label;
7730ffe40b3SMatthew Dillon 			if (writelabel(f, lp) == 0) {
7740ffe40b3SMatthew Dillon 				fclose(fp);
7750ffe40b3SMatthew Dillon 				unlink(tmpfil);
7760ffe40b3SMatthew Dillon 				return (0);
7770ffe40b3SMatthew Dillon 			}
7780ffe40b3SMatthew Dillon 		}
7790ffe40b3SMatthew Dillon 		fclose(fp);
7800ffe40b3SMatthew Dillon 		printf("re-edit the label? [y]: "); fflush(stdout);
7810ffe40b3SMatthew Dillon 		c = getchar();
7820ffe40b3SMatthew Dillon 		if (c != EOF && c != (int)'\n')
7830ffe40b3SMatthew Dillon 			while (getchar() != (int)'\n')
7840ffe40b3SMatthew Dillon 				;
7850ffe40b3SMatthew Dillon 		if  (c == (int)'n')
7860ffe40b3SMatthew Dillon 			break;
7870ffe40b3SMatthew Dillon 	}
7880ffe40b3SMatthew Dillon 	unlink(tmpfil);
7890ffe40b3SMatthew Dillon 	return (1);
7900ffe40b3SMatthew Dillon }
7910ffe40b3SMatthew Dillon 
7920a319615SMatthew Dillon static int
editit(void)7930ffe40b3SMatthew Dillon editit(void)
7940ffe40b3SMatthew Dillon {
7950ffe40b3SMatthew Dillon 	int pid, xpid;
7960ffe40b3SMatthew Dillon 	int status, omask;
7970ffe40b3SMatthew Dillon 	const char *ed;
7980ffe40b3SMatthew Dillon 
7990ffe40b3SMatthew Dillon 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
8000ffe40b3SMatthew Dillon 	while ((pid = fork()) < 0) {
8010ffe40b3SMatthew Dillon 		if (errno == EPROCLIM) {
8020ffe40b3SMatthew Dillon 			warnx("you have too many processes");
8030ffe40b3SMatthew Dillon 			return(0);
8040ffe40b3SMatthew Dillon 		}
8050ffe40b3SMatthew Dillon 		if (errno != EAGAIN) {
8060ffe40b3SMatthew Dillon 			warn("fork");
8070ffe40b3SMatthew Dillon 			return(0);
8080ffe40b3SMatthew Dillon 		}
8090ffe40b3SMatthew Dillon 		sleep(1);
8100ffe40b3SMatthew Dillon 	}
8110ffe40b3SMatthew Dillon 	if (pid == 0) {
8120ffe40b3SMatthew Dillon 		sigsetmask(omask);
8130ffe40b3SMatthew Dillon 		setgid(getgid());
8140ffe40b3SMatthew Dillon 		setuid(getuid());
81560233e58SSascha Wildner 		if ((ed = getenv("EDITOR")) == NULL)
8160ffe40b3SMatthew Dillon 			ed = DEFEDITOR;
81760233e58SSascha Wildner 		execlp(ed, ed, tmpfil, NULL);
8180ffe40b3SMatthew Dillon 		err(1, "%s", ed);
8190ffe40b3SMatthew Dillon 	}
8200ffe40b3SMatthew Dillon 	while ((xpid = wait(&status)) >= 0)
8210ffe40b3SMatthew Dillon 		if (xpid == pid)
8220ffe40b3SMatthew Dillon 			break;
8230ffe40b3SMatthew Dillon 	sigsetmask(omask);
8240ffe40b3SMatthew Dillon 	return(!status);
8250ffe40b3SMatthew Dillon }
8260ffe40b3SMatthew Dillon 
8270a319615SMatthew Dillon static char *
skip(char * cp)8280ffe40b3SMatthew Dillon skip(char *cp)
8290ffe40b3SMatthew Dillon {
8300ffe40b3SMatthew Dillon 
8310ffe40b3SMatthew Dillon 	while (*cp != '\0' && isspace(*cp))
8320ffe40b3SMatthew Dillon 		cp++;
8330ffe40b3SMatthew Dillon 	if (*cp == '\0' || *cp == '#')
8340ffe40b3SMatthew Dillon 		return (NULL);
8350ffe40b3SMatthew Dillon 	return (cp);
8360ffe40b3SMatthew Dillon }
8370ffe40b3SMatthew Dillon 
8380a319615SMatthew Dillon static char *
word(char * cp)8390ffe40b3SMatthew Dillon word(char *cp)
8400ffe40b3SMatthew Dillon {
8410ffe40b3SMatthew Dillon 	char c;
8420ffe40b3SMatthew Dillon 
8430ffe40b3SMatthew Dillon 	while (*cp != '\0' && !isspace(*cp) && *cp != '#')
8440ffe40b3SMatthew Dillon 		cp++;
8450ffe40b3SMatthew Dillon 	if ((c = *cp) != '\0') {
8460ffe40b3SMatthew Dillon 		*cp++ = '\0';
8470ffe40b3SMatthew Dillon 		if (c != '#')
8480ffe40b3SMatthew Dillon 			return (skip(cp));
8490ffe40b3SMatthew Dillon 	}
8500ffe40b3SMatthew Dillon 	return (NULL);
8510ffe40b3SMatthew Dillon }
8520ffe40b3SMatthew Dillon 
8530ffe40b3SMatthew Dillon /*
8540ffe40b3SMatthew Dillon  * Read an ascii label in from fd f,
8550ffe40b3SMatthew Dillon  * in the same format as that put out by display(),
8560ffe40b3SMatthew Dillon  * and fill in lp.
8570ffe40b3SMatthew Dillon  */
8580a319615SMatthew Dillon static int
getasciilabel(FILE * f,struct disklabel64 * lp)8590ffe40b3SMatthew Dillon getasciilabel(FILE *f, struct disklabel64 *lp)
8600ffe40b3SMatthew Dillon {
8610ffe40b3SMatthew Dillon 	char *cp;
8620ffe40b3SMatthew Dillon 	u_int part;
8630ffe40b3SMatthew Dillon 	char *tp, line[BUFSIZ];
8640ffe40b3SMatthew Dillon 	u_long v;
8650ffe40b3SMatthew Dillon 	uint32_t blksize = 0;
8660ffe40b3SMatthew Dillon 	uint64_t vv;
8670ffe40b3SMatthew Dillon 	int lineno = 0, errors = 0;
8680ffe40b3SMatthew Dillon 	char empty[] = "";
8690ffe40b3SMatthew Dillon 
8700ffe40b3SMatthew Dillon 	bzero(&part_set, sizeof(part_set));
8710ffe40b3SMatthew Dillon 	bzero(&part_size_type, sizeof(part_size_type));
8720ffe40b3SMatthew Dillon 	bzero(&part_offset_type, sizeof(part_offset_type));
8730ffe40b3SMatthew Dillon 	while (fgets(line, sizeof(line) - 1, f)) {
8740ffe40b3SMatthew Dillon 		lineno++;
875678e8cc6SSascha Wildner 		if ((cp = strchr(line,'\n')) != NULL)
8760ffe40b3SMatthew Dillon 			*cp = '\0';
8770ffe40b3SMatthew Dillon 		cp = skip(line);
8780ffe40b3SMatthew Dillon 		if (cp == NULL)
8790ffe40b3SMatthew Dillon 			continue;
8800ffe40b3SMatthew Dillon 		tp = strchr(cp, ':');
8810ffe40b3SMatthew Dillon 		if (tp == NULL) {
8820ffe40b3SMatthew Dillon 			fprintf(stderr, "line %d: syntax error\n", lineno);
8830ffe40b3SMatthew Dillon 			errors++;
8840ffe40b3SMatthew Dillon 			continue;
8850ffe40b3SMatthew Dillon 		}
8860ffe40b3SMatthew Dillon 		*tp++ = '\0', tp = skip(tp);
8870ffe40b3SMatthew Dillon 		if (sscanf(cp, "%lu partitions", &v) == 1) {
8880ffe40b3SMatthew Dillon 			if (v == 0 || v > MAXPARTITIONS64) {
8890ffe40b3SMatthew Dillon 				fprintf(stderr,
8900ffe40b3SMatthew Dillon 				    "line %d: bad # of partitions\n", lineno);
8910ffe40b3SMatthew Dillon 				lp->d_npartitions = MAXPARTITIONS64;
8920ffe40b3SMatthew Dillon 				errors++;
8930ffe40b3SMatthew Dillon 			} else
8940ffe40b3SMatthew Dillon 				lp->d_npartitions = v;
8950ffe40b3SMatthew Dillon 			continue;
8960ffe40b3SMatthew Dillon 		}
8970ffe40b3SMatthew Dillon 		if (tp == NULL)
8980ffe40b3SMatthew Dillon 			tp = empty;
8990ffe40b3SMatthew Dillon 
9000ffe40b3SMatthew Dillon 		if (streq(cp, "diskid")) {
9010ffe40b3SMatthew Dillon 			uint32_t status = 0;
902529d55c9SMatthew Dillon 			uuid_from_string(tp, &lp->d_stor_uuid, &status);
9030ffe40b3SMatthew Dillon 			if (status != uuid_s_ok) {
9040ffe40b3SMatthew Dillon 				fprintf(stderr,
9050ffe40b3SMatthew Dillon 				    "line %d: %s: illegal UUID\n",
9060ffe40b3SMatthew Dillon 				    lineno, tp);
9070ffe40b3SMatthew Dillon 				errors++;
9080ffe40b3SMatthew Dillon 			}
9090ffe40b3SMatthew Dillon 			continue;
9100ffe40b3SMatthew Dillon 		}
9110ffe40b3SMatthew Dillon 		if (streq(cp, "label")) {
9120a319615SMatthew Dillon 			strlcpy((char *)lp->d_packname, tp, sizeof(lp->d_packname));
9130ffe40b3SMatthew Dillon 			continue;
9140ffe40b3SMatthew Dillon 		}
9150ffe40b3SMatthew Dillon 
9160ffe40b3SMatthew Dillon 		if (streq(cp, "alignment")) {
9170ffe40b3SMatthew Dillon 			v = strtoul(tp, NULL, 0);
9180ffe40b3SMatthew Dillon 			if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
9190ffe40b3SMatthew Dillon 				fprintf(stderr,
9200ffe40b3SMatthew Dillon 				    "line %d: %s: bad alignment\n",
9210ffe40b3SMatthew Dillon 				    lineno, tp);
9220ffe40b3SMatthew Dillon 				errors++;
9230ffe40b3SMatthew Dillon 			} else {
9240ffe40b3SMatthew Dillon 				lp->d_align = v;
9250ffe40b3SMatthew Dillon 			}
9260ffe40b3SMatthew Dillon 			continue;
9270ffe40b3SMatthew Dillon 		}
9280ffe40b3SMatthew Dillon 		if (streq(cp, "total size")) {
9290ffe40b3SMatthew Dillon 			vv = strtoull(tp, NULL, 0);
9300ffe40b3SMatthew Dillon 			if (vv == 0 || vv == (uint64_t)-1) {
9310ffe40b3SMatthew Dillon 				fprintf(stderr, "line %d: %s: bad %s\n",
9320ffe40b3SMatthew Dillon 				    lineno, tp, cp);
9330ffe40b3SMatthew Dillon 				errors++;
9340ffe40b3SMatthew Dillon 			} else {
9350ffe40b3SMatthew Dillon 				lp->d_total_size = vv;
9360ffe40b3SMatthew Dillon 			}
9370ffe40b3SMatthew Dillon 			continue;
9380ffe40b3SMatthew Dillon 		}
9390ffe40b3SMatthew Dillon 		if (streq(cp, "boot2 data base")) {
9400ffe40b3SMatthew Dillon 			vv = strtoull(tp, NULL, 0);
9410ffe40b3SMatthew Dillon 			if (vv == 0 || vv == (uint64_t)-1) {
9420ffe40b3SMatthew Dillon 				fprintf(stderr, "line %d: %s: bad %s\n",
9430ffe40b3SMatthew Dillon 				    lineno, tp, cp);
9440ffe40b3SMatthew Dillon 				errors++;
9450ffe40b3SMatthew Dillon 			} else {
9460ffe40b3SMatthew Dillon 				lp->d_bbase = vv;
9470ffe40b3SMatthew Dillon 			}
9480ffe40b3SMatthew Dillon 			continue;
9490ffe40b3SMatthew Dillon 		}
9500ffe40b3SMatthew Dillon 		if (streq(cp, "partitions data base")) {
9510ffe40b3SMatthew Dillon 			vv = strtoull(tp, NULL, 0);
9520ffe40b3SMatthew Dillon 			if (vv == 0 || vv == (uint64_t)-1) {
9530ffe40b3SMatthew Dillon 				fprintf(stderr, "line %d: %s: bad %s\n",
9540ffe40b3SMatthew Dillon 				    lineno, tp, cp);
9550ffe40b3SMatthew Dillon 				errors++;
9560ffe40b3SMatthew Dillon 			} else {
9570ffe40b3SMatthew Dillon 				lp->d_pbase = vv;
9580ffe40b3SMatthew Dillon 			}
9590ffe40b3SMatthew Dillon 			continue;
9600ffe40b3SMatthew Dillon 		}
9610ffe40b3SMatthew Dillon 		if (streq(cp, "partitions data stop")) {
9620ffe40b3SMatthew Dillon 			vv = strtoull(tp, NULL, 0);
9630ffe40b3SMatthew Dillon 			if (vv == 0 || vv == (uint64_t)-1) {
9640ffe40b3SMatthew Dillon 				fprintf(stderr, "line %d: %s: bad %s\n",
9650ffe40b3SMatthew Dillon 				    lineno, tp, cp);
9660ffe40b3SMatthew Dillon 				errors++;
9670ffe40b3SMatthew Dillon 			} else {
9680ffe40b3SMatthew Dillon 				lp->d_pstop = vv;
9690ffe40b3SMatthew Dillon 			}
9700ffe40b3SMatthew Dillon 			continue;
9710ffe40b3SMatthew Dillon 		}
9720ffe40b3SMatthew Dillon 		if (streq(cp, "backup label")) {
9730ffe40b3SMatthew Dillon 			vv = strtoull(tp, NULL, 0);
9740ffe40b3SMatthew Dillon 			if (vv == 0 || vv == (uint64_t)-1) {
9750ffe40b3SMatthew Dillon 				fprintf(stderr, "line %d: %s: bad %s\n",
9760ffe40b3SMatthew Dillon 				    lineno, tp, cp);
9770ffe40b3SMatthew Dillon 				errors++;
9780ffe40b3SMatthew Dillon 			} else {
9790ffe40b3SMatthew Dillon 				lp->d_abase = vv;
9800ffe40b3SMatthew Dillon 			}
9810ffe40b3SMatthew Dillon 			continue;
9820ffe40b3SMatthew Dillon 		}
9830ffe40b3SMatthew Dillon 		if (streq(cp, "display block size")) {
9840ffe40b3SMatthew Dillon 			v = strtoul(tp, NULL, 0);
9850ffe40b3SMatthew Dillon 			if (v <= 0 || (v & DEV_BMASK) != 0 || v > 1024*1024) {
986cd0af6a8SAaron LI 				fprintf(stderr, "line %d: %s: bad %s\n",
987cd0af6a8SAaron LI 				    lineno, tp, cp);
9880ffe40b3SMatthew Dillon 				errors++;
9890ffe40b3SMatthew Dillon 			} else {
9900ffe40b3SMatthew Dillon 				blksize = v;
9910ffe40b3SMatthew Dillon 			}
9920ffe40b3SMatthew Dillon 			continue;
9930ffe40b3SMatthew Dillon 		}
9940ffe40b3SMatthew Dillon 
9950ffe40b3SMatthew Dillon 		/* the ':' was removed above */
996529d55c9SMatthew Dillon 
997529d55c9SMatthew Dillon 		/*
998529d55c9SMatthew Dillon 		 * Handle main partition data, e.g. a:, b:, etc.
999529d55c9SMatthew Dillon 		 */
1000529d55c9SMatthew Dillon 		if (*cp < 'a' || *cp > MAX_PART) {
10010ffe40b3SMatthew Dillon 			fprintf(stderr,
10020ffe40b3SMatthew Dillon 			    "line %d: %s: Unknown disklabel field\n", lineno,
10030ffe40b3SMatthew Dillon 			    cp);
10040ffe40b3SMatthew Dillon 			errors++;
10050ffe40b3SMatthew Dillon 			continue;
10060ffe40b3SMatthew Dillon 		}
10070ffe40b3SMatthew Dillon 
10080ffe40b3SMatthew Dillon 		/* Process a partition specification line. */
10090ffe40b3SMatthew Dillon 		part = *cp - 'a';
10100ffe40b3SMatthew Dillon 		if (part >= lp->d_npartitions) {
10110ffe40b3SMatthew Dillon 			fprintf(stderr,
10120ffe40b3SMatthew Dillon 			    "line %d: partition name out of range a-%c: %s\n",
10130ffe40b3SMatthew Dillon 			    lineno, 'a' + lp->d_npartitions - 1, cp);
10140ffe40b3SMatthew Dillon 			errors++;
10150ffe40b3SMatthew Dillon 			continue;
10160ffe40b3SMatthew Dillon 		}
10170ffe40b3SMatthew Dillon 
10180ffe40b3SMatthew Dillon 		if (blksize == 0) {
10190ffe40b3SMatthew Dillon 			fprintf(stderr, "block size to use for partition "
10200ffe40b3SMatthew Dillon 					"display was not specified!\n");
10210ffe40b3SMatthew Dillon 			errors++;
10220ffe40b3SMatthew Dillon 			continue;
10230ffe40b3SMatthew Dillon 		}
10240ffe40b3SMatthew Dillon 
1025529d55c9SMatthew Dillon 		if (strcmp(cp + 1, "-stor_uuid") == 0) {
1026529d55c9SMatthew Dillon 			if (getasciipartuuid(tp, lp, part, lineno, blksize)) {
10270ffe40b3SMatthew Dillon 				errors++;
10280ffe40b3SMatthew Dillon 				break;
10290ffe40b3SMatthew Dillon 			}
1030529d55c9SMatthew Dillon 			continue;
1031529d55c9SMatthew Dillon 		} else if (cp[1] == 0) {
1032529d55c9SMatthew Dillon 			part_set[part] = 1;
1033529d55c9SMatthew Dillon 			if (getasciipartspec(tp, lp, part, lineno, blksize)) {
1034529d55c9SMatthew Dillon 				errors++;
1035529d55c9SMatthew Dillon 				break;
1036529d55c9SMatthew Dillon 			}
1037529d55c9SMatthew Dillon 			continue;
1038529d55c9SMatthew Dillon 		}
1039529d55c9SMatthew Dillon 		fprintf(stderr, "line %d: %s: Unknown disklabel field\n",
1040529d55c9SMatthew Dillon 			lineno, cp);
1041529d55c9SMatthew Dillon 		errors++;
1042529d55c9SMatthew Dillon 		continue;
10430ffe40b3SMatthew Dillon 	}
10440ffe40b3SMatthew Dillon 	errors += checklabel(lp);
10450ffe40b3SMatthew Dillon 	return (errors == 0);
10460ffe40b3SMatthew Dillon }
10470ffe40b3SMatthew Dillon 
10480a319615SMatthew Dillon static int
parse_field_val(char ** tp,char ** cp,u_int64_t * vv,int lineno)10490ffe40b3SMatthew Dillon parse_field_val(char **tp, char **cp, u_int64_t *vv, int lineno)
10500ffe40b3SMatthew Dillon {
10510ffe40b3SMatthew Dillon 	char *tmp;
10520ffe40b3SMatthew Dillon 
10530ffe40b3SMatthew Dillon 	if (*tp == NULL || **tp == 0) {
10540ffe40b3SMatthew Dillon 		fprintf(stderr, "line %d: too few numeric fields\n", lineno);
10550ffe40b3SMatthew Dillon 		return(-1);
10560ffe40b3SMatthew Dillon 	}
10570ffe40b3SMatthew Dillon 	*cp = *tp;
10580ffe40b3SMatthew Dillon 	*tp = word(*cp);
10590ffe40b3SMatthew Dillon 	*vv = strtoull(*cp, &tmp, 0);
10600ffe40b3SMatthew Dillon 	if (*vv == ULLONG_MAX) {
10610ffe40b3SMatthew Dillon 		fprintf(stderr, "line %d: illegal number\n", lineno);
10620ffe40b3SMatthew Dillon 		return(-1);
10630ffe40b3SMatthew Dillon 	}
10640ffe40b3SMatthew Dillon 	if (tmp)
10650ffe40b3SMatthew Dillon 		return(*tmp);
10660ffe40b3SMatthew Dillon 	else
10670ffe40b3SMatthew Dillon 		return(0);
10680ffe40b3SMatthew Dillon }
10690ffe40b3SMatthew Dillon 
10700ffe40b3SMatthew Dillon /*
10710ffe40b3SMatthew Dillon  * Read a partition line into partition `part' in the specified disklabel.
10720ffe40b3SMatthew Dillon  * Return 0 on success, 1 on failure.
10730ffe40b3SMatthew Dillon  */
10740a319615SMatthew Dillon static int
getasciipartspec(char * tp,struct disklabel64 * lp,int part,int lineno,uint32_t blksize)1075529d55c9SMatthew Dillon getasciipartspec(char *tp, struct disklabel64 *lp, int part,
1076529d55c9SMatthew Dillon 		 int lineno, uint32_t blksize)
10770ffe40b3SMatthew Dillon {
10780ffe40b3SMatthew Dillon 	struct partition64 *pp;
10790ffe40b3SMatthew Dillon 	char *cp;
10800ffe40b3SMatthew Dillon 	const char **cpp;
10810ffe40b3SMatthew Dillon 	int r;
10820ffe40b3SMatthew Dillon 	u_long v;
10830ffe40b3SMatthew Dillon 	uint64_t vv;
10840ffe40b3SMatthew Dillon 	uint64_t mpx;
10850ffe40b3SMatthew Dillon 
10860ffe40b3SMatthew Dillon 	pp = &lp->d_partitions[part];
10870ffe40b3SMatthew Dillon 	cp = NULL;
10880ffe40b3SMatthew Dillon 
10890ffe40b3SMatthew Dillon 	/*
10900ffe40b3SMatthew Dillon 	 * size
10910ffe40b3SMatthew Dillon 	 */
10920ffe40b3SMatthew Dillon 	r = parse_field_val(&tp, &cp, &vv, lineno);
10930ffe40b3SMatthew Dillon 	if (r < 0)
10940ffe40b3SMatthew Dillon 		return (1);
10950ffe40b3SMatthew Dillon 
10960ffe40b3SMatthew Dillon 	mpx = 1;
10970ffe40b3SMatthew Dillon 	switch(r) {
10980ffe40b3SMatthew Dillon 	case 0:
10990ffe40b3SMatthew Dillon 		mpx = blksize;
11000ffe40b3SMatthew Dillon 		break;
11010ffe40b3SMatthew Dillon 	case '%':
11020ffe40b3SMatthew Dillon 		/* mpx = 1; */
11030ffe40b3SMatthew Dillon 		break;
11040ffe40b3SMatthew Dillon 	case '*':
11050ffe40b3SMatthew Dillon 		mpx = 0;
11060ffe40b3SMatthew Dillon 		break;
1107f61a91d2SSascha Wildner 	case 't':
1108f61a91d2SSascha Wildner 	case 'T':
1109f61a91d2SSascha Wildner 		mpx *= 1024ULL;
1110f61a91d2SSascha Wildner 		/* fall through */
11110ffe40b3SMatthew Dillon 	case 'g':
11120ffe40b3SMatthew Dillon 	case 'G':
11130ffe40b3SMatthew Dillon 		mpx *= 1024ULL;
11140ffe40b3SMatthew Dillon 		/* fall through */
11150ffe40b3SMatthew Dillon 	case 'm':
11160ffe40b3SMatthew Dillon 	case 'M':
11170ffe40b3SMatthew Dillon 		mpx *= 1024ULL;
11180ffe40b3SMatthew Dillon 		/* fall through */
11190ffe40b3SMatthew Dillon 	case 'k':
11200ffe40b3SMatthew Dillon 	case 'K':
11210ffe40b3SMatthew Dillon 		mpx *= 1024ULL;
11220ffe40b3SMatthew Dillon 		r = 0;			/* eat the suffix */
11230ffe40b3SMatthew Dillon 		break;
11240ffe40b3SMatthew Dillon 	default:
1125f61a91d2SSascha Wildner 		Warning("unknown size specifier '%c' (*/%%/K/M/G/T are valid)",
11260ffe40b3SMatthew Dillon 			r);
11270ffe40b3SMatthew Dillon 		return(1);
11280ffe40b3SMatthew Dillon 	}
11290ffe40b3SMatthew Dillon 
11300ffe40b3SMatthew Dillon 	part_size_type[part] = r;
11310ffe40b3SMatthew Dillon 	if (vv == 0 && r != '*') {
11320ffe40b3SMatthew Dillon 		fprintf(stderr,
11330ffe40b3SMatthew Dillon 		    "line %d: %s: bad partition size (0)\n", lineno, cp);
11340ffe40b3SMatthew Dillon 		return (1);
11350ffe40b3SMatthew Dillon 	}
11360ffe40b3SMatthew Dillon 	pp->p_bsize = vv * mpx;
11370ffe40b3SMatthew Dillon 
11380ffe40b3SMatthew Dillon 	/*
11390ffe40b3SMatthew Dillon 	 * offset
11400ffe40b3SMatthew Dillon 	 */
11410ffe40b3SMatthew Dillon 	r = parse_field_val(&tp, &cp, &vv, lineno);
11420ffe40b3SMatthew Dillon 	if (r < 0)
11430ffe40b3SMatthew Dillon 		return (1);
11440ffe40b3SMatthew Dillon 	part_offset_type[part] = r;
11450ffe40b3SMatthew Dillon 	switch(r) {
11460ffe40b3SMatthew Dillon 	case '*':
11470ffe40b3SMatthew Dillon 		pp->p_boffset = 0;
11480ffe40b3SMatthew Dillon 		break;
11490ffe40b3SMatthew Dillon 	case 0:
11500ffe40b3SMatthew Dillon 		pp->p_boffset = vv * blksize + lp->d_pbase;
11510ffe40b3SMatthew Dillon 		break;
11520ffe40b3SMatthew Dillon 	default:
11530ffe40b3SMatthew Dillon 		fprintf(stderr,
11540ffe40b3SMatthew Dillon 		    "line %d: %s: bad suffix on partition offset (%c)\n",
11550ffe40b3SMatthew Dillon 		    lineno, cp, r);
11560ffe40b3SMatthew Dillon 		return (1);
11570ffe40b3SMatthew Dillon 	}
11580ffe40b3SMatthew Dillon 
11590ffe40b3SMatthew Dillon 	/*
11600ffe40b3SMatthew Dillon 	 * fstype
11610ffe40b3SMatthew Dillon 	 */
1162d5c4918aSAntonio Huete Jimenez 	if (tp == NULL) {
1163d5c4918aSAntonio Huete Jimenez 		fprintf(stderr,
1164d5c4918aSAntonio Huete Jimenez 		    "line %d: no filesystem type was specified\n", lineno);
1165d5c4918aSAntonio Huete Jimenez 		return(1);
1166d5c4918aSAntonio Huete Jimenez 	}
11670ffe40b3SMatthew Dillon 	cp = tp;
11680ffe40b3SMatthew Dillon 	tp = word(cp);
1169a8de4644SMatthew Dillon 	for (cpp = fstypenames; cpp < &fstypenames[FSMAXTYPES]; cpp++) {
1170a8de4644SMatthew Dillon 		if (*cpp && strcasecmp(*cpp, cp) == 0)
11710ffe40b3SMatthew Dillon 			break;
1172a8de4644SMatthew Dillon 	}
11730ffe40b3SMatthew Dillon 	if (*cpp != NULL) {
11740ffe40b3SMatthew Dillon 		pp->p_fstype = cpp - fstypenames;
11750ffe40b3SMatthew Dillon 	} else {
11760ffe40b3SMatthew Dillon 		if (isdigit(*cp))
11770ffe40b3SMatthew Dillon 			v = strtoul(cp, NULL, 0);
11780ffe40b3SMatthew Dillon 		else
11790ffe40b3SMatthew Dillon 			v = FSMAXTYPES;
11800ffe40b3SMatthew Dillon 		if (v >= FSMAXTYPES) {
11810ffe40b3SMatthew Dillon 			fprintf(stderr,
11820ffe40b3SMatthew Dillon 			    "line %d: Warning, unknown filesystem type %s\n",
11830ffe40b3SMatthew Dillon 			    lineno, cp);
11840ffe40b3SMatthew Dillon 			v = FS_UNUSED;
11850ffe40b3SMatthew Dillon 		}
11860ffe40b3SMatthew Dillon 		pp->p_fstype = v;
11870ffe40b3SMatthew Dillon 	}
11880ffe40b3SMatthew Dillon 
11890ffe40b3SMatthew Dillon 	cp = tp;
11900ffe40b3SMatthew Dillon 	if (tp) {
11910ffe40b3SMatthew Dillon 		fprintf(stderr, "line %d: Warning, extra data on line\n",
11920ffe40b3SMatthew Dillon 			lineno);
11930ffe40b3SMatthew Dillon 	}
11940ffe40b3SMatthew Dillon 	return(0);
11950ffe40b3SMatthew Dillon }
11960ffe40b3SMatthew Dillon 
11970a319615SMatthew Dillon static int
getasciipartuuid(char * tp,struct disklabel64 * lp,int part,int lineno,uint32_t blksize __unused)1198529d55c9SMatthew Dillon getasciipartuuid(char *tp, struct disklabel64 *lp, int part,
1199529d55c9SMatthew Dillon 		 int lineno, uint32_t blksize __unused)
1200529d55c9SMatthew Dillon {
1201529d55c9SMatthew Dillon 	struct partition64 *pp;
1202529d55c9SMatthew Dillon 	uint32_t status;
1203529d55c9SMatthew Dillon 	char *cp;
1204529d55c9SMatthew Dillon 
1205529d55c9SMatthew Dillon 	pp = &lp->d_partitions[part];
1206529d55c9SMatthew Dillon 
1207529d55c9SMatthew Dillon 	cp = tp;
1208529d55c9SMatthew Dillon 	tp = word(cp);
1209529d55c9SMatthew Dillon 	uuid_from_string(cp, &pp->p_stor_uuid, &status);
1210529d55c9SMatthew Dillon 	if (status != uuid_s_ok) {
1211529d55c9SMatthew Dillon 		fprintf(stderr, "line %d: Illegal storage uuid specification\n",
1212529d55c9SMatthew Dillon 			lineno);
1213529d55c9SMatthew Dillon 		return(1);
1214529d55c9SMatthew Dillon 	}
1215529d55c9SMatthew Dillon 	return(0);
1216529d55c9SMatthew Dillon }
1217529d55c9SMatthew Dillon 
12180ffe40b3SMatthew Dillon /*
12190ffe40b3SMatthew Dillon  * Check disklabel for errors and fill in
12200ffe40b3SMatthew Dillon  * derived fields according to supplied values.
12210ffe40b3SMatthew Dillon  */
12220a319615SMatthew Dillon static int
checklabel(struct disklabel64 * lp)12230ffe40b3SMatthew Dillon checklabel(struct disklabel64 *lp)
12240ffe40b3SMatthew Dillon {
12250ffe40b3SMatthew Dillon 	struct partition64 *pp;
12260ffe40b3SMatthew Dillon 	int errors = 0;
12270ffe40b3SMatthew Dillon 	char part;
12280ffe40b3SMatthew Dillon 	u_int64_t total_size;
12290ffe40b3SMatthew Dillon 	u_int64_t current_offset;
12300ffe40b3SMatthew Dillon 	u_long total_percent;
12310ffe40b3SMatthew Dillon 	int seen_default_offset;
12320ffe40b3SMatthew Dillon 	int hog_part;
12330ffe40b3SMatthew Dillon 	int i, j;
12340ffe40b3SMatthew Dillon 	struct partition64 *pp2;
12350ffe40b3SMatthew Dillon 	u_int64_t off;
12360ffe40b3SMatthew Dillon 
12370ffe40b3SMatthew Dillon 	if (lp->d_align < 512 ||
12380ffe40b3SMatthew Dillon 	    (lp->d_align ^ (lp->d_align - 1)) != lp->d_align * 2 - 1) {
12390ffe40b3SMatthew Dillon 		Warning("Illegal alignment specified: %u\n", lp->d_align);
12400ffe40b3SMatthew Dillon 		return (1);
12410ffe40b3SMatthew Dillon 	}
12420ffe40b3SMatthew Dillon 	if (lp->d_npartitions > MAXPARTITIONS64) {
12430ffe40b3SMatthew Dillon 		Warning("number of partitions (%u) > MAXPARTITIONS (%d)",
12440ffe40b3SMatthew Dillon 			lp->d_npartitions, MAXPARTITIONS64);
12450ffe40b3SMatthew Dillon 		return (1);
12460ffe40b3SMatthew Dillon 	}
12470ffe40b3SMatthew Dillon 	off = offsetof(struct disklabel64, d_partitions[lp->d_npartitions]);
12480ffe40b3SMatthew Dillon 	off = (off + lp->d_align - 1) & ~(int64_t)(lp->d_align - 1);
12490ffe40b3SMatthew Dillon 
12500ffe40b3SMatthew Dillon 	if (lp->d_bbase < off || lp->d_bbase % lp->d_align) {
12510ffe40b3SMatthew Dillon 		Warning("illegal boot2 data base ");
12520ffe40b3SMatthew Dillon 		return (1);
12530ffe40b3SMatthew Dillon 	}
12545179f0c5SMatthew Dillon 
12555179f0c5SMatthew Dillon 	/*
12565179f0c5SMatthew Dillon 	 * pbase can be unaligned slice-relative but will be
12575179f0c5SMatthew Dillon 	 * aligned physically.
12585179f0c5SMatthew Dillon 	 */
12595179f0c5SMatthew Dillon 	if (lp->d_pbase < lp->d_bbase) {
12600ffe40b3SMatthew Dillon 		Warning("illegal partition data base");
12610ffe40b3SMatthew Dillon 		return (1);
12620ffe40b3SMatthew Dillon 	}
12635179f0c5SMatthew Dillon 	if (lp->d_pstop < lp->d_pbase) {
12640ffe40b3SMatthew Dillon 		Warning("illegal partition data stop");
12650ffe40b3SMatthew Dillon 		return (1);
12660ffe40b3SMatthew Dillon 	}
12670ffe40b3SMatthew Dillon 	if (lp->d_pstop > lp->d_total_size) {
1268a276dc6bSMatthew Dillon 		printf("%012jx\n%012jx\n",
12691f5e0b99SSascha Wildner 			(uintmax_t)lp->d_pstop, (uintmax_t)lp->d_total_size);
12700ffe40b3SMatthew Dillon 		Warning("disklabel control info is beyond the total size");
12710ffe40b3SMatthew Dillon 		return (1);
12720ffe40b3SMatthew Dillon 	}
12730ffe40b3SMatthew Dillon 	if (lp->d_abase &&
12745179f0c5SMatthew Dillon 	    (lp->d_abase < lp->d_pstop ||
12750ffe40b3SMatthew Dillon 	     lp->d_abase > lp->d_total_size - off)) {
12760ffe40b3SMatthew Dillon 		Warning("illegal backup label location");
12770ffe40b3SMatthew Dillon 		return (1);
12780ffe40b3SMatthew Dillon 	}
12790ffe40b3SMatthew Dillon 
12800ffe40b3SMatthew Dillon 	/* first allocate space to the partitions, then offsets */
12810ffe40b3SMatthew Dillon 	total_size = 0;		/* in bytes */
12820ffe40b3SMatthew Dillon 	total_percent = 0;	/* in percent */
12830ffe40b3SMatthew Dillon 	hog_part = -1;
12840ffe40b3SMatthew Dillon 	/* find all fixed partitions */
12850ffe40b3SMatthew Dillon 	for (i = 0; i < (int)lp->d_npartitions; i++) {
12860ffe40b3SMatthew Dillon 		pp = &lp->d_partitions[i];
12870ffe40b3SMatthew Dillon 		if (part_set[i]) {
12880ffe40b3SMatthew Dillon 			if (part_size_type[i] == '*') {
1289b00e432bSMatthew Dillon 				if (part_offset_type[i] != '*') {
1290b00e432bSMatthew Dillon 					if (total_size < pp->p_boffset)
1291b00e432bSMatthew Dillon 						total_size = pp->p_boffset;
1292b00e432bSMatthew Dillon 				}
1293b00e432bSMatthew Dillon 				if (hog_part != -1) {
12940ffe40b3SMatthew Dillon 					Warning("Too many '*' partitions (%c and %c)",
12950ffe40b3SMatthew Dillon 					    hog_part + 'a',i + 'a');
1296b00e432bSMatthew Dillon 				} else {
12970ffe40b3SMatthew Dillon 					hog_part = i;
1298b00e432bSMatthew Dillon 				}
12990ffe40b3SMatthew Dillon 			} else {
13000ffe40b3SMatthew Dillon 				off_t size;
13010ffe40b3SMatthew Dillon 
13020ffe40b3SMatthew Dillon 				size = pp->p_bsize;
13030ffe40b3SMatthew Dillon 				if (part_size_type[i] == '%') {
13040ffe40b3SMatthew Dillon 					/*
13050ffe40b3SMatthew Dillon 					 * don't count %'s yet
13060ffe40b3SMatthew Dillon 					 */
13070ffe40b3SMatthew Dillon 					total_percent += size;
13080ffe40b3SMatthew Dillon 				} else {
13090ffe40b3SMatthew Dillon 					/*
13100ffe40b3SMatthew Dillon 					 * Value has already been converted
13110ffe40b3SMatthew Dillon 					 * to bytes.
13120ffe40b3SMatthew Dillon 					 */
13130ffe40b3SMatthew Dillon 					if (size % lp->d_align != 0) {
13140ffe40b3SMatthew Dillon 						Warning("partition %c's size is not properly aligned",
13150ffe40b3SMatthew Dillon 							i + 'a');
13160ffe40b3SMatthew Dillon 					}
13170ffe40b3SMatthew Dillon 					total_size += size;
13180ffe40b3SMatthew Dillon 				}
13190ffe40b3SMatthew Dillon 			}
13200ffe40b3SMatthew Dillon 		}
13210ffe40b3SMatthew Dillon 	}
13220ffe40b3SMatthew Dillon 	/* handle % partitions - note %'s don't need to add up to 100! */
13230ffe40b3SMatthew Dillon 	if (total_percent != 0) {
13240ffe40b3SMatthew Dillon 		int64_t free_space;
13250ffe40b3SMatthew Dillon 		int64_t space_left;
13260ffe40b3SMatthew Dillon 
13270ffe40b3SMatthew Dillon 		free_space = (int64_t)(lp->d_pstop - lp->d_pbase - total_size);
13285179f0c5SMatthew Dillon 		free_space &= ~(u_int64_t)(lp->d_align - 1);
13295179f0c5SMatthew Dillon 
13300ffe40b3SMatthew Dillon 		space_left = free_space;
13310ffe40b3SMatthew Dillon 		if (total_percent > 100) {
13320ffe40b3SMatthew Dillon 			fprintf(stderr,"total percentage %lu is greater than 100\n",
13330ffe40b3SMatthew Dillon 			    total_percent);
13340ffe40b3SMatthew Dillon 			errors++;
13350ffe40b3SMatthew Dillon 		}
13360ffe40b3SMatthew Dillon 
13370ffe40b3SMatthew Dillon 		if (free_space > 0) {
13380ffe40b3SMatthew Dillon 			for (i = 0; i < (int)lp->d_npartitions; i++) {
13390ffe40b3SMatthew Dillon 				pp = &lp->d_partitions[i];
13400ffe40b3SMatthew Dillon 				if (part_set[i] && part_size_type[i] == '%') {
13410ffe40b3SMatthew Dillon 					/* careful of overflows! and integer roundoff */
13420ffe40b3SMatthew Dillon 					pp->p_bsize = ((double)pp->p_bsize/100) * free_space;
13430ffe40b3SMatthew Dillon 					pp->p_bsize = (pp->p_bsize + lp->d_align - 1) & ~(u_int64_t)(lp->d_align - 1);
13440ffe40b3SMatthew Dillon 					if ((int64_t)pp->p_bsize > space_left)
13450ffe40b3SMatthew Dillon 						pp->p_bsize = (u_int64_t)space_left;
13460ffe40b3SMatthew Dillon 					total_size += pp->p_bsize;
13470ffe40b3SMatthew Dillon 					space_left -= pp->p_bsize;
13480ffe40b3SMatthew Dillon 				}
13490ffe40b3SMatthew Dillon 			}
13500ffe40b3SMatthew Dillon 		} else {
1351a276dc6bSMatthew Dillon 			fprintf(stderr, "%jd bytes available to give to "
1352a276dc6bSMatthew Dillon 					"'*' and '%%' partitions\n",
1353a276dc6bSMatthew Dillon 				(intmax_t)free_space);
13540ffe40b3SMatthew Dillon 			errors++;
13550ffe40b3SMatthew Dillon 			/* fix?  set all % partitions to size 0? */
13560ffe40b3SMatthew Dillon 		}
13570ffe40b3SMatthew Dillon 	}
13580ffe40b3SMatthew Dillon 	/* give anything remaining to the hog partition */
13590ffe40b3SMatthew Dillon 	if (hog_part != -1) {
13605179f0c5SMatthew Dillon 		off = lp->d_pstop - lp->d_pbase - total_size;
13615179f0c5SMatthew Dillon 		off &= ~(u_int64_t)(lp->d_align - 1);
13625179f0c5SMatthew Dillon 		lp->d_partitions[hog_part].p_bsize = off;
13630ffe40b3SMatthew Dillon 		total_size = lp->d_pstop - lp->d_pbase;
13640ffe40b3SMatthew Dillon 	}
13650ffe40b3SMatthew Dillon 
13660ffe40b3SMatthew Dillon 	/* Now set the offsets for each partition */
13670ffe40b3SMatthew Dillon 	current_offset = lp->d_pbase;
13680ffe40b3SMatthew Dillon 	seen_default_offset = 0;
13690ffe40b3SMatthew Dillon 	for (i = 0; i < (int)lp->d_npartitions; i++) {
13700ffe40b3SMatthew Dillon 		part = 'a' + i;
13710ffe40b3SMatthew Dillon 		pp = &lp->d_partitions[i];
13720ffe40b3SMatthew Dillon 		if (pp->p_bsize == 0)
13730ffe40b3SMatthew Dillon 			continue;
13740ffe40b3SMatthew Dillon 		if (part_set[i]) {
13750ffe40b3SMatthew Dillon 			if (part_offset_type[i] == '*') {
13760ffe40b3SMatthew Dillon 				pp->p_boffset = current_offset;
13770ffe40b3SMatthew Dillon 				seen_default_offset = 1;
13780ffe40b3SMatthew Dillon 			} else {
13790ffe40b3SMatthew Dillon 				/* allow them to be out of order for old-style tables */
13800ffe40b3SMatthew Dillon 				if (pp->p_boffset < current_offset &&
13810ffe40b3SMatthew Dillon 				    seen_default_offset &&
13820ffe40b3SMatthew Dillon 				    pp->p_fstype != FS_VINUM) {
13830ffe40b3SMatthew Dillon 					fprintf(stderr,
1384a276dc6bSMatthew Dillon "Offset 0x%012jx for partition %c overlaps previous partition which ends at 0x%012jx\n",
13851f5e0b99SSascha Wildner 					    (uintmax_t)pp->p_boffset,
1386a276dc6bSMatthew Dillon 					    i + 'a',
13871f5e0b99SSascha Wildner 					    (uintmax_t)current_offset);
13880ffe40b3SMatthew Dillon 					fprintf(stderr,
13890ffe40b3SMatthew Dillon "Labels with any *'s for offset must be in ascending order by sector\n");
13900ffe40b3SMatthew Dillon 					errors++;
13910ffe40b3SMatthew Dillon 				} else if (pp->p_boffset != current_offset &&
13920ffe40b3SMatthew Dillon 					   seen_default_offset) {
13930ffe40b3SMatthew Dillon 					/*
13940ffe40b3SMatthew Dillon 					 * this may give unneeded warnings if
13950ffe40b3SMatthew Dillon 					 * partitions are out-of-order
13960ffe40b3SMatthew Dillon 					 */
13970ffe40b3SMatthew Dillon 					Warning(
1398a276dc6bSMatthew Dillon "Offset 0x%012jx for partition %c doesn't match expected value 0x%012jx",
13990ffe40b3SMatthew Dillon 					    pp->p_boffset, i + 'a',
1400a276dc6bSMatthew Dillon 					    (intmax_t)current_offset);
14010ffe40b3SMatthew Dillon 				}
14020ffe40b3SMatthew Dillon 			}
14030ffe40b3SMatthew Dillon 			current_offset = pp->p_boffset + pp->p_bsize;
14040ffe40b3SMatthew Dillon 		}
14050ffe40b3SMatthew Dillon 	}
14060ffe40b3SMatthew Dillon 
14070ffe40b3SMatthew Dillon 	for (i = 0; i < (int)lp->d_npartitions; i++) {
14080ffe40b3SMatthew Dillon 		part = 'a' + i;
14090ffe40b3SMatthew Dillon 		pp = &lp->d_partitions[i];
14100ffe40b3SMatthew Dillon 		if (pp->p_bsize == 0 && pp->p_boffset != 0)
1411a276dc6bSMatthew Dillon 			Warning("partition %c: size 0, but offset 0x%012jx",
1412a276dc6bSMatthew Dillon 				part, (intmax_t)pp->p_boffset);
14130ffe40b3SMatthew Dillon 		if (pp->p_bsize == 0) {
14140ffe40b3SMatthew Dillon 			pp->p_boffset = 0;
14150ffe40b3SMatthew Dillon 			continue;
14160ffe40b3SMatthew Dillon 		}
1417529d55c9SMatthew Dillon 		if (uuid_is_nil(&pp->p_stor_uuid, NULL))
1418529d55c9SMatthew Dillon 			uuid_create(&pp->p_stor_uuid, NULL);
14190ffe40b3SMatthew Dillon 
14200ffe40b3SMatthew Dillon 		if (pp->p_boffset < lp->d_pbase) {
14210ffe40b3SMatthew Dillon 			fprintf(stderr,
1422a276dc6bSMatthew Dillon 			    "partition %c: offset out of bounds (%jd)\n",
1423a276dc6bSMatthew Dillon 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
14240ffe40b3SMatthew Dillon 			errors++;
14250ffe40b3SMatthew Dillon 		}
14260ffe40b3SMatthew Dillon 		if (pp->p_boffset > lp->d_pstop) {
14270ffe40b3SMatthew Dillon 			fprintf(stderr,
1428a276dc6bSMatthew Dillon 			    "partition %c: offset out of bounds (%jd)\n",
1429a276dc6bSMatthew Dillon 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
14300ffe40b3SMatthew Dillon 			errors++;
14310ffe40b3SMatthew Dillon 		}
14320ffe40b3SMatthew Dillon 		if (pp->p_boffset + pp->p_bsize > lp->d_pstop) {
14330ffe40b3SMatthew Dillon 			fprintf(stderr,
1434a276dc6bSMatthew Dillon 			    "partition %c: size out of bounds (%jd)\n",
1435a276dc6bSMatthew Dillon 			    part, (intmax_t)(pp->p_boffset - lp->d_pbase));
14360ffe40b3SMatthew Dillon 			errors++;
14370ffe40b3SMatthew Dillon 		}
14380ffe40b3SMatthew Dillon 
14390ffe40b3SMatthew Dillon 		/* check for overlaps */
14400ffe40b3SMatthew Dillon 		/* this will check for all possible overlaps once and only once */
14410ffe40b3SMatthew Dillon 		for (j = 0; j < i; j++) {
14420ffe40b3SMatthew Dillon 			pp2 = &lp->d_partitions[j];
14430ffe40b3SMatthew Dillon 			if (pp->p_fstype != FS_VINUM &&
14440ffe40b3SMatthew Dillon 			    pp2->p_fstype != FS_VINUM &&
14450ffe40b3SMatthew Dillon 			    part_set[i] && part_set[j]) {
14460ffe40b3SMatthew Dillon 				if (pp2->p_boffset < pp->p_boffset + pp->p_bsize &&
14470ffe40b3SMatthew Dillon 				    (pp2->p_boffset + pp2->p_bsize > pp->p_boffset ||
14480ffe40b3SMatthew Dillon 					pp2->p_boffset >= pp->p_boffset)) {
14490ffe40b3SMatthew Dillon 					fprintf(stderr,"partitions %c and %c overlap!\n",
14500ffe40b3SMatthew Dillon 					    j + 'a', i + 'a');
14510ffe40b3SMatthew Dillon 					errors++;
14520ffe40b3SMatthew Dillon 				}
14530ffe40b3SMatthew Dillon 			}
14540ffe40b3SMatthew Dillon 		}
14550ffe40b3SMatthew Dillon 	}
14560ffe40b3SMatthew Dillon 	for (; i < (int)lp->d_npartitions; i++) {
14570ffe40b3SMatthew Dillon 		part = 'a' + i;
14580ffe40b3SMatthew Dillon 		pp = &lp->d_partitions[i];
14590ffe40b3SMatthew Dillon 		if (pp->p_bsize || pp->p_boffset)
1460a276dc6bSMatthew Dillon 			Warning("unused partition %c: size 0x%012jx "
1461a276dc6bSMatthew Dillon 				"offset 0x%012jx",
1462a276dc6bSMatthew Dillon 				'a' + i, (intmax_t)pp->p_bsize,
1463a276dc6bSMatthew Dillon 				(intmax_t)pp->p_boffset);
14640ffe40b3SMatthew Dillon 	}
14650ffe40b3SMatthew Dillon 	return (errors);
14660ffe40b3SMatthew Dillon }
14670ffe40b3SMatthew Dillon 
146835a9ab8aSMatthew Dillon static int
expandlabel(int f,struct disklabel64 * lp,int * wbackp)146935a9ab8aSMatthew Dillon expandlabel(int f, struct disklabel64 *lp, int *wbackp)
147035a9ab8aSMatthew Dillon {
147135a9ab8aSMatthew Dillon 	const uint64_t onemeg = 1024 * 1024;
147235a9ab8aSMatthew Dillon 	uint64_t pstop;
147335a9ab8aSMatthew Dillon 	uint64_t abase;
147435a9ab8aSMatthew Dillon 	uint64_t tsize;
147535a9ab8aSMatthew Dillon 	uint64_t bsize;
147635a9ab8aSMatthew Dillon 	struct partinfo info;
147735a9ab8aSMatthew Dillon 	struct partition64 *part;
147835a9ab8aSMatthew Dillon 	struct partition64 *best;
147935a9ab8aSMatthew Dillon 	struct stat st;
148035a9ab8aSMatthew Dillon 	uint32_t n;
148135a9ab8aSMatthew Dillon 
148235a9ab8aSMatthew Dillon 	if (ioctl(f, DIOCGPART, &info) == 0) {
148335a9ab8aSMatthew Dillon 		st.st_size = info.media_size;
148435a9ab8aSMatthew Dillon 	} else if (fstat(f, &st) == 0) {
148535a9ab8aSMatthew Dillon 		;
148635a9ab8aSMatthew Dillon 	} else {
148735a9ab8aSMatthew Dillon 		fprintf(stderr, "disklabel64: cannot ioctl/stat device\n");
148835a9ab8aSMatthew Dillon 		return EINVAL;
148935a9ab8aSMatthew Dillon 	}
149035a9ab8aSMatthew Dillon 	abase = st.st_size - 4096;
149135a9ab8aSMatthew Dillon 	pstop = abase & ~(onemeg - 1);
149235a9ab8aSMatthew Dillon 	tsize = st.st_size;
149335a9ab8aSMatthew Dillon 
149435a9ab8aSMatthew Dillon 	printf("partitions data stop:  %ld -> %ld\n", lp->d_pstop, pstop);
149535a9ab8aSMatthew Dillon 	printf("backup label:          %ld -> %ld\n", lp->d_abase, abase);
149635a9ab8aSMatthew Dillon 	printf("total size:            %ld -> %ld\n", lp->d_total_size, tsize);
149735a9ab8aSMatthew Dillon 
149835a9ab8aSMatthew Dillon 	/*
149935a9ab8aSMatthew Dillon 	 * This directive does not shrink disklabels!!!
150035a9ab8aSMatthew Dillon 	 */
150135a9ab8aSMatthew Dillon 	if (lp->d_pstop > pstop ||
150235a9ab8aSMatthew Dillon 	    lp->d_abase > abase ||
150335a9ab8aSMatthew Dillon 	    lp->d_total_size > tsize) {
150435a9ab8aSMatthew Dillon 		fprintf(stderr, "disklabel64: cannot expand "
150535a9ab8aSMatthew Dillon 				"disklabel because it would "
150635a9ab8aSMatthew Dillon 				"shrink!\n");
150735a9ab8aSMatthew Dillon 		return 1;
150835a9ab8aSMatthew Dillon 	}
150935a9ab8aSMatthew Dillon 
151035a9ab8aSMatthew Dillon 
151135a9ab8aSMatthew Dillon 	if (lp->d_pstop == pstop &&
151235a9ab8aSMatthew Dillon 	    lp->d_abase == abase &&
151335a9ab8aSMatthew Dillon 	    lp->d_total_size == tsize) {
1514*e04444f9SMatthew Dillon 		printf("disklabel64: expand: "
151535a9ab8aSMatthew Dillon 		       "no change in disklabel "
151635a9ab8aSMatthew Dillon 		       "size\n");
151735a9ab8aSMatthew Dillon 	} else {
151835a9ab8aSMatthew Dillon 		lp->d_pstop = pstop;
151935a9ab8aSMatthew Dillon 		lp->d_abase = abase;
152035a9ab8aSMatthew Dillon 		lp->d_total_size = tsize;
152135a9ab8aSMatthew Dillon 		*wbackp = 1;
152235a9ab8aSMatthew Dillon 	}
152335a9ab8aSMatthew Dillon 
152435a9ab8aSMatthew Dillon 	/*
152535a9ab8aSMatthew Dillon 	 * Resize the last partition
152635a9ab8aSMatthew Dillon 	 */
152735a9ab8aSMatthew Dillon 	if (expandopt > 1) {
152835a9ab8aSMatthew Dillon 		best = NULL;
152935a9ab8aSMatthew Dillon 		for (n = 0; n < lp->d_npartitions; ++n) {
153035a9ab8aSMatthew Dillon 			part = &lp->d_partitions[n];
153135a9ab8aSMatthew Dillon 			if (best == NULL || best->p_boffset < part->p_boffset)
153235a9ab8aSMatthew Dillon 				best = part;
153335a9ab8aSMatthew Dillon 		}
153435a9ab8aSMatthew Dillon 		if (best) {
153535a9ab8aSMatthew Dillon 			bsize = lp->d_pstop - best->p_boffset;
153635a9ab8aSMatthew Dillon 			if (best->p_bsize > bsize) {
1537*e04444f9SMatthew Dillon 				printf("disklabel64: cannot expand "
153835a9ab8aSMatthew Dillon 				       "partition because it would "
153935a9ab8aSMatthew Dillon 				       "shrink!\n");
154035a9ab8aSMatthew Dillon 				return 1;
154135a9ab8aSMatthew Dillon 			} else if (best->p_bsize == bsize) {
1542*e04444f9SMatthew Dillon 				printf("disklabel64: expand: "
154335a9ab8aSMatthew Dillon 				       "no change in partition "
154435a9ab8aSMatthew Dillon 				       "size\n");
154535a9ab8aSMatthew Dillon 			} else {
1546*e04444f9SMatthew Dillon 				printf("disklabel64: expand: increase part "
1547*e04444f9SMatthew Dillon 				       "%ld to %ld bytes\n",
1548*e04444f9SMatthew Dillon 				       best->p_bsize,
1549*e04444f9SMatthew Dillon 				       bsize);
155035a9ab8aSMatthew Dillon 				best->p_bsize = bsize;
155135a9ab8aSMatthew Dillon 				*wbackp = 1;
155235a9ab8aSMatthew Dillon 			}
155335a9ab8aSMatthew Dillon 		}
155435a9ab8aSMatthew Dillon 	}
155535a9ab8aSMatthew Dillon 
155635a9ab8aSMatthew Dillon 	return 0;
155735a9ab8aSMatthew Dillon }
155835a9ab8aSMatthew Dillon 
15590ffe40b3SMatthew Dillon /*
15600ffe40b3SMatthew Dillon  * When operating on a "virgin" disk, try getting an initial label
15610ffe40b3SMatthew Dillon  * from the associated device driver.  This might work for all device
15620ffe40b3SMatthew Dillon  * drivers that are able to fetch some initial device parameters
15630ffe40b3SMatthew Dillon  * without even having access to a (BSD) disklabel, like SCSI disks,
15640ffe40b3SMatthew Dillon  * most IDE drives, or vn devices.
15650ffe40b3SMatthew Dillon  *
15660ffe40b3SMatthew Dillon  * The device name must be given in its "canonical" form.
15670ffe40b3SMatthew Dillon  */
15680ffe40b3SMatthew Dillon static struct disklabel64 dlab;
15690ffe40b3SMatthew Dillon 
15700a319615SMatthew Dillon static struct disklabel64 *
getvirginlabel(void)15710ffe40b3SMatthew Dillon getvirginlabel(void)
15720ffe40b3SMatthew Dillon {
15730ffe40b3SMatthew Dillon 	struct disklabel64 *dl = &dlab;
15740ffe40b3SMatthew Dillon 	int f;
15750ffe40b3SMatthew Dillon 
1576d736a600SMatthew Dillon 	if ((f = open(dkname, O_RDONLY)) == -1) {
1577d736a600SMatthew Dillon 		warn("cannot open %s", dkname);
15780ffe40b3SMatthew Dillon 		return (NULL);
15790ffe40b3SMatthew Dillon 	}
15800ffe40b3SMatthew Dillon 
15810ffe40b3SMatthew Dillon 	/*
15820a319615SMatthew Dillon 	 * Generate a virgin disklabel via ioctl
15830ffe40b3SMatthew Dillon 	 */
15840ffe40b3SMatthew Dillon 	if (ioctl(f, DIOCGDVIRGIN64, dl) < 0) {
15850ffe40b3SMatthew Dillon 		l_perror("ioctl DIOCGDVIRGIN64");
15860ffe40b3SMatthew Dillon 		close(f);
15870ffe40b3SMatthew Dillon 		return (NULL);
15880ffe40b3SMatthew Dillon 	}
15890ffe40b3SMatthew Dillon 	close(f);
15900ffe40b3SMatthew Dillon 	return (dl);
15910ffe40b3SMatthew Dillon }
15920ffe40b3SMatthew Dillon 
15930ffe40b3SMatthew Dillon /*VARARGS1*/
15940a319615SMatthew Dillon static void
Warning(const char * fmt,...)15950ffe40b3SMatthew Dillon Warning(const char *fmt, ...)
15960ffe40b3SMatthew Dillon {
15970ffe40b3SMatthew Dillon 	va_list ap;
15980ffe40b3SMatthew Dillon 
15990ffe40b3SMatthew Dillon 	fprintf(stderr, "Warning, ");
16000ffe40b3SMatthew Dillon 	va_start(ap, fmt);
16010ffe40b3SMatthew Dillon 	vfprintf(stderr, fmt, ap);
16020ffe40b3SMatthew Dillon 	fprintf(stderr, "\n");
16030ffe40b3SMatthew Dillon 	va_end(ap);
16040ffe40b3SMatthew Dillon }
16050ffe40b3SMatthew Dillon 
16060a319615SMatthew Dillon static void
usage(void)16070ffe40b3SMatthew Dillon usage(void)
16080ffe40b3SMatthew Dillon {
16090fcbc539SThomas Nikolajsen 	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",
1610bdddbf50SThomas Nikolajsen 		"usage: disklabel64 [-r] disk",
16110ffe40b3SMatthew Dillon 		"\t\t(to read label)",
16120a319615SMatthew Dillon 		"       disklabel64 -w [-r] [-n] disk [type [packid]]",
16130ffe40b3SMatthew Dillon 		"\t\t(to write label with existing boot program)",
1614bdddbf50SThomas Nikolajsen 		"       disklabel64 -e [-r] [-n] disk",
16150ffe40b3SMatthew Dillon 		"\t\t(to edit label)",
1616bdddbf50SThomas Nikolajsen 		"       disklabel64 -R [-r] [-n] disk protofile",
16170ffe40b3SMatthew Dillon 		"\t\t(to restore label with existing boot program)",
16180fcbc539SThomas Nikolajsen 		"       disklabel64 -B [-n] [-b boot1 -s boot2] disk [type]",
16190ffe40b3SMatthew Dillon 		"\t\t(to install boot program with existing label)",
16200a319615SMatthew Dillon 		"       disklabel64 -w -B [-n] [-b boot1 -s boot2] disk [type [packid]]",
16210ffe40b3SMatthew Dillon 		"\t\t(to write label and boot program)",
16220fcbc539SThomas Nikolajsen 		"       disklabel64 -R -B [-n] [-b boot1 -s boot2] disk protofile [type]",
16230ffe40b3SMatthew Dillon 		"\t\t(to restore label and boot program)",
1624bdddbf50SThomas Nikolajsen 		"       disklabel64 [-NW] disk",
16250ffe40b3SMatthew Dillon 		"\t\t(to write disable/enable label)");
16260ffe40b3SMatthew Dillon 	exit(1);
16270ffe40b3SMatthew Dillon }
1628